Merge pull request 'feature/reset-password' (#67) from feature/reset-password into main
Reviewed-on: https://gitea.pangea.org/trustchain-oc1-orchestral/IdHub/pulls/67
This commit is contained in:
commit
233d8dfcc6
|
@ -1,5 +1,6 @@
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
from idhub.models import Rol
|
||||||
|
|
||||||
|
|
||||||
class ProfileForm(forms.ModelForm):
|
class ProfileForm(forms.ModelForm):
|
||||||
|
@ -21,5 +22,6 @@ class RolForm(forms.ModelForm):
|
||||||
class ServiceForm(forms.ModelForm):
|
class ServiceForm(forms.ModelForm):
|
||||||
MANDATORY_FIELDS = ['domain', 'rol']
|
MANDATORY_FIELDS = ['domain', 'rol']
|
||||||
|
|
||||||
|
|
||||||
class UserRolForm(forms.ModelForm):
|
class UserRolForm(forms.ModelForm):
|
||||||
MANDATORY_FIELDS = ['service']
|
MANDATORY_FIELDS = ['service']
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import logging
|
import logging
|
||||||
|
from smtplib import SMTPException
|
||||||
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.views.generic.base import TemplateView
|
from django.views.generic.base import TemplateView
|
||||||
|
@ -9,6 +10,7 @@ from django.urls import reverse_lazy
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from idhub.models import Membership, Rol, Service, UserRol
|
from idhub.models import Membership, Rol, Service, UserRol
|
||||||
from idhub.mixins import AdminView
|
from idhub.mixins import AdminView
|
||||||
|
from idhub.email.views import NotifyActivateUserByEmail
|
||||||
from idhub.admin.forms import (
|
from idhub.admin.forms import (
|
||||||
ProfileForm,
|
ProfileForm,
|
||||||
MembershipForm,
|
MembershipForm,
|
||||||
|
@ -121,7 +123,7 @@ class AdminPeopleEditView(AdminPeopleView, UpdateView):
|
||||||
success_url = reverse_lazy('idhub:admin_people_list')
|
success_url = reverse_lazy('idhub:admin_people_list')
|
||||||
|
|
||||||
|
|
||||||
class AdminPeopleRegisterView(People, CreateView):
|
class AdminPeopleRegisterView(NotifyActivateUserByEmail, People, CreateView):
|
||||||
template_name = "idhub/admin/people_register.html"
|
template_name = "idhub/admin/people_register.html"
|
||||||
subtitle = _('People Register')
|
subtitle = _('People Register')
|
||||||
icon = 'bi bi-person'
|
icon = 'bi bi-person'
|
||||||
|
@ -137,6 +139,16 @@ class AdminPeopleRegisterView(People, CreateView):
|
||||||
)
|
)
|
||||||
return self.success_url
|
return self.success_url
|
||||||
|
|
||||||
|
def form_valid(self, form):
|
||||||
|
user = form.save()
|
||||||
|
messages.success(self.request, _('The account is created successfully'))
|
||||||
|
if user.is_active:
|
||||||
|
try:
|
||||||
|
self.send_email(user)
|
||||||
|
except SMTPException as e:
|
||||||
|
messages.error(self.request, e)
|
||||||
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
|
||||||
class AdminPeopleMembershipRegisterView(People, CreateView):
|
class AdminPeopleMembershipRegisterView(People, CreateView):
|
||||||
template_name = "idhub/admin/people_membership_register.html"
|
template_name = "idhub/admin/people_membership_register.html"
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
from django.conf import settings
|
||||||
|
from django.template import loader
|
||||||
|
from django.core.mail import EmailMultiAlternatives
|
||||||
|
from django.contrib.auth.tokens import default_token_generator
|
||||||
|
from django.contrib.sites.shortcuts import get_current_site
|
||||||
|
from django.utils.encoding import force_bytes
|
||||||
|
from django.utils.http import urlsafe_base64_encode
|
||||||
|
|
||||||
|
|
||||||
|
class NotifyActivateUserByEmail:
|
||||||
|
def get_email_context(self, user):
|
||||||
|
"""
|
||||||
|
Define a new context with a token for put in a email
|
||||||
|
when send a email for add a new password
|
||||||
|
"""
|
||||||
|
protocol = 'https' if self.request.is_secure() else 'http'
|
||||||
|
current_site = get_current_site(self.request)
|
||||||
|
site_name = current_site.name
|
||||||
|
domain = current_site.domain
|
||||||
|
context = {
|
||||||
|
'email': user.email,
|
||||||
|
'domain': domain,
|
||||||
|
'site_name': site_name,
|
||||||
|
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
|
||||||
|
'user': user,
|
||||||
|
'token': default_token_generator.make_token(user),
|
||||||
|
'protocol': protocol,
|
||||||
|
}
|
||||||
|
return context
|
||||||
|
|
||||||
|
def send_email(self, user):
|
||||||
|
"""
|
||||||
|
Send a email when a user is activated.
|
||||||
|
"""
|
||||||
|
context = self.get_email_context(user)
|
||||||
|
subject_template_name = 'idhub/admin/registration/activate_user_subject.txt'
|
||||||
|
email_template_name = 'idhub/admin/registration/activate_user_email.txt'
|
||||||
|
html_email_template_name = 'idhub/admin/registration/activate_user_email.html'
|
||||||
|
subject = loader.render_to_string(subject_template_name, context)
|
||||||
|
# Email subject *must not* contain newlines
|
||||||
|
subject = ''.join(subject.splitlines())
|
||||||
|
body = loader.render_to_string(email_template_name, context)
|
||||||
|
from_email = settings.DEFAULT_FROM_EMAIL
|
||||||
|
to_email = user.email
|
||||||
|
|
||||||
|
email_message = EmailMultiAlternatives(
|
||||||
|
subject, body, from_email, [to_email])
|
||||||
|
html_email = loader.render_to_string(html_email_template_name, context)
|
||||||
|
email_message.attach_alternative(html_email, 'text/html')
|
||||||
|
if settings.DEVELOPMENT:
|
||||||
|
print(to_email)
|
||||||
|
print(body)
|
||||||
|
return
|
||||||
|
|
||||||
|
email_message.send()
|
|
@ -0,0 +1,21 @@
|
||||||
|
# Generated by Django 4.2.5 on 2023-10-19 13:01
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("idhub", "0004_userrol"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="service",
|
||||||
|
name="rol",
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="service",
|
||||||
|
name="rol",
|
||||||
|
field=models.ManyToManyField(to="idhub.rol"),
|
||||||
|
),
|
||||||
|
]
|
|
@ -92,12 +92,13 @@ class Rol(models.Model):
|
||||||
class Service(models.Model):
|
class Service(models.Model):
|
||||||
domain = models.CharField(max_length=250)
|
domain = models.CharField(max_length=250)
|
||||||
description = models.CharField(max_length=250)
|
description = models.CharField(max_length=250)
|
||||||
rol = models.ForeignKey(
|
rol = models.ManyToManyField(
|
||||||
Rol,
|
Rol,
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='services',
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def get_roles(self):
|
||||||
|
return ", ".join([x.name for x in self.rol.all()])
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "{} -> {}".format(self.domain, self.rol.name)
|
return "{} -> {}".format(self.domain, self.rol.name)
|
||||||
|
|
||||||
|
|
|
@ -1,162 +1,54 @@
|
||||||
|
{% extends "auth/login_base.html" %}
|
||||||
{% load i18n static %}
|
{% load i18n static %}
|
||||||
|
|
||||||
<!doctype html>
|
{% block login_content %}
|
||||||
<html lang="en">
|
<form action="{% url 'idhub:login' %}" role="form" method="post">
|
||||||
<head>
|
{% csrf_token %}
|
||||||
{% block head %}
|
<input type="hidden" name="next" value="{{ next }}" />
|
||||||
{% 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 %}IdHub{% endblock %}</title>
|
|
||||||
|
|
||||||
<!-- Bootstrap core CSS -->
|
<div id="div_id_username"
|
||||||
{% block style %}
|
class="clearfix control-group {% if form.username.errors %}error{% endif %}">
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
|
<div class="form-group">
|
||||||
<link rel="stylesheet" href= "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css">
|
<input type="text" name="username" maxlength="100" autocapitalize="off"
|
||||||
<link href="{% static "/css/bootstrap.min.css" %}" rel="stylesheet">
|
autocorrect="off" class="form-control textinput textInput" id="id_username" required
|
||||||
|
autofocus placeholder="{{ form.username.label }}"
|
||||||
<style>
|
{% if form.username.value %}value="{{ form.username.value }}" {% endif %}>
|
||||||
.bd-placeholder-img {
|
{% if form.username.errors %}
|
||||||
font-size: 1.125rem;
|
<p class="text-error">
|
||||||
text-anchor: middle;
|
{{ form.username.errors|striptags }}
|
||||||
-webkit-user-select: none;
|
</p>
|
||||||
-moz-user-select: none;
|
{% endif %}
|
||||||
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">
|
|
||||||
<header class="navbar navbar-dark sticky-top bg-grey flex-md-nowrap p-0 shadow">
|
|
||||||
<div class="navbar-nav navbar-sub-brand">
|
|
||||||
</div>
|
|
||||||
<div class="navbar-nav">
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<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">×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
{% endblock messages %}
|
|
||||||
|
|
||||||
<div class="jumbotron vertical-center">
|
|
||||||
<div id="login-wrapper" class="container" style="width: 430px;">
|
|
||||||
<div id="login-content" class="rounded">
|
|
||||||
<div id="login-branding">
|
|
||||||
{% block branding %}
|
|
||||||
<h1>
|
|
||||||
<img class="img-fluid" src="{% static '/images/logo-pangea-monocrome-h.png' %}"
|
|
||||||
alt="Pangea.org - Internet etic i solidari" />
|
|
||||||
</h1>
|
|
||||||
{% endblock %}
|
|
||||||
</div><!-- /login-branding -->
|
|
||||||
<div class="mt-5">
|
|
||||||
<form action="{% url 'idhub:login' %}" role="form" method="post">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="hidden" name="next" value="{{ next }}" />
|
|
||||||
|
|
||||||
<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><!-- /.row-fluid -->
|
|
||||||
</div>
|
|
||||||
<!--/#login-content-->
|
|
||||||
<div id="login-footer">
|
|
||||||
<a href="#password_reset" data-toggle="modal" data-target="#forgotPasswordModal">{% trans "Forgot your password? Click here to recover" %}</a>
|
|
||||||
</div>
|
|
||||||
</div><!-- /#login-wrapper -->
|
|
||||||
</div><!-- /.jumbotron -->
|
|
||||||
|
|
||||||
<!-- Modal -->
|
|
||||||
<div class="modal fade" id="forgotPasswordModal" tabindex="-1" role="dialog" aria-labelledby="forgotPasswordModalLabel" 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="forgotPasswordModalLabel">{% trans "Forgot your password?" %}</h5>
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
|
||||||
{% blocktrans trimmed with support_email="suport@pangea.org" %}
|
|
||||||
Send an email to <a href="mailto:{{ support_email }}">{{ support_email }}</a> including your username and we will provide instructions.
|
|
||||||
{% endblocktrans %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/static/js/bootstrap.bundle.min.js"></script>
|
<div id="div_id_password"
|
||||||
<script src="https://cdn.jsdelivr.net/npm/feather-icons@4.28.0/dist/feather.min.js" integrity="sha384-uO3SXW5IuS1ZpFPKugNNWqTZRRglnUJK6UAZ/gxOX80nxEkN9NcGZTftn6RzhGWE" crossorigin="anonymous"></script>
|
class="clearfix control-group {% if form.password.errors %}error{% endif %}">
|
||||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.4/dist/Chart.min.js" integrity="sha384-zNy6FEbO50N+Cg5wap8IKA4M/ZnLJgzc6w2NqACZaK0u0FXfOWRRJOnQtpZun8ha" crossorigin="anonymous"></script>
|
<div class="form-group">
|
||||||
<script src="/static/js/dashboard.js"></script>
|
<input type="password" name="password" maxlength="100" autocapitalize="off"
|
||||||
</body>
|
autocorrect="off" class="form-control textinput textInput" id="id_password"
|
||||||
</html>
|
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">
|
||||||
|
<a href="{% url 'idhub:password_reset' %}" data-toggle="modal" data-target="#forgotPasswordModal">{% trans "Forgot your password? Click here to recover" %}</a>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
{% 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 %}IdHub{% 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">
|
||||||
|
<header class="navbar navbar-dark sticky-top bg-grey flex-md-nowrap p-0 shadow">
|
||||||
|
<div class="navbar-nav navbar-sub-brand">
|
||||||
|
</div>
|
||||||
|
<div class="navbar-nav">
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<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">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endblock messages %}
|
||||||
|
|
||||||
|
<div class="jumbotron vertical-center">
|
||||||
|
<div id="login-wrapper" class="container" style="width: 430px;">
|
||||||
|
<div id="login-content" class="rounded">
|
||||||
|
<div id="login-branding">
|
||||||
|
{% block branding %}
|
||||||
|
<h1>
|
||||||
|
<img class="img-fluid" src="{% static '/images/logo-pangea-monocrome-h.png' %}"
|
||||||
|
alt="Pangea.org - Internet etic i solidari" />
|
||||||
|
</h1>
|
||||||
|
{% endblock %}
|
||||||
|
</div><!-- /login-branding -->
|
||||||
|
<div class="mt-5">
|
||||||
|
{% block login_content %}
|
||||||
|
{% endblock %}
|
||||||
|
</div><!-- /.row-fluid -->
|
||||||
|
</div>
|
||||||
|
<!--/#login-content-->
|
||||||
|
</div><!-- /#login-wrapper -->
|
||||||
|
</div><!-- /.jumbotron -->
|
||||||
|
|
||||||
|
<!-- Modal -->
|
||||||
|
<div class="modal fade" id="forgotPasswordModal" tabindex="-1" role="dialog" aria-labelledby="forgotPasswordModalLabel" 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="forgotPasswordModalLabel">{% trans "Forgot your password?" %}</h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
{% blocktrans trimmed with support_email="suport@pangea.org" %}
|
||||||
|
Send an email to <a href="mailto:{{ support_email }}">{{ support_email }}</a> including your username and we will provide instructions.
|
||||||
|
{% endblocktrans %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,27 @@
|
||||||
|
{% extends "auth/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 'idhub: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 %}
|
|
@ -0,0 +1,16 @@
|
||||||
|
{% extends "auth/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 'idhub:login' %}">{% trans 'Login' %}</a>
|
||||||
|
</div>
|
||||||
|
</div><!--/.well-->
|
||||||
|
</div><!-- /.row-fluid -->
|
||||||
|
</div><!-- /.container-fluid -->
|
||||||
|
{% endblock %}
|
|
@ -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 %}
|
|
@ -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 %}
|
|
@ -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 %}
|
|
@ -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 %}
|
|
@ -0,0 +1,3 @@
|
||||||
|
{% load i18n %}{% autoescape off %}
|
||||||
|
{% blocktrans %}Password reset on {{ site_name }}{% endblocktrans %}
|
||||||
|
{% endautoescape %}
|
|
@ -31,7 +31,7 @@
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{% for r in user.roles.all %}
|
{% for r in user.roles.all %}
|
||||||
{{ r.service.rol.name }}
|
{{ r.service.get_roles }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</td>
|
</td>
|
||||||
<td><a type="button" class="btn btn-green-admin rounded-pill" href="{% url 'idhub:admin_people' user.id %}">{% trans 'View' %}</td>
|
<td><a type="button" class="btn btn-green-admin rounded-pill" href="{% url 'idhub:admin_people' user.id %}">{% trans 'View' %}</td>
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
{% load i18n %}{% autoescape off %}
|
||||||
|
{% trans "IdHub" as site %}
|
||||||
|
<p>
|
||||||
|
{% blocktrans %}You're receiving this email because your user account at {{site}} has been activated.{% endblocktrans %}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
{% trans "Your username is:" %} {{ user.username }}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
{% trans "Please go to the following page and choose a 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 "Thanks for using our site!" %}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
{% blocktrans %}The {{site}} team{% endblocktrans %}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{% endautoescape %}
|
|
@ -0,0 +1,19 @@
|
||||||
|
{% load i18n %}{% autoescape off %}
|
||||||
|
|
||||||
|
{% trans "Idhub" as site %}
|
||||||
|
|
||||||
|
{% blocktrans %}You're receiving this email because your user account at {{site}} has been activated.{% endblocktrans %}
|
||||||
|
|
||||||
|
{% trans "Your username is:" %} {{ user.username }}
|
||||||
|
|
||||||
|
{% trans "Please go to the following page and choose a password:" %}
|
||||||
|
{% block reset_link %}
|
||||||
|
{{ protocol }}://{{ domain }}{% url 'idhub:password_reset_confirm' uidb64=uid token=token %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
{% trans "Thanks for using our site!" %}
|
||||||
|
|
||||||
|
{% blocktrans %}The {{site}} team{% endblocktrans %}
|
||||||
|
|
||||||
|
{% endautoescape %}
|
|
@ -0,0 +1,4 @@
|
||||||
|
{% load i18n %}{% autoescape off %}
|
||||||
|
{% trans "IdHub" as site %}
|
||||||
|
{% blocktrans %}User activation on {{site}}{% endblocktrans %}
|
||||||
|
{% endautoescape %}
|
|
@ -24,7 +24,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ service.domain }}</td>
|
<td>{{ service.domain }}</td>
|
||||||
<td>{{ service.description }}</td>
|
<td>{{ service.description }}</td>
|
||||||
<td>{{ service.rol.name }}</td>
|
<td>{{ service.get_roles }}</td>
|
||||||
<td><a href="{% url 'idhub:admin_service_edit' service.id %}" title="{% trans 'Edit' %}"><i class="bi bi-pencil-square"></i></a></td>
|
<td><a href="{% url 'idhub:admin_service_edit' service.id %}" title="{% trans 'Edit' %}"><i class="bi bi-pencil-square"></i></a></td>
|
||||||
<td><a href="{% url 'idhub:admin_service_del' service.id %}" title="{% trans 'Delete' %}"><i class="bi bi-trash"></i></a></td>
|
<td><a href="{% url 'idhub:admin_service_del' service.id %}" title="{% trans 'Delete' %}"><i class="bi bi-trash"></i></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -92,7 +92,7 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for rol in object.roles.all %}
|
{% for rol in object.roles.all %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ rol.service.rol.name }}</td>
|
<td>{{ rol.service.get_roles }}</td>
|
||||||
<td>{{ rol.service.description }}</td>
|
<td>{{ rol.service.description }}</td>
|
||||||
<td>{{ rol.service.domain }}</td>
|
<td>{{ rol.service.domain }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -80,7 +80,7 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for rol in object.roles.all %}
|
{% for rol in object.roles.all %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ rol.service.rol.name }}</td>
|
<td>{{ rol.service.get_roles }}</td>
|
||||||
<td>{{ rol.service.description }}</td>
|
<td>{{ rol.service.description }}</td>
|
||||||
<td>{{ rol.service.domain }}</td>
|
<td>{{ rol.service.domain }}</td>
|
||||||
<td><a href="{% url 'idhub:admin_people_rol_edit' rol.id %}" title="{% trans 'Edit' %}"><i class="bi bi-pencil-square"></i></a></td>
|
<td><a href="{% url 'idhub:admin_people_rol_edit' rol.id %}" title="{% trans 'Edit' %}"><i class="bi bi-pencil-square"></i></a></td>
|
||||||
|
|
|
@ -2,4 +2,30 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
<div class="row mt-5">
|
||||||
|
<div class="col">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped table-sm">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'Rol' %}</button></th>
|
||||||
|
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'Description' %}</button></th>
|
||||||
|
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'Service' %}</button></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for rol in user.roles.all %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ rol.service.rol.name }}</td>
|
||||||
|
<td>{{ rol.service.description }}</td>
|
||||||
|
<td>{{ rol.service.domain }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -28,6 +28,35 @@ urlpatterns = [
|
||||||
permanent=False)),
|
permanent=False)),
|
||||||
path('login/', LoginView.as_view(), name='login'),
|
path('login/', LoginView.as_view(), name='login'),
|
||||||
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
|
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
|
||||||
|
path('auth/password_reset/',
|
||||||
|
auth_views.PasswordResetView.as_view(
|
||||||
|
template_name='auth/password_reset.html',
|
||||||
|
email_template_name='auth/password_reset_email.txt',
|
||||||
|
html_email_template_name='auth/password_reset_email.html',
|
||||||
|
subject_template_name='auth/password_reset_subject.txt',
|
||||||
|
success_url=reverse_lazy('idhub:password_reset_done')
|
||||||
|
),
|
||||||
|
name='password_reset'
|
||||||
|
),
|
||||||
|
path('auth/password_reset/done/',
|
||||||
|
auth_views.PasswordResetDoneView.as_view(
|
||||||
|
template_name='auth/password_reset_done.html'
|
||||||
|
),
|
||||||
|
name='password_reset_done'
|
||||||
|
),
|
||||||
|
path('auth/reset/<uidb64>/<token>/',
|
||||||
|
auth_views.PasswordResetConfirmView.as_view(
|
||||||
|
template_name='auth/password_reset_confirm.html',
|
||||||
|
success_url=reverse_lazy('idhub:password_reset_complete')
|
||||||
|
),
|
||||||
|
name='password_reset_confirm'
|
||||||
|
),
|
||||||
|
path('auth/reset/done/',
|
||||||
|
auth_views.PasswordResetCompleteView.as_view(
|
||||||
|
template_name='auth/password_reset_complete.html'
|
||||||
|
),
|
||||||
|
name='password_reset_complete'
|
||||||
|
),
|
||||||
|
|
||||||
# User
|
# User
|
||||||
path('user/dashboard/', views_user.UserDashboardView.as_view(),
|
path('user/dashboard/', views_user.UserDashboardView.as_view(),
|
||||||
|
|
|
@ -30,6 +30,7 @@ SECRET_KEY = config('SECRET_KEY')
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = config('DEBUG', default=False, cast=bool)
|
DEBUG = config('DEBUG', default=False, cast=bool)
|
||||||
|
DEVELOPMENT = config('DEVELOPMENT', default=False, cast=bool)
|
||||||
|
|
||||||
ALLOWED_HOSTS = config('ALLOWED_HOSTS', default=[], cast=Csv())
|
ALLOWED_HOSTS = config('ALLOWED_HOSTS', default=[], cast=Csv())
|
||||||
|
|
||||||
|
@ -173,3 +174,4 @@ MESSAGE_TAGS = {
|
||||||
messages.WARNING: 'alert-warning',
|
messages.WARNING: 'alert-warning',
|
||||||
messages.ERROR: 'alert-danger',
|
messages.ERROR: 'alert-danger',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue