Add view to change mailbox password
This commit is contained in:
parent
6c773893f7
commit
33e68b5d07
|
@ -24,6 +24,7 @@ API_PATHS = {
|
|||
'address-detail': 'addresses/{pk}/',
|
||||
'mailbox-list': 'mailboxes/',
|
||||
'mailbox-detail': 'mailboxes/{pk}/',
|
||||
'mailbox-password': 'mailboxes/{pk}/set_password/',
|
||||
'mailinglist-list': 'lists/',
|
||||
'saas-list': 'saas/',
|
||||
'website-list': 'websites/',
|
||||
|
@ -194,6 +195,13 @@ class Orchestra(object):
|
|||
# return self.request("DELETE", url=url, render_as=None)
|
||||
return self.request("PATCH", url=url, data={"is_active": False})
|
||||
|
||||
def set_password_mailbox(self, pk, data):
|
||||
path = API_PATHS.get('mailbox-password').format_map({'pk': pk})
|
||||
url = urllib.parse.urljoin(self.base_url, path)
|
||||
status, response = self.request("POST", url=url, data=data, raise_exception=False)
|
||||
return status, response
|
||||
|
||||
|
||||
def retrieve_domain(self, pk):
|
||||
path = API_PATHS.get('domain-detail').format_map({'pk': pk})
|
||||
|
||||
|
|
|
@ -60,6 +60,40 @@ class MailForm(forms.Form):
|
|||
return serialized_data
|
||||
|
||||
|
||||
class MailboxChangePasswordForm(forms.Form):
|
||||
error_messages = {
|
||||
'password_mismatch': _('The two password fields didn’t match.'),
|
||||
}
|
||||
password = forms.CharField(
|
||||
label=_("Password"),
|
||||
strip=False,
|
||||
widget=forms.PasswordInput(attrs={'autocomplete': 'new-password'}),
|
||||
)
|
||||
password2 = forms.CharField(
|
||||
label=_("Password confirmation"),
|
||||
widget=forms.PasswordInput(attrs={'autocomplete': 'new-password'}),
|
||||
strip=False,
|
||||
help_text=_("Enter the same password as before, for verification."),
|
||||
)
|
||||
|
||||
def clean_password2(self):
|
||||
password = self.cleaned_data.get("password")
|
||||
password2 = self.cleaned_data.get("password2")
|
||||
if password and password2 and password != password2:
|
||||
raise ValidationError(
|
||||
self.error_messages['password_mismatch'],
|
||||
code='password_mismatch',
|
||||
)
|
||||
return password2
|
||||
|
||||
def serialize(self):
|
||||
assert self.is_valid()
|
||||
serialized_data = {
|
||||
"password": self.cleaned_data["password2"],
|
||||
}
|
||||
return serialized_data
|
||||
|
||||
|
||||
class MailboxCreateForm(forms.Form):
|
||||
error_messages = {
|
||||
'password_mismatch': _('The two password fields didn’t match.'),
|
||||
|
|
|
@ -4,31 +4,30 @@ a, a:hover, a:focus {
|
|||
}
|
||||
|
||||
a:hover {
|
||||
color: rgba(0,0,0,.7);
|
||||
color: rgba(0, 0, 0, .7);
|
||||
}
|
||||
|
||||
.btn-arrow-left{
|
||||
.btn-arrow-left {
|
||||
color: #eee;
|
||||
background: #D3D0DA;
|
||||
position: relative;
|
||||
padding: 8px 20px 8px 30px;
|
||||
margin-left: 1em; /** equal value than arrow.left **/
|
||||
margin-left: 1em;
|
||||
/** equal value than arrow.left **/
|
||||
}
|
||||
|
||||
.btn-arrow-left::after,
|
||||
.btn-arrow-left::before{
|
||||
.btn-arrow-left::after, .btn-arrow-left::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: -1em;
|
||||
|
||||
margin-top: -19px;
|
||||
border-top: 19px solid transparent;
|
||||
border-bottom: 19px solid transparent;
|
||||
border-right: 1em solid;
|
||||
}
|
||||
|
||||
.btn-arrow-left::after{
|
||||
.btn-arrow-left::after {
|
||||
border-right-color: #D3D0DA;
|
||||
z-index: 2;
|
||||
}
|
||||
|
@ -43,13 +42,12 @@ a:hover {
|
|||
min-width: 280px;
|
||||
max-width: 280px;
|
||||
min-height: 100vh;
|
||||
|
||||
position: fixed;
|
||||
z-index: 999;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#sidebar #sidebar-services {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
@ -62,20 +60,20 @@ a:hover {
|
|||
padding-left: 2rem;
|
||||
padding-right: 2rem;
|
||||
}
|
||||
|
||||
#sidebar #sidebar-services {
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
#sidebar #user-profile-menu {
|
||||
background:rgba(254, 251, 242, 0.25);
|
||||
background: rgba(254, 251, 242, 0.25);
|
||||
}
|
||||
|
||||
#sidebar ul.components {
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
|
||||
#sidebar ul li a {
|
||||
padding: 10px;
|
||||
font-size: 1.1em;
|
||||
|
@ -89,25 +87,26 @@ a:hover {
|
|||
}
|
||||
|
||||
.vertical-center {
|
||||
min-height: 100%; /* Fallback for browsers do NOT support vh unit */
|
||||
min-height: 100vh; /* These two lines are counted as one :-) */
|
||||
|
||||
min-height: 100%;
|
||||
/* Fallback for browsers do NOT support vh unit */
|
||||
min-height: 100vh;
|
||||
/* These two lines are counted as one :-) */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
/** login **/
|
||||
|
||||
#body-login .jumbotron {
|
||||
background: #282532 no-repeat url("../images/logo-pangea-lilla-bg.svg") right;
|
||||
}
|
||||
|
||||
#login-content {
|
||||
background:white;
|
||||
background: white;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
#login-content input[type="text"].form-control,
|
||||
#login-content input[type="password"].form-control {
|
||||
#login-content input[type="text"].form-control, #login-content input[type="password"].form-control {
|
||||
border-radius: 0;
|
||||
border: 0;
|
||||
border-bottom: 2px solid #8E8E8E;
|
||||
|
@ -121,6 +120,7 @@ a:hover {
|
|||
margin-top: 1.5rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#login-footer a {
|
||||
color: #FEFBF2;
|
||||
}
|
||||
|
@ -130,34 +130,37 @@ a:hover {
|
|||
background-position: right 5% top 10%;
|
||||
color: #343434;
|
||||
padding-left: 2rem;
|
||||
margin-left: 280px; /** sidebar width **/
|
||||
margin-left: 280px;
|
||||
/** sidebar width **/
|
||||
}
|
||||
|
||||
/** services **/
|
||||
|
||||
h1.service-name {
|
||||
|
||||
font: Bold 26px/34px Roboto;
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
||||
.service-description {
|
||||
|
||||
font: 16px/21px Roboto;
|
||||
}
|
||||
|
||||
.table.service-list {
|
||||
margin-top: 2rem;
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
/** TODO update theme instead of overriding **/
|
||||
.service-list thead.thead-dark th,
|
||||
.service-card .card-header {
|
||||
|
||||
.service-list thead.thead-dark th, .service-card .card-header {
|
||||
background: rgba(80, 70, 110, 0.25);
|
||||
color: #50466E;
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
/** /TODO **/
|
||||
.table.service-list td,
|
||||
.table.service-list th {
|
||||
|
||||
.table.service-list td, .table.service-list th {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
|
@ -202,11 +205,10 @@ h1.service-name {
|
|||
|
||||
.service-card .card-body {
|
||||
color: #787878;
|
||||
|
||||
}
|
||||
|
||||
.service-card .card-body i.fas {
|
||||
color:#9C9AA7;
|
||||
color: #9C9AA7;
|
||||
}
|
||||
|
||||
.service-manager-link {
|
||||
|
@ -215,8 +217,7 @@ h1.service-name {
|
|||
right: 15px;
|
||||
}
|
||||
|
||||
.service-card .service-manager-link a,
|
||||
.service-card .service-manager-link a i.fas {
|
||||
.service-card .service-manager-link a, .service-card .service-manager-link a i.fas {
|
||||
color: white;
|
||||
}
|
||||
|
||||
|
@ -243,11 +244,9 @@ h1.service-name {
|
|||
font-variant: normal;
|
||||
text-rendering: auto;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 10px;
|
||||
|
||||
color: #E8E7EB;
|
||||
font-size: 2em;
|
||||
}
|
||||
|
@ -308,3 +307,13 @@ h1.service-name {
|
|||
border-top: 0;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.roll-hover {
|
||||
visibility: hidden;
|
||||
display: inline-block;
|
||||
margin-left: 2rem;
|
||||
}
|
||||
|
||||
td:hover .roll-hover {
|
||||
visibility: visible;
|
||||
}
|
||||
|
|
15
musician/templates/musician/mailbox_change_password.html
Normal file
15
musician/templates/musician/mailbox_change_password.html
Normal file
|
@ -0,0 +1,15 @@
|
|||
{% extends "musician/base.html" %}
|
||||
{% load bootstrap4 i18n %}
|
||||
|
||||
{% block content %}
|
||||
<h1 class="service-name">{% trans "Change password" %}: <span class="font-weight-light">{{ object.name }}</span></h1>
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{% bootstrap_form form %}
|
||||
{% buttons %}
|
||||
<a class="btn btn-light mr-2" href="{% url 'musician:mailbox-list' %}">{% trans "Cancel" %}</a>
|
||||
<button type="submit" class="btn btn-secondary">{% trans "Save" %}</button>
|
||||
{% endbuttons %}
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -21,6 +21,7 @@
|
|||
<button type="submit" class="btn btn-secondary">{% trans "Save" %}</button>
|
||||
{% if form.instance %}
|
||||
<div class="float-right">
|
||||
<a class="btn btn-outline-warning" href="{% url 'musician:mailbox-password' mailbox.id %}"><i class="fas fa-key"></i> {% trans "Change password" %}</a>
|
||||
<a class="btn btn-danger" href="{% url 'musician:mailbox-delete' view.kwargs.pk %}">{% trans "Delete" %}</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -21,7 +21,11 @@
|
|||
{# <!-- Exclude (don't render) inactive mailboxes -->#}
|
||||
{% if mailbox.is_active %}
|
||||
<tr>
|
||||
<td><a href="{% url 'musician:mailbox-update' mailbox.id %}">{{ mailbox.name }}</a></td>
|
||||
<td>
|
||||
<a href="{% url 'musician:mailbox-update' mailbox.id %}">{{ mailbox.name }}</a>
|
||||
<a class="roll-hover btn btn-outline-warning" href="{% url 'musician:mailbox-password' mailbox.id %}">
|
||||
<i class="fas fa-key"></i> {% trans "Update password" %}</a>
|
||||
</td>
|
||||
<td>{{ mailbox.filtering }}</td>
|
||||
<td>
|
||||
{% for addr in mailbox.addresses %}
|
||||
|
|
|
@ -27,6 +27,7 @@ urlpatterns = [
|
|||
path('mailboxes/new/', views.MailboxCreateView.as_view(), name='mailbox-create'),
|
||||
path('mailboxes/<int:pk>/', views.MailboxUpdateView.as_view(), name='mailbox-update'),
|
||||
path('mailboxes/<int:pk>/delete/', views.MailboxDeleteView.as_view(), name='mailbox-delete'),
|
||||
path('mailboxes/<int:pk>/change-password/', views.MailboxChangePasswordView.as_view(), name='mailbox-password'),
|
||||
path('mailing-lists/', views.MailingListsView.as_view(), name='mailing-lists'),
|
||||
path('databases/', views.DatabasesView.as_view(), name='database-list'),
|
||||
path('saas/', views.SaasView.as_view(), name='saas-list'),
|
||||
|
|
|
@ -20,7 +20,7 @@ from requests.exceptions import HTTPError
|
|||
from . import api, get_version
|
||||
from .auth import login as auth_login
|
||||
from .auth import logout as auth_logout
|
||||
from .forms import LoginForm, MailboxCreateForm, MailboxUpdateForm, MailForm
|
||||
from .forms import LoginForm, MailboxChangePasswordForm, MailboxCreateForm, MailboxUpdateForm, MailForm
|
||||
from .mixins import (CustomContextMixin, ExtendedPaginationMixin,
|
||||
UserTokenRequiredMixin)
|
||||
from .models import (Address, Bill, DatabaseService, Mailbox,
|
||||
|
@ -435,6 +435,31 @@ class MailboxDeleteView(CustomContextMixin, UserTokenRequiredMixin, DeleteView):
|
|||
logger.error("Error sending email to managers", exc_info=True)
|
||||
|
||||
|
||||
class MailboxChangePasswordView(CustomContextMixin, UserTokenRequiredMixin, FormView):
|
||||
template_name = "musician/mailbox_change_password.html"
|
||||
form_class = MailboxChangePasswordForm
|
||||
success_url = reverse_lazy("musician:mailbox-list")
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
self.object = self.get_object()
|
||||
context.update({
|
||||
'object': self.object,
|
||||
})
|
||||
return context
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
obj = self.orchestra.retrieve_mailbox(self.kwargs['pk'])
|
||||
return obj
|
||||
|
||||
def form_valid(self, form):
|
||||
data = {
|
||||
'password': form.cleaned_data['password2']
|
||||
}
|
||||
status, response = self.orchestra.set_password_mailbox(self.kwargs['pk'], data)
|
||||
return super().form_valid(form)
|
||||
|
||||
|
||||
class DatabasesView(ServiceListView):
|
||||
template_name = "musician/databases.html"
|
||||
service_class = DatabaseService
|
||||
|
|
Loading…
Reference in a new issue