add login

This commit is contained in:
Cayo Puigdefabregas 2024-07-01 12:18:42 +02:00
parent b26ed184a1
commit c013bc8d43
24 changed files with 768 additions and 1 deletions

View file

@ -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",
}
}

0
login/__init__.py Normal file
View file

3
login/admin.py Normal file
View file

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

6
login/apps.py Normal file
View file

@ -0,0 +1,6 @@
from django.apps import AppConfig
class LoginConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "login"

View file

3
login/models.py Normal file
View file

@ -0,0 +1,3 @@
from django.db import models
# Create your models here.

View file

@ -0,0 +1,19 @@
{% extends "auth/login_base.html" %}
{% load i18n django_bootstrap5 %}
{% block login_content %}
<div class="well">
<div class="row-fluid">
<h2>{% trans 'Two-factor Authentication' %}</h2>
</div>
</div>
<div class="well">
<div class="row-fluid">
<div>
<span>{% trans "We have sent you an email with a link that you have to click to log in." %}</span>
</div>
</div><!-- /.row-fluid -->
</div><!--/.well-->
{% endblock %}

View file

@ -0,0 +1,26 @@
{% load i18n %}{% autoescape off %}
<p>
{% blocktrans %}You're receiving this email because you tried to access {{ site_name }}.{% endblocktrans %}
</p>
<p>
{% trans "Please go to the following page" %}
</p>
<p>
{% block reset_link %}
<a href="{{ protocol }}://{{ domain }}{% url 'idhub:admin_2fauth' admin2fauth=token %}">
{{ protocol }}://{{ domain }}{% url 'idhub:admin_2fauth' admin2fauth=token %}
</a>
{% endblock %}
</p>
<p>
{% trans "Thanks for using our site!" %}
</p>
<p>
{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
</p>
{% endautoescape %}

View file

@ -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 %}

View file

@ -0,0 +1,3 @@
{% load i18n %}{% autoescape off %}
{% blocktrans %}Authentication in {{ site_name }}{% endblocktrans %}
{% endautoescape %}

View file

@ -0,0 +1,45 @@
{% extends "login_base.html" %}
{% load i18n static %}
{% block login_content %}
<form action="{% url 'login:login' %}" method="post" class="row g-3 needs-validation" novalidate>
{% csrf_token %}
<div class="col-12">
<input type="email" name="username" maxlength="100" autocapitalize="off"
autocorrect="off" class="form-control textinput textInput" id="yourEmail" required
autofocus placeholder="{{ form.username.label }}"
{% if form.username.value %}value="{{ form.username.value }}" {% endif %}>
<div class="invalid-feedback">Please enter your email.</div>
{% if form.username.errors %}
<p class="text-error">
{{ form.username.errors|striptags }}
</p>
{% endif %}
</div>
<div class="col-12">
<div class="input-group">
<input type="password" name="password" maxlength="100" autocapitalize="off"
autocorrect="off" class="form-control textinput textInput" id="id_password"
placeholder="{{ form.password.label }}" required>
{% if form.password.errors %}
<p class="text-error">
{{ form.password.errors|striptags }}
</p>
{% endif %}
<i class="input-group-text bi bi-eye" id="togglePassword" style="cursor: pointer">
</i>
</div>
<div class="invalid-feedback">Please enter your password!</div>
</div>
<input name="next" type="hidden" value="{{ success_url }}">
<div class="col-12">
<button class="btn btn-primary w-100" type="submit">Next</button>
</div>
</form>
<div id="login-footer" class="mt-3">
<a href="{% url 'login:password_reset' %}" data-toggle="modal" data-target="#forgotPasswordModal">{% trans "Forgot your password? Click here to recover" %}</a>
</div>
{% endblock %}

View file

