Révision 323fc37c
Ajouté par Josué Kouka il y a presque 6 ans
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/static/css/corbo.css | ||
---|---|---|
93 | 93 |
padding: 0; |
94 | 94 |
} |
95 | 95 |
|
96 |
ul.objects-list.single-links li { |
|
97 |
padding: 0 1em; |
|
98 |
} |
|
99 |
|
|
96 | 100 |
.actions a:hover { |
97 | 101 |
color: #333; |
98 | 102 |
} |
... | ... | |
166 | 170 |
text-transform: uppercase; |
167 | 171 |
} |
168 | 172 |
|
173 |
.subscriptions-search a { |
|
174 |
float: right; |
|
175 |
} |
|
176 |
|
|
169 | 177 |
.announce_dashboard { |
170 | 178 |
font-size: 1.1em; |
171 | 179 |
margin-left: 0.5em; |
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-search"> |
|
22 |
<p>{% blocktrans %} Subscriptions of <em>{{query}}</em> : {% endblocktrans %}</p> |
|
23 |
<ul class="objects-list single-links"> |
|
24 |
{% for subscription in subscriptions %} |
|
25 |
<li>{{ subscription.category.name}}<a rel="popup" href="{% url 'subscription-delete' pk=subscription.pk %}">{% trans "unsubscribe" %}</a></li> |
|
26 |
{% endfor %} |
|
27 |
</ul> |
|
28 |
</div> |
|
29 |
{% endif %} |
|
30 |
|
|
31 |
{% 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-search'}) is None |
|
373 |
# unknow identifier |
|
374 |
resp.form['q'] = 'toto' |
|
375 |
resp = resp.form.submit() |
|
376 |
assert resp.html.find('div', {'class': 'subscriptions-search'}) 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-search'}).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-search'}).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 |
Formats disponibles : Unified diff
add back office subscription management (#14093)