addons-server/apps/devhub/helpers.py

218 строки
6.8 KiB
Python

from collections import defaultdict
import urllib
import chardet
import jinja2
from jingo import register
from jingo.helpers import datetime
from tower import ugettext as _, ungettext as ngettext
import amo
from amo.urlresolvers import reverse
from amo.helpers import breadcrumbs, impala_breadcrumbs, page_title
from access import acl
from addons.helpers import new_context
register.function(acl.check_addon_ownership)
@register.inclusion_tag('devhub/addons/listing/items.html')
@jinja2.contextfunction
def dev_addon_listing_items(context, addons, src=None, notes={}):
return new_context(**locals())
@register.function
@jinja2.contextfunction
def dev_page_title(context, title=None, addon=None):
"""Wrapper for devhub page titles."""
if addon:
title = u'%s :: %s' % (title, addon.name)
else:
devhub = _('Developer Hub')
title = '%s :: %s' % (title, devhub) if title else devhub
return page_title(context, title, force_webapps=context.get('webapp'))
@register.function
@jinja2.contextfunction
def docs_page_title(context, title=None):
"""Wrapper for docs page titles."""
devhub = _('Add-on Documentation :: Developer Hub')
title = '%s :: %s' % (title, devhub) if title else devhub
return page_title(context, title)
@register.function
@jinja2.contextfunction
def dev_breadcrumbs(context, addon=None, items=None, add_default=False,
impala=False):
"""
Wrapper function for ``breadcrumbs``. Prepends 'Developer Hub'
breadcrumbs.
**items**
list of [(url, label)] to be inserted after Add-on.
**addon**
Adds the Add-on name to the end of the trail. If items are
specified then the Add-on will be linked.
**add_default**
Prepends trail back to home when True. Default is False.
**impala**
Whether to use the impala_breadcrumbs helper. Default is False.
"""
if context.get('webapp'):
crumbs = []
title = _('My Apps')
link = reverse('devhub.apps')
else:
crumbs = [(reverse('devhub.index'), _('Developer Hub'))]
title = _('My Add-ons')
link = reverse('devhub.addons')
if not addon and not items:
# We are at the end of the crumb trail.
crumbs.append((None, title))
else:
crumbs.append((link, title))
if addon:
if items:
url = addon.get_dev_url()
else:
# The Addon is the end of the trail.
url = None
crumbs.append((url, addon.name))
if items:
crumbs.extend(items)
if len(crumbs) == 1:
crumbs = []
if impala:
return impala_breadcrumbs(context, crumbs, add_default)
else:
return breadcrumbs(context, crumbs, add_default)
@register.function
@jinja2.contextfunction
def docs_breadcrumbs(context, items=None):
"""
Wrapper function for `breadcrumbs` for devhub docs.
"""
crumbs = [(reverse('devhub.index'), _('Developer Hub')),
(None, _('Developer Docs'))]
if items:
crumbs.extend(items)
return breadcrumbs(context, crumbs, True)
@register.inclusion_tag('devhub/versions/add_file_modal.html')
@jinja2.contextfunction
def add_file_modal(context, title, action, upload_url, action_label):
return new_context(modal_type='file', context=context, title=title,
action=action, upload_url=upload_url,
action_label=action_label)
@register.inclusion_tag('devhub/versions/add_file_modal.html')
@jinja2.contextfunction
def add_version_modal(context, title, action, upload_url, action_label):
return new_context(modal_type='version', context=context, title=title,
action=action, upload_url=upload_url,
action_label=action_label)
@register.function
def status_choices(addon):
"""Return a dict like STATUS_CHOICES customized for the addon status."""
# Show "awaiting full review" for unreviewed files on that track.
choices = dict(amo.STATUS_CHOICES)
if addon.status in (amo.STATUS_NOMINATED, amo.STATUS_LITE_AND_NOMINATED,
amo.STATUS_PUBLIC):
choices[amo.STATUS_UNREVIEWED] = choices[amo.STATUS_NOMINATED]
return choices
@register.inclusion_tag('devhub/versions/file_status_message.html')
def file_status_message(file, addon, file_history=False):
choices = status_choices(addon)
return {'fileid': file.id, 'platform': file.amo_platform.name,
'created': datetime(file.created),
'status': choices[file.status],
'file_history': file_history,
'actions': amo.LOG_REVIEW_EMAIL_USER,
'status_date': datetime(file.datestatuschanged)}
@register.function
def dev_files_status(files, addon):
"""Group files by their status (and files per status)."""
status_count = defaultdict(int)
choices = status_choices(addon)
for file in files:
status_count[file.status] += 1
return [(count, unicode(choices[status])) for
(status, count) in status_count.items()]
@register.function
def status_class(addon):
classes = {
amo.STATUS_NULL: 'incomplete',
amo.STATUS_UNREVIEWED: 'unreviewed',
amo.STATUS_NOMINATED: 'nominated',
amo.STATUS_PUBLIC: 'fully-approved',
amo.STATUS_DISABLED: 'admin-disabled',
amo.STATUS_LITE: 'lite',
amo.STATUS_LITE_AND_NOMINATED: 'lite-nom',
amo.STATUS_PURGATORY: 'purgatory',
amo.STATUS_DELETED: 'deleted',
amo.STATUS_REJECTED: 'rejected',
}
if addon.disabled_by_user and addon.status != amo.STATUS_DISABLED:
cls = 'disabled'
else:
cls = classes.get(addon.status, 'none')
return 'status-' + cls
@register.function
def log_action_class(action_id):
if action_id in amo.LOG_BY_ID:
cls = amo.LOG_BY_ID[action_id].action_class
if cls is not None:
return 'action-' + cls
@register.function
def summarize_validation(validation):
"""Readable summary of add-on validation results."""
# L10n: first parameter is the number of errors
errors = ngettext('{0} error', '{0} errors',
validation.errors).format(validation.errors)
# L10n: first parameter is the number of warnings
warnings = ngettext('{0} warning', '{0} warnings',
validation.warnings).format(validation.warnings)
return "%s, %s" % (errors, warnings)
@register.filter
def display_url(url):
"""Display a URL like the browser URL bar would.
Note: returns a Unicode object, not a valid URL.
"""
if isinstance(url, unicode):
# Byte sequences will be url encoded so convert
# to bytes here just to stop auto decoding.
url = url.encode('utf8')
bytes = urllib.unquote(url)
c = chardet.detect(bytes)
return bytes.decode(c['encoding'], 'replace')