@ -0,0 +1,52 @@
{% extends "login_base.html" %}
{% load i18n static %}
{% block login_content %}
<form action="{% url 'login:login' %}" role="form" method="post">
{% csrf_token %}
<div id="div_id_username"
class="clearfix control-group {% if form.username.errors %}error{% endif %}">
<div class="form-group">
<input type="text" name="username" maxlength="100" autocapitalize="off"
autocorrect="off" class="form-control textinput textInput" id="id_username" required
autofocus placeholder="{{ form.username.label }}"
{% if form.username.value %}value="{{ form.username.value }}" {% endif %}>
{% if form.username.errors %}
<p class="text-error">
{{ form.username.errors|striptags }}
</p>
{% endif %}
</div>
</div>
<div id="div_id_password"
class="clearfix control-group {% if form.password.errors %}error{% endif %}">
<div class="form-group">
<input type="password" name="password" maxlength="100" autocapitalize="off"
autocorrect="off" class="form-control textinput textInput" id="id_password"
placeholder="{{ form.password.label }}" required>
{% if form.password.errors %}
<p class="text-error">
{{ form.password.errors|striptags }}
</p>
{% endif %}
</div>
</div>
{% if form.non_field_errors %}
{% for error in form.non_field_errors %}
<div class="well well-small text-error" style="border: none">{{ error }}</div>
{% endfor %}
{% endif %}
<input name="next" type="hidden" value="{{ success_url }}">
<div class="form-actions-no-box">
<input type="submit" name="submit" value="{% trans 'Log in' %}"
class="btn btn-primary form-control" id="submit-id-submit">
</div>
</form>
<div id="login-footer" class="mt-3">
<a href="{% url 'login:password_reset' %}" data-toggle="modal" data-target="#forgotPasswordModal">{% trans "Forgot your password? Click here to recover" %}</a>
</div>
{% endblock %}

179
login/templates/login3.html Normal file
View file

