From ddd8ecf634289f68e705107f2b94fd0fe9f98b5b Mon Sep 17 00:00:00 2001 From: Santiago Lamora Date: Thu, 7 Oct 2021 13:51:31 +0200 Subject: [PATCH] Allow updating mailbox addresses --- musician/api.py | 7 +++- musician/forms.py | 20 ++++++++++ musician/models.py | 7 ++++ musician/templates/musician/mailbox_form.html | 2 +- musician/templates/musician/mailboxes.html | 14 ++----- musician/urls.py | 1 + musician/views.py | 38 ++++++++++++++++++- 7 files changed, 76 insertions(+), 13 deletions(-) diff --git a/musician/api.py b/musician/api.py index a106040..15ca269 100644 --- a/musician/api.py +++ b/musician/api.py @@ -1,5 +1,4 @@ import urllib.parse -from itertools import groupby import requests from django.conf import settings @@ -178,6 +177,12 @@ class Orchestra(object): raise Http404(_("No mailbox found matching the query")) 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): mailboxes = self.retrieve_service_list(Mailbox.api_name) return [Mailbox.new_from_json(mailbox_data) for mailbox_data in mailboxes] diff --git a/musician/forms.py b/musician/forms.py index 4823fd7..cd3b74d 100644 --- a/musician/forms.py +++ b/musician/forms.py @@ -94,3 +94,23 @@ class MailboxCreateForm(forms.Form): "password": self.cleaned_data["password2"], } 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 diff --git a/musician/models.py b/musician/models.py index ffd594e..146f7c3 100644 --- a/musician/models.py +++ b/musician/models.py @@ -241,6 +241,7 @@ class Address(OrchestraModel): "domain": None, "mailboxes": [], "forward": None, + 'url': None, } FORWARD = 'forward' @@ -324,6 +325,12 @@ class Mailbox(OrchestraModel): addresses = [Address.new_from_json(addr) for addr in data.get('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): api_name = 'mailinglist' diff --git a/musician/templates/musician/mailbox_form.html b/musician/templates/musician/mailbox_form.html index b7484bc..af51a04 100644 --- a/musician/templates/musician/mailbox_form.html +++ b/musician/templates/musician/mailbox_form.html @@ -21,7 +21,7 @@ {% if form.instance %}
- {% trans "Delete" %} + {% trans "Delete" %}
{% endif %} {% endbuttons %} diff --git a/musician/templates/musician/mailboxes.html b/musician/templates/musician/mailboxes.html index 8260b75..961dd74 100644 --- a/musician/templates/musician/mailboxes.html +++ b/musician/templates/musician/mailboxes.html @@ -5,17 +5,15 @@
- - - + + - @@ -23,19 +21,15 @@ {# #} {% if mailbox.is_active %} - + - {% endif %}{# #} {% endfor %} diff --git a/musician/urls.py b/musician/urls.py index 0902ae6..62a3794 100644 --- a/musician/urls.py +++ b/musician/urls.py @@ -25,6 +25,7 @@ urlpatterns = [ path('address//delete/', views.AddressDeleteView.as_view(), name='address-delete'), path('mailboxes/', views.MailboxesView.as_view(), name='mailbox-list'), path('mailboxes/new/', views.MailboxCreateView.as_view(), name='mailbox-create'), + path('mailboxes//', views.MailboxUpdateView.as_view(), name='mailbox-update'), path('mailboxes//delete/', views.MailboxDeleteView.as_view(), name='mailbox-delete'), path('mailing-lists/', views.MailingListsView.as_view(), name='mailing-lists'), path('databases/', views.DatabasesView.as_view(), name='database-list'), diff --git a/musician/views.py b/musician/views.py index 8683261..4cc0b40 100644 --- a/musician/views.py +++ b/musician/views.py @@ -18,7 +18,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, MailForm, MailboxCreateForm +from .forms import LoginForm, MailForm, MailboxCreateForm, MailboxUpdateForm from .mixins import (CustomContextMixin, ExtendedPaginationMixin, UserTokenRequiredMixin) from .models import (Address, Bill, DatabaseService, Mailbox, MailinglistService, @@ -356,6 +356,42 @@ class MailboxCreateView(CustomContextMixin, UserTokenRequiredMixin, FormView): 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): template_name = "musician/mailbox_check_delete.html" success_url = reverse_lazy("musician:mailbox-list")
{% trans "Name" %} {% trans "Filtering" %} {% trans "Addresses" %}
{{ mailbox.name }}{{ mailbox.name }} {{ mailbox.filtering }} {% for addr in mailbox.addresses %} - {{ addr.data.name }}@{{ addr.data.domain.name }} + {{ addr.full_address_name }}
{% endfor %}
- - -