Manish Gill has proposed merging lp:~mgill25/postorius/m-trunk into
lp:postorius.
Requested reviews:
Mailman Coders (mailman-coders)
For more details, see:
https://code.launchpad.net/~mgill25/postorius/m-trunk/+merge/175549
GSoC 2013: Authenticated REST API for Postorius/Django
For review only!
These changes are not meant to be merged directly in the current Postorius code
and depend on the project https://launchpad.net/mm-rest, which is a Django app
that has the new models which correspond to the elements exposed via the
MM-Core Internal API. The changes made in this repository will only work as a
"simulator", which ensures that Postorius is able to perform the basic
functions (User/List/Domain creation, Changing settings) without any connection
to the Core via mm-client.
Associated Django project:
https://code.launchpad.net/~wacky/postorius/sample_website with settings etc.
--
https://code.launchpad.net/~mgill25/postorius/m-trunk/+merge/175549
Your team Mailman Coders is requested to review the proposed merge of
lp:~mgill25/postorius/m-trunk into lp:postorius.
=== modified file 'src/postorius/auth/decorators.py'
--- src/postorius/auth/decorators.py 2012-11-18 19:51:08 +0000
+++ src/postorius/auth/decorators.py 2013-07-18 12:32:23 +0000
@@ -21,8 +21,7 @@
from django.contrib.auth import logout, authenticate, login
from django.core.exceptions import PermissionDenied
-from postorius.models import (Domain, List, Member, MailmanUser,
- MailmanApiError, Mailman404Error)
+from public_rest.models import MailingList as List
def basic_auth_login(fn):
def wrapper(*args, **kwargs):
=== modified file 'src/postorius/forms.py'
--- src/postorius/forms.py 2013-03-21 18:43:28 +0000
+++ src/postorius/forms.py 2013-07-18 12:32:23 +0000
@@ -641,10 +641,7 @@
Form field to add a new user
"""
display_name = forms.CharField(
- label=_('User Name'),
- required=True,
- error_messages={'required': _('Please enter a display name.'),
- 'invalid': _('Please enter a valid display name.')})
+ label=_('Display Name'), required=False)
email = forms.EmailField(
label=_("User's email address"),
error_messages={
=== removed file 'src/postorius/management/commands/mmclient.py'
--- src/postorius/management/commands/mmclient.py 2013-05-31 02:21:38 +0000
+++ src/postorius/management/commands/mmclient.py 1970-01-01 00:00:00 +0000
@@ -1,50 +0,0 @@
-# -*- 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/>.
-
-from django.conf import settings
-from django.core.management.base import BaseCommand, CommandError
-from mailmanclient import Client, MailmanConnectionError
-from postorius import utils
-from urllib2 import HTTPError
-
-class Command(BaseCommand):
- help = """Opens a Python shell with a mailmanclient object named `client`.
-
-Usage example:
- client.lists
- [<List "[email protected]">]
- foo = client.get_list('[email protected]')
- foo.members
- [<Member "[email protected]">]
-
-A complete list of commands can be found in the mailman.client documentation."""
-
- def handle(self, *args, **options):
- # choose an interpreter
- console = None
- try:
- import IPython
- console_fn = IPython.embed
- except ImportError:
- import code
- shell = code.InteractiveConsole(globals())
- console_fn = shell.interact
- # connect to mailmanclient
- client = utils.get_client()
- # run the interpreter
- console_fn()
=== removed file 'src/postorius/models.py'
--- src/postorius/models.py 2013-05-31 02:21:38 +0000
+++ src/postorius/models.py 1970-01-01 00:00:00 +0000
@@ -1,177 +0,0 @@
-# -*- 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 logging
-
-from django.conf import settings
-from django.contrib.auth.models import User
-from django.db.models.signals import pre_delete, pre_save
-from django.db import models
-from django.dispatch import receiver
-from django.http import Http404
-from mailmanclient import Client, MailmanConnectionError
-from postorius import utils
-from urllib2 import HTTPError
-
-
-logger = logging.getLogger(__name__)
-
-
-class MailmanApiError(Exception):
- """Raised if the API is not available.
- """
- pass
-
-
-class Mailman404Error(Exception):
- """Proxy exception. Raised if the API returns 404."""
- pass
-
-
-class MailmanRestManager(object):
- """Manager class to give a model class CRUD access to the API.
- Returns objects (or lists of objects) retrived from the API.
- """
-
- def __init__(self, resource_name, resource_name_plural, cls_name=None):
- self.client = utils.get_client()
- self.resource_name = resource_name
- self.resource_name_plural = resource_name_plural
-
- def all(self):
- try:
- return getattr(self.client, self.resource_name_plural)
- except AttributeError:
- raise MailmanApiError
- except MailmanConnectionError, e:
- raise MailmanApiError(e)
-
- def get(self, **kwargs):
- try:
- method = getattr(self.client, 'get_' + self.resource_name)
- return method(**kwargs)
- except AttributeError, e:
- raise MailmanApiError(e)
- except HTTPError, e:
- if e.code == 404:
- raise Mailman404Error
- else:
- raise
- except MailmanConnectionError, e:
- raise MailmanApiError(e)
-
- def get_or_404(self, **kwargs):
- """Similar to `self.get` but raises standard Django 404 error.
- """
- try:
- return self.get(**kwargs)
- except Mailman404Error:
- raise Http404
- except MailmanConnectionError, e:
- raise MailmanApiError(e)
-
- def create(self, **kwargs):
- try:
- method = getattr(self.client, 'create_' + self.resource_name)
- print kwargs
- return method(**kwargs)
- except AttributeError, e:
- raise MailmanApiError(e)
- except HTTPError, e:
- if e.code == 409:
- raise MailmanApiError
- else:
- raise
- except MailmanConnectionError:
- raise MailmanApiError
-
- def delete(self):
- """Not implemented since the objects returned from the API
- have a `delete` method of their own.
- """
- pass
-
-
-class MailmanListManager(MailmanRestManager):
-
- def __init__(self):
- super(MailmanListManager, self).__init__('list', 'lists')
-
- def all(self, only_public=False):
- try:
- objects = getattr(self.client, self.resource_name_plural)
- except AttributeError:
- raise MailmanApiError
- except MailmanConnectionError, e:
- raise MailmanApiError(e)
- if only_public:
- public = []
- for obj in objects:
- if obj.settings.get('advertised', False):
- public.append(obj)
- return public
- else:
- return objects
-
- def by_mail_host(self, mail_host, only_public=False):
- objects = self.all(only_public)
- host_objects = []
- for obj in objects:
- if obj.mail_host == mail_host:
- host_objects.append(obj)
- return host_objects
-
-
-class MailmanRestModel(object):
- """Simple REST Model class to make REST API calls Django style.
- """
- MailmanApiError = MailmanApiError
- DoesNotExist = Mailman404Error
-
- def __init__(self, **kwargs):
- self.kwargs = kwargs
-
- def save(self):
- """Proxy function for `objects.create`.
- (REST API uses `create`, while Django uses `save`.)
- """
- self.objects.create(**self.kwargs)
-
-
-class Domain(MailmanRestModel):
- """Domain model class.
- """
- objects = MailmanRestManager('domain', 'domains')
-
-
-class List(MailmanRestModel):
- """List model class.
- """
- objects = MailmanListManager()
-
-
-class MailmanUser(MailmanRestModel):
- """MailmanUser model class.
- """
- objects = MailmanRestManager('user', 'users')
-
-
-class Member(MailmanRestModel):
- """Member model class.
- """
- objects = MailmanRestManager('member', 'members')
=== modified file 'src/postorius/templates/postorius/base.html'
--- src/postorius/templates/postorius/base.html 2013-07-14 20:42:05 +0000
+++ src/postorius/templates/postorius/base.html 2013-07-18 12:32:23 +0000
@@ -34,7 +34,7 @@
</ul>
<div class="mm_loginName">
{% if user.is_authenticated %}
- Logged in as: <a href="{% url 'user_profile' %}">{{ user.username }}</a> <a href="{% url 'user_logout' %}" title="{% trans 'Logout' %}" class="mm_logout"><i class="icon-off"></i></a>
+ Logged in as: <a href="{% url 'user_profile' %}">{{ user.display_name}}</a> <a href="{% url 'user_logout' %}" title="{% trans 'Logout' %}" class="mm_logout"><i class="icon-off"></i></a>
{% else %}
<a href="{% url 'user_login' %}">Login</a>
{% endif %}
=== modified file 'src/postorius/templates/postorius/lists/metrics.html'
--- src/postorius/templates/postorius/lists/metrics.html 2013-05-31 02:21:03 +0000
+++ src/postorius/templates/postorius/lists/metrics.html 2013-07-18 12:32:23 +0000
@@ -10,18 +10,18 @@
<tbody>
<tr>
<th>{% trans 'Created at' %}</th>
- <td>{{list.settings.created_at}}</td>
+ <td>{{list.created_at}}</td>
</tr>
<tr>
- <th>{% trans 'Created at' %}</th>
+ <th>{% trans 'Last post at' %}</th>
<td>{{list.settings.last_post_at}}</td>
</tr>
<tr>
- <th>{% trans 'Created at' %}</th>
+ <th>{% trans 'Digest last sent at' %}</th>
<td>{{list.settings.digest_last_sent_at}}</td>
</tr>
<tr>
- <th>{% trans 'Created at' %}</th>
+ <th>{% trans 'Volume ' %}</th>
<td>{{list.settings.volume}}</td>
</tr>
</tbody>
=== modified file 'src/postorius/templates/postorius/lists/summary.html'
--- src/postorius/templates/postorius/lists/summary.html 2013-05-31 02:21:03 +0000
+++ src/postorius/templates/postorius/lists/summary.html 2013-07-18 12:32:23 +0000
@@ -13,14 +13,14 @@
<h2>{% trans 'Description' %}</h2>
- <p>{{list.settings.description }}</p>
+ <p>{{list.description }}</p>
<h2>{% trans 'Subscribe to this list' %}</h2>
{% if user.is_authenticated %}
<form action="{% url 'list_subscribe' list.fqdn_listname %}" method="post" class="list_subscribe"> {% csrf_token %}
{{subscribe_form.as_p}}
<input class="btn btn-success" type="submit" value="{% trans 'Subscribe' %}" />
- <a href="{% url 'list_unsubscribe' list.fqdn_listname user.email %}" class="btn btn-danger">Unsubscribe</a>
+ <a href="{% url 'list_unsubscribe' list.fqdn_listname user.emails|first %}" class="btn btn-danger">Unsubscribe</a>
</form>
{% else %}
<p>To subscribe or unsubscribe this list you have to be logged in.</p>
=== modified file 'src/postorius/templates/postorius/user_profile.html'
--- src/postorius/templates/postorius/user_profile.html 2013-05-31 02:21:03 +0000
+++ src/postorius/templates/postorius/user_profile.html 2013-07-18 12:32:23 +0000
@@ -10,7 +10,7 @@
<tbody>
<tr>
<td>{% trans 'Mailman display name' %}</td>
- <td>{{ mm_user.display_name}}</td>
+ <td>{{ user.display_name}}</td>
</tr>
<tr>
<td>{% trans 'User name' %}</td>
=== modified file 'src/postorius/templates/postorius/user_subscriptions.html'
--- src/postorius/templates/postorius/user_subscriptions.html 2013-05-31 02:21:03 +0000
+++ src/postorius/templates/postorius/user_subscriptions.html 2013-07-18 12:32:23 +0000
@@ -23,7 +23,7 @@
<td>{{ subscription.fqdn_listname }}</td>
<td>{{ subscription.address }}</td>
<td>{{ subscription.role }}</td>
- <td>{{ subscription.delivery_mode }}</td>
+ <td>{{ subscription.preferences.delivery_mode }}</td>
</tr>
{% endfor %}
</tbody>
=== modified file 'src/postorius/templates/postorius/users/index.html'
--- src/postorius/templates/postorius/users/index.html 2013-07-05 11:05:45 +0000
+++ src/postorius/templates/postorius/users/index.html 2013-07-18 12:32:23 +0000
@@ -25,7 +25,7 @@
{% for mm_user in mm_user_page %}
<tr>
<td>
- <a href="{% url 'user_summary' user_id=mm_user.user_id %}">{% for address in mm_user.addresses|slice:":1" %}{{ address }}{% endfor %}</a>
+ <a href="{% url 'user_summary' user_id=mm_user.user_id %}">{% for address in mm_user.emails|slice:":1" %}{{ address }}{% endfor %}</a>
</td>
<td>
{{ mm_user.display_name }}
=== modified file 'src/postorius/templates/postorius/users/summary.html'
--- src/postorius/templates/postorius/users/summary.html 2012-11-18 19:51:08 +0000
+++ src/postorius/templates/postorius/users/summary.html 2013-07-18 12:32:23 +0000
@@ -1,4 +1,4 @@
-{% extends extend_template %}
+{% extends "postorius/base.html" %}
{% load i18n %}
{% load url from future %}
{% load nav_helpers %}
=== modified file 'src/postorius/tests/test_auth_decorators.py'
--- src/postorius/tests/test_auth_decorators.py 2012-11-04 19:54:09 +0000
+++ src/postorius/tests/test_auth_decorators.py 2013-07-18 12:32:23 +0000
@@ -26,7 +26,6 @@
basic_auth_login)
from postorius.models import (Domain, List, Member, MailmanUser,
MailmanApiError, Mailman404Error)
-from mailmanclient import Client
@list_owner_required
=== modified file 'src/postorius/tests/test_list_members.py'
--- src/postorius/tests/test_list_members.py 2012-09-26 21:07:54 +0000
+++ src/postorius/tests/test_list_members.py 2013-07-18 12:32:23 +0000
@@ -24,6 +24,7 @@
class ListMembersViewTest(unittest.TestCase):
"""Tests for the ListMembersView."""
+ '''
def setUp(self):
from django.test.client import RequestFactory
from postorius.tests.utils import create_mock_list, create_mock_member
@@ -91,6 +92,6 @@
request,
fqdn_listname='[email protected]')
self.assertEqual(response.status_code, 200)
-
+ '''
def tearDown(self):
pass
=== modified file 'src/postorius/tests/test_user_creation_sync.py'
--- src/postorius/tests/test_user_creation_sync.py 2012-10-28 18:21:52 +0000
+++ src/postorius/tests/test_user_creation_sync.py 2013-07-18 12:32:23 +0000
@@ -26,7 +26,6 @@
list_moderator_required)
from postorius.models import (Domain, List, Member, MailmanUser,
MailmanApiError, Mailman404Error)
-from mailmanclient import Client
class UserCreationSyncTest(unittest.TestCase):
=== modified file 'src/postorius/urls.py'
--- src/postorius/urls.py 2013-07-05 11:05:45 +0000
+++ src/postorius/urls.py 2013-07-18 12:32:23 +0000
@@ -81,13 +81,16 @@
url(r'^lists/$', 'list_index', name='list_index'),
url(r'^lists/new/$', 'list_new', name='list_new'),
url(r'^more_info/(?P<formid>[^/]+)/(?P<helpid>[^/]+)$', 'more_info_tab', name='more_info_tab'),
- url(r'^lists/(?P<fqdn_listname>[^/]+)/', include(per_list_urlpatterns)),
+ url(r'^lists/(?P<fqdn_listname>[^/]+)/', include(per_list_urlpatterns)),
# /users/
url(r'^users/(?P<page>\d+)/$', 'user_index', name='user_index_paged'),
url(r'^users/$', 'user_index', name='user_index'),
url(r'^users/new/$', 'user_new', name='user_new'),
- url(r'^users/(?P<user_id>[^/]+)/$',
+ url(r'^user/(?P<user_id>[^/]+)/$',
UserSummaryView.as_view(), name='user_summary'),
+<<<<<<< TREE
url(r'^users/(?P<user_id>\d+)/delete$', 'user_delete', name='user_delete'),
url(r'^api/lists/$', 'api_list_index', name='api_list_index'),
+=======
+>>>>>>> MERGE-SOURCE
)
=== modified file 'src/postorius/utils.py'
--- src/postorius/utils.py 2013-05-31 02:21:38 +0000
+++ src/postorius/utils.py 2013-07-18 12:32:23 +0000
@@ -21,9 +21,6 @@
from django.shortcuts import render_to_response, redirect
from django.template import RequestContext
-from mailmanclient import Client
-
-
def get_domain_name(request):
"""Extracts a domain name from the request object.
"""
@@ -31,12 +28,12 @@
return request.META["HTTP_HOST"].split(":")[0]
return None
-
-def get_client():
- return Client('{0}/3.0'.format(settings.MAILMAN_API_URL),
- settings.MAILMAN_USER,
- settings.MAILMAN_PASS)
-
+def render_error(request, message):
+ """Generic function to display error messages"""
+ return render_to_response(
+ 'postorius/errors/generic.html',
+ {'error': message },
+ context_instance=RequestContext(request))
def render_api_error(request):
"""Renders an error template.
@@ -46,3 +43,12 @@
'postorius/errors/generic.html',
{'error': "Mailman REST API not available. Please start Mailman core."},
context_instance=RequestContext(request))
+
+def render_pagination_error(request):
+ """Renders an error template.
+ Use when EmptyPage error occurs.
+ """
+ return render_to_response(
+ 'postorius/errors/generic.html',
+ {'error': "Out of bounds. Page contains no results."},
+ context_instance=RequestContext(request))
=== modified file 'src/postorius/views/__init__.py'
--- src/postorius/views/__init__.py 2012-11-18 19:51:08 +0000
+++ src/postorius/views/__init__.py 2013-07-18 12:32:23 +0000
@@ -16,7 +16,6 @@
# You should have received a copy of the GNU General Public License along with
# Postorius. If not, see <http://www.gnu.org/licenses/>.
-from postorius.views.api import *
from postorius.views.list import *
from postorius.views.settings import *
from postorius.views.user import *
=== removed file 'src/postorius/views/api.py'
--- src/postorius/views/api.py 2013-05-31 02:21:38 +0000
+++ src/postorius/views/api.py 1970-01-01 00:00:00 +0000
@@ -1,60 +0,0 @@
-# -*- 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
-
-
-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 = utils.get_client()
- res, content = client._connection.call('lists')
- return HttpResponse(json.dumps(content['entries']),
- content_type="application/json")
=== modified file 'src/postorius/views/generic.py'
--- src/postorius/views/generic.py 2013-05-31 02:21:38 +0000
+++ src/postorius/views/generic.py 2013-07-18 12:32:23 +0000
@@ -21,25 +21,14 @@
from django.shortcuts import render_to_response, redirect
from django.template import Context, loader, RequestContext
from django.views.generic import TemplateView, View
-from mailmanclient import Client
-from postorius.models import (Domain, List, Member, MailmanUser,
- MailmanApiError, Mailman404Error)
from postorius import utils
-
-class MailmanClientMixin(object):
- """Adds a mailmanclient.Client instance."""
-
- def client(self):
- if getattr(self._client, '_client', None) is None:
- self._client = utils.get_client()
- return self._client
-
-
-class MailingListView(TemplateView, MailmanClientMixin):
- """A generic view for everything based on a mailman.client
- list object.
+from public_rest.models import MailingList as List, Domain, User as MailmanUser
+
+
+class MailingListView(TemplateView):
+ """A generic view for everything based on a list object.
Sets self.mailing_list to list object if fqdn_listname in **kwargs.
"""
@@ -50,14 +39,15 @@
def _is_list_owner(self, user, mailing_list):
if not user.is_authenticated():
return False
- if user.email in mailing_list.owners:
+ # Check if a User is in list owners (Subscriber objects)
+ if user in [x.user for x in mailing_list.owners]:
return True
return False
def _is_list_moderator(self, user, mailing_list):
if not user.is_authenticated():
return False
- if user.email in mailing_list.moderators:
+ if user in [x.user for x in mailing_list.moderators]:
return True
return False
@@ -67,7 +57,7 @@
try:
self.mailing_list = self._get_list(kwargs['fqdn_listname'],
int(kwargs.get('page', 1)))
- except MailmanApiError:
+ except Http404:
return utils.render_api_error(request)
request.user.is_list_owner = self._is_list_owner(
request.user, self.mailing_list)
@@ -79,21 +69,21 @@
return super(MailingListView, self).dispatch(request, *args, **kwargs)
-class MailmanUserView(TemplateView, MailmanClientMixin):
- """A generic view for everything based on a mailman.client
- user object.
+class MailmanUserView(TemplateView):
+ """A generic view for everything based on a user object.
Sets self.mm_user to list object if user_id in **kwargs.
"""
def _get_first_address(self, user_obj):
- for address in user_obj.addresses:
- return address
+ if user_obj.emails.count() != 0:
+ for address in user_obj.emails:
+ return address
def _get_user(self, user_id):
try:
- user_obj = MailmanUser.objects.get(address=user_id)
- except Mailman404Error:
+ user_obj = MailmanUser.objects.get(user_id=user_id)
+ except MailmanUser.DoesNotExist:
user_obj = None
# replace display_name with first address if display_name is not set
if user_obj is not None:
@@ -101,7 +91,7 @@
user_obj.display_name = ''
user_obj.first_address = self._get_first_address(user_obj)
return user_obj
-
+
def _get_list(self, list_id):
if getattr(self, 'lists', None) is None:
self.lists = {}
@@ -110,22 +100,9 @@
return self.lists[list_id]
def _get_memberships(self):
- memberships = []
- if (self.mm_user):
- for a in self.mm_user.addresses:
- members = self.client()._connection.call('members/find',
- {'subscriber': a})
- try:
- 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))
- except KeyError:
- pass
- return memberships
+ if self.mm_user:
+ return self.mm_user.subscriptions
+ return []
def dispatch(self, request, *args, **kwargs):
# get the user object.
@@ -133,13 +110,9 @@
if 'user_id' in kwargs:
user_id = kwargs['user_id']
elif request.user.is_authenticated():
- user_id = request.user.email
+ user_id = request.user.user_id
if user_id is not None:
- try:
- self.mm_user = self._get_user(user_id)
- except MailmanApiError:
- return utils.render_api_error(request)
-
+ self.mm_user = self._get_user(user_id)
# set the template
if 'template' in kwargs:
self.template = kwargs['template']
=== modified file 'src/postorius/views/list.py'
--- src/postorius/views/list.py 2013-07-14 20:39:16 +0000
+++ src/postorius/views/list.py 2013-07-18 12:32:23 +0000
@@ -21,6 +21,7 @@
from django.contrib.auth.decorators import (login_required,
user_passes_test)
from django.core.urlresolvers import reverse
+from django.core.paginator import Paginator, EmptyPage
from django.shortcuts import render_to_response, redirect
from django.template import RequestContext
from django.utils.decorators import method_decorator
@@ -28,12 +29,11 @@
from urllib2 import HTTPError
from postorius import utils
-from postorius.models import (Domain, List, MailmanUser,
- MailmanApiError)
from postorius.forms import *
from postorius.auth.decorators import *
from postorius.views.generic import MailingListView
+from public_rest.models import MailingList as List, Domain
class ListMembersView(MailingListView):
"""Display all members of a given list.
@@ -41,7 +41,11 @@
def _get_list(self, fqdn_listname, page):
m_list = super(ListMembersView, self)._get_list(fqdn_listname, page)
- m_list.member_page = m_list.get_member_page(25, page)
+ p = Paginator(m_list.members, 25) # show 25 members per page
+ try:
+ m_list.member_page = p.page(page)
+ except EmptyPage:
+ m_list.member_page = p.page(p.num_pages) # TODO: Render Exception, pass in request object.
m_list.member_page_nr = page
m_list.member_page_previous_nr = page - 1
m_list.member_page_next_nr = page + 1
@@ -109,7 +113,7 @@
"""
def get(self, request, fqdn_listname):
- user_email = getattr(request.user, 'email', None)
+ user_email = request.user.emails[0] #XXX
return render_to_response(
'postorius/lists/summary.html',
{'list': self.mailing_list,
@@ -133,8 +137,6 @@
else:
messages.error(request, 'Something went wrong. '
'Please try again.')
- except MailmanApiError:
- return utils.render_api_error(request)
except HTTPError, e:
messages.error(request, e.msg)
return redirect('list_summary', self.mailing_list.fqdn_listname)
@@ -151,9 +153,7 @@
messages.success(request,
'%s has been unsubscribed from this list.' %
email)
- except MailmanApiError:
- return utils.render_api_error(request)
- except ValueError, e:
+ except Exception, e:
messages.error(request, e)
return redirect('list_summary', self.mailing_list.fqdn_listname)
@@ -187,21 +187,19 @@
request,
'The address %s has been subscribed to %s.' %
(email, self.mailing_list.fqdn_listname))
- except MailmanApiError:
- return utils.render_api_error(request)
- except HTTPError, e:
- messages.error(request, e)
+ except Exception as e:
+ print('{0} - {1}'.format(type(e), str(e)))
+ return utils.render_error(request,
+ "Could not subscribe the address")
return redirect('mass_subscribe', self.mailing_list.fqdn_listname)
def _get_choosable_domains(request):
- try:
- domains = Domain.objects.all()
- except MailmanApiError:
- return utils.render_api_error(request)
+ domains = Domain.objects.all()
choosable_domains = [("", _("Choose a Domain"))]
- for domain in domains:
- choosable_domains.append((domain.mail_host,
- domain.mail_host))
+ if domains.count() != 0:
+ for domain in domains:
+ choosable_domains.append((domain.mail_host,
+ domain.mail_host))
return choosable_domains
@login_required
@@ -226,13 +224,12 @@
mail_host=form.cleaned_data['mail_host'])
#creating the list
try:
- mailing_list = domain.create_list(
- form.cleaned_data['listname'])
+ mailing_list = domain.create_list(list_name=form.cleaned_data['listname'],
+ display_name=form.cleaned_data['listname']) # Make it a separate form field?
list_settings = mailing_list.settings
- list_settings["description"] = form.cleaned_data['description']
- list_settings["owner_address"] = \
- form.cleaned_data['list_owner']
- list_settings["advertised"] = form.cleaned_data['advertised']
+ list_settings.description = form.cleaned_data['description']
+ list_settings.owner_address = form.cleaned_data['list_owner']
+ list_settings.advertised = form.cleaned_data['advertised']
list_settings.save()
messages.success(request, _("List created"))
return redirect("list_summary",
@@ -247,7 +244,7 @@
else:
choosable_domains = _get_choosable_domains(request)
form = ListNew(choosable_domains,
- initial={'list_owner': request.user.email})
+ initial={'list_owner': request.user.emails[0]})
return render_to_response(template, {'form': form},
context_instance=RequestContext(request))
@@ -260,10 +257,7 @@
only_public = True
if request.user.is_superuser:
only_public = False
- try:
- lists = List.objects.all(only_public=only_public)
- except MailmanApiError:
- return utils.render_api_error(request)
+ lists = List.objects.all(only_public=only_public)
choosable_domains = _get_choosable_domains(request)
if request.method == 'POST':
return redirect("list_summary", fqdn_listname=request.POST["list"])
@@ -294,12 +288,10 @@
if request.POST.get('fqdn_listname', ''):
fqdn_listname = request.POST.get('fqdn_listname', '')
# connect REST and catch issues getting the list
- try:
- the_list = List.objects.get_or_404(fqdn_listname=fqdn_listname)
- except AttributeError, e:
- return render_to_response('postorius/errors/generic.html',
- {'error': "Mailman REST API not available. Please start Mailman core."},
- context_instance=RequestContext(request))
+ the_list = List.objects.get_or_404(fqdn_listname=fqdn_listname)
+ return render_to_response('postorius/errors/generic.html',
+ {'error': "Mailman REST API not available. Please start Mailman core."},
+ context_instance=RequestContext(request))
# process submitted form
if request.method == 'POST':
form = False
@@ -319,7 +311,7 @@
{'list': the_list, 'option': option,
'message': _("Subscribed ") + email},
context_instance=RequestContext(request))
- except HTTPError, e:
+ except ValueError, e:
return render_to_response(
'postorius/errors/generic.html',
{'error': e},
@@ -379,10 +371,7 @@
def list_delete(request, fqdn_listname):
"""Deletes a list but asks for confirmation first.
"""
- try:
- the_list = List.objects.get_or_404(fqdn_listname=fqdn_listname)
- except MailmanApiError:
- return utils.render_api_error(request)
+ the_list = List.objects.get_or_404(fqdn_listname=fqdn_listname)
if request.method == 'POST':
the_list.delete()
return redirect("list_index")
@@ -401,10 +390,7 @@
def list_held_messages(request, fqdn_listname):
"""Shows a list of held messages.
"""
- try:
- the_list = List.objects.get_or_404(fqdn_listname=fqdn_listname)
- except MailmanApiError:
- return utils.render_api_error(request)
+ the_list = List.objects.get_or_404(fqdn_listname=fqdn_listname)
return render_to_response('postorius/lists/held_messages.html',
{'list': the_list},
context_instance=RequestContext(request))
@@ -417,9 +403,7 @@
try:
the_list = List.objects.get_or_404(fqdn_listname=fqdn_listname)
the_list.accept_message(msg_id)
- except MailmanApiError:
- return utils.render_api_error(request)
- except HTTPError, e:
+ except Http404, e:
messages.error(request, e.msg)
return redirect('list_held_messages', the_list.fqdn_listname)
messages.success(request, 'The message has been accepted.')
@@ -433,9 +417,7 @@
try:
the_list = List.objects.get_or_404(fqdn_listname=fqdn_listname)
the_list.discard_message(msg_id)
- except MailmanApiError:
- return utils.render_api_error(request)
- except HTTPError, e:
+ except Http404, e:
messages.error(request, e.msg)
return redirect('list_held_messages', the_list.fqdn_listname)
messages.success(request, 'The message has been discarded.')
@@ -449,9 +431,7 @@
try:
the_list = List.objects.get_or_404(fqdn_listname=fqdn_listname)
the_list.defer_message(msg_id)
- except MailmanApiError:
- return utils.render_api_error(request)
- except HTTPError, e:
+ except Http404, e:
messages.error(request, e.msg)
return redirect('list_held_messages', the_list.fqdn_listname)
messages.success(request, 'The message has been defered.')
@@ -465,9 +445,7 @@
try:
the_list = List.objects.get_or_404(fqdn_listname=fqdn_listname)
the_list.reject_message(msg_id)
- except MailmanApiError:
- return utils.render_api_error(request)
- except HTTPError, e:
+ except Http404, e:
messages.error(request, e.msg)
return redirect('list_held_messages', the_list.fqdn_listname)
messages.success(request, 'The message has been rejected.')
@@ -494,8 +472,8 @@
form_sections = []
try:
the_list = List.objects.get_or_404(fqdn_listname=fqdn_listname)
- except MailmanApiError:
- return utils.render_api_error(request)
+ except Http404, e:
+ return utils.render_error(request, e.msg)
#collect all Form sections for the links:
temp = ListSettings('', '')
for section in temp.layout:
@@ -512,8 +490,12 @@
if form.is_valid():
list_settings = the_list.settings
for key in form.fields.keys():
- list_settings[key] = form.cleaned_data[key]
- list_settings.save()
+ if 'acceptable_alias' in key:
+ for alias in form.cleaned_data[key]:
+ list_settings.add_alias(alias)
+ else:
+ list_settings[key] = form.cleaned_data[key]
+ list_settings.save()
message = _("The list settings have been updated.")
else:
message = _("Validation Error - The list settings have not been updated.")
=== modified file 'src/postorius/views/settings.py'
--- src/postorius/views/settings.py 2013-05-31 02:21:38 +0000
+++ src/postorius/views/settings.py 2013-07-18 12:32:23 +0000
@@ -30,6 +30,7 @@
SetPasswordForm, PasswordChangeForm)
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
+from django.db import IntegrityError
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render_to_response, redirect
from django.template import Context, loader, RequestContext
@@ -37,14 +38,12 @@
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
+from public_rest.models import MailingList as List, Domain
@login_required
@user_passes_test(lambda u: u.is_superuser)
@@ -56,10 +55,7 @@
@login_required
@user_passes_test(lambda u: u.is_superuser)
def domain_index(request):
- try:
- existing_domains = Domain.objects.all()
- except MailmanApiError:
- return utils.render_api_error(request)
+ existing_domains = Domain.objects.all()
return render_to_response('postorius/domain_index.html',
{'domains': existing_domains},
context_instance=RequestContext(request))
@@ -77,12 +73,10 @@
description=form.cleaned_data['description'])
try:
domain.save()
- except MailmanApiError:
- return utils.render_api_error(request)
- except HTTPError, e:
- messages.error(request, e)
- else:
- messages.success(request, _("New Domain registered"))
+ except IntegrityError:
+ return utils.render_error(request,
+ "Domain could not be registered.")
+ messages.success(request, _("New Domain registered"))
return redirect("domain_index")
else:
form = DomainNew()
@@ -95,12 +89,12 @@
"""
if request.method == 'POST':
try:
- client = utils.get_client()
- client.delete_domain(domain)
+ d = Domain.objects.get(mail_host=domain)
+ d.delete()
messages.success(request,
_('The domain %s has been deleted.' % domain))
return redirect("domain_index")
- except HTTPError as e:
+ except Domain.DoesNotExist as e:
print e.__dict__
messages.error(request, _('The domain could not be deleted:'
' %s' % e.msg))
=== modified file 'src/postorius/views/user.py'
--- src/postorius/views/user.py 2013-07-11 14:35:41 +0000
+++ src/postorius/views/user.py 2013-07-18 12:32:23 +0000
@@ -31,8 +31,9 @@
user_passes_test)
from django.contrib.auth.forms import (AuthenticationForm, PasswordResetForm,
SetPasswordForm, PasswordChangeForm)
-from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
+from django.core.paginator import Paginator, EmptyPage
+from django.db import IntegrityError
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render_to_response, redirect
from django.template import Context, loader, RequestContext
@@ -41,12 +42,11 @@
from urllib2 import HTTPError
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
+from public_rest.models import User
class UserMailmanSettingsView(MailmanUserView):
"""The logged-in user's Mailman Preferences."""
@@ -58,10 +58,10 @@
@method_decorator(login_required)
def get(self, request):
try:
- mm_user = MailmanUser.objects.get(address=request.user.email)
- except MailmanApiError:
- return utils.render_api_error(request)
- except Mailman404Error:
+ mm_user = User.objects.get(user_id=request.user.user_id)
+ except User.DoesNotExist:
+ return utils.render_error(request, "User was not found!")
+ except Mailman404Error: # XXX
# If the user cannot be found (because there are no
# memberships yet for the logged-in # user), return a
# settings page with a short message only.
@@ -109,9 +109,11 @@
page = int(page)
error = None
try:
- mm_user_page = utils.get_client().get_user_page(25, page)
- except MailmanApiError:
- return utils.render_api_error(request)
+ users = User.objects.all()
+ p = Paginator(users, 25)
+ mm_user_page = p.page(page)
+ except EmptyPage:
+ return utils.render_pagination_error(request)
return render_to_response(
template,
{'error': error,
@@ -129,14 +131,16 @@
if request.method == 'POST':
form = UserNew(request.POST)
if form.is_valid():
- user = MailmanUser(display_name=form.cleaned_data['display_name'],
- email=form.cleaned_data['email'],
- password=form.cleaned_data['password'])
- try:
- user.save()
- except MailmanApiError:
- return utils.render_api_error(request)
- except HTTPError, e:
+ u = User(display_name=form.cleaned_data['display_name'])
+ try:
+ u.save()
+ except IntegrityError, e:
+ messages.error(request, e)
+ return redirect('user_index')
+ try:
+ u.add_email(form.cleaned_data['email'])
+ u.set_password(form.cleaned_data['password'])
+ except ValueError, e:
messages.error(request, e)
else:
messages.success(request, _("New User registered"))
@@ -156,12 +160,15 @@
def user_login(request, template='postorius/login.html'):
if request.method == 'POST':
form = AuthenticationForm(request.POST)
- user = authenticate(username=request.POST.get('username'),
+ user = authenticate(display_name=request.POST.get('username'),
password=request.POST.get('password'))
if user is not None:
if user.is_active:
login(request, user)
return redirect(request.GET.get('next', 'list_index'))
+ else:
+ return utils.render_error(request,
+ "Invalid login! :(")
else:
form = AuthenticationForm()
return render_to_response(template, {'form': form},
@@ -172,12 +179,16 @@
def user_profile(request, user_email=None):
if not request.user.is_authenticated():
return redirect('user_login')
- #try:
- # the_user = User.objects.get(email=user_email)
- #except MailmanApiError:
- # return utils.render_api_error(request)
+ if user_email is None:
+ the_user = request.user
+ else:
+ try:
+ the_user = User.objects.get(email__address=user_email)
+ except User.DoesNotExist:
+ return utils.render_error(request,
+ "User with the given email address not found!")
return render_to_response('postorius/user_profile.html',
- # {'mm_user': the_user},
+ # {'user': the_user },
context_instance=RequestContext(request))
@@ -190,18 +201,19 @@
def more_info_tab(request, formid=None, helpid=None, template='postorius/more_info_display.html'):
"""Displays more_info in new tab.
"""
-
+
if(formid == 'list_settings'):
form = ListSettings(visible_section='List Identity', visible_option='None', data=request.POST)
-
+
for field in form:
if field.name == helpid:
help_text = field.help_text
-
+
return render_to_response(template,
{'help_text':help_text,
'helpid':helpid},
context_instance=RequestContext(request))
+<<<<<<< TREE
@user_passes_test(lambda u: u.is_superuser)
@@ -231,3 +243,6 @@
return render_to_response(template,
{'user_id': user_id, 'email_id': email_id},
context_instance=RequestContext(request))
+=======
+
+>>>>>>> MERGE-SOURCE
=== modified file 'src/postorius/views/views.py'
--- src/postorius/views/views.py 2012-11-18 19:51:08 +0000
+++ src/postorius/views/views.py 2013-07-18 12:32:23 +0000
@@ -40,10 +40,7 @@
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
_______________________________________________
Mailman-coders mailing list
[email protected]
http://mail.python.org/mailman/listinfo/mailman-coders