addons-server/apps/editors/helpers.py

806 строки
32 KiB
Python

import datetime
from django.conf import settings
from django.template import Context, loader
from django.utils.datastructures import SortedDict
import django_tables as tables
import jinja2
from jingo import register
from tower import ugettext as _, ugettext_lazy as _lazy, ungettext as ngettext
import waffle
import amo
from addons.helpers import new_context
from amo.helpers import absolutify, breadcrumbs, page_title, timesince
from amo.urlresolvers import reverse
from amo.utils import send_mail as amo_send_mail
import commonware.log
from editors.models import (ReviewerScore, ViewFastTrackQueue,
ViewFullReviewQueue, ViewPendingQueue,
ViewPreliminaryQueue)
from editors.sql_table import SQLTable
from mkt.webapps.models import Webapp
@register.function
def file_compare(file_obj, version):
# Compare this file to the one in the version with same platform
file_obj = version.files.filter(platform=file_obj.platform)
# If not there, just compare to all.
if not file_obj:
file_obj = version.files.filter(platform=amo.PLATFORM_ALL.id)
# At this point we've got no idea what Platform file to
# compare with, so just chose the first.
if not file_obj:
file_obj = version.files.all()
return file_obj[0]
@register.function
def file_review_status(addon, file):
if file.status not in [amo.STATUS_DISABLED, amo.STATUS_PUBLIC]:
if addon.status in [amo.STATUS_UNREVIEWED, amo.STATUS_LITE]:
return _(u'Pending Preliminary Review')
elif addon.status in [amo.STATUS_NOMINATED,
amo.STATUS_LITE_AND_NOMINATED,
amo.STATUS_PUBLIC]:
return _(u'Pending Full Review')
return amo.STATUS_CHOICES[file.status]
@register.function
@jinja2.contextfunction
def editor_page_title(context, title=None, addon=None):
"""Wrapper for editor page titles. Eerily similar to dev_page_title."""
if addon:
title = u'%s :: %s' % (title, addon.name)
else:
section = _lazy('Editor Tools')
title = u'%s :: %s' % (title, section) if title else section
return page_title(context, title)
@register.function
@jinja2.contextfunction
def editors_breadcrumbs(context, queue=None, addon_queue=None, items=None):
"""
Wrapper function for ``breadcrumbs``. Prepends 'Editor Tools'
breadcrumbs.
**items**
list of [(url, label)] to be inserted after Add-on.
**addon_queue**
Addon object. This sets the queue by addon type or addon status.
**queue**
Explicit queue type to set.
"""
crumbs = [(reverse('editors.home'), _('Editor Tools'))]
if addon_queue:
if addon_queue.type == amo.ADDON_WEBAPP:
queue = 'apps'
else:
queue_id = addon_queue.status
queue_ids = {amo.STATUS_UNREVIEWED: 'prelim',
amo.STATUS_NOMINATED: 'nominated',
amo.STATUS_PUBLIC: 'pending',
amo.STATUS_LITE: 'prelim',
amo.STATUS_LITE_AND_NOMINATED: 'nominated',
amo.STATUS_PENDING: 'pending'}
queue = queue_ids.get(queue_id, 'queue')
if queue:
queues = {'queue': _("Queue"),
'pending': _("Pending Updates"),
'nominated': _("Full Reviews"),
'prelim': _("Preliminary Reviews"),
'moderated': _("Moderated Reviews"),
'fast_track': _("Fast Track"),
'apps': _("Apps")}
if items and not queue == 'queue':
url = reverse('editors.queue_%s' % queue)
else:
# The Addon is the end of the trail.
url = None
crumbs.append((url, queues[queue]))
if items:
crumbs.extend(items)
return breadcrumbs(context, crumbs, add_default=False)
@register.function
@jinja2.contextfunction
def queue_tabnav(context):
"""Returns tuple of tab navigation for the queue pages.
Each tuple contains three elements: (tab_code, page_url, tab_text)
"""
from .views import queue_counts
counts = queue_counts()
tabnav = [('fast_track', 'queue_fast_track',
(ngettext('Fast Track ({0})', 'Fast Track ({0})',
counts['fast_track'])
.format(counts['fast_track']))),
('nominated', 'queue_nominated',
(ngettext('Full Review ({0})', 'Full Reviews ({0})',
counts['nominated'])
.format(counts['nominated']))),
('pending', 'queue_pending',
(ngettext('Pending Update ({0})', 'Pending Updates ({0})',
counts['pending'])
.format(counts['pending']))),
('prelim', 'queue_prelim',
(ngettext('Preliminary Review ({0})',
'Preliminary Reviews ({0})',
counts['prelim'])
.format(counts['prelim']))),
('moderated', 'queue_moderated',
(ngettext('Moderated Review ({0})', 'Moderated Reviews ({0})',
counts['moderated'])
.format(counts['moderated'])))]
if waffle.flag_is_active(context['request'], 'accept-webapps'):
tabnav.append(('apps', 'queue_apps',
(ngettext('Apps ({0})', 'Apps ({0})', counts['apps'])
.format(counts['apps']))))
return tabnav
@register.inclusion_tag('editors/includes/reviewers_score_bar.html')
@jinja2.contextfunction
def reviewers_score_bar(context):
user = context.get('amo_user')
return new_context(dict(
amo=amo,
points=ReviewerScore.get_recent(user),
total=ReviewerScore.get_total(user),
**ReviewerScore.get_leaderboards(user)))
class ItemStateTable(object):
def increment_item(self):
self.item_number += 1
def set_page(self, page):
self.item_number = page.start_index()
class EditorQueueTable(SQLTable, ItemStateTable):
addon_name = tables.Column(verbose_name=_lazy(u'Addon'))
addon_type_id = tables.Column(verbose_name=_lazy(u'Type'))
waiting_time_min = tables.Column(verbose_name=_lazy(u'Waiting Time'))
flags = tables.Column(verbose_name=_lazy(u'Flags'), sortable=False)
applications = tables.Column(verbose_name=_lazy(u'Applications'),
sortable=False)
platforms = tables.Column(verbose_name=_lazy(u'Platforms'),
sortable=False)
additional_info = tables.Column(
verbose_name=_lazy(u'Additional'), sortable=False)
def render_addon_name(self, row):
url = '%s?num=%s' % (reverse('editors.review',
args=[row.addon_slug]),
self.item_number)
self.increment_item()
return u'<a href="%s">%s <em>%s</em></a>' % (
url, jinja2.escape(row.addon_name),
jinja2.escape(row.latest_version))
def render_addon_type_id(self, row):
return amo.ADDON_TYPE[row.addon_type_id]
def render_additional_info(self, row):
info = []
if row.is_site_specific:
info.append(_lazy(u'Site Specific'))
if row.external_software:
info.append(_lazy(u'Requires External Software'))
if row.binary or row.binary_components:
info.append(_lazy(u'Binary Components'))
return u', '.join([jinja2.escape(i) for i in info])
def render_applications(self, row):
# TODO(Kumar) show supported version ranges on hover (if still needed)
icon = u'<div class="app-icon ed-sprite-%s" title="%s"></div>'
return u''.join([icon % (amo.APPS_ALL[i].short, amo.APPS_ALL[i].pretty)
for i in row.application_ids])
def render_platforms(self, row):
icons = []
html = u'<div class="platform-icon plat-sprite-%s" title="%s"></div>'
for i in row.file_platform_vers:
platform, version = i.split('-')
if int(version) == row.latest_version_id:
icons.append(html % (amo.PLATFORMS[int(platform)].shortname,
amo.PLATFORMS[int(platform)].name))
return u''.join(icons)
def render_flags(self, row):
o = []
if row.admin_review:
o.append(u'<div class="app-icon ed-sprite-admin-review" '
u'title="%s"></div>' % _('Admin Review'))
if row.is_jetpack:
o.append(u'<div class="app-icon ed-sprite-jetpack" title="%s">'
u'</div>' % _('Jetpack Add-on'))
elif row.is_restartless:
# Only show restartless if it's not also a jetpack
o.append(u'<div class="app-icon ed-sprite-restartless" title="%s">'
u'</div>' % _('Bootstrapped Restartless Add-on'))
if row.is_premium:
o.append(u'<div class="app-icon ed-sprite-premium" title="%s">'
u'</div>' % _('Premium add-on'))
if row.has_info_request:
o.append(u'<div class="app-icon ed-sprite-info" title="%s">'
u'</div>' % _('More Information Requested'))
if row.has_editor_comment:
o.append(u'<div class="app-icon ed-sprite-editor" title="%s">'
u'</div>' % _('Contains Editor Comment'))
return ''.join(o)
def render_waiting_time_min(self, row):
if row.waiting_time_min == 0:
r = _lazy('moments ago')
elif row.waiting_time_hours == 0:
# L10n: first argument is number of minutes
r = ngettext(u'{0} minute', u'{0} minutes',
row.waiting_time_min).format(row.waiting_time_min)
elif row.waiting_time_days == 0:
# L10n: first argument is number of hours
r = ngettext(u'{0} hour', u'{0} hours',
row.waiting_time_hours).format(row.waiting_time_hours)
else:
# L10n: first argument is number of days
r = ngettext(u'{0} day', u'{0} days',
row.waiting_time_days).format(row.waiting_time_days)
return jinja2.escape(r)
@classmethod
def translate_sort_cols(cls, colname):
legacy_sorts = {
'name': 'addon_name',
'age': 'waiting_time_min',
'type': 'addon_type_id',
}
return legacy_sorts.get(colname, colname)
@classmethod
def default_order_by(cls):
return '-waiting_time_min'
@classmethod
def review_url(cls, row):
return reverse('editors.review', args=[row.addon_slug])
class Meta:
sortable = True
columns = ['addon_name', 'addon_type_id', 'waiting_time_min',
'flags', 'applications', 'additional_info']
class ViewPendingQueueTable(EditorQueueTable):
class Meta(EditorQueueTable.Meta):
model = ViewPendingQueue
class ViewFullReviewQueueTable(EditorQueueTable):
class Meta(EditorQueueTable.Meta):
model = ViewFullReviewQueue
class ViewPreliminaryQueueTable(EditorQueueTable):
class Meta(EditorQueueTable.Meta):
model = ViewPreliminaryQueue
class ViewFastTrackQueueTable(EditorQueueTable):
class Meta(EditorQueueTable.Meta):
model = ViewFastTrackQueue
class WebappQueueTable(tables.ModelTable, ItemStateTable):
name = tables.Column(verbose_name=_lazy(u'App'))
created = tables.Column(verbose_name=_lazy(u'Waiting Time'))
abuse_reports__count = tables.Column(verbose_name=_lazy(u'Abuse Reports'))
def render_name(self, row):
url = '%s?num=%s' % (reverse('editors.app_review', args=[row.slug]),
self.item_number)
self.increment_item()
return u'<a href="%s">%s</a>' % (url, jinja2.escape(row.name))
def render_abuse_reports__count(self, row):
url = reverse('editors.abuse_reports', args=[row.slug])
return u'<a href="%s">%s</a>' % (jinja2.escape(url),
row.abuse_reports__count)
def render_created(self, row):
return timesince(row.created)
@classmethod
def translate_sort_cols(cls, colname):
return colname
@classmethod
def default_order_by(cls):
return 'created'
@classmethod
def review_url(cls, row):
return reverse('editors.app_review', args=[row.slug])
class Meta:
sortable = True
model = Webapp
columns = ['name', 'created', 'abuse_reports__count']
log = commonware.log.getLogger('z.mailer')
NOMINATED_STATUSES = (amo.STATUS_NOMINATED, amo.STATUS_LITE_AND_NOMINATED)
PRELIMINARY_STATUSES = (amo.STATUS_UNREVIEWED, amo.STATUS_LITE)
PENDING_STATUSES = (amo.STATUS_BETA, amo.STATUS_DISABLED, amo.STATUS_LISTED,
amo.STATUS_NULL, amo.STATUS_PENDING, amo.STATUS_PUBLIC)
def send_mail(template, subject, emails, context, perm_setting=None):
template = loader.get_template(template)
amo_send_mail(subject, template.render(Context(context, autoescape=False)),
recipient_list=emails, from_email=settings.EDITORS_EMAIL,
use_blacklist=False, perm_setting=perm_setting)
def get_position(addon):
version = addon.latest_version
if not version:
return False
q = version.current_queue
if not q:
return False
mins_query = q.objects.filter(id=addon.id)
if mins_query.count() > 0:
mins = mins_query[0].waiting_time_min
pos = q.objects.having('waiting_time_min >=', mins).count()
total = q.objects.count()
return dict(mins=mins, pos=pos, total=total)
return False
class ReviewHelper:
"""
A class that builds enough to render the form back to the user and
process off to the correct handler.
"""
def __init__(self, request=None, addon=None, version=None):
self.handler = None
self.required = {}
self.addon = addon
self.all_files = version.files.all()
self.get_review_type(request, addon, version)
self.actions = self.get_actions()
def set_data(self, data):
self.handler.set_data(data)
def get_review_type(self, request, addon, version):
if self.addon.type == amo.ADDON_WEBAPP:
self.review_type = 'apps'
self.handler = ReviewAddon(request, addon, version, 'pending')
elif self.addon.status in NOMINATED_STATUSES:
self.review_type = 'nominated'
self.handler = ReviewAddon(request, addon, version, 'nominated')
elif self.addon.status == amo.STATUS_UNREVIEWED:
self.review_type = 'preliminary'
self.handler = ReviewAddon(request, addon, version, 'preliminary')
elif self.addon.status == amo.STATUS_LITE:
self.review_type = 'preliminary'
self.handler = ReviewFiles(request, addon, version, 'preliminary')
else:
self.review_type = 'pending'
self.handler = ReviewFiles(request, addon, version, 'pending')
def get_actions(self):
if self.addon.type == amo.ADDON_WEBAPP:
return self.get_app_actions()
labels, details = self._review_actions()
actions = SortedDict()
if self.review_type != 'preliminary':
actions['public'] = {'method': self.handler.process_public,
'minimal': False,
'label': _lazy('Push to public')}
if not self.addon.is_premium():
actions['prelim'] = {'method': self.handler.process_preliminary,
'label': labels['prelim'],
'minimal': False}
actions['reject'] = {'method': self.handler.process_sandbox,
'label': _lazy('Reject'),
'minimal': False}
actions['info'] = {'method': self.handler.request_information,
'label': _lazy('Request more information'),
'minimal': True}
actions['super'] = {'method': self.handler.process_super_review,
'label': _lazy('Request super-review'),
'minimal': True}
actions['comment'] = {'method': self.handler.process_comment,
'label': _lazy('Comment'),
'minimal': True}
for k, v in actions.items():
v['details'] = details.get(k)
return actions
def get_app_actions(self):
actions = SortedDict()
actions['public'] = {'method': self.handler.process_public,
'minimal': False,
'label': _lazy('Push to public'),
'details': _lazy(
'This will approve the sandboxed app so it '
'appears on the public side.')}
actions['reject'] = {'method': self.handler.process_sandbox,
'label': _lazy('Reject'),
'minimal': False,
'details': _lazy(
'This will reject the app and remove it '
'from the review queue.')}
actions['comment'] = {'method': self.handler.process_comment,
'label': _lazy('Comment'),
'minimal': True,
'details': _lazy(
'Make a comment on this app. The '
'author won\'t be able to see this.')}
return actions
def _review_actions(self):
labels = {'prelim': _lazy('Grant preliminary review')}
details = {'prelim': _lazy('This will mark the files as '
'premliminary reviewed.'),
'info': _lazy('Use this form to request more information '
'from the author. They will receive an email '
'and be able to answer here. You will be '
'notified by email when they reply.'),
'super': _lazy('If you have concerns about this add-on\'s '
'security, copyright issues, or other '
'concerns that an administrator should look '
'into, enter your comments in the area '
'below. They will be sent to '
'administrators, not the author.'),
'reject': _lazy('This will reject the add-on and remove '
'it from the review queue.'),
'comment': _lazy('Make a comment on this version. The '
'author won\'t be able to see this.')}
if self.addon.status == amo.STATUS_LITE:
details['reject'] = _lazy('This will reject the files and remove '
'them from the review queue.')
if self.addon.status in (amo.STATUS_UNREVIEWED, amo.STATUS_NOMINATED):
details['prelim'] = _lazy('This will mark the add-on as '
'preliminarily reviewed. Future '
'versions will undergo '
'preliminary review.')
elif self.addon.status == amo.STATUS_LITE:
details['prelim'] = _lazy('This will mark the files as '
'preliminarily reviewed. Future '
'versions will undergo '
'preliminary review.')
elif self.addon.status == amo.STATUS_LITE_AND_NOMINATED:
labels['prelim'] = _lazy('Retain preliminary review')
details['prelim'] = _lazy('This will retain the add-on as '
'preliminarily reviewed. Future '
'versions will undergo preliminary '
'review.')
if self.review_type == 'pending':
details['public'] = _lazy('This will approve a sandboxed version '
'of a public add-on to appear on the '
'public side.')
details['reject'] = _lazy('This will reject a version of a public '
'add-on and remove it from the queue.')
else:
details['public'] = _lazy('This will mark the add-on and its most '
'recent version and files as public. '
'Future versions will go into the '
'sandbox until they are reviewed by an '
'editor.')
return labels, details
def process(self):
action = self.handler.data.get('action', '')
if not action:
raise NotImplementedError
return self.actions[action]['method']()
class ReviewBase(object):
def __init__(self, request, addon, version, review_type):
self.request = request
self.user = self.request.user
self.addon = addon
self.version = version
self.review_type = review_type
self.files = None
def set_addon(self, **kw):
"""Alters addon and sets reviewed timestamp on version."""
self.addon.update(**kw)
self.version.update(reviewed=datetime.datetime.now())
def set_files(self, status, files, copy_to_mirror=False,
hide_disabled_file=False):
"""Change the files to be the new status
and copy, remove from the mirror as appropriate."""
for file in files:
file.datestatuschanged = datetime.datetime.now()
file.reviewed = datetime.datetime.now()
if copy_to_mirror:
file.copy_to_mirror()
if hide_disabled_file:
file.hide_disabled_file()
file.status = status
file.save()
def log_action(self, action):
details = {'comments': self.data['comments'],
'reviewtype': self.review_type}
if self.files:
details['files'] = [f.id for f in self.files]
if self.version:
details['version'] = self.version.version
amo.log(action, self.addon, self.version, user=self.user.get_profile(),
created=datetime.datetime.now(), details=details)
def notify_email(self, template, subject):
"""Notify the authors that their addon has been reviewed."""
emails = [a.email for a in self.addon.authors.all()]
data = self.data.copy()
data.update(self.get_context_data())
data['tested'] = ''
os, app = data.get('operating_systems'), data.get('applications')
if os and app:
data['tested'] = 'Tested on %s with %s' % (os, app)
elif os and not app:
data['tested'] = 'Tested on %s' % os
elif not os and app:
data['tested'] = 'Tested with %s' % app
data['addon_type'] = (_lazy('app')
if self.addon.type == amo.ADDON_WEBAPP
else _lazy('add-on'))
send_mail('editors/emails/%s.ltxt' % template,
subject % (self.addon.name, self.version.version),
emails, Context(data), perm_setting='editor_reviewed')
def get_context_data(self):
return {'name': self.addon.name,
'number': self.version.version,
'reviewer': (self.request.user.get_profile().display_name),
'addon_url': absolutify(
self.addon.get_url_path(add_prefix=False)),
'review_url': absolutify(reverse('editors.review',
args=[self.addon.pk],
add_prefix=False)),
'comments': self.data['comments'],
'SITE_URL': settings.SITE_URL}
def request_information(self):
"""Send a request for information to the authors."""
emails = [a.email for a in self.addon.authors.all()]
self.log_action(amo.LOG.REQUEST_INFORMATION)
self.version.update(has_info_request=True)
log.info(u'Sending request for information for %s to %s' %
(self.addon, emails))
send_mail('editors/emails/info.ltxt',
u'Mozilla Add-ons: %s %s' %
(self.addon.name, self.version.version),
emails, Context(self.get_context_data()),
perm_setting='individual_contact')
def send_super_mail(self):
self.log_action(amo.LOG.REQUEST_SUPER_REVIEW)
log.info(u'Super review requested for %s' % (self.addon))
send_mail('editors/emails/super_review.ltxt',
u'Super review requested: %s' % (self.addon.name),
[settings.SENIOR_EDITORS_EMAIL],
Context(self.get_context_data()))
def process_comment(self):
self.version.update(has_editor_comment=True)
self.log_action(amo.LOG.COMMENT_VERSION)
class ReviewAddon(ReviewBase):
def __init__(self, *args, **kwargs):
super(ReviewAddon, self).__init__(*args, **kwargs)
self.is_upgrade = (self.addon.status is amo.STATUS_LITE_AND_NOMINATED
and self.review_type == 'nominated')
def set_data(self, data):
self.data = data
self.files = self.version.files.all()
def process_public(self):
"""Set an addon to public."""
if self.review_type == 'preliminary':
raise AssertionError('Preliminary addons cannot be made public.')
# Save files first, because set_addon checks to make sure there
# is at least one public file or it won't make the addon public.
self.set_files(amo.STATUS_PUBLIC, self.version.files.all(),
copy_to_mirror=True)
self.set_addon(highest_status=amo.STATUS_PUBLIC,
status=amo.STATUS_PUBLIC)
self.log_action(amo.LOG.APPROVE_VERSION)
self.notify_email('%s_to_public' % self.review_type,
u'Mozilla Add-ons: %s %s Fully Reviewed')
log.info(u'Making %s public' % (self.addon))
log.info(u'Sending email for %s' % (self.addon))
# Assign reviewer incentive scores.
event = ReviewerScore.get_event_by_type(self.addon, self.review_type)
ReviewerScore.award_points(self.request.amo_user, self.addon, event)
def process_sandbox(self):
"""Set an addon back to sandbox."""
if (not self.is_upgrade or
not self.addon.versions.exclude(id=self.version.id)
.filter(files__status__in=amo.REVIEWED_STATUSES)):
self.set_addon(status=amo.STATUS_NULL)
else:
self.set_addon(status=amo.STATUS_LITE)
self.set_files(amo.STATUS_DISABLED, self.version.files.all(),
hide_disabled_file=True)
self.log_action(amo.LOG.REJECT_VERSION)
self.notify_email('%s_to_sandbox' % self.review_type,
u'Mozilla Add-ons: %s %s Rejected')
log.info(u'Making %s disabled' % (self.addon))
log.info(u'Sending email for %s' % (self.addon))
def process_preliminary(self):
"""Set an addon to preliminary."""
if self.addon.is_premium():
raise AssertionError('Premium add-ons cannot become preliminary.')
changes = {'status': amo.STATUS_LITE}
if (self.addon.status in (amo.STATUS_PUBLIC,
amo.STATUS_LITE_AND_NOMINATED)):
changes['highest_status'] = amo.STATUS_LITE
template = '%s_to_preliminary' % self.review_type
if (self.review_type == 'preliminary' and
self.addon.status == amo.STATUS_LITE_AND_NOMINATED):
template = 'nominated_to_nominated'
self.set_addon(**changes)
self.set_files(amo.STATUS_LITE, self.version.files.all(),
copy_to_mirror=True)
self.log_action(amo.LOG.PRELIMINARY_VERSION)
self.notify_email(template,
u'Mozilla Add-ons: %s %s Preliminary Reviewed')
log.info(u'Making %s preliminary' % (self.addon))
log.info(u'Sending email for %s' % (self.addon))
# Assign reviewer incentive scores.
event = ReviewerScore.get_event_by_type(self.addon, 'preliminary')
ReviewerScore.award_points(self.request.amo_user, self.addon, event)
def process_super_review(self):
"""Give an addon super review."""
self.addon.update(admin_review=True)
self.notify_email('author_super_review',
u'Mozilla Add-ons: %s %s flagged for Admin Review')
self.send_super_mail()
class ReviewFiles(ReviewBase):
def set_data(self, data):
self.data = data
self.files = data.get('addon_files', None)
def process_public(self):
"""Set an addons files to public."""
if self.review_type == 'preliminary':
raise AssertionError('Preliminary addons cannot be made public.')
self.set_files(amo.STATUS_PUBLIC, self.data['addon_files'],
copy_to_mirror=True)
self.log_action(amo.LOG.APPROVE_VERSION)
self.notify_email('%s_to_public' % self.review_type,
u'Mozilla Add-ons: %s %s Fully Reviewed')
log.info(u'Making %s files %s public' %
(self.addon,
', '.join([f.filename for f in self.data['addon_files']])))
log.info(u'Sending email for %s' % (self.addon))
# Assign reviewer incentive scores.
event = ReviewerScore.get_event_by_type(self.addon, self.review_type)
ReviewerScore.award_points(self.request.amo_user, self.addon, event)
def process_sandbox(self):
"""Set an addons files to sandbox."""
self.set_files(amo.STATUS_DISABLED, self.data['addon_files'],
hide_disabled_file=True)
self.log_action(amo.LOG.REJECT_VERSION)
self.notify_email('%s_to_sandbox' % self.review_type,
u'Mozilla Add-ons: %s %s Rejected')
log.info(u'Making %s files %s disabled' %
(self.addon,
', '.join([f.filename for f in self.data['addon_files']])))
log.info(u'Sending email for %s' % (self.addon))
def process_preliminary(self):
"""Set an addons files to preliminary."""
if self.addon.is_premium():
raise AssertionError('Premium add-ons cannot become preliminary.')
self.set_files(amo.STATUS_LITE, self.data['addon_files'],
copy_to_mirror=True)
self.log_action(amo.LOG.PRELIMINARY_VERSION)
self.notify_email('%s_to_preliminary' % self.review_type,
u'Mozilla Add-ons: %s %s Preliminary Reviewed')
log.info(u'Making %s files %s preliminary' %
(self.addon,
', '.join([f.filename for f in self.data['addon_files']])))
log.info(u'Sending email for %s' % (self.addon))
# Assign reviewer incentive scores.
event = ReviewerScore.get_event_by_type(self.addon, self.review_type)
ReviewerScore.award_points(self.request.amo_user, self.addon, event)
def process_super_review(self):
"""Give an addon super review when preliminary."""
self.addon.update(admin_review=True)
if any(f.status for f in self.data['addon_files'] if f.status
in (amo.STATUS_PENDING, amo.STATUS_UNREVIEWED)):
self.log_action(amo.LOG.ESCALATE_VERSION)
self.notify_email('author_super_review',
u'Mozilla Add-ons: %s %s flagged for Admin Review')
self.send_super_mail()