add in editor subscriptions table, hook up to notify button and version change (bug 631977)
This commit is contained in:
Родитель
e21d9de30d
Коммит
ef6eebcd3e
|
@ -1,16 +1,26 @@
|
|||
import copy
|
||||
import os
|
||||
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
from django.template import Context, loader
|
||||
from django.utils.datastructures import SortedDict
|
||||
from tower import ugettext_lazy as _
|
||||
|
||||
import amo
|
||||
import amo.models
|
||||
from amo.helpers import absolutify
|
||||
from amo.urlresolvers import reverse
|
||||
from amo.utils import send_mail
|
||||
from addons.models import Addon
|
||||
from editors.sql_model import RawSQLModel
|
||||
from translations.fields import TranslatedField
|
||||
from tower import ugettext as _
|
||||
from users.models import UserProfile
|
||||
from versions.models import Version
|
||||
|
||||
import commonware.log
|
||||
|
||||
|
||||
user_log = commonware.log.getLogger('z.users')
|
||||
|
||||
|
||||
class CannedResponse(amo.models.ModelBase):
|
||||
|
@ -91,7 +101,7 @@ class ViewQueue(RawSQLModel):
|
|||
('_file_platform_ids', """GROUP_CONCAT(DISTINCT
|
||||
files.platform_id)"""),
|
||||
('_application_ids', """GROUP_CONCAT(DISTINCT
|
||||
apps.application_id)""")
|
||||
apps.application_id)"""),
|
||||
]),
|
||||
'from': [
|
||||
'files',
|
||||
|
@ -134,7 +144,7 @@ class ViewFullReviewQueue(ViewQueue):
|
|||
'waiting_time_hours':
|
||||
'TIMESTAMPDIFF(HOUR, versions.nomination, NOW())',
|
||||
'waiting_time_min':
|
||||
'TIMESTAMPDIFF(MINUTE, versions.nomination, NOW())'
|
||||
'TIMESTAMPDIFF(MINUTE, versions.nomination, NOW())',
|
||||
})
|
||||
q['where'].extend(['files.status <> %s' % amo.STATUS_BETA,
|
||||
'addons.status IN (%s, %s)' % (
|
||||
|
@ -154,7 +164,7 @@ class VersionSpecificQueue(ViewQueue):
|
|||
'waiting_time_hours':
|
||||
'TIMESTAMPDIFF(HOUR, MAX(versions.created), NOW())',
|
||||
'waiting_time_min':
|
||||
'TIMESTAMPDIFF(MINUTE, MAX(versions.created), NOW())'
|
||||
'TIMESTAMPDIFF(MINUTE, MAX(versions.created), NOW())',
|
||||
})
|
||||
return q
|
||||
|
||||
|
@ -177,3 +187,46 @@ class ViewPreliminaryQueue(VersionSpecificQueue):
|
|||
amo.STATUS_LITE,
|
||||
amo.STATUS_UNREVIEWED)])
|
||||
return q
|
||||
|
||||
|
||||
class EditorSubscription(amo.models.ModelBase):
|
||||
user = models.ForeignKey(UserProfile)
|
||||
addon = models.ForeignKey(Addon)
|
||||
|
||||
class Meta:
|
||||
db_table = 'editor_subscriptions'
|
||||
|
||||
def send_notification(self, version):
|
||||
user_log.info('Sending addon update notice to %s for %s' %
|
||||
(self.user.email, self.addon.pk))
|
||||
context = Context({
|
||||
'name': self.addon.name,
|
||||
'url': absolutify(reverse('addons.detail', args=[self.addon.pk])),
|
||||
'number': version.version,
|
||||
'review': absolutify(reverse('editors.review', args=[version.pk])),
|
||||
'SITE_URL': settings.SITE_URL,
|
||||
})
|
||||
#L10N: addon.name
|
||||
subject = _('Mozilla Add-ons: %s Updated') % self.addon.name
|
||||
template = loader.get_template('editors/emails/notify_update.ltxt')
|
||||
send_mail(subject, template.render(Context(context)),
|
||||
recipient_list=[self.user.email],
|
||||
from_email=settings.EDITORS_EMAIL,
|
||||
use_blacklist=False)
|
||||
|
||||
|
||||
def send_notifications(sender, instance, **kw):
|
||||
if kw.get('raw') or not kw.get('created'):
|
||||
return
|
||||
|
||||
subscribers = instance.addon.editorsubscription_set.all()
|
||||
if not subscribers:
|
||||
return
|
||||
|
||||
for subscriber in subscribers:
|
||||
subscriber.send_notification(instance)
|
||||
subscriber.delete()
|
||||
|
||||
|
||||
models.signals.post_save.connect(send_notifications, sender=Version,
|
||||
dispatch_uid='version_send_notifications')
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
{% load i18n %}
|
||||
{% blocktrans %}
|
||||
Dear editor,
|
||||
|
||||
An add-on you previously reviewed was just updated.
|
||||
|
||||
Add-on Information:
|
||||
|
||||
Name: {{ name }}
|
||||
URL: {{ url }}
|
||||
|
||||
Version Number: {{ number }}
|
||||
Review Link: {{ review }}
|
||||
|
||||
Thanks!
|
||||
Mozilla Add-ons
|
||||
{{ SITE_URL }}
|
||||
|
||||
This is a one-time notification sent to you because you requested a follow up email regarding queue activity for {{ name }}. There is no need to unsubscribe if you don't wish to receive further mail.
|
||||
{% endblocktrans %}
|
|
@ -1,5 +1,7 @@
|
|||
# -*- coding: utf8 -*-
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime
|
||||
|
||||
from django.core import mail
|
||||
|
||||
from nose.tools import eq_
|
||||
import test_utils
|
||||
|
@ -9,8 +11,10 @@ from addons.models import Addon
|
|||
from versions.models import Version, ApplicationsVersions, VersionSummary
|
||||
from files.models import Platform, File
|
||||
from applications.models import Application, AppVersion
|
||||
from editors.models import (ViewPendingQueue, ViewFullReviewQueue,
|
||||
from editors.models import (EditorSubscription, send_notifications,
|
||||
ViewPendingQueue, ViewFullReviewQueue,
|
||||
ViewPreliminaryQueue)
|
||||
from users.models import UserProfile
|
||||
|
||||
|
||||
def create_addon_file(name, version_str, addon_status, file_status,
|
||||
|
@ -35,14 +39,11 @@ def create_addon_file(name, version_str, addon_status, file_status,
|
|||
min=app_vr.id)
|
||||
va, created = ApplicationsVersions.objects.get_or_create(
|
||||
version=vr, application=app, min=app_vr, max=app_vr)
|
||||
fi = File.objects.create(version=vr, filename=u"%s.xpi" % name,
|
||||
platform=pl, status=file_status)
|
||||
File.objects.create(version=vr, filename=u"%s.xpi" % name,
|
||||
platform=pl, status=file_status)
|
||||
# Update status *after* there are files:
|
||||
Addon.objects.get(pk=ad.id).update(status=addon_status)
|
||||
return {
|
||||
'addon': ad,
|
||||
'version': vr
|
||||
}
|
||||
return {'addon': ad, 'version': vr}
|
||||
|
||||
|
||||
def create_search_ext(name, version_str, addon_status, file_status):
|
||||
|
@ -52,8 +53,8 @@ def create_search_ext(name, version_str, addon_status, file_status):
|
|||
ad = Addon.objects.create(type=amo.ADDON_SEARCH, name=name)
|
||||
vr, created = Version.objects.get_or_create(addon=ad, version=version_str)
|
||||
pl, created = Platform.objects.get_or_create(id=amo.PLATFORM_ALL.id)
|
||||
fi = File.objects.create(version=vr, filename=u"%s.xpi" % name,
|
||||
platform=pl, status=file_status)
|
||||
File.objects.create(version=vr, filename=u"%s.xpi" % name,
|
||||
platform=pl, status=file_status)
|
||||
# Update status *after* there are files:
|
||||
Addon.objects.get(pk=ad.id).update(status=addon_status)
|
||||
return ad
|
||||
|
@ -61,7 +62,7 @@ def create_search_ext(name, version_str, addon_status, file_status):
|
|||
|
||||
class TestQueue(test_utils.TestCase):
|
||||
"""Tests common attributes and coercions that each view must support."""
|
||||
__test__ = False # this is an abstract test case
|
||||
__test__ = False # this is an abstract test case
|
||||
|
||||
def test_latest_version(self):
|
||||
self.new_file(version=u'0.1')
|
||||
|
@ -204,3 +205,52 @@ class TestPreliminaryQueue(TestQueue):
|
|||
# Time zone might be off due to your MySQL install, hard to test this.
|
||||
assert row.waiting_time_min is not None
|
||||
assert row.waiting_time_hours is not None
|
||||
|
||||
|
||||
class TestEditorSubscription(test_utils.TestCase):
|
||||
fixtures = ['base/addon_3615', 'base/users']
|
||||
|
||||
def setUp(self):
|
||||
self.addon = Addon.objects.get(pk=3615)
|
||||
self.version = self.addon.current_version
|
||||
self.user_one = UserProfile.objects.get(pk=55021)
|
||||
self.user_two = UserProfile.objects.get(pk=999)
|
||||
for user in [self.user_one, self.user_two]:
|
||||
EditorSubscription.objects.create(addon=self.addon, user=user)
|
||||
|
||||
def test_email(self):
|
||||
es = EditorSubscription.objects.get(user=self.user_one)
|
||||
es.send_notification(self.version)
|
||||
eq_(len(mail.outbox), 1)
|
||||
eq_(mail.outbox[0].to, [u'del@icio.us'])
|
||||
eq_(mail.outbox[0].subject,
|
||||
'Mozilla Add-ons: Delicious Bookmarks Updated')
|
||||
|
||||
def test_notifications(self):
|
||||
send_notifications(Version, self.version, created=True)
|
||||
eq_(len(mail.outbox), 2)
|
||||
emails = sorted([o.to for o in mail.outbox])
|
||||
eq_(emails, [[u'del@icio.us'], [u'regular@mozilla.com']])
|
||||
|
||||
def test_notifications_clean(self):
|
||||
send_notifications(Version, self.version, created=True)
|
||||
eq_(EditorSubscription.objects.count(), 0)
|
||||
mail.outbox = []
|
||||
send_notifications(Version, self.version, created=True)
|
||||
eq_(len(mail.outbox), 0)
|
||||
|
||||
def test_signal_edit(self):
|
||||
self.version.save()
|
||||
eq_(len(mail.outbox), 0)
|
||||
|
||||
def test_signal_create(self):
|
||||
Version.objects.create(addon=self.addon)
|
||||
eq_(len(mail.outbox), 2)
|
||||
eq_(mail.outbox[0].subject,
|
||||
'Mozilla Add-ons: Delicious Bookmarks Updated')
|
||||
|
||||
def test_signal_create_twice(self):
|
||||
Version.objects.create(addon=self.addon)
|
||||
mail.outbox = []
|
||||
Version.objects.create(addon=self.addon)
|
||||
eq_(len(mail.outbox), 0)
|
||||
|
|
|
@ -19,7 +19,7 @@ from addons.models import Addon, AddonUser
|
|||
from applications.models import Application
|
||||
from cake.urlresolvers import remora_url
|
||||
from devhub.models import ActivityLog
|
||||
from editors.models import EventLog
|
||||
from editors.models import EditorSubscription, EventLog
|
||||
from files.models import Approval, Platform, File
|
||||
import reviews
|
||||
from reviews.models import Review, ReviewFlag
|
||||
|
@ -869,6 +869,19 @@ class TestReview(ReviewBase):
|
|||
eq_(len(mail.outbox), 1)
|
||||
self.assertTemplateUsed(response, 'editors/emails/info.ltxt')
|
||||
|
||||
def test_notify(self):
|
||||
response = self.client.post(self.url, {'action': 'info',
|
||||
'comments': 'hello sailor',
|
||||
'notify': True})
|
||||
eq_(response.status_code, 302)
|
||||
eq_(EditorSubscription.objects.count(), 1)
|
||||
|
||||
def test_no_notify(self):
|
||||
response = self.client.post(self.url, {'action': 'info',
|
||||
'comments': 'hello sailor'})
|
||||
eq_(response.status_code, 302)
|
||||
eq_(EditorSubscription.objects.count(), 0)
|
||||
|
||||
def test_paging_none(self):
|
||||
response = self.client.get(self.url)
|
||||
eq_(response.context['paging'], {})
|
||||
|
|
|
@ -16,8 +16,9 @@ from amo.utils import paginate
|
|||
from amo.urlresolvers import reverse
|
||||
from devhub.models import ActivityLog
|
||||
from editors import forms
|
||||
from editors.models import (ViewPendingQueue, ViewFullReviewQueue,
|
||||
ViewPreliminaryQueue, EventLog, CannedResponse)
|
||||
from editors.models import (EditorSubscription, ViewPendingQueue,
|
||||
ViewFullReviewQueue, ViewPreliminaryQueue,
|
||||
EventLog, CannedResponse)
|
||||
from editors.helpers import (ViewPendingQueueTable, ViewFullReviewQueueTable,
|
||||
ViewPreliminaryQueueTable, LOG_STATUSES)
|
||||
from files.models import Approval
|
||||
|
@ -242,6 +243,9 @@ def review(request, version_id):
|
|||
|
||||
if request.method == 'POST' and form.is_valid():
|
||||
form.helper.process()
|
||||
if form.cleaned_data.get('notify'):
|
||||
EditorSubscription.objects.get_or_create(user=request.amo_user,
|
||||
addon=addon)
|
||||
amo.messages.success(request, _('Review successfully processed.'))
|
||||
return redirect(redirect_url)
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
ALTER TABLE editor_subscriptions ADD COLUMN created datetime NOT NULL;
|
||||
ALTER TABLE editor_subscriptions ADD COLUMN modified datetime NOT NULL;
|
||||
ALTER TABLE editor_subscriptions DROP PRIMARY KEY;
|
||||
ALTER TABLE editor_subscriptions ADD COLUMN id integer AUTO_INCREMENT NOT NULL PRIMARY KEY;
|
Загрузка…
Ссылка в новой задаче