From c013bc8d4354f3fad630d0bea5febb918ab80fb2 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 1 Jul 2024 12:18:42 +0200 Subject: [PATCH] add login --- dhub/settings.py | 35 +++- login/__init__.py | 0 login/admin.py | 3 + login/apps.py | 6 + login/migrations/__init__.py | 0 login/models.py | 3 + login/templates/2fadmin.html | 19 ++ login/templates/2fadmin_email.html | 26 +++ login/templates/2fadmin_email.txt | 14 ++ login/templates/2fadmin_email_subject.txt | 3 + login/templates/login.html | 45 +++++ login/templates/login2.html | 52 ++++++ login/templates/login3.html | 179 +++++++++++++++++++ login/templates/login_base.html | 133 ++++++++++++++ login/templates/password_reset.html | 27 +++ login/templates/password_reset_complete.html | 16 ++ login/templates/password_reset_confirm.html | 36 ++++ login/templates/password_reset_done.html | 15 ++ login/templates/password_reset_email.html | 30 ++++ login/templates/password_reset_email.txt | 14 ++ login/templates/password_reset_subject.txt | 3 + login/tests.py | 3 + login/urls.py | 34 ++++ login/views.py | 73 ++++++++ 24 files changed, 768 insertions(+), 1 deletion(-) create mode 100644 login/__init__.py create mode 100644 login/admin.py create mode 100644 login/apps.py create mode 100644 login/migrations/__init__.py create mode 100644 login/models.py create mode 100644 login/templates/2fadmin.html create mode 100644 login/templates/2fadmin_email.html create mode 100644 login/templates/2fadmin_email.txt create mode 100644 login/templates/2fadmin_email_subject.txt create mode 100644 login/templates/login.html create mode 100644 login/templates/login2.html create mode 100644 login/templates/login3.html create mode 100644 login/templates/login_base.html create mode 100644 login/templates/password_reset.html create mode 100644 login/templates/password_reset_complete.html create mode 100644 login/templates/password_reset_confirm.html create mode 100644 login/templates/password_reset_done.html create mode 100644 login/templates/password_reset_email.html create mode 100644 login/templates/password_reset_email.txt create mode 100644 login/templates/password_reset_subject.txt create mode 100644 login/tests.py create mode 100644 login/urls.py create mode 100644 login/views.py diff --git a/dhub/settings.py b/dhub/settings.py index ec38755..7feb8c6 100644 --- a/dhub/settings.py +++ b/dhub/settings.py @@ -11,6 +11,8 @@ https://docs.djangoproject.com/en/5.0/ref/settings/ """ from pathlib import Path +from django.contrib.messages import constants as messages +from decouple import config, Csv # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent @@ -40,6 +42,7 @@ INSTALLED_APPS = [ 'django_extensions', 'django_bootstrap5', "rest_framework", + "login", "user", "device", "snapshot", @@ -47,7 +50,7 @@ INSTALLED_APPS = [ "tag", "lot", "documents", - "inventory", + "dashboard", ] @@ -55,6 +58,7 @@ MIDDLEWARE = [ "django.middleware.security.SecurityMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", "django.middleware.common.CommonMiddleware", + 'django.middleware.locale.LocaleMiddleware', "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", @@ -128,6 +132,11 @@ USE_TZ = True # https://docs.djangoproject.com/en/5.0/howto/static-files/ STATIC_URL = "static/" +STATIC_URL = '/static/' +MEDIA_URL = '/media/' + +STATIC_ROOT = config('STATIC_ROOT', default="static") +MEDIA_ROOT = config('MEDIA_ROOT', default="upload") # Default primary key field type # https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field @@ -135,3 +144,27 @@ STATIC_URL = "static/" DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" AUTH_USER_MODEL = 'user.User' + +MESSAGE_TAGS = { + messages.DEBUG: 'alert-secondary', + messages.INFO: 'alert-info', + messages.SUCCESS: 'alert-success', + messages.WARNING: 'alert-warning', + messages.ERROR: 'alert-danger', + } + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' +LOGIN_REDIRECT_URL = 'dashboard:dashboard' +LOGOUT_REDIRECT_URL = '/' + +LOGGING = { + "version": 1, + "disable_existing_loggers": False, + "handlers": { + "console": {"level": "DEBUG", "class": "logging.StreamHandler"}, + }, + "root": { + "handlers": ["console"], + "level": "DEBUG", + } +} diff --git a/login/__init__.py b/login/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/login/admin.py b/login/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/login/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/login/apps.py b/login/apps.py new file mode 100644 index 0000000..498a928 --- /dev/null +++ b/login/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class LoginConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "login" diff --git a/login/migrations/__init__.py b/login/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/login/models.py b/login/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/login/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/login/templates/2fadmin.html b/login/templates/2fadmin.html new file mode 100644 index 0000000..e96d1b7 --- /dev/null +++ b/login/templates/2fadmin.html @@ -0,0 +1,19 @@ +{% extends "auth/login_base.html" %} +{% load i18n django_bootstrap5 %} + +{% block login_content %} + +
+
+

