Commit e419a2f64dd942d7e7553e8dd3d02ba9a5c0f4f7
1 parent
0edbf5e5
Exists in
dev
Add new version for user management (almost complete)
Showing
17 changed files
with
1141 additions
and
484 deletions
Show diff stats
src/core/pyros_django/user_manager/forms.py
1 | -from django import forms | |
2 | -from common.models import PyrosUser, Country, UserLevel, ScientificProgram | |
3 | -from django.core.mail import send_mail | |
4 | -from django.urls import reverse | |
5 | -from django.conf import settings | |
6 | - | |
7 | -class PyrosUserCreationForm(forms.ModelForm): | |
8 | - ''' | |
9 | - Form used at user creation. | |
10 | - | |
11 | - IMPORTANT : The user must not be able to choose his Country, Scientific Program(s), Quota, Priority, and User Level | |
12 | - ''' | |
13 | - | |
14 | - email = forms.EmailField(label="Email", widget=forms.TextInput) | |
15 | - | |
16 | - password = forms.CharField(label='Password', widget=forms.PasswordInput) | |
17 | - password_confirm = forms.CharField(label='Password confirmation', widget=forms.PasswordInput) | |
18 | - | |
19 | - first_name = forms.CharField(label='First name') | |
20 | - last_name = forms.CharField(label='Last name') | |
21 | - | |
22 | - class Meta: | |
23 | - model = PyrosUser | |
24 | - fields = ('tel', 'laboratory', 'address') | |
25 | - | |
26 | - def __init__(self, *args, **kwargs): | |
27 | - super(PyrosUserCreationForm, self).__init__(*args, **kwargs) | |
28 | - self.fields.move_to_end('tel', True) | |
29 | - self.fields.move_to_end('laboratory', True) | |
30 | - self.fields.move_to_end('address', True) | |
31 | - for field in self.fields.values(): | |
32 | - field.required = True | |
33 | - field.widget.attrs['class'] = "form-control" | |
34 | - | |
35 | - def clean_password_confirm(self): | |
36 | - ''' | |
37 | - Checks if password and confirmation are equal | |
38 | - ''' | |
39 | - password = self.cleaned_data.get("password") | |
40 | - password_confirmation = self.cleaned_data.get("password_confirm") | |
41 | - if password and password_confirmation and password != password_confirmation: | |
42 | - raise forms.ValidationError("Passwords don't match") | |
43 | - return password_confirmation | |
44 | - | |
45 | - def clean_email(self): | |
46 | - ''' | |
47 | - Checks if the email already exists in DB | |
48 | - ''' | |
49 | - email = self.cleaned_data.get("email") | |
50 | - if PyrosUser.objects.filter(email=email).exists(): | |
51 | - raise forms.ValidationError("Email address already taken") | |
52 | - return email | |
53 | - | |
54 | - def save(self): | |
55 | - ''' | |
56 | - Creates a User and a PyrosUser in DB | |
57 | - ''' | |
58 | - pyros_user = PyrosUser.objects.create(username=self.cleaned_data['email'], email=self.cleaned_data['email'], country=Country.objects.all()[0], | |
59 | - tel=self.cleaned_data['tel'], laboratory=self.cleaned_data['laboratory'], | |
60 | - address=self.cleaned_data['address']) | |
61 | - pyros_user.set_password(self.cleaned_data['password']) | |
62 | - pyros_user.first_name = self.cleaned_data['first_name'] | |
63 | - pyros_user.last_name = self.cleaned_data['last_name'] | |
64 | - | |
65 | - # associate user_level Visitor to user | |
66 | - UserLevel.objects.get(name = "Visitor").pyros_users.add(pyros_user) | |
67 | - pyros_user.save() | |
68 | - | |
69 | - # get list of admin users | |
70 | - admin_users = PyrosUser.objects.filter(user_level__priority=7).values_list("email",flat=True) | |
71 | - | |
72 | - # sending mail to new user | |
73 | - send_mail( | |
74 | - '[PyROS CC] Registration', | |
75 | - 'Hi,\n\nThanks for your registration. The PI will examinate your account as soon as possible.\n\nCordially,\n\nPyROS Control Center', | |
76 | - '', | |
77 | - [self.cleaned_data['email']], | |
78 | - fail_silently=False, | |
79 | - ) | |
80 | - | |
81 | - domain = settings.DEFAULT_DOMAIN | |
82 | - url = f"{domain}{reverse('user-detail',args=(pyros_user.pk,))}" | |
83 | - | |
84 | - # sending mail to admin | |
85 | - send_mail( | |
86 | - '[PyROS CC] New registration', | |
87 | - f"Hi,\n\nA new user : {self.cleaned_data['email']}, need a validation for his registration.\nClick on the following link to verify this user profile : {url} \n\nCordially,\n\nPyROS Control Center", | |
88 | - '', | |
89 | - admin_users, | |
90 | - fail_silently=False, | |
91 | - ) | |
92 | - return pyros_user | |
1 | +from django import forms | |
2 | +from common.models import PyrosUser, Country, UserLevel, Institute | |
3 | +from django.core.mail import send_mail | |
4 | +from django.urls import reverse | |
5 | +from django.conf import settings | |
6 | +from django.contrib.auth.forms import PasswordResetForm | |
7 | + | |
8 | +class PyrosUserCreationForm(forms.ModelForm): | |
9 | + ''' | |
10 | + Form used at user creation. | |
11 | + | |
12 | + IMPORTANT : The user must not be able to choose his Country, Scientific Program(s), Quota, Priority, and User Level | |
13 | + ''' | |
14 | + | |
15 | + email = forms.EmailField(label="Email", widget=forms.TextInput) | |
16 | + | |
17 | + password = forms.CharField(label='Password', widget=forms.PasswordInput) | |
18 | + password_confirm = forms.CharField(label='Password confirmation', widget=forms.PasswordInput) | |
19 | + | |
20 | + first_name = forms.CharField(label='First name') | |
21 | + last_name = forms.CharField(label='Last name') | |
22 | + institute = forms.ModelChoiceField(queryset=Institute.objects.all()) | |
23 | + reason = forms.CharField(widget=forms.Textarea,label="Motive of registration") | |
24 | + class Meta: | |
25 | + model = PyrosUser | |
26 | + fields = ('tel', 'laboratory', 'address') | |
27 | + | |
28 | + def __init__(self, *args, **kwargs): | |
29 | + super(PyrosUserCreationForm, self).__init__(*args, **kwargs) | |
30 | + self.fields.move_to_end('tel', True) | |
31 | + self.fields.move_to_end('laboratory', True) | |
32 | + self.fields.move_to_end('address', True) | |
33 | + for field in self.fields.values(): | |
34 | + field.required = True | |
35 | + field.widget.attrs['class'] = "form-control" | |
36 | + self.fields["roles"] = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple, required | |
37 | + =False,queryset=UserLevel.objects.all(),to_field_name="name", label="Wished role(s)") | |
38 | + | |
39 | + def clean_password_confirm(self): | |
40 | + ''' | |
41 | + Checks if password and confirmation are equal | |
42 | + ''' | |
43 | + password = self.cleaned_data.get("password") | |
44 | + password_confirmation = self.cleaned_data.get("password_confirm") | |
45 | + if password and password_confirmation and password != password_confirmation: | |
46 | + raise forms.ValidationError("Passwords don't match") | |
47 | + return password_confirmation | |
48 | + | |
49 | + def clean_email(self): | |
50 | + ''' | |
51 | + Checks if the email already exists in DB | |
52 | + ''' | |
53 | + email = self.cleaned_data.get("email") | |
54 | + if PyrosUser.objects.filter(email=email).exists(): | |
55 | + raise forms.ValidationError("Email address already taken") | |
56 | + return email | |
57 | + | |
58 | + def save(self): | |
59 | + ''' | |
60 | + Creates a User and a PyrosUser in DB | |
61 | + ''' | |
62 | + pyros_user = PyrosUser.objects.create(username=self.cleaned_data['email'], email=self.cleaned_data['email'], country=Country.objects.all()[0], | |
63 | + tel=self.cleaned_data['tel'], laboratory=self.cleaned_data['laboratory'], | |
64 | + address=self.cleaned_data['address'], institute=self.cleaned_data["institute"], motive_of_registration=self.cleaned_data["reason"]) | |
65 | + pyros_user.set_password(self.cleaned_data['password']) | |
66 | + pyros_user.first_name = self.cleaned_data['first_name'] | |
67 | + pyros_user.last_name = self.cleaned_data['last_name'] | |
68 | + | |
69 | + # associate user_level Visitor to user | |
70 | + UserLevel.objects.get(name = "Visitor").pyros_users.add(pyros_user) | |
71 | + pyros_user.save() | |
72 | + | |
73 | + # get list of admin and Unit-PI users | |
74 | + admin_and_unit_PI_users = PyrosUser.objects.filter(user_level__priority__gte=6).distinct().values_list("email",flat=True) | |
75 | + | |
76 | + # sending mail to new user | |
77 | + send_mail( | |
78 | + '[PyROS CC] Registration', | |
79 | + 'Hi,\n\nThanks for your registration. The PI will examinate your account as soon as possible.\n\nCordially,\n\nPyROS Control Center', | |
80 | + '', | |
81 | + [self.cleaned_data['email']], | |
82 | + fail_silently=False, | |
83 | + ) | |
84 | + | |
85 | + domain = settings.DEFAULT_DOMAIN | |
86 | + url = f"{domain}{reverse('user_detail',args=(pyros_user.pk,))}" | |
87 | + wished_roles = "" | |
88 | + for role in self.cleaned_data["roles"]: | |
89 | + wished_roles+= f"{role} " | |
90 | + # sending mail to admin | |
91 | + send_mail( | |
92 | + '[PyROS CC] New registration', | |
93 | + f"Hi,\n\nA new user : {self.cleaned_data['email']}, need a validation for his registration.\nClick on the following link to verify this user profile : {url}\n\nReason of the registration : {self.cleaned_data['reason']}\n\nWished role(s) : {wished_roles}\n\nCordially,\n\nPyROS Control Center", | |
94 | + '', | |
95 | + admin_and_unit_PI_users, | |
96 | + fail_silently=False, | |
97 | + ) | |
98 | + return pyros_user | |
99 | + | |
100 | +class UserPasswordResetForm(PasswordResetForm): | |
101 | + def __init__(self, *args, **kwargs): | |
102 | + super(UserPasswordResetForm, self).__init__(*args, **kwargs) | |
103 | + | |
104 | + email = forms.EmailField(label='Email ', widget=forms.EmailInput(attrs={ | |
105 | + 'placeholder': '', | |
106 | + 'type': 'text', | |
107 | + 'name': 'email' | |
108 | + })) | |
93 | 109 | \ No newline at end of file | ... | ... |
src/core/pyros_django/user_manager/static/user_manager/css/user_detail.css
0 โ 100644
... | ... | @@ -0,0 +1,92 @@ |
1 | +/* Float cancel and delete buttons and add an equal width */ | |
2 | + | |
3 | +.modal-btn { | |
4 | + float: left; | |
5 | + width: 50%; | |
6 | +} | |
7 | + | |
8 | + | |
9 | +/* Add padding and center-align text to the container */ | |
10 | + | |
11 | +.container { | |
12 | + padding: 16px; | |
13 | + text-align: center; | |
14 | +} | |
15 | + | |
16 | + | |
17 | +/* The Modal (background) */ | |
18 | + | |
19 | +#modal_delete_user { | |
20 | + display: none; | |
21 | + /* Hidden by default */ | |
22 | + position: fixed; | |
23 | + /* Stay in place */ | |
24 | + z-index: 1; | |
25 | + /* Sit on top */ | |
26 | + left: 0; | |
27 | + top: 0; | |
28 | + width: 100%; | |
29 | + /* Full width */ | |
30 | + height: 100%; | |
31 | + /* Full height */ | |
32 | + overflow: auto; | |
33 | + /* Enable scroll if needed */ | |
34 | + background-color: #474e5d; | |
35 | + padding-top: 50px; | |
36 | +} | |
37 | + | |
38 | + | |
39 | +/* Modal Content/Box */ | |
40 | + | |
41 | +.modal-content { | |
42 | + background-color: #fefefe; | |
43 | + margin: 5% auto 15% auto; | |
44 | + /* 5% from the top, 15% from the bottom and centered */ | |
45 | + border: 1px solid #888; | |
46 | + width: 80%; | |
47 | + /* Could be more or less, depending on screen size */ | |
48 | +} | |
49 | + | |
50 | + | |
51 | +/* Style the horizontal ruler */ | |
52 | + | |
53 | +hr { | |
54 | + border: 1px solid #f1f1f1; | |
55 | + margin-bottom: 25px; | |
56 | +} | |
57 | + | |
58 | + | |
59 | +/* The Modal Close Button (x) */ | |
60 | + | |
61 | +#close_modal_delete_user { | |
62 | + position: absolute; | |
63 | + right: 35px; | |
64 | + top: 15px; | |
65 | + font-size: 40px; | |
66 | + font-weight: bold; | |
67 | + color: #f1f1f1; | |
68 | +} | |
69 | + | |
70 | +.close:hover, | |
71 | +.close:focus { | |
72 | + color: #f44336; | |
73 | + cursor: pointer; | |
74 | +} | |
75 | + | |
76 | + | |
77 | +/* Clear floats */ | |
78 | + | |
79 | +.clearfix::after { | |
80 | + content: ""; | |
81 | + clear: both; | |
82 | + display: table; | |
83 | +} | |
84 | + | |
85 | + | |
86 | +/* Change styles for cancel button and delete button on extra small screens */ | |
87 | + | |
88 | +@media screen and (max-width: 300px) { | |
89 | + .modal-btn { | |
90 | + width: 100%; | |
91 | + } | |
92 | +} | |
0 | 93 | \ No newline at end of file | ... | ... |
src/core/pyros_django/user_manager/static/user_manager/js/user_detail.js
0 โ 100644
... | ... | @@ -0,0 +1,12 @@ |
1 | +function changeActiveRole() { | |
2 | + csrf_value = $("[name='csrfmiddlewaretoken']").val(); | |
3 | + console.log($("#change_active_role").attr('action')); | |
4 | + $.post($("#change_active_role").attr('action'), { "role": $("#selected_role option:selected").val(), csrfmiddlewaretoken: csrf_value }, function(data) { | |
5 | + $("#has_changed").html("").append(data); | |
6 | + }); | |
7 | + | |
8 | +} | |
9 | + | |
10 | +$("#selected_role").change(function(event) { | |
11 | + changeActiveRole(); | |
12 | +}); | |
0 | 13 | \ No newline at end of file | ... | ... |
src/core/pyros_django/user_manager/templates/user_manager/base_home.html
1 | -{% load bootstrap3 %} | |
2 | - | |
3 | -{% bootstrap_css %} | |
4 | - | |
5 | -<!DOCTYPE html> | |
6 | -<html lang="en"> | |
7 | - <head> | |
8 | - {% load staticfiles %} | |
9 | - | |
10 | - <meta charset="utf-8"> | |
11 | - <meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
12 | - <meta name="viewport" content="width=device-width, initial-scale=1"> | |
13 | - <meta name="description" content=""> | |
14 | - <meta name="author" content=""> | |
15 | - | |
16 | - <title>Pyros - SVOM</title> | |
17 | - </head> | |
18 | - | |
19 | - <body> | |
20 | - | |
21 | - | |
22 | - | |
23 | - <div class="container" style="padding-top: 50px;"> | |
24 | - | |
25 | - <center> | |
26 | - | |
27 | - | |
28 | - <div class="row"> | |
29 | - | |
30 | - | |
31 | - <div class="jumbotron"> | |
32 | - <a href="/"> | |
33 | - <h2>Welcome to Pyros : the French GTF Control Center</h2> | |
34 | - </a> | |
35 | - </div> | |
36 | - | |
37 | - <hr> | |
38 | - | |
39 | - | |
40 | - | |
41 | - | |
42 | - <div class="row"> | |
43 | - {% if error %} | |
44 | - <div class="alert alert-dismissable alert-danger"> | |
45 | - {{message}} | |
46 | - {% endif %} | |
47 | - {% if success %} | |
48 | - <div class="alert alert-dismissable alert-success"> | |
49 | - {{message}} | |
50 | - {% endif %} | |
51 | - | |
52 | - </div> | |
53 | - | |
54 | - </div> | |
55 | - | |
56 | - | |
57 | - {% block content %} | |
58 | - | |
59 | - | |
60 | - {% endblock %} | |
61 | - | |
62 | - </div> | |
63 | - <div class="row"> | |
64 | - <p><br/></p> | |
65 | - </div> | |
66 | - <div class="row"> | |
67 | - <div class="col-lg-12 text-center" > | |
68 | - OBSERVATOIRE MIDI-PYRENEES - 14, avenue Edouard Belin - 31400 TOULOUSE | |
69 | - Tรฉl. +33 (0)5 61 33 29 29 - Fax : +33 (0)5 61 33 28 88 | |
70 | - Copyright ยฉ 2016 OMP - Tous droits rรฉservรฉs. | |
71 | - Service web OMP - Mentions lรฉgales | |
72 | - </div> | |
73 | - </div> | |
74 | - <div class="row"> | |
75 | - <p><br/></p> | |
76 | - </div> | |
77 | - | |
78 | - </div> | |
79 | - | |
80 | - </center> | |
81 | - | |
82 | - </div> | |
83 | - | |
84 | - | |
85 | - | |
86 | - | |
87 | - | |
88 | - | |
89 | - <!-- Bootstrap core JavaScript | |
90 | - ================================================== --> | |
91 | - <!-- Placed at the end of the document so the pages load faster --> | |
92 | - <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script> | |
93 | - | |
94 | - </body> | |
1 | +{% load bootstrap3 %} | |
2 | + | |
3 | +{% bootstrap_css %} | |
4 | + | |
5 | +<!DOCTYPE html> | |
6 | +<html lang="en"> | |
7 | + <head> | |
8 | + {% load staticfiles %} | |
9 | + | |
10 | + <meta charset="utf-8"> | |
11 | + <meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
12 | + <meta name="viewport" content="width=device-width, initial-scale=1"> | |
13 | + <meta name="description" content=""> | |
14 | + <meta name="author" content=""> | |
15 | + | |
16 | + <title>Pyros</title> | |
17 | + </head> | |
18 | + | |
19 | + <body> | |
20 | + | |
21 | + | |
22 | + | |
23 | + <div class="container" style="padding-top: 50px;"> | |
24 | + | |
25 | + <center> | |
26 | + | |
27 | + | |
28 | + <div class="row"> | |
29 | + | |
30 | + | |
31 | + <div class="jumbotron"> | |
32 | + <a href="/"> | |
33 | + <h2>Welcome to Pyros</h2> | |
34 | + </a> | |
35 | + </div> | |
36 | + | |
37 | + <hr> | |
38 | + | |
39 | + | |
40 | + | |
41 | + | |
42 | + <div class="row"> | |
43 | + {% if error %} | |
44 | + <div class="alert alert-dismissable alert-danger"> | |
45 | + {{message}} | |
46 | + {% endif %} | |
47 | + {% if success %} | |
48 | + <div class="alert alert-dismissable alert-success"> | |
49 | + {{message}} | |
50 | + {% endif %} | |
51 | + | |
52 | + </div> | |
53 | + | |
54 | + </div> | |
55 | + | |
56 | + | |
57 | + {% block content %} | |
58 | + | |
59 | + | |
60 | + {% endblock %} | |
61 | + | |
62 | + </div> | |
63 | + <div class="row"> | |
64 | + <p><br/></p> | |
65 | + </div> | |
66 | + <div class="row"> | |
67 | + <div class="col-lg-12 text-center" > | |
68 | + OBSERVATOIRE MIDI-PYRENEES - 14, avenue Edouard Belin - 31400 TOULOUSE | |
69 | + Tรฉl. +33 (0)5 61 33 29 29 - Fax : +33 (0)5 61 33 28 88 | |
70 | + Copyright ยฉ 2016 OMP - Tous droits rรฉservรฉs. | |
71 | + Service web OMP - Mentions lรฉgales | |
72 | + </div> | |
73 | + </div> | |
74 | + <div class="row"> | |
75 | + <p><br/></p> | |
76 | + </div> | |
77 | + | |
78 | + </div> | |
79 | + | |
80 | + </center> | |
81 | + | |
82 | + </div> | |
83 | + | |
84 | + | |
85 | + | |
86 | + | |
87 | + | |
88 | + | |
89 | + <!-- Bootstrap core JavaScript | |
90 | + ================================================== --> | |
91 | + <!-- Placed at the end of the document so the pages load faster --> | |
92 | + <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script> | |
93 | + | |
94 | + </body> | |
95 | 95 | </html> |
96 | 96 | \ No newline at end of file | ... | ... |
src/core/pyros_django/user_manager/templates/user_manager/home_user_creation.html
1 | - | |
2 | - {% extends "user_manager/base_home.html" %} | |
3 | - | |
4 | - {% block content %} | |
5 | - | |
6 | - | |
7 | - <div class="form-group"> | |
8 | - | |
9 | - | |
10 | - <form action="{% url "user_signup_validation" %}" method="post" enctype="multipart/form-data"> | |
11 | - {% csrf_token %} | |
12 | - <div class="col-lg-3 text-left" > | |
13 | - <p></p> | |
14 | - </div> | |
15 | - <div class="col-lg-6 text-left" > | |
16 | - <div class="row"> | |
17 | - <h3>Subscription to Pyros</h3> | |
18 | - <hr> | |
19 | - </div> | |
20 | - {% for field in form %} | |
21 | - <div class="row"> | |
22 | - | |
23 | - <label> {{ field.label_tag }} {% if field.field.required %} *{% endif %} </label> | |
24 | - | |
25 | - {{ field }} | |
26 | - {{ field.errors }} | |
27 | - <br/> | |
28 | - </div> | |
29 | - {% endfor %} | |
30 | - <br> | |
31 | - <p>Once validated, your subscription will be sent to our team.</p> | |
32 | - <p>You will be given an answer by email.</p> | |
33 | - | |
34 | - <p><input type="submit" class="btn btn-primary" value="Send subscription request" /></p> | |
35 | - </div> | |
36 | - </form> | |
37 | - | |
38 | - </div> | |
39 | - | |
40 | - | |
41 | - | |
42 | - | |
43 | - {% endblock %} | |
1 | + | |
2 | + {% extends "user_manager/base_home.html" %} | |
3 | + {% load static %} | |
4 | + {% block content %} | |
5 | + | |
6 | + <div class="form-group"> | |
7 | + | |
8 | + | |
9 | + <form action="{% url "user_signup_validation" %}" method="post" enctype="multipart/form-data"> | |
10 | + {% csrf_token %} | |
11 | + {% if next %} | |
12 | + <input class="form-control" type="hidden" name="next" value="{{ next }}" /> | |
13 | + {% endif %} | |
14 | + <div class="col-lg-3 text-left" > | |
15 | + <p></p> | |
16 | + </div> | |
17 | + <div class="col-lg-6 text-left" > | |
18 | + <div class="row"> | |
19 | + <h3>Subscription to Pyros</h3> | |
20 | + <hr> | |
21 | + </div> | |
22 | + {% for field in form %} | |
23 | + <div class="row"> | |
24 | + | |
25 | + <label> {{ field.label_tag }} {% if field.field.required %} *{% endif %} </label> | |
26 | + {% if "role" in field.label_tag %} | |
27 | + <a href="{% url "roles_description" %}" target="_blank" rel="noopener noreferrer"> <img class="bi bi-info-circle" width="20" heigth="20" src="{% static "media/info-circle.svg" %}"/> </a> | |
28 | + {% endif %} | |
29 | + </div> | |
30 | + <div class="row"> | |
31 | + {{ field }} | |
32 | + {{ field.errors }} | |
33 | + </div> | |
34 | + <br/> | |
35 | + {% endfor %} | |
36 | + <br> | |
37 | + <p>Once validated, your subscription will be sent to our team.</p> | |
38 | + <p>You will be given an answer by email.</p> | |
39 | + | |
40 | + <p><input type="submit" class="btn btn-primary" value="Send subscription request" /></p> | |
41 | + </div> | |
42 | + </form> | |
43 | + | |
44 | + </div> | |
45 | + | |
46 | + | |
47 | + | |
48 | + | |
49 | + {% endblock %} | ... | ... |
src/core/pyros_django/user_manager/templates/user_manager/password_reset.html
0 โ 100644
... | ... | @@ -0,0 +1,22 @@ |
1 | +{% extends 'base.html' %} | |
2 | +{% block content %} | |
3 | + | |
4 | +<div class="text-center" style="width: 80%; margin: 0 auto"> | |
5 | + <h1>Welcome to the Password Reset Page</h1> | |
6 | + <h3> | |
7 | + Forgot your password? Please enter the email address you used to register | |
8 | + with us and we will send you a link to reset your password | |
9 | + </h3> | |
10 | +</div> | |
11 | +<br/> | |
12 | + | |
13 | +<form action="" method="POST" class="text-center"> | |
14 | + {% csrf_token %} | |
15 | + {{form}} | |
16 | + <input type="submit" value="Send email" /><br> | |
17 | +</form><br/> | |
18 | +<div class="text-center"> | |
19 | + <a href="{% url 'index' %}">Return to home page</a> | |
20 | +</div> | |
21 | + | |
22 | +{% endblock%} | |
0 | 23 | \ No newline at end of file | ... | ... |
src/core/pyros_django/user_manager/templates/user_manager/password_reset_complete.html
0 โ 100644
... | ... | @@ -0,0 +1,13 @@ |
1 | +{% extends 'base_unlogged.html' %} | |
2 | +{% block content%} | |
3 | +<div class="text-center" style="width: 80%; margin: 0 auto"> | |
4 | + <h1>Password reset complete</h1> | |
5 | + <h6 style="width: 60%; margin: 0 auto"> | |
6 | + Your Password has been set. You may go ahead and login | |
7 | + </h6> | |
8 | +</div> | |
9 | +<br /> | |
10 | +<div class="text-center"> | |
11 | + <a href="{% url 'user_signin' %}">Login</a> | |
12 | +</div> | |
13 | +{% endblock%} | |
0 | 14 | \ No newline at end of file | ... | ... |
src/core/pyros_django/user_manager/templates/user_manager/password_reset_confirm.html
0 โ 100644
... | ... | @@ -0,0 +1,16 @@ |
1 | +{% extends 'base_unlogged.html' %} | |
2 | +{% block content%} | |
3 | +<div class="text-center" style="width: 80%; margin: 0 auto"> | |
4 | + <h1>Password Reset Form</h1> | |
5 | + <h6 style="width: 60%; margin: 0 auto"> | |
6 | + Please enter your new password so we can verify. | |
7 | + </h6> | |
8 | +</div> | |
9 | +<br /> | |
10 | +<form action="" method="POST"> | |
11 | + {% csrf_token %} | |
12 | + {{form}} | |
13 | + <input type="submit" value="Reset Password"/> | |
14 | +</form> | |
15 | + | |
16 | +{% endblock%} | |
0 | 17 | \ No newline at end of file | ... | ... |
src/core/pyros_django/user_manager/templates/user_manager/password_reset_done.html
0 โ 100644
... | ... | @@ -0,0 +1,11 @@ |
1 | +{% extends 'base_unlogged.html' %} | |
2 | +{% block content%} | |
3 | +<div class="text-center" style="width: 80%; margin: 0 auto"> | |
4 | + <h1>Password reset sent</h1> | |
5 | + <h5>Weโve emailed you instructions for setting your password, if an account exists with the email you entered. You should receive them shortly.</h5><br> | |
6 | + <h6 style="width: 60%; margin: 0 auto">If you donโt receive an email, please make sure youโve entered the address you registered with, and check your spam folder.</h6> | |
7 | +</div> | |
8 | +<div class="text-center"> | |
9 | + <a href="{% url 'index' %}">Return to home page</a> | |
10 | +</div> | |
11 | +{% endblock%} | |
0 | 12 | \ No newline at end of file | ... | ... |
src/core/pyros_django/user_manager/templates/user_manager/password_reset_email.html
0 โ 100644
... | ... | @@ -0,0 +1,13 @@ |
1 | +{% autoescape off %} | |
2 | +To initiate the password reset process for your {{ user.get_username }} PyROS Account, | |
3 | +click the link below: | |
4 | + | |
5 | +{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %} | |
6 | + | |
7 | +If clicking the link above doesn't work, please copy and paste the URL in a new browser | |
8 | +window instead. | |
9 | + | |
10 | +Sincerely, | |
11 | + | |
12 | +PyROS Control Center | |
13 | +{% endautoescape %} | |
0 | 14 | \ No newline at end of file | ... | ... |
src/core/pyros_django/user_manager/templates/user_manager/roles_description.html
0 โ 100644
... | ... | @@ -0,0 +1,48 @@ |
1 | +{% extends "user_manager/base_home.html" %} | |
2 | +{% block content %} | |
3 | + | |
4 | + <table class="table table-bordered"> | |
5 | + <thead> | |
6 | + <tr> | |
7 | + <th>Role</th> | |
8 | + <th>Description</th> | |
9 | + </thead> | |
10 | + </tr> | |
11 | + <tbody> | |
12 | + <tr> | |
13 | + <td>Admin</td> | |
14 | + <td>User with all authorizations, can access to Django admin pages.</td> | |
15 | + </tr> | |
16 | + <tr> | |
17 | + <td>Observer</td> | |
18 | + <td>User that can create a scientific program or be an member of an scientific program to do observations.</td> | |
19 | + </tr> | |
20 | + <tr> | |
21 | + <td>TAC</td> | |
22 | + <td>Time Allocation Comity. User that will give his opinion about proposals (i.e. scientific programs that has been submitted by an Observer but not accepted by the Unit PI).</td> | |
23 | + </tr> | |
24 | + <tr> | |
25 | + <td>Management board member</td> | |
26 | + <td>User that represents an Institute.</td> | |
27 | + </tr> | |
28 | + <tr> | |
29 | + <td>Operator</td> | |
30 | + <td>User that is assigned to the maintenance of an Unit.</td> | |
31 | + </tr> | |
32 | + <tr> | |
33 | + <td>Unit-PI</td> | |
34 | + <td>Principal Investigator of the Unit.</td> | |
35 | + </tr> | |
36 | + <tr> | |
37 | + <td>Unit board</td> | |
38 | + <td>Help the Unit-PI to manage the unit.</td> | |
39 | + </tr> | |
40 | + <tr> | |
41 | + <td>Visitor</td> | |
42 | + <td>User without any privileges.</td> | |
43 | + </tr> | |
44 | + </tbody> | |
45 | + | |
46 | +</table> | |
47 | + | |
48 | +{% endblock %} | |
0 | 49 | \ No newline at end of file | ... | ... |
src/core/pyros_django/user_manager/templates/user_manager/user_detail.html
0 โ 100644
... | ... | @@ -0,0 +1,107 @@ |
1 | +{% extends "base.html" %} | |
2 | + | |
3 | +{% block content %} | |
4 | +{% load static %} | |
5 | +{% load tags %} | |
6 | +<link rel="stylesheet" type="text/css" href="{% static 'user_manager/css/user_detail.css' %}"> | |
7 | +<script src="{% static "user_manager/js/user_detail.js" %}" defer></script> | |
8 | +<link rel="stylesheet" type="text/css" href="{% static '/css/global.css' %}"> | |
9 | +<script src="{% static "/js/global.js" %}" defer></script> | |
10 | + | |
11 | + <h2>User : </h2> | |
12 | + <br> <br> | |
13 | + <p><strong>Name : </strong> {{ user.first_name }} {{ user.last_name }}</p> | |
14 | + <p><strong>Email : </strong> {{user.email }}</p> | |
15 | + <p><strong>Country : </strong>{{ user.country }}</p> | |
16 | + <p><strong>Role(s) : </strong>{{ user.get_roles_str }}</p> | |
17 | + {% if current_user.id is user.id %} | |
18 | + <p><strong>Active role : </strong> | |
19 | + {% if roles|length == 1 %} | |
20 | + {{ request.session.role }} | |
21 | + {% else %} | |
22 | + {# user visiting his own page to change active role #} | |
23 | + <form id="change_active_role" action="{% url 'set_active_role' %}" method="POST"> | |
24 | + {% csrf_token %} | |
25 | + <select id="selected_role" class="form-select" name="selected_role"> | |
26 | + {% for role in roles %} | |
27 | + {% if role == request.session.role %} | |
28 | + <option value="{{role}}" selected>{{role}}</option> | |
29 | + {% else %} | |
30 | + <option value="{{role}}">{{role}}</option> | |
31 | + {% endif %} | |
32 | + {% endfor %} | |
33 | + </select> | |
34 | + </form> | |
35 | + {# will display a text if changing role succeed #} | |
36 | + <p id="has_changed"></p> | |
37 | + {% endif %} | |
38 | + {% endif %} | |
39 | + <p><strong>Role Description : </strong>{{ user.get_max_priority_desc }}</p> | |
40 | + {% comment %} | |
41 | + <p><strong>Role Priority : </strong>{{ user.get_priority }}</p> | |
42 | + <p><strong>Max Level Quota : </strong>{{ user.get_max_priority_quota }}</p> | |
43 | + <p><strong>Description : </strong>{{ user.desc }}</p> | |
44 | + {% endcomment %} | |
45 | + <p><strong>Telephone : </strong>{{ user.tel }}</p> | |
46 | + <p><strong>Laboratory : </strong>{{ user.laboratory }}</p> | |
47 | + <p><strong>Address : </strong>{{ user.address }}</p> | |
48 | + <p><strong>Institute : </strong>{{ user.institute }}</p> | |
49 | + {% comment %} | |
50 | + <p><strong>Last connection : </strong>{{ user.last_connect }}</p> | |
51 | + <p><strong>Current connection : </strong>{{ user.cur_connect }}</p> | |
52 | + <p><strong>Put validation beginning : </strong>{{ user.putvalid_beg }}</p> | |
53 | + <p><strong>Put validation end : </strong>{{ user.putvalid_end }}</p> | |
54 | + <p><strong>Quota : </strong>{{ user.quota }}</p> | |
55 | + {% endcomment %} | |
56 | + {% if scientific_programs|length > 0 %} | |
57 | + <p><strong>Scientific Program(s) : </strong> <table class="table table-bordered table-hover table-striped" style="font-family: 'Montserra', sans-serif;"> | |
58 | + | |
59 | + <thead> | |
60 | + <tr> | |
61 | + <th>Scientific Program</th> | |
62 | + </tr> | |
63 | + </thead> | |
64 | + | |
65 | + <tbody> | |
66 | + {% for sp in scientific_programs %} | |
67 | + <tr> | |
68 | + <td> <a href="{% url "detail_scientific_program" sp.pk %}">{{ sp }} </a></td> | |
69 | + </tr> | |
70 | + {% endfor %} | |
71 | + </tbody> | |
72 | + </table></p> | |
73 | + {% endif %} | |
74 | + {% if current_user.id is user.id or USER_LEVEL|ifinlist:"Admin,Unit-PI,Unit board"%} | |
75 | + <p><strong>Validator : </strong>{{ user.validator }}</p> | |
76 | + {% if user.motive_of_registration|length > 0 %} | |
77 | + <p><strong>Motive of registration : </strong>{{ user.motive_of_registration }}</p> | |
78 | + {% endif %} | |
79 | + <a href="{% url "user-edit" user.pk %}" class="btn btn-info" role="button">Edit</a> | |
80 | + {% if USER_LEVEL|ifinlist:"Admin,Unit-PI,Unit board" %} | |
81 | + {% if not is_last_user or not user.is_superuser%} | |
82 | + <a href="{% url "change_activate" user.pk current_user.id %}" class="btn btn-danger" role="button">{% active_account user.pk %} </a> | |
83 | + {% endif %} | |
84 | + <button type="button" class="btn btn-danger open-modal" id="open_modal_delete">Delete</button> | |
85 | + {# start of modal #} | |
86 | + <div id="modal_delete"> | |
87 | + <span id="close_modal_delete" class="close">x</span> | |
88 | + | |
89 | + <form class="modal-content" action="{% url 'user-delete' user.id %}" method="post"> | |
90 | + {% csrf_token %} | |
91 | + <div class="container"> | |
92 | + <h1> Delete Account </h1> | |
93 | + <p>Are you sure you want to delete this account?</p> | |
94 | + | |
95 | + <div class="clearfix"> | |
96 | + <button type="button" class="btn btn-info" id="cancel_modal_delete_btn">Cancel</button> | |
97 | + <input class="btn btn-danger delete_modal_delete_btn" type="submit" value="Delete user"> | |
98 | + </div> | |
99 | + </div> | |
100 | + </form> | |
101 | + </div> | |
102 | + {# end of modal #} | |
103 | + | |
104 | + {% endif %} | |
105 | + {% endif %} | |
106 | + <a href="{% url "users" %}" class="btn btn-info" role="button">Return to list of users</a> | |
107 | +{% endblock %} | |
0 | 108 | \ No newline at end of file | ... | ... |
src/core/pyros_django/user_manager/templates/user_manager/user_detail_edit.html
0 โ 100644
... | ... | @@ -0,0 +1,40 @@ |
1 | +{% extends "base.html" %} | |
2 | +{% load tags %} | |
3 | +{% block content %} | |
4 | +<form id="siteForm" action="" method="post"> | |
5 | + {% csrf_token %} | |
6 | + {{ form.as_p }} | |
7 | + {% if current_user.id is user.id or USER_LEVEL|ifinlist:"Admin,Unit-PI,Unit board" %} | |
8 | + <label> Roles : </label> | |
9 | + {% for role in roles %} | |
10 | + <br> | |
11 | + {% comment %} | |
12 | + input name is the same for all role so we can retrieve a list of selected values | |
13 | + {% endcomment %} | |
14 | + {# if user is sp_pi, he can have the "unit board" role #} | |
15 | + {% if role.name == "Unit board" and is_sp_pi %} | |
16 | + | |
17 | + {% if role.name in user_edit.get_roles_str %} | |
18 | + <input type="checkbox" checked id="{{role.name}}" name="roles" value="{{role.id}}"> | |
19 | + <label for="{{role.name}}">{{role.name}}</label> | |
20 | + {% else %} | |
21 | + <input type="checkbox" id="{{role.name}}" name="roles" value="{{role.id}}"> | |
22 | + <label for="{{role.name}}">{{role.name}}</label> | |
23 | + {% endif %} | |
24 | + {% else %} | |
25 | + {% if role.name in user_edit.get_roles_str %} | |
26 | + <input type="checkbox" checked id="{{role.name}}" name="roles" value="{{role.id}}"> | |
27 | + <label for="{{role.name}}">{{role.name}}</label> | |
28 | + {% else %} | |
29 | + <input type="checkbox" id="{{role.name}}" name="roles" value="{{role.id}}"> | |
30 | + <label for="{{role.name}}">{{role.name}}</label> | |
31 | + {% endif %} | |
32 | + {% endif %} | |
33 | + {% endfor %} | |
34 | + {% endif %} | |
35 | + <br> | |
36 | + <input id="Update" class="btn btn-info" type="submit" value="Update" /> | |
37 | + <a href="{% url "user_detail" pk %}" class="btn btn-info" role="button">Cancel</a> | |
38 | +</form> | |
39 | +<a href="{% url "password_reset" %}" class="btn btn-info" role="button">Reset password</a> | |
40 | +{% endblock %} | |
0 | 41 | \ No newline at end of file | ... | ... |
src/core/pyros_django/user_manager/templates/user_manager/users_management.html
0 โ 100644
... | ... | @@ -0,0 +1,89 @@ |
1 | +{% extends "base.html" %} | |
2 | +{% load tags %} | |
3 | +{% block title %} | |
4 | + PYROS USERS MANAGEMENT | |
5 | +{% endblock %} | |
6 | + | |
7 | +{% block content %} | |
8 | +<style> | |
9 | + #div_users { | |
10 | + padding-left: 5%; | |
11 | + padding-top: 5%; | |
12 | + } | |
13 | + a { | |
14 | + color: inherit; | |
15 | + } | |
16 | +</style> | |
17 | + | |
18 | +<div id="div_users"class="row"> | |
19 | + <h3>List of active users </h3> | |
20 | + {% if user.get_priority >= 6 %} | |
21 | + <a href="{% url "create_user" %}" class="btn btn-info" role="button">Create new user </a> | |
22 | + {% endif %} | |
23 | + <div class="table-responsive"> | |
24 | + <table class="table table-bordered table-hover table-striped tablesorter" style="font-family: 'Montserra', sans-serif;"> | |
25 | + <thead> | |
26 | + <tr> | |
27 | + <th>Name <i class="fa fa-sort"></i></th> | |
28 | + <th>Roles</th> | |
29 | + <th>Laboratory </th> | |
30 | + <th colspan="{{ nb_of_scientific_program }}">Scientific programs</th> | |
31 | + </tr> | |
32 | + </thead> | |
33 | + <tbody> | |
34 | + {% for field in pyros_users_with_roles %} | |
35 | + <tr> | |
36 | + <td> <a href="{% url "user_detail" field.pk %}"> {{ field.username }} </a></td> | |
37 | + <td>{{ field.get_roles_str}}</td> | |
38 | + <td> {{ field.laboratory }} </td> | |
39 | + <td> {{field.get_scientific_programs_str }}</td> | |
40 | + {% comment %} | |
41 | + {% for sp in field.scientific_programs.all %} | |
42 | + | |
43 | + {% if forloop.last and forloop.counter < nb_of_scientific_program %} | |
44 | + {% comment "" %} | |
45 | + we need to fill the remaining colspan size | |
46 | + | |
47 | + | |
48 | + | |
49 | + {% else %} | |
50 | + {% endif %} | |
51 | + <td> <a href="{% url "detail_scientific_program" sp.pk %}"> {{ sp }} </a> </td> | |
52 | + {% endfor %} | |
53 | + {% endcomment %} | |
54 | + | |
55 | + </td> | |
56 | + </tr> | |
57 | + {% endfor %} | |
58 | + </tbody> | |
59 | + </table> | |
60 | + </div> | |
61 | +</div> | |
62 | +{% if pyros_users_without_roles.count > 0 %} | |
63 | +<div id="div_users"class="row"> | |
64 | + <h3>List of users that need role assignation </h3> | |
65 | + <div class="table-responsive"> | |
66 | + <table class="table table-bordered table-hover table-striped tablesorter" style="font-family: 'Montserra', sans-serif;"> | |
67 | + <thead> | |
68 | + <tr> | |
69 | + <th>Name <i class="fa fa-sort"></i></th> | |
70 | + <th>Roles</th> | |
71 | + <th>Laboratory </th> | |
72 | + </tr> | |
73 | + </thead> | |
74 | + <tbody> | |
75 | + {% for field in pyros_users_without_roles %} | |
76 | + <tr> | |
77 | + <td> <a href="{% url "user_detail" field.pk %}"> {{ field.username }} </a></td> | |
78 | + <td>{{ field.get_roles_str}}</td> | |
79 | + <td> {{ field.laboratory }} </td> | |
80 | + | |
81 | + </td> | |
82 | + </tr> | |
83 | + {% endfor %} | |
84 | + </tbody> | |
85 | + </table> | |
86 | + </div> | |
87 | +</div> | |
88 | +{% endif %} | |
89 | +{% endblock %} | |
0 | 90 | \ No newline at end of file | ... | ... |
src/core/pyros_django/user_manager/tests.py
1 | -from django.test import TestCase | |
2 | -from common.models import * | |
3 | -from django.contrib.auth.models import User | |
4 | - | |
5 | - | |
6 | - | |
7 | -class UserManagerTests(TestCase): | |
8 | - | |
9 | - def setUp(self): | |
10 | - UserLevel.objects.create(name="Visitor",desc="Visitor description",priority=0,quota=0.0) | |
11 | - UserLevel.objects.create(name="PI",desc="PI description",priority=5,quota=100.0) | |
12 | - UserLevel.objects.create(name="SysAdmin",desc="SysAdmin description",priority=7,quota=1000.0) | |
13 | - Country.objects.create() | |
14 | - self.assertEqual(PyrosUser.objects.count(), 0, "There should be no User") | |
15 | - path = "/user_manager/creation_validate" | |
16 | - response = self.client.post(path, {"email": "toto@titi.fr", "password": "aze", "password_confirm": "aze", | |
17 | - "first_name": "toto", "last_name": "titi", "tel": "0123456789", | |
18 | - "laboratory": "IRAP", "address": "ici"}) | |
19 | - self.assertTrue("success" in response.context.keys(), "There should be a success") | |
20 | - self.assertEqual(PyrosUser.objects.count(), 1, "Theroue shld be one User") | |
21 | - | |
22 | - def test_creation(self): | |
23 | - self.assertEqual(Country.objects.count(), 1, "There should be 1 Country") | |
24 | - self.assertEqual(UserLevel.objects.count(), 3, "There should be 3 UserLevel") | |
25 | - | |
26 | - self.assertEqual(PyrosUser.objects.all()[0].first_name, 'toto') | |
27 | - self.assertEqual(PyrosUser.objects.all()[0].email, 'toto@titi.fr') | |
28 | - self.assertEqual(PyrosUser.objects.all()[0].user_level.filter(name="Visitor").count(),1,"There should be one UserLevel (=Visitor)") | |
29 | - | |
30 | - def test_login(self): | |
31 | - self.assertEqual(Country.objects.count(), 1, "There should be 1 Country") | |
32 | - self.assertEqual(UserLevel.objects.count(), 3, "There should be 3 UserLevel") | |
33 | - | |
34 | - # Activate user | |
35 | - # La variable qui rรฉgit l'activation d'un compte est contenue dans pyrosUsers | |
36 | - # et s'appelle is_active, il suffit de passer cette variable ร True | |
37 | - current_user = PyrosUser.objects.all()[0] | |
38 | - current_user.is_active=True | |
39 | - current_user.save() | |
40 | - self.assertEqual(PyrosUser.objects.all()[0].is_active, True, "user should be active") | |
41 | - | |
42 | - # Log user | |
43 | - path = "/user_manager/login" | |
44 | - response = self.client.post(path, {"email": "toto@titi.fr", "password": "aze"}) | |
45 | - self.assertTrue(response.context.get("success")) | |
46 | - self.assertIn('_auth_user_id', self.client.session, "The user should be logged in") | |
47 | - | |
48 | - def test_login_not_active(self): | |
49 | - self.assertEqual(Country.objects.count(), 1, "There should be 1 Country") | |
50 | - self.assertEqual(UserLevel.objects.count(), 3, "There should be 3 UserLevel") | |
51 | - | |
52 | - # Activate user | |
53 | - # La variable qui rรฉgit l'activation d'un compte est contenue dans pyrosUsers | |
54 | - # et s'appelle is_active, il suffit de passer cette variable ร True | |
55 | - | |
56 | - self.assertEqual(PyrosUser.objects.all()[0].is_active, False, "user should not be active") | |
57 | - | |
58 | - # Log user | |
59 | - path = "/user_manager/login" | |
60 | - response = self.client.post(path, {"email": "toto@titi.fr", "password": "aze"}) | |
61 | - | |
62 | - self.assertFalse(response.context.get("success")) | |
63 | - self.assertNotIn('_auth_user_id', self.client.session, "The user should be logged in") | |
64 | - | |
65 | - def test_wrong_email(self): | |
66 | - path = "/user_manager/login" | |
67 | - response = self.client.post(path, {"email": "toto@tti.fr", "password": "aze"}) | |
68 | - self.assertIn("error", response.context.keys(), "There should be an error") | |
69 | - self.assertNotIn('_auth_user_id', self.client.session, "There shouldn't be an authentified user") | |
70 | - | |
71 | - def test_wrong_password(self): | |
72 | - path = "/user_manager/login" | |
73 | - response = self.client.post(path, {"email": "toto@titi.fr", "password": "azee"}) | |
74 | - self.assertIn("error", response.context.keys(), "There should be an error") | |
75 | - self.assertNotIn('_auth_user_id', self.client.session, "There shouldn't be an authentified user") | |
76 | - | |
77 | - def test_logout(self): | |
78 | - self.client.login(username="toto@titi.fr", password="aze") | |
79 | - path = "/user_manager/logout" | |
80 | - self.client.get(path) | |
81 | - self.assertNotIn('_auth_user_id', self.client.session, "There shouldn't be an authentified user") | |
82 | - | |
83 | - def test_get_user_priority(self): | |
84 | - user = PyrosUser.objects.all()[0] | |
85 | - # add PI role to user | |
86 | - UserLevel.objects.get(name="PI").pyros_users.add(user) | |
87 | - self.assertEqual(user.get_priority(),UserLevel.objects.get(name="PI").priority,"The priority should be equal to PI's priority") | |
88 | - | |
89 | - def test_wrong_get_user_priority(self): | |
90 | - user = PyrosUser.objects.all()[0] | |
91 | - # add PI role to user | |
92 | - UserLevel.objects.get(name="PI").pyros_users.add(user) | |
93 | - self.assertNotEqual(user.get_priority(),UserLevel.objects.get(name="Visitor").priority,"The priority shouldn't be equal to Visitor's priority") | |
94 | - | |
95 | - def test_get_roles_str(self): | |
96 | - user = PyrosUser.objects.all()[0] | |
97 | - # add PI role to user | |
98 | - UserLevel.objects.get(name="PI").pyros_users.add(user) | |
99 | - roles_str = user.get_roles_str() | |
100 | - for role in user.user_level.all(): | |
101 | - self.assertIn(role.name,roles_str,f"The role {role} should be in the str representation") | |
102 | - | |
103 | - def test_wrong_get_roles_str(self): | |
104 | - user = PyrosUser.objects.all()[0] | |
105 | - # add PI role to user | |
106 | - UserLevel.objects.get(name="PI").pyros_users.add(user) | |
107 | - roles_str = user.get_roles_str() | |
108 | - self.assertNotIn(UserLevel.objects.get(name="SysAdmin").name,roles_str,"The role SysAdmin shouldn't be in the str representation") | |
109 | - | |
110 | - def test_max_priority_desc(self): | |
111 | - user = PyrosUser.objects.all()[0] | |
112 | - # add PI role to user | |
113 | - UserLevel.objects.get(name="PI").pyros_users.add(user) | |
114 | - self.assertEqual(user.get_max_priority_desc(),UserLevel.objects.get(name="PI").desc,"The desc of user_level should be 'PI description' ") | |
115 | - | |
116 | - def test_wrong_max_priority_desc(self): | |
117 | - user = PyrosUser.objects.all()[0] | |
118 | - # add PI role to user | |
119 | - UserLevel.objects.get(name="PI").pyros_users.add(user) | |
120 | - # add SysAdmin role to user (has a greatier priority than PI and Visitor roles) | |
121 | - UserLevel.objects.get(name="SysAdmin").pyros_users.add(user) | |
122 | - self.assertNotEqual(user.get_max_priority_desc(),UserLevel.objects.get(name="PI").desc,"The desc of user_level shouldn't be 'PI description' ") | |
123 | - | |
124 | - | |
125 | - def test_max_priority_quota(self): | |
126 | - user = PyrosUser.objects.all()[0] | |
127 | - # add PI role to user | |
128 | - UserLevel.objects.get(name="PI").pyros_users.add(user) | |
129 | - self.assertEqual(user.get_max_priority_quota(),UserLevel.objects.get(name="PI").quota,"The quota of user_level should be 100.0 ") | |
130 | - | |
131 | - def test_wrong_max_priority_quota(self): | |
132 | - user = PyrosUser.objects.all()[0] | |
133 | - # add PI role to user | |
134 | - UserLevel.objects.get(name="PI").pyros_users.add(user) | |
135 | - # add SysAdmin role to user (has a greatier priority than PI and Visitor roles) | |
136 | - UserLevel.objects.get(name="SysAdmin").pyros_users.add(user) | |
137 | - self.assertNotEqual(user.get_max_priority_quota(),UserLevel.objects.get(name="PI").desc,"The quota of user_level shouldn't be 1000.0 ") | |
138 | 1 | \ No newline at end of file |
2 | +from django.test import TestCase | |
3 | +from common.models import * | |
4 | +from django.contrib.auth.models import User | |
5 | +from django.urls import reverse | |
6 | + | |
7 | + | |
8 | + | |
9 | +class UserManagerTests(TestCase): | |
10 | + | |
11 | + def setUp(self): | |
12 | + institute = Institute.objects.create(name="CNRS",quota=999.0) | |
13 | + UserLevel.objects.create(name="Visitor",desc="Visitor description",priority=0,quota=0.0) | |
14 | + UserLevel.objects.create(name="Unit-PI",desc="Unit-PI description",priority=5,quota=100.0) | |
15 | + UserLevel.objects.create(name="Admin",desc="Admin description",priority=7,quota=1000.0) | |
16 | + Country.objects.create() | |
17 | + self.assertEqual(PyrosUser.objects.count(), 0, "There should be no User") | |
18 | + path = reverse("user_signup_validation") | |
19 | + response = self.client.post(path, {"email": "toto@titi.fr", "password": "aze", "password_confirm": "aze", | |
20 | + "first_name": "toto", "last_name": "titi", "tel": "0123456789", | |
21 | + "laboratory": "IRAP", "address": "ici","institute":institute.id,"reason":"this is a test", | |
22 | + "roles":"Admin" | |
23 | + }) | |
24 | + | |
25 | + | |
26 | + self.assertTrue("success" in response.context.keys(), "There should be a success") | |
27 | + self.assertEqual(PyrosUser.objects.count(), 1, "Theroue shld be one User") | |
28 | + | |
29 | + def test_creation(self): | |
30 | + self.assertEqual(Country.objects.count(), 1, "There should be 1 Country") | |
31 | + self.assertEqual(UserLevel.objects.count(), 3, "There should be 3 UserLevel") | |
32 | + | |
33 | + self.assertEqual(PyrosUser.objects.all()[0].first_name, 'toto') | |
34 | + self.assertEqual(PyrosUser.objects.all()[0].email, 'toto@titi.fr') | |
35 | + self.assertEqual(PyrosUser.objects.all()[0].user_level.filter(name="Visitor").count(),1,"There should be one UserLevel (=Visitor)") | |
36 | + | |
37 | + def test_login(self): | |
38 | + self.assertEqual(Country.objects.count(), 1, "There should be 1 Country") | |
39 | + self.assertEqual(UserLevel.objects.count(), 3, "There should be 3 UserLevel") | |
40 | + | |
41 | + # Activate user | |
42 | + # La variable qui rรฉgit l'activation d'un compte est contenue dans pyrosUsers | |
43 | + # et s'appelle is_active, il suffit de passer cette variable ร True | |
44 | + current_user = PyrosUser.objects.all()[0] | |
45 | + current_user.is_active=True | |
46 | + current_user.save() | |
47 | + self.assertEqual(PyrosUser.objects.all()[0].is_active, True, "user should be active") | |
48 | + | |
49 | + # Log user | |
50 | + path = "/user_manager/login" | |
51 | + response = self.client.post(path, {"email": "toto@titi.fr", "password": "aze"}) | |
52 | + self.assertTrue(response.context.get("success")) | |
53 | + self.assertIn('_auth_user_id', self.client.session, "The user should be logged in") | |
54 | + | |
55 | + def test_login_not_active(self): | |
56 | + self.assertEqual(Country.objects.count(), 1, "There should be 1 Country") | |
57 | + self.assertEqual(UserLevel.objects.count(), 3, "There should be 3 UserLevel") | |
58 | + | |
59 | + # Activate user | |
60 | + # La variable qui rรฉgit l'activation d'un compte est contenue dans pyrosUsers | |
61 | + # et s'appelle is_active, il suffit de passer cette variable ร True | |
62 | + | |
63 | + self.assertEqual(PyrosUser.objects.all()[0].is_active, False, "user should not be active") | |
64 | + | |
65 | + # Log user | |
66 | + path = "/user_manager/login" | |
67 | + response = self.client.post(path, {"email": "toto@titi.fr", "password": "aze"}) | |
68 | + | |
69 | + self.assertFalse(response.context.get("success")) | |
70 | + self.assertNotIn('_auth_user_id', self.client.session, "The user should be logged in") | |
71 | + | |
72 | + def test_wrong_email(self): | |
73 | + path = "/user_manager/login" | |
74 | + response = self.client.post(path, {"email": "toto@tti.fr", "password": "aze"}) | |
75 | + self.assertIn("error", response.context.keys(), "There should be an error") | |
76 | + self.assertNotIn('_auth_user_id', self.client.session, "There shouldn't be an authentified user") | |
77 | + | |
78 | + def test_wrong_password(self): | |
79 | + path = "/user_manager/login" | |
80 | + response = self.client.post(path, {"email": "toto@titi.fr", "password": "azee"}) | |
81 | + self.assertIn("error", response.context.keys(), "There should be an error") | |
82 | + self.assertNotIn('_auth_user_id', self.client.session, "There shouldn't be an authentified user") | |
83 | + | |
84 | + def test_logout(self): | |
85 | + self.client.login(username="toto@titi.fr", password="aze") | |
86 | + path = "/user_manager/logout" | |
87 | + self.client.get(path) | |
88 | + self.assertNotIn('_auth_user_id', self.client.session, "There shouldn't be an authentified user") | |
89 | + | |
90 | + def test_get_user_priority(self): | |
91 | + user = PyrosUser.objects.all()[0] | |
92 | + # add Unit-PI role to user | |
93 | + UserLevel.objects.get(name="Unit-PI").pyros_users.add(user) | |
94 | + self.assertEqual(user.get_priority(),UserLevel.objects.get(name="Unit-PI").priority,"The priority should be equal to Unit-PI's priority") | |
95 | + | |
96 | + def test_wrong_get_user_priority(self): | |
97 | + user = PyrosUser.objects.all()[0] | |
98 | + # add Unit-PI role to user | |
99 | + UserLevel.objects.get(name="Unit-PI").pyros_users.add(user) | |
100 | + self.assertNotEqual(user.get_priority(),UserLevel.objects.get(name="Visitor").priority,"The priority shouldn't be equal to Visitor's priority") | |
101 | + | |
102 | + def test_get_roles_str(self): | |
103 | + user = PyrosUser.objects.all()[0] | |
104 | + # add Unit-PI role to user | |
105 | + UserLevel.objects.get(name="Unit-PI").pyros_users.add(user) | |
106 | + roles_str = user.get_roles_str() | |
107 | + for role in user.user_level.all(): | |
108 | + self.assertIn(role.name,roles_str,f"The role {role} should be in the str representation") | |
109 | + | |
110 | + def test_wrong_get_roles_str(self): | |
111 | + user = PyrosUser.objects.all()[0] | |
112 | + # add Unit-PI role to user | |
113 | + UserLevel.objects.get(name="Unit-PI").pyros_users.add(user) | |
114 | + roles_str = user.get_roles_str() | |
115 | + self.assertNotIn(UserLevel.objects.get(name="Admin").name,roles_str,"The role Admin shouldn't be in the str representation") | |
116 | + | |
117 | + def test_max_priority_desc(self): | |
118 | + user = PyrosUser.objects.all()[0] | |
119 | + # add Unit-PI role to user | |
120 | + UserLevel.objects.get(name="Unit-PI").pyros_users.add(user) | |
121 | + self.assertEqual(user.get_max_priority_desc(),UserLevel.objects.get(name="Unit-PI").desc,"The desc of user_level should be 'Unit-PI description' ") | |
122 | + | |
123 | + def test_wrong_max_priority_desc(self): | |
124 | + user = PyrosUser.objects.all()[0] | |
125 | + # add Unit-PI role to user | |
126 | + UserLevel.objects.get(name="Unit-PI").pyros_users.add(user) | |
127 | + # add Admin role to user (has a greatier priority than Unit-PI and Visitor roles) | |
128 | + UserLevel.objects.get(name="Admin").pyros_users.add(user) | |
129 | + self.assertNotEqual(user.get_max_priority_desc(),UserLevel.objects.get(name="Unit-PI").desc,"The desc of user_level shouldn't be 'Unit-PI description' ") | |
130 | + | |
131 | + | |
132 | + def test_max_priority_quota(self): | |
133 | + user = PyrosUser.objects.all()[0] | |
134 | + # add Unit-PI role to user | |
135 | + UserLevel.objects.get(name="Unit-PI").pyros_users.add(user) | |
136 | + self.assertEqual(user.get_max_priority_quota(),UserLevel.objects.get(name="Unit-PI").quota,"The quota of user_level should be 100.0 ") | |
137 | + | |
138 | + def test_wrong_max_priority_quota(self): | |
139 | + user = PyrosUser.objects.all()[0] | |
140 | + # add Unit-PI role to user | |
141 | + UserLevel.objects.get(name="Unit-PI").pyros_users.add(user) | |
142 | + # add Admin role to user (has a greatier priority than Unit-PI and Visitor roles) | |
143 | + UserLevel.objects.get(name="Admin").pyros_users.add(user) | |
144 | + self.assertNotEqual(user.get_max_priority_quota(),UserLevel.objects.get(name="Unit-PI").desc,"The quota of user_level shouldn't be 1000.0 ") | |
139 | 145 | \ No newline at end of file | ... | ... |
src/core/pyros_django/user_manager/urls.py
1 | -from django.conf.urls import url | |
2 | -from django.urls import path | |
3 | -from . import views | |
4 | - | |
5 | -urlpatterns = [ | |
6 | - url(r'^create$', views.create_user, name="create_user"), | |
7 | - url(r'^creation_validate$', views.user_signup_validation, name="user_signup_validation"), | |
8 | - url(r'^login$', views.login_validation, name="login_validation"), | |
9 | - url(r'^profile$', views.profile, name="profile"), | |
10 | - url(r'^logout$', views.user_logout, name="user_logout"), | |
11 | - path('signin', views.user_signin, name="user_signin"), | |
12 | - path('sp_profile', views.superoperator_return, name="sp_profile") | |
13 | - ] | |
1 | +from django.conf.urls import url | |
2 | +from django.urls import path | |
3 | +from . import views | |
4 | +from django.contrib.auth import views as auth_views | |
5 | +from .forms import UserPasswordResetForm | |
6 | + | |
7 | +urlpatterns = [ | |
8 | + path('users', views.users, name="users"), | |
9 | + url(r'^create$', views.create_user, name="create_user"), | |
10 | + url(r'^creation_validate$', views.user_signup_validation, name="user_signup_validation"), | |
11 | + url(r'^login$', views.login_validation, name="login_validation"), | |
12 | + url(r'^profile$', views.profile, name="profile"), | |
13 | + url(r'^logout$', views.user_logout, name="user_logout"), | |
14 | + path('signin', views.user_signin, name="user_signin"), | |
15 | + path('sp_profile', views.superoperator_return, name="sp_profile"), | |
16 | + path('users/<int:pk>', views.user_detail_view, name='user_detail'), | |
17 | + path('users_delete/<int:pk>', views.delete_user, name='user-delete'), | |
18 | + path('users/<int:pk>/edit', views.user_detail_edit, name='user-edit'), | |
19 | + path('user-status/<int:pk>/<int:current_user_id>', views.change_activate, name='change_activate'), | |
20 | + path("set_active_role", views.set_active_role,name="set_active_role"), | |
21 | + path("password-reset", auth_views.PasswordResetView.as_view( template_name="user_manager/password_reset.html"), name="password_reset"), | |
22 | + path("password-reset/done/", auth_views.PasswordResetDoneView.as_view( template_name="user_manager/password_reset_done.html"), name="password_reset_done"), | |
23 | + path("password-reset-confirm/<uidb64>/<token>", auth_views.PasswordResetConfirmView.as_view( template_name="user_manager/password_reset_confirm.html"), name="password_reset_confirm"), | |
24 | + path("password-reset-complete/", auth_views.PasswordResetCompleteView.as_view( template_name="user_manager/password_reset_complete.html"), name="password_reset_complete"), | |
25 | + path('roles_description', views.roles_description, name="roles_description") | |
26 | + ] | ... | ... |
src/core/pyros_django/user_manager/views.py
1 | -from django.shortcuts import render,redirect | |
2 | -from django.contrib.auth import authenticate, login, logout | |
3 | -from django.contrib.auth.decorators import login_required | |
4 | -from .forms import PyrosUserCreationForm | |
5 | - | |
6 | -LOGGED_PAGE = "../../dashboard/templates/dashboard/index.html" | |
7 | - | |
8 | -def home(request): | |
9 | - ''' | |
10 | - Initial login view when coming on the website | |
11 | - ''' | |
12 | - if request.user.is_authenticated: | |
13 | - return(render(request, LOGGED_PAGE, {'USER_LEVEL': request.user.get_priority(), 'base_template' : "base.html", 'weather_img': "normal"})) | |
14 | - return(render(request, LOGGED_PAGE, {'USER_LEVEL': 0, 'base_template' : 'base_unlogged.html', 'weather_img': "red"})) | |
15 | - | |
16 | -def create_user(request): | |
17 | - ''' | |
18 | - View called to open the user creation form | |
19 | - ''' | |
20 | - if request.user.is_authenticated: | |
21 | - return(render(request, LOGGED_PAGE, {'USER_LEVEL': request.user.get_priority(), 'base_template' : "base.html", 'weather_img': "normal"})) | |
22 | - form = PyrosUserCreationForm() | |
23 | - return (render(request, "user_manager/home_user_creation.html", locals())) | |
24 | - | |
25 | -def user_signup_validation(request): | |
26 | - ''' | |
27 | - View called to validate the user creation (form submitted) | |
28 | - ''' | |
29 | - if request.user.is_authenticated: | |
30 | - return(render(request, LOGGED_PAGE, {'USER_LEVEL': request.user.get_priority(), 'base_template' : "base.html", 'weather_img': "normal"})) | |
31 | - form = PyrosUserCreationForm(request.POST) | |
32 | - if request.POST: | |
33 | - if form.is_valid(): | |
34 | - form.save() | |
35 | - message = "Account creation successful ! Login to continue" | |
36 | - success = True | |
37 | - return(render(request, "user_manager/home_login.html", locals())) | |
38 | - else: | |
39 | - message = "One or more fields contain errors. Please try again" | |
40 | - | |
41 | - else: | |
42 | - message = "The system encountered an error. Please try again" | |
43 | - | |
44 | - error = True | |
45 | - return (render(request, "user_manager/home_user_creation.html", locals())) | |
46 | - | |
47 | -def login_validation(request): | |
48 | - ''' | |
49 | - View called when the user log in (form submitted) | |
50 | - ''' | |
51 | - if request.user.is_authenticated: | |
52 | - if request.POST.get("next"): | |
53 | - return redirect(request.POST.get('next')) | |
54 | - return(render(request, LOGGED_PAGE, {'USER_LEVEL': request.user.get_priority(),'base_template' : "base.html", 'weather_img': "normal"})) | |
55 | - username = password = '' | |
56 | - if request.POST: | |
57 | - email = request.POST.get('email') | |
58 | - password = request.POST.get('password') | |
59 | - user = authenticate(username=email, password=password) | |
60 | - if user is not None: | |
61 | - success = False | |
62 | - if user.is_active: | |
63 | - login(request, user) | |
64 | - request.session['user'] = email | |
65 | - message = "Oui" | |
66 | - success = True | |
67 | - if request.POST.get("next"): | |
68 | - return redirect(request.POST.get('next')) | |
69 | - return(render(request, LOGGED_PAGE, {'USER_LEVEL': request.user.get_priority(), 'base_template' : "base.html", 'weather_img': "normal", 'success' : success})) | |
70 | - else: | |
71 | - message = "Your account is not active, please contact the site administrator." | |
72 | - else: | |
73 | - message = "Your email and/or password were incorrect." | |
74 | - else: | |
75 | - message = "An unexpected error has occurred" | |
76 | - error = True | |
77 | - return(render(request, "user_manager/home_login.html", locals())) | |
78 | - | |
79 | -@login_required | |
80 | -def profile(request): | |
81 | - ''' | |
82 | - View called to see the current user profile | |
83 | - ''' | |
84 | - current_user = request.user | |
85 | - USER_LEVEL = request.user.get_priority() | |
86 | - if (current_user.get_priority() < 4): | |
87 | - return(render(request, "dashboard/user_detail.html", {'user': current_user, 'admin': 0})) | |
88 | - return(render(request, "user_manager/profile.html", locals())) | |
89 | - | |
90 | -@login_required | |
91 | -def superoperator_return(request): | |
92 | - current_user = request.user | |
93 | - return(render(request, "dashboard/user_detail.html", {'user': current_user, 'admin': 0})) | |
94 | - | |
95 | -@login_required | |
96 | -def user_logout(request): | |
97 | - ''' | |
98 | - View called to log out. Redirects on login page. | |
99 | - ''' | |
100 | - | |
101 | - logout(request) | |
102 | - return(render(request, LOGGED_PAGE, {'USER_LEVEL' : 0, 'base_template' : 'base_unlogged.html', 'weather_img': "red"})) | |
103 | - | |
104 | -def user_signin(request): | |
105 | - return(render(request, "user_manager/home_login.html",{"next": request.GET.get("next")})) | |
106 | 1 | \ No newline at end of file |
2 | +from django.shortcuts import render,redirect | |
3 | +from django.contrib.auth import authenticate, login, logout | |
4 | +from django.contrib.auth.decorators import login_required | |
5 | +from dashboard.decorator import level_required | |
6 | +from django.shortcuts import get_object_or_404 | |
7 | +from dashboard.forms import UserForm | |
8 | +from .forms import PyrosUserCreationForm | |
9 | +from django.core.mail import send_mail | |
10 | +from common.models import ScientificProgram, PyrosUser,UserLevel, SP_Period, SP_Period_User | |
11 | +from django.urls import reverse | |
12 | +from django.http import HttpResponseRedirect,HttpResponse | |
13 | + | |
14 | + | |
15 | +LOGGED_PAGE = "../../dashboard/templates/dashboard/index.html" | |
16 | + | |
17 | +def home(request): | |
18 | + ''' | |
19 | + Initial login view when coming on the website | |
20 | + ''' | |
21 | + if request.user.is_authenticated: | |
22 | + return(render(request, LOGGED_PAGE, {'USER_LEVEL': request.user.get_priority(), 'base_template' : "base.html", 'weather_img': "normal"})) | |
23 | + return(render(request, LOGGED_PAGE, {"USER_LEVEL" : "Visitor", 'base_template' : 'base_unlogged.html', 'weather_img': "red"})) | |
24 | + | |
25 | +def roles_description(request): | |
26 | + return (render(request,"user_manager/roles_description.html")) | |
27 | + | |
28 | +def create_user(request): | |
29 | + ''' | |
30 | + View called to open the user creation form | |
31 | + ''' | |
32 | + """ | |
33 | + if request.user.is_authenticated: | |
34 | + return(render(request, LOGGED_PAGE, {'USER_LEVEL': request.user.get_priority(), 'base_template' : "base.html", 'weather_img': "normal"})) | |
35 | + """ | |
36 | + form = PyrosUserCreationForm() | |
37 | + return (render(request, "user_manager/home_user_creation.html", locals())) | |
38 | + | |
39 | +def user_signup_validation(request): | |
40 | + ''' | |
41 | + View called to validate the user creation (form submitted) | |
42 | + ''' | |
43 | + """ | |
44 | + if request.user.is_authenticated: | |
45 | + return(render(request, LOGGED_PAGE, {'USER_LEVEL': request.user.get_priority(), 'base_template' : "base.html", 'weather_img': "normal"})) | |
46 | + """ | |
47 | + form = PyrosUserCreationForm(request.POST) | |
48 | + if request.POST: | |
49 | + if form.is_valid(): | |
50 | + form.save() | |
51 | + message = "Account creation successful ! Login to continue" | |
52 | + success = True | |
53 | + if request.user.is_authenticated: | |
54 | + if request.POST.get("next"): | |
55 | + return redirect(request.POST.get('next')) | |
56 | + else: | |
57 | + return redirect(reverse("users")) | |
58 | + else: | |
59 | + return(render(request, "user_manager/home_login.html", locals())) | |
60 | + else: | |
61 | + message = "One or more fields contain errors. Please try again" | |
62 | + form_errors = form.errors | |
63 | + else: | |
64 | + message = "The system encountered an error. Please try again" | |
65 | + | |
66 | + error = True | |
67 | + return (render(request, "user_manager/home_user_creation.html", locals())) | |
68 | + | |
69 | +def login_validation(request): | |
70 | + ''' | |
71 | + View called when the user log in (form submitted) | |
72 | + ''' | |
73 | + if request.user.is_authenticated: | |
74 | + if request.POST.get("next"): | |
75 | + return redirect(request.POST.get('next')) | |
76 | + # initiate variable session for telling which role the user is using if this user has multiple roles | |
77 | + # default role is the role with maximum priority | |
78 | + request.session["role"] = str(UserLevel.objects.get(priority=request.user.get_priority())) | |
79 | + return(render(request, LOGGED_PAGE, {'USER_LEVEL': request.user.get_priority(),'base_template' : "base.html", 'weather_img': "normal"})) | |
80 | + username = password = '' | |
81 | + if request.POST: | |
82 | + email = request.POST.get('email') | |
83 | + password = request.POST.get('password') | |
84 | + user = authenticate(username=email, password=password) | |
85 | + if user is not None: | |
86 | + success = False | |
87 | + if user.is_active: | |
88 | + login(request, user) | |
89 | + request.session['user'] = email | |
90 | + message = "Oui" | |
91 | + success = True | |
92 | + # initiate variable session for telling which role the user is using if this user has multiple roles | |
93 | + # default role is the role with maximum priority | |
94 | + request.session["role"] = str(UserLevel.objects.get(priority=request.user.get_priority())) | |
95 | + if request.POST.get("next"): | |
96 | + return redirect(request.POST.get('next')) | |
97 | + return(render(request, LOGGED_PAGE, {'USER_LEVEL': request.user.get_priority(), 'base_template' : "base.html", 'weather_img': "normal", 'success' : success})) | |
98 | + else: | |
99 | + message = "Your account is not active, please contact the site administrator." | |
100 | + else: | |
101 | + message = "Your email and/or password were incorrect." | |
102 | + else: | |
103 | + message = "An unexpected error has occurred" | |
104 | + error = True | |
105 | + return(render(request, "user_manager/home_login.html", locals())) | |
106 | + | |
107 | +@login_required | |
108 | +def profile(request): | |
109 | + ''' | |
110 | + View called to see the current user profile | |
111 | + ''' | |
112 | + current_user = request.user | |
113 | + USER_LEVEL = request.user.get_priority() | |
114 | + if (current_user.get_priority() < 4): | |
115 | + return(render(request, "user_manager/user_detail.html", {'user': current_user, 'admin': 0})) | |
116 | + return(render(request, "user_manager/profile.html", locals())) | |
117 | + | |
118 | +@login_required | |
119 | +def superoperator_return(request): | |
120 | + current_user = request.user | |
121 | + return(render(request, "user_manager/user_detail.html", {'user': current_user, 'admin': 0})) | |
122 | + | |
123 | +@login_required | |
124 | +def user_logout(request): | |
125 | + ''' | |
126 | + View called to log out. Redirects on login page. | |
127 | + ''' | |
128 | + | |
129 | + logout(request) | |
130 | + return(render(request, LOGGED_PAGE, {'USER_LEVEL' : "Visitor", 'base_template' : 'base_unlogged.html', 'weather_img': "red"})) | |
131 | + | |
132 | +def user_signin(request): | |
133 | + return(render(request, "user_manager/home_login.html",{"next": request.GET.get("next")})) | |
134 | + | |
135 | + | |
136 | +@login_required | |
137 | +@level_required("Admin") | |
138 | +def delete_user(request,pk): | |
139 | + user_to_be_deleted = get_object_or_404(PyrosUser,pk=pk) | |
140 | + if request.method == "POST": | |
141 | + user_to_be_deleted.delete() | |
142 | + return HttpResponseRedirect(reverse('users')) | |
143 | + | |
144 | + | |
145 | +@login_required | |
146 | +@level_required("Admin","Observer","Management","Operator","Unit-PI","TAC","Unit board") | |
147 | +def users(request): | |
148 | + current_user = request.user | |
149 | + pyros_users_with_roles = [] | |
150 | + pyros_users_without_roles = None | |
151 | + if request.session.get("role"): | |
152 | + role = request.session.get("role") | |
153 | + else: | |
154 | + role = current_user.get_priority() | |
155 | + | |
156 | + if role in "Admin,Unit-PI,Unit board": | |
157 | + pyros_users_with_roles = PyrosUser.objects.exclude(user_level__name="Visitor").order_by("-id") | |
158 | + pyros_users_without_roles = PyrosUser.objects.filter(user_level__name="Visitor").order_by("-id") | |
159 | + else: | |
160 | + sp_of_current_user = SP_Period_User.objects.filter(user=current_user) | |
161 | + pyros_user_with_roles = [] | |
162 | + for sp in sp_of_current_user: | |
163 | + for user in SP_Period_User.objects.filter(SP_Period=sp.SP_Period).exclude(user=current_user).values_list("user",flat=True): | |
164 | + pyros_users_with_roles.append(PyrosUser.objects.get(id=user)) | |
165 | + nb_of_scientific_program = ScientificProgram.objects.count() | |
166 | + # need the negative to calculate in the template for adjusting correctly the information display | |
167 | + negative_nb_scientific_program = -nb_of_scientific_program | |
168 | + return render(request, 'user_manager/users_management.html', {'pyros_users_with_roles': pyros_users_with_roles,"pyros_users_without_roles":pyros_users_without_roles,"nb_of_scientific_program": nb_of_scientific_program,"negative_nb_scientific_program":negative_nb_scientific_program}) # return the initial view (the users management's one) | |
169 | + | |
170 | +@login_required | |
171 | +@level_required("Admin","Unit-PI","Unit board") | |
172 | +def change_activate(request, pk, current_user_id): | |
173 | + try : | |
174 | + user = get_object_or_404(PyrosUser, pk=pk) | |
175 | + user.is_active = not user.is_active | |
176 | + text_mail = "" | |
177 | + text_object = "" | |
178 | + if (user.first_time == False and user.is_active == True): | |
179 | + user.first_time = True | |
180 | + text_mail = "Hi,\n\nCongratulations, your registration has been approved by the PI. Welcome to the PyROS Control Center.\nIn order to submit observation sequences, you need to be associated to a scientific program.\n\nCordially,\n\nPyROS Control Center" | |
181 | + text_object = "[PyROS CC] Welcome" | |
182 | + user.validator = get_object_or_404(PyrosUser,pk=current_user_id) | |
183 | + send_mail(text_object, text_mail, '', [user.email], fail_silently=False,) | |
184 | + | |
185 | + # We're not sending an email if the account has been desactivated or re-activated | |
186 | + # elif (user.is_active == True): | |
187 | + # text_mail = "Hi,\n\nYour account on the PyROS Control Center have been re-activated.\n\nCordially,\n\nPyROS Control Center" | |
188 | + # text_object = "[PyROS CC] Re-activation" | |
189 | + # else : | |
190 | + # text_mail = "Hi,\n\nYour account on the PyROS Control Center have benn desactivated. Please contact the PI for futher information.\n\nCordially,\n\nPyROS Control Center" | |
191 | + # text_object = "[PyROS CC] Desactivation" | |
192 | + | |
193 | + user.save() | |
194 | + | |
195 | + return redirect('user_detail', pk=pk) | |
196 | + except PyrosUser.DoesNotExist: | |
197 | + return redirect('user_detail', pk=pk) | |
198 | + | |
199 | +@login_required | |
200 | +@level_required("Admin","Observer","Management","Operator","Unit-PI","TAC","Unit board") | |
201 | +def user_detail_view(request,pk): | |
202 | + try: | |
203 | + is_last_user = PyrosUser.objects.count() == 1 | |
204 | + user_id=PyrosUser.objects.get(pk=pk) | |
205 | + current_user = request.user | |
206 | + roles = current_user.get_list_of_roles() | |
207 | + sp_periods = SP_Period_User.objects.filter(user=user_id) | |
208 | + scientific_programs = [] | |
209 | + for sp_period in sp_periods: | |
210 | + | |
211 | + scientific_programs.append(sp_period.SP_Period.scientific_program) | |
212 | + except PyrosUser.DoesNotExist: | |
213 | + raise Http404("User does not exist") | |
214 | + return render(request, 'user_manager/user_detail.html', context={'user' : user_id, 'current_user' : current_user, 'USER_LEVEL': request.user.get_priority(), 'is_last_user' : is_last_user,"roles" : roles,"scientific_programs":scientific_programs}) | |
215 | + | |
216 | +@login_required | |
217 | +@level_required() | |
218 | +def user_detail_edit(request,pk): | |
219 | + if request.session.get("role"): | |
220 | + role = request.session.get("role") | |
221 | + else: | |
222 | + role = request.user.get_priority() | |
223 | + # If its not his user profile or user isn't Unit-PI, Unit board, Admin or SP-PI, He can't edit this user profile and he is redirected to home page | |
224 | + if (request.user.id != pk and role not in ("Admin","Unit-PI","Unit board") ): | |
225 | + return HttpResponseRedirect(reverse('index')) | |
226 | + edit = get_object_or_404(PyrosUser, pk=pk) | |
227 | + is_sp_pi = SP_Period_User.objects.filter(is_SP_PI=True,user=edit).count() > 0 | |
228 | + form = UserForm(request.POST or None, instance=edit) | |
229 | + # creating list of roles for the formular excluding visitor of the list | |
230 | + roles = UserLevel.objects.exclude(name="Visitor") | |
231 | + if form.is_valid(): | |
232 | + obj = form.save(commit=False) | |
233 | + if(len(request.POST.getlist("roles"))>0): | |
234 | + if("Admin" in request.POST.getlist("roles")): | |
235 | + # if Admin role has been assigned, add the authorisations to access to django admin pages | |
236 | + obj.is_staff = True | |
237 | + obj.is_admin = True | |
238 | + obj.is_superuser = True | |
239 | + else: | |
240 | + # just in case (for example, if user was previously an admin and has been downgraded) we're removing those authorisations | |
241 | + obj.is_staff = False | |
242 | + obj.is_admin = False | |
243 | + obj.user_level.set(request.POST.getlist("roles")) | |
244 | + else: | |
245 | + # No role has been assigned, so the user has the Visitor role | |
246 | + obj.user_level.set([UserLevel.objects.get(name="Visitor")]) | |
247 | + | |
248 | + obj.save() | |
249 | + return redirect('user_detail', pk=pk) | |
250 | + return render(request, 'user_manager/user_detail_edit.html', {'form': form,"roles":roles, "pk":pk,"user_edit":edit,'USER_LEVEL': request.user.get_priority(),"is_sp_pi":is_sp_pi}) | |
251 | + | |
252 | + | |
253 | +def set_active_role(request): | |
254 | + previous_active_role = request.session.get("role") | |
255 | + if request.user.is_authenticated: | |
256 | + if request.POST.get("role"): | |
257 | + request.session["role"] = str(UserLevel.objects.get(name=request.POST.get("role"))) | |
258 | + if(previous_active_role is not None and previous_active_role != request.session.get("role")): | |
259 | + return HttpResponse("Changed !") | |
107 | 260 | \ No newline at end of file | ... | ... |