diff --git a/src/postorius/forms.py b/src/postorius/forms.py index 68a4075..39ecfb7 100644 --- a/src/postorius/forms.py +++ b/src/postorius/forms.py @@ -19,10 +19,12 @@ from __future__ import absolute_import, unicode_literals from django import forms +from django.core.urlresolvers import reverse from django.core.validators import validate_email from django.utils.encoding import smart_text from django.utils.translation import ugettext_lazy as _ from django.utils.version import get_complete_version +from django.contrib.sites.models import Site ACTION_CHOICES = ( @@ -55,6 +57,11 @@ return result +def _get_site_choices(): + for site in Site.objects.order_by("name"): + yield (site.pk, "{} ({})".format(site.name, site.domain)) + + class DomainNew(forms.Form): """ @@ -70,6 +77,15 @@ description = forms.CharField( label=_('Description'), required=False) + web_host = forms.ChoiceField( + label=_('Web Host'), + error_messages={'required': _('Please enter a domain name'), + 'invalid': _('Please enter a valid domain name.')}, + required=True, + choices=_get_site_choices, + help_text=lambda: _('Edit the list of available web hosts.') + % reverse("admin:sites_site_changelist"), + ) def clean_mail_host(self): mail_host = self.cleaned_data['mail_host'] diff --git a/src/postorius/templates/postorius/domain/index.html b/src/postorius/templates/postorius/domain/index.html index ef83e5c..298fa9e 100644 --- a/src/postorius/templates/postorius/domain/index.html +++ b/src/postorius/templates/postorius/domain/index.html @@ -19,6 +19,7 @@ {% trans 'Mail Host' %} {% trans 'Description' %} + {% trans 'Web Host' %}   @@ -27,6 +28,7 @@ {{ domain.mail_host }} {{ domain.description }} + {{ domain.site.name }} ({{ domain.site.domain }}) {% trans 'Delete' %} {% endfor %} diff --git a/src/postorius/tests/fixtures/vcr_cassettes/DomainDeleteTest.test_domain_delete.yaml b/src/postorius/tests/fixtures/vcr_cassettes/DomainDeleteTest.test_domain_delete.yaml index 75b2eeb..00140e2 100644 --- a/src/postorius/tests/fixtures/vcr_cassettes/DomainDeleteTest.test_domain_delete.yaml +++ b/src/postorius/tests/fixtures/vcr_cassettes/DomainDeleteTest.test_domain_delete.yaml @@ -87,6 +87,19 @@ body: null headers: accept-encoding: ['gzip, deflate'] + method: !!python/unicode GET + uri: http://localhost:9001/3.0/domains/example.com + response: + body: {string: !!python/unicode '{"description": null, "http_etag": "\"d150abd34fabbcef42a2c654bfac81aa04ea4d6f\"", + "mail_host": "example.com", "self_link": "http://localhost:9001/3.0/domains/example.com"}'} + headers: + content-length: ['172'] + content-type: [application/json; charset=UTF-8] + status: {code: 200, message: OK} +- request: + body: null + headers: + accept-encoding: ['gzip, deflate'] method: !!python/unicode DELETE uri: http://localhost:9001/3.0/domains/example.com response: diff --git a/src/postorius/tests/fixtures/vcr_cassettes/DomainIndexPageTest.test_contains_domains_and_site.yaml b/src/postorius/tests/fixtures/vcr_cassettes/DomainIndexPageTest.test_contains_domains_and_site.yaml new file mode 100644 index 0000000..7ae002d --- /dev/null +++ b/src/postorius/tests/fixtures/vcr_cassettes/DomainIndexPageTest.test_contains_domains_and_site.yaml @@ -0,0 +1,182 @@ +interactions: +- request: + body: !!python/unicode mail_host=example.com + headers: + accept-encoding: ['gzip, deflate'] + !!python/unicode content-type: [!!python/unicode application/x-www-form-urlencoded] + method: !!python/unicode POST + uri: http://localhost:9001/3.0/domains + response: + body: {string: !!python/unicode ''} + headers: + content-length: ['0'] + content-type: [application/json; charset=UTF-8] + location: ['http://localhost:9001/3.0/domains/example.com'] + status: {code: 201, message: Created} +- request: + body: null + headers: + accept-encoding: ['gzip, deflate'] + method: !!python/unicode GET + uri: http://localhost:9001/3.0/domains/example.com + response: + body: {string: !!python/unicode '{"description": null, "http_etag": "\"d150abd34fabbcef42a2c654bfac81aa04ea4d6f\"", + "mail_host": "example.com", "self_link": "http://localhost:9001/3.0/domains/example.com"}'} + headers: + content-length: ['172'] + content-type: [application/json; charset=UTF-8] + status: {code: 200, message: OK} +- request: + body: !!python/unicode fqdn_listname=foo%40example.com + headers: + accept-encoding: ['gzip, deflate'] + !!python/unicode content-type: [!!python/unicode application/x-www-form-urlencoded] + method: !!python/unicode POST + uri: http://localhost:9001/3.0/lists + response: + body: {string: !!python/unicode ''} + headers: + content-length: ['0'] + content-type: [application/json; charset=UTF-8] + location: ['http://localhost:9001/3.0/lists/foo.example.com'] + status: {code: 201, message: Created} +- request: + body: null + headers: + accept-encoding: ['gzip, deflate'] + method: !!python/unicode GET + uri: http://localhost:9001/3.0/lists/foo.example.com + response: + body: {string: !!python/unicode '{"display_name": "Foo", "fqdn_listname": "foo@example.com", + "http_etag": "\"698a819bbb6b902096a8c5543cc7fac2328960d5\"", "list_id": "foo.example.com", + "list_name": "foo", "mail_host": "example.com", "member_count": 0, "self_link": + "http://localhost:9001/3.0/lists/foo.example.com", "volume": 1}'} + headers: + content-length: ['294'] + content-type: [application/json; charset=UTF-8] + status: {code: 200, message: OK} +- request: + body: !!python/unicode list_id=foo.example.com&role=owner&subscriber=owner%40example.com + headers: + accept-encoding: ['gzip, deflate'] + !!python/unicode content-type: [!!python/unicode application/x-www-form-urlencoded] + method: !!python/unicode POST + uri: http://localhost:9001/3.0/members + response: + body: {string: !!python/unicode ''} + headers: + content-length: ['0'] + content-type: [application/json; charset=UTF-8] + location: ['http://localhost:9001/3.0/members/114'] + status: {code: 201, message: Created} +- request: + body: !!python/unicode list_id=foo.example.com&role=moderator&subscriber=moderator%40example.com + headers: + accept-encoding: ['gzip, deflate'] + !!python/unicode content-type: [!!python/unicode application/x-www-form-urlencoded] + method: !!python/unicode POST + uri: http://localhost:9001/3.0/members + response: + body: {string: !!python/unicode ''} + headers: + content-length: ['0'] + content-type: [application/json; charset=UTF-8] + location: ['http://localhost:9001/3.0/members/115'] + status: {code: 201, message: Created} +- request: + body: null + headers: + accept-encoding: ['gzip, deflate'] + method: !!python/unicode GET + uri: http://localhost:9001/3.0/domains + response: + body: {string: !!python/unicode '{"entries": [{"description": null, "http_etag": + "\"d150abd34fabbcef42a2c654bfac81aa04ea4d6f\"", "mail_host": "example.com", + "self_link": "http://localhost:9001/3.0/domains/example.com"}], "http_etag": + "\"2ec9679269ad1f741705a62db0162f5585ae5c3c\"", "start": 0, "total_size": + 1}'} + headers: + content-length: ['277'] + content-type: [application/json; charset=UTF-8] + status: {code: 200, message: OK} +- request: + body: null + headers: + accept-encoding: ['gzip, deflate'] + method: !!python/unicode GET + uri: http://localhost:9001/3.0/domains/example.com + response: + body: {string: !!python/unicode '{"description": null, "http_etag": "\"d150abd34fabbcef42a2c654bfac81aa04ea4d6f\"", + "mail_host": "example.com", "self_link": "http://localhost:9001/3.0/domains/example.com"}'} + headers: + content-length: ['172'] + content-type: [application/json; charset=UTF-8] + status: {code: 200, message: OK} +- request: + body: null + headers: + accept-encoding: ['gzip, deflate'] + method: !!python/unicode GET + uri: http://localhost:9001/3.0/domains + response: + body: {string: !!python/unicode '{"entries": [{"description": null, "http_etag": + "\"d150abd34fabbcef42a2c654bfac81aa04ea4d6f\"", "mail_host": "example.com", + "self_link": "http://localhost:9001/3.0/domains/example.com"}], "http_etag": + "\"2ec9679269ad1f741705a62db0162f5585ae5c3c\"", "start": 0, "total_size": + 1}'} + headers: + content-length: ['277'] + content-type: [application/json; charset=UTF-8] + status: {code: 200, message: OK} +- request: + body: null + headers: + accept-encoding: ['gzip, deflate'] + method: !!python/unicode DELETE + uri: http://localhost:9001/3.0/domains/example.com + response: + body: {string: !!python/unicode ''} + headers: + content-length: ['0'] + status: {code: 204, message: No Content} +- request: + body: null + headers: + accept-encoding: ['gzip, deflate'] + method: !!python/unicode GET + uri: http://localhost:9001/3.0/users + response: + body: {string: !!python/unicode '{"entries": [{"created_on": "2005-08-01T07:49:23", + "http_etag": "\"562a0d26c257705a22902c5a8cd196ab62f7ced1\"", "is_server_owner": + false, "self_link": "http://localhost:9001/3.0/users/115", "user_id": 115}, + {"created_on": "2005-08-01T07:49:23", "http_etag": "\"ce2c375de7d732a159dcd47a5d9ffebbe27a4091\"", + "is_server_owner": false, "self_link": "http://localhost:9001/3.0/users/116", + "user_id": 116}], "http_etag": "\"cab28cf9697db1ef375c2f1b3ca55622bf7997c2\"", + "start": 0, "total_size": 2}'} + headers: + content-length: ['491'] + content-type: [application/json; charset=UTF-8] + status: {code: 200, message: OK} +- request: + body: null + headers: + accept-encoding: ['gzip, deflate'] + method: !!python/unicode DELETE + uri: http://localhost:9001/3.0/users/115 + response: + body: {string: !!python/unicode ''} + headers: + content-length: ['0'] + status: {code: 204, message: No Content} +- request: + body: null + headers: + accept-encoding: ['gzip, deflate'] + method: !!python/unicode DELETE + uri: http://localhost:9001/3.0/users/116 + response: + body: {string: !!python/unicode ''} + headers: + content-length: ['0'] + status: {code: 204, message: No Content} +version: 1 diff --git a/src/postorius/tests/fixtures/vcr_cassettes/DomainIndexPageTest.test_domain_index_contains_the_domains.yaml b/src/postorius/tests/fixtures/vcr_cassettes/DomainIndexPageTest.test_domain_index_contains_the_domains.yaml deleted file mode 100644 index 7ae002d..0000000 --- a/src/postorius/tests/fixtures/vcr_cassettes/DomainIndexPageTest.test_domain_index_contains_the_domains.yaml +++ /dev/null @@ -1,182 +0,0 @@ -interactions: -- request: - body: !!python/unicode mail_host=example.com - headers: - accept-encoding: ['gzip, deflate'] - !!python/unicode content-type: [!!python/unicode application/x-www-form-urlencoded] - method: !!python/unicode POST - uri: http://localhost:9001/3.0/domains - response: - body: {string: !!python/unicode ''} - headers: - content-length: ['0'] - content-type: [application/json; charset=UTF-8] - location: ['http://localhost:9001/3.0/domains/example.com'] - status: {code: 201, message: Created} -- request: - body: null - headers: - accept-encoding: ['gzip, deflate'] - method: !!python/unicode GET - uri: http://localhost:9001/3.0/domains/example.com - response: - body: {string: !!python/unicode '{"description": null, "http_etag": "\"d150abd34fabbcef42a2c654bfac81aa04ea4d6f\"", - "mail_host": "example.com", "self_link": "http://localhost:9001/3.0/domains/example.com"}'} - headers: - content-length: ['172'] - content-type: [application/json; charset=UTF-8] - status: {code: 200, message: OK} -- request: - body: !!python/unicode fqdn_listname=foo%40example.com - headers: - accept-encoding: ['gzip, deflate'] - !!python/unicode content-type: [!!python/unicode application/x-www-form-urlencoded] - method: !!python/unicode POST - uri: http://localhost:9001/3.0/lists - response: - body: {string: !!python/unicode ''} - headers: - content-length: ['0'] - content-type: [application/json; charset=UTF-8] - location: ['http://localhost:9001/3.0/lists/foo.example.com'] - status: {code: 201, message: Created} -- request: - body: null - headers: - accept-encoding: ['gzip, deflate'] - method: !!python/unicode GET - uri: http://localhost:9001/3.0/lists/foo.example.com - response: - body: {string: !!python/unicode '{"display_name": "Foo", "fqdn_listname": "foo@example.com", - "http_etag": "\"698a819bbb6b902096a8c5543cc7fac2328960d5\"", "list_id": "foo.example.com", - "list_name": "foo", "mail_host": "example.com", "member_count": 0, "self_link": - "http://localhost:9001/3.0/lists/foo.example.com", "volume": 1}'} - headers: - content-length: ['294'] - content-type: [application/json; charset=UTF-8] - status: {code: 200, message: OK} -- request: - body: !!python/unicode list_id=foo.example.com&role=owner&subscriber=owner%40example.com - headers: - accept-encoding: ['gzip, deflate'] - !!python/unicode content-type: [!!python/unicode application/x-www-form-urlencoded] - method: !!python/unicode POST - uri: http://localhost:9001/3.0/members - response: - body: {string: !!python/unicode ''} - headers: - content-length: ['0'] - content-type: [application/json; charset=UTF-8] - location: ['http://localhost:9001/3.0/members/114'] - status: {code: 201, message: Created} -- request: - body: !!python/unicode list_id=foo.example.com&role=moderator&subscriber=moderator%40example.com - headers: - accept-encoding: ['gzip, deflate'] - !!python/unicode content-type: [!!python/unicode application/x-www-form-urlencoded] - method: !!python/unicode POST - uri: http://localhost:9001/3.0/members - response: - body: {string: !!python/unicode ''} - headers: - content-length: ['0'] - content-type: [application/json; charset=UTF-8] - location: ['http://localhost:9001/3.0/members/115'] - status: {code: 201, message: Created} -- request: - body: null - headers: - accept-encoding: ['gzip, deflate'] - method: !!python/unicode GET - uri: http://localhost:9001/3.0/domains - response: - body: {string: !!python/unicode '{"entries": [{"description": null, "http_etag": - "\"d150abd34fabbcef42a2c654bfac81aa04ea4d6f\"", "mail_host": "example.com", - "self_link": "http://localhost:9001/3.0/domains/example.com"}], "http_etag": - "\"2ec9679269ad1f741705a62db0162f5585ae5c3c\"", "start": 0, "total_size": - 1}'} - headers: - content-length: ['277'] - content-type: [application/json; charset=UTF-8] - status: {code: 200, message: OK} -- request: - body: null - headers: - accept-encoding: ['gzip, deflate'] - method: !!python/unicode GET - uri: http://localhost:9001/3.0/domains/example.com - response: - body: {string: !!python/unicode '{"description": null, "http_etag": "\"d150abd34fabbcef42a2c654bfac81aa04ea4d6f\"", - "mail_host": "example.com", "self_link": "http://localhost:9001/3.0/domains/example.com"}'} - headers: - content-length: ['172'] - content-type: [application/json; charset=UTF-8] - status: {code: 200, message: OK} -- request: - body: null - headers: - accept-encoding: ['gzip, deflate'] - method: !!python/unicode GET - uri: http://localhost:9001/3.0/domains - response: - body: {string: !!python/unicode '{"entries": [{"description": null, "http_etag": - "\"d150abd34fabbcef42a2c654bfac81aa04ea4d6f\"", "mail_host": "example.com", - "self_link": "http://localhost:9001/3.0/domains/example.com"}], "http_etag": - "\"2ec9679269ad1f741705a62db0162f5585ae5c3c\"", "start": 0, "total_size": - 1}'} - headers: - content-length: ['277'] - content-type: [application/json; charset=UTF-8] - status: {code: 200, message: OK} -- request: - body: null - headers: - accept-encoding: ['gzip, deflate'] - method: !!python/unicode DELETE - uri: http://localhost:9001/3.0/domains/example.com - response: - body: {string: !!python/unicode ''} - headers: - content-length: ['0'] - status: {code: 204, message: No Content} -- request: - body: null - headers: - accept-encoding: ['gzip, deflate'] - method: !!python/unicode GET - uri: http://localhost:9001/3.0/users - response: - body: {string: !!python/unicode '{"entries": [{"created_on": "2005-08-01T07:49:23", - "http_etag": "\"562a0d26c257705a22902c5a8cd196ab62f7ced1\"", "is_server_owner": - false, "self_link": "http://localhost:9001/3.0/users/115", "user_id": 115}, - {"created_on": "2005-08-01T07:49:23", "http_etag": "\"ce2c375de7d732a159dcd47a5d9ffebbe27a4091\"", - "is_server_owner": false, "self_link": "http://localhost:9001/3.0/users/116", - "user_id": 116}], "http_etag": "\"cab28cf9697db1ef375c2f1b3ca55622bf7997c2\"", - "start": 0, "total_size": 2}'} - headers: - content-length: ['491'] - content-type: [application/json; charset=UTF-8] - status: {code: 200, message: OK} -- request: - body: null - headers: - accept-encoding: ['gzip, deflate'] - method: !!python/unicode DELETE - uri: http://localhost:9001/3.0/users/115 - response: - body: {string: !!python/unicode ''} - headers: - content-length: ['0'] - status: {code: 204, message: No Content} -- request: - body: null - headers: - accept-encoding: ['gzip, deflate'] - method: !!python/unicode DELETE - uri: http://localhost:9001/3.0/users/116 - response: - body: {string: !!python/unicode ''} - headers: - content-length: ['0'] - status: {code: 204, message: No Content} -version: 1 diff --git a/src/postorius/tests/mailman_api_tests/test_domain_delete.py b/src/postorius/tests/mailman_api_tests/test_domain_delete.py index 3f35f75..370c548 100644 --- a/src/postorius/tests/mailman_api_tests/test_domain_delete.py +++ b/src/postorius/tests/mailman_api_tests/test_domain_delete.py @@ -20,6 +20,8 @@ from allauth.account.models import EmailAddress from django.core.urlresolvers import reverse from django.contrib.auth.models import User +from django.contrib.sites.models import Site +from django_mailman3.models import MailDomain from postorius.tests.utils import ViewTestCase @@ -45,6 +47,8 @@ user=user, email=user.email, verified=True) self.foo_list.add_owner('owner@example.com') self.foo_list.add_moderator('moderator@example.com') + MailDomain.objects.create( + site=Site.objects.get_current(), mail_domain='example.com') self.url = reverse('domain_delete', args=['example.com']) def test_access_anonymous(self): @@ -85,3 +89,5 @@ self.assertEqual(len(self.mm_client.domains), 0) self.assertEqual(len(self.mm_client.lists), 0) self.assertHasSuccessMessage(response) + self.assertFalse( + MailDomain.objects.filter(mail_domain='example.com').exists()) diff --git a/src/postorius/tests/mailman_api_tests/test_domain_index.py b/src/postorius/tests/mailman_api_tests/test_domain_index.py index 0f79193..2b830bf 100644 --- a/src/postorius/tests/mailman_api_tests/test_domain_index.py +++ b/src/postorius/tests/mailman_api_tests/test_domain_index.py @@ -20,6 +20,7 @@ from allauth.account.models import EmailAddress from django.core.urlresolvers import reverse from django.contrib.auth.models import User +from django_mailman3.models import MailDomain try: from urllib2 import HTTPError except ImportError: @@ -72,10 +73,12 @@ response = self.client.get(reverse('domain_index')) self.assertEqual(response.status_code, 403) - def test_domain_index_contains_the_domains(self): + def test_contains_domains_and_site(self): # The list index page should contain the lists self.client.login(username='testsu', password='testpass') response = self.client.get(reverse('domain_index')) self.assertEqual(response.status_code, 200) self.assertEqual(len(response.context['domains']), 1) self.assertContains(response, 'example.com') + self.assertTrue( + MailDomain.objects.filter(mail_domain='example.com').exists()) diff --git a/src/postorius/tests/mailman_api_tests/test_domain_new.py b/src/postorius/tests/mailman_api_tests/test_domain_new.py index 32683f0..ab13204 100644 --- a/src/postorius/tests/mailman_api_tests/test_domain_new.py +++ b/src/postorius/tests/mailman_api_tests/test_domain_new.py @@ -20,6 +20,7 @@ from allauth.account.models import EmailAddress from django.contrib.auth.models import User from django.core.urlresolvers import reverse +from django_mailman3.models import MailDomain from postorius.tests.utils import ViewTestCase @@ -44,7 +45,9 @@ def test_new_domain_created_with_owner(self): self.client.login(username='su', password='pwd') post_data = {'mail_host': 'example.com', - 'description': 'A new Domain.'} + 'description': 'A new Domain.', + 'web_host': '1', + } response = self.client.post(reverse('domain_new'), post_data) self.assertHasSuccessMessage(response) @@ -54,12 +57,16 @@ self.assertEqual(a_new_domain.mail_host, u'example.com') self.assertEqual(a_new_domain.owners[0]['user_id'], self.mm_client.get_user('su@example.com').user_id) + self.assertTrue( + MailDomain.objects.filter(mail_domain='example.com').exists()) a_new_domain.delete() def test_validation_of_mail_host(self): self.client.login(username='su', password='pwd') post_data = {'mail_host': 'example com', - 'description': 'A new Domain'} + 'description': 'A new Domain', + 'web_host': '1', + } response = self.client.post(reverse('domain_new'), post_data) self.assertContains(response, 'Please check the errors below') self.assertContains(response, 'Please enter a valid domain name') diff --git a/src/postorius/views/domain.py b/src/postorius/views/domain.py index 4a0ca70..abf7a2c 100644 --- a/src/postorius/views/domain.py +++ b/src/postorius/views/domain.py @@ -21,9 +21,11 @@ from django.contrib import messages from django.contrib.auth.decorators import login_required +from django.contrib.sites.models import Site from django.shortcuts import render, redirect from django.utils.translation import gettext as _ from django_mailman3.lib.mailman import get_mailman_client +from django_mailman3.models import MailDomain try: from urllib2 import HTTPError except ImportError: @@ -41,8 +43,17 @@ existing_domains = Domain.objects.all() except MailmanApiError: return utils.render_api_error(request) - return render(request, 'postorius/domain/index.html', - {'domains': existing_domains}) + for domain in existing_domains: + try: + web_host = MailDomain.objects.get(mail_domain=domain.mail_host) + except MailDomain.DoesNotExist: + site = Site.objects.get_current(request) + web_host = MailDomain.objects.create( + site=site, mail_domain=domain.mail_host) + domain.site = web_host.site + return render(request, 'postorius/domain/index.html', { + 'domains': existing_domains, + }) @login_required @@ -62,6 +73,9 @@ messages.error(request, e) else: messages.success(request, _("New Domain registered")) + MailDomain.objects.get_or_create( + site=Site.objects.get(pk=int(form.cleaned_data['web_host'])), + mail_domain=form.cleaned_data['mail_host']) return redirect("domain_index") else: messages.error(request, _('Please check the errors below')) @@ -77,8 +91,9 @@ """ if request.method == 'POST': try: - client = get_mailman_client() - client.delete_domain(domain) + domain_obj = Domain.objects.get(mail_host=domain) + domain_obj.delete() + MailDomain.objects.filter(mail_domain=domain).delete() messages.success(request, _('The domain %s has been deleted.' % domain)) return redirect("domain_index")