Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
R
re2o
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Nounous
re2o
Commits
f1d96c19
Commit
f1d96c19
authored
Oct 26, 2017
by
root
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' into klafyvel
parents
7bc0f2b7
0efe0c27
Changes
10
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
233 additions
and
91 deletions
+233
-91
freeradius_utils/auth.py
freeradius_utils/auth.py
+8
-4
re2o/utils.py
re2o/utils.py
+11
-1
search/views.py
search/views.py
+1
-1
users/admin.py
users/admin.py
+1
-2
users/forms.py
users/forms.py
+29
-59
users/migrations/0058_auto_20171025_0154.py
users/migrations/0058_auto_20171025_0154.py
+61
-0
users/migrations/0059_auto_20171025_1854.py
users/migrations/0059_auto_20171025_1854.py
+25
-0
users/models.py
users/models.py
+46
-15
users/templates/users/email_auto_newmachine
users/templates/users/email_auto_newmachine
+27
-0
users/views.py
users/views.py
+24
-9
No files found.
freeradius_utils/auth.py
View file @
f1d96c19
...
...
@@ -292,10 +292,11 @@ def decide_vlan_and_register_switch(nas, nas_type, port_number, mac_address):
if
not
port
.
room
:
return
(
sw_name
,
u
'Chambre inconnue'
,
VLAN_NOK
)
room_user
=
User
.
objects
.
filter
(
room
=
port
.
room
)
room_user
=
User
.
objects
.
filter
(
Q
(
club__room
=
port
.
room
)
|
Q
(
adherent__room
=
port
.
room
)
)
if
not
room_user
:
return
(
sw_name
,
u
'Chambre non cotisante'
,
VLAN_NOK
)
elif
not
room_user
.
first
().
has_access
():
for
user
in
room_user
:
if
not
user
.
has_access
():
return
(
sw_name
,
u
'Chambre resident desactive'
,
VLAN_NOK
)
# else: user OK, on passe à la verif MAC
...
...
@@ -309,9 +310,12 @@ def decide_vlan_and_register_switch(nas, nas_type, port_number, mac_address):
elif
not
port
.
room
:
return
(
sw_name
,
u
'Chambre et machine inconnues'
,
VLAN_NOK
)
else
:
room_user
=
User
.
objects
.
filter
(
room
=
Room
.
objects
.
filter
(
name
=
port
.
room
))
if
not
room_user
:
room_user
=
User
.
objects
.
filter
(
Q
(
club__room
=
port
.
room
)
|
Q
(
adherent__room
=
port
.
room
))
if
not
room_user
:
return
(
sw_name
,
u
'Machine et propriétaire de la chambre inconnus'
,
VLAN_NOK
)
elif
room_user
.
count
()
>
1
:
return
(
sw_name
,
u
'Machine inconnue, il y a au moins 2 users dans la chambre/local -> ajout de mac automatique impossible'
,
VLAN_NOK
)
elif
not
room_user
.
first
().
has_access
():
return
(
sw_name
,
u
'Machine inconnue et adhérent non cotisant'
,
VLAN_NOK
)
else
:
...
...
re2o/utils.py
View file @
f1d96c19
...
...
@@ -42,7 +42,7 @@ from django.db.models import Q
from
cotisations.models
import
Cotisation
,
Facture
,
Paiement
,
Vente
from
machines.models
import
Domain
,
Interface
,
Machine
from
users.models
import
User
,
Ban
,
Whitelist
from
users.models
import
Adherent
,
User
,
Ban
,
Whitelist
from
preferences.models
import
Service
DT_NOW
=
timezone
.
now
()
...
...
@@ -238,3 +238,13 @@ class SortTable:
return
request
.
reverse
()
else
:
return
request
def
remove_user_room
(
room
):
""" Déménage de force l'ancien locataire de la chambre """
try
:
user
=
Adherent
.
objects
.
get
(
room
=
room
)
except
Adherent
.
DoesNotExist
:
return
user
.
room
=
None
user
.
save
()
search/views.py
View file @
f1d96c19
...
...
@@ -81,7 +81,7 @@ def search_result(search, type, request):
for
i
in
aff
:
if
i
==
'0'
:
query_user_list
=
Q
(
room__name__icontains
=
search
)
|
Q
(
pseudo__icontains
=
search
)
|
Q
(
adherent__name__icontains
=
search
)
|
Q
(
surname__icontains
=
search
)
&
query1
query_user_list
=
Q
(
adherent__room__name__icontains
=
search
)
|
Q
(
club__
room__name__icontains
=
search
)
|
Q
(
pseudo__icontains
=
search
)
|
Q
(
adherent__name__icontains
=
search
)
|
Q
(
surname__icontains
=
search
)
&
query1
if
request
.
user
.
has_perms
((
'cableur'
,)):
recherche
[
'users_list'
]
=
User
.
objects
.
filter
(
query_user_list
).
order_by
(
'state'
,
'surname'
).
distinct
()
else
:
...
...
users/admin.py
View file @
f1d96c19
...
...
@@ -44,13 +44,12 @@ class UserAdmin(admin.ModelAdmin):
list_display
=
(
'surname'
,
'pseudo'
,
'room'
,
'email'
,
'school'
,
'shell'
,
'state'
)
search_fields
=
(
'surname'
,
'pseudo'
,
'room'
)
search_fields
=
(
'surname'
,
'pseudo'
)
class
LdapUserAdmin
(
admin
.
ModelAdmin
):
...
...
users/forms.py
View file @
f1d96c19
...
...
@@ -41,7 +41,8 @@ from django.utils import timezone
from
preferences.models
import
OptionalUser
from
.models
import
User
,
ServiceUser
,
Right
,
School
,
ListRight
,
Whitelist
from
.models
import
Ban
,
remove_user_room
,
Adherent
,
Club
from
.models
import
Ban
,
Adherent
,
Club
from
re2o.utils
import
remove_user_room
NOW
=
timezone
.
now
()
...
...
@@ -252,13 +253,13 @@ class MassArchiveForm(forms.Form):
utilisateurs dont la fin d'accès se situe dans le futur !"
)
class
NewUser
Form
(
ModelForm
):
class
Adherent
Form
(
ModelForm
):
"""Formulaire de base d'edition d'un user. Formulaire de base, utilisé
pour l'edition de self par self ou un cableur. On formate les champs
avec des label plus jolis"""
def
__init__
(
self
,
*
args
,
**
kwargs
):
prefix
=
kwargs
.
pop
(
'prefix'
,
self
.
Meta
.
model
.
__name__
)
super
(
NewUser
Form
,
self
).
__init__
(
*
args
,
prefix
=
prefix
,
**
kwargs
)
super
(
Adherent
Form
,
self
).
__init__
(
*
args
,
prefix
=
prefix
,
**
kwargs
)
self
.
fields
[
'name'
].
label
=
'Prénom'
self
.
fields
[
'surname'
].
label
=
'Nom'
self
.
fields
[
'school'
].
label
=
'Établissement'
...
...
@@ -291,18 +292,31 @@ class NewUserForm(ModelForm):
)
return
telephone
force
=
forms
.
BooleanField
(
label
=
"Forcer le déménagement ?"
,
initial
=
False
,
required
=
False
)
def
clean_force
(
self
):
"""On supprime l'ancien user de la chambre si et seulement si la
case est cochée"""
if
self
.
cleaned_data
.
get
(
'force'
,
False
):
remove_user_room
(
self
.
cleaned_data
.
get
(
'room'
))
return
class
NewClubForm
(
ModelForm
):
class
ClubForm
(
ModelForm
):
"""Formulaire de base d'edition d'un user. Formulaire de base, utilisé
pour l'edition de self par self ou un cableur. On formate les champs
avec des label plus jolis"""
def
__init__
(
self
,
*
args
,
**
kwargs
):
prefix
=
kwargs
.
pop
(
'prefix'
,
self
.
Meta
.
model
.
__name__
)
super
(
New
ClubForm
,
self
).
__init__
(
*
args
,
prefix
=
prefix
,
**
kwargs
)
super
(
ClubForm
,
self
).
__init__
(
*
args
,
prefix
=
prefix
,
**
kwargs
)
self
.
fields
[
'surname'
].
label
=
'Nom'
self
.
fields
[
'school'
].
label
=
'Établissement'
self
.
fields
[
'comment'
].
label
=
'Commentaire'
self
.
fields
[
'room'
].
label
=
'
Chambre
'
self
.
fields
[
'room'
].
label
=
'
Local
'
self
.
fields
[
'room'
].
empty_label
=
"Pas de chambre"
self
.
fields
[
'school'
].
empty_label
=
"Séléctionner un établissement"
...
...
@@ -330,50 +344,29 @@ class NewClubForm(ModelForm):
return
telephone
class
BaseInfoForm
(
ModelForm
):
"""Formulaire de base d'edition d'un user. Formulaire de base, utilisé
pour l'edition de self par self ou un cableur. On formate les champs
avec des label plus jolis"""
def
__init__
(
self
,
*
args
,
**
kwargs
):
prefix
=
kwargs
.
pop
(
'prefix'
,
self
.
Meta
.
model
.
__name__
)
super
(
BaseInfoForm
,
self
).
__init__
(
*
args
,
prefix
=
prefix
,
**
kwargs
)
self
.
fields
[
'surname'
].
label
=
'Nom'
self
.
fields
[
'school'
].
label
=
'Établissement'
self
.
fields
[
'comment'
].
label
=
'Commentaire'
self
.
fields
[
'room'
].
label
=
'Chambre'
self
.
fields
[
'room'
].
empty_label
=
"Pas de chambre"
self
.
fields
[
'school'
].
empty_label
=
"Séléctionner un établissement"
class
Meta
:
model
=
User
class
FullAdherentForm
(
AdherentForm
):
"""Edition complète d'un user. Utilisé par admin,
permet d'editer normalement la chambre, ou le shell
Herite de la base"""
class
Meta
(
AdherentForm
.
Meta
):
fields
=
[
'name'
,
'surname'
,
'pseudo'
,
'email'
,
'school'
,
'comment'
,
'room'
,
'shell'
,
'telephone'
,
]
def
clean_telephone
(
self
):
"""Verifie que le tel est présent si 'option est validée
dans preferences"""
telephone
=
self
.
cleaned_data
[
'telephone'
]
preferences
,
_created
=
OptionalUser
.
objects
.
get_or_create
()
if
not
telephone
and
preferences
.
is_tel_mandatory
:
raise
forms
.
ValidationError
(
"Un numéro de téléphone valide est requis"
)
return
telephone
class
EditInfoForm
(
BaseInfo
Form
):
class
FullClubForm
(
Club
Form
):
"""Edition complète d'un user. Utilisé par admin,
permet d'editer normalement la chambre, ou le shell
Herite de la base"""
class
Meta
(
BaseInfo
Form
.
Meta
):
class
Meta
(
Club
Form
.
Meta
):
fields
=
[
'surname'
,
'pseudo'
,
...
...
@@ -386,29 +379,6 @@ class EditInfoForm(BaseInfoForm):
]
class
InfoForm
(
EditInfoForm
):
""" Utile pour forcer un déménagement quand il y a déjà un user en place
Formuaire utilisé pour la creation initiale"""
force
=
forms
.
BooleanField
(
label
=
"Forcer le déménagement ?"
,
initial
=
False
,
required
=
False
)
def
clean_force
(
self
):
"""On supprime l'ancien user de la chambre si et seulement si la
case est cochée"""
if
self
.
cleaned_data
.
get
(
'force'
,
False
):
remove_user_room
(
self
.
cleaned_data
.
get
(
'room'
))
return
class
UserForm
(
InfoForm
):
""" Model form general"""
class
Meta
(
InfoForm
.
Meta
):
fields
=
'__all__'
class
PasswordForm
(
ModelForm
):
""" Formulaire de changement brut de mot de passe.
Ne pas utiliser sans traitement"""
...
...
users/migrations/0058_auto_20171025_0154.py
0 → 100644
View file @
f1d96c19
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2017-10-24 23:54
from
__future__
import
unicode_literals
from
django.db
import
migrations
,
models
import
django.db.models.deletion
def
create_move_room
(
apps
,
schema_editor
):
User
=
apps
.
get_model
(
'users'
,
'User'
)
Adherent
=
apps
.
get_model
(
'users'
,
'Adherent'
)
Club
=
apps
.
get_model
(
'users'
,
'Club'
)
db_alias
=
schema_editor
.
connection
.
alias
users
=
Adherent
.
objects
.
using
(
db_alias
).
all
()
clubs
=
Club
.
objects
.
using
(
db_alias
).
all
()
for
user
in
users
:
user
.
room_adherent_id
=
user
.
room_id
user
.
save
(
using
=
db_alias
)
for
user
in
clubs
:
user
.
room_club_id
=
user
.
room_id
user
.
save
(
using
=
db_alias
)
def
delete_move_room
(
apps
,
schema_editor
):
User
=
apps
.
get_model
(
'users'
,
'User'
)
Adherent
=
apps
.
get_model
(
'users'
,
'Adherent'
)
Club
=
apps
.
get_model
(
'users'
,
'Club'
)
db_alias
=
schema_editor
.
connection
.
alias
users
=
Adherent
.
objects
.
using
(
db_alias
).
all
()
clubs
=
Club
.
objects
.
using
(
db_alias
).
all
()
for
user
in
users
:
user
.
room_id
=
user
.
room_adherent_id
user
.
save
(
using
=
db_alias
)
for
user
in
clubs
:
user
.
room_id
=
user
.
room_club_id
user
.
save
(
using
=
db_alias
)
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'topologie'
,
'0031_auto_20171015_2033'
),
(
'users'
,
'0057_auto_20171023_0301'
),
]
operations
=
[
migrations
.
AddField
(
model_name
=
'adherent'
,
name
=
'room_adherent'
,
field
=
models
.
OneToOneField
(
blank
=
True
,
null
=
True
,
on_delete
=
django
.
db
.
models
.
deletion
.
PROTECT
,
to
=
'topologie.Room'
),
),
migrations
.
AddField
(
model_name
=
'club'
,
name
=
'room_club'
,
field
=
models
.
ForeignKey
(
blank
=
True
,
null
=
True
,
on_delete
=
django
.
db
.
models
.
deletion
.
PROTECT
,
to
=
'topologie.Room'
),
),
migrations
.
RunPython
(
create_move_room
,
delete_move_room
),
migrations
.
RemoveField
(
model_name
=
'user'
,
name
=
'room'
,
),
]
users/migrations/0059_auto_20171025_1854.py
0 → 100644
View file @
f1d96c19
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2017-10-25 16:54
from
__future__
import
unicode_literals
from
django.db
import
migrations
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'users'
,
'0058_auto_20171025_0154'
),
]
operations
=
[
migrations
.
RenameField
(
model_name
=
'adherent'
,
old_name
=
'room_adherent'
,
new_name
=
'room'
,
),
migrations
.
RenameField
(
model_name
=
'club'
,
old_name
=
'room_club'
,
new_name
=
'room'
,
),
]
users/models.py
View file @
f1d96c19
...
...
@@ -81,15 +81,6 @@ DT_NOW = timezone.now()
# Utilitaires généraux
def
remove_user_room
(
room
):
""" Déménage de force l'ancien locataire de la chambre """
try
:
user
=
User
.
objects
.
get
(
room
=
room
)
except
User
.
DoesNotExist
:
return
user
.
room
=
None
user
.
save
()
def
linux_user_check
(
login
):
""" Validation du pseudo pour respecter les contraintes unix"""
...
...
@@ -230,12 +221,6 @@ class User(AbstractBaseUser):
max_length
=
255
,
blank
=
True
)
room
=
models
.
OneToOneField
(
'topologie.Room'
,
on_delete
=
models
.
PROTECT
,
blank
=
True
,
null
=
True
)
pwd_ntlm
=
models
.
CharField
(
max_length
=
255
)
state
=
models
.
IntegerField
(
choices
=
STATES
,
default
=
STATE_ACTIVE
)
registered
=
models
.
DateTimeField
(
auto_now_add
=
True
)
...
...
@@ -256,6 +241,16 @@ class User(AbstractBaseUser):
else
:
return
''
@
cached_property
def
room
(
self
):
"""Alias vers room """
if
self
.
is_class_adherent
:
return
self
.
adherent
.
room
elif
self
.
is_class_club
:
return
self
.
club
.
room
else
:
raise
NotImplementedError
(
"Type inconnu"
)
@
cached_property
def
class_name
(
self
):
"""Renvoie si il s'agit d'un adhérent ou d'un club"""
...
...
@@ -674,10 +669,34 @@ class User(AbstractBaseUser):
domain
.
interface_parent
=
interface_cible
domain
.
clean
()
domain
.
save
()
self
.
notif_auto_newmachine
(
interface_cible
)
except
Exception
as
error
:
return
False
,
error
return
True
,
"Ok"
def
notif_auto_newmachine
(
self
,
interface
):
"""Notification mail lorsque une machine est automatiquement
ajoutée par le radius"""
template
=
loader
.
get_template
(
'users/email_auto_newmachine'
)
assooptions
,
_created
=
AssoOption
.
objects
.
get_or_create
()
general_options
,
_created
=
GeneralOption
.
objects
.
get_or_create
()
context
=
Context
({
'nom'
:
self
.
get_full_name
(),
'mac_address'
:
interface
.
mac_address
,
'asso_name'
:
assooptions
.
name
,
'interface_name'
:
interface
.
domain
,
'asso_email'
:
assooptions
.
contact
,
'pseudo'
:
self
.
pseudo
,
})
send_mail
(
"Ajout automatique d'une machine / New machine autoregistered"
,
''
,
general_options
.
email_from
,
[
self
.
email
],
html_message
=
template
.
render
(
context
)
)
return
def
set_user_password
(
self
,
password
):
""" A utiliser de préférence, set le password en hash courrant et
dans la version ntlm"""
...
...
@@ -712,10 +731,22 @@ class User(AbstractBaseUser):
class
Adherent
(
User
):
name
=
models
.
CharField
(
max_length
=
255
)
room
=
models
.
OneToOneField
(
'topologie.Room'
,
on_delete
=
models
.
PROTECT
,
blank
=
True
,
null
=
True
)
pass
class
Club
(
User
):
room
=
models
.
ForeignKey
(
'topologie.Room'
,
on_delete
=
models
.
PROTECT
,
blank
=
True
,
null
=
True
)
pass
...
...
users/templates/users/email_auto_newmachine
0 → 100644
View file @
f1d96c19
<p>Bonjour {{nom}} </p>
<p>Une nouvelle machine a automatiquement été inscrite sur votre compte.</p>
<p>Si vous êtes à l'origine de la connexion de cet appareil en filaire ou wifi, ne tenez pas compte de cette notification</p>
<p>La nouvelle machine possède l'adresse mac {{ mac_address }}, et s'est vu assigner le nom suivant : {{ interface_name }}</p>
<p>Vous pouvez à tout moment modifier ces informations sur votre compte en ligne</p>
<p>Si vous n'êtes pas à l'origine de cette connexion, merci de le signaler rapidement à {{asso_email}}</p>
<p>À bientôt,<br>
L'équipe de {{asso_name}}.</p>
<p>---</p>
<p>A new device has been automatically added on your account.</p>
<p>If you connected a new device recently, please don't take this mail into account<p>
<p>The new device has this mac address : {{ mac_address }}, and this name : {{ interface_name }}</p>
<p>Please contact us if you didn't connect a new device with this mail address {{asso_email}}.</p>
<p>Regards,<br>
The {{asso_name}} team.</p>
users/views.py
View file @
f1d96c19
...
...
@@ -55,10 +55,10 @@ from users.serializers import MailSerializer
from
users.models
import
User
,
Right
,
Ban
,
Whitelist
,
School
,
ListRight
from
users.models
import
Request
,
ServiceUser
,
Adherent
,
Club
from
users.forms
import
DelRightForm
,
BanForm
,
WhitelistForm
,
DelSchoolForm
from
users.forms
import
DelListRightForm
,
NewListRightForm
from
users.forms
import
InfoForm
,
BaseInfoForm
,
State
Form
from
users.forms
import
DelListRightForm
,
NewListRightForm
,
FullAdherentForm
from
users.forms
import
StateForm
,
FullClub
Form
from
users.forms
import
RightForm
,
SchoolForm
,
EditServiceUserForm
from
users.forms
import
ServiceUserForm
,
ListRightForm
,
NewUserForm
,
New
ClubForm
from
users.forms
import
ServiceUserForm
,
ListRightForm
,
AdherentForm
,
ClubForm
from
users.forms
import
MassArchiveForm
,
PassForm
,
ResetPasswordForm
from
cotisations.models
import
Facture
from
machines.models
import
Machine
...
...
@@ -85,7 +85,7 @@ def password_change_action(u_form, user, request, req=False):
def
new_user
(
request
):
""" Vue de création d'un nouvel utilisateur,
envoie un mail pour le mot de passe"""
user
=
NewUser
Form
(
request
.
POST
or
None
)
user
=
Adherent
Form
(
request
.
POST
or
None
)
if
user
.
is_valid
():
user
=
user
.
save
(
commit
=
False
)
with
transaction
.
atomic
(),
reversion
.
create_revision
():
...
...
@@ -104,7 +104,7 @@ def new_user(request):
def
new_club
(
request
):
""" Vue de création d'un nouveau club,
envoie un mail pour le mot de passe"""
club
=
New
ClubForm
(
request
.
POST
or
None
)
club
=
ClubForm
(
request
.
POST
or
None
)
if
club
.
is_valid
():
club
=
club
.
save
(
commit
=
False
)
with
transaction
.
atomic
(),
reversion
.
create_revision
():
...
...
@@ -118,6 +118,24 @@ def new_club(request):
return
form
({
'userform'
:
club
},
'users/user.html'
,
request
)
def
select_user_edit_form
(
request
,
user
):
"""Fonction de choix du bon formulaire, en fonction de:
- droit
- type d'object
"""
if
not
request
.
user
.
has_perms
((
'cableur'
,)):
if
user
.
is_class_adherent
:
user
=
AdherentForm
(
request
.
POST
or
None
,
instance
=
user
.
adherent
)
elif
user
.
is_class_club
:
user
=
ClubForm
(
request
.
POST
or
None
,
instance
=
user
.
club
)
else
:
if
user
.
is_class_adherent
:
user
=
FullAdherentForm
(
request
.
POST
or
None
,
instance
=
user
.
adherent
)
elif
user
.
is_class_club
:
user
=
FullClubForm
(
request
.
POST
or
None
,
instance
=
user
.
club
)
return
user
@
login_required
def
edit_info
(
request
,
userid
):
""" Edite un utilisateur à partir de son id,
...
...
@@ -132,10 +150,7 @@ def edit_info(request, userid):
messages
.
error
(
request
,
"Vous ne pouvez pas modifier un autre
\
user que vous sans droit cableur"
)
return
redirect
(
"/users/profil/"
+
str
(
request
.
user
.
id
))
if
not
request
.
user
.
has_perms
((
'cableur'
,)):
user
=
BaseInfoForm
(
request
.
POST
or
None
,
instance
=
user
)
else
:
user
=
InfoForm
(
request
.
POST
or
None
,
instance
=
user
)
user
=
select_user_edit_form
(
request
,
user
)
if
user
.
is_valid
():
with
transaction
.
atomic
(),
reversion
.
create_revision
():
user
.
save
()
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment