diff --git a/mailadmin/api.py b/mailadmin/api.py index ace8d76..0a4d550 100644 --- a/mailadmin/api.py +++ b/mailadmin/api.py @@ -1,5 +1,18 @@ import requests from django.conf import settings +import logging +from rest_framework import exceptions + +logger = logging.getLogger(__name__) + + +class DPDAPIException(exceptions.APIException): + status_code = 503 + detail = 'Unknown error.' + + def __init__(self, status_code, detail): + self.status_code = status_code + self.detail = detail class DjangoPostfixDovecotAPI(object): @@ -26,7 +39,11 @@ class DjangoPostfixDovecotAPI(object): json=json, headers=headers) - r.raise_for_status() + try: + r.raise_for_status() + except requests.exceptions.RequestException as e: + logger.warning('mxapi errored {}'.format(e.response)) + raise DPDAPIException(status_code=e.response.status_code, detail=e.response.json()) return r.json() @@ -46,4 +63,16 @@ class DjangoPostfixDovecotAPI(object): 'GET', '/aliases/', params=params + ) + + def list_domains(self, name=None): + params = {} + + if name is not None: + params['name'] = name + + return self._api( + 'GET', + '/domains/', + params=params ) \ No newline at end of file diff --git a/mailadmin/serializers.py b/mailadmin/serializers.py index 7422923..94f8fdc 100644 --- a/mailadmin/serializers.py +++ b/mailadmin/serializers.py @@ -30,11 +30,13 @@ class OrgUnitSerializer(serializers.ModelSerializer): class AliasSerializer(serializers.Serializer): source = serializers.EmailField(required=True) destination = serializers.EmailField(required=True) - _domain_name = settings.NEUF_EMAIL_DOMAIN_NAME + domain = serializers.IntegerField(required=True) - def validate_destonation(self, attrs, source): - domain_part = attrs[source].split('@')[1] - if domain_part != self._domain_name: - raise serializers.ValidationError("dest '{0}' is not in domain {1}".format(attrs[source], self._domain_name)) + def validate_source(self, value): + _domain_name = settings.NEUF_EMAIL_DOMAIN_NAME - return attrs \ No newline at end of file + domain_part = value.split('@')[1] + if domain_part != _domain_name: + raise serializers.ValidationError("source '{0}' is not in domain {1}".format(value, _domain_name)) + + return value \ No newline at end of file diff --git a/mailadmin/static/app/scripts/main.js b/mailadmin/static/app/scripts/main.js index c786ff7..f514bce 100644 --- a/mailadmin/static/app/scripts/main.js +++ b/mailadmin/static/app/scripts/main.js @@ -67,7 +67,8 @@ var api_urls = { aliases: '/api/aliases/', ou_list: '/api/orgunits/', - me: '/api/me/' + me: '/api/me/', + email_domain: '/api/emaildomain/' }; var forwards_container = $(".forwards-container"); nunjucks.configure({ autoescape: true }); @@ -87,103 +88,117 @@ $('.orgunit-list li a[data-prefix="'+prefix+'"]').parent().toggleClass('active'); } - /* New list */ - var new_list_html = nunjucks.render('new_list.html', { - orgunits: data, - api_urls: api_urls - }); + $.getJSON(api_urls.email_domain, function(email_domain) { + email_domain = email_domain.domain; + console.log(email_domain); - - $('.new-list').html(new_list_html); - $('.new-list .js-new-list-name').on('keyup', function() { - var new_list_name = $('.new-list .js-new-list-name').val(); - if(new_list_name === '') { - new_list_name = 'Ny liste'; - } else { - var prefix = $('.new-list .prefix-select .active').attr('data-value'); - new_list_name = 'NY: ' + prefix + new_list_name + "@studentersamfundet.no"; - } - $('.js-new-list-preview').text(new_list_name); - }); - /* Prefix select */ - $('.new-list .prefix-select a').on('click', function() { - $('.new-list .prefix-select a').parent().removeClass('active'); - $(this).parent().addClass('active'); - var prefix = $(this).parent().attr('data-value'); - $('.new-list .prefix-btn').html(prefix+' '); - }); - // TODO put this in a function with selector as argument - $('.new-list textarea').on('keyup', function() { - var text = $(this).val(); - var emails = parseEmails(text); - - if(emails.length > 0) { - $('.new-list .email-counter').text(emails.length); - } else { - $('.new-list .email-counter').text(''); - } - }); - $('.js-add-list').on('click', function(e) { - $('.new-list .result').html(''); // reset errors - e.preventDefault(); - /* Validate */ - var new_list_name = $('.new-list .js-new-list-name').val(); - if(new_list_name.length === 0) { - notify('Ny epostliste', 'Navn på epostliste mangler', 'error'); - return; - } - var text = $('.new-list textarea').val(); - var emails = parseEmails(text); - if(emails.length === 0) { - notify('Ny epostliste', 'Ingen eposter i epost-feltet...', 'error'); - return; - } - // Valid form - var prefix = $('.new-list .prefix-select .active').attr('data-value'); - var dest = prefix + new_list_name + "@studentersamfundet.no"; - - var new_list = {}; - new_list[dest] = _.map(emails, function(el) { - return {'dest': dest, 'forward': el}; + /* New list */ + var new_list_html = nunjucks.render('new_list.html', { + orgunits: data, + api_urls: api_urls, + email_domain: email_domain }); - $.post( - api_urls.aliases, - new_list[dest], - function() { - notify('Lagt til', 'Ny liste: ' + dest + 'lagt til', 'success'); + + $('.new-list').html(new_list_html); + $('.new-list .js-new-list-name').on('keyup', function() { + var new_list_name = $('.new-list .js-new-list-name').val(); + if(new_list_name === '') { + new_list_name = 'Ny liste'; + } else { + var prefix = $('.new-list .prefix-select .active').attr('data-value'); + new_list_name = 'NY: ' + prefix + new_list_name + "@" + email_domain.name; + } + $('.js-new-list-preview').text(new_list_name); + }); + /* Prefix select */ + $('.new-list .prefix-select a').on('click', function() { + $('.new-list .prefix-select a').parent().removeClass('active'); + $(this).parent().addClass('active'); + var prefix = $(this).parent().attr('data-value'); + $('.new-list .prefix-btn').html(prefix+' '); + }); + // TODO put this in a function with selector as argument + $('.new-list textarea').on('keyup', function() { + var text = $(this).val(); + var emails = parseEmails(text); + + if(emails.length > 0) { + $('.new-list .email-counter').text(emails.length); + } else { + $('.new-list .email-counter').text(''); + } + }); + $('.js-add-list').on('click', function(e) { + e.preventDefault(); + /* Validate */ + var new_list_name = $('.new-list .js-new-list-name').val(); + if(new_list_name.length === 0) { + notify('Ny epostliste', 'Navn på epostliste mangler', 'error'); + return; + } + var text = $('.new-list textarea').val(); + var emails = parseEmails(text); + if(emails.length === 0) { + notify('Ny epostliste', 'Ingen eposter i epost-feltet...', 'error'); + return; + } + // Valid form + var prefix = $('.new-list .prefix-select .active').attr('data-value'); + var source = prefix + new_list_name + "@" + email_domain.name; + + var new_aliases = {}; + new_aliases = _.map(emails, function(el) { + return { + 'source': source, + 'destination': el, + 'domain': email_domain.id + }; + }); + console.log(new_aliases); + $.ajax({ + url: api_urls.aliases, + type: 'POST', + headers: {'X-CSRFToken': csrf_token}, + dataType: 'json', + contentType: "application/json; charset=utf-8", + data: JSON.stringify(new_aliases), + + }).done(function(resp) { + console.log(resp); + notify('Lagt til', 'Ny liste: ' + source + ' lagt til', 'success'); $('.new-list textarea').val(''); $('.new-list .js-new-list-name').val(''); - }, - 'json' - ); - var added_list_html = nunjucks.render('list.html', { lists: new_list }); - forwards_container.prepend(added_list_html); + // FIXME: Existing list? + var added_list_html = nunjucks.render('list.html', { lists: new_aliases }); + forwards_container.prepend(added_list_html); + }); - }); + }); - /* Filter lists by orgunit */ - $(".orgunit-list a").on('click', function(e) { - var prefix = $(this).attr('data-prefix'); - e.preventDefault(); + /* Filter lists by orgunit */ + $(".orgunit-list a").on('click', function(e) { + var prefix = $(this).attr('data-prefix'); + e.preventDefault(); - /* Toggle selection */ - $(".orgunit-list li").removeClass('active'); - $(this).parent().toggleClass('active'); - $('.orgunits-select').val(prefix); + /* Toggle selection */ + $(".orgunit-list li").removeClass('active'); + $(this).parent().toggleClass('active'); + $('.orgunits-select').val(prefix); - filter_lists('^'+prefix+'-', true); - $('.js-lists-filter-field').val(''); - }); - $(".orgunits-select").on('change', function() { - var prefix = $(this).val(); + filter_lists('^'+prefix+'-', true); + $('.js-lists-filter-field').val(''); + }); + $(".orgunits-select").on('change', function() { + var prefix = $(this).val(); - /* Toggle selection */ - $(".orgunit-list li").removeClass('active'); - $(".orgunit-list li a[data-prefix="+prefix+"]").parent().toggleClass('active'); + /* Toggle selection */ + $(".orgunit-list li").removeClass('active'); + $(".orgunit-list li a[data-prefix="+prefix+"]").parent().toggleClass('active'); - filter_lists('^'+prefix+'-', true); - $('.js-lists-filter-field').val(''); + filter_lists('^'+prefix+'-', true); + $('.js-lists-filter-field').val(''); + }); }); }); diff --git a/mailadmin/static/app/templates/new_list.html b/mailadmin/static/app/templates/new_list.html index 591296b..eb104c0 100644 --- a/mailadmin/static/app/templates/new_list.html +++ b/mailadmin/static/app/templates/new_list.html @@ -11,7 +11,7 @@ - @studentersamfundet.no + @{{email_domain.name}}

Eposter

diff --git a/mailadmin/static/dist/scripts/main.js b/mailadmin/static/dist/scripts/main.js index c786ff7..f514bce 100644 --- a/mailadmin/static/dist/scripts/main.js +++ b/mailadmin/static/dist/scripts/main.js @@ -67,7 +67,8 @@ var api_urls = { aliases: '/api/aliases/', ou_list: '/api/orgunits/', - me: '/api/me/' + me: '/api/me/', + email_domain: '/api/emaildomain/' }; var forwards_container = $(".forwards-container"); nunjucks.configure({ autoescape: true }); @@ -87,103 +88,117 @@ $('.orgunit-list li a[data-prefix="'+prefix+'"]').parent().toggleClass('active'); } - /* New list */ - var new_list_html = nunjucks.render('new_list.html', { - orgunits: data, - api_urls: api_urls - }); + $.getJSON(api_urls.email_domain, function(email_domain) { + email_domain = email_domain.domain; + console.log(email_domain); - - $('.new-list').html(new_list_html); - $('.new-list .js-new-list-name').on('keyup', function() { - var new_list_name = $('.new-list .js-new-list-name').val(); - if(new_list_name === '') { - new_list_name = 'Ny liste'; - } else { - var prefix = $('.new-list .prefix-select .active').attr('data-value'); - new_list_name = 'NY: ' + prefix + new_list_name + "@studentersamfundet.no"; - } - $('.js-new-list-preview').text(new_list_name); - }); - /* Prefix select */ - $('.new-list .prefix-select a').on('click', function() { - $('.new-list .prefix-select a').parent().removeClass('active'); - $(this).parent().addClass('active'); - var prefix = $(this).parent().attr('data-value'); - $('.new-list .prefix-btn').html(prefix+' '); - }); - // TODO put this in a function with selector as argument - $('.new-list textarea').on('keyup', function() { - var text = $(this).val(); - var emails = parseEmails(text); - - if(emails.length > 0) { - $('.new-list .email-counter').text(emails.length); - } else { - $('.new-list .email-counter').text(''); - } - }); - $('.js-add-list').on('click', function(e) { - $('.new-list .result').html(''); // reset errors - e.preventDefault(); - /* Validate */ - var new_list_name = $('.new-list .js-new-list-name').val(); - if(new_list_name.length === 0) { - notify('Ny epostliste', 'Navn på epostliste mangler', 'error'); - return; - } - var text = $('.new-list textarea').val(); - var emails = parseEmails(text); - if(emails.length === 0) { - notify('Ny epostliste', 'Ingen eposter i epost-feltet...', 'error'); - return; - } - // Valid form - var prefix = $('.new-list .prefix-select .active').attr('data-value'); - var dest = prefix + new_list_name + "@studentersamfundet.no"; - - var new_list = {}; - new_list[dest] = _.map(emails, function(el) { - return {'dest': dest, 'forward': el}; + /* New list */ + var new_list_html = nunjucks.render('new_list.html', { + orgunits: data, + api_urls: api_urls, + email_domain: email_domain }); - $.post( - api_urls.aliases, - new_list[dest], - function() { - notify('Lagt til', 'Ny liste: ' + dest + 'lagt til', 'success'); + + $('.new-list').html(new_list_html); + $('.new-list .js-new-list-name').on('keyup', function() { + var new_list_name = $('.new-list .js-new-list-name').val(); + if(new_list_name === '') { + new_list_name = 'Ny liste'; + } else { + var prefix = $('.new-list .prefix-select .active').attr('data-value'); + new_list_name = 'NY: ' + prefix + new_list_name + "@" + email_domain.name; + } + $('.js-new-list-preview').text(new_list_name); + }); + /* Prefix select */ + $('.new-list .prefix-select a').on('click', function() { + $('.new-list .prefix-select a').parent().removeClass('active'); + $(this).parent().addClass('active'); + var prefix = $(this).parent().attr('data-value'); + $('.new-list .prefix-btn').html(prefix+' '); + }); + // TODO put this in a function with selector as argument + $('.new-list textarea').on('keyup', function() { + var text = $(this).val(); + var emails = parseEmails(text); + + if(emails.length > 0) { + $('.new-list .email-counter').text(emails.length); + } else { + $('.new-list .email-counter').text(''); + } + }); + $('.js-add-list').on('click', function(e) { + e.preventDefault(); + /* Validate */ + var new_list_name = $('.new-list .js-new-list-name').val(); + if(new_list_name.length === 0) { + notify('Ny epostliste', 'Navn på epostliste mangler', 'error'); + return; + } + var text = $('.new-list textarea').val(); + var emails = parseEmails(text); + if(emails.length === 0) { + notify('Ny epostliste', 'Ingen eposter i epost-feltet...', 'error'); + return; + } + // Valid form + var prefix = $('.new-list .prefix-select .active').attr('data-value'); + var source = prefix + new_list_name + "@" + email_domain.name; + + var new_aliases = {}; + new_aliases = _.map(emails, function(el) { + return { + 'source': source, + 'destination': el, + 'domain': email_domain.id + }; + }); + console.log(new_aliases); + $.ajax({ + url: api_urls.aliases, + type: 'POST', + headers: {'X-CSRFToken': csrf_token}, + dataType: 'json', + contentType: "application/json; charset=utf-8", + data: JSON.stringify(new_aliases), + + }).done(function(resp) { + console.log(resp); + notify('Lagt til', 'Ny liste: ' + source + ' lagt til', 'success'); $('.new-list textarea').val(''); $('.new-list .js-new-list-name').val(''); - }, - 'json' - ); - var added_list_html = nunjucks.render('list.html', { lists: new_list }); - forwards_container.prepend(added_list_html); + // FIXME: Existing list? + var added_list_html = nunjucks.render('list.html', { lists: new_aliases }); + forwards_container.prepend(added_list_html); + }); - }); + }); - /* Filter lists by orgunit */ - $(".orgunit-list a").on('click', function(e) { - var prefix = $(this).attr('data-prefix'); - e.preventDefault(); + /* Filter lists by orgunit */ + $(".orgunit-list a").on('click', function(e) { + var prefix = $(this).attr('data-prefix'); + e.preventDefault(); - /* Toggle selection */ - $(".orgunit-list li").removeClass('active'); - $(this).parent().toggleClass('active'); - $('.orgunits-select').val(prefix); + /* Toggle selection */ + $(".orgunit-list li").removeClass('active'); + $(this).parent().toggleClass('active'); + $('.orgunits-select').val(prefix); - filter_lists('^'+prefix+'-', true); - $('.js-lists-filter-field').val(''); - }); - $(".orgunits-select").on('change', function() { - var prefix = $(this).val(); + filter_lists('^'+prefix+'-', true); + $('.js-lists-filter-field').val(''); + }); + $(".orgunits-select").on('change', function() { + var prefix = $(this).val(); - /* Toggle selection */ - $(".orgunit-list li").removeClass('active'); - $(".orgunit-list li a[data-prefix="+prefix+"]").parent().toggleClass('active'); + /* Toggle selection */ + $(".orgunit-list li").removeClass('active'); + $(".orgunit-list li a[data-prefix="+prefix+"]").parent().toggleClass('active'); - filter_lists('^'+prefix+'-', true); - $('.js-lists-filter-field').val(''); + filter_lists('^'+prefix+'-', true); + $('.js-lists-filter-field').val(''); + }); }); }); diff --git a/mailadmin/static/dist/scripts/templates.js b/mailadmin/static/dist/scripts/templates.js index e29dc63..5625085 100644 --- a/mailadmin/static/dist/scripts/templates.js +++ b/mailadmin/static/dist/scripts/templates.js @@ -205,7 +205,9 @@ output += "-\n\t\t\t"; } } frame = frame.pop(); -output += "\n\t\t\t\n\t\t\n\t\t\n\t\t@studentersamfundet.no\n\t\n \t

Eposter

\n \n \n \n"; +output += "\n\t\t\t\n\t\t\n\t\t\n\t\t@"; +output += runtime.suppressValue(runtime.memberLookup((runtime.contextOrFrameLookup(context, frame, "email_domain")),"name", env.autoesc), env.autoesc); +output += "\n\t\n \t

Eposter

\n \n \n \n"; cb(null, output); ; } catch (e) { diff --git a/mailadmin/urls.py b/mailadmin/urls.py index 29d40d8..74b0a2d 100644 --- a/mailadmin/urls.py +++ b/mailadmin/urls.py @@ -1,7 +1,7 @@ from django.conf.urls import patterns, url from rest_framework.routers import DefaultRouter -from mailadmin.views import MyUserViewSet, MyOrgUnitViewSet, OrgUnitViewSet, AliasesView +from mailadmin.views import MyUserViewSet, MyOrgUnitViewSet, OrgUnitViewSet, AliasesView, get_domain router = DefaultRouter() router.register(r'me', MyUserViewSet, base_name='me') @@ -12,4 +12,5 @@ urlpatterns = router.urls urlpatterns += patterns( '', url(r'^aliases/$', AliasesView.as_view(), name='aliases'), + url(r'^emaildomain/$', get_domain, name='email-domain'), ) diff --git a/mailadmin/views.py b/mailadmin/views.py index 1d5dd80..4fa0137 100644 --- a/mailadmin/views.py +++ b/mailadmin/views.py @@ -1,3 +1,4 @@ +from django.conf import settings from django.contrib.auth import login, logout as auth_logout from django.contrib.auth.decorators import login_required from django.contrib.auth.forms import AuthenticationForm @@ -6,6 +7,7 @@ from django.shortcuts import render, redirect import logging from requests import exceptions from rest_framework import viewsets, views +from rest_framework.decorators import api_view from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from rest_framework import status @@ -46,7 +48,7 @@ def logout(request): class AliasesView(views.APIView): - """ List, create and delete aliases from mxapi """ + """ List, create and delete aliases from django-postfix-dovecot-api """ _api = DjangoPostfixDovecotAPI() permission_classes = (SourcePrefixOwner,) @@ -73,30 +75,32 @@ class AliasesView(views.APIView): if len(my_prefixes) == 0: return Response({'result': 'No results'}) # Need at least one - try: - res = self._api.list_aliases_regex(regexp) - except exceptions.RequestException as e: - logger.warning('mxapi errored {}'.format(e.strerror)) - return Response({'error': e.strerror}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + res = self._api.list_aliases_regex(regexp) return Response(res) def post(self, request): - aliases = AliasSerializer(data=request.DATA, many=True) + aliases = AliasSerializer(data=request.data, many=True) if not aliases.is_valid(): return Response(aliases.errors, status=status.HTTP_400_BAD_REQUEST) res = self._api.create_aliases(aliases.data) + return Response(res) def delete(self, request): - aliases = AliasSerializer(data=request.DATA, many=True) + aliases = AliasSerializer(data=request.data, many=True) if not aliases.is_valid(): return Response(aliases.errors, status=status.HTTP_400_BAD_REQUEST) - # FIXME: not tested - # res = self._api.delete_aliases(aliases) - res = {'errors': 'Not implemented'} + try: + # FIXME: not tested + # res = self._api.delete_aliases(aliases) + res = {'errors': 'Not implemented'} + except exceptions.RequestException as e: + logger.warning('mxapi errored {}'.format(e.strerror)) + return Response({'error': e.strerror}, status=status.HTTP_400_BAD_REQUEST) + return Response(res) @@ -127,3 +131,14 @@ class OrgUnitViewSet(viewsets.ReadOnlyModelViewSet): queryset = OrgUnit.objects.all() serializer_class = OrgUnitSerializer permission_classes = [IsAuthenticated] + + +@api_view(['GET']) +def get_domain(request): + api = DjangoPostfixDovecotAPI() + domains = api.list_domains(name=settings.NEUF_EMAIL_DOMAIN_NAME) + + if len(domains) != 1: + return Response({'domain': domains}) + + return Response({'domain': domains[0]}) \ No newline at end of file