{% trans 'Two-factor Authentication' %}

+
+
+ +
+
+
+ {% trans "We have sent you an email with a link that you have to click to log in." %} +
+
+
+{% endblock %} diff --git a/login/templates/2fadmin_email.html b/login/templates/2fadmin_email.html new file mode 100644 index 0000000..6ea0793 --- /dev/null +++ b/login/templates/2fadmin_email.html @@ -0,0 +1,26 @@ +{% load i18n %}{% autoescape off %} +

+{% blocktrans %}You're receiving this email because you tried to access {{ site_name }}.{% endblocktrans %} +

+ +

+{% trans "Please go to the following page" %} +

+ +

+{% block reset_link %} + +{{ protocol }}://{{ domain }}{% url 'idhub:admin_2fauth' admin2fauth=token %} + +{% endblock %} +

+ +

+{% trans "Thanks for using our site!" %} +

+ +

+{% blocktrans %}The {{ site_name }} team{% endblocktrans %} +

+ +{% endautoescape %} diff --git a/login/templates/2fadmin_email.txt b/login/templates/2fadmin_email.txt new file mode 100644 index 0000000..6328f66 --- /dev/null +++ b/login/templates/2fadmin_email.txt @@ -0,0 +1,14 @@ +{% load i18n %}{% autoescape off %} +{% blocktrans %}You're receiving this email because you tried to access {{ site_name }}.{% endblocktrans %} + +{% trans "Please go to the following page" %} +{% block reset_link %} +{{ protocol }}://{{ domain }}{% url 'idhub:admin_2fauth' admin2fauth=token %} +{% endblock %} +{% trans "Your username, in case you've forgotten:" %} {{ user.username }} + +{% trans "Thanks for using our site!" %} + +{% blocktrans %}The {{ site_name }} team{% endblocktrans %} + +{% endautoescape %} diff --git a/login/templates/2fadmin_email_subject.txt b/login/templates/2fadmin_email_subject.txt new file mode 100644 index 0000000..6d3bb21 --- /dev/null +++ b/login/templates/2fadmin_email_subject.txt @@ -0,0 +1,3 @@ +{% load i18n %}{% autoescape off %} +{% blocktrans %}Authentication in {{ site_name }}{% endblocktrans %} +{% endautoescape %} \ No newline at end of file diff --git a/login/templates/login.html b/login/templates/login.html new file mode 100644 index 0000000..97ba4cb --- /dev/null +++ b/login/templates/login.html @@ -0,0 +1,45 @@ +{% extends "login_base.html" %} +{% load i18n static %} + +{% block login_content %} +
+ {% csrf_token %} +
+ +
Please enter your email.
+ {% if form.username.errors %} +

+ {{ form.username.errors|striptags }} +

+ {% endif %} +
+ +
+
+ + {% if form.password.errors %} +

+ {{ form.password.errors|striptags }} +

+ {% endif %} + + +
+
Please enter your password!
+
+ + + +
+ +
+
+ +{% endblock %} diff --git a/login/templates/login2.html b/login/templates/login2.html new file mode 100644 index 0000000..4693f0b --- /dev/null +++ b/login/templates/login2.html @@ -0,0 +1,52 @@ +{% extends "login_base.html" %} +{% load i18n static %} + +{% block login_content %} +
+ {% csrf_token %} +
+
+ + {% if form.username.errors %} +

+ {{ form.username.errors|striptags }} +

+ {% endif %} +
+
+ +
+
+ + {% if form.password.errors %} +

+ {{ form.password.errors|striptags }} +

+ {% endif %} +
+
+ + {% if form.non_field_errors %} + {% for error in form.non_field_errors %} +
{{ error }}
+ {% endfor %} + {% endif %} + + + +
+ +
+
+ +{% endblock %} diff --git a/login/templates/login3.html b/login/templates/login3.html new file mode 100644 index 0000000..8ea40f1 --- /dev/null +++ b/login/templates/login3.html @@ -0,0 +1,179 @@ + + + + + + + + Login - Usody + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+ +
+ + + +
+ +
+ +
+ +
+
Sign in
+ +
+ +
+ + +
+ +
Please enter your email.
+
+ +
+
+ + + +
+
Please enter your password!
+
+ + +
+ +
+
+

Don't have account? Create an account

+

Forgot password? Reset your password

+
+
+ +
+
+ +
+ Help | + Privacy | + Terms +
+ +
+
+
+ +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + diff --git a/login/templates/login_base.html b/login/templates/login_base.html new file mode 100644 index 0000000..53ad77f --- /dev/null +++ b/login/templates/login_base.html @@ -0,0 +1,133 @@ +{% load i18n static %} + + + + + {% block head %} + {% block meta %} + + + + + + {% endblock %} + {% block title %}{% if title %}{{ title }} – {% endif %}DeviceHub{% endblock %} + + + {% block style %} + + + + + + + + + + {% endblock %} + {% endblock %} + + + +
+ +
+
+
+
+ +
+ + Pangea.org - Internet etic i solidari + +
+ +
+ +
+ +
+
Sign in
+ +
+ + {% block login_content %} + {% endblock login_content %} + +
+
+ +
+
+ +
+
+
+ +
+ +
+ +
+
+
+ {% block messages %} + {% for message in messages %} + + {% endfor %} + {% endblock messages %} +
+
+
+ + + + + + + + + + + diff --git a/login/templates/password_reset.html b/login/templates/password_reset.html new file mode 100644 index 0000000..3bc5e79 --- /dev/null +++ b/login/templates/password_reset.html @@ -0,0 +1,27 @@ +{% extends "login_base.html" %} +{% load i18n django_bootstrap5 %} + +{% block login_content %} + +
+
+

{% trans 'Password reset' %}

+ {% trans "Forgotten your password? Enter your email address below, and we'll email instructions for setting a new one." %} +
+
+ +
+
+
+
+ {% csrf_token %} + {% bootstrap_form form %} + {% bootstrap_form_errors form type='non_fields' %} +
+ +
+
+
+
+
+{% endblock %} diff --git a/login/templates/password_reset_complete.html b/login/templates/password_reset_complete.html new file mode 100644 index 0000000..292cced --- /dev/null +++ b/login/templates/password_reset_complete.html @@ -0,0 +1,16 @@ +{% extends "login_base.html" %} +{% load i18n %} + +{% block login_content %} +
+
+
+
+

{% trans 'Password reset complete' %}

+

{% trans 'Your password has been set. You may go ahead and log in now.' %}

+ {% trans 'Login' %} +
+
+
+
+{% endblock %} diff --git a/login/templates/password_reset_confirm.html b/login/templates/password_reset_confirm.html new file mode 100644 index 0000000..30b103e --- /dev/null +++ b/login/templates/password_reset_confirm.html @@ -0,0 +1,36 @@ +{% extends "auth/login_base.html" %} +{% load i18n django_bootstrap5 %} + +{% block login_content %} +
+
+ {% if validlink %} +
+

{% trans 'Enter new password' %}

+

{% trans 'Please enter your new password twice so we can verify you typed it in correctly.' %}

+
+ +
+
+
+
+ {% csrf_token %} + {% bootstrap_form form %} + {% bootstrap_form_errors form type='non_fields' %} +
+ +
+
+
+
+
+ {% else %} +
+

{% trans 'Password reset unsuccessful' %}

+

{% trans 'The password reset link was invalid, possibly because it has already been used.' %}
+ {% trans 'Please request a new password reset.' %}

+
+ {% endif %} +
+
+{% endblock %} diff --git a/login/templates/password_reset_done.html b/login/templates/password_reset_done.html new file mode 100644 index 0000000..1b18de7 --- /dev/null +++ b/login/templates/password_reset_done.html @@ -0,0 +1,15 @@ +{% extends "auth/login_base.html" %} +{% load i18n %} + +{% block login_content %} +
+
+

{% trans 'Password reset sent' %}

+ +

{% trans "We've emailed you instructions for setting your password, if an account exists with the email you entered. You should receive them shortly." %}

+ +

{% trans "If you don't receive an email, please make sure you've entered the address you registered with, and check your spam folder." %}

+ +
+
+{% endblock %} diff --git a/login/templates/password_reset_email.html b/login/templates/password_reset_email.html new file mode 100644 index 0000000..062025a --- /dev/null +++ b/login/templates/password_reset_email.html @@ -0,0 +1,30 @@ +{% load i18n %}{% autoescape off %} +

+{% blocktrans %}You're receiving this email because you requested a password reset for your user account at {{ site_name }}.{% endblocktrans %} +

+ +

+{% trans "Please go to the following page and choose a new password:" %} +

+ +

+{% block reset_link %} + +{{ protocol }}://{{ domain }}{% url 'idhub:password_reset_confirm' uidb64=uid token=token %} + +{% endblock %} +

+ +

+{% trans "Your username, in case you've forgotten:" %} {{ user.username }} +

+ +

+{% trans "Thanks for using our site!" %} +

+ +

+{% blocktrans %}The {{ site_name }} team{% endblocktrans %} +

