Commit d8ab8257 authored by Giorgos Kazelidis's avatar Giorgos Kazelidis

- Created the session continuation template and modified the...

- Created the session continuation template and modified the display_default_login_page() view to display the former when it is accessed by (logged-in) instances of the application user models (usermerge.{User/Admin})
- Modified the log_in() view to deny access to (logged-in) instances of the application user models (usermerge.{User/Admin})
- Modified the display_default_login_page(), log_in() and log_out() views to deny access to (logged-in) instances of Django's default user model (auth.User)
- Defined the has_empty_profile() method for the usermerge.User model and used it in templates and views to enhance functionality and readability
- Omitted the redundant user_id parameters/arguments from (i) the application site URLs defined in the URLconf and used in templates/views and (ii) the corresponding view declarations (the current/session user can be specified in any view via the user attribute of the associated request)
- Utilized the recov_user_id value of the session data in the _display_user_profile_recovery_success_message() and _display_user_profile_recovery_error_messages() helper functions as well as the search_for_recovery_user_profile() and recover_user_profile() views to enhance functionality and security
- Hooked the Django admin site into the /django-admin/ URL (instead of the default one, /admin/) to distinguish its pages from the ones that refer to the usermerge.Admin model and have an /admin/ URL prefix
parent 95a43695
......@@ -18,6 +18,6 @@ from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('usermerge.urls')),
path('django-admin/', admin.site.urls), # (Django) admin site URLs
path('', include('usermerge.urls')), # usermerge (application) site URLs
]
"""
Modified version of django.contrib.auth module (https://docs.djangoproject.com/en/2.0/_modules/django/contrib/auth/).
Modified version of django.contrib.auth module (https://docs.djangoproject.com/en/2.0/_modules/django/contrib/auth/)
that refers to authentication against the application user models, i.e. usermerge.User and usermerge.Admin models.
"""
from django.apps import apps as django_apps
......@@ -63,8 +64,8 @@ def login(request, user, backend = None):
# Calculate the session authentication hash for the authenticated user that attempts to log in based on the platform selected in the
# login form. The selected platform is representative of the user model (if the selected platform was SLUB, the user model is Admin,
# otherwise it is User) and the calculation of the hash differs between the user models (see the different get_session_auth_hash()
# methods in models.py). If the user logs in successfully, the hash is stored in the session data and can then be used to verify the
# user's authenticity during the session (see, for example, the get_user() function below).
# methods in models.py). If the user logs in successfully, the hash is stored in the session data as the HASH_SESSION_KEY value and
# can then be used to verify the user's authenticity during the session (see, for example, the get_user() function below).
if platform_name == 'SLUB':
# Admin hash calculation
session_auth_hash = user.get_session_auth_hash()
......@@ -93,7 +94,7 @@ def login(request, user, backend = None):
'provide the "backend" argument or set the "backend" attribute on the user.')
request.session[SESSION_KEY] = user._meta.pk.value_to_string(user)
# The platform (name) selected in the login form is stored in the session data.
# The platform (name) selected in the login form is stored in the session data as the PLATFORM_SESSION_KEY value.
request.session[PLATFORM_SESSION_KEY] = platform_name
request.session[BACKEND_SESSION_KEY] = backend
request.session[HASH_SESSION_KEY] = session_auth_hash
......
......@@ -17,7 +17,7 @@ def User_login_required(view):
def User_model_required(func):
@wraps(func)
def wrapper(request, *args, **kwargs):
if str(request.user.__class__) == "<class 'usermerge.models.User'>":
if request.user._meta.label == 'usermerge.User':
return func(request, *args, **kwargs)
else: # either auth.User or usermerge.Admin model
raise PermissionDenied
......@@ -34,7 +34,7 @@ def Admin_login_required(view):
def Admin_model_required(func):
@wraps(func)
def wrapper(request, *args, **kwargs):
if str(request.user.__class__) == "<class 'usermerge.models.Admin'>":
if request.user._meta.label == 'usermerge.Admin':
return func(request, *args, **kwargs)
else: # either auth.User or usermerge.User model
raise PermissionDenied
......
......@@ -85,12 +85,13 @@ def _display_user_profile_recovery_success_message(request, recov_user):
"""
[Acts as inner function of the search_for_recovery_user_profile() view] Display the appropriate success message in the user profile
recovery page by taking the recovery user profile (non-empty User instance that corresponds to both the validated - cleaned - and
adequate ece_id and email values of the corresponding form) into account. This message presents the (empty) session user with all the
field values of the aforementioned profile and informs him/her that if he/she proceeds with the profile recovery, he/she will get
logged out after his/her credentials for the login platform have first been associated with this profile (they will replace any
previously associated ones). Finally, include the recovery profile in the page context to assist the recovery procedure - see the
recover_user_profile() view.
adequate ece_id and email values of the corresponding form) into account. This message presents the (empty) session user with all
the field values of the aforementioned profile and informs him/her that if he/she proceeds with the profile recovery, he/she will
get logged out after his/her credentials for the login platform have first been associated with this profile (they will replace any
previously associated ones). Finally, enable the recovery procedure - see the recover_user_profile() view - by storing the id of
the recovery user profile in the session data as the recov_user_id value (it replaces any previously stored one).
"""
request.session['recov_user_id'] = recov_user.id
success_message = ('Τα δηλωθέντα στοιχεία εντοπίστηκαν επιτυχώς στη βάση και παραπέμπουν στο εξής καταχωρημένο προφίλ:\n\n'
'Όνομα: %s\n'
'Επώνυμο: %s\n'
......@@ -102,14 +103,19 @@ def _display_user_profile_recovery_success_message(request, recov_user):
) % (recov_user.first_name, recov_user.last_name,
'[Δεν έχει καταχωρηθεί]' if recov_user.ece_id is None else recov_user.ece_id,
recov_user.email, request.session[PLATFORM_SESSION_KEY])
return TemplateResponse(request, 'user_profile_recovery.html', {'success_message': success_message, 'recov_user': recov_user})
return TemplateResponse(request, 'user_profile_recovery.html', {'success_message': success_message})
def _display_user_profile_recovery_error_messages(request, error_data):
"""
[Acts as inner function of the search_for_recovery_user_profile() view] Create the appropriate post-validation error messages
by using the validated (cleaned), yet inadequate, ece_id or/and email values of the user profile recovery form along with the
corresponding error codes, display them in the user profile recovery page and include the error codes in the page context.
corresponding error codes, display them in the user profile recovery page and include the error codes in the page context. Since
no recovery user profile (non-empty User instance that corresponds to both of the aforementioned form values) has been specified
in usermergeDB, disable the recovery procedure - see the recover_user_profile() view - by ensuring that the recov_user_id value
does not exist in the session data (if it exists, delete it).
"""
if 'recov_user_id' in request.session:
del request.session['recov_user_id']
error_messages = []
error_codes = []
# The ece_id_and_email_exist_in_different_profiles error can only occur by itself. This means that if it occurs,
......
......@@ -9,7 +9,7 @@ from . import auth as usermerge_auth
# AuthenticationMiddleware is a middleware component that associates the current user with every incoming web request. Original source code for the get_user() function and the aforementioned component can be found in https://github.com/django/django/blob/master/django/contrib/auth/middleware.py (for more information, see https://docs.djangoproject.com/en/2.0/ref/middleware/#django.contrib.auth.middleware.AuthenticationMiddleware).
# For more information on default/customizing user authentication and password management, see https://docs.djangoproject.com/en/2.0/topics/auth/, auth.py and backends.py .
# The login() function of the application's authentication module (usermerge.auth) is used to log a user (usermerge.{User/Admin} instance) in via the login page of the application - see the log_in() view - and inserts the PLATFORM_SESSION_KEY value into the (dictionary-like) session data based on the platform selected in the corresponding form. On the other hand, the login() function of the default authentication module (django.contrib.auth) is used to log a user (auth.User instance) in via the login page of the admin site (see https://docs.djangoproject.com/en/2.0/ref/contrib/admin/) and does not insert any PLATFORM_SESSION_KEY value into the session data as the corresponding form does not include any platform field.
# The login() function of the application's authentication module (usermerge.auth) is used to log a user (usermerge.{User/Admin} instance) in via the login page of the application - see the log_in() view - and stores the PLATFORM_SESSION_KEY value in the session data based on the platform (name) selected in the corresponding form. On the other hand, the login() function of the default authentication module (django.contrib.auth) is used to log a user (auth.User instance) in via the login page of the admin site (see https://docs.djangoproject.com/en/2.0/ref/contrib/admin/) and does not store any PLATFORM_SESSION_KEY value in the session data as the corresponding form does not include any platform field.
def get_user(request):
if not hasattr(request, '_cached_user'):
......
......@@ -34,11 +34,20 @@ class User(models.Model):
@property
def is_authenticated(self):
"""
Always return True. This is a way to tell if the user has been
authenticated in templates, views, etc.
Always return True. This is a way to tell if the user has been authenticated in templates, views, etc.
"""
return True
def has_empty_profile(self):
"""
Return the opposite boolean value of the email field, i.e. True if the email is None and False otherwise. This is a way to tell
whether the user has an empty profile in templates, views, etc. as the user profile is empty if the email is None and vice versa.
"""
# The email value can be used to determine whether the user profile (User instance) is empty or not due to the latter's
# possible/valid (field) states in usermergeDB and the allowed/consistent transitions between them (see the relative
# comment at the top).
return not bool(self.email)
class Platform(models.Model):
name = models.CharField(max_length = 50, unique = True)
......@@ -84,8 +93,7 @@ class Admin(models.Model):
@property
def is_authenticated(self):
"""
Always return True. This is a way to tell if the user has been
authenticated in templates, views, etc.
Always return True. This is a way to tell whether the user has been authenticated in templates, views, etc.
"""
return True
......
......@@ -7,7 +7,7 @@
{% block content %}
<nav id="session_nav">
Έχετε εισέλθει ως <strong>{{ user.first_name }} {{ user.last_name }}</strong>!
| <a href="{% url 'admin_home' user.id %}">Αρχική Σελίδα</a>
| <a href="{% url 'admin_home' %}">Αρχική Σελίδα</a>
| <a href="{% url 'logout' %}">Έξοδος</a>
</nav>
......
{# This page/template is utilized in the display_default_login_page() view. #}
{% extends 'base.html' %}
{% block title %}
SLUB - Συνέχιση Συνεδρίας ή Έξοδος
{% endblock %}
{% block content %}
<nav id="session_nav">
{% if user.first_name and user.last_name %}
Έχετε εισέλθει ως <strong>{{ user.first_name }} {{ user.last_name }}</strong>!
{% else %}
Έχετε εισέλθει επιτυχώς!
{% endif %}
| <a href="{% url home_page_url %}">Αρχική Σελίδα</a>
| <a href="{% url 'logout' %}">Έξοδος</a>
</nav>
<h4>Συνέχιση Συνεδρίας ή Έξοδος</h4>
<p>
<strong>
Υπάρχει ήδη μία συνεδρία σε ισχύ! Θα θέλατε να <a href="{% url home_page_url %}">συνεχίσετε</a> την πλοήγηση σε αυτήν <br />
ή να <a href="{% url 'logout' %}">εξέλθετε</a> για να ξεκινήσετε μία νέα συνεδρία ως διαφορετικός χρήστης;
</strong>
</p>
{% endblock %}
......@@ -5,13 +5,14 @@
{% endblock %}
{% block content %}
{% with empty_user_profile=user.has_empty_profile %}
<nav id="session_nav">
{% if user.first_name and user.last_name %}
{% if not empty_user_profile %}
Έχετε εισέλθει ως <strong>{{ user.first_name }} {{ user.last_name }}</strong>!
{% else %}
Έχετε εισέλθει επιτυχώς!
{% endif %}
| <a href="{% url 'user_home' user.id %}">Αρχική Σελίδα</a>
| <a href="{% url 'user_home' %}">Αρχική Σελίδα</a>
| <a href="{% url 'logout' %}">Έξοδος</a>
</nav>
......@@ -20,7 +21,7 @@
{% if user.ece_id is None %}
<p>
<strong>
{% if user.first_name == '' and user.last_name == '' and user.email is None %}
{% if empty_user_profile %}
&#x272A; Παρακαλούμε συμπληρώστε άμεσα τα στοιχεία του προφίλ σας επιλέγοντας "Επεξεργασία Προφίλ"!
{% else %}
&#x272A; Αν διαθέτετε αριθμό μητρώου, παρακαλούμε συμπληρώστε άμεσα το <br />
......@@ -35,8 +36,8 @@
The "Edit Profile" and "Log out" options are ALWAYS available to the user. ALL the OTHER
navigation options are available to him/her ONLY if his/her profile is NON-empty.
{% endcomment %}
<p><a href="{% url 'default_user_profile_edit' user.id %}">Επεξεργασία Προφίλ</a></p>
{% if user.first_name != '' and user.last_name != '' and user.email is not None %}
<p><a href="{% url 'default_user_profile_edit' %}">Επεξεργασία Προφίλ</a></p>
{% if not empty_user_profile %}
{# Insert ALL the OTHER navigation options HERE! #}
{# ... #}
{# ... #}
......@@ -44,5 +45,6 @@
{% endif %}
<p><a href="{% url 'logout' %}">Έξοδος</a></p>
</nav>
{% endwith %}
{% endblock %}
......@@ -5,32 +5,33 @@
{% endblock %}
{% block content %}
{% with empty_user_profile=user.has_empty_profile %}
<nav id="session_nav">
{% if user.first_name and user.last_name %}
{% if not empty_user_profile %}
Έχετε εισέλθει ως <strong>{{ user.first_name }} {{ user.last_name }}</strong>!
{% else %}
Έχετε εισέλθει επιτυχώς!
{% endif %}
| <a href="{% url 'user_home' user.id %}">Αρχική Σελίδα</a>
| <a href="{% url 'user_home' %}">Αρχική Σελίδα</a>
| <a href="{% url 'logout' %}">Έξοδος</a>
</nav>
<h4>Επεξεργασία Προφίλ Χρήστη</h4>
{% if user.first_name == '' and user.last_name == '' and user.email is None %}
{% if empty_user_profile %}
<p>
<strong>
&#x272A; Αν καταχωρήσατε τα στοιχεία του προφίλ σας κατά τη διάρκεια παλιότερης εισόδου σας στο σύστημα και <br />
αυτά δεν εμφανίζονται τώρα στην παρακάτω φόρμα (είτε γιατί έχετε αλλάξει τα διαπιστευτήρια της <br />
πλατφόρμας εισόδου είτε γιατί έχετε εισέλθει για πρώτη φορά με διαπιστευτήρια αυτής της πλατφόρμας), <br />
παρακαλούμε ανακτήστε τα από τη βάση χωρίς να συμπληρώσετε τα πεδία της παρακάτω φόρμας! <br />
<a href="{% url 'default_user_profile_recovery' user.id %}">&#x2192; Ανάκτηση χωρίς Συμπλήρωση</a>
<a href="{% url 'default_user_profile_recovery' %}">&#x2192; Ανάκτηση χωρίς Συμπλήρωση</a>
</strong>
</p>
<br />
{% endif %}
<form id="user_profile_edit_form" accept-charset="utf-8" action="{% url 'edit_user_profile' user.id %}" method="post">
<form id="user_profile_edit_form" accept-charset="utf-8" action="{% url 'edit_user_profile' %}" method="post">
{% csrf_token %}
<table>
......@@ -50,7 +51,9 @@
</td>
</tr>
<tr>
<td style="text-align:right;"><label for="ece_id">Αριθμός μητρώου<span style="color:darkorange;">*</span>:</label></td>
<td style="text-align:right;">
<label for="ece_id">Αριθμός μητρώου<span style="color:darkorange;">*</span>:</label>
</td>
<td style="text-align:left;">
<input type="text" name="ece_id" id="ece_id" maxlength="8" pattern="031[0-9]{5}"
{% if user.ece_id is not None %}value="{{ user.ece_id }}"{% endif %} />
......@@ -90,6 +93,7 @@
{% endfor %}
{% endif %}
<p><a href="{% url 'user_home' user.id %}">&#x21B5; Επιστροφή στην Αρχική Σελίδα</a></p>
<p><a href="{% url 'user_home' %}">&#x21B5; Επιστροφή στην Αρχική Σελίδα</a></p>
{% endwith %}
{% endblock %}
......@@ -7,7 +7,7 @@
{% block content %}
<nav id="session_nav">
Έχετε εισέλθει επιτυχώς!
| <a href="{% url 'user_home' user.id %}">Αρχική Σελίδα</a>
| <a href="{% url 'user_home' %}">Αρχική Σελίδα</a>
| <a href="{% url 'logout' %}">Έξοδος</a>
</nav>
......@@ -21,7 +21,7 @@
</strong>
</p>
<form id="user_profile_recovery_form" accept-charset="utf-8" action="{% url 'search_for_recovery_user_profile' user.id %}" method="post">
<form id="user_profile_recovery_form" accept-charset="utf-8" action="{% url 'search_for_recovery_user_profile' %}" method="post">
{% csrf_token %}
<table>
......@@ -51,7 +51,7 @@
<strong>
{{ success_message | linebreaksbr }}
<br />
<a href="{% url 'recover_user_profile' user.id recov_user.id %}">&#x2192; Ανάκτηση και Έξοδος</a>
<a href="{% url 'recover_user_profile' %}">&#x2192; Ανάκτηση και Έξοδος</a>
</strong>
</p>
{% elif error_messages %}
......@@ -63,6 +63,6 @@
{% endfor %}
{% endif %}
<p><a href="{% url 'default_user_profile_edit' user.id %}">&#x21B5; Επιστροφή στην Επεξεργασία Προφίλ</a></p>
<p><a href="{% url 'default_user_profile_edit' %}">&#x21B5; Επιστροφή στην Επεξεργασία Προφίλ</a></p>
{% endblock %}
"""usermerge URL Configuration
"""usermerge (application) URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/2.0/topics/http/urls/
......@@ -21,16 +21,13 @@ urlpatterns = [
# The default login page serves as index page. Therefore, its regular route becomes r'^$' instead of r'^login/default$'.
re_path(r'^$', views.display_default_login_page, name = 'default_login'),
re_path(r'^login/submit$', views.log_in, name = 'submit_login'),
re_path(r'^user/home/id=(\d{1,10})$', views.display_user_home_page, name = 'user_home'),
re_path(r'^user/profile/edit/default/id=(\d{1,10})$', views.display_default_user_profile_edit_page, name = 'default_user_profile_edit'),
re_path(r'^user/profile/edit/submit/id=(\d{1,10})$', views.edit_user_profile, name = 'edit_user_profile'),
re_path(r'^user/profile/recovery/default/id=(\d{1,10})$', views.display_default_user_profile_recovery_page,
name = 'default_user_profile_recovery'),
re_path(r'^user/profile/recovery/search/id=(\d{1,10})$', views.search_for_recovery_user_profile,
name = 'search_for_recovery_user_profile'),
re_path(r'^user/profile/recovery/submit/id=(\d{1,10})/recover/id=(\d{1,10})$', views.recover_user_profile,
name = 'recover_user_profile'),
re_path(r'^admin/home/id=(\d{1,10})$', views.display_admin_home_page, name = 'admin_home'),
re_path(r'^user/home$', views.display_user_home_page, name = 'user_home'),
re_path(r'^user/profile/edit/default$', views.display_default_user_profile_edit_page, name = 'default_user_profile_edit'),
re_path(r'^user/profile/edit/submit$', views.edit_user_profile, name = 'edit_user_profile'),
re_path(r'^user/profile/recovery/default$', views.display_default_user_profile_recovery_page, name = 'default_user_profile_recovery'),
re_path(r'^user/profile/recovery/search$', views.search_for_recovery_user_profile, name = 'search_for_recovery_user_profile'),
re_path(r'^user/profile/recovery/submit$', views.recover_user_profile, name = 'recover_user_profile'),
re_path(r'^admin/home$', views.display_admin_home_page, name = 'admin_home'),
re_path(r'^logout$', views.log_out, name = 'logout'),
]
......@@ -23,42 +23,69 @@ from .models import Registry, User
# For more information on making database queries, i.e. creating, retrieving, updating and deleting model instances, see https://docs.djangoproject.com/en/2.0/topics/db/queries/ .
# For more information on working with forms, see https://docs.djangoproject.com/en/2.0/topics/forms/ .
# For more information on using TemplateResponse objects - instead of standard HttpResponse objects and calls to the render() shortcut function - to display application pages/templates, see https://docs.djangoproject.com/en/2.0/ref/template-response/ .
# For more information on the possible/valid (field) states of a user profile (User instance) in usermergeDB and the allowed/consistent transitions between them, see models.py . It is worth mentioning that a user profile is empty if its email is None and vice versa.
# The below defined views refer to the application site; therefore, they are not targeted at the default user model but at the application user models (see the _get_user_model_label() function of auth.py), i.e. the views can be accessed only by usermerge.{User/Admin} instances (the "usermerge." prefix is usually omitted in the application context) and not by auth.User ones - see the User_login_required() and Admin_login_required() decorators. Furthermore, the user instances (including the session one) that are created, retrieved, updated or deleted in the context of each view are usermerge.{User/Admin} instances. On the other hand, the admin site (see https://docs.djangoproject.com/en/2.0/ref/contrib/admin/) is not targeted at the application user models but at the default user model as only auth.User instances can be active staff members - each one has the is_active and is_staff attributes and the latter are set to True - and also have permissions - each one has the is_superuser, groups and user_permissions attributes as well as the relative methods, e.g. get_group_permissions(), get_all_permissions(), etc. - to access the site and utilize some or all of its capabilities. The admin site should generally be used for retrieving/reviewing model instances and not for creating, updating or deleting them - the latter actions should better be performed by appropriately defined views. When trying to create, update or delete instances via the admin site, extra care should be given to retain consistency in usermergeDB, e.g. a Platform instance could be created without any problem, while the updated password of an Admin instance would wrongly be stored in raw format (without being hashed first), etc. (for more information, see models.py).
# For more information on the possible/valid (field) states of a user profile (User instance) in usermergeDB and the allowed/consistent transitions between them, see models.py . It is worth mentioning that a user profile is empty if its email is None and vice versa - see the has_empty_profile() method of User model.
# A user whose model is User and profile is non-empty should have access to all the User-targeted, i.e. User_login_required()-decorated, views except for the user profile recovery ones. On the other hand, a user whose model is User and profile is empty should have access only to the User-targeted views that relate to the user home page and the user profile edit/recovery. Therefore, he/she should fill out his/her profile or recover a non-empty one from usermergeDB first to gain access to all the other User-targeted views (these views should ensure that only non-empty user profiles are allowed access) - if this was done, he/she would have access to all the User-targeted views except for the user profile recovery ones. Finally, a user whose model is Admin should have access to all the Admin-targeted, i.e. Admin_login_required()-decorated, views.
# The below defined views are not targeted at the default user model but at the application user models (see the _get_user_model_label() function of auth.py), i.e. the views can be accessed only by usermerge.{User/Admin} instances (the "usermerge." prefix is usually omitted in the application context) and not by auth.User ones - see the User_login_required() and Admin_login_required() decorators. Furthermore, the user instances (including the session one) that are created, retrieved, updated or deleted in the context of each view are usermerge.{User/Admin} instances. On the other hand, the admin site (see https://docs.djangoproject.com/en/2.0/ref/contrib/admin/) is not targeted at the application user models but at the default user model as only auth.User instances can be active staff members - each one has the is_active and is_staff attributes and the latter are set to True - and also have permissions - each one has the is_superuser, groups and user_permissions attributes as well as the relative methods, e.g. get_group_permissions(), get_all_permissions(), etc. - to access the site and utilize some or all of its capabilities. The admin site should generally be used for retrieving/reviewing model instances and not for creating, updating or deleting them - the latter actions should better be performed by appropriately defined views. When trying to create, update or delete instances via the admin site, extra care should be given to retain consistency in usermergeDB, e.g. a Platform instance could be created without any problem, while the updated password of an Admin instance would wrongly be stored in raw format (without being hashed first), etc. (for more information, see models.py).
def display_default_login_page(request):
def display_default_login_page(request): # The default login page is the index page of the application site.
"""
Display the login page in default mode, i.e. without any form-submission-related messages.
The default login page is the index page of the usermerge application.
Check if the current user has logged in. If he/she has not (his/her model is AnonymousUser), display the login page in default
mode, i.e. without any form-submission-related messages. Otherwise, check if his/her model is auth.User . If it is (he/she has
logged in to the admin site), display an HTTP 403 (Forbidden) page by raising a PermissionDenied exception (he/she has logged
in to the admin site and should thus be prevented from accessing any application page/template). Otherwise (his/her model is
usermerge.{User/Admin} and he/she has logged in to the application site), display the session continuation page which informs
him/her that his/her session is still active and provides him/her with the choices of either navigating to his/her model-specific
home page (if he/she would like to continue navigating in this session) or logging out of the application site (if he/she would
like to start a new session as another user).
"""
current_user = request.user
if current_user.is_authenticated:
current_user_model_label = current_user._meta.label
if current_user_model_label == 'usermerge.User':
return TemplateResponse(request, 'session_continuation.html', {'home_page_url': 'user_home'})
elif current_user_model_label == 'usermerge.Admin':
return TemplateResponse(request, 'session_continuation.html', {'home_page_url': 'admin_home'})
else: # current_user_model_label == 'auth.User'
raise PermissionDenied
else: # current user model is AnonymousUser
return TemplateResponse(request, 'login.html', {'platform_names': get_all_platform_names_from_DB()})
def log_in(request):
"""
Collect the data, i.e. platform, username and password, POSTed via the login form and validate them. If they are not valid, display
the appropriate validation error messages in the login page. Otherwise, authenticate the credentials (username and password) for
the selected platform. If they do not correspond to any user instance of usermergeDB, display the appropriate post-validation error
message in the login page and include the corresponding error code in the page context. Otherwise, log the user in and redirect
him/her to the appropriate home page depending on his/her model (User/Admin).
Check if the current user has logged in. If he/she has (he/she has logged in either to the admin site as an auth.User instance or
to the application site as a usermerge.{User/Admin} instance), display an HTTP 403 (Forbidden) page by raising a PermissionDenied
exception (he/she has logged in either to the admin site and should thus be prevented from accessing any application view or to
the application site and should thus be prevented from reattempting to log in to the latter). Otherwise (he/she is an AnonymousUser
instance), collect the data, i.e. platform, username and password, POSTed via the login form and validate them. If they are not
valid, display the appropriate validation error messages in the login page. Otherwise, authenticate the credentials (username and
password) for the selected platform. If they do not specify any usermerge.{User/Admin} instance of usermergeDB, display the
appropriate post-validation error message in the login page and include the corresponding error code in the page context. Otherwise,
log the current user in to the application site as the specified (authenticated) usermerge.{User/Admin} instance and redirect him/her
to his/her model-specific home page.
"""
if request.user.is_authenticated: # The current user is either an auth.User or a usermerge.{User/Admin} instance.
raise PermissionDenied
else: # The current user is an AnonymousUser instance.
form = LoginForm(request.POST)
if form.is_valid():
platform = form.cleaned_data['platform']
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user = authenticate(request, platform = platform, username = username, password = password)
if user:
login(request, user)
# If the selected platform is SLUB, the user model is Admin. Otherwise, it is User.
auth_user = authenticate(request, platform = platform, username = username, password = password)
if auth_user:
login(request, auth_user)
# If the selected platform is SLUB, the authenticated (just logged-in) user's model is usermerge.Admin .
# Otherwise, it is usermerge.User .
if platform == 'SLUB':
return redirect('admin_home', user.id)
return redirect('admin_home')
else:
return redirect('user_home', user.id)
return redirect('user_home')
else:
return TemplateResponse(request, 'login.html',
{'platform_names': get_all_platform_names_from_DB(),
'error_messages': ['Τα δηλωθέντα στοιχεία εισόδου δεν ανταποκρίνονται σε κανέναν χρήστη της βάσης!\n'
'error_messages': ['Τα δηλωθέντα στοιχεία εισόδου δεν ανταποκρίνονται '
'σε κανέναν χρήστη της βάσης!\n'
'Παρακαλούμε ελέγξτε την ορθότητα των στοιχείων εισόδου και δοκιμάστε ξανά!'],
'post_validation_error_codes': ['non_existent_credentials_pair_for_selected_login_platform']})
else:
......@@ -66,21 +93,21 @@ def log_in(request):
'error_messages': get_form_error_messages(form)})
@User_login_required
def display_user_home_page(request, user_id):
def display_user_home_page(request):
"""
Display the user home page.
"""
return TemplateResponse(request, 'user_home.html', {})
@User_login_required
def display_default_user_profile_edit_page(request, user_id):
def display_default_user_profile_edit_page(request):
"""
Display the user profile edit page in default mode, i.e. without any form-submission-related messages.
"""
return TemplateResponse(request, 'user_profile_edit.html', {})
@User_login_required
def edit_user_profile(request, user_id):
def edit_user_profile(request):
"""
Collect the data, i.e. first name, last name, ece_id and email, POSTed via the user profile edit form and validate them. If they
are not valid, display the appropriate validation error messages in the user profile edit page. Otherwise, check if any form fields
......@@ -93,7 +120,7 @@ def edit_user_profile(request, user_id):
function with the (name) list of all the changed form fields as the changed_data argument and the dictionary of all the validated
form data (the field names are used as keys and the corresponding validated values as values) as the cleaned_data argument.
"""
session_user = User.objects.get(pk = user_id)
session_user = request.user
form = UserProfileEditForm(request.POST, initial = {'first_name': session_user.first_name, 'last_name': session_user.last_name,
'ece_id': session_user.ece_id, 'email': session_user.email})
if form.is_valid():
......@@ -113,7 +140,7 @@ def edit_user_profile(request, user_id):
else:
changed_data = form.changed_data
# The session user's profile in usermergeDB is empty (session_user.ece_id is None and session_user.email is None).
if session_user.first_name == '' and session_user.last_name == '' and session_user.email is None:
if session_user.has_empty_profile():
try:
User.objects.get(email = email)
except User.DoesNotExist:
......@@ -231,22 +258,21 @@ def edit_user_profile(request, user_id):
return TemplateResponse(request, 'user_profile_edit.html', {'error_messages': get_form_error_messages(form)})
@User_login_required
def display_default_user_profile_recovery_page(request, user_id):
def display_default_user_profile_recovery_page(request):
"""
Check if the session user's profile in usermergeDB is empty. If it is not, display an HTTP 403 (Forbidden) page by raising a
PermissionDenied exception (there is no point in specifying and recovering a non-empty user profile from usermergeDB for the
session user if the latter's profile is already non-empty - see the search_for_recovery_user_profile() and recover_user_profile()
views below). Otherwise, display the user profile recovery page in default mode, i.e. without any form-submission-related messages.
"""
session_user = User.objects.get(pk = user_id)
# The session user's profile in usermergeDB is non-empty.
if session_user.first_name != '' and session_user.last_name != '' and session_user.email is not None:
session_user = request.user
if not session_user.has_empty_profile():
raise PermissionDenied
else:
return TemplateResponse(request, 'user_profile_recovery.html', {})
@User_login_required
def search_for_recovery_user_profile(request, user_id):
def search_for_recovery_user_profile(request):
"""
Check if the session user's profile in usermergeDB is empty. If it is not, display an HTTP 403 (Forbidden) page by raising a
PermissionDenied exception (there is no point in searching usermergeDB to recover a non-empty profile for the session user if
......@@ -260,13 +286,19 @@ def search_for_recovery_user_profile(request, user_id):
Otherwise, call the _display_user_profile_recovery_success_message() helper function with the specified profile as the
recov_user argument.
"""
# This view serves as the preparatory step of the user profile recovery procedure, i.e. it is used to set up the corresponding
# page context appropriately before the actual procedure takes place - see the recover_user_profile() view below. The context
# is set up by the called helper function - either _display_user_profile_recovery_error_messages() or
# _display_user_profile_recovery_success_message().
session_user = User.objects.get(pk = user_id)
# The current view serves as the preparatory step of the user profile recovery procedure, i.e. it is used to set up the
# corresponding session and page contexts appropriately before the recovery procedure takes place - see the recover_user_profile()
# view below. Both contexts are set up by the called helper function - either _display_user_profile_recovery_success_message()
# or _display_user_profile_recovery_error_messages(). For the session one in particular, the state of the recov_user_id value is
# appropriately modified in the session data to represent the latest search result of the current view, i.e. either the
# recov_user_id value exists in the session data and represents the id of the specified recovery user profile or it does not
# exist and indicates that no recovery user profile has been specified. The recov_user_id value is stored in the session data and
# is obtained from there by the recover_user_profile() view instead of being given to that view as a URL argument because in the
# latter case it would be susceptible to manual change (e.g. it could be misedited via JavaScript) and could thus bypass the
# appropriate recovery user profile specification provided by the current view.
session_user = request.user
# The session user's profile in usermergeDB is non-empty (session_user.email is not None).
if session_user.first_name != '' and session_user.last_name != '' and session_user.email is not None:
if not session_user.has_empty_profile():
raise PermissionDenied
else: # The session user's profile in usermergeDB is empty (session_user.ece_id is None and session_user.email is None).
form = UserProfileRecoveryForm(request.POST)
......@@ -358,27 +390,30 @@ def search_for_recovery_user_profile(request, user_id):
return TemplateResponse(request, 'user_profile_recovery.html', {'error_messages': get_form_error_messages(form)})
@User_login_required
def recover_user_profile(request, session_user_id, recov_user_id):
def recover_user_profile(request):
"""
Check if the session user's profile in usermergeDB is empty. If it is not, display an HTTP 403 (Forbidden) page by raising a
PermissionDenied exception (there is no point in recovering a non-empty profile from usermergeDB for the session user if the latter's
profile is already non-empty). Otherwise, delete any previous credentials that the recovery user may have retained for the login
platform in usermergeDB and associate him/her with the session user's respective ones. More specifically, delete the recovery
registry, i.e. the Registry instance that corresponds to both the recovery user and the login platform, if it exists in usermergeDB
and update the existing session registry, i.e. the Registry instance that corresponds to both the session user and the login platform,
to reference the recovery user instead. Then delete the session user's profile to complete his/her merge with the recovery user and if
the latter's credentials for the login platform have changed, i.e. he/she retained previous credentials before receiving the session
user's respective ones, use the view logger (usermerge.views.recover_user_profile) to log the appropriate INFO message that mentions
the recovery user's previous and current username (key credential) for the login platform. Finally, log the session user out (flush
the session as it is based on a no longer existing user - profile - and has thus become inconsistent) and redirect him/her to the
default login page.
Check if the session user's profile in usermergeDB is empty and if the recov_user_id value exists in the session data, i.e. if a
non-empty recovery user profile (User instance) has been specified in usermergeDB via the search_for_recovery_user_profile() view.
If any of the checks fails, display an HTTP 403 (Forbidden) page by raising a PermissionDenied exception (it is impossible to recover
an unspecified non-empty user profile from usermergeDB and there is no point in recovering a specified one for the session user if
the latter's profile is already non-empty). Otherwise, delete any previous credentials that the recovery user may have retained for
the login platform in usermergeDB and associate him/her with the session user's respective ones. More specifically, delete the
recovery registry, i.e. the Registry instance that corresponds to both the recovery user and the login platform, if it exists in
usermergeDB and update the existing session registry, i.e. the Registry instance that corresponds to both the session user and the
login platform, to reference the recovery user instead. Then delete the session user's profile to complete his/her merge with the
recovery user and if the latter's credentials for the login platform have changed, i.e. he/she retained previous credentials before
receiving the session user's respective ones, use the view logger (usermerge.views.recover_user_profile) to log the appropriate INFO
message that mentions the recovery user's previous and current username (key credential) for the login platform. Finally, log the
session user out (flush the session as it is based on a no longer existing user - profile - and has thus become inconsistent) and
redirect him/her to the default login page.
"""
# For more information on the recov_user_id value of the session data, see the search_for_recovery_user_profile() view above.
view_logger = logging.getLogger('usermerge.views.recover_user_profile')
session_user = User.objects.get(pk = session_user_id)
# The session user's profile in usermergeDB is non-empty.
if session_user.first_name != '' and session_user.last_name != '' and session_user.email is not None:
session_user = request.user
if not (session_user.has_empty_profile() and 'recov_user_id' in request.session):
raise PermissionDenied
else:
recov_user_id = request.session['recov_user_id']
login_platform_name = request.session[PLATFORM_SESSION_KEY]
session_registry = Registry.objects.get(user = session_user, platform__name = login_platform_name)
prev_recov_username = ''
......@@ -412,17 +447,24 @@ def recover_user_profile(request, session_user_id, recov_user_id):
return redirect('default_login')
@Admin_login_required
def display_admin_home_page(request, user_id):
def display_admin_home_page(request):
"""
Display the admin home page.
"""
return TemplateResponse(request, 'admin_home.html', {})
@login_required(redirect_field_name = None, login_url = 'default_login') # The session user's model can be either User or Admin.
# The session user's model can be either auth.User or usermerge.{User/Admin} .
@login_required(redirect_field_name = None, login_url = 'default_login')
def log_out(request):
"""
Log the session user out and redirect him/her to the default login page.
Check if the session user's model is auth.User . If it is (he/she has logged in to the admin site), display an HTTP 403 (Forbidden)
page by raising a PermissionDenied exception (he/she has logged in to the admin site and should thus be prevented from accessing
any application view). Otherwise (his/her model is usermerge.{User/Admin} and he/she has logged in to the application site), log
him/her out and redirect him/her to the default login page.
"""
if request.user._meta.label == 'auth.User':
raise PermissionDenied
else: # request.user._meta.label in ['usermerge.User', 'usermerge.Admin']
logout(request)
return redirect('default_login')
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment