Allow updating mailbox addresses

This commit is contained in:
Santiago L 2021-10-07 13:51:31 +02:00
parent a0808896b4
commit ddd8ecf634
7 changed files with 76 additions and 13 deletions

View File

@ -1,5 +1,4 @@
import urllib.parse import urllib.parse
from itertools import groupby
import requests import requests
from django.conf import settings from django.conf import settings
@ -178,6 +177,12 @@ class Orchestra(object):
raise Http404(_("No mailbox found matching the query")) raise Http404(_("No mailbox found matching the query"))
return Mailbox.new_from_json(data_json) return Mailbox.new_from_json(data_json)
def update_mailbox(self, pk, data):
path = API_PATHS.get('mailbox-detail').format_map({'pk': pk})
url = urllib.parse.urljoin(self.base_url, path)
status, response = self.request("PATCH", url=url, data=data, raise_exception=False)
return status, response
def retrieve_mailbox_list(self): def retrieve_mailbox_list(self):
mailboxes = self.retrieve_service_list(Mailbox.api_name) mailboxes = self.retrieve_service_list(Mailbox.api_name)
return [Mailbox.new_from_json(mailbox_data) for mailbox_data in mailboxes] return [Mailbox.new_from_json(mailbox_data) for mailbox_data in mailboxes]

View File

@ -94,3 +94,23 @@ class MailboxCreateForm(forms.Form):
"password": self.cleaned_data["password2"], "password": self.cleaned_data["password2"],
} }
return serialized_data return serialized_data
class MailboxUpdateForm(forms.Form):
addresses = forms.MultipleChoiceField(required=False)
def __init__(self, *args, **kwargs):
self.instance = kwargs.pop('instance', None)
if self.instance is not None:
kwargs['initial'] = self.instance.deserialize()
addresses = kwargs.pop('addresses')
super().__init__(*args, **kwargs)
self.fields['addresses'].choices = [(addr.url, addr.full_address_name) for addr in addresses]
def serialize(self):
assert self.is_valid()
serialized_data = {
"addresses": self.cleaned_data["addresses"],
}
return serialized_data

View File

@ -241,6 +241,7 @@ class Address(OrchestraModel):
"domain": None, "domain": None,
"mailboxes": [], "mailboxes": [],
"forward": None, "forward": None,
'url': None,
} }
FORWARD = 'forward' FORWARD = 'forward'
@ -324,6 +325,12 @@ class Mailbox(OrchestraModel):
addresses = [Address.new_from_json(addr) for addr in data.get('addresses', [])] addresses = [Address.new_from_json(addr) for addr in data.get('addresses', [])]
return super().new_from_json(data=data, addresses=addresses) return super().new_from_json(data=data, addresses=addresses)
def deserialize(self):
data = {
'addresses': [addr.url for addr in self.addresses],
}
return data
class MailinglistService(OrchestraModel): class MailinglistService(OrchestraModel):
api_name = 'mailinglist' api_name = 'mailinglist'

View File

@ -21,7 +21,7 @@
<button type="submit" class="btn btn-secondary">{% trans "Save" %}</button> <button type="submit" class="btn btn-secondary">{% trans "Save" %}</button>
{% if form.instance %} {% if form.instance %}
<div class="float-right"> <div class="float-right">
<a class="btn btn-danger" href="{# TODO url 'musician:mailbox-delete' view.kwargs.pk #}">{% trans "Delete" %}</a> <a class="btn btn-danger" href="{% url 'musician:mailbox-delete' view.kwargs.pk %}">{% trans "Delete" %}</a>
</div> </div>
{% endif %} {% endif %}
{% endbuttons %} {% endbuttons %}

View File

