Projet

Général

Profil

0001-add-back-office-subscription-management-14093.patch

Josué Kouka, 02 mai 2018 16:03

Télécharger (10,4 ko)

Voir les différences:

Subject: [PATCH] add back office subscription management (#14093)

 corbo/manage_urls.py                           |  6 ++-
 corbo/models.py                                |  3 ++
 corbo/settings.py                              |  3 ++
 corbo/templates/corbo/manage.html              |  1 +
 corbo/templates/corbo/subscription_delete.html | 17 +++++++++
 corbo/templates/corbo/subscription_search.html | 30 +++++++++++++++
 corbo/views.py                                 | 52 +++++++++++++++++++++++++-
 tests/test_manager.py                          | 38 ++++++++++++++++++-
 8 files changed, 147 insertions(+), 3 deletions(-)
 create mode 100644 corbo/templates/corbo/subscription_delete.html
 create mode 100644 corbo/templates/corbo/subscription_search.html
corbo/manage_urls.py
3 3
from .views import add_announce, edit_announce, delete_announce, \
4 4
    add_category, edit_category, view_category, delete_category, manage, \
5 5
    subscriptions_import, view_announce, email_announce, sms_announce, \
6
    menu_json
6
    menu_json, subscription_delete, subscription_search
7 7

  
8 8
urlpatterns = patterns('',
9 9
            url(r'^$', manage, name='manage'),
......
29 29
                name='delete_category'),
30 30
            url(r'^category/(?P<slug>[\w-]+)/import-subscriptions/$', subscriptions_import,
31 31
                name='subscriptions-import'),
32
            url(r'^subscription/delete/(?P<pk>[\w-]+)/$', subscription_delete,
33
                name='subscription-delete'),
34
            url(r'^subscriptions/search$', subscription_search,
35
                name='subscription-search'),
32 36
            url(r'^menu.json$', menu_json),
33 37
)
corbo/models.py
188 188
    identifier = models.CharField(_('identifier'), max_length=128, blank=True,
189 189
                                  help_text=_('ex.: mailto, ...'))
190 190

  
191
    def __unicode__(self):
192
        return '%s - %s - %s' % (self.uuid, self.identifier, self.category.name)
193

  
191 194
    def get_identifier_display(self):
192 195
        try:
193 196
            scheme, identifier = self.identifier.split(':')
corbo/settings.py
192 192
REQUESTS_PROXIES = None
193 193

  
194 194

  
195
CORBO_PHONE_SEARCH_DIGITS = 9
196

  
197

  
195 198
local_settings_file = os.environ.get('CORBO_SETTINGS_FILE',
196 199
        os.path.join(os.path.dirname(__file__), 'local_settings.py'))
197 200
if os.path.exists(local_settings_file):
corbo/templates/corbo/manage.html
12 12
</ul>
13 13
{% endif %}
14 14
<a href="{% url 'add_category' %}" rel='popup'>{% trans 'New category' %}</a>
15
<a href="{% url 'subscription-search' %}">{% trans 'Search subscribers' %}</a>
15 16
{% endblock %}
16 17

  
17 18
{% block content %}
corbo/templates/corbo/subscription_delete.html
1
{% extends "corbo/manage.html" %}
2
{% load i18n %}
3

  
4
{% block appbar %}
5
<h2>{{ view.model.get_verbose_name }}</h2>
6
{% endblock %}
7

  
8
{% block content %}
9
<form method="post">
10
  {% csrf_token %}
11
  <p>{% blocktrans %}Are you sure you want to unsubscribe <em>{{identifier}}</em> from <em>{{category}}</em> ?{% endblocktrans %}</p>
12
  <div class="buttons">
13
      <button class="delete-button">{% trans 'Confirm' %}</button>
14
      <a class="cancel" href="{{ object.get_absolute_url }}">{% trans 'Cancel' %}</a>
15
  </div>
16
</form>
17
{% endblock %}
corbo/templates/corbo/subscription_search.html
1
{% extends "corbo/base.html" %}
2
{% load i18n %}
3

  
4
{% block appbar %}
5
<h2>{% trans "Search subscriptions by email or phone number" %}</h2>
6
{% endblock %}
7

  
8
{% block breadcrumb %}
9
{{ block.super }}
10
<a href="{% url 'subscription-search' %}">{% trans 'Search' %}</a>
11
{% endblock %}
12

  
13
{% block content %}
14

  
15
<form action="{% url 'subscription-search' %}">
16
    <p><input name="q" type="search" value="{{query}}" /> <button>{% trans 'Search' %}</button>
17
    <span class="help_text"> {% trans "(type an email or a phone number)" %} </span></p>
18
</form>
19

  
20
{% if subscriptions %}
21
<div class="subscriptions">
22
    <ul class="objects-list single-links">
23
    {% for subscription in subscriptions %}
24
    <li>{{ subscription.category.name}}<a class="delete" rel="popup" href="{% url 'subscription-delete' pk=subscription.pk %}">{% trans "unsubscribe" %}</a></li>
25
    {% endfor %}
26
    </ul>
