add in editor subscriptions table, hook up to notify button and version change (bug 631977)

This commit is contained in:
Andy McKay 2011-03-28 12:41:55 -07:00
Родитель e21d9de30d
Коммит ef6eebcd3e
6 изменённых файлов: 164 добавлений и 20 удалений

Просмотреть файл

@ -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;