add announce view (#15213)
This commit is contained in:
parent
b56be82b22
commit
06620ee794
|
@ -2,7 +2,7 @@ from django.conf.urls import patterns, include, url
|
|||
|
||||
from .views import add_announce, edit_announce, delete_announce, \
|
||||
add_category, edit_category, view_category, delete_category, manage, \
|
||||
subscriptions_import, menu_json
|
||||
subscriptions_import, view_announce, menu_json
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url(r'^$', manage, name='manage'),
|
||||
|
@ -14,6 +14,8 @@ urlpatterns = patterns('',
|
|||
name='delete_announce'),
|
||||
url(r'^category/(?P<slug>[\w-]+)/$', view_category,
|
||||
name='view_category'),
|
||||
url(r'^announce/(?P<pk>\d+)/$', view_announce,
|
||||
name='view_announce'),
|
||||
url(r'^category/add$', add_category,
|
||||
name='add_category'),
|
||||
url(r'^category/edit/(?P<slug>[\w-]+)$', edit_category,
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
def migrate_delivery_count(apps, schema_editor):
|
||||
Broadcast = apps.get_model('corbo', 'Broadcast')
|
||||
for broadcast in Broadcast.objects.all():
|
||||
try:
|
||||
broadcast.delivery_count = int(broadcast.result)
|
||||
except ValueError:
|
||||
broadcast.delivery_count = 0
|
||||
broadcast.save()
|
||||
|
||||
def migrate_result(apps, schema_editor):
|
||||
Broadcast = apps.get_model('corbo', 'Broadcast')
|
||||
for broadcast in Broadcast.objects.all():
|
||||
broadcast.result = str(broadcast.delivery_count)
|
||||
broadcast.save()
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('corbo', '0009_auto_20170120_1533'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunSQL('SET CONSTRAINTS ALL IMMEDIATE',
|
||||
reverse_sql=migrations.RunSQL.noop),
|
||||
migrations.AddField(
|
||||
model_name='broadcast',
|
||||
name='delivery_count',
|
||||
field=models.IntegerField(default=0, verbose_name='Delivery count'),
|
||||
),
|
||||
migrations.RunPython(migrate_delivery_count, migrate_result),
|
||||
migrations.RemoveField(
|
||||
model_name='broadcast',
|
||||
name='result',
|
||||
),
|
||||
migrations.RunSQL(migrations.RunSQL.noop,
|
||||
reverse_sql='SET CONSTRAINTS ALL IMMEDIATE'),
|
||||
]
|
|
@ -161,7 +161,7 @@ class Announce(models.Model):
|
|||
class Broadcast(models.Model):
|
||||
announce = models.ForeignKey(Announce, verbose_name=_('announce'))
|
||||
deliver_time = models.DateTimeField(_('Deliver time'), null=True)
|
||||
result = models.TextField(_('result'), blank=True)
|
||||
delivery_count = models.IntegerField(_('Delivery count'), default=0)
|
||||
|
||||
def __unicode__(self):
|
||||
if self.deliver_time:
|
||||
|
@ -201,7 +201,7 @@ class Broadcast(models.Model):
|
|||
else:
|
||||
logger.warning('Error occured while sending announce "%s" to %s.',
|
||||
self.announce.title, s.identifier)
|
||||
self.result = total_sent
|
||||
self.delivery_count = total_sent
|
||||
self.deliver_time = timezone.now()
|
||||
self.save()
|
||||
|
||||
|
|
|
@ -165,3 +165,36 @@ form ul li label {
|
|||
border-radius: 0.3em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
div.announce_block {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.announce_dashboard {
|
||||
background: #eee;
|
||||
font-size: 1.1em;
|
||||
margin-left: 0.5em;
|
||||
padding: 0.3rem;
|
||||
width: 15%;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.announce_dashboard p {
|
||||
border-bottom: 1px solid #ccc;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.announce_dashboard strong {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.announce_dashboard p:last-child {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
div.announce_preview {
|
||||
width: 84%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
|
|
@ -3,15 +3,15 @@
|
|||
|
||||
{% block breadcrumb %}
|
||||
{{ block.super }}
|
||||
{% if category %}
|
||||
<a href='{% url "view_category" slug=category.slug %}'>{{ category }}</a>
|
||||
{% if object %}
|
||||
<a href='{% url "view_announce" pk=object.pk %}'>{{ object.title }}</a>
|
||||
{% endif %}
|
||||
<a href='{% url "view_category" slug=category.slug %}'>{{ category }}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block appbar %}
|
||||
{% if object %}
|
||||
<h2>{% trans "Edit Announce" %}</h2>
|
||||
<a href='{% url "delete_announce" pk=object.pk %}' rel='popup'>{% trans 'Delete' %}</a>
|
||||
{% else %}
|
||||
<h2>{% trans "New Announce" %}</h2>
|
||||
{% endif %}
|
||||
|
@ -26,7 +26,7 @@
|
|||
{{ form.as_p }}
|
||||
<div class="buttons">
|
||||
<button class="submit-button">{% trans "Save" %}</button>
|
||||
<a class="cancel" href="{% url 'view_category' slug=category.slug %}">{% trans 'Cancel' %}</a>
|
||||
<a class="cancel" href="{% if object %}{% url 'view_announce' pk=object.pk %}{% else %}{% url 'view_category' slug=category.slug %}{% endif %}">{% trans 'Cancel' %}</a>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
<ul class='objects-list single-links'>
|
||||
{% for announce in object_list %}
|
||||
<li class="{% if not announce.is_published %}unpublished{% endif %}">
|
||||
<a href="{% url 'edit_announce' announce.id %}">{{ announce.title }}</a>
|
||||
<a href="{% url 'view_announce' pk=announce.id %}">{{ announce.title }}</a>
|
||||
<div class="datetime">
|
||||
{% if announce.publication_time %}
|
||||
{% blocktrans with mtime=announce.publication_time|date:'DATETIME_FORMAT' %}
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
{% extends "corbo/announce_list.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block breadcrumb %}
|
||||
{{ block.super }}
|
||||
<a href='{% url "view_category" slug=object.category.slug %}'>{{ object.category }}</a>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block appbar %}
|
||||
<h2>{{ object.title }}</h2>
|
||||
<a href="{% url 'delete_announce' pk=object.pk %}" rel="popup">{% trans 'Delete' %}</a>
|
||||
<a href="{% url 'edit_announce' pk=object.pk %}">{% trans 'Edit' %}</a>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div class="announce_block">
|
||||
<div class="announce_preview">
|
||||
{{ object.text|safe }}
|
||||
</div>
|
||||
|
||||
{% if object.publication_time or object.expiration_time or broadcasts %}
|
||||
<div class="announce_dashboard">
|
||||
{% if object.publication_time %}
|
||||
<p>
|
||||
<strong>{% trans "Publication" %}</strong>
|
||||
{{ announce.publication_time|date:'DATETIME_FORMAT' }}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% if object.expiration_time %}
|
||||
<p>
|
||||
<strong>{% trans "Expiration" %}</strong>
|
||||
{{ announce.expiration_time|date:'DATETIME_FORMAT' }}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% if broadcasts %}
|
||||
{% for broadcast in broadcasts %}
|
||||
<p>
|
||||
<strong>{% trans "Sent" %}</strong>
|
||||
{{ broadcast.deliver_time|date:'DATETIME_FORMAT' }}
|
||||
{% blocktrans count delivers=broadcast.delivery_count %}
|
||||
to {{ delivers }} destination
|
||||
{% plural %}
|
||||
to {{ delivers }} destinations
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -87,7 +87,7 @@ class AnnounceEditView(UpdateView):
|
|||
return context
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse('view_category', kwargs={'slug': self.object.category.slug})
|
||||
return reverse('view_announce', kwargs={'pk': self.object.pk})
|
||||
|
||||
|
||||
edit_announce = AnnounceEditView.as_view()
|
||||
|
@ -255,6 +255,19 @@ class SubscriptionsImportView(FormView):
|
|||
subscriptions_import = SubscriptionsImportView.as_view()
|
||||
|
||||
|
||||
class AnnounceView(DetailView):
|
||||
model = models.Announce
|
||||
template_name = 'corbo/announce_view.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(AnnounceView, self).get_context_data(**kwargs)
|
||||
context['category'] = self.object.category
|
||||
context['broadcasts'] = self.object.broadcast_set.filter(deliver_time__isnull=False)
|
||||
return context
|
||||
|
||||
view_announce = AnnounceView.as_view()
|
||||
|
||||
|
||||
def menu_json(request):
|
||||
label = _('Announces')
|
||||
json_str = json.dumps([{'label': force_text(label),
|
||||
|
|
|
@ -49,7 +49,7 @@ def test_emailing_with_no_subscriptions(app, categories, announces, mailoutbox):
|
|||
for announce in announces:
|
||||
broadcast = Broadcast.objects.get(announce=announce)
|
||||
broadcast.send()
|
||||
assert not broadcast.result
|
||||
assert not broadcast.delivery_count
|
||||
assert not len(mailoutbox)
|
||||
|
||||
|
||||
|
@ -61,7 +61,7 @@ def test_send_email(app, categories, announces, mailoutbox):
|
|||
for i, announce in enumerate(announces):
|
||||
broadcast = Broadcast.objects.get(announce=announce)
|
||||
broadcast.send()
|
||||
assert broadcast.result
|
||||
assert broadcast.delivery_count
|
||||
assert len(mailoutbox) == i+1
|
||||
|
||||
|
||||
|
@ -75,9 +75,9 @@ def test_check_inline_css(app, categories, announces, mailoutbox):
|
|||
identifier='%s@example.net' % uuid, uuid=uuid)
|
||||
broadcast = Broadcast.objects.get(announce=announce)
|
||||
broadcast.send()
|
||||
assert broadcast.result
|
||||
assert len(mailoutbox) == total_sent + broadcast.result
|
||||
total_sent += broadcast.result
|
||||
assert broadcast.delivery_count
|
||||
assert len(mailoutbox) == total_sent + broadcast.delivery_count
|
||||
total_sent += broadcast.delivery_count
|
||||
assert 'h2 style="color:#F00"' in mailoutbox[i].html
|
||||
|
||||
|
||||
|
@ -100,14 +100,14 @@ def test_check_inline_images(mocked_get, app, categories, announces, mailoutbox)
|
|||
headers={'content-type': 'image/png'},
|
||||
content=storage.open(image_name).read())
|
||||
broadcast.send()
|
||||
assert broadcast.result
|
||||
assert broadcast.delivery_count
|
||||
|
||||
assert len(mailoutbox) == total_sent + broadcast.result
|
||||
assert len(mailoutbox) == total_sent + broadcast.delivery_count
|
||||
attachments = [a['filename'] for a in mailoutbox[0].attachments.as_dict()]
|
||||
assert image_name in attachments
|
||||
assert 'cid:%s' % image_name in mail.outbox[0].html_body
|
||||
assert 'cid:%s' % image_name in mail.outbox[0].text_body
|
||||
total_sent += broadcast.result
|
||||
total_sent += broadcast.delivery_count
|
||||
storage.delete(image_name)
|
||||
|
||||
|
||||
|
@ -123,7 +123,7 @@ def test_unsubscription_link(app, categories, announces, mailoutbox):
|
|||
continue
|
||||
broadcast = Broadcast.objects.get(announce=announce)
|
||||
broadcast.send()
|
||||
assert broadcast.result
|
||||
assert broadcast.delivery_count
|
||||
assert len(mailoutbox) == i+1
|
||||
|
||||
signature = urllib.unquote(re.findall('/unsubscribe/(.*)"', mailoutbox[i].html)[0])
|
||||
|
|
|
@ -4,6 +4,8 @@ import pytest
|
|||
from django.core.urlresolvers import reverse
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from corbo.models import Broadcast
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
@pytest.fixture
|
||||
|
@ -142,12 +144,36 @@ def test_edit_announce(app, admin_user):
|
|||
assert resp.location == 'http://testserver/manage/category/alerts/'
|
||||
resp = app.get(resp.location)
|
||||
assert 'First announce' in resp.content
|
||||
announce_edit_page = resp.click('First announce')
|
||||
announce_page = resp.click('First announce')
|
||||
assert 'First announce' in announce_page.content
|
||||
assert 'Edit' in announce_page.content
|
||||
assert 'Delete' in announce_page.content
|
||||
announce_edit_page = announce_page.click('Edit')
|
||||
edit_form = announce_edit_page.forms[0]
|
||||
edit_form['publication_time'] = '2017-03-03 09:00:00'
|
||||
edit_form['expiration_time'] = '2017-12-31 23:00:00'
|
||||
resp = edit_form.submit()
|
||||
assert resp.status_int == 302
|
||||
assert resp.location == 'http://testserver/manage/category/alerts/'
|
||||
assert resp.location == 'http://testserver/manage/announce/1/'
|
||||
|
||||
# simulate announce deliver
|
||||
broadcast = Broadcast.objects.get(announce__pk=1)
|
||||
broadcast.deliver_time = '2017-03-30 20:00:00'
|
||||
broadcast.delivery_count = 1
|
||||
broadcast.save()
|
||||
|
||||
resp = app.get(resp.location)
|
||||
|
||||
assert 'Publication at March 3, 2017, 9 a.m.' in resp.content
|
||||
assert 'Expiration at Dec. 31, 2017, 11 p.m.' in resp.content
|
||||
assert 'Sent at March 30, 2017, 8 p.m. to 1 destination' in resp.content
|
||||
|
||||
broadcast.delivery_count = 2
|
||||
broadcast.save()
|
||||
|
||||
resp = app.get('http://testserver/manage/announce/1/')
|
||||
assert 'Sent at March 30, 2017, 8 p.m. to 2 destinations' in resp.content
|
||||
|
||||
|
||||
def test_delete_announce(app, admin_user):
|
||||
app = login(app)
|
||||
|
|
Reference in New Issue