Functional API
This commit is contained in:
1 parent
32ee67eaa9
commit
81fe4a6872
11 files changed
+218
-25
No files matched your search
@@ -4,3 +4,4 @@ local_settings.py
|
||||
venv
|
||||
.idea
|
||||
db.sqlite3
|
||||
node_modules
|
||||
@@ -0,0 +1,36 @@
|
||||
from rest_framework import permissions
|
||||
from mailadmin.models import OrgUnit
|
||||
import re
|
||||
|
||||
from mailadmin.serializers import ForwardSerializer
|
||||
|
||||
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):
|
||||
def has_permission(self, request, view):
|
||||
fw = ForwardSerializer(data=request.DATA)
|
||||
if not fw.is_valid():
|
||||
return True # Skip auth if not valid data
|
||||
|
||||
my_groups = request.user.groups.all()
|
||||
# Look for mailinglist prefixes
|
||||
my_prefixes = OrgUnit.objects.filter(admin_groups__in=my_groups).distinct().values_list('prefix', flat=True)
|
||||
# Prepare regular expression
|
||||
regexp = '|'.join(['{0}-'.format(p) for p in my_prefixes])
|
||||
if len(my_prefixes) == 0:
|
||||
return False
|
||||
# The destination should have at least one match with the prefix regexp
|
||||
return re.search(regexp, fw.data['dest']) is not None
|
||||
@@ -0,0 +1,40 @@
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User, Group
|
||||
from rest_framework import serializers
|
||||
|
||||
from mailadmin.models import OrgUnit
|
||||
|
||||
|
||||
class GroupSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Group
|
||||
fields = ['id', 'name']
|
||||
|
||||
|
||||
class UserSerializer(serializers.ModelSerializer):
|
||||
groups = GroupSerializer(many=True)
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
exclude = ['password', 'user_permissions']
|
||||
|
||||
|
||||
class OrgUnitSerializer(serializers.ModelSerializer):
|
||||
admin_groups = GroupSerializer(many=True)
|
||||
member_groups = GroupSerializer(many=True)
|
||||
|
||||
class Meta:
|
||||
model = OrgUnit
|
||||
|
||||
|
||||
class ForwardSerializer(serializers.Serializer):
|
||||
dest = serializers.EmailField(required=True)
|
||||
forward = serializers.EmailField(required=True)
|
||||
_domain = settings.NEUF_EMAIL_DOMAIN
|
||||
|
||||
def validate_dest(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))
|
||||
|
||||
return attrs
|
||||
@@ -1,8 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
{% load staticfiles %}<!DOCTYPE html>
|
||||
<html>
|
||||
<head lang="en">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block "title" %}{% endblock %}</title>
|
||||
<link rel="stylesheet" href="{% static 'dist/styles/main.css' %}" type="text/css">
|
||||
<script type="text/javascript" src="{% static 'bower_components/jquery/dist/jquery.js' %}"></script>
|
||||
</head>
|
||||
<body>
|
||||
{% block "body" %}{% endblock %}
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
{% extends "base.html" %}
|
||||
{% load bootstrap %}
|
||||
{% block "body" %}
|
||||
Hi, you should try the <a href="/api/">APIS</a>
|
||||
{% if not user.is_authenticated %}
|
||||
{{ form|bootstrap }}
|
||||
{% else %}
|
||||
<div class="greeting">Hei, {{ user.username }}</div>
|
||||
{% endif %}
|
||||
<div></div><a href="/api/">API</a></div>.
|
||||
{% endblock %}
|
||||
+3
-3
@@ -36,9 +36,9 @@ class APITest(TestCase):
|
||||
@unittest.skip("Not now")
|
||||
def test_delforward(self):
|
||||
server = CPanel()
|
||||
params = dict(
|
||||
forwarder='test.testesen@studentersamfundet.no=nikolaik@gmail.com',
|
||||
)
|
||||
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)
|
||||
|
||||
+11
-1
@@ -1,6 +1,16 @@
|
||||
from mailadmin.views import ForwardsViewSet
|
||||
from django.conf.urls import patterns, url
|
||||
from rest_framework.routers import DefaultRouter
|
||||
|
||||
from mailadmin.views import ForwardsViewSet, MyUserViewSet, OrgUnitViewSet, ForwardCreateView, ForwardDeleteView
|
||||
|
||||
router = DefaultRouter()
|
||||
router.register(r'forwards', ForwardsViewSet, base_name='all')
|
||||
router.register(r'me', MyUserViewSet, base_name='me')
|
||||
router.register(r'orgunits', OrgUnitViewSet, base_name='ous')
|
||||
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'),
|
||||
)
|
||||
+101
-13
@@ -1,32 +1,120 @@
|
||||
from django.contrib.auth.models import Group
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import login
|
||||
from django.contrib.auth.forms import AuthenticationForm
|
||||
from django.contrib.auth.models import User
|
||||
from django.shortcuts import render
|
||||
from rest_framework import viewsets
|
||||
from rest_framework import viewsets, views
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
|
||||
from mailadmin.api import CPanel
|
||||
from mailadmin.models import OrgUnit
|
||||
from mailadmin.serializers import UserSerializer, OrgUnitSerializer, ForwardSerializer
|
||||
from mailadmin.permissions import DestinationPrefixOwner
|
||||
|
||||
|
||||
def home(request):
|
||||
return render(request, "home.html")
|
||||
form = {}
|
||||
if request.method == "POST":
|
||||
form = AuthenticationForm(data=request.POST)
|
||||
if form.is_valid():
|
||||
# Log the user in.
|
||||
login(request, form.get_user())
|
||||
else:
|
||||
if not request.user.is_authenticated():
|
||||
form = AuthenticationForm(request)
|
||||
|
||||
return render(request, "home.html", {'form': form})
|
||||
|
||||
|
||||
class ForwardsViewSet(viewsets.ViewSet):
|
||||
"""
|
||||
A simple ViewSet that for listing forwards
|
||||
Forwards from cPanel
|
||||
"""
|
||||
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def list(self, request):
|
||||
group_filter = request.QUERY_PARAMS.get('groups', None)
|
||||
if group_filter is None:
|
||||
my_groups = request.user.groups.all()
|
||||
else:
|
||||
# Filter groups
|
||||
if ',' in group_filter:
|
||||
group_filter = group_filter.split(',')
|
||||
else:
|
||||
group_filter = [group_filter]
|
||||
my_groups = request.user.groups.filter(pk__in=group_filter)
|
||||
|
||||
# Look for mailinglist prefixes
|
||||
my_prefixes = OrgUnit.objects.filter(admin_groups__in=my_groups).distinct().values_list('prefix', flat=True)
|
||||
# Prepare regular expression
|
||||
regexp = '|'.join(['{0}-'.format(p) for p in my_prefixes])
|
||||
|
||||
if len(my_prefixes) == 0:
|
||||
return Response({'result': 'No results'}) # Need at least one
|
||||
|
||||
cp = CPanel()
|
||||
regexp = self.request.QUERY_PARAMS.get('regexp', None)
|
||||
my_groups = request.user.groups.values_list('pk', flat=True)
|
||||
print my_groups
|
||||
ous = OrgUnit.objects.filter(admin_groups__in=my_groups).values_list('prefix', flat=True)
|
||||
ous = set(ous)
|
||||
print ous
|
||||
#regexp = 'kak-*'
|
||||
params = dict(
|
||||
domain='studentersamfundet.no',
|
||||
domain=settings.NEUF_EMAIL_DOMAIN,
|
||||
regex=regexp
|
||||
)
|
||||
|
||||
res = cp.api('Email', 'listforwards', params)
|
||||
return Response(res)
|
||||
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)
|
||||
|
||||
# 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']
|
||||
)
|
||||
res = self._cp.api('Email', 'addforward', params)
|
||||
return Response(res)
|
||||
|
||||
|
||||
class ForwardDeleteView(views.APIView):
|
||||
_cp = CPanel()
|
||||
|
||||
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'])
|
||||
}
|
||||
res = self._cp.api('Email', 'delforward', params, version=1)
|
||||
return Response(res)
|
||||
|
||||
|
||||
class MyUserViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
queryset = User.objects.none()
|
||||
serializer_class = UserSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get_queryset(self):
|
||||
return User.objects.filter(pk=self.request.user.pk)
|
||||
|
||||
|
||||
class OrgUnitViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
queryset = OrgUnit.objects.all()
|
||||
serializer_class = OrgUnitSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
@@ -37,6 +37,7 @@ INSTALLED_APPS = (
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'rest_framework',
|
||||
'bootstrapform',
|
||||
'mailadmin',
|
||||
)
|
||||
|
||||
@@ -83,10 +84,14 @@ USE_TZ = True
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
LOGIN_REDIRECT_URL = '/'
|
||||
|
||||
CP_API_URL = 'https://web.studentersamfundet.no:2083/json-api/cpanel'
|
||||
CP_API_USERNAME = "root"
|
||||
CP_API_PASSWORD = ""
|
||||
|
||||
NEUF_EMAIL_DOMAIN = 'studentersamfundet.no'
|
||||
|
||||
AUTHENTICATION_BACKENDS = (
|
||||
'mailadmin.backends.LDAPEmailBackend',
|
||||
'mailadmin.backends.LDAPUsernameBackend',
|
||||
@@ -147,12 +152,12 @@ AUTH_LDAP_E_USER_ATTR_MAP = AUTH_LDAP_U_USER_ATTR_MAP
|
||||
AUTH_LDAP_E_PROFILE_ATTR_MAP = AUTH_LDAP_U_PROFILE_ATTR_MAP
|
||||
AUTH_LDAP_E_ALWAYS_UPDATE_USER = AUTH_LDAP_U_ALWAYS_UPDATE_USER
|
||||
|
||||
# Debug logging
|
||||
import logging
|
||||
logger = logging.getLogger('django_auth_ldap')
|
||||
logger.addHandler(logging.StreamHandler())
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
REST_FRAMEWORK = {
|
||||
'DEFAULT_AUTHENTICATION_CLASSES': (
|
||||
'rest_framework.authentication.BasicAuthentication',
|
||||
'rest_framework.authentication.SessionAuthentication',
|
||||
)
|
||||
}
|
||||
|
||||
# Local settings
|
||||
try:
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from django.conf.urls import patterns, include, url
|
||||
from django.contrib import admin
|
||||
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
||||
|
||||
urlpatterns = patterns(
|
||||
'',
|
||||
@@ -8,3 +9,5 @@ urlpatterns = patterns(
|
||||
url(r'^admin/', include(admin.site.urls)),
|
||||
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
|
||||
)
|
||||
|
||||
urlpatterns += staticfiles_urlpatterns()
|
||||
@@ -5,3 +5,4 @@ django-filter==0.8
|
||||
djangorestframework==2.4.4
|
||||
python-ldap==2.4.18
|
||||
requests==2.4.3
|
||||
django-bootstrap-form==3.1
|
||||
Reference in new issue
Block a user