@ -0,0 +1,179 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>Login - Usody</title>
<meta content="" name="description">
<meta content="" name="keywords">
<!-- Favicons -->
<link href="/static/img/favicon.png" rel="icon">
<link href="/static/img/apple-touch-icon.png" rel="apple-touch-icon">
<!-- Google Fonts -->
<link href="https://fonts.gstatic.com" rel="preconnect">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i|Nunito:300,300i,400,400i,600,600i,700,700i|Poppins:300,300i,400,400i,500,500i,600,600i,700,700i" rel="stylesheet">
<!-- JS Files -->
<script src="/static/js/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/simple-datatables@5.0.3" type="text/javascript"></script>
<!-- Vendor CSS Files -->
<link href="/static/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/static/vendor/bootstrap-icons/bootstrap-icons.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/simple-datatables@5.0.3/dist/style.css" rel="stylesheet" type="text/css">
<!-- Template Main CSS File -->
<link href="/static/css/style.css" rel="stylesheet">
<link href="/static/css/devicehub.css" rel="stylesheet">
<!-- =======================================================
* Template Name: NiceAdmin - v2.2.0
* Template URL: https://bootstrapmade.com/nice-admin-bootstrap-admin-html-template/
* Author: BootstrapMade.com
* License: https://bootstrapmade.com/license/
======================================================== -->
</head>
<body>
<main>
<div class="container">
<section class="section register min-vh-100 d-flex flex-column align-items-center justify-content-center py-4">
<div class="container">
<div class="row justify-content-center">
<div class="col-lg-4 col-md-6 d-flex flex-column align-items-center justify-content-center">
<div class="d-flex justify-content-center py-4">
<a href="/login/" class="d-flex align-items-center w-auto">
<img src="/static/img/usody_logo_transparent_noicon-y-purple-120x41.png" alt="">
</a>
</div><!-- End Logo -->
<div class="card mb-3">
<div class="card-body">
<div class="pt-2 pb-3">
<h5 class="card-title text-center pb-0 fs-4 help">Sign in</h5>
</div>
<form method="post" class="row g-3 needs-validation" novalidate>
<input id="csrf_token" name="csrf_token" type="hidden" value="ImNlZTM1N2RlMjQ2MDMxYmQ0NDQzMWI0ZDQ0NmZkNjdhZjc0NGU2NjMi.Zn14CA.unYlCb0lVq4wtzKx_42V3vXQ0dg">
<div class="col-12">
<input type="email" placeholder="Email" name="email" class="form-control" id="yourEmail" required value="">
<div class="invalid-feedback">Please enter your email.</div>
</div>
<div class="col-12">
<div class="input-group">
<input type="password" placeholder="Password" name="password" class="form-control" id="id_password" required>
<i class="input-group-text bi bi-eye" id="togglePassword" style="cursor: pointer">
</i>
</div>
<div class="invalid-feedback">Please enter your password!</div>
</div>
<!-- TODO(@slamora): hidde until it is implemented
<div class="col-12">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="remember" id="rememberMe">
<label class="form-check-label" for="rememberMe">Remember me</label>
</div>
</div>
-->
<div class="col-12">
<button class="btn btn-primary w-100" type="submit">Next</button>
</div>
<div class="col-12">
<p class="small mb-0">Don't have account? <a href="https://www.usody.com/pricing.html">Create an account</a></p>
<p class="small mb-0">Forgot password? <a href="/reset_password/">Reset your password</a></p>
</div>
</form>
</div>
</div>
<div class="credits">
<a href="https://help.usody.com/en/getting-started/login-usody/" target="_blank">Help</a> |
<a href="https://www.usody.com/legal/privacy-policy" target="_blank">Privacy</a> |
<a href="https://www.usody.com/legal/terms" target="_blank">Terms</a>
</div>
</div>
</div>
</div>
</section>
</div>
</main><!-- End #main -->
<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Do you want to try USOdy tools?</h5>
</div>
<div class="modal-body">
Just write an email to <a href="mali:hello@usody.com">hello@usody.com</a>
</div>
</div>
</div>
</div> <!-- End register modal -->
<script>
const togglePassword = document.querySelector('#togglePassword');
const password = document.querySelector('#id_password');
togglePassword.addEventListener('click', function (e) {
// toggle the type attribute
const type = password.getAttribute('type') === 'password' ? 'text' : 'password';
// toggle the eye slash icon
if(type == "password"){
this.classList.remove('bi-eye-slash');
this.classList.add('bi-eye');
} else if(type == "text"){
this.classList.remove('bi-eye');
this.classList.add('bi-eye-slash');
}
password.setAttribute('type', type);
});
</script>
<a href="#" class="back-to-top d-flex align-items-center justify-content-center"><i class="bi bi-arrow-up-short"></i></a>
<!-- Vendor JS Files -->
<script src="/static/vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Template Main JS File -->
<script src="/static/js/main.js"></script>
<!-- Api backend -->
<script>
const API_URLS = {
Auth_Token: `Basic ${btoa("fa0cd7fb-690d-4ebb-a482-c1d4eae3deb1:")}`, //
currentUserID: "56957cdb-db7b-452c-843b-200dc4604b08",
lots: "/lots/",
lots_detail: "/inventory/lot/ReplaceTEXT/device/",
devices: "/devices/",
devices_modify: "/lots/UUID/devices",
devices_detail: "/inventory/device/ReplaceTEXT/"
}
</script>
<script src="/static/js/api.js"></script>
</body>
</html>

View file

@ -0,0 +1,133 @@
{% load i18n static %}
<!doctype html>
<html lang="en">
<head>
{% block head %}
{% block meta %}
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="robots" content="NONE,NOARCHIVE" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="Pangea">
{% endblock %}
<title>{% block title %}{% if title %}{{ title }} {% endif %}DeviceHub{% endblock %}</title>
<!-- Bootstrap core CSS -->
{% block style %}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
<link rel="stylesheet" href= "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css">
<link href="{% static "/css/bootstrap.min.css" %}" rel="stylesheet">
<style>
.bd-placeholder-img {
font-size: 1.125rem;
text-anchor: middle;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
@media (min-width: 768px) {
.bd-placeholder-img-lg {
font-size: 3.5rem;
}
}
</style>
<!-- Custom styles for this template -->
<link href="{% static "/css/dashboard.css" %}" rel="stylesheet">
{% endblock %}
{% endblock %}
</head>
<body id="body-login">
<div class="container">
<section class="section register min-vh-100 d-flex flex-column align-items-center justify-content-center py-4">
<div class="container">
<div class="row justify-content-center">
<div class="col-lg-4 col-md-6 d-flex flex-column align-items-center justify-content-center">
<div class="d-flex justify-content-center py-4">
<a href="/login/" class="d-flex align-items-center w-auto">
<img class="img-fluid" src="{% static '/images/logo-pangea-monocrome-h.png' %}"
alt="Pangea.org - Internet etic i solidari" />
</a>
</div><!-- End Logo -->
<div class="card mb-3 shadow p-3 mb-5 bg-body rounded">
<div class="card-body">
<div class="pt-2 pb-3">
<h5 class="card-title text-center pb-0 fs-4 help">Sign in</h5>
</div>
{% block login_content %}
{% endblock login_content %}
</div>
</div>
<div class="credits">
</div>
</div>
</div>
</div>
</section>
</div>
<div class="container-fluid">
<div class="row">
<main class="col-md-12 bt-5">
{% block messages %}
{% for message in messages %}
<div class="alert alert-{{ message.tags|default:'info' }} alert-dismissible fade show" role="alert">
{{ message }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
{% endfor %}
{% endblock messages %}
</main>
</div>
</div>
<!-- Footer -->
<footer class="footer text-center">
<div class="container">
<span class="text-muted">{{ commit_id }}</span>
</div>
</footer>
<script src="/static/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/feather-icons@4.28.0/dist/feather.min.js" integrity="sha384-uO3SXW5IuS1ZpFPKugNNWqTZRRglnUJK6UAZ/gxOX80nxEkN9NcGZTftn6RzhGWE" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.4/dist/Chart.min.js" integrity="sha384-zNy6FEbO50N+Cg5wap8IKA4M/ZnLJgzc6w2NqACZaK0u0FXfOWRRJOnQtpZun8ha" crossorigin="anonymous"></script>
<script src="/static/js/dashboard.js"></script>
<script>
const togglePassword = document.querySelector('#togglePassword');
const password = document.querySelector('#id_password');
togglePassword.addEventListener('click', function (e) {
// toggle the type attribute
const type = password.getAttribute('type') === 'password' ? 'text' : 'password';
// toggle the eye slash icon
if(type == "password"){
this.classList.remove('bi-eye-slash');
this.classList.add('bi-eye');
} else if(type == "text"){
this.classList.remove('bi-eye');
this.classList.add('bi-eye-slash');
}
password.setAttribute('type', type);
});
</script>
</body>
</html>

View file

@ -0,0 +1,27 @@
{% extends "login_base.html" %}
{% load i18n django_bootstrap5 %}
{% block login_content %}
<div class="well">
<div class="row-fluid">
<h2>{% trans 'Password reset' %}</h2>
<span>{% trans "Forgotten your password? Enter your email address below, and we'll email instructions for setting a new one." %}</span>
</div>
</div>
<div class="well">
<div class="row-fluid">
<div>
<form action="{% url 'login:password_reset' %}" role="form" method="post">
{% csrf_token %}
{% bootstrap_form form %}
{% bootstrap_form_errors form type='non_fields' %}
<div class="form-actions-no-box">
<input type="submit" name="submit" value="{% trans 'Reset my password' %}" class="btn btn-primary form-control" id="submit-id-submit">
</div>
</form>
</div>
</div><!-- /.row-fluid -->
</div><!--/.well-->
{% endblock %}

View file

@ -0,0 +1,16 @@
{% extends "login_base.html" %}
{% load i18n %}
{% block login_content %}
<div class="container-fluid" style="margin-top: 30px">
<div class="row-fluid">
<div class="well" style="width: 800px; margin: auto auto 50px auto">
<div class="row-fluid">
<h2>{% trans 'Password reset complete' %}</h2>
<p>{% trans 'Your password has been set. You may go ahead and log in now.' %}</p>
<a href="{% url 'login:login' %}">{% trans 'Login' %}</a>
</div>
</div><!--/.well-->
</div><!-- /.row-fluid -->
</div><!-- /.container-fluid -->
{% endblock %}

View file

@ -0,0 +1,36 @@
{% extends "auth/login_base.html" %}
{% load i18n django_bootstrap5 %}
{% block login_content %}
<div class="container-fluid" style="margin-top: 30px">
<div class="row-fluid">
{% if validlink %}
<div class="well" style="width: 600px; margin-left: auto; margin-right: auto">
<h2>{% trans 'Enter new password' %}</h2>
<p>{% trans 'Please enter your new password twice so we can verify you typed it in correctly.' %}</p>
</div><!-- /well -->
<div class="well" style="width: 320px; margin-left: auto; margin-right: auto">
<div class="row-fluid">
<div>
<form role="form" method="post">
{% csrf_token %}
{% bootstrap_form form %}
{% bootstrap_form_errors form type='non_fields' %}
<div class="form-actions-no-box">
<input type="submit" name="submit" value="{% trans 'Change my password' %}" class="btn btn-primary form-control" id="submit-id-submit">
</div>
</form>
</div>
</div><!-- /.row-fluid -->
</div><!--/.well-->
{% else %}
<div class="well" style="width: 800px; margin-left: auto; margin-right: auto">
<h2>{% trans 'Password reset unsuccessful' %}</h2>
<p>{% trans 'The password reset link was invalid, possibly because it has already been used.' %}<br />
{% trans 'Please request a new password reset.' %}</p>
</div><!-- /well -->
{% endif %}
</div><!-- /.row-fluid -->
</div><!-- /.container-fluid -->
{% endblock %}

View file

@ -0,0 +1,15 @@
{% extends "auth/login_base.html" %}
{% load i18n %}
{% block login_content %}
<div class="well">
<div class="row-fluid">
<h2>{% trans 'Password reset sent' %}</h2>
<p>{% trans "We've emailed you instructions for setting your password, if an account exists with the email you entered. You should receive them shortly." %}</p>
<p>{% trans "If you don't receive an email, please make sure you've entered the address you registered with, and check your spam folder." %}</p>
</div><!-- /.row-fluid -->
</div><!--/.well-->
{% endblock %}

View file

@ -0,0 +1,30 @@
{% load i18n %}{% autoescape off %}
<p>
{% blocktrans %}You're receiving this email because you requested a password reset for your user account at {{ site_name }}.{% endblocktrans %}
</p>
<p>
{% trans "Please go to the following page and choose a new password:" %}
</p>
<p>
{% block reset_link %}
<a href="{{ protocol }}://{{ domain }}{% url 'idhub:password_reset_confirm' uidb64=uid token=token %}">
{{ protocol }}://{{ domain }}{% url 'idhub:password_reset_confirm' uidb64=uid token=token %}
</a>
{% endblock %}
</p>
<p>
{% trans "Your username, in case you've forgotten:" %} {{ user.username }}
</p>
<p>
{% trans "Thanks for using our site!" %}
</p>
<p>
{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
</p>
{% endautoescape %}

View file

@ -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 %}

View file

@ -0,0 +1,3 @@
{% load i18n %}{% autoescape off %}
{% blocktrans %}Password reset on {{ site_name }}{% endblocktrans %}
{% endautoescape %}

3
login/tests.py Normal file
View file

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

34
login/urls.py Normal file
View file

@ -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/<uidb64>/<token>/', 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'
),
]

73
login/views.py Normal file
View file

@ -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)