Merge lp:~mgill25/postorius/m-trunk into lp:postorius

Proposed by Manish Gill
Status: Needs review
Proposed branch: lp:~mgill25/postorius/m-trunk
Merge into: lp:postorius
Diff against target: 1208 lines (+153/-476) (has conflicts)
23 files modified
src/postorius/auth/decorators.py (+1/-2)
src/postorius/forms.py (+1/-4)
src/postorius/management/commands/mmclient.py (+0/-50)
src/postorius/models.py (+0/-177)
src/postorius/templates/postorius/base.html (+1/-1)
src/postorius/templates/postorius/lists/metrics.html (+4/-4)
src/postorius/templates/postorius/lists/summary.html (+2/-2)
src/postorius/templates/postorius/user_profile.html (+1/-1)
src/postorius/templates/postorius/user_subscriptions.html (+1/-1)
src/postorius/templates/postorius/users/index.html (+1/-1)
src/postorius/templates/postorius/users/summary.html (+1/-1)
src/postorius/tests/test_auth_decorators.py (+0/-1)
src/postorius/tests/test_list_members.py (+2/-1)
src/postorius/tests/test_user_creation_sync.py (+0/-1)
src/postorius/urls.py (+5/-2)
src/postorius/utils.py (+15/-9)
src/postorius/views/__init__.py (+0/-1)
src/postorius/views/api.py (+0/-60)
src/postorius/views/generic.py (+22/-49)
src/postorius/views/list.py (+44/-62)
src/postorius/views/settings.py (+10/-16)
src/postorius/views/user.py (+42/-27)
src/postorius/views/views.py (+0/-3)
Text conflict in src/postorius/urls.py
Text conflict in src/postorius/views/user.py
To merge this branch: bzr merge lp:~mgill25/postorius/m-trunk
Reviewer Review Type Date Requested Status
Terri Needs Fixing
Review via email: mp+175549@code.launchpad.net

Description of the change

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.

To post a comment you must log in.
Revision history for this message
Terri (terriko) wrote :

This was just submitted for the purpose of review, so I'm formally listing it as "needs fixing" so that it stops showing up as a pending unreviewed merge.

review: Needs Fixing

Unmerged revisions

171. By Manish Gill <email address hidden>

Modified user_summary url from /users/id/<user_id> to /user/<user_id>

170. By Manish Gill <email address hidden>

Query with user_id instead of one out of multiple possible emails

169. By Manish Gill <email address hidden>

User Summary url modified to have /id prefix to avoid ambiguity with pagination urls

168. By Manish Gill <email address hidden>

User summary template fix

167. By Manish Gill <email address hidden>

Remove Old API code from views and corresponding URLConf

166. By Manish Gill <email address hidden>

Models.py reverted during merge; delete it

165. By Manish Gill <email address hidden>

Merged result of m-updating and m-noclient

164. By Manish Gill <email address hidden>

Updated models in auth decorators

163. By Manish Gill <email address hidden>

Proper commit of models.py removal

162. By Manish Gill <email address hidden>