27
</div>
28
{% endif %}
29

  
30
{% endblock %}
corbo/views.py
2 2
import json
3 3

  
4 4
from django.conf import settings
5
from django.contrib import messages
5 6
from django.core import signing
6 7
from django.utils import timezone
7 8
from django.core.urlresolvers import reverse
8 9
from django.views.generic import CreateView, UpdateView, DeleteView, \
9
    ListView, TemplateView, RedirectView, DetailView, FormView, RedirectView
10
    ListView, TemplateView, RedirectView, DetailView, FormView
10 11
from django.contrib.syndication.views import Feed
11 12
from django.shortcuts import resolve_url
12 13
from django.utils.encoding import force_text
......
256 257
subscriptions_import = SubscriptionsImportView.as_view()
257 258

  
258 259

  
260
class SubscriptionSearchView(TemplateView):
261

  
262
    template_name = 'corbo/subscription_search.html'
263

  
264
    def get_context_data(self, **kwargs):
265
        context = super(SubscriptionSearchView, self).get_context_data(**kwargs)
266
        query = self.request.GET.get('q', '').strip()
267
        context['query'] = query
268
        if not query:
269
            return context
270
        context['subscriptions'] = models.Subscription.objects.filter(identifier='mailto:' + query)
271
        phonenumber = utils.format_phonenumber(query)
272
        if not context['subscriptions'] and phonenumber:
273
            # search by last n digits
274
            context['subscriptions'] = models.Subscription.objects.filter(
275
                identifier__endswith=phonenumber[-settings.CORBO_PHONE_SEARCH_DIGITS:])
276
        return context
277

  
278

  
279
subscription_search = SubscriptionSearchView.as_view()
280

  
281

  
282
class SubscriptionDeleteView(DeleteView):
283

  
284
    model = models.Subscription
285
    template_name = 'corbo/subscription_delete.html'
286

  
287
    def get_context_data(self, **kwargs):
288
        context = super(SubscriptionDeleteView, self).get_context_data(**kwargs)
289
        context['identifier'] = self.object.identifier.split(':', 1)[1]
290
        context['category'] = self.object.category.name
291
        return context
292

  
293
    def get_success_url(self):
294
        identifier = self.object.identifier.split(':', 1)[1]
295
        return reverse('subscription-search') + '?q=%s' % identifier
296

  
297
    def delete(self, request, *args, **kwargs):
298
        response = super(SubscriptionDeleteView, self).delete(request, *args, **kwargs)
299
        success_message = _('%s successfuly unsubscribed from %s') % (
300
            self.object.identifier.split(':', 1)[1], self.object.category.name)
301
        messages.success(request, success_message)
302
        return response
303

  
304

  
305

  
306
subscription_delete = SubscriptionDeleteView.as_view()
307

  
308

  
259 309
class AnnounceView(DetailView):
260 310
    model = models.Announce
261 311
    template_name = 'corbo/announce_view.html'
tests/test_manager.py
7 7
from django.contrib.auth.models import User
8 8
from django.test import override_settings
9 9

  
10
from corbo.models import Broadcast
10
from corbo.models import Broadcast, Subscription
11
from corbo.utils import format_phonenumber
11 12

  
12 13
pytestmark = pytest.mark.django_db
13 14

  
......
352 353
        assert record.name == 'corbo.utils'
353 354
        assert record.levelno == logging.WARNING
354 355
        assert 'Invalid URL' in record.getMessage()
356

  
357

  
358
@pytest.fixture(params=['foo@example.net', '06 07 08 09 00', '+33 6 07 08 09 00',
359
                '0033607080900', '+33 (0) 6 07 08 09 00', '0033+607080900+'])
360
def search_identifier(request, subscriptions):
361
    return request.param
362

  
363

  
364
def test_subscriptions_search(app, admin_user, search_identifier):
365
    app = login(app)
366
    resp = app.get('/manage/')
367
    resp = resp.click('Search')
368
    if format_phonenumber(search_identifier):
369
        search_identifier = format_phonenumber(search_identifier)[-9:]
370
    # empty search
371
    resp = resp.form.submit()
372
    assert resp.html.find('div', {'class': 'subscriptions'}) is None
373
    # unknow identifier
374
    resp.form['q'] = 'toto'
375
    resp = resp.form.submit()
376
    assert resp.html.find('div', {'class': 'subscriptions'}) is None
377
    # search by email
378
    assert Subscription.objects.filter(identifier__contains=search_identifier).count() == 2
379
    resp.form['q'] = search_identifier
380
    resp = resp.form.submit()
381
    assert len(resp.html.find('div', {'class': 'subscriptions'}).find_all('li')) == 2
382
    # delete sub
383
    first_sub = Subscription.objects.filter(identifier__contains=search_identifier).first()
384
    resp = resp.click(href='/manage/subscription/delete/%d/' % first_sub.pk)
385
    resp = resp.form.submit().follow()
386
    assert Subscription.objects.filter(identifier__contains=search_identifier).count() == 1
387
    # ensure we're back on the previous page with less result
388
    assert len(resp.html.find('div', {'class': 'subscriptions'}).find_all('li')) == 1
389
    assert len(resp.html.find_all('li', {'class': 'success'})) == 1
390
    assert '%s successfuly unsubscribed from' % search_identifier in resp.html.find('li', {'class': 'success'}).text
355
-