@ -5,17 +5,15 @@
<div class="tab-pane fade show active" id="mailboxes" role="tabpanel" aria-labelledby="mailboxes-tab"> <div class="tab-pane fade show active" id="mailboxes" role="tabpanel" aria-labelledby="mailboxes-tab">
<table class="table service-list"> <table class="table service-list">
<colgroup> <colgroup>
<col span="1" style="width: 20%;"> <col span="1" style="width: 25%;">
<col span="1" style="width: 10%;">
<col span="1" style="width: 60%;">
<col span="1" style="width: 10%;"> <col span="1" style="width: 10%;">
<col span="1" style="width: 65%;">
</colgroup> </colgroup>
<thead class="thead-dark"> <thead class="thead-dark">
<tr> <tr>
<th scope="col">{% trans "Name" %}</th> <th scope="col">{% trans "Name" %}</th>
<th scope="col">{% trans "Filtering" %}</th> <th scope="col">{% trans "Filtering" %}</th>
<th scope="col">{% trans "Addresses" %}</th> <th scope="col">{% trans "Addresses" %}</th>
<th scope="col"></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -23,19 +21,15 @@
{# <!-- Exclude (don't render) inactive mailboxes -->#} {# <!-- Exclude (don't render) inactive mailboxes -->#}
{% if mailbox.is_active %} {% if mailbox.is_active %}
<tr> <tr>
<td>{{ mailbox.name }}</td> <td><a href="{% url 'musician:mailbox-update' mailbox.id %}">{{ mailbox.name }}</a></td>
<td>{{ mailbox.filtering }}</td> <td>{{ mailbox.filtering }}</td>
<td> <td>
{% for addr in mailbox.addresses %} {% for addr in mailbox.addresses %}
<a href="{% url 'musician:address-update' addr.data.id %}"> <a href="{% url 'musician:address-update' addr.data.id %}">
{{ addr.data.name }}@{{ addr.data.domain.name }} {{ addr.full_address_name }}
</a><br/> </a><br/>
{% endfor %} {% endfor %}
</td> </td>
<td>
<a class="btn btn-outline-danger" href="{% url 'musician:mailbox-delete' mailbox.id %}" title="{% trans 'Delete' %}"><i class="fas fa-trash"></i></a>
</td>
</tr> </tr>
{% endif %}{# <!-- /is_active --> #} {% endif %}{# <!-- /is_active --> #}
{% endfor %} {% endfor %}

View File

@ -25,6 +25,7 @@ urlpatterns = [
path('address/<int:pk>/delete/', views.AddressDeleteView.as_view(), name='address-delete'), path('address/<int:pk>/delete/', views.AddressDeleteView.as_view(), name='address-delete'),
path('mailboxes/', views.MailboxesView.as_view(), name='mailbox-list'), path('mailboxes/', views.MailboxesView.as_view(), name='mailbox-list'),
path('mailboxes/new/', views.MailboxCreateView.as_view(), name='mailbox-create'), 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>/delete/', views.MailboxDeleteView.as_view(), name='mailbox-delete'),
path('mailing-lists/', views.MailingListsView.as_view(), name='mailing-lists'), path('mailing-lists/', views.MailingListsView.as_view(), name='mailing-lists'),
path('databases/', views.DatabasesView.as_view(), name='database-list'), path('databases/', views.DatabasesView.as_view(), name='database-list'),

View File

@ -18,7 +18,7 @@ from requests.exceptions import HTTPError
from . import api, get_version from . import api, get_version
from .auth import login as auth_login from .auth import login as auth_login
from .auth import logout as auth_logout from .auth import logout as auth_logout
from .forms import LoginForm, MailForm, MailboxCreateForm from .forms import LoginForm, MailForm, MailboxCreateForm, MailboxUpdateForm
from .mixins import (CustomContextMixin, ExtendedPaginationMixin, from .mixins import (CustomContextMixin, ExtendedPaginationMixin,
UserTokenRequiredMixin) UserTokenRequiredMixin)
from .models import (Address, Bill, DatabaseService, Mailbox, MailinglistService, from .models import (Address, Bill, DatabaseService, Mailbox, MailinglistService,
@ -356,6 +356,42 @@ class MailboxCreateView(CustomContextMixin, UserTokenRequiredMixin, FormView):
return super().form_valid(form) return super().form_valid(form)
class MailboxUpdateView(CustomContextMixin, UserTokenRequiredMixin, FormView):
service_class = Mailbox
template_name = "musician/mailbox_form.html"
form_class = MailboxUpdateForm
success_url = reverse_lazy("musician:mailbox-list")
extra_context = {'service': service_class}
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
instance = self.orchestra.retrieve_mailbox(self.kwargs['pk'])
kwargs.update({
'instance': instance,
'addresses': self.orchestra.retrieve_mail_address_list(),
})
return kwargs
def form_valid(self, form):
serialized_data = form.serialize()
status, response = self.orchestra.update_mailbox(self.kwargs['pk'], serialized_data)
if status >= 400:
if status == 400:
# handle errors & add to form (they will be rendered)
form.add_error(field=None, error=response)
else:
logger.error("{}: {}".format(status, response[:120]))
msg = "Sorry, an error occurred while processing your request ({})".format(status)
form.add_error(field='__all__', error=msg)
return self.form_invalid(form)
return super().form_valid(form)
class MailboxDeleteView(CustomContextMixin, UserTokenRequiredMixin, DeleteView): class MailboxDeleteView(CustomContextMixin, UserTokenRequiredMixin, DeleteView):
template_name = "musician/mailbox_check_delete.html" template_name = "musician/mailbox_check_delete.html"
success_url = reverse_lazy("musician:mailbox-list") success_url = reverse_lazy("musician:mailbox-list")