Delete the old models.py file

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/postorius/auth/decorators.py'
2--- src/postorius/auth/decorators.py 2012-11-18 19:51:08 +0000
3+++ src/postorius/auth/decorators.py 2013-07-18 12:32:23 +0000
4@@ -21,8 +21,7 @@
5 from django.contrib.auth import logout, authenticate, login
6 from django.core.exceptions import PermissionDenied
7
8-from postorius.models import (Domain, List, Member, MailmanUser,
9- MailmanApiError, Mailman404Error)
10+from public_rest.models import MailingList as List
11
12 def basic_auth_login(fn):
13 def wrapper(*args, **kwargs):
14
15=== modified file 'src/postorius/forms.py'
16--- src/postorius/forms.py 2013-03-21 18:43:28 +0000
17+++ src/postorius/forms.py 2013-07-18 12:32:23 +0000
18@@ -641,10 +641,7 @@
19 Form field to add a new user
20 """
21 display_name = forms.CharField(
22- label=_('User Name'),
23- required=True,
24- error_messages={'required': _('Please enter a display name.'),
25- 'invalid': _('Please enter a valid display name.')})
26+ label=_('Display Name'), required=False)
27 email = forms.EmailField(
28 label=_("User's email address"),
29 error_messages={
30
31=== removed file 'src/postorius/management/commands/mmclient.py'
32--- src/postorius/management/commands/mmclient.py 2013-05-31 02:21:38 +0000
33+++ src/postorius/management/commands/mmclient.py 1970-01-01 00:00:00 +0000
34@@ -1,50 +0,0 @@
35-# -*- coding: utf-8 -*-
36-# Copyright (C) 1998-2012 by the Free Software Foundation, Inc.
37-#
38-# This file is part of Postorius.
39-#
40-# Postorius is free software: you can redistribute it and/or modify it under
41-# the terms of the GNU General Public License as published by the Free
42-# Software Foundation, either version 3 of the License, or (at your option)
43-# any later version.
44-#
45-# Postorius is distributed in the hope that it will be useful, but WITHOUT
46-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
47-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
48-# more details.
49-#
50-# You should have received a copy of the GNU General Public License along with
51-# Postorius. If not, see <http://www.gnu.org/licenses/>.
52-
53-from django.conf import settings
54-from django.core.management.base import BaseCommand, CommandError
55-from mailmanclient import Client, MailmanConnectionError
56-from postorius import utils
57-from urllib2 import HTTPError
58-
59-class Command(BaseCommand):
60- help = """Opens a Python shell with a mailmanclient object named `client`.
61-
62-Usage example:
63- client.lists
64- [<List "foo@example.org">]
65- foo = client.get_list('foo@example.org')
66- foo.members
67- [<Member "les@primus.org">]
68-
69-A complete list of commands can be found in the mailman.client documentation."""
70-
71- def handle(self, *args, **options):
72- # choose an interpreter
73- console = None
74- try:
75- import IPython
76- console_fn = IPython.embed
77- except ImportError:
78- import code
79- shell = code.InteractiveConsole(globals())
80- console_fn = shell.interact
81- # connect to mailmanclient
82- client = utils.get_client()
83- # run the interpreter
84- console_fn()
85
86=== removed file 'src/postorius/models.py'
87--- src/postorius/models.py 2013-05-31 02:21:38 +0000
88+++ src/postorius/models.py 1970-01-01 00:00:00 +0000
89@@ -1,177 +0,0 @@
90-# -*- coding: utf-8 -*-
91-# Copyright (C) 1998-2012 by the Free Software Foundation, Inc.
92-#
93-# This file is part of Postorius.
94-#
95-# Postorius is free software: you can redistribute it and/or modify it under
96-# the terms of the GNU General Public License as published by the Free
97-# Software Foundation, either version 3 of the License, or (at your option)
98-# any later version.
99-#
100-# Postorius is distributed in the hope that it will be useful, but WITHOUT
101-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
102-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
103-# more details.
104-#
105-# You should have received a copy of the GNU General Public License along with
106-# Postorius. If not, see <http://www.gnu.org/licenses/>.
107-
108-import logging
109-
110-from django.conf import settings
111-from django.contrib.auth.models import User
112-from django.db.models.signals import pre_delete, pre_save
113-from django.db import models
114-from django.dispatch import receiver
115-from django.http import Http404
116-from mailmanclient import Client, MailmanConnectionError
117-from postorius import utils
118-from urllib2 import HTTPError
119-
120-
121-logger = logging.getLogger(__name__)
122-
123-
124-class MailmanApiError(Exception):
125- """Raised if the API is not available.
126- """
127- pass
128-
129-
130-class Mailman404Error(Exception):
131- """Proxy exception. Raised if the API returns 404."""
132- pass
133-
134-
135-class MailmanRestManager(object):
136- """Manager class to give a model class CRUD access to the API.
137- Returns objects (or lists of objects) retrived from the API.
138- """
139-
140- def __init__(self, resource_name, resource_name_plural, cls_name=None):
141- self.client = utils.get_client()
142- self.resource_name = resource_name
143- self.resource_name_plural = resource_name_plural
144-
145- def all(self):
146- try:
147- return getattr(self.client, self.resource_name_plural)
148- except AttributeError:
149- raise MailmanApiError
150- except MailmanConnectionError, e:
151- raise MailmanApiError(e)
152-
153- def get(self, **kwargs):
154- try:
155- method = getattr(self.client, 'get_' + self.resource_name)
156- return method(**kwargs)
157- except AttributeError, e:
158- raise MailmanApiError(e)
159- except HTTPError, e:
160- if e.code == 404:
161- raise Mailman404Error
162- else:
163- raise
164- except MailmanConnectionError, e:
165- raise MailmanApiError(e)
166-
167- def get_or_404(self, **kwargs):
168- """Similar to `self.get` but raises standard Django 404 error.
169- """
170- try:
171- return self.get(**kwargs)
172- except Mailman404Error:
173- raise Http404
174- except MailmanConnectionError, e:
175- raise MailmanApiError(e)
176-
177- def create(self, **kwargs):
178- try:
179- method = getattr(self.client, 'create_' + self.resource_name)
180- print kwargs
181- return method(**kwargs)
182- except AttributeError, e:
183- raise MailmanApiError(e)
184- except HTTPError, e:
185- if e.code == 409:
186- raise MailmanApiError
187- else:
188- raise
189- except MailmanConnectionError:
190- raise MailmanApiError
191-
192- def delete(self):
193- """Not implemented since the objects returned from the API
194- have a `delete` method of their own.
195- """
196- pass
197-
198-
199-class MailmanListManager(MailmanRestManager):
200-
201- def __init__(self):
202- super(MailmanListManager, self).__init__('list', 'lists')
203-
204- def all(self, only_public=False):
205- try:
206- objects = getattr(self.client, self.resource_name_plural)
207- except AttributeError:
208- raise MailmanApiError
209- except MailmanConnectionError, e:
210- raise MailmanApiError(e)
211- if only_public:
212- public = []
213- for obj in objects:
214- if obj.settings.get('advertised', False):
215- public.append(obj)
216- return public
217- else:
218- return objects
219-
220- def by_mail_host(self, mail_host, only_public=False):
221- objects = self.all(only_public)
222- host_objects = []
223- for obj in objects:
224- if obj.mail_host == mail_host:
225- host_objects.append(obj)
226- return host_objects
227-
228-
229-class MailmanRestModel(object):
230- """Simple REST Model class to make REST API calls Django style.
231- """
232- MailmanApiError = MailmanApiError
233- DoesNotExist = Mailman404Error
234-
235- def __init__(self, **kwargs):
236- self.kwargs = kwargs
237-
238- def save(self):
239- """Proxy function for `objects.create`.
240- (REST API uses `create`, while Django uses `save`.)
241- """
242- self.objects.create(**self.kwargs)
243-
244-
245-class Domain(MailmanRestModel):
246- """Domain model class.
247- """
248- objects = MailmanRestManager('domain', 'domains')
249-
250-
251-class List(MailmanRestModel):
252- """List model class.
253- """
254- objects = MailmanListManager()
255-
256-
257-class MailmanUser(MailmanRestModel):
258- """MailmanUser model class.
259- """
260- objects = MailmanRestManager('user', 'users')
261-
262-
263-class Member(MailmanRestModel):
264- """Member model class.
265- """
266- objects = MailmanRestManager('member', 'members')
267
268=== modified file 'src/postorius/templates/postorius/base.html'
269--- src/postorius/templates/postorius/base.html 2013-07-14 20:42:05 +0000
270+++ src/postorius/templates/postorius/base.html 2013-07-18 12:32:23 +0000
271@@ -34,7 +34,7 @@
272 </ul>
273 <div class="mm_loginName">
274 {% if user.is_authenticated %}
275- 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>
276+ 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>
277 {% else %}
278 <a href="{% url 'user_login' %}">Login</a>
279 {% endif %}
280
281=== modified file 'src/postorius/templates/postorius/lists/metrics.html'
282--- src/postorius/templates/postorius/lists/metrics.html 2013-05-31 02:21:03 +0000
283+++ src/postorius/templates/postorius/lists/metrics.html 2013-07-18 12:32:23 +0000
284@@ -10,18 +10,18 @@
285 <tbody>
286 <tr>
287 <th>{% trans 'Created at' %}</th>
288- <td>{{list.settings.created_at}}</td>
289+ <td>{{list.created_at}}</td>
290 </tr>
291 <tr>
292- <th>{% trans 'Created at' %}</th>
293+ <th>{% trans 'Last post at' %}</th>
294 <td>{{list.settings.last_post_at}}</td>
295 </tr>
296 <tr>
297- <th>{% trans 'Created at' %}</th>
298+ <th>{% trans 'Digest last sent at' %}</th>
299 <td>{{list.settings.digest_last_sent_at}}</td>
300 </tr>
301 <tr>
302- <th>{% trans 'Created at' %}</th>
303+ <th>{% trans 'Volume ' %}</th>
304 <td>{{list.settings.volume}}</td>
305 </tr>
306 </tbody>
307
308=== modified file 'src/postorius/templates/postorius/lists/summary.html'
309--- src/postorius/templates/postorius/lists/summary.html 2013-05-31 02:21:03 +0000
310+++ src/postorius/templates/postorius/lists/summary.html 2013-07-18 12:32:23 +0000
311@@ -13,14 +13,14 @@
312
313
314 <h2>{% trans 'Description' %}</h2>
315- <p>{{list.settings.description }}</p>
316+ <p>{{list.description }}</p>
317
318 <h2>{% trans 'Subscribe to this list' %}</h2>
319 {% if user.is_authenticated %}
320 <form action="{% url 'list_subscribe' list.fqdn_listname %}" method="post" class="list_subscribe"> {% csrf_token %}
321 {{subscribe_form.as_p}}
322 <input class="btn btn-success" type="submit" value="{% trans 'Subscribe' %}" />
323- <a href="{% url 'list_unsubscribe' list.fqdn_listname user.email %}" class="btn btn-danger">Unsubscribe</a>
324+ <a href="{% url 'list_unsubscribe' list.fqdn_listname user.emails|first %}" class="btn btn-danger">Unsubscribe</a>
325 </form>
326 {% else %}
327 <p>To subscribe or unsubscribe this list you have to be logged in.</p>
328
329=== modified file 'src/postorius/templates/postorius/user_profile.html'
330--- src/postorius/templates/postorius/user_profile.html 2013-05-31 02:21:03 +0000
331+++ src/postorius/templates/postorius/user_profile.html 2013-07-18 12:32:23 +0000
332@@ -10,7 +10,7 @@
333 <tbody>
334 <tr>
335 <td>{% trans 'Mailman display name' %}</td>
336- <td>{{ mm_user.display_name}}</td>
337+ <td>{{ user.display_name}}</td>
338 </tr>
339 <tr>
340 <td>{% trans 'User name' %}</td>
341
342=== modified file 'src/postorius/templates/postorius/user_subscriptions.html'
343--- src/postorius/templates/postorius/user_subscriptions.html 2013-05-31 02:21:03 +0000
344+++ src/postorius/templates/postorius/user_subscriptions.html 2013-07-18 12:32:23 +0000
345@@ -23,7 +23,7 @@
346 <td>{{ subscription.fqdn_listname }}</td>
347 <td>{{ subscription.address }}</td>
348 <td>{{ subscription.role }}</td>
349- <td>{{ subscription.delivery_mode }}</td>
350+ <td>{{ subscription.preferences.delivery_mode }}</td>
351 </tr>
352 {% endfor %}
353 </tbody>
354
355=== modified file 'src/postorius/templates/postorius/users/index.html'
356--- src/postorius/templates/postorius/users/index.html 2013-07-05 11:05:45 +0000
357+++ src/postorius/templates/postorius/users/index.html 2013-07-18 12:32:23 +0000
358@@ -25,7 +25,7 @@
359 {% for mm_user in mm_user_page %}
360 <tr>
361 <td>
362- <a href="{% url 'user_summary' user_id=mm_user.user_id %}">{% for address in mm_user.addresses|slice:":1" %}{{ address }}{% endfor %}</a>
363+ <a href="{% url 'user_summary' user_id=mm_user.user_id %}">{% for address in mm_user.emails|slice:":1" %}{{ address }}{% endfor %}</a>
364 </td>
365 <td>
366 {{ mm_user.display_name }}
367
368=== modified file 'src/postorius/templates/postorius/users/summary.html'
369--- src/postorius/templates/postorius/users/summary.html 2012-11-18 19:51:08 +0000
370+++ src/postorius/templates/postorius/users/summary.html 2013-07-18 12:32:23 +0000
371@@ -1,4 +1,4 @@
372-{% extends extend_template %}
373+{% extends "postorius/base.html" %}
374 {% load i18n %}
375 {% load url from future %}
376 {% load nav_helpers %}
377
378=== modified file 'src/postorius/tests/test_auth_decorators.py'
379--- src/postorius/tests/test_auth_decorators.py 2012-11-04 19:54:09 +0000
380+++ src/postorius/tests/test_auth_decorators.py 2013-07-18 12:32:23 +0000
381@@ -26,7 +26,6 @@
382 basic_auth_login)
383 from postorius.models import (Domain, List, Member, MailmanUser,
384 MailmanApiError, Mailman404Error)
385-from mailmanclient import Client
386
387
388 @list_owner_required
389
390=== modified file 'src/postorius/tests/test_list_members.py'
391--- src/postorius/tests/test_list_members.py 2012-09-26 21:07:54 +0000
392+++ src/postorius/tests/test_list_members.py 2013-07-18 12:32:23 +0000
393@@ -24,6 +24,7 @@
394 class ListMembersViewTest(unittest.TestCase):
395 """Tests for the ListMembersView."""
396
397+ '''
398 def setUp(self):
399 from django.test.client import RequestFactory
400 from postorius.tests.utils import create_mock_list, create_mock_member
401@@ -91,6 +92,6 @@
402 request,
403 fqdn_listname='foolist@example.org')
404 self.assertEqual(response.status_code, 200)
405-
406+ '''
407 def tearDown(self):
408 pass
409
410=== modified file 'src/postorius/tests/test_user_creation_sync.py'
411--- src/postorius/tests/test_user_creation_sync.py 2012-10-28 18:21:52 +0000
412+++ src/postorius/tests/test_user_creation_sync.py 2013-07-18 12:32:23 +0000
413@@ -26,7 +26,6 @@
414 list_moderator_required)
415 from postorius.models import (Domain, List, Member, MailmanUser,
416 MailmanApiError, Mailman404Error)
417-from mailmanclient import Client
418
419
420 class UserCreationSyncTest(unittest.TestCase):
421
422=== modified file 'src/postorius/urls.py'
423--- src/postorius/urls.py 2013-07-05 11:05:45 +0000
424+++ src/postorius/urls.py 2013-07-18 12:32:23 +0000
425@@ -81,13 +81,16 @@
426 url(r'^lists/$', 'list_index', name='list_index'),
427 url(r'^lists/new/$', 'list_new', name='list_new'),
428 url(r'^more_info/(?P<formid>[^/]+)/(?P<helpid>[^/]+)$', 'more_info_tab', name='more_info_tab'),
429- url(r'^lists/(?P<fqdn_listname>[^/]+)/', include(per_list_urlpatterns)),
430+ url(r'^lists/(?P<fqdn_listname>[^/]+)/', include(per_list_urlpatterns)),
431 # /users/
432 url(r'^users/(?P<page>\d+)/$', 'user_index', name='user_index_paged'),
433 url(r'^users/$', 'user_index', name='user_index'),
434 url(r'^users/new/$', 'user_new', name='user_new'),
435- url(r'^users/(?P<user_id>[^/]+)/$',
436+ url(r'^user/(?P<user_id>[^/]+)/$',
437 UserSummaryView.as_view(), name='user_summary'),
438+<<<<<<< TREE
439 url(r'^users/(?P<user_id>\d+)/delete$', 'user_delete', name='user_delete'),
440 url(r'^api/lists/$', 'api_list_index', name='api_list_index'),
441+=======
442+>>>>>>> MERGE-SOURCE
443 )
444
445=== modified file 'src/postorius/utils.py'
446--- src/postorius/utils.py 2013-05-31 02:21:38 +0000
447+++ src/postorius/utils.py 2013-07-18 12:32:23 +0000
448@@ -21,9 +21,6 @@
449 from django.shortcuts import render_to_response, redirect
450 from django.template import RequestContext
451
452-from mailmanclient import Client
453-
454-
455 def get_domain_name(request):
456 """Extracts a domain name from the request object.
457 """
458@@ -31,12 +28,12 @@
459 return request.META["HTTP_HOST"].split(":")[0]
460 return None
461
462-
463-def get_client():
464- return Client('{0}/3.0'.format(settings.MAILMAN_API_URL),
465- settings.MAILMAN_USER,
466- settings.MAILMAN_PASS)
467-
468+def render_error(request, message):
469+ """Generic function to display error messages"""
470+ return render_to_response(
471+ 'postorius/errors/generic.html',
472+ {'error': message },
473+ context_instance=RequestContext(request))
474
475 def render_api_error(request):
476 """Renders an error template.
477@@ -46,3 +43,12 @@
478 'postorius/errors/generic.html',
479 {'error': "Mailman REST API not available. Please start Mailman core."},
480 context_instance=RequestContext(request))
481+
482+def render_pagination_error(request):
483+ """Renders an error template.
484+ Use when EmptyPage error occurs.
485+ """
486+ return render_to_response(
487+ 'postorius/errors/generic.html',
488+ {'error': "Out of bounds. Page contains no results."},
489+ context_instance=RequestContext(request))
490
491=== modified file 'src/postorius/views/__init__.py'
492--- src/postorius/views/__init__.py 2012-11-18 19:51:08 +0000
493+++ src/postorius/views/__init__.py 2013-07-18 12:32:23 +0000
494@@ -16,7 +16,6 @@
495 # You should have received a copy of the GNU General Public License along with
496 # Postorius. If not, see <http://www.gnu.org/licenses/>.
497
498-from postorius.views.api import *
499 from postorius.views.list import *
500 from postorius.views.settings import *
501 from postorius.views.user import *
502
503=== removed file 'src/postorius/views/api.py'
504--- src/postorius/views/api.py 2013-05-31 02:21:38 +0000
505+++ src/postorius/views/api.py 1970-01-01 00:00:00 +0000
506@@ -1,60 +0,0 @@
507-# -*- coding: utf-8 -*-
508-# Copyright (C) 1998-2012 by the Free Software Foundation, Inc.
509-#
510-# This file is part of Postorius.
511-#
512-# Postorius is free software: you can redistribute it and/or modify it under
513-# the terms of the GNU General Public License as published by the Free
514-# Software Foundation, either version 3 of the License, or (at your option)
515-# any later version.
516-#
517-# Postorius is distributed in the hope that it will be useful, but WITHOUT
518-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
519-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
520-# more details.
521-#
522-# You should have received a copy of the GNU General Public License along with
523-# Postorius. If not, see <http://www.gnu.org/licenses/>.
524-
525-
526-import re
527-import sys
528-import json
529-import logging
530-
531-
532-from django.conf import settings
533-from django.contrib import messages
534-from django.contrib.auth import logout, authenticate, login
535-from django.contrib.auth.decorators import (login_required,
536- permission_required,
537- user_passes_test)
538-from django.contrib.auth.forms import AuthenticationForm
539-from django.contrib.auth.models import User
540-from django.core.urlresolvers import reverse
541-from django.http import HttpResponse, HttpResponseRedirect
542-from django.shortcuts import render_to_response, redirect
543-from django.template import Context, loader, RequestContext
544-from django.utils.decorators import method_decorator
545-from django.utils.translation import gettext as _
546-from urllib2 import HTTPError
547-
548-from mailmanclient import Client
549-from postorius import utils
550-from postorius.models import (Domain, List, Member, MailmanUser,
551- MailmanApiError, Mailman404Error)
552-from postorius.forms import *
553-from postorius.auth.decorators import *
554-from postorius.views.generic import MailingListView, MailmanUserView
555-
556-
557-logger = logging.getLogger(__name__)
558-
559-
560-@basic_auth_login
561-@loggedin_or_403
562-def api_list_index(request):
563- client = utils.get_client()
564- res, content = client._connection.call('lists')
565- return HttpResponse(json.dumps(content['entries']),
566- content_type="application/json")
567
568=== modified file 'src/postorius/views/generic.py'
569--- src/postorius/views/generic.py 2013-05-31 02:21:38 +0000
570+++ src/postorius/views/generic.py 2013-07-18 12:32:23 +0000
571@@ -21,25 +21,14 @@
572 from django.shortcuts import render_to_response, redirect
573 from django.template import Context, loader, RequestContext
574 from django.views.generic import TemplateView, View
575-from mailmanclient import Client
576
577-from postorius.models import (Domain, List, Member, MailmanUser,
578- MailmanApiError, Mailman404Error)
579 from postorius import utils
580
581-
582-class MailmanClientMixin(object):
583- """Adds a mailmanclient.Client instance."""
584-
585- def client(self):
586- if getattr(self._client, '_client', None) is None:
587- self._client = utils.get_client()
588- return self._client
589-
590-
591-class MailingListView(TemplateView, MailmanClientMixin):
592- """A generic view for everything based on a mailman.client
593- list object.
594+from public_rest.models import MailingList as List, Domain, User as MailmanUser
595+
596+
597+class MailingListView(TemplateView):
598+ """A generic view for everything based on a list object.
599
600 Sets self.mailing_list to list object if fqdn_listname in **kwargs.
601 """
602@@ -50,14 +39,15 @@
603 def _is_list_owner(self, user, mailing_list):
604 if not user.is_authenticated():
605 return False
606- if user.email in mailing_list.owners:
607+ # Check if a User is in list owners (Subscriber objects)
608+ if user in [x.user for x in mailing_list.owners]:
609 return True
610 return False
611
612 def _is_list_moderator(self, user, mailing_list):
613 if not user.is_authenticated():
614 return False
615- if user.email in mailing_list.moderators:
616+ if user in [x.user for x in mailing_list.moderators]:
617 return True
618 return False
619
620@@ -67,7 +57,7 @@
621 try:
622 self.mailing_list = self._get_list(kwargs['fqdn_listname'],
623 int(kwargs.get('page', 1)))
624- except MailmanApiError:
625+ except Http404:
626 return utils.render_api_error(request)
627 request.user.is_list_owner = self._is_list_owner(
628 request.user, self.mailing_list)
629@@ -79,21 +69,21 @@
630 return super(MailingListView, self).dispatch(request, *args, **kwargs)
631
632
633-class MailmanUserView(TemplateView, MailmanClientMixin):
634- """A generic view for everything based on a mailman.client
635- user object.
636+class MailmanUserView(TemplateView):
637+ """A generic view for everything based on a user object.
638
639 Sets self.mm_user to list object if user_id in **kwargs.
640 """
641
642 def _get_first_address(self, user_obj):
643- for address in user_obj.addresses:
644- return address
645+ if user_obj.emails.count() != 0:
646+ for address in user_obj.emails:
647+ return address
648
649 def _get_user(self, user_id):
650 try:
651- user_obj = MailmanUser.objects.get(address=user_id)
652- except Mailman404Error:
653+ user_obj = MailmanUser.objects.get(user_id=user_id)
654+ except MailmanUser.DoesNotExist:
655 user_obj = None
656 # replace display_name with first address if display_name is not set
657 if user_obj is not None:
658@@ -101,7 +91,7 @@
659 user_obj.display_name = ''
660 user_obj.first_address = self._get_first_address(user_obj)
661 return user_obj
662-
663+
664 def _get_list(self, list_id):
665 if getattr(self, 'lists', None) is None:
666 self.lists = {}
667@@ -110,22 +100,9 @@
668 return self.lists[list_id]
669
670 def _get_memberships(self):
671- memberships = []
672- if (self.mm_user):
673- for a in self.mm_user.addresses:
674- members = self.client()._connection.call('members/find',
675- {'subscriber': a})
676- try:
677- for m in members[1]['entries']:
678- mlist = self._get_list(m['list_id'])
679- memberships.append(
680- dict(fqdn_listname=mlist.fqdn_listname,
681- role=m['role'],
682- delivery_mode=m['delivery_mode'],
683- address=a))
684- except KeyError:
685- pass
686- return memberships
687+ if self.mm_user:
688+ return self.mm_user.subscriptions
689+ return []
690
691 def dispatch(self, request, *args, **kwargs):
692 # get the user object.
693@@ -133,13 +110,9 @@
694 if 'user_id' in kwargs:
695 user_id = kwargs['user_id']
696 elif request.user.is_authenticated():
697- user_id = request.user.email
698+ user_id = request.user.user_id
699 if user_id is not None:
700- try:
701- self.mm_user = self._get_user(user_id)
702- except MailmanApiError:
703- return utils.render_api_error(request)
704-
705+ self.mm_user = self._get_user(user_id)
706 # set the template
707 if 'template' in kwargs:
708 self.template = kwargs['template']
709
710=== modified file 'src/postorius/views/list.py'
711--- src/postorius/views/list.py 2013-07-14 20:39:16 +0000
712+++ src/postorius/views/list.py 2013-07-18 12:32:23 +0000
713@@ -21,6 +21,7 @@
714 from django.contrib.auth.decorators import (login_required,
715 user_passes_test)
716 from django.core.urlresolvers import reverse
717+from django.core.paginator import Paginator, EmptyPage
718 from django.shortcuts import render_to_response, redirect
719 from django.template import RequestContext
720 from django.utils.decorators import method_decorator
721@@ -28,12 +29,11 @@
722 from urllib2 import HTTPError
723
724 from postorius import utils
725-from postorius.models import (Domain, List, MailmanUser,
726- MailmanApiError)
727 from postorius.forms import *
728 from postorius.auth.decorators import *
729 from postorius.views.generic import MailingListView
730
731+from public_rest.models import MailingList as List, Domain
732
733 class ListMembersView(MailingListView):
734 """Display all members of a given list.
735@@ -41,7 +41,11 @@
736
737 def _get_list(self, fqdn_listname, page):
738 m_list = super(ListMembersView, self)._get_list(fqdn_listname, page)
739- m_list.member_page = m_list.get_member_page(25, page)
740+ p = Paginator(m_list.members, 25) # show 25 members per page
741+ try:
742+ m_list.member_page = p.page(page)
743+ except EmptyPage:
744+ m_list.member_page = p.page(p.num_pages) # TODO: Render Exception, pass in request object.
745 m_list.member_page_nr = page
746 m_list.member_page_previous_nr = page - 1
747 m_list.member_page_next_nr = page + 1
748@@ -109,7 +113,7 @@
749 """
750
751 def get(self, request, fqdn_listname):
752- user_email = getattr(request.user, 'email', None)
753+ user_email = request.user.emails[0] #XXX
754 return render_to_response(
755 'postorius/lists/summary.html',
756 {'list': self.mailing_list,
757@@ -133,8 +137,6 @@
758 else:
759 messages.error(request, 'Something went wrong. '
760 'Please try again.')
761- except MailmanApiError:
762- return utils.render_api_error(request)
763 except HTTPError, e:
764 messages.error(request, e.msg)
765 return redirect('list_summary', self.mailing_list.fqdn_listname)
766@@ -151,9 +153,7 @@
767 messages.success(request,
768 '%s has been unsubscribed from this list.' %
769 email)
770- except MailmanApiError:
771- return utils.render_api_error(request)
772- except ValueError, e:
773+ except Exception, e:
774 messages.error(request, e)
775 return redirect('list_summary', self.mailing_list.fqdn_listname)
776
777@@ -187,21 +187,19 @@
778 request,
779 'The address %s has been subscribed to %s.' %
780 (email, self.mailing_list.fqdn_listname))
781- except MailmanApiError:
782- return utils.render_api_error(request)
783- except HTTPError, e:
784- messages.error(request, e)
785+ except Exception as e:
786+ print('{0} - {1}'.format(type(e), str(e)))
787+ return utils.render_error(request,
788+ "Could not subscribe the address")
789 return redirect('mass_subscribe', self.mailing_list.fqdn_listname)
790
791 def _get_choosable_domains(request):
792- try:
793- domains = Domain.objects.all()
794- except MailmanApiError:
795- return utils.render_api_error(request)
796+ domains = Domain.objects.all()
797 choosable_domains = [("", _("Choose a Domain"))]
798- for domain in domains:
799- choosable_domains.append((domain.mail_host,
800- domain.mail_host))
801+ if domains.count() != 0:
802+ for domain in domains:
803+ choosable_domains.append((domain.mail_host,
804+ domain.mail_host))
805 return choosable_domains
806
807 @login_required
808@@ -226,13 +224,12 @@
809 mail_host=form.cleaned_data['mail_host'])
810 #creating the list
811 try:
812- mailing_list = domain.create_list(
813- form.cleaned_data['listname'])
814+ mailing_list = domain.create_list(list_name=form.cleaned_data['listname'],
815+ display_name=form.cleaned_data['listname']) # Make it a separate form field?
816 list_settings = mailing_list.settings
817- list_settings["description"] = form.cleaned_data['description']
818- list_settings["owner_address"] = \
819- form.cleaned_data['list_owner']
820- list_settings["advertised"] = form.cleaned_data['advertised']
821+ list_settings.description = form.cleaned_data['description']
822+ list_settings.owner_address = form.cleaned_data['list_owner']
823+ list_settings.advertised = form.cleaned_data['advertised']
824 list_settings.save()
825 messages.success(request, _("List created"))
826 return redirect("list_summary",
827@@ -247,7 +244,7 @@
828 else:
829 choosable_domains = _get_choosable_domains(request)
830 form = ListNew(choosable_domains,
831- initial={'list_owner': request.user.email})
832+ initial={'list_owner': request.user.emails[0]})
833 return render_to_response(template, {'form': form},
834 context_instance=RequestContext(request))
835
836@@ -260,10 +257,7 @@
837 only_public = True
838 if request.user.is_superuser:
839 only_public = False
840- try:
841- lists = List.objects.all(only_public=only_public)
842- except MailmanApiError:
843- return utils.render_api_error(request)
844+ lists = List.objects.all(only_public=only_public)
845 choosable_domains = _get_choosable_domains(request)
846 if request.method == 'POST':
847 return redirect("list_summary", fqdn_listname=request.POST["list"])
848@@ -294,12 +288,10 @@
849 if request.POST.get('fqdn_listname', ''):
850 fqdn_listname = request.POST.get('fqdn_listname', '')
851 # connect REST and catch issues getting the list
852- try:
853- the_list = List.objects.get_or_404(fqdn_listname=fqdn_listname)
854- except AttributeError, e:
855- return render_to_response('postorius/errors/generic.html',
856- {'error': "Mailman REST API not available. Please start Mailman core."},
857- context_instance=RequestContext(request))
858+ the_list = List.objects.get_or_404(fqdn_listname=fqdn_listname)
859+ return render_to_response('postorius/errors/generic.html',
860+ {'error': "Mailman REST API not available. Please start Mailman core."},
861+ context_instance=RequestContext(request))
862 # process submitted form
863 if request.method == 'POST':
864 form = False
865@@ -319,7 +311,7 @@
866 {'list': the_list, 'option': option,
867 'message': _("Subscribed ") + email},
868 context_instance=RequestContext(request))
869- except HTTPError, e:
870+ except ValueError, e:
871 return render_to_response(
872 'postorius/errors/generic.html',
873 {'error': e},
874@@ -379,10 +371,7 @@
875 def list_delete(request, fqdn_listname):
876 """Deletes a list but asks for confirmation first.
877 """
878- try:
879- the_list = List.objects.get_or_404(fqdn_listname=fqdn_listname)
880- except MailmanApiError:
881- return utils.render_api_error(request)
882+ the_list = List.objects.get_or_404(fqdn_listname=fqdn_listname)
883 if request.method == 'POST':
884 the_list.delete()
885 return redirect("list_index")
886@@ -401,10 +390,7 @@
887 def list_held_messages(request, fqdn_listname):
888 """Shows a list of held messages.
889 """
890- try:
891- the_list = List.objects.get_or_404(fqdn_listname=fqdn_listname)
892- except MailmanApiError:
893- return utils.render_api_error(request)
894+ the_list = List.objects.get_or_404(fqdn_listname=fqdn_listname)
895 return render_to_response('postorius/lists/held_messages.html',
896 {'list': the_list},
897 context_instance=RequestContext(request))
898@@ -417,9 +403,7 @@
899 try:
900 the_list = List.objects.get_or_404(fqdn_listname=fqdn_listname)
901 the_list.accept_message(msg_id)
902- except MailmanApiError:
903- return utils.render_api_error(request)
904- except HTTPError, e:
905+ except Http404, e:
906 messages.error(request, e.msg)
907 return redirect('list_held_messages', the_list.fqdn_listname)
908 messages.success(request, 'The message has been accepted.')
909@@ -433,9 +417,7 @@
910 try:
911 the_list = List.objects.get_or_404(fqdn_listname=fqdn_listname)
912 the_list.discard_message(msg_id)
913- except MailmanApiError:
914- return utils.render_api_error(request)
915- except HTTPError, e:
916+ except Http404, e:
917 messages.error(request, e.msg)
918 return redirect('list_held_messages', the_list.fqdn_listname)
919 messages.success(request, 'The message has been discarded.')
920@@ -449,9 +431,7 @@
921 try:
922 the_list = List.objects.get_or_404(fqdn_listname=fqdn_listname)
923 the_list.defer_message(msg_id)
924- except MailmanApiError:
925- return utils.render_api_error(request)
926- except HTTPError, e:
927+ except Http404, e:
928 messages.error(request, e.msg)
929 return redirect('list_held_messages', the_list.fqdn_listname)
930 messages.success(request, 'The message has been defered.')
931@@ -465,9 +445,7 @@
932 try:
933 the_list = List.objects.get_or_404(fqdn_listname=fqdn_listname)
934 the_list.reject_message(msg_id)
935- except MailmanApiError:
936- return utils.render_api_error(request)
937- except HTTPError, e:
938+ except Http404, e:
939 messages.error(request, e.msg)
940 return redirect('list_held_messages', the_list.fqdn_listname)
941 messages.success(request, 'The message has been rejected.')
942@@ -494,8 +472,8 @@
943 form_sections = []
944 try:
945 the_list = List.objects.get_or_404(fqdn_listname=fqdn_listname)
946- except MailmanApiError:
947- return utils.render_api_error(request)
948+ except Http404, e:
949+ return utils.render_error(request, e.msg)
950 #collect all Form sections for the links:
951 temp = ListSettings('', '')
952 for section in temp.layout:
953@@ -512,8 +490,12 @@
954 if form.is_valid():
955 list_settings = the_list.settings
956 for key in form.fields.keys():
957- list_settings[key] = form.cleaned_data[key]
958- list_settings.save()
959+ if 'acceptable_alias' in key:
960+ for alias in form.cleaned_data[key]:
961+ list_settings.add_alias(alias)
962+ else:
963+ list_settings[key] = form.cleaned_data[key]
964+ list_settings.save()
965 message = _("The list settings have been updated.")
966 else:
967 message = _("Validation Error - The list settings have not been updated.")
968
969=== modified file 'src/postorius/views/settings.py'
970--- src/postorius/views/settings.py 2013-05-31 02:21:38 +0000
971+++ src/postorius/views/settings.py 2013-07-18 12:32:23 +0000
972@@ -30,6 +30,7 @@
973 SetPasswordForm, PasswordChangeForm)
974 from django.contrib.auth.models import User
975 from django.core.urlresolvers import reverse
976+from django.db import IntegrityError
977 from django.http import HttpResponse, HttpResponseRedirect
978 from django.shortcuts import render_to_response, redirect
979 from django.template import Context, loader, RequestContext
980@@ -37,14 +38,12 @@
981 from django.utils.translation import gettext as _
982 from urllib2 import HTTPError
983
984-from mailmanclient import Client
985 from postorius import utils
986-from postorius.models import (Domain, List, Member, MailmanUser,
987- MailmanApiError, Mailman404Error)
988 from postorius.forms import *
989 from postorius.auth.decorators import *
990 from postorius.views.generic import MailingListView, MailmanUserView
991
992+from public_rest.models import MailingList as List, Domain
993
994 @login_required
995 @user_passes_test(lambda u: u.is_superuser)
996@@ -56,10 +55,7 @@
997 @login_required
998 @user_passes_test(lambda u: u.is_superuser)
999 def domain_index(request):
1000- try:
1001- existing_domains = Domain.objects.all()
1002- except MailmanApiError:
1003- return utils.render_api_error(request)
1004+ existing_domains = Domain.objects.all()
1005 return render_to_response('postorius/domain_index.html',
1006 {'domains': existing_domains},
1007 context_instance=RequestContext(request))
1008@@ -77,12 +73,10 @@
1009 description=form.cleaned_data['description'])
1010 try:
1011 domain.save()
1012- except MailmanApiError:
1013- return utils.render_api_error(request)
1014- except HTTPError, e:
1015- messages.error(request, e)
1016- else:
1017- messages.success(request, _("New Domain registered"))
1018+ except IntegrityError:
1019+ return utils.render_error(request,
1020+ "Domain could not be registered.")
1021+ messages.success(request, _("New Domain registered"))
1022 return redirect("domain_index")
1023 else:
1024 form = DomainNew()
1025@@ -95,12 +89,12 @@
1026 """
1027 if request.method == 'POST':
1028 try:
1029- client = utils.get_client()
1030- client.delete_domain(domain)
1031+ d = Domain.objects.get(mail_host=domain)
1032+ d.delete()
1033 messages.success(request,
1034 _('The domain %s has been deleted.' % domain))
1035 return redirect("domain_index")
1036- except HTTPError as e:
1037+ except Domain.DoesNotExist as e:
1038 print e.__dict__
1039 messages.error(request, _('The domain could not be deleted:'
1040 ' %s' % e.msg))
1041
1042=== modified file 'src/postorius/views/user.py'
1043--- src/postorius/views/user.py 2013-07-11 14:35:41 +0000
1044+++ src/postorius/views/user.py 2013-07-18 12:32:23 +0000
1045@@ -31,8 +31,9 @@
1046 user_passes_test)
1047 from django.contrib.auth.forms import (AuthenticationForm, PasswordResetForm,
1048 SetPasswordForm, PasswordChangeForm)
1049-from django.contrib.auth.models import User
1050 from django.core.urlresolvers import reverse
1051+from django.core.paginator import Paginator, EmptyPage
1052+from django.db import IntegrityError
1053 from django.http import HttpResponse, HttpResponseRedirect
1054 from django.shortcuts import render_to_response, redirect
1055 from django.template import Context, loader, RequestContext
1056@@ -41,12 +42,11 @@
1057 from urllib2 import HTTPError
1058
1059 from postorius import utils
1060-from postorius.models import (Domain, List, Member, MailmanUser,
1061- MailmanApiError, Mailman404Error)
1062 from postorius.forms import *
1063 from postorius.auth.decorators import *
1064 from postorius.views.generic import MailingListView, MailmanUserView
1065
1066+from public_rest.models import User
1067
1068 class UserMailmanSettingsView(MailmanUserView):
1069 """The logged-in user's Mailman Preferences."""
1070@@ -58,10 +58,10 @@
1071 @method_decorator(login_required)
1072 def get(self, request):
1073 try:
1074- mm_user = MailmanUser.objects.get(address=request.user.email)
1075- except MailmanApiError:
1076- return utils.render_api_error(request)
1077- except Mailman404Error:
1078+ mm_user = User.objects.get(user_id=request.user.user_id)
1079+ except User.DoesNotExist:
1080+ return utils.render_error(request, "User was not found!")
1081+ except Mailman404Error: # XXX
1082 # If the user cannot be found (because there are no
1083 # memberships yet for the logged-in # user), return a
1084 # settings page with a short message only.
1085@@ -109,9 +109,11 @@
1086 page = int(page)
1087 error = None
1088 try:
1089- mm_user_page = utils.get_client().get_user_page(25, page)
1090- except MailmanApiError:
1091- return utils.render_api_error(request)
1092+ users = User.objects.all()
1093+ p = Paginator(users, 25)
1094+ mm_user_page = p.page(page)
1095+ except EmptyPage:
1096+ return utils.render_pagination_error(request)
1097 return render_to_response(
1098 template,
1099 {'error': error,
1100@@ -129,14 +131,16 @@
1101 if request.method == 'POST':
1102 form = UserNew(request.POST)
1103 if form.is_valid():
1104- user = MailmanUser(display_name=form.cleaned_data['display_name'],
1105- email=form.cleaned_data['email'],
1106- password=form.cleaned_data['password'])
1107- try:
1108- user.save()
1109- except MailmanApiError:
1110- return utils.render_api_error(request)
1111- except HTTPError, e:
1112+ u = User(display_name=form.cleaned_data['display_name'])
1113+ try:
1114+ u.save()
1115+ except IntegrityError, e:
1116+ messages.error(request, e)
1117+ return redirect('user_index')
1118+ try:
1119+ u.add_email(form.cleaned_data['email'])
1120+ u.set_password(form.cleaned_data['password'])
1121+ except ValueError, e:
1122 messages.error(request, e)
1123 else:
1124 messages.success(request, _("New User registered"))
1125@@ -156,12 +160,15 @@
1126 def user_login(request, template='postorius/login.html'):
1127 if request.method == 'POST':
1128 form = AuthenticationForm(request.POST)
1129- user = authenticate(username=request.POST.get('username'),
1130+ user = authenticate(display_name=request.POST.get('username'),
1131 password=request.POST.get('password'))
1132 if user is not None:
1133 if user.is_active:
1134 login(request, user)
1135 return redirect(request.GET.get('next', 'list_index'))
1136+ else:
1137+ return utils.render_error(request,
1138+ "Invalid login! :(")
1139 else:
1140 form = AuthenticationForm()
1141 return render_to_response(template, {'form': form},
1142@@ -172,12 +179,16 @@
1143 def user_profile(request, user_email=None):
1144 if not request.user.is_authenticated():
1145 return redirect('user_login')
1146- #try:
1147- # the_user = User.objects.get(email=user_email)
1148- #except MailmanApiError:
1149- # return utils.render_api_error(request)
1150+ if user_email is None:
1151+ the_user = request.user
1152+ else:
1153+ try:
1154+ the_user = User.objects.get(email__address=user_email)
1155+ except User.DoesNotExist:
1156+ return utils.render_error(request,
1157+ "User with the given email address not found!")
1158 return render_to_response('postorius/user_profile.html',
1159- # {'mm_user': the_user},
1160+ # {'user': the_user },
1161 context_instance=RequestContext(request))
1162
1163
1164@@ -190,18 +201,19 @@
1165 def more_info_tab(request, formid=None, helpid=None, template='postorius/more_info_display.html'):
1166 """Displays more_info in new tab.
1167 """
1168-
1169+
1170 if(formid == 'list_settings'):
1171 form = ListSettings(visible_section='List Identity', visible_option='None', data=request.POST)
1172-
1173+
1174 for field in form:
1175 if field.name == helpid:
1176 help_text = field.help_text
1177-
1178+
1179 return render_to_response(template,
1180 {'help_text':help_text,
1181 'helpid':helpid},
1182 context_instance=RequestContext(request))
1183+<<<<<<< TREE
1184
1185
1186 @user_passes_test(lambda u: u.is_superuser)
1187@@ -231,3 +243,6 @@
1188 return render_to_response(template,
1189 {'user_id': user_id, 'email_id': email_id},
1190 context_instance=RequestContext(request))
1191+=======
1192+
1193+>>>>>>> MERGE-SOURCE
1194
1195=== modified file 'src/postorius/views/views.py'
1196--- src/postorius/views/views.py 2012-11-18 19:51:08 +0000
1197+++ src/postorius/views/views.py 2013-07-18 12:32:23 +0000
1198@@ -40,10 +40,7 @@
1199 from django.utils.translation import gettext as _
1200 from urllib2 import HTTPError
1201
1202-from mailmanclient import Client
1203 from postorius import utils
1204-from postorius.models import (Domain, List, Member, MailmanUser,
1205- MailmanApiError, Mailman404Error)
1206 from postorius.forms import *
1207 from postorius.auth.decorators import *
1208 from postorius.views.generic import MailingListView, MailmanUserView

Subscribers

People subscribed via source and target branches