musician add webappusers and systemusers
This commit is contained in:
parent
ee7cf07294
commit
5c0c82d50b
|
@ -3,8 +3,11 @@ from django.contrib.auth.forms import AuthenticationForm
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from django.contrib.auth.hashers import make_password
|
||||||
|
|
||||||
from orchestra.contrib.domains.models import Domain, Record
|
from orchestra.contrib.domains.models import Domain, Record
|
||||||
from orchestra.contrib.mailboxes.models import Address, Mailbox
|
from orchestra.contrib.mailboxes.models import Address, Mailbox
|
||||||
|
from orchestra.contrib.systemusers.models import WebappUsers, SystemUser
|
||||||
from orchestra.contrib.musician.validators import ValidateZoneMixin
|
from orchestra.contrib.musician.validators import ValidateZoneMixin
|
||||||
|
|
||||||
from . import api
|
from . import api
|
||||||
|
@ -27,6 +30,42 @@ class LoginForm(AuthenticationForm):
|
||||||
|
|
||||||
return self.cleaned_data
|
return self.cleaned_data
|
||||||
|
|
||||||
|
class ChangePasswordForm(forms.ModelForm):
|
||||||
|
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."),
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
fields = ("password",)
|
||||||
|
model = WebappUsers
|
||||||
|
|
||||||
|
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 clean(self):
|
||||||
|
cleaned_data = super().clean()
|
||||||
|
password = cleaned_data.get("password")
|
||||||
|
cleaned_data['password'] = make_password(password)
|
||||||
|
return cleaned_data
|
||||||
|
|
||||||
|
|
||||||
class MailForm(forms.ModelForm):
|
class MailForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -53,36 +92,12 @@ class MailForm(forms.ModelForm):
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
|
|
||||||
class MailboxChangePasswordForm(forms.ModelForm):
|
class MailboxChangePasswordForm(ChangePasswordForm):
|
||||||
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."),
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
fields = ("password",)
|
fields = ("password",)
|
||||||
model = Mailbox
|
model = Mailbox
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
class MailboxCreateForm(forms.ModelForm):
|
class MailboxCreateForm(forms.ModelForm):
|
||||||
error_messages = {
|
error_messages = {
|
||||||
|
@ -120,7 +135,7 @@ class MailboxCreateForm(forms.ModelForm):
|
||||||
self.error_messages['password_mismatch'],
|
self.error_messages['password_mismatch'],
|
||||||
code='password_mismatch',
|
code='password_mismatch',
|
||||||
)
|
)
|
||||||
return password2
|
return password
|
||||||
|
|
||||||
def save(self, commit=True):
|
def save(self, commit=True):
|
||||||
instance = super().save(commit=False)
|
instance = super().save(commit=False)
|
||||||
|
@ -169,3 +184,14 @@ class RecordUpdateForm(ValidateZoneMixin, forms.ModelForm):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.domain = self.instance.domain
|
self.domain = self.instance.domain
|
||||||
|
|
||||||
|
|
||||||
|
class WebappUsersChangePasswordForm(ChangePasswordForm):
|
||||||
|
class Meta:
|
||||||
|
fields = ("password",)
|
||||||
|
model = WebappUsers
|
||||||
|
|
||||||
|
class SystemUsersChangePasswordForm(ChangePasswordForm):
|
||||||
|
class Meta:
|
||||||
|
fields = ("password",)
|
||||||
|
model = SystemUser
|
||||||
|
|
|
@ -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:systemuser-list' %}">{% trans "Cancel" %}</a>
|
||||||
|
<button type="submit" class="btn btn-secondary">{% trans "Save" %}</button>
|
||||||
|
{% endbuttons %}
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,41 @@
|
||||||
|
{% extends "musician/users_base.html" %}
|
||||||
|
{% load bootstrap4 i18n %}
|
||||||
|
|
||||||
|
{% block tabcontent %}
|
||||||
|
<p></p>
|
||||||
|
<p>{% trans "The main user is your system's main user on each server. You'll be able to view the logs of your websites at (/home/account/logs) and all web content, but you'll never be able to edit content on a website." %}</p>
|
||||||
|
<p>{% trans "This user only has write permissions in their own directory." %}</p>
|
||||||
|
|
||||||
|
|
||||||
|
<table class="table service-list">
|
||||||
|
<colgroup>
|
||||||
|
<col span="1" style="width: 15%;">
|
||||||
|
<col span="1" style="width: 25%;">
|
||||||
|
<col span="1" style="width: 60%;">
|
||||||
|
</colgroup>
|
||||||
|
<thead class="thead-dark">
|
||||||
|
<tr>
|
||||||
|
<th scope="col">{% trans "Username" %}</th>
|
||||||
|
<th scope="col">{% trans "Path" %}</th>
|
||||||
|
<th scope="col"></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for systemuser in object_list %}
|
||||||
|
{% if systemuser.is_main %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ systemuser.username }}</td>
|
||||||
|
<td>{{ systemuser.home }}/{{ systemuser.username }}</td>
|
||||||
|
<td>
|
||||||
|
<div class="d-flex justify-content-end">
|
||||||
|
<a class="btn btn-outline-warning" href="{% url 'musician:systemuser-password' systemuser.id %}">
|
||||||
|
<i class="fas fa-key"></i> {% trans "Update password" %}</a>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,31 @@
|
||||||
|
{% extends "musician/base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% if active_domain %}
|
||||||
|
<a class="btn-arrow-left" href="{% url 'musician:systemuser-list' %}">{% trans "Go to global" %}</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<h1 class="service-name">{{ service.verbose_name }}
|
||||||
|
{% if active_domain %}<span class="font-weight-light">{% trans "for" %} {{ active_domain.name }}</span>{% endif %}
|
||||||
|
</h1>
|
||||||
|
<p class="service-description">{{ service.description }}</p>
|
||||||
|
|
||||||
|
{% with request.resolver_match.url_name as url_name %}
|
||||||
|
<ul class="nav nav-tabs" id="myTab" role="tablist">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link {% if url_name == 'systemuser-list' %}active{% endif %}" href="{% url 'musician:systemuser-list' %}" role="tab"
|
||||||
|
aria-selected="{% if url_name == 'systemuser-list' %}true{% else %}false{% endif %}">{% trans "Main User" %}</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link {% if url_name == 'webappuser-list' %}active{% endif %}" href="{% url 'musician:webappuser-list' %}" role="tab"
|
||||||
|
aria-selected="{% if url_name == 'webappuser-list' %}true{% else %}false{% endif %}">{% trans "SFTP Users" %}</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
{% endwith %}
|
||||||
|
|
||||||
|
<div class="tab-content" id="myTabContent">
|
||||||
|
{% block tabcontent %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -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:webappuser-list' %}">{% trans "Cancel" %}</a>
|
||||||
|
<button type="submit" class="btn btn-secondary">{% trans "Save" %}</button>
|
||||||
|
{% endbuttons %}
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,37 @@
|
||||||
|
{% extends "musician/users_base.html" %}
|
||||||
|
{% load bootstrap4 i18n %}
|
||||||
|
|
||||||
|
{% block tabcontent %}
|
||||||
|
|
||||||
|
<table class="table service-list">
|
||||||
|
<colgroup>
|
||||||
|
<col span="1" style="width: 15%;">
|
||||||
|
<col span="1" style="width: 25%;">
|
||||||
|
<col span="1" style="width: 40%;">
|
||||||
|
<col span="1" style="width: 20%;">
|
||||||
|
</colgroup>
|
||||||
|
<thead class="thead-dark">
|
||||||
|
<tr>
|
||||||
|
<th scope="col">{% trans "Username" %}</th>
|
||||||
|
<th scope="col">{% trans "Path" %}</th>
|
||||||
|
<th scope="col">{% trans "Server" %}</th>
|
||||||
|
<th scope="col"></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for webappuser in object_list %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ webappuser.username }}</td>
|
||||||
|
<td>/home/{{ webappuser.account }}/webapps/{{ webappuser.home }}</td>
|
||||||
|
<td>{{ webappuser.target_server }}</td>
|
||||||
|
<td>
|
||||||
|
<a class="btn btn-outline-warning" href="{% url 'musician:webappuser-password' webappuser.id %}">
|
||||||
|
<i class="fas fa-key"></i> {% trans "Update password" %}</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
{% include "musician/components/table_paginator.html" %}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -39,4 +39,9 @@ urlpatterns = [
|
||||||
path('mailing-lists/', views.MailingListsView.as_view(), name='mailing-lists'),
|
path('mailing-lists/', views.MailingListsView.as_view(), name='mailing-lists'),
|
||||||
path('databases/', views.DatabaseListView.as_view(), name='database-list'),
|
path('databases/', views.DatabaseListView.as_view(), name='database-list'),
|
||||||
path('saas/', views.SaasListView.as_view(), name='saas-list'),
|
path('saas/', views.SaasListView.as_view(), name='saas-list'),
|
||||||
|
|
||||||
|
path('webappusers/', views.WebappUserListView.as_view(), name='webappuser-list'),
|
||||||
|
path('webappuser/<int:pk>/change-password/', views.WebappUserChangePasswordView.as_view(), name='webappuser-password'),
|
||||||
|
path('systemusers/', views.SystemUserListView.as_view(), name='systemuser-list'),
|
||||||
|
path('systemuser/<int:pk>/change-password/', views.SystemUserChangePasswordView.as_view(), name='systemuser-password'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -32,12 +32,14 @@ from orchestra.contrib.lists.models import List
|
||||||
from orchestra.contrib.mailboxes.models import Address, Mailbox
|
from orchestra.contrib.mailboxes.models import Address, Mailbox
|
||||||
from orchestra.contrib.resources.models import Resource, ResourceData
|
from orchestra.contrib.resources.models import Resource, ResourceData
|
||||||
from orchestra.contrib.saas.models import SaaS
|
from orchestra.contrib.saas.models import SaaS
|
||||||
|
from orchestra.contrib.systemusers.models import WebappUsers, SystemUser
|
||||||
from orchestra.utils.html import html_to_pdf
|
from orchestra.utils.html import html_to_pdf
|
||||||
|
|
||||||
from .auth import logout as auth_logout
|
from .auth import logout as auth_logout
|
||||||
from .forms import (LoginForm, MailboxChangePasswordForm, MailboxCreateForm,
|
from .forms import (LoginForm, MailboxChangePasswordForm, MailboxCreateForm,
|
||||||
MailboxSearchForm, MailboxUpdateForm, MailForm,
|
MailboxSearchForm, MailboxUpdateForm, MailForm,
|
||||||
RecordCreateForm, RecordUpdateForm)
|
RecordCreateForm, RecordUpdateForm, WebappUsersChangePasswordForm,
|
||||||
|
SystemUsersChangePasswordForm)
|
||||||
from .mixins import (CustomContextMixin, ExtendedPaginationMixin,
|
from .mixins import (CustomContextMixin, ExtendedPaginationMixin,
|
||||||
UserTokenRequiredMixin)
|
UserTokenRequiredMixin)
|
||||||
from .models import Address as AddressService
|
from .models import Address as AddressService
|
||||||
|
@ -612,3 +614,39 @@ class LogoutView(RedirectView):
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
"""Logout may be done via POST."""
|
"""Logout may be done via POST."""
|
||||||
return self.get(request, *args, **kwargs)
|
return self.get(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class WebappUserListView(ServiceListView):
|
||||||
|
model = WebappUsers
|
||||||
|
template_name = "musician/webappuser_list.html"
|
||||||
|
extra_context = {
|
||||||
|
# Translators: This message appears on the page title
|
||||||
|
'title': _('Webapp users'),
|
||||||
|
}
|
||||||
|
|
||||||
|
class WebappUserChangePasswordView(CustomContextMixin, UserTokenRequiredMixin, UpdateView):
|
||||||
|
template_name = "musician/webappuser_change_password.html"
|
||||||
|
model = WebappUsers
|
||||||
|
form_class = WebappUsersChangePasswordForm
|
||||||
|
success_url = reverse_lazy("musician:webappuser-list")
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return self.model.objects.filter(account=self.request.user)
|
||||||
|
|
||||||
|
|
||||||
|
class SystemUserListView(ServiceListView):
|
||||||
|
model = SystemUser
|
||||||
|
template_name = "musician/systemuser_list.html"
|
||||||
|
extra_context = {
|
||||||
|
# Translators: This message appears on the page title
|
||||||
|
'title': _('Main users'),
|
||||||
|
}
|
||||||
|
|
||||||
|
class SystemUserChangePasswordView(CustomContextMixin, UserTokenRequiredMixin, UpdateView):
|
||||||
|
template_name = "musician/systemuser_change_password.html"
|
||||||
|
model = SystemUser
|
||||||
|
form_class = SystemUsersChangePasswordForm
|
||||||
|
success_url = reverse_lazy("musician:systemuser-list")
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return self.model.objects.filter(account=self.request.user)
|
Loading…
Reference in New Issue