Commit 62c853d0 authored by Florian Fuchs's avatar Florian Fuchs

* added subscription list page for logged in user

* added decorator to allow login via http basic auth (to allow non-browser clients to use API views)
* added api view for list index
* several changes regarding style and navigation structure
parent f316c1bc
...@@ -36,5 +36,5 @@ setup( ...@@ -36,5 +36,5 @@ setup(
package_dir = {'': 'src'}, package_dir = {'': 'src'},
include_package_data = True, include_package_data = True,
install_requires = ['django-social-auth>=0.6.7', install_requires = ['django-social-auth>=0.6.7',
'mailmanclient'] 'mailmanclient', ]
) )
...@@ -18,11 +18,29 @@ ...@@ -18,11 +18,29 @@
"""Postorius view decorators.""" """Postorius view decorators."""
from django.contrib.auth import logout, authenticate, login
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from postorius.models import (Domain, List, Member, MailmanUser, from postorius.models import (Domain, List, Member, MailmanUser,
MailmanApiError, Mailman404Error) MailmanApiError, Mailman404Error)
def basic_auth_login(fn):
def wrapper(*args, **kwargs):
request = args[0]
if request.user.is_authenticated():
print 'already logged in'
if not request.user.is_authenticated():
if request.META.has_key('HTTP_AUTHORIZATION'):
authmeth, auth = request.META['HTTP_AUTHORIZATION'].split(' ', 1)
if authmeth.lower() == 'basic':
auth = auth.strip().decode('base64')
username, password = auth.split(':', 1)
user = authenticate(username=username, password=password)
if user:
login(request, user)
return fn(request, **kwargs)
return wrapper
def list_owner_required(fn): def list_owner_required(fn):
"""Check if the logged in user is the list owner of the given list. """Check if the logged in user is the list owner of the given list.
...@@ -65,3 +83,27 @@ def list_moderator_required(fn): ...@@ -65,3 +83,27 @@ def list_moderator_required(fn):
user.is_list_moderator = True user.is_list_moderator = True
return fn(*args, **kwargs) return fn(*args, **kwargs)
return wrapper return wrapper
def superuser_or_403(fn):
"""Make sure that the logged in user is a superuser or otherwise raise
PermissionDenied.
Assumes the request object to be the first arg."""
def wrapper(*args, **kwargs):
user = args[0].user
if not user.is_superuser:
raise PermissionDenied
return fn(*args, **kwargs)
return wrapper
def loggedin_or_403(fn):
"""Make sure that the logged in user is not anonymous or otherwise raise
PermissionDenied.
Assumes the request object to be the first arg."""
def wrapper(*args, **kwargs):
user = args[0].user
if not user.is_authenticated():
raise PermissionDenied
return fn(*args, **kwargs)
return wrapper
...@@ -92,12 +92,40 @@ Apart from these default roles, there are two others relevant in Postorius: ...@@ -92,12 +92,40 @@ Apart from these default roles, there are two others relevant in Postorius:
There are a number of decorators to protect views from unauthorized users. There are a number of decorators to protect views from unauthorized users.
- ``@user_passes_test(lambda u: u.is_superuser)`` - ``@user_passes_test(lambda u: u.is_superuser)`` (redirects to login form)
- ``@login_required`` - ``@login_required`` (redirects to login form)
- ``@list_owner_required`` - ``@list_owner_required`` (returns 403)
- ``@list_moderator_required`` - ``@list_moderator_required`` (returns 403)
- ``@superuser_or_403`` (returns 403)
- ``@loggedin_or_403`` (returns 403)
- ``@basic_auth_login``
Check out views/views.py for examples! Check out ``views/views.py`` or ``views/api.py`` for examples!
The last one (basic_auth_login) checks the request header for HTTP Basic Auth
credentials and uses those to authenticate against Django's session-based
mechanism. It can be used in cases where a view is accessed from other clients
than the web browser.
Please make sure to put it outside the other auth decorators.
Good:
::
@basic_auth_login
@list_owner_required
def my_view_func(request):
...
Won't work, because list_owner_required will not recognize the user:
::
@list_owner_required
@basic_auth_login
def my_view_func(request):
...
Accessing the Mailman API Accessing the Mailman API
......
...@@ -39,6 +39,10 @@ along with Postorius. If not, see <http://www.gnu.org/licenses/>. ...@@ -39,6 +39,10 @@ along with Postorius. If not, see <http://www.gnu.org/licenses/>.
* added a mailmanclient shell to use as a `manage.py` command (`python manage.py mmclient`) * added a mailmanclient shell to use as a `manage.py` command (`python manage.py mmclient`)
* use "url from future" template tag in all templates. Contributed by Richard Wackerbarth. * use "url from future" template tag in all templates. Contributed by Richard Wackerbarth.
* added "new user" form. Contributed by George Chatzisofroniou. * added "new user" form. Contributed by George Chatzisofroniou.
* added user subscription page
* added decorator to allow login via http basic auth (to allow non-browser clients to use API views)
* added api view for list index
* several changes regarding style and navigation structure
1.0 alpha 1 -- "Space Farm" 1.0 alpha 1 -- "Space Farm"
......
...@@ -123,12 +123,34 @@ lists.</li> ...@@ -123,12 +123,34 @@ lists.</li>
</ul> </ul>
<p>There are a number of decorators to protect views from unauthorized users.</p> <p>There are a number of decorators to protect views from unauthorized users.</p>
<ul class="simple"> <ul class="simple">
<li><tt class="docutils literal"><span class="pre">&#64;user_passes_test(lambda</span> <span class="pre">u:</span> <span class="pre">u.is_superuser)</span></tt></li> <li><tt class="docutils literal"><span class="pre">&#64;user_passes_test(lambda</span> <span class="pre">u:</span> <span class="pre">u.is_superuser)</span></tt> (redirects to login form)</li>
<li><tt class="docutils literal"><span class="pre">&#64;login_required</span></tt></li> <li><tt class="docutils literal"><span class="pre">&#64;login_required</span></tt> (redirects to login form)</li>
<li><tt class="docutils literal"><span class="pre">&#64;list_owner_required</span></tt></li> <li><tt class="docutils literal"><span class="pre">&#64;list_owner_required</span></tt> (returns 403)</li>
<li><tt class="docutils literal"><span class="pre">&#64;list_moderator_required</span></tt></li> <li><tt class="docutils literal"><span class="pre">&#64;list_moderator_required</span></tt> (returns 403)</li>
<li><tt class="docutils literal"><span class="pre">&#64;superuser_or_403</span></tt> (returns 403)</li>
<li><tt class="docutils literal"><span class="pre">&#64;loggedin_or_403</span></tt> (returns 403)</li>
<li><tt class="docutils literal"><span class="pre">&#64;basic_auth_login</span></tt></li>
</ul> </ul>
<p>Check out views/views.py for examples!</p> <p>Check out <tt class="docutils literal"><span class="pre">views/views.py</span></tt> or <tt class="docutils literal"><span class="pre">views/api.py</span></tt> for examples!</p>
<p>The last one (basic_auth_login) checks the request header for HTTP Basic Auth
credentials and uses those to authenticate against Django&#8217;s session-based
mechanism. It can be used in cases where a view is accessed from other clients
than the web browser.</p>
<p>Please make sure to put it outside the other auth decorators.</p>
<p>Good:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="nd">@basic_auth_login</span>
<span class="nd">@list_owner_required</span>
<span class="k">def</span> <span class="nf">my_view_func</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="o">...</span>
</pre></div>
</div>
<p>Won&#8217;t work, because list_owner_required will not recognize the user:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="nd">@list_owner_required</span>
<span class="nd">@basic_auth_login</span>
<span class="k">def</span> <span class="nf">my_view_func</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="o">...</span>
</pre></div>
</div>
</div> </div>
<div class="section" id="accessing-the-mailman-api"> <div class="section" id="accessing-the-mailman-api">
<h2>Accessing the Mailman API<a class="headerlink" href="#accessing-the-mailman-api" title="Permalink to this headline"></a></h2> <h2>Accessing the Mailman API<a class="headerlink" href="#accessing-the-mailman-api" title="Permalink to this headline"></a></h2>
......
...@@ -87,6 +87,10 @@ along with Postorius. If not, see &lt;<a class="reference external" href="http:/ ...@@ -87,6 +87,10 @@ along with Postorius. If not, see &lt;<a class="reference external" href="http:/
<li>added a mailmanclient shell to use as a <cite>manage.py</cite> command (<cite>python manage.py mmclient</cite>)</li> <li>added a mailmanclient shell to use as a <cite>manage.py</cite> command (<cite>python manage.py mmclient</cite>)</li>
<li>use &#8220;url from future&#8221; template tag in all templates. Contributed by Richard Wackerbarth.</li> <li>use &#8220;url from future&#8221; template tag in all templates. Contributed by Richard Wackerbarth.</li>
<li>added &#8220;new user&#8221; form. Contributed by George Chatzisofroniou.</li> <li>added &#8220;new user&#8221; form. Contributed by George Chatzisofroniou.</li>
<li>added user subscription page</li>
<li>added decorator to allow login via http basic auth (to allow non-browser clients to use API views)</li>
<li>added api view for list index</li>
<li>several changes regarding style and navigation structure</li>
</ul> </ul>
</div> </div>
<div class="section" id="alpha-1-space-farm"> <div class="section" id="alpha-1-space-farm">
......
...@@ -92,12 +92,40 @@ Apart from these default roles, there are two others relevant in Postorius: ...@@ -92,12 +92,40 @@ Apart from these default roles, there are two others relevant in Postorius:
There are a number of decorators to protect views from unauthorized users. There are a number of decorators to protect views from unauthorized users.
- ``@user_passes_test(lambda u: u.is_superuser)`` - ``@user_passes_test(lambda u: u.is_superuser)`` (redirects to login form)
- ``@login_required`` - ``@login_required`` (redirects to login form)
- ``@list_owner_required`` - ``@list_owner_required`` (returns 403)
- ``@list_moderator_required`` - ``@list_moderator_required`` (returns 403)
- ``@superuser_or_403`` (returns 403)
- ``@loggedin_or_403`` (returns 403)
- ``@basic_auth_login``
Check out views/views.py for examples! Check out ``views/views.py`` or ``views/api.py`` for examples!
The last one (basic_auth_login) checks the request header for HTTP Basic Auth
credentials and uses those to authenticate against Django's session-based
mechanism. It can be used in cases where a view is accessed from other clients
than the web browser.
Please make sure to put it outside the other auth decorators.
Good:
::
@basic_auth_login
@list_owner_required
def my_view_func(request):
...
Won't work, because list_owner_required will not recognize the user:
::
@list_owner_required
@basic_auth_login
def my_view_func(request):
...
Accessing the Mailman API Accessing the Mailman API
......
...@@ -39,6 +39,10 @@ along with Postorius. If not, see <http://www.gnu.org/licenses/>. ...@@ -39,6 +39,10 @@ along with Postorius. If not, see <http://www.gnu.org/licenses/>.
* added a mailmanclient shell to use as a `manage.py` command (`python manage.py mmclient`) * added a mailmanclient shell to use as a `manage.py` command (`python manage.py mmclient`)
* use "url from future" template tag in all templates. Contributed by Richard Wackerbarth. * use "url from future" template tag in all templates. Contributed by Richard Wackerbarth.
* added "new user" form. Contributed by George Chatzisofroniou. * added "new user" form. Contributed by George Chatzisofroniou.
* added user subscription page
* added decorator to allow login via http basic auth (to allow non-browser clients to use API views)
* added api view for list index
* several changes regarding style and navigation structure
1.0 alpha 1 -- "Space Farm" 1.0 alpha 1 -- "Space Farm"
......
...@@ -20,7 +20,7 @@ import logging ...@@ -20,7 +20,7 @@ import logging
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.db.models.signals import pre_save from django.db.models.signals import pre_delete, pre_save
from django.db import models from django.db import models
from django.dispatch import receiver from django.dispatch import receiver
from django.http import Http404 from django.http import Http404
...@@ -88,6 +88,7 @@ class MailmanRestManager(object): ...@@ -88,6 +88,7 @@ class MailmanRestManager(object):
def create(self, **kwargs): def create(self, **kwargs):
try: try:
method = getattr(self.client, 'create_' + self.resource_name) method = getattr(self.client, 'create_' + self.resource_name)
print kwargs
return method(**kwargs) return method(**kwargs)
except AttributeError, e: except AttributeError, e:
raise MailmanApiError(e) raise MailmanApiError(e)
...@@ -174,9 +175,3 @@ class Member(MailmanRestModel): ...@@ -174,9 +175,3 @@ class Member(MailmanRestModel):
"""Member model class. """Member model class.
""" """
objects = MailmanRestManager('member', 'members') objects = MailmanRestManager('member', 'members')
@receiver(pre_save, sender=User)
def user_create_callback(sender, **kwargs):
# inst = kwargs['instance']
pass
...@@ -110,8 +110,9 @@ h2 { ...@@ -110,8 +110,9 @@ h2 {
.mm_nav { .mm_nav {
padding: 10px 0 30px 0; padding: 10px 0 30px 0;
margin: 20px 0; margin: 20px 0;
border: solid #d8d8d8; border-style: solid;
border-width: 1px 0; border-width: 1px 0;
border-color: #e8e8e8 #fff #d8d8d8 #fff;
background: -webkit-linear-gradient(top, white 0%,#EFEFEF 100%); background: -webkit-linear-gradient(top, white 0%,#EFEFEF 100%);
background: -moz-linear-gradient(top, white 0%,#EFEFEF 100%); background: -moz-linear-gradient(top, white 0%,#EFEFEF 100%);
background: -ms-linear-gradient(top, white 0%,#EFEFEF 100%); background: -ms-linear-gradient(top, white 0%,#EFEFEF 100%);
......
<!doctype html>
{% load i18n %} {% load i18n %}
{% block header%}{% endblock %} {% block header%}{% endblock %}
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
<ul class="mm_nav"> <ul class="mm_nav">
<li><a href="{% url 'user_profile' %}">{% trans "Profile" %}</a></li> <li><a href="{% url 'user_profile' %}">{% trans "Profile" %}</a></li>
<li><a href="{% url 'user_mailmansettings' %}">{% trans "Mailman settings" %}</a></li> <li><a href="{% url 'user_mailmansettings' %}">{% trans "Mailman settings" %}</a></li>
<li><a href="{% url 'user_subscriptions' %}">{% trans "Subscriptions" %}</a></li>
<li><a href="{% url 'user_todos' %}">{% trans "Todos" %}</a></li> <li><a href="{% url 'user_todos' %}">{% trans "Todos" %}</a></li>
</ul> </ul>
</div> </div>
{% extends extend_template %}
{% load url from future %}
{% load i18n %}
{% block main %}
{% include 'postorius/menu/user_nav.html' %}
<h1>List Subscriptions <span></span></h1>
<p>You are subscribed to the following mailing lists:</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>{% trans 'List Name' %}</th>
<th>{% trans 'Subscription Address' %}</th>
<th>{% trans 'Role' %}</th>
<th>{% trans 'Delivery Mode' %}</th>
</tr>
</thead>
<tbody>
{% for subscription in memberships %}
<tr>
<td>{{ subscription.fqdn_listname }}</td>
<td>{{ subscription.address }}</td>
<td>{{ subscription.role }}</td>
<td>{{ subscription.delivery_mode }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock main %}
...@@ -7,7 +7,8 @@ ...@@ -7,7 +7,8 @@
<span class="mm_context">{% trans 'Users' %}</span> <span class="mm_context">{% trans 'Users' %}</span>
{% if user.is_superuser %} {% if user.is_superuser %}
<ul class="mm_nav"> <ul class="mm_nav">
<li><a href="{% url 'user_index' %}">{% trans "User Index" %}</a></li> <li><a href="{% url 'user_index' %}">{% trans "Mailman Users" %}</a></li>
<li><a href="{% url 'user_index' %}">{% trans "Web Users" %}</a></li>
<li class="mm_new_user mm_action"><a class="btn btn-mini btn-success" href="{% url 'user_new' %}">{% trans "Create User" %}</a></li> <li class="mm_new_user mm_action"><a class="btn btn-mini btn-success" href="{% url 'user_new' %}">{% trans "Create User" %}</a></li>
</ul> </ul>
{% endif %} {% endif %}
......
...@@ -17,11 +17,13 @@ ...@@ -17,11 +17,13 @@
from django.contrib.auth.models import AnonymousUser, User from django.contrib.auth.models import AnonymousUser, User
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.test.client import RequestFactory
from django.utils import unittest from django.utils import unittest
from mock import patch from mock import patch
from postorius.auth.decorators import (list_owner_required, from postorius.auth.decorators import (list_owner_required,
list_moderator_required) list_moderator_required,
basic_auth_login)
from postorius.models import (Domain, List, Member, MailmanUser, from postorius.models import (Domain, List, Member, MailmanUser,
MailmanApiError, Mailman404Error) MailmanApiError, Mailman404Error)
from mailmanclient import Client from mailmanclient import Client
......
...@@ -32,9 +32,8 @@ urlpatterns = patterns( ...@@ -32,9 +32,8 @@ urlpatterns = patterns(
url(r'^accounts/logout/$', 'user_logout', name='user_logout'), url(r'^accounts/logout/$', 'user_logout', name='user_logout'),
url(r'^accounts/profile/$', 'user_profile', name='user_profile'), url(r'^accounts/profile/$', 'user_profile', name='user_profile'),
url(r'^accounts/todos/$', 'user_todos', name='user_todos'), url(r'^accounts/todos/$', 'user_todos', name='user_todos'),
url(r'^accounts/membership/(?:(?P<fqdn_listname>[^/]+)/)?$', url(r'^accounts/subscriptions/$', UserSubscriptionsView.as_view(),
'membership_settings', kwargs={"tab": "membership"}, name='user_subscriptions'),
name='membership_settings'),
url(r'^accounts/mailmansettings/$', url(r'^accounts/mailmansettings/$',
'user_mailmansettings', 'user_mailmansettings',
name='user_mailmansettings'), name='user_mailmansettings'),
...@@ -81,4 +80,5 @@ urlpatterns = patterns( ...@@ -81,4 +80,5 @@ urlpatterns = patterns(
url(r'^users/new/$', 'user_new', name='user_new'), url(r'^users/new/$', 'user_new', name='user_new'),
url(r'^users/(?P<user_id>[^/]+)/$', url(r'^users/(?P<user_id>[^/]+)/$',
UserSummaryView.as_view(), name='user_summary'), UserSummaryView.as_view(), name='user_summary'),
url(r'^api/lists/$', 'api_list_index', name='api_list_index'),
) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) ) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
...@@ -17,3 +17,4 @@ ...@@ -17,3 +17,4 @@
# Postorius. If not, see <http://www.gnu.org/licenses/>. # Postorius. If not, see <http://www.gnu.org/licenses/>.
from postorius.views.views import * from postorius.views.views import *
from postorius.views.api import *
# -*- coding: utf-8 -*-
# Copyright (C) 1998-2012 by the Free Software Foundation, Inc.
#
# This file is part of Postorius.
#
# Postorius is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# Postorius is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# Postorius. If not, see <http://www.gnu.org/licenses/>.
import re
import sys
import json
import logging
import requests
from django.conf import settings
from django.contrib import messages
from django.contrib.auth import logout, authenticate, login
from django.contrib.auth.decorators import (login_required,
permission_required,
user_passes_test)
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render_to_response, redirect
from django.template import Context, loader, RequestContext
from django.utils.decorators import method_decorator
from django.utils.translation import gettext as _
from urllib2 import HTTPError
from mailmanclient import Client
from postorius import utils
from postorius.models import (Domain, List, Member, MailmanUser,
MailmanApiError, Mailman404Error)
from postorius.forms import *
from postorius.auth.decorators import *
from postorius.views.generic import MailingListView, MailmanUserView
logger = logging.getLogger(__name__)
@basic_auth_login
@loggedin_or_403
def api_list_index(request):
client = Client('%s/3.0' % settings.REST_SERVER,
settings.API_USER, settings.API_PASS)
res, content = client._connection.call('lists')
return HttpResponse(json.dumps(content['entries']),
content_type="application/json")
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
from django.shortcuts import render_to_response, redirect from django.shortcuts import render_to_response, redirect
from django.template import Context, loader, RequestContext from django.template import Context, loader, RequestContext
from django.views.generic import TemplateView from django.views.generic import TemplateView, View
from postorius.models import (Domain, List, Member, MailmanUser, from postorius.models import (Domain, List, Member, MailmanUser,
MailmanApiError, Mailman404Error) MailmanApiError, Mailman404Error)
...@@ -61,20 +61,30 @@ class MailmanUserView(TemplateView): ...@@ -61,20 +61,30 @@ class MailmanUserView(TemplateView):
return address return address
def _get_user(self, user_id): def _get_user(self, user_id):
user_obj = MailmanUser.objects.get_or_404(address=user_id) try:
user_obj = MailmanUser.objects.get(address=user_id)
except Mailman404Error:
user_obj = None
# replace display_name with first address if display_name is not set # replace display_name with first address if display_name is not set
if user_obj.display_name == 'None' or user_obj.display_name is None: if user_obj is not None:
user_obj.display_name = '' if user_obj.display_name == 'None' or user_obj.display_name is None:
user_obj.first_address = self._get_first_address(user_obj) user_obj.display_name = ''
user_obj.first_address = self._get_first_address(user_obj)
return user_obj return user_obj
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
# get the user object. # get the user object.
user_id = None
if 'user_id' in kwargs: if 'user_id' in kwargs:
user_id = kwargs['user_id']
elif request.user.is_authenticated():
user_id = request.user.email
if user_id is not None:
try: try:
self.mm_user = self._get_user(kwargs['user_id']) self.mm_user = self._get_user(user_id)
except MailmanApiError: except MailmanApiError:
return utils.render_api_error(request) return utils.render_api_error(request)
# set the template # set the template
if 'template' in kwargs: if 'template' in kwargs:
self.template = kwargs['template'] self.template = kwargs['template']
......
...@@ -19,7 +19,9 @@ ...@@ -19,7 +19,9 @@
import re import re
import sys import sys
import json
import logging import logging
import requests
from django.conf import settings from django.conf import settings
...@@ -28,7 +30,8 @@ from django.contrib.auth import logout, authenticate, login ...@@ -28,7 +30,8 @@ from django.contrib.auth import logout, authenticate, login
from django.contrib.auth.decorators import (login_required, from django.contrib.auth.decorators import (login_required,
permission_required, permission_required,
user_passes_test) user_passes_test)
from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth.forms import (AuthenticationForm, PasswordResetForm,
SetPasswordForm, PasswordChangeForm)
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.http import HttpResponse, HttpResponseRedirect from django.http import HttpResponse, HttpResponseRedirect
...@@ -43,7 +46,7 @@ from postorius import utils ...@@ -43,7 +46,7 @@ from postorius import utils
from postorius.models import (Domain, List, Member, MailmanUser, from postorius.models import (Domain, List, Member, MailmanUser,
MailmanApiError, Mailman404Error) MailmanApiError, Mailman404Error)
from postorius.forms import * from postorius.forms import *
from postorius.auth.decorators import list_owner_required from postorius.auth.decorators import *
from postorius.views.generic import MailingListView, MailmanUserView from postorius.views.generic import MailingListView, MailmanUserView
...@@ -710,6 +713,39 @@ class UserSummaryView(MailmanUserView): ...@@ -710,6 +713,39 @@ class UserSummaryView(MailmanUserView):
context_instance=RequestContext(request)) context_instance=RequestContext(request))
class UserSubscriptionsView(MailmanUserView):
"""Shows a summary of a user.
"""
def _get_list(self, list_id):
if getattr(self, 'lists', None) is None:
self.lists = {}
if self.lists.get(list_id) is None:
self.lists[list_id] = List.objects.get(fqdn_listname=list_id)
return self.lists[list_id]
def _get_memberships(self):
client = Client('%s/3.0' % settings.REST_SERVER,
settings.API_USER, settings.API_PASS)
memberships = []
for a in self.mm_user.addresses:
members = client._connection.call('members/find',
{'subscriber': a})
for m in members[1]['entries']:
mlist = self._get_list(m['list_id'])
memberships.append(dict(fqdn_listname=mlist.fqdn_listname,
role=m['role'],
delivery_mode=m['delivery_mode'],
address=a))
return memberships
def get(self, request):
memberships = self._get_memberships()
return render_to_response('postorius/user_subscriptions.html',
{'memberships': memberships},
context_instance=RequestContext(request))
@user_passes_test(lambda u: u.is_superuser) @user_passes_test(lambda u: u.is_superuser)
def user_index(request, template='postorius/users/index.html'): def user_index(request, template='postorius/users/index.html'):
"""Show a table of all users. """Show a table of all users.
...@@ -771,7 +807,7 @@ def user_login(request, template='postorius/login.html'): ...@@ -771,7 +807,7 @@ def user_login(request, template='postorius/login.html'):
context_instance=RequestContext(request)) context_instance=RequestContext(request))
@login_required @login_required()
def user_profile(request, user_email=None): def user_profile(request, user_email=None):
if not request.user.is_authenticated(): if not request.user.is_authenticated():
return redirect('user_login') return redirect('user_login')
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment