Commit 79256399 authored by Skia's avatar Skia
Browse files

Allow root to reset user password

parent a033c4df
Pipeline #114 failed with stage
in 2 minutes and 38 seconds
......@@ -223,6 +223,9 @@ class User(AbstractBaseUser):
return True
return self.groups.filter(name=group_name).exists()
def is_root(self):
return self.is_superuser or self.groups.filter(name=settings.SITH_GROUPS['root']['name']).exists()
def save(self, *args, **kwargs):
with transaction.atomic():
if self.id:
......
......@@ -2,7 +2,10 @@
{% block content %}
<form method="post" action="{{ url('core:password_change') }}">
{% if target %}
<p>{% trans user=target.get_display_name() %}Change password for {{ user }}{% endtrans %}</p>
{% endif %}
<form method="post" action="">
{% csrf_token %}
{{ form.as_p() }}
<input type="submit" value="{% trans %}Change{% endtrans %}" />
......
......@@ -28,6 +28,8 @@
{% endif %}
{% if form.instance == user %}
<p><a href="{{ url('core:password_change') }}">{% trans %}Change my password{% endtrans %}</a></p>
{% elif user.is_root() %}
<p><a href="{{ url('core:password_root_change', user_id=form.instance.id) }}">{% trans %}Change user password{% endtrans %}</a></p>
{% endif %}
</form>
{% endblock %}
......
......@@ -9,6 +9,7 @@ urlpatterns = [
url(r'^login/$', login, name='login'),
url(r'^logout/$', logout, name='logout'),
url(r'^password_change/$', password_change, name='password_change'),
url(r'^password_change/(?P<user_id>[0-9]+)$', password_root_change, name='password_root_change'),
url(r'^password_change/done$', password_change_done, name='password_change_done'),
url(r'^password_reset/$', password_reset, name='password_reset'),
url(r'^password_reset/done$', password_reset_done, name='password_reset_done'),
......
......@@ -3,10 +3,12 @@ from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth import logout as auth_logout, views
from django.core.urlresolvers import reverse
from django.core.exceptions import PermissionDenied, ObjectDoesNotExist
from django.http import Http404
from django.views.generic.edit import UpdateView
from django.views.generic import ListView, DetailView, TemplateView
from django.forms.models import modelform_factory
from django.forms import CheckboxSelectMultiple
from django.template.response import TemplateResponse
from django.conf import settings
import logging
......@@ -40,6 +42,24 @@ def password_change_done(request):
"""
return views.password_change_done(request, template_name="core/password_change_done.jinja")
def password_root_change(request, user_id):
"""
Allows a root user to change someone's password
"""
if not request.user.is_superuser and not request.user.is_in_group(settings.SITH_GROUPS['root']['name']):
raise PermissionDenied
user = User.objects.filter(id=user_id).first()
if not user:
raise Http404("User not found")
if request.method == "POST":
form = views.SetPasswordForm(user=user, data=request.POST)
if form.is_valid():
form.save()
return redirect("core:password_change_done")
else:
form = views.SetPasswordForm(user=user)
return TemplateResponse(request, "core/password_change.jinja", {'form': form, 'target': user})
def password_reset(request):
"""
Allows someone to enter an email adresse for resetting password
......
......@@ -6,7 +6,7 @@
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-08-11 04:02+0200\n"
"POT-Creation-Date: 2016-08-13 17:14+0200\n"
"PO-Revision-Date: 2016-07-18\n"
"Last-Translator: Skia <skia@libskia.so>\n"
"Language-Team: AE info <ae.info@utbm.fr>\n"
......@@ -18,8 +18,8 @@ msgstr ""
#: accounting/models.py:33 accounting/models.py:45 accounting/models.py:68
#: accounting/models.py:111 club/models.py:18 counter/models.py:52
#: counter/models.py:77 counter/models.py:105 launderette/models.py:14
#: launderette/models.py:54 launderette/models.py:77
#: counter/models.py:77 counter/models.py:105 launderette/models.py:15
#: launderette/models.py:60 launderette/models.py:85
msgid "name"
msgstr "nom"
......@@ -41,7 +41,7 @@ msgid "%(club_account)s on %(bank_account)s"
msgstr "%(club_account)s sur %(bank_account)s"
#: accounting/models.py:109 club/models.py:147 counter/models.py:268
#: launderette/models.py:112
#: launderette/models.py:122
msgid "start date"
msgstr "date de début"
......@@ -66,7 +66,7 @@ msgstr "montant effectif"
msgid "number"
msgstr "numéro"
#: accounting/models.py:154 core/models.py:390 core/models.py:666
#: accounting/models.py:154 core/models.py:403 core/models.py:679
#: counter/models.py:209 counter/models.py:244 eboutic/models.py:13
#: eboutic/models.py:46
msgid "date"
......@@ -106,7 +106,7 @@ msgid "target type"
msgstr "type de cible"
#: accounting/models.py:163
#: launderette/templates/launderette/launderette_admin.jinja:34
#: launderette/templates/launderette/launderette_admin.jinja:44
msgid "User"
msgstr "Utilisateur"
......@@ -114,7 +114,7 @@ msgstr "Utilisateur"
msgid "Club"
msgstr "Club"
#: accounting/models.py:163 core/templates/core/user_base.jinja:16
#: accounting/models.py:163 core/templates/core/user_base.jinja:17
msgid "Account"
msgstr "Compte"
......@@ -122,7 +122,7 @@ msgstr "Compte"
msgid "Company"
msgstr "Entreprise"
#: accounting/models.py:163 sith/settings.py:263 sith/settings_sample.py:263
#: accounting/models.py:163 sith/settings.py:278 sith/settings_sample.py:268
msgid "Other"
msgstr "Autre"
......@@ -176,17 +176,17 @@ msgstr "Il n'y a pas de types comptable dans ce site web."
#: accounting/templates/accounting/bank_account_details.jinja:5
#: accounting/templates/accounting/club_account_details.jinja:5
#: accounting/templates/accounting/journal_details.jinja:5
#: core/templates/core/user_tools.jinja:43
#: core/templates/core/user_tools.jinja:39
msgid "Accounting"
msgstr "Comptabilité"
#: accounting/templates/accounting/bank_account_details.jinja:8
#: core/templates/core/user_tools.jinja:50
#: core/templates/core/user_tools.jinja:46
msgid "Bank account: "
msgstr "Compte en banque : "
#: accounting/templates/accounting/bank_account_details.jinja:9
#: core/templates/core/user_base.jinja:6
#: core/templates/core/user_base.jinja:7
msgid "Infos"
msgstr "Infos"
......@@ -207,8 +207,8 @@ msgstr "Nouveau compte club"
#: accounting/templates/accounting/club_account_details.jinja:44
#: accounting/templates/accounting/journal_details.jinja:62
#: club/templates/club/club_detail.jinja:7 core/templates/core/file.jinja:38
#: core/templates/core/page.jinja:31 core/templates/core/user_base.jinja:8
#: core/templates/core/user_tools.jinja:37
#: core/templates/core/page.jinja:31 core/templates/core/user_base.jinja:9
#: core/templates/core/user_tools.jinja:33
#: counter/templates/counter/counter_list.jinja:15
#: counter/templates/counter/counter_list.jinja:18
#: launderette/templates/launderette/launderette_list.jinja:14
......@@ -254,7 +254,7 @@ msgid "You can not create new journal while you still have one opened"
msgstr "Vous ne pouvez pas créer de journal tant qu'il y en a un d'ouvert"
#: accounting/templates/accounting/club_account_details.jinja:17
#: launderette/templates/launderette/launderette_admin.jinja:33
#: launderette/templates/launderette/launderette_admin.jinja:43
msgid "Name"
msgstr "Nom"
......@@ -378,11 +378,11 @@ msgstr ""
msgid "A club with that unix name already exists."
msgstr "Un club avec ce nom UNIX existe déjà."
#: club/models.py:32
#: club/models.py:32 core/models.py:166
msgid "address"
msgstr "Adresse"
#: club/models.py:38 core/models.py:112
#: club/models.py:38 core/models.py:115
msgid "home"
msgstr "home"
......@@ -395,7 +395,7 @@ msgid "A club with that unix_name already exists"
msgstr "Un club avec ce nom UNIX existe déjà."
#: club/models.py:145 eboutic/models.py:12 eboutic/models.py:45
#: launderette/models.py:81 launderette/models.py:116
#: launderette/models.py:89 launderette/models.py:126
msgid "user"
msgstr "nom d'utilisateur"
......@@ -403,11 +403,11 @@ msgstr "nom d'utilisateur"
msgid "club"
msgstr "club"
#: club/models.py:149 core/models.py:127
#: club/models.py:149 core/models.py:133
msgid "role"
msgstr "rôle"
#: club/models.py:151 core/models.py:28 counter/models.py:53
#: club/models.py:151 core/models.py:30 counter/models.py:53
#: counter/models.py:78
msgid "description"
msgstr "description"
......@@ -456,7 +456,8 @@ msgstr "Sauver"
msgid "Edit club properties"
msgstr "Éditer les propriétés du club"
#: club/templates/club/club_list.jinja:4 club/templates/club/club_list.jinja:24
#: club/templates/club/club_list.jinja:4
#: club/templates/club/club_list.jinja:24
msgid "Club list"
msgstr "Liste des clubs"
......@@ -478,7 +479,7 @@ msgid "Add"
msgstr "Ajouter"
#: club/templates/club/club_tools.jinja:4
#: core/templates/core/user_tools.jinja:61
#: core/templates/core/user_tools.jinja:57
msgid "Club tools"
msgstr "Outils club"
......@@ -486,30 +487,34 @@ msgstr "Outils club"
msgid "Counters:"
msgstr "Comptoirs : "
#: core/models.py:24
#: club/templates/club/club_tools.jinja:22
msgid "Manage launderettes"
msgstr "Gestion des laveries"
#: core/models.py:26
msgid "meta group status"
msgstr "status du meta-groupe"
#: core/models.py:26
#: core/models.py:28
msgid "Whether a group is a meta group or not"
msgstr "Si un groupe est un meta-groupe ou pas"
#: core/models.py:54
#: core/models.py:56
#, python-format
msgid "%(value)s is not a valid promo (between 0 and %(end)s)"
msgstr "%(value)s n'est pas une promo valide (doit être entre 0 et %(end)s)"
#: core/models.py:70
#: core/models.py:72
msgid "username"
msgstr "nom d'utilisateur"
#: core/models.py:73
#: core/models.py:75
msgid "Required. 254 characters or fewer. Letters, digits and @/./+/-/_ only."
msgstr ""
"Requis. Pas plus de 254 caractères. Uniquement des lettres, numéros, et @/./"
"+/-/_"
#: core/models.py:77
#: core/models.py:79
msgid ""
"Enter a valid username. This value may contain only letters, numbers and @/./"
"+/-/_ characters."
......@@ -517,43 +522,43 @@ msgstr ""
"Entrez un nom d'utilisateur correct. Uniquement des lettres, numéros, et @/./"
"+/-/_"
#: core/models.py:82
#: core/models.py:84
msgid "A user with that username already exists."
msgstr "Un utilisateur de ce nom existe déjà"
#: core/models.py:85
#: core/models.py:87
msgid "first name"
msgstr "Prénom"
#: core/models.py:86
#: core/models.py:88
msgid "last name"
msgstr "Nom"
#: core/models.py:87
#: core/models.py:89
msgid "email address"
msgstr "adresse email"
#: core/models.py:88
#: core/models.py:90
msgid "date of birth"
msgstr "date de naissance"
#: core/models.py:89
#: core/models.py:91
msgid "nick name"
msgstr "surnom"
#: core/models.py:91
#: core/models.py:93
msgid "staff status"
msgstr "status \"staff\""
#: core/models.py:93
#: core/models.py:95
msgid "Designates whether the user can log into this admin site."
msgstr "Est-ce que l'utilisateur peut se logger à la partie admin du site."
#: core/models.py:96
#: core/models.py:98
msgid "active"
msgstr "actif"
#: core/models.py:99
#: core/models.py:101
msgid ""
"Designates whether this user should be treated as active. Unselect this "
"instead of deleting accounts."
......@@ -561,293 +566,313 @@ msgstr ""
"Est-ce que l'utilisateur doit être traité comme actif. Déselectionnez au "
"lieu de supprimer les comptes."
#: core/models.py:103
#: core/models.py:105
msgid "date joined"
msgstr "date d'inscription"
#: core/models.py:105
#: core/models.py:106
msgid "last update"
msgstr "dernière mise à jour"
#: core/models.py:108
msgid "superuser"
msgstr "super-utilisateur"
#: core/models.py:108
#: core/models.py:111
msgid "Designates whether this user is a superuser. "
msgstr "Est-ce que l'utilisateur est super-utilisateur."
#: core/models.py:113
#: core/models.py:116
msgid "profile"
msgstr "profil"
#: core/models.py:114
#: core/models.py:118
msgid "avatar"
msgstr "avatar"
#: core/models.py:115
#: core/models.py:120
msgid "scrub"
msgstr "blouse"
#: core/models.py:116
#: core/models.py:122
msgid "sex"
msgstr "sexe"
#: core/models.py:116
#: core/models.py:122
msgid "Man"
msgstr "Homme"
#: core/models.py:116
#: core/models.py:122
msgid "Woman"
msgstr "Femme"
#: core/models.py:117
#: core/models.py:123
msgid "tshirt size"
msgstr "taille de tshirt"
#: core/models.py:118
#: core/models.py:124
msgid "-"
msgstr "-"
#: core/models.py:119
#: core/models.py:125
msgid "XS"
msgstr "XS"
#: core/models.py:120
#: core/models.py:126
msgid "S"
msgstr "S"
#: core/models.py:121
#: core/models.py:127
msgid "M"
msgstr "M"
#: core/models.py:122
#: core/models.py:128
msgid "L"
msgstr "L"
#: core/models.py:123
#: core/models.py:129
msgid "XL"
msgstr "XL"
#: core/models.py:124
#: core/models.py:130
msgid "XXL"
msgstr "XXL"
#: core/models.py:125
#: core/models.py:131
msgid "XXXL"
msgstr "XXXL"
#: core/models.py:128
#: core/models.py:134
msgid "Student"
msgstr "Étudiant"
#: core/models.py:129
#: core/models.py:135
msgid "Administrative agent"
msgstr "Personnel administratif"
#: core/models.py:130
#: core/models.py:136
msgid "Teacher"
msgstr "Enseignant"
#: core/models.py:131
#: core/models.py:137
msgid "Agent"
msgstr "Personnel"
#: core/models.py:132
#: core/models.py:138
msgid "Doctor"
msgstr "Doctorant"
#: core/models.py:133
#: core/models.py:139
msgid "Former student"
msgstr "Ancien étudiant"
#: core/models.py:134
#: core/models.py:140
msgid "Service"
msgstr "Service"
#: core/models.py:136
#: core/models.py:142
msgid "department"
msgstr "département"
#: core/models.py:137
#: core/models.py:143
msgid "TC"
msgstr "TC"
#: core/models.py:138
#: core/models.py:144
msgid "IMSI"
msgstr "IMSI"
#: core/models.py:139
#: core/models.py:145
msgid "IMAP"
msgstr "IMAP"
#: core/models.py:140
#: core/models.py:146
msgid "INFO"
msgstr "INFO"
#: core/models.py:141
#: core/models.py:147
msgid "GI"
msgstr "GI"
#: core/models.py:142
#: core/models.py:148
msgid "E"
msgstr "E"
#: core/models.py:143
#: core/models.py:149
msgid "EE"
msgstr "EE"
#: core/models.py:144
#: core/models.py:150
msgid "GESC"
msgstr "GESC"
#: core/models.py:145
#: core/models.py:151
msgid "GMC"
msgstr "GMC"
#: core/models.py:146
#: core/models.py:152
msgid "MC"
msgstr "MC"
#: core/models.py:147
#: core/models.py:153
msgid "EDIM"
msgstr "EDIM"
#: core/models.py:148
#: core/models.py:154
msgid "Humanities"
msgstr "Humanités"
#: core/models.py:149
#: core/models.py:155
msgid "N/A"
msgstr "N/A"
#: core/models.py:151
#: core/models.py:157
msgid "dpt option"
msgstr "Filière"
#: core/models.py:152
#: core/models.py:158
msgid "semester"
msgstr "semestre"
#: core/models.py:153
#: core/models.py:159
msgid "quote"
msgstr "citation"
#: core/models.py:154
#: core/models.py:160
msgid "school"
msgstr "école"
#: core/models.py:155
#: core/models.py:161
msgid "promo"
msgstr "promo"
#: core/models.py:156
#: core/models.py:162
msgid "forum signature"
msgstr "signature du forum"
#: core/models.py:240
#: core/models.py:163
msgid "second email address"
msgstr "adresse email secondaire"
#: core/models.py:164
msgid "phone"
msgstr "téléphone"
#: core/models.py:165
msgid "parent phone"
msgstr "téléphone des parents"
#: core/models.py:167
msgid "parent address"
msgstr "adresse des parents"
#: core/models.py:253
msgid "A user with that username already exists"
msgstr "Un utilisateur de ce nom d'utilisateur existe déjà"
#: core/models.py:367
#: core/models.py:380
msgid "Visitor"
msgstr "Visiteur"
#: core/models.py:372
#: core/models.py:385
msgid "define if we show a users stats"
msgstr "Definit si l'on montre les statistiques de l'utilisateur"
#: core/models.py:374
#: core/models.py:387
msgid "Show your account statistics to others"
msgstr "Montrez vos statistiques de compte aux autres"
#: core/models.py:381
#: core/models.py:394
msgid "file name"
msgstr "nom du fichier"
#: core/models.py:382 core/models.py:515
#: core/models.py:395 core/models.py:528
msgid "parent"
msgstr "parent"
#: core/models.py:383 core/models.py:393
#: core/models.py:396 core/models.py:406
msgid "file"
msgstr "fichier"
#: core/models.py:384
#: core/models.py:397
msgid "owner"
msgstr "propriétaire"
#: core/models.py:385 core/models.py:521
#: core/models.py:398 core/models.py:534
msgid "edit group"
msgstr "groupe d'édition"
#: core/models.py:386 core/models.py:522
#: core/models.py:399 core/models.py:535
msgid "view group"
msgstr "groupe de vue"
#: core/models.py:387
#: core/models.py:400
msgid "is folder"
msgstr "est un dossier"
#: core/models.py:388
#: core/models.py:401
msgid "mime type"
msgstr "type mime"
#: core/models.py:389
#: core/models.py:402
msgid "size"