0001-add-back-office-subscription-management-14093.patch
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 delete <em>{{identifier}}</em> from <em>{{category}}</em> ?{% endblocktrans %}</p> |
|
12 |
<div class="buttons"> |
|
13 |
<button class="delete-button">{% trans 'Delete' %}</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 of 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> </p> |
|
17 |
<span class="help_text"> {% trans "type an email or a phone number" %} </span> |
|
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 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 | ||
---|---|---|
6 | 6 |
from django.utils import timezone |
7 | 7 |
from django.core.urlresolvers import reverse |
8 | 8 |
from django.views.generic import CreateView, UpdateView, DeleteView, \ |
9 |
ListView, TemplateView, RedirectView, DetailView, FormView, RedirectView
|
|
9 |
ListView, TemplateView, RedirectView, DetailView, FormView |
|
10 | 10 |
from django.contrib.syndication.views import Feed |
11 | 11 |
from django.shortcuts import resolve_url |
12 | 12 |
from django.utils.encoding import force_text |
... | ... | |
256 | 256 |
subscriptions_import = SubscriptionsImportView.as_view() |
257 | 257 | |
258 | 258 | |
259 |
class SubscriptionSearchView(TemplateView): |
|
260 | ||
261 |
template_name = 'corbo/subscription_search.html' |
|
262 | ||
263 |
def get_context_data(self, **kwargs): |
|
264 |
context = super(SubscriptionSearchView, self).get_context_data(**kwargs) |
|
265 |
query = self.request.GET.get('q', '').strip() |
|
266 |
context['query'] = query |
|
267 |
if not query: |
|
268 |
return context |
|
269 |
context['subscriptions'] = models.Subscription.objects.filter(identifier='mailto:' + query) |
|
270 |
phonenumber = utils.format_phonenumber(query) |
|
271 |
if not context['subscriptions'] and phonenumber: |
|
272 |
# search by last n digits |
|
273 |
context['subscriptions'] = models.Subscription.objects.filter( |
|
274 |
identifier__endswith=phonenumber[-settings.CORBO_PHONE_SEARCH_DIGITS:]) |
|
275 |
return context |
|
276 | ||
277 | ||
278 |
subscription_search = SubscriptionSearchView.as_view() |
|
279 | ||
280 | ||
281 |
class SubscriptionDeleteView(DeleteView): |
|
282 | ||
283 |
model = models.Subscription |
|
284 |
template_name = 'corbo/subscription_delete.html' |
|
285 | ||
286 |
def get_context_data(self, **kwargs): |
|
287 |
context = super(SubscriptionDeleteView, self).get_context_data(**kwargs) |
|
288 |
context['identifier'] = self.object.identifier.split(':', 1)[1] |
|
289 |
context['category'] = self.object.category.name |
|
290 |
return context |
|
291 | ||
292 |
def get_success_url(self): |
|
293 |
return reverse('subscription-search') |
|
294 | ||
295 | ||
296 |
subscription_delete = SubscriptionDeleteView.as_view() |
|
297 | ||
298 | ||
259 | 299 |
class AnnounceView(DetailView): |
260 | 300 |
model = models.Announce |
261 | 301 |
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 |
|
355 |
- |