Commit 0320cadc authored by Giorgos Kazelidis's avatar Giorgos Kazelidis

- Wrapped the edit_user_profile(), recover_user_profile() and...

- Wrapped the edit_user_profile(), recover_user_profile() and import_user_credentials() views in the atomic() decorator to run database modification queries within an atomic transaction
- Utilized SELECT FOR UPDATE queries in the edit_user_profile() and recover_user_profile() views to lock database rows (model instances) intended for update during an atomic transaction
- Added the "PROJECT OVERVIEW" and "LIST OF SUGGESTED TO-DO ACTIONS" parts to README.md
- Added documentation links to the "ENVIRONMENT SPECIFICATIONS" part of README.md
- Changed the names of the Django root and project directories from myprj to slub
- Changed the name of helper.py module to helpers.py
parent 3fbfccbd
......@@ -9,4 +9,4 @@
venv/
# folder that contains the log files created in production - see the "Logging" part of settings.py
myprj/usermerge/production_logs/
slub/usermerge/production_logs/
## PROJECT OVERVIEW
* Type: Diploma thesis
* Subject: Development of the SoftLab UserBase (SLUB) web tool
* Author: Georgios Kazelidis \<giorgkazelidis@gmail.com>
* Supervisor: Nikolaos Papaspyrou \<nickie@softlab.ntua.gr>
* Copyright: -
* License: -
## ENVIRONMENT SPECIFICATIONS
* Working OS: Ubuntu 16.04 LTS
* Python version: 3.5.2 (pre-installed)
* Git version: 2.7.4
* pip3 version: 10.0.1
* virtualenv version: 15.2.0
* Django version: 2.0.4
* pytz version: 2018.4
* concurrent-log-handler version: 0.9.12
* mysqlclient version: 1.3.12
* MySQL server version: 5.7.24
* Working OS: Ubuntu 16.04 LTS [https://www.ubuntu.com/]
* Python version: 3.5.2 (pre-installed) [https://www.python.org/]
* Git version: 2.7.4 [https://git-scm.com/]
* pip3 version: 10.0.1 [https://pypi.org/project/pip/]
* virtualenv version: 15.2.0 [https://pypi.org/project/virtualenv/]
* Django version: 2.0.4 [https://www.djangoproject.com/]
* pytz version: 2018.4 [https://pypi.org/project/pytz/]
* concurrent-log-handler version: 0.9.12 [https://pypi.org/project/concurrent-log-handler/]
* mysqlclient version: 1.3.12 [https://pypi.org/project/mysqlclient/]
* MySQL server version: 5.7.24 [https://dev.mysql.com/]
## DOWNLOADING THE PROJECT & SETTING UP THE ENVIRONMENT
(A) install pip3 (`pip3 --version` to see if it is already installed):
......@@ -85,14 +93,14 @@
sudo apt-get install mysql-server
mysql_secure_installation
&nbsp; &nbsp; &nbsp; (7) use the password that was set for the root user during MySQL server installation as the DATABASES['default']['PASSWORD'] value in **~/Desktop/userbase/myprj/myprj/settings.py**
&nbsp; &nbsp; &nbsp; (7) use the password that was set for the root user during MySQL server installation as the DATABASES['default']['PASSWORD'] value in **~/Desktop/userbase/slub/slub/settings.py**
&nbsp; &nbsp; &nbsp; (8) copy the time zone definitions of the system's zoneinfo database, which is located in the /usr/share/zoneinfo/ directory of Ubuntu and most other Unix-like systems, to the "mysql" database without worrying about some possible "Unable to load/Skipping" warnings (you will be asked to provide the password of the MySQL root user) and restart MySQL server (you can skip this substep if you have already executed it once):
mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql
sudo service mysql restart
&nbsp; &nbsp; &nbsp; (9) navigate to the project directory (myprj):
&nbsp; &nbsp; &nbsp; (9) navigate to the project directory (slub):
cd myprj
cd slub
&nbsp; &nbsp; &nbsp; (10) open MySQL console with root privileges:
python manage.py dbshell
......@@ -108,8 +116,8 @@
&nbsp; &nbsp; &nbsp; (13) exit MySQL console:
EXIT;
&nbsp; &nbsp; &nbsp; (14) use the collation that was selected during the project database creation as the DATABASES['default']['OPTIONS']['init_command']#collation_connection value in **~/Desktop/userbase/myprj/myprj/settings.py**
&nbsp; &nbsp; &nbsp; (15) if MySQL server version is 5.5.4 and earlier, set SET_DEFAULT_STORAGE_ENGINE_TO_INNODB to "True" in **~/Desktop/userbase/myprj/myprj/settings.py**
&nbsp; &nbsp; &nbsp; (14) use the collation that was selected during the project database creation as the DATABASES['default']['OPTIONS']['init_command']#collation_connection value in **~/Desktop/userbase/slub/slub/settings.py**
&nbsp; &nbsp; &nbsp; (15) if MySQL server version is 5.5.4 and earlier, set SET_DEFAULT_STORAGE_ENGINE_TO_INNODB to "True" in **~/Desktop/userbase/slub/slub/settings.py**
&nbsp; &nbsp; &nbsp; (16) initiate the project database (the tables are created during this substep):
python manage.py migrate
......@@ -128,7 +136,7 @@
source venv/bin/activate
(B) navigate to the project directory:
cd myprj
cd slub
(C\) create a superuser account in the project database (usermergeDB) if you have not already done so (this step is necessary for accessing the Django admin site) [sources:
&nbsp; &nbsp; &nbsp; -- https://docs.djangoproject.com/en/2.0/ref/contrib/admin/
&nbsp; &nbsp; &nbsp; ]:
......@@ -138,7 +146,7 @@
(D) start the Django development server (at http://127.0.0.1:8000/):
python manage.py runserver
(E) access the Django admin site by navigating to http://127.0.0.1:8000/admin/ (via web browser) and filling out the emerging login form with the credentials of the aforementioned superuser account OR run the project by navigating to http://127.0.0.1:8000/
(E) access the Django admin site by navigating to http://127.0.0.1:8000/django-admin/ (via web browser) and filling out the emerging login form with the credentials of the aforementioned superuser account OR run the project by navigating to http://127.0.0.1:8000/
## STOPPING THE DJANGO DEVELOPMENT SERVER (AND EXITING THE VIRTUAL ENVIRONMENT)
(A) stop the Django development server (running at http://127.0.0.1:8000/):
......@@ -153,3 +161,12 @@ Provided you have already downloaded the (source code of the) project (that is,
rm -rf ~/Desktop/userbase
&nbsp; &nbsp; &nbsp; (2) follow steps (D) and (E) of the "DOWNLOADING THE PROJECT & SETTING UP THE ENVIRONMENT" section above
## LIST OF SUGGESTED TO-DO ACTIONS
* Create and use a Makefile for setting up/updating the project [https://www.gnu.org/software/make/manual/make.html]
* Create and use a criteria-based (e.g. last_login-based) batch deletion view for User/Registry instances to ensure that the project database (usermergeDB) remains "small" and thus efficient to interact with - see models.py
* Create and run unit tests [https://docs.djangoproject.com/en/2.0/topics/testing/]
* Make better use of the Django admin site capabilities
* Make better use of Django's model validation capabilities [https://docs.djangoproject.com/en/2.0/ref/models/instances/]
* Utilize Django's password upgrading and validation schemes [https://docs.djangoproject.com/en/2.0/topics/auth/passwords/]
* Enhance security, e.g. enable HTTPS/SSL protection, enable Host header validation, etc. [https://docs.djangoproject.com/en/2.0/topics/security/]
......@@ -3,7 +3,7 @@ import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myprj.settings")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "slub.settings")
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
......
"""
Django settings for myprj project.
Django settings for slub project.
Generated by 'django-admin startproject' using Django 2.0.4.
......@@ -50,7 +50,7 @@ MIDDLEWARE = [
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'myprj.urls'
ROOT_URLCONF = 'slub.urls'
TEMPLATES = [
{
......@@ -68,7 +68,7 @@ TEMPLATES = [
},
]
WSGI_APPLICATION = 'myprj.wsgi.application'
WSGI_APPLICATION = 'slub.wsgi.application'
# Authentication
......
"""myprj URL Configuration
"""slub URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/2.0/topics/http/urls/
......
"""
WSGI config for myprj project.
WSGI config for slub project.
It exposes the WSGI callable as a module-level variable named ``application``.
......@@ -11,6 +11,6 @@ import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myprj.settings")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "slub.settings")
application = get_wsgi_application()
from django.core.exceptions import ValidationError
from .helper import get_all_platform_names_from_DB
from .helpers import get_all_platform_names_from_DB
from .models import Platform
# Create your validators here.
......
......@@ -4,6 +4,7 @@ from django.contrib.auth.decorators import login_required
from django.contrib.auth.hashers import make_password
from django.contrib.auth.models import AnonymousUser
from django.core.exceptions import PermissionDenied
from django.db import transaction
from django.db.models import Q
from django.http import HttpResponse
from django.shortcuts import redirect
......@@ -12,7 +13,7 @@ from django.utils import timezone
from .auth import login, PLATFORM_SESSION_KEY
from .decorators import Admin_login_required, User_login_required
from .forms import LoginForm, UserCredentialsImportForm, UserProfileEditForm, UserProfileRecoveryForm, UserReportCreationForm
from .helper import (
from .helpers import (
get_all_platform_names_from_DB, get_form_error_messages, seq_to_aligned_str, _display_user_profile_edit_error_messages,
_display_user_profile_recovery_error_messages, _display_user_profile_recovery_success_message, _update_user_profile
)
......@@ -23,6 +24,7 @@ from .models import Platform, Registry, User
# For more information on configuring and using the logging system, see https://docs.djangoproject.com/en/2.0/topics/logging/ and the "Logging" part of settings.py .
# For more information on default/customizing user authentication and password management, see https://docs.djangoproject.com/en/2.0/topics/auth/, auth.py, backends.py and AuthenticationMiddleware of middleware.py .
# For more information on managing database transactions, see https://docs.djangoproject.com/en/2.0/topics/db/transactions/ .
# 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 handling file uploads, see https://docs.djangoproject.com/en/2.0/topics/http/file-uploads/ .
......@@ -113,6 +115,7 @@ def display_default_user_profile_edit_page(request):
return TemplateResponse(request, 'user_profile_edit.html', {})
@User_login_required
@transaction.atomic
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
......@@ -126,7 +129,7 @@ def edit_user_profile(request):
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 = request.user
session_user = User.objects.select_for_update().get(pk = request.user.id)
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():
......@@ -396,6 +399,7 @@ def search_for_recovery_user_profile(request):
return TemplateResponse(request, 'user_profile_recovery.html', {'error_messages': get_form_error_messages(form)})
@User_login_required
@transaction.atomic
def recover_user_profile(request):
"""
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
......@@ -421,7 +425,7 @@ def recover_user_profile(request):
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)
session_registry = Registry.objects.select_for_update().get(user = session_user, platform__name = login_platform_name)
prev_recov_username = ''
# The changes in usermergeDB should be made in the following order:
# * Due to the user-platform unique key constraint of the Registry model, the recovery registry should be deleted if it exists
......@@ -467,6 +471,7 @@ def display_default_user_credentials_import_page(request):
return TemplateResponse(request, 'user_credentials_import.html', {'platform_names': get_all_platform_names_from_DB()})
@Admin_login_required
@transaction.atomic
def import_user_credentials(request):
"""
Collect the data, i.e. platform and credentials file, POSTed via the user credentials import form and validate them. If they are not
......
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