Replace everything cpanl with django-postfix-dovecot-api
This commit is contained in:
1 parent
99b296aaea
commit
47c033b274
13 files changed
+209
-204
No files matched your search
Vendored
+63
@@ -0,0 +1,63 @@
|
||||
import logging
|
||||
import sys
|
||||
|
||||
from contextlib import contextmanager as _contextmanager
|
||||
from fabric.api import run, sudo, env, cd, prefix, lcd
|
||||
from fabric.api import local as lrun
|
||||
|
||||
env.use_ssh_config = True
|
||||
env.hosts = ['dreamcast.neuf.no']
|
||||
env.project_path = '/var/www/neuf.no/mailadmin'
|
||||
env.user = 'gitdeploy'
|
||||
env.activate = 'source {}/venv/bin/activate'.format(env.project_path)
|
||||
|
||||
|
||||
@_contextmanager
|
||||
def virtualenv():
|
||||
with cd(env.project_path):
|
||||
with prefix(env.activate):
|
||||
yield
|
||||
|
||||
|
||||
def __git_validate_clean():
|
||||
with lcd(env.project_path):
|
||||
if lrun('git diff-files', capture=True) != '':
|
||||
logging.error("Your git-tree isn't clean! Commit your changes before deploying.")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def test():
|
||||
lrun("python manage.py test dpdapi")
|
||||
|
||||
|
||||
def commit():
|
||||
lrun("git add -p && git commit")
|
||||
|
||||
|
||||
def push():
|
||||
lrun("git push")
|
||||
|
||||
|
||||
def prepare_deploy():
|
||||
test()
|
||||
commit()
|
||||
push()
|
||||
|
||||
|
||||
def gitstatus():
|
||||
# __git_validate_clean()
|
||||
with virtualenv():
|
||||
# Get source
|
||||
run('git branch -v')
|
||||
|
||||
|
||||
def deploy():
|
||||
# __git_validate_clean()
|
||||
with virtualenv():
|
||||
run('git pull') # Get source
|
||||
run('pip install -r requirements.txt') # install deps in virtualenv
|
||||
run('python manage.py collectstatic --noinput') # Collect static
|
||||
run('python manage.py migrate') # Run DB migrations
|
||||
|
||||
# Reload gunicorn
|
||||
sudo('/etc/init.d/gunicorn reload', shell=False)
|
||||
+34
-20
@@ -2,33 +2,47 @@ import requests
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
class CPanel(object):
|
||||
class DjangoPostfixDovecotAPI(object):
|
||||
"""
|
||||
CPanel API
|
||||
django-postfix-dovecot-api
|
||||
|
||||
https://git.neuf.no/edb/django-postfix-dovecot-api#tab-readme
|
||||
|
||||
https://documentation.cpanel.net/display/SDK/cPanel+API+2+-+Email
|
||||
https://documentation.cpanel.net/display/SDK/cPanel+API+1+-+Email
|
||||
"""
|
||||
def __init__(self, base_url=settings.CP_API_URL, username=settings.CP_API_USERNAME, password=settings.CP_API_PASSWORD):
|
||||
def __init__(self, base_url=settings.DPD_API_URL, username=settings.DPD_API_USERNAME, password=settings.DPD_API_PASSWORD):
|
||||
self.base_url = base_url
|
||||
self.username = username
|
||||
self.password = password
|
||||
|
||||
def api(self, module, function, params=None, version=2):
|
||||
generic = {
|
||||
'cpanel_jsonapi_user': self.username,
|
||||
'cpanel_jsonapi_module': module,
|
||||
'cpanel_jsonapi_func': function,
|
||||
'cpanel_jsonapi_apiversion': version,
|
||||
}
|
||||
if params is not None:
|
||||
params = dict(generic.items() + params.items())
|
||||
|
||||
def _api(self, method, path, params=None, json=None):
|
||||
headers = {'content-type': 'application/json'}
|
||||
r = requests.get(
|
||||
self.base_url,
|
||||
url = "{}{}".format(self.base_url, path)
|
||||
|
||||
r = requests.request(
|
||||
method,
|
||||
url,
|
||||
params=params,
|
||||
headers=headers,
|
||||
auth=requests.auth.HTTPBasicAuth(self.username, self.password),
|
||||
verify=False)
|
||||
return r.json()
|
||||
json=json,
|
||||
headers=headers)
|
||||
|
||||
return r.json()
|
||||
|
||||
def create_aliases(self, aliases):
|
||||
return self._api('POST', '/aliases/create_bulk/', json=aliases)
|
||||
|
||||
def delete_aliases(self, aliases):
|
||||
return self._api('DELETE', '/aliases/delete_bulk/', json=aliases)
|
||||
|
||||
def list_aliases_regex(self, regex):
|
||||
""" Limit aliases by regular expression and domain name """
|
||||
params = {
|
||||
'domain__name': settings.NEUF_EMAIL_DOMAIN_NAME,
|
||||
'source_regex': regex
|
||||
}
|
||||
print params
|
||||
return self._api(
|
||||
'GET',
|
||||
'/aliases/',
|
||||
params=params
|
||||
)
|
||||
@@ -2,33 +2,22 @@ from rest_framework import permissions
|
||||
from mailadmin.models import OrgUnit
|
||||
import re
|
||||
|
||||
from mailadmin.serializers import ForwardSerializer
|
||||
from mailadmin.serializers import AliasSerializer
|
||||
|
||||
|
||||
class IsOwnerOrReadOnly(permissions.BasePermission):
|
||||
"""
|
||||
Custom permission to only allow owners of an object to edit it.
|
||||
"""
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
# Read permissions are allowed to any request,
|
||||
# so we'll always allow GET, HEAD or OPTIONS requests.
|
||||
if request.method in permissions.SAFE_METHODS:
|
||||
return True
|
||||
|
||||
# Write permissions are only allowed to the owner
|
||||
return obj.owner == request.user
|
||||
|
||||
|
||||
class DestinationPrefixOwner(permissions.BasePermission):
|
||||
class SourcePrefixOwner(permissions.BasePermission):
|
||||
# Ref: http://www.django-rest-framework.org/api-guide/permissions
|
||||
# TODO have no idea if this works
|
||||
def has_permission(self, request, view):
|
||||
# Read permissions (GET, HEAD or OPTIONS) are allowed for all authenticated request
|
||||
if request.method in permissions.SAFE_METHODS and request.user and request.user.is_authenticated():
|
||||
return True
|
||||
|
||||
# TODO test handling the DELETE requests
|
||||
if request.user.is_superuser:
|
||||
return True
|
||||
|
||||
if request.method == 'DELETE':
|
||||
if request.method in ['DELETE', 'POST']:
|
||||
print view
|
||||
print view.kwargs
|
||||
forwarder = view.kwargs['forwarder'] # TODO you are here
|
||||
@@ -37,9 +26,9 @@ class DestinationPrefixOwner(permissions.BasePermission):
|
||||
return True
|
||||
|
||||
fwd_data = forwarder.split("=")
|
||||
fw = ForwardSerializer(data={'dest': fwd_data[0], 'forward': fwd_data[1]})
|
||||
fw = AliasSerializer(data={'dest': fwd_data[0], 'forward': fwd_data[1]})
|
||||
else:
|
||||
fw = ForwardSerializer(data=request.DATA)
|
||||
fw = AliasSerializer(data=request.DATA)
|
||||
|
||||
if not fw.is_valid():
|
||||
return True # Skip auth if not valid data
|
||||
|
||||
@@ -27,14 +27,14 @@ class OrgUnitSerializer(serializers.ModelSerializer):
|
||||
model = OrgUnit
|
||||
|
||||
|
||||
class ForwardSerializer(serializers.Serializer):
|
||||
dest = serializers.EmailField(required=True)
|
||||
forward = serializers.EmailField(required=True)
|
||||
_domain = settings.NEUF_EMAIL_DOMAIN
|
||||
class AliasSerializer(serializers.Serializer):
|
||||
source = serializers.EmailField(required=True)
|
||||
destination = serializers.EmailField(required=True)
|
||||
_domain_name = settings.NEUF_EMAIL_DOMAIN_NAME
|
||||
|
||||
def validate_dest(self, attrs, source):
|
||||
def validate_destonation(self, attrs, source):
|
||||
domain_part = attrs[source].split('@')[1]
|
||||
if domain_part != self._domain:
|
||||
raise serializers.ValidationError("dest '{0}' is not in domain {1}".format(attrs[source], self._domain))
|
||||
if domain_part != self._domain_name:
|
||||
raise serializers.ValidationError("dest '{0}' is not in domain {1}".format(attrs[source], self._domain_name))
|
||||
|
||||
return attrs
|
||||
@@ -65,9 +65,7 @@
|
||||
$(document).ready(function() {
|
||||
var csrf_token = $('meta[name=x-csrf-token]').attr('content');
|
||||
var api_urls = {
|
||||
fwd_list: '/api/forwards/',
|
||||
fwd_delete: '/api/forward/',
|
||||
fwd_create: '/api/forward/', // + forwarder
|
||||
aliases: '/api/aliases/',
|
||||
ou_list: '/api/orgunits/',
|
||||
me: '/api/me/'
|
||||
};
|
||||
@@ -150,7 +148,7 @@
|
||||
});
|
||||
|
||||
$.post(
|
||||
api_urls.fwd_create,
|
||||
api_urls.aliases,
|
||||
new_list[dest],
|
||||
function() {
|
||||
notify('Lagt til', 'Ny liste: ' + dest + 'lagt til', 'success');
|
||||
@@ -190,22 +188,24 @@
|
||||
});
|
||||
|
||||
/* Load forwards from API and put on page */
|
||||
$.getJSON(api_urls.fwd_list, function(data) {
|
||||
if( !data.cpanelresult ) {
|
||||
notify("Ingen lister.", 'Fant ingen tilhørende lister', 'info');
|
||||
$.getJSON(api_urls.aliases, function(data) {
|
||||
var err_msg;
|
||||
if( data && data.length === 0 ) {
|
||||
err_msg = 'Fant ingen tilhørende lister';
|
||||
notify("Ingen lister.", err_msg, 'info');
|
||||
forwards_container.html(err_msg);
|
||||
return;
|
||||
}
|
||||
if( 'error' in data.cpanelresult ) {
|
||||
notify('Oops!', 'Klarte ikke hente epostlister fra APIet: '+data.cpanelresult.error, 'error');
|
||||
if( data && 'error' in data ) {
|
||||
err_msg = 'Klarte ikke hente epostlister fra APIet: '+data.error;
|
||||
notify('Oops!', err_msg, 'error');
|
||||
forwards_container.html(err_msg);
|
||||
return;
|
||||
}
|
||||
|
||||
var forwards = data.cpanelresult.data;
|
||||
var lists =_.groupBy(forwards, function(fwd) { return fwd.dest; });
|
||||
var fw_html = nunjucks.render('list.html', {
|
||||
lists: lists,
|
||||
api_urls: api_urls
|
||||
});
|
||||
var forwards = data;
|
||||
var lists =_.groupBy(forwards, function(fwd) { return fwd.source; });
|
||||
var fw_html = nunjucks.render('list.html', { lists: lists });
|
||||
|
||||
forwards_container.html(fw_html);
|
||||
|
||||
@@ -248,7 +248,7 @@
|
||||
var data = {
|
||||
type: 'DELETE',
|
||||
headers: {'X-CSRFToken': csrf_token},
|
||||
url: api_urls.fwd_delete,
|
||||
url: api_urls.aliases,
|
||||
data: delete_these,
|
||||
dataType: 'json'
|
||||
};
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
{% for list,members in lists %}
|
||||
{% for list,aliases in lists %}
|
||||
<div class="fwdlist" data-list-name="{{ list }}">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><span class="glyphicon glyphicon-list-alt icon-faded" aria-hidden="true"></span> {{ list }} <span class="badge">{{members|length}}</span></div>
|
||||
<div class="panel-heading"><span class="glyphicon glyphicon-list-alt icon-faded" aria-hidden="true"></span> {{ list }} <span class="badge">{{aliases|length}}</span></div>
|
||||
<table class="table table-condensed">
|
||||
<tbody>
|
||||
{% for member in members %}
|
||||
<tr><td class="member">{{ member.forward }}</td><td class="del-cell"><label class="del-label" for="{{ member.dest }}={{ member.forward }}"><input id="{{ member.dest }}={{ member.forward }}" type="checkbox" name='fwd-delete' value="{{ member.dest }}={{ member.forward }}"></label></td></tr>
|
||||
{% for member in aliases %}
|
||||
<tr><td class="member">{{ member.destination }}</td><td class="del-cell"><label class="del-label" for="{{ member.source }}={{ member.destination }}"><input id="{{ member.source }}={{ member.destination }}" type="checkbox" name='fwd-delete' value="{{ member.source }}={{ member.destination }}"></label></td></tr>
|
||||
{% endfor %}
|
||||
<tr class="action-row">
|
||||
<td>
|
||||
|
||||
+16
-16
@@ -65,9 +65,7 @@
|
||||
$(document).ready(function() {
|
||||
var csrf_token = $('meta[name=x-csrf-token]').attr('content');
|
||||
var api_urls = {
|
||||
fwd_list: '/api/forwards/',
|
||||
fwd_delete: '/api/forward/',
|
||||
fwd_create: '/api/forward/', // + forwarder
|
||||
aliases: '/api/aliases/',
|
||||
ou_list: '/api/orgunits/',
|
||||
me: '/api/me/'
|
||||
};
|
||||
@@ -150,7 +148,7 @@
|
||||
});
|
||||
|
||||
$.post(
|
||||
api_urls.fwd_create,
|
||||
api_urls.aliases,
|
||||
new_list[dest],
|
||||
function() {
|
||||
notify('Lagt til', 'Ny liste: ' + dest + 'lagt til', 'success');
|
||||
@@ -190,22 +188,24 @@
|
||||
});
|
||||
|
||||
/* Load forwards from API and put on page */
|
||||
$.getJSON(api_urls.fwd_list, function(data) {
|
||||
if( !data.cpanelresult ) {
|
||||
notify("Ingen lister.", 'Fant ingen tilhørende lister', 'info');
|
||||
$.getJSON(api_urls.aliases, function(data) {
|
||||
var err_msg;
|
||||
if( data && data.length === 0 ) {
|
||||
err_msg = 'Fant ingen tilhørende lister';
|
||||
notify("Ingen lister.", err_msg, 'info');
|
||||
forwards_container.html(err_msg);
|
||||
return;
|
||||
}
|
||||
if( 'error' in data.cpanelresult ) {
|
||||
notify('Oops!', 'Klarte ikke hente epostlister fra APIet: '+data.cpanelresult.error, 'error');
|
||||
if( data && 'error' in data ) {
|
||||
err_msg = 'Klarte ikke hente epostlister fra APIet: '+data.error;
|
||||
notify('Oops!', err_msg, 'error');
|
||||
forwards_container.html(err_msg);
|
||||
return;
|
||||
}
|
||||
|
||||
var forwards = data.cpanelresult.data;
|
||||
var lists =_.groupBy(forwards, function(fwd) { return fwd.dest; });
|
||||
var fw_html = nunjucks.render('list.html', {
|
||||
lists: lists,
|
||||
api_urls: api_urls
|
||||
});
|
||||
var forwards = data;
|
||||
var lists =_.groupBy(forwards, function(fwd) { return fwd.source; });
|
||||
var fw_html = nunjucks.render('list.html', { lists: lists });
|
||||
|
||||
forwards_container.html(fw_html);
|
||||
|
||||
@@ -248,7 +248,7 @@
|
||||
var data = {
|
||||
type: 'DELETE',
|
||||
headers: {'X-CSRFToken': csrf_token},
|
||||
url: api_urls.fwd_delete,
|
||||
url: api_urls.aliases,
|
||||
data: delete_these,
|
||||
dataType: 'json'
|
||||
};
|
||||
|
||||
+16
-16
@@ -40,7 +40,7 @@ for(t_1=0; t_1 < t_3.length; t_1++) {
|
||||
var t_4 = t_3[t_1][0]
|
||||
frame.set("list", t_3[t_1][0]);
|
||||
var t_5 = t_3[t_1][1]
|
||||
frame.set("members", t_3[t_1][1]);
|
||||
frame.set("aliases", t_3[t_1][1]);
|
||||
frame.set("loop.index", t_1 + 1);
|
||||
frame.set("loop.index0", t_1);
|
||||
frame.set("loop.revindex", t_2 - t_1);
|
||||
@@ -69,19 +69,19 @@ 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<tr><td class=\"member\">";
|
||||
output += runtime.suppressValue(runtime.memberLookup((t_9),"forward", env.autoesc), env.autoesc);
|
||||
output += runtime.suppressValue(runtime.memberLookup((t_9),"destination", env.autoesc), env.autoesc);
|
||||
output += "</td><td class=\"del-cell\"><label class=\"del-label\" for=\"";
|
||||
output += runtime.suppressValue(runtime.memberLookup((t_9),"dest", env.autoesc), env.autoesc);
|
||||
output += runtime.suppressValue(runtime.memberLookup((t_9),"source", env.autoesc), env.autoesc);
|
||||
output += "=";
|
||||
output += runtime.suppressValue(runtime.memberLookup((t_9),"forward", env.autoesc), env.autoesc);
|
||||
output += runtime.suppressValue(runtime.memberLookup((t_9),"destination", env.autoesc), env.autoesc);
|
||||
output += "\"><input id=\"";
|
||||
output += runtime.suppressValue(runtime.memberLookup((t_9),"dest", env.autoesc), env.autoesc);
|
||||
output += runtime.suppressValue(runtime.memberLookup((t_9),"source", env.autoesc), env.autoesc);
|
||||
output += "=";
|
||||
output += runtime.suppressValue(runtime.memberLookup((t_9),"forward", env.autoesc), env.autoesc);
|
||||
output += runtime.suppressValue(runtime.memberLookup((t_9),"destination", env.autoesc), env.autoesc);
|
||||
output += "\" type=\"checkbox\" name='fwd-delete' value=\"";
|
||||
output += runtime.suppressValue(runtime.memberLookup((t_9),"dest", env.autoesc), env.autoesc);
|
||||
output += runtime.suppressValue(runtime.memberLookup((t_9),"source", env.autoesc), env.autoesc);
|
||||
output += "=";
|
||||
output += runtime.suppressValue(runtime.memberLookup((t_9),"forward", env.autoesc), env.autoesc);
|
||||
output += runtime.suppressValue(runtime.memberLookup((t_9),"destination", env.autoesc), env.autoesc);
|
||||
output += "\"></label></td></tr>\n\t\t\t";
|
||||
;
|
||||
}
|
||||
@@ -101,7 +101,7 @@ for(var t_10 in t_3) {
|
||||
t_1++;
|
||||
var t_11 = t_3[t_10];
|
||||
frame.set("list", t_10);
|
||||
frame.set("members", t_11);
|
||||
frame.set("aliases", t_11);
|
||||
frame.set("loop.index", t_1 + 1);
|
||||
frame.set("loop.index0", t_1);
|
||||
frame.set("loop.revindex", t_2 - t_1);
|
||||
@@ -130,19 +130,19 @@ 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<tr><td class=\"member\">";
|
||||
output += runtime.suppressValue(runtime.memberLookup((t_15),"forward", env.autoesc), env.autoesc);
|
||||
output += runtime.suppressValue(runtime.memberLookup((t_15),"destination", env.autoesc), env.autoesc);
|
||||
output += "</td><td class=\"del-cell\"><label class=\"del-label\" for=\"";
|
||||
output += runtime.suppressValue(runtime.memberLookup((t_15),"dest", env.autoesc), env.autoesc);
|
||||
output += runtime.suppressValue(runtime.memberLookup((t_15),"source", env.autoesc), env.autoesc);
|
||||
output += "=";
|
||||
output += runtime.suppressValue(runtime.memberLookup((t_15),"forward", env.autoesc), env.autoesc);
|
||||
output += runtime.suppressValue(runtime.memberLookup((t_15),"destination", env.autoesc), env.autoesc);
|
||||
output += "\"><input id=\"";
|
||||
output += runtime.suppressValue(runtime.memberLookup((t_15),"dest", env.autoesc), env.autoesc);
|
||||
output += runtime.suppressValue(runtime.memberLookup((t_15),"source", env.autoesc), env.autoesc);
|
||||
output += "=";
|
||||
output += runtime.suppressValue(runtime.memberLookup((t_15),"forward", env.autoesc), env.autoesc);
|
||||
output += runtime.suppressValue(runtime.memberLookup((t_15),"destination", env.autoesc), env.autoesc);
|
||||
output += "\" type=\"checkbox\" name='fwd-delete' value=\"";
|
||||
output += runtime.suppressValue(runtime.memberLookup((t_15),"dest", env.autoesc), env.autoesc);
|
||||
output += runtime.suppressValue(runtime.memberLookup((t_15),"source", env.autoesc), env.autoesc);
|
||||
output += "=";
|
||||
output += runtime.suppressValue(runtime.memberLookup((t_15),"forward", env.autoesc), env.autoesc);
|
||||
output += runtime.suppressValue(runtime.memberLookup((t_15),"destination", env.autoesc), env.autoesc);
|
||||
output += "\"></label></td></tr>\n\t\t\t";
|
||||
;
|
||||
}
|
||||
|
||||
+8
-31
@@ -1,5 +1,5 @@
|
||||
from django.test import TestCase
|
||||
from mailadmin.api import CPanel
|
||||
from mailadmin.api import DjangoPostfixDovecotAPI
|
||||
import unittest
|
||||
|
||||
|
||||
@@ -7,41 +7,18 @@ class APITest(TestCase):
|
||||
|
||||
@unittest.skip("Not now")
|
||||
def test_listforwards(self):
|
||||
server = CPanel()
|
||||
_api = DjangoPostfixDovecotAPI()
|
||||
params = dict(
|
||||
domain='studentersamfundet.no',
|
||||
regex='kak-*'
|
||||
regex='^kak-*'
|
||||
)
|
||||
res = server.api('Email', 'listforwards', params)
|
||||
self.assertIsInstance(res, dict)
|
||||
self.assertIn('cpanelresult', res)
|
||||
self.assertEqual(True, True)
|
||||
|
||||
@unittest.skip("Not now")
|
||||
def test_addforward(self):
|
||||
server = CPanel()
|
||||
params = dict(
|
||||
domain='studentersamfundet.no',
|
||||
email='test.testesen',
|
||||
fwdopt='fwd',
|
||||
fwdemail='nikolaik@gmail.com'
|
||||
)
|
||||
res = server.api('Email', 'addforward', params)
|
||||
self.assertIsInstance(res, dict)
|
||||
self.assertIn('cpanelresult', res)
|
||||
cp_res = res['cpanelresult']
|
||||
self.assertIn('event', cp_res)
|
||||
self.assertIn('result', cp_res['event'])
|
||||
self.assertEqual(cp_res['event']['result'], 1)
|
||||
_api = DjangoPostfixDovecotAPI()
|
||||
self.assertEqual(True, True)
|
||||
|
||||
@unittest.skip("Not now")
|
||||
def test_delforward(self):
|
||||
server = CPanel()
|
||||
params = {
|
||||
'arg-0': 'kak-lol@studentersamfundet.no=nikolaik@gmail.com',
|
||||
}
|
||||
res = server.api('Email', 'delforward', params, version=1)
|
||||
# FIXME: Does not work!
|
||||
self.assertIsInstance(res, dict)
|
||||
self.assertIn('event', res)
|
||||
self.assertIn('result', res['event'])
|
||||
self.assertEqual(res['event']['result'], 1)
|
||||
_api = DjangoPostfixDovecotAPI()
|
||||
self.assertEqual(True, True)
|
||||
+2
-4
@@ -1,10 +1,9 @@
|
||||
from django.conf.urls import patterns, url
|
||||
from rest_framework.routers import DefaultRouter
|
||||
|
||||
from mailadmin.views import ForwardsViewSet, MyUserViewSet, MyOrgUnitViewSet, OrgUnitViewSet, ForwardCreateView, ForwardDeleteView
|
||||
from mailadmin.views import MyUserViewSet, MyOrgUnitViewSet, OrgUnitViewSet, AliasesView
|
||||
|
||||
router = DefaultRouter()
|
||||
router.register(r'forwards', ForwardsViewSet, base_name='all')
|
||||
router.register(r'me', MyUserViewSet, base_name='me')
|
||||
router.register(r'orgunits', MyOrgUnitViewSet, base_name='ous')
|
||||
router.register(r'orgunits/all', OrgUnitViewSet, base_name='allous')
|
||||
@@ -12,6 +11,5 @@ urlpatterns = router.urls
|
||||
|
||||
urlpatterns += patterns(
|
||||
'',
|
||||
url(r'^forward/$', ForwardCreateView.as_view(), name='forward-create'),
|
||||
url(r'^forward/(?P<forwarder>.+)/$', ForwardDeleteView.as_view(), name='forward-delete'),
|
||||
url(r'^aliases/$', AliasesView.as_view(), name='aliases'),
|
||||
)
|
||||
+21
-58
@@ -1,4 +1,3 @@
|
||||
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
|
||||
@@ -7,15 +6,15 @@ from django.shortcuts import render, redirect
|
||||
from rest_framework import viewsets, views
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from rest_framework import status
|
||||
|
||||
from mailadmin.api import CPanel
|
||||
from mailadmin.api import DjangoPostfixDovecotAPI
|
||||
from mailadmin.models import OrgUnit
|
||||
from mailadmin.serializers import UserSerializer, OrgUnitSerializer, ForwardSerializer
|
||||
from mailadmin.permissions import DestinationPrefixOwner
|
||||
from mailadmin.serializers import UserSerializer, OrgUnitSerializer, AliasSerializer
|
||||
from mailadmin.permissions import SourcePrefixOwner
|
||||
|
||||
|
||||
def index(request):
|
||||
form = {}
|
||||
if request.method == "POST":
|
||||
form = AuthenticationForm(data=request.POST)
|
||||
if form.is_valid():
|
||||
@@ -41,14 +40,12 @@ def logout(request):
|
||||
return redirect('index')
|
||||
|
||||
|
||||
class ForwardsViewSet(viewsets.ViewSet):
|
||||
"""
|
||||
Forwards from cPanel
|
||||
"""
|
||||
class AliasesView(views.APIView):
|
||||
""" List, create and delete aliases from mxapi """
|
||||
_api = DjangoPostfixDovecotAPI()
|
||||
permission_classes = (SourcePrefixOwner,)
|
||||
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def list(self, request):
|
||||
def get(self, request):
|
||||
group_filter = request.QUERY_PARAMS.get('groups', None)
|
||||
if group_filter is None:
|
||||
my_groups = request.user.groups.all()
|
||||
@@ -67,62 +64,28 @@ class ForwardsViewSet(viewsets.ViewSet):
|
||||
|
||||
my_prefixes = orgunits.values_list('prefix', flat=True)
|
||||
# Prepare regular expression
|
||||
regexp = '|'.join(['^{0}-'.format(p) for p in my_prefixes])
|
||||
regexp = '|'.join(['^{0}-|^{0}@'.format(p) for p in my_prefixes])
|
||||
if len(my_prefixes) == 0:
|
||||
return Response({'result': 'No results'}) # Need at least one
|
||||
|
||||
cp = CPanel()
|
||||
params = dict(
|
||||
domain=settings.NEUF_EMAIL_DOMAIN,
|
||||
regex=regexp
|
||||
)
|
||||
|
||||
res = cp.api('Email', 'listforwards', params)
|
||||
res = self._api.list_aliases_regex(regexp)
|
||||
return Response(res)
|
||||
|
||||
|
||||
class ForwardCreateView(views.APIView):
|
||||
_cp = CPanel()
|
||||
permission_classes = (DestinationPrefixOwner,)
|
||||
|
||||
def post(self, request):
|
||||
fw = ForwardSerializer(data=request.DATA)
|
||||
if not fw.is_valid():
|
||||
return Response(fw.errors, status=400)
|
||||
aliases = AliasSerializer(data=request.DATA, many=True)
|
||||
if not aliases.is_valid():
|
||||
return Response(aliases.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# fw.data
|
||||
params = dict(
|
||||
domain=settings.NEUF_EMAIL_DOMAIN,
|
||||
email=fw.data['dest'].replace('@{0}'.format(settings.NEUF_EMAIL_DOMAIN), ''),
|
||||
fwdopt='fwd',
|
||||
fwdemail=fw.data['forward']
|
||||
)
|
||||
# FIXME: unreliable
|
||||
# res = self._cp.api('Email', 'addforward', params)
|
||||
res = {'errors': 'Not implemented'}
|
||||
res = self._api.create_aliases(aliases.data)
|
||||
return Response(res)
|
||||
|
||||
def delete(self, request):
|
||||
aliases = AliasSerializer(data=request.DATA, many=True)
|
||||
if not aliases.is_valid():
|
||||
return Response(aliases.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
class ForwardDeleteView(views.APIView):
|
||||
_cp = CPanel()
|
||||
permission_classes = (DestinationPrefixOwner,)
|
||||
|
||||
def delete(self, request, forwarder=None):
|
||||
invalid_forwarder = {'error': 'Invalid forwarder: {0}'.format(forwarder)}
|
||||
if '=' not in forwarder:
|
||||
return Response(invalid_forwarder, status=400)
|
||||
|
||||
fwd_data = forwarder.split("=")
|
||||
|
||||
fw = ForwardSerializer(data={'dest': fwd_data[0], 'forward': fwd_data[1]})
|
||||
if not fw.is_valid():
|
||||
return Response(fw.errors, status=400)
|
||||
|
||||
params = {
|
||||
'arg-0': '{0}={1}'.format(fw.data['dest'], fw.data['forward'])
|
||||
}
|
||||
# FIXME: unreliable
|
||||
# res = self._cp.api('Email', 'delforward', params, version=1)
|
||||
# FIXME: not tested
|
||||
# res = self._api.delete_aliases(aliases)
|
||||
res = {'errors': 'Not implemented'}
|
||||
return Response(res)
|
||||
|
||||
|
||||
@@ -86,11 +86,11 @@ STATIC_URL = '/static/'
|
||||
|
||||
LOGIN_REDIRECT_URL = '/lists/'
|
||||
|
||||
CP_API_URL = 'https://web.studentersamfundet.no:2083/json-api/cpanel'
|
||||
CP_API_USERNAME = "root"
|
||||
CP_API_PASSWORD = ""
|
||||
DPD_API_URL= 'https://mxapi.neuf.no/api'
|
||||
DPD_API_USERNAME = ""
|
||||
DPD_API_PASSWORD = ""
|
||||
|
||||
NEUF_EMAIL_DOMAIN = 'studentersamfundet.no'
|
||||
NEUF_EMAIL_DOMAIN_NAME = 'stry.no'
|
||||
|
||||
AUTHENTICATION_BACKENDS = (
|
||||
'mailadmin.backends.LDAPEmailBackend',
|
||||
|
||||
+9
-8
@@ -1,12 +1,13 @@
|
||||
Django==1.7.1
|
||||
django-auth-ldap==1.2.2
|
||||
Django>=1.7,<1.8
|
||||
django-auth-ldap==1.2.4
|
||||
django-bootstrap-form==3.1
|
||||
django-filter==0.8
|
||||
djangorestframework==2.4.4
|
||||
django-extensions==1.4.9
|
||||
django-filter==0.9.1
|
||||
djangorestframework==3.0.2
|
||||
Fabric==1.10.1
|
||||
Markdown==2.5.1
|
||||
MySQL-python==1.2.5
|
||||
ndg-httpsclient==0.3.2
|
||||
ndg-httpsclient==0.3.3
|
||||
pyasn1==0.1.7
|
||||
pyOpenSSL==0.14
|
||||
python-ldap==2.4.18
|
||||
requests==2.4.3
|
||||
python-ldap==2.4.19
|
||||
requests==2.5.1
|
||||
Reference in new issue
Block a user