diff --git a/musician/api.py b/musician/api.py index 15ca269..2b33dee 100644 --- a/musician/api.py +++ b/musician/api.py @@ -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}) diff --git a/musician/forms.py b/musician/forms.py index 62ea0ae..98e23c4 100644 --- a/musician/forms.py +++ b/musician/forms.py @@ -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.'), diff --git a/musician/static/musician/css/default.css b/musician/static/musician/css/default.css index 3fbe7da..0bbfe4b 100644 --- a/musician/static/musician/css/default.css +++ b/musician/static/musician/css/default.css @@ -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; +} diff --git a/musician/templates/musician/mailbox_change_password.html b/musician/templates/musician/mailbox_change_password.html new file mode 100644 index 0000000..e18b95a --- /dev/null +++ b/musician/templates/musician/mailbox_change_password.html @@ -0,0 +1,15 @@ +{% extends "musician/base.html" %} +{% load bootstrap4 i18n %} + +{% block content %} +