diff --git a/mailadmin/api.py b/mailadmin/api.py index 0a4d550..b084073 100644 --- a/mailadmin/api.py +++ b/mailadmin/api.py @@ -1,8 +1,10 @@ import requests from django.conf import settings import logging +from requests.exceptions import ConnectionError +from requests.auth import HTTPBasicAuth from rest_framework import exceptions - +from rest_framework import status logger = logging.getLogger(__name__) @@ -31,21 +33,34 @@ class DjangoPostfixDovecotAPI(object): headers = {'content-type': 'application/json'} url = "{}{}".format(self.base_url, path) - r = requests.request( - method, - url, - params=params, - auth=requests.auth.HTTPBasicAuth(self.username, self.password), - json=json, - headers=headers) + try: + r = requests.request( + method, + url, + params=params, + auth=HTTPBasicAuth(self.username, self.password), + json=json, + headers=headers) + except ConnectionError as e: + msg = 'mxapi at {} unavailable {}'.format(url, unicode(e)) + logger.warning(msg) + raise DPDAPIException(status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail={'error': msg}) 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()) + try: + raise DPDAPIException(status_code=e.response.status_code, detail=e.response.json()) + except ValueError: + raise DPDAPIException(status_code=e.response.status_code, detail='mxapi fatal error') - return r.json() + try: + ret = r.json() + except ValueError: + return None + + return ret def create_aliases(self, aliases): return self._api('POST', '/aliases/create_bulk/', json=aliases) diff --git a/mailadmin/static/app/scripts/main.js b/mailadmin/static/app/scripts/main.js index f514bce..c173f28 100644 --- a/mailadmin/static/app/scripts/main.js +++ b/mailadmin/static/app/scripts/main.js @@ -1,6 +1,14 @@ (function() { 'use strict'; /*global moment, jQuery, document, _, $, window, List */ + var api_urls = { + aliases: '/api/aliases/', + ou_list: '/api/orgunits/', + me: '/api/me/', + email_domain: '/api/emaildomain/' + }; + var csrf_token; + function getParameterByName(name) { name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]'); var regex = new RegExp('[\\?&]' + name + '=([^&#]*)'), @@ -37,7 +45,7 @@ /* Filter lists */ var re_term = new RegExp(term); - $(".fwdlist").each(function() { + $(".fwdlist").not('.new-list').each(function() { var cur_name = $(this).attr('data-list-name'); var members = $(this).find('.member'); var hits = _.filter(members, function(el) { @@ -61,15 +69,32 @@ animate_speed: 'fast' }); } + function update_num_emails(event) { + var el = $(event.target); + var emails = parseEmails(el.val()); + var list_name = el.attr('data-list-name'); + var counter = $('.fwdlist[data-list-name="'+ list_name +'"] .email-counter'); + + if(emails.length > 0) { + counter.text(emails.length); + } else { + counter.text(''); + } + } + function create_aliases(new_aliases, onSuccess) { + $.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), + success: onSuccess + }); + } $(document).ready(function() { - var csrf_token = $('meta[name=x-csrf-token]').attr('content'); - var api_urls = { - aliases: '/api/aliases/', - ou_list: '/api/orgunits/', - me: '/api/me/', - email_domain: '/api/emaildomain/' - }; + csrf_token = $('meta[name=x-csrf-token]').attr('content'); var forwards_container = $(".forwards-container"); nunjucks.configure({ autoescape: true }); @@ -90,7 +115,6 @@ $.getJSON(api_urls.email_domain, function(email_domain) { email_domain = email_domain.domain; - console.log(email_domain); /* New list */ var new_list_html = nunjucks.render('new_list.html', { @@ -118,17 +142,8 @@ 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); + $('.new-list textarea').on('keyup', update_num_emails); - 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 */ @@ -155,25 +170,16 @@ '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'); + + create_aliases(new_aliases, function(forwards) { + notify('Lagt til', 'Ny liste: ' + forwards[0].source + ' lagt til', 'success'); $('.new-list textarea').val(''); $('.new-list .js-new-list-name').val(''); - // FIXME: Existing list? - var added_list_html = nunjucks.render('list.html', { lists: new_aliases }); - forwards_container.prepend(added_list_html); + // TODO: Existing list? + //var new_list =_.groupBy(forwards, function(fwd) { return fwd.source; }); + //var added_list_html = nunjucks.render('list.html', { lists: new_list }); + //forwards_container.prepend(added_list_html); }); - }); /* Filter lists by orgunit */ @@ -256,22 +262,36 @@ /* Delete selected */ forwards_container.on('click', '.js-del-selected', function() { var list_name = $(this).attr('data-delete-list-name'); - var checked = $('[data-list-name="'+list_name+'"] [name="fwd-delete"]:checked'); + var list_el = $('.fwdlist[data-list-name="'+list_name+'"]'); + var checked = list_el.find('[name="fwd-delete"]:checked'); + var delete_these = _.map(checked, function(el) { - return $(el).val(); + return { + 'source': $(el).attr('data-source'), + 'destination': $(el).attr('data-destination'), + 'domain': parseInt($(el).attr('data-domain'), 10), + }; }); + function success(res){ + checked.closest('tr').remove(); + /* remove list if no more rows */ + if(list_el.find('.alias-row').length === 0) { + list_el.remove(); + } + } + function error(res) { + notify('Kunne ikke slette', res.detail, 'error'); + } var data = { type: 'DELETE', headers: {'X-CSRFToken': csrf_token}, url: api_urls.aliases, - data: delete_these, - dataType: 'json' + data: JSON.stringify(delete_these), + contentType: "application/json; charset=utf-8", + success: success, + error: error }; - $.ajax(data, function(){ - // Success - checked.closest('tr').remove(); - // TODO remove list if no more rows - }); + $.ajax(data); }); /* Toggles emails textarea */ @@ -284,8 +304,35 @@ /* Add emails to current list */ forwards_container.on('click', '.js-new-email', function(e) { e.preventDefault(); - // TODO refactor logic from new list and add here + var source = $(this).attr('data-list-name'); + var textarea = $('textarea[data-list-name="'+source+'"]'); + var emails = parseEmails(textarea.val()); + if(emails.length === 0) { + notify('Ny epostliste', 'Ingen eposter i epost-feltet...', 'error'); + return; + } + var list_el = $('.fwdlist[data-list-name="'+source+'"]'); + var new_aliases = {}; + new_aliases = _.map(emails, function(el) { + return { + 'source': source, + 'destination': el, + 'domain': parseInt(list_el.attr('data-domain'), 10) + }; + }); + + create_aliases(new_aliases, function(forwards) { + var aliases_formatted = _.map(forwards, function(el) { return el.destination; }).join(', '); + notify('Oppdatert '+ forwards[0].source, 'La til epostene: ' + aliases_formatted + '.', 'success'); + textarea.val(''); + list_el.find('.email-counter').text(''); + // TODO: Update the list. + //var new_list =_.groupBy(forwards, function(fwd) { return fwd.source; }); + //var added_list_html = nunjucks.render('list.html', { lists: new_list }); + //forwards_container.prepend(added_list_html); + }); }); + forwards_container.on('keyup', '.js-add-list-textarea', update_num_emails); /* New list toggle display */ $('.new-list-btn').on('click', function() { diff --git a/mailadmin/static/app/styles/main.scss b/mailadmin/static/app/styles/main.scss index 84894d9..1b66acc 100644 --- a/mailadmin/static/app/styles/main.scss +++ b/mailadmin/static/app/styles/main.scss @@ -73,7 +73,7 @@ $icon-font-path: "../fonts/"; padding-left: 16px; padding-right: 16px; } -.forwards-container .badge { +.forwards-container .badge-list-total { float: right; margin-right: 14px; } diff --git a/mailadmin/static/app/templates/list.html b/mailadmin/static/app/templates/list.html index ed8157c..def5631 100644 --- a/mailadmin/static/app/templates/list.html +++ b/mailadmin/static/app/templates/list.html @@ -1,26 +1,33 @@ {% for list,aliases in lists %} -
+
-
{{ list }} {{aliases|length}}
+
{{ list }} {{aliases|length}}
- {% for member in aliases %} - - {% endfor %} + + {% for alias in aliases %} + + + + + {% endfor %} + - - + + - +
{{ member.destination }}
{{ alias.destination }} + +
- Legg til - - Slett - + Legg til + + Slett +
-

Eposter

- - -
+

Eposter

+ + +
diff --git a/mailadmin/static/app/templates/new_list.html b/mailadmin/static/app/templates/new_list.html index eb104c0..451fe6f 100644 --- a/mailadmin/static/app/templates/new_list.html +++ b/mailadmin/static/app/templates/new_list.html @@ -14,7 +14,7 @@ @{{email_domain.name}}

Eposter

- +
\ No newline at end of file diff --git a/mailadmin/static/dist/scripts/main.js b/mailadmin/static/dist/scripts/main.js index f514bce..c173f28 100644 --- a/mailadmin/static/dist/scripts/main.js +++ b/mailadmin/static/dist/scripts/main.js @@ -1,6 +1,14 @@ (function() { 'use strict'; /*global moment, jQuery, document, _, $, window, List */ + var api_urls = { + aliases: '/api/aliases/', + ou_list: '/api/orgunits/', + me: '/api/me/', + email_domain: '/api/emaildomain/' + }; + var csrf_token; + function getParameterByName(name) { name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]'); var regex = new RegExp('[\\?&]' + name + '=([^&#]*)'), @@ -37,7 +45,7 @@ /* Filter lists */ var re_term = new RegExp(term); - $(".fwdlist").each(function() { + $(".fwdlist").not('.new-list').each(function() { var cur_name = $(this).attr('data-list-name'); var members = $(this).find('.member'); var hits = _.filter(members, function(el) { @@ -61,15 +69,32 @@ animate_speed: 'fast' }); } + function update_num_emails(event) { + var el = $(event.target); + var emails = parseEmails(el.val()); + var list_name = el.attr('data-list-name'); + var counter = $('.fwdlist[data-list-name="'+ list_name +'"] .email-counter'); + + if(emails.length > 0) { + counter.text(emails.length); + } else { + counter.text(''); + } + } + function create_aliases(new_aliases, onSuccess) { + $.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), + success: onSuccess + }); + } $(document).ready(function() { - var csrf_token = $('meta[name=x-csrf-token]').attr('content'); - var api_urls = { - aliases: '/api/aliases/', - ou_list: '/api/orgunits/', - me: '/api/me/', - email_domain: '/api/emaildomain/' - }; + csrf_token = $('meta[name=x-csrf-token]').attr('content'); var forwards_container = $(".forwards-container"); nunjucks.configure({ autoescape: true }); @@ -90,7 +115,6 @@ $.getJSON(api_urls.email_domain, function(email_domain) { email_domain = email_domain.domain; - console.log(email_domain); /* New list */ var new_list_html = nunjucks.render('new_list.html', { @@ -118,17 +142,8 @@ 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); + $('.new-list textarea').on('keyup', update_num_emails); - 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 */ @@ -155,25 +170,16 @@ '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'); + + create_aliases(new_aliases, function(forwards) { + notify('Lagt til', 'Ny liste: ' + forwards[0].source + ' lagt til', 'success'); $('.new-list textarea').val(''); $('.new-list .js-new-list-name').val(''); - // FIXME: Existing list? - var added_list_html = nunjucks.render('list.html', { lists: new_aliases }); - forwards_container.prepend(added_list_html); + // TODO: Existing list? + //var new_list =_.groupBy(forwards, function(fwd) { return fwd.source; }); + //var added_list_html = nunjucks.render('list.html', { lists: new_list }); + //forwards_container.prepend(added_list_html); }); - }); /* Filter lists by orgunit */ @@ -256,22 +262,36 @@ /* Delete selected */ forwards_container.on('click', '.js-del-selected', function() { var list_name = $(this).attr('data-delete-list-name'); - var checked = $('[data-list-name="'+list_name+'"] [name="fwd-delete"]:checked'); + var list_el = $('.fwdlist[data-list-name="'+list_name+'"]'); + var checked = list_el.find('[name="fwd-delete"]:checked'); + var delete_these = _.map(checked, function(el) { - return $(el).val(); + return { + 'source': $(el).attr('data-source'), + 'destination': $(el).attr('data-destination'), + 'domain': parseInt($(el).attr('data-domain'), 10), + }; }); + function success(res){ + checked.closest('tr').remove(); + /* remove list if no more rows */ + if(list_el.find('.alias-row').length === 0) { + list_el.remove(); + } + } + function error(res) { + notify('Kunne ikke slette', res.detail, 'error'); + } var data = { type: 'DELETE', headers: {'X-CSRFToken': csrf_token}, url: api_urls.aliases, - data: delete_these, - dataType: 'json' + data: JSON.stringify(delete_these), + contentType: "application/json; charset=utf-8", + success: success, + error: error }; - $.ajax(data, function(){ - // Success - checked.closest('tr').remove(); - // TODO remove list if no more rows - }); + $.ajax(data); }); /* Toggles emails textarea */ @@ -284,8 +304,35 @@ /* Add emails to current list */ forwards_container.on('click', '.js-new-email', function(e) { e.preventDefault(); - // TODO refactor logic from new list and add here + var source = $(this).attr('data-list-name'); + var textarea = $('textarea[data-list-name="'+source+'"]'); + var emails = parseEmails(textarea.val()); + if(emails.length === 0) { + notify('Ny epostliste', 'Ingen eposter i epost-feltet...', 'error'); + return; + } + var list_el = $('.fwdlist[data-list-name="'+source+'"]'); + var new_aliases = {}; + new_aliases = _.map(emails, function(el) { + return { + 'source': source, + 'destination': el, + 'domain': parseInt(list_el.attr('data-domain'), 10) + }; + }); + + create_aliases(new_aliases, function(forwards) { + var aliases_formatted = _.map(forwards, function(el) { return el.destination; }).join(', '); + notify('Oppdatert '+ forwards[0].source, 'La til epostene: ' + aliases_formatted + '.', 'success'); + textarea.val(''); + list_el.find('.email-counter').text(''); + // TODO: Update the list. + //var new_list =_.groupBy(forwards, function(fwd) { return fwd.source; }); + //var added_list_html = nunjucks.render('list.html', { lists: new_list }); + //forwards_container.prepend(added_list_html); + }); }); + forwards_container.on('keyup', '.js-add-list-textarea', update_num_emails); /* New list toggle display */ $('.new-list-btn').on('click', function() { diff --git a/mailadmin/static/dist/scripts/templates.js b/mailadmin/static/dist/scripts/templates.js index 5625085..b8f25d4 100644 --- a/mailadmin/static/dist/scripts/templates.js +++ b/mailadmin/static/dist/scripts/templates.js @@ -50,17 +50,19 @@ frame.set("loop.last", t_1 === t_2 - 1); frame.set("loop.length", t_2); output += "\n
\n\t
\n\t
"; output += runtime.suppressValue(t_4, env.autoesc); -output += " "; +output += " "; output += runtime.suppressValue(env.getFilter("length").call(context, t_5), env.autoesc); -output += "
\n\t\t\n\t \n\t\t\t"; +output += "\n\t\t
\n\t \n\t \t\n\t\t\t\t"; frame = frame.push(); var t_8 = t_5; if(t_8) {var t_7 = t_8.length; for(var t_6=0; t_6 < t_8.length; t_6++) { var t_9 = t_8[t_6]; -frame.set("member", t_9); +frame.set("alias", t_9); frame.set("loop.index", t_6 + 1); frame.set("loop.index0", t_6); frame.set("loop.revindex", t_7 - t_6); @@ -68,30 +70,32 @@ frame.set("loop.revindex0", t_7 - t_6 - 1); frame.set("loop.first", t_6 === 0); frame.set("loop.last", t_6 === t_7 - 1); frame.set("loop.length", t_7); -output += "\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t"; +output += "\" data-domain=\""; +output += runtime.suppressValue(runtime.memberLookup((t_9),"domain", env.autoesc), env.autoesc); +output += "\"/>\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t"; ; } } frame = frame.pop(); -output += "\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n \t\t\t\n\t\t\t\n\t\t
"; -output += runtime.suppressValue(runtime.memberLookup((t_9),"destination", env.autoesc), env.autoesc); -output += ""; output += runtime.suppressValue(runtime.memberLookup((t_9),"destination", env.autoesc), env.autoesc); +output += "\n\t\t\t\t\t\t
\n\t\t\t\t\t Legg til\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t Legg til\n\t\t\t\t\t\n\t\t\t\t\t\t Slett\n\t\t\t\t
\n\t\t\t\t\t

Eposter

\n \t\t\t\t\n \t\t\t\t\n \t\t\t
\n\t\t
\n\t
\n
\n"; +output += "\" placeholder=\"asdf@studentersamfundet.no, qwerty@studentersamfundet.no f.eks. Klipp og lim så mye du orker\" rows=\"4\">\n\t \t\t\t\t\n\t \t\t\t\n \t\t\t\n\t\t\t\n\t\t\n\t\t
\n\t\n\n"; ; } } else { @@ -111,17 +115,19 @@ frame.set("loop.last", t_1 === t_2 - 1); frame.set("loop.length", t_2); output += "\n
\n\t
\n\t
"; output += runtime.suppressValue(t_10, env.autoesc); -output += " "; +output += " "; output += runtime.suppressValue(env.getFilter("length").call(context, t_11), env.autoesc); -output += "
\n\t\t\n\t \n\t\t\t"; +output += "\n\t\t
\n\t \n\t \t\n\t\t\t\t"; frame = frame.push(); var t_14 = t_11; if(t_14) {var t_13 = t_14.length; for(var t_12=0; t_12 < t_14.length; t_12++) { var t_15 = t_14[t_12]; -frame.set("member", t_15); +frame.set("alias", t_15); frame.set("loop.index", t_12 + 1); frame.set("loop.index0", t_12); frame.set("loop.revindex", t_13 - t_12); @@ -129,30 +135,32 @@ frame.set("loop.revindex0", t_13 - t_12 - 1); frame.set("loop.first", t_12 === 0); frame.set("loop.last", t_12 === t_13 - 1); frame.set("loop.length", t_13); -output += "\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t"; +output += "\" data-domain=\""; +output += runtime.suppressValue(runtime.memberLookup((t_15),"domain", env.autoesc), env.autoesc); +output += "\"/>\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t"; ; } } frame = frame.pop(); -output += "\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n \t\t\t\n\t\t\t\n\t\t
"; -output += runtime.suppressValue(runtime.memberLookup((t_15),"destination", env.autoesc), env.autoesc); -output += ""; output += runtime.suppressValue(runtime.memberLookup((t_15),"destination", env.autoesc), env.autoesc); +output += "\n\t\t\t\t\t\t
\n\t\t\t\t\t Legg til\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t Legg til\n\t\t\t\t\t\n\t\t\t\t\t\t Slett\n\t\t\t\t
\n\t\t\t\t\t

Eposter

\n \t\t\t\t\n \t\t\t\t\n \t\t\t
\n\t\t
\n\t
\n
\n"; +output += "\" placeholder=\"asdf@studentersamfundet.no, qwerty@studentersamfundet.no f.eks. Klipp og lim så mye du orker\" rows=\"4\">\n\t \t\t\t\t\n\t \t\t\t\n \t\t\t\n\t\t\t\n\t\t\n\t\t
\n\t\n\n"; ; } } @@ -207,7 +215,7 @@ output += "-\n\t\t\t"; frame = frame.pop(); 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"; +output += "\n\t\n \t

Eposter

\n \n \n \n"; cb(null, output); ; } catch (e) { diff --git a/mailadmin/static/dist/styles/main.css b/mailadmin/static/dist/styles/main.css index 4c8595e..9bebebd 100644 --- a/mailadmin/static/dist/styles/main.css +++ b/mailadmin/static/dist/styles/main.css @@ -6677,7 +6677,7 @@ html > body > .ui-pnotify { padding-right: 16px; } -.forwards-container .badge { +.forwards-container .badge-list-total { float: right; margin-right: 14px; } diff --git a/mailadmin/templates/lists.html b/mailadmin/templates/lists.html index 98bd429..8c82db7 100644 --- a/mailadmin/templates/lists.html +++ b/mailadmin/templates/lists.html @@ -13,7 +13,7 @@
-
+
Laster...
diff --git a/mailadmin/views.py b/mailadmin/views.py index 4fa0137..e9b744b 100644 --- a/mailadmin/views.py +++ b/mailadmin/views.py @@ -93,13 +93,7 @@ class AliasesView(views.APIView): if not aliases.is_valid(): return Response(aliases.errors, status=status.HTTP_400_BAD_REQUEST) - 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) + res = self._api.delete_aliases(aliases.data) return Response(res)