+ +{% endautoescape %} diff --git a/login/templates/password_reset_email.txt b/login/templates/password_reset_email.txt new file mode 100644 index 0000000..a4313fe --- /dev/null +++ b/login/templates/password_reset_email.txt @@ -0,0 +1,14 @@ +{% load i18n %}{% autoescape off %} +{% blocktrans %}You're receiving this email because you requested a password reset for your user account at {{ site_name }}.{% endblocktrans %} + +{% trans "Please go to the following page and choose a new password:" %} +{% block reset_link %} +{{ protocol }}://{{ domain }}{% url 'idhub:password_reset_confirm' uidb64=uid token=token %} +{% endblock %} +{% trans "Your username, in case you've forgotten:" %} {{ user.username }} + +{% trans "Thanks for using our site!" %} + +{% blocktrans %}The {{ site_name }} team{% endblocktrans %} + +{% endautoescape %} diff --git a/login/templates/password_reset_subject.txt b/login/templates/password_reset_subject.txt new file mode 100644 index 0000000..45a354b --- /dev/null +++ b/login/templates/password_reset_subject.txt @@ -0,0 +1,3 @@ +{% load i18n %}{% autoescape off %} +{% blocktrans %}Password reset on {{ site_name }}{% endblocktrans %} +{% endautoescape %} \ No newline at end of file diff --git a/login/tests.py b/login/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/login/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/login/urls.py b/login/urls.py new file mode 100644 index 0000000..e55d814 --- /dev/null +++ b/login/urls.py @@ -0,0 +1,34 @@ +from django.contrib.auth import views as auth_views +from django.views.generic import RedirectView +from django.urls import path, reverse_lazy +from login.views import ( + LoginView, + LogoutView, + PasswordResetView, + PasswordResetConfirmView, +) + +app_name = 'login' + +urlpatterns = [ + path("", RedirectView.as_view(url=reverse_lazy('login:login'), + permanent=False)), + path('login/', LoginView.as_view(), name='login'), + path('logout/', LogoutView, name='logout'), + path('auth/password_reset/', PasswordResetView.as_view(), name='password_reset'), + path('auth/password_reset/done/', + auth_views.PasswordResetDoneView.as_view( + template_name='password_reset_done.html' + ), + name='password_reset_done' + ), + path('auth/reset///', PasswordResetConfirmView.as_view(), + name='password_reset_confirm' + ), + path('auth/reset/done/', + auth_views.PasswordResetCompleteView.as_view( + template_name='password_reset_complete.html' + ), + name='password_reset_complete' + ), +] diff --git a/login/views.py b/login/views.py new file mode 100644 index 0000000..7c3062e --- /dev/null +++ b/login/views.py @@ -0,0 +1,73 @@ +import logging + +from django.urls import reverse_lazy +from django.contrib.auth import views as auth_views +from django.contrib.auth import login as auth_login +from django.contrib.auth import logout as auth_logout +from django.utils.translation import gettext_lazy as _ +from django.shortcuts import redirect +from django.http import HttpResponseRedirect + + +logger = logging.getLogger(__name__) + + +class LoginView(auth_views.LoginView): + template_name = 'login.html' + extra_context = { + 'title': _('Login'), + 'success_url': reverse_lazy('dashboard:dashboard'), + # 'commit_id': settings.COMMIT, + } + + def get(self, request, *args, **kwargs): + self.extra_context['success_url'] = request.GET.get( + 'next', + reverse_lazy('dashboard:dashboard') + ) + if not self.request.user.is_anonymous: + return redirect(reverse_lazy('dashboard:dashboard')) + + return super().get(request, *args, **kwargs) + + def form_valid(self, form): + user = form.get_user() + auth_login(self.request, user) + + if user.is_anonymous: + return redirect(reverse_lazy("login:login")) + + return redirect(self.extra_context['success_url']) + + +def LogoutView(request): + auth_logout(request) + return redirect(reverse_lazy("login:login")) + + +class PasswordResetConfirmView(auth_views.PasswordResetConfirmView): + template_name = 'password_reset_confirm.html' + success_url = reverse_lazy('login:password_reset_complete') + + def form_valid(self, form): + password = form.cleaned_data.get("new_password1") + user = form.user + user.set_password(password) + user.save() + return HttpResponseRedirect(self.success_url) + + +class PasswordResetView(auth_views.PasswordResetView): + template_name = 'password_reset.html' + email_template_name = 'password_reset_email.txt' + html_email_template_name = 'password_reset_email.html' + subject_template_name = 'password_reset_subject.txt' + success_url = reverse_lazy('login:password_reset_done') + + def form_valid(self, form): + try: + return super().form_valid(form) + except Exception as err: + logger.error(err) + return HttpResponseRedirect(self.success_url) +