def wrapper(request, *args, **kw): from mkt.access import acl if (acl.action_allowed(request, '*', '*') or not acl.action_allowed(request, 'Restricted', 'UGC')): return f(request, *args, **kw) else: raise PermissionDenied
def is_admin(self, user): """ Returns a boolean indicating whether the passed user passes either OperatorDashboard:* or Feed:Curate. """ return (acl.action_allowed(self.request, 'OperatorDashboard', '*') or acl.action_allowed(self.request, 'Feed', 'Curate'))
def global_settings(request): """Store global Marketplace-wide info. used in the header.""" account_links = [] tools_links = [] footer_links = [] context = {} tools_title = _('Tools') context['user'] = request.user if request.user.is_authenticated(): context['is_reviewer'] = acl.check_reviewer(request) account_links = [ # TODO: Coming soon with payments. # {'text': _('Account History'), # 'href': reverse('account.purchases')}, {'text': _('Account Settings'), 'href': '/settings'}, {'text': _('Change Password'), 'href': 'https://login.persona.org/signin'}, {'text': _('Sign out'), 'href': reverse('users.logout')}, ] if '/developers/' not in request.path: tools_links.append({'text': _('Developer Hub'), 'href': reverse('ecosystem.landing')}) if request.user.is_developer: tools_links.append({'text': _('My Submissions'), 'href': reverse('mkt.developers.apps')}) if '/reviewers/' not in request.path and context['is_reviewer']: footer_links.append({ 'text': _('Reviewer Tools'), 'href': reverse('reviewers.apps.queue_pending'), }) if acl.action_allowed(request, 'AccountLookup', '%'): footer_links.append({'text': _('Lookup Tool'), 'href': reverse('lookup.home')}) if acl.action_allowed(request, 'Admin', '%'): footer_links.append({'text': _('Admin Tools'), 'href': reverse('zadmin.home')}) tools_links += footer_links logged = True else: logged = False DESKTOP = (getattr(request, 'TABLET', None) or not getattr(request, 'MOBILE', None)) context.update(account_links=account_links, settings=settings, mkt=mkt, tools_links=tools_links, tools_title=tools_title, footer_links=footer_links, ADMIN_MESSAGE=get_config('site_notice'), collect_timings_percent=get_collect_timings(), is_admin=acl.action_allowed(request, 'Apps', 'Edit'), DESKTOP=DESKTOP, logged=logged) return context
def is_admin(self, user): """ Returns a boolean indicating whether the passed user passes either OperatorDashboard:* or Feed:Curate. """ return acl.action_allowed(self.request, "OperatorDashboard", "*") or acl.action_allowed( self.request, "Feed", "Curate" )
def wrapper(request, *args, **kw): admin = (action_allowed(request, 'Admin', '%') or action_allowed(request, 'AdminTools', 'View')) if reviewers is True: admin = (admin or action_allowed(request, 'ReviewerAdminTools', 'View')) if admin: return f(request, *args, **kw) raise PermissionDenied
def wrapper(request, *args, **kw): admin = (action_allowed(request, 'Admin', '%') or action_allowed(request, 'AdminTools', 'View')) if reviewers is True: admin = ( admin or action_allowed(request, 'ReviewerAdminTools', 'View')) if admin: return f(request, *args, **kw) raise PermissionDenied
def wrapper(request, *args, **kw): reviewer_perm = acl.check_reviewer(request) moderator_perm = (moderator and acl.action_allowed( request, 'Apps', 'ModerateReview')) view_only = (request.method == 'GET' and acl.action_allowed( request, 'ReviewerTools', 'View')) if (reviewer_perm or moderator_perm or view_only): return f(request, *args, **kw) else: raise PermissionDenied
def queue_tabnav(context): """ Returns tuple of tab navigation for the queue pages. Each tuple contains three elements: (url, tab_code, tab_text) """ request = context['request'] counts = context['queue_counts'] apps_reviewing = AppsReviewing(request).get_apps() # Apps. if acl.action_allowed(request, 'Apps', 'Review'): rv = [ (reverse('reviewers.apps.queue_pending'), 'pending', _('Apps ({0})', counts['pending']).format(counts['pending'])), (reverse('reviewers.apps.queue_rereview'), 'rereview', _('Re-reviews ({0})', counts['rereview']).format( counts['rereview'])), (reverse('reviewers.apps.queue_updates'), 'updates', _('Updates ({0})', counts['updates']).format(counts['updates'])), ] if acl.action_allowed(request, 'Apps', 'ReviewEscalated'): rv.append((reverse('reviewers.apps.queue_escalated'), 'escalated', _('Escalations ({0})', counts['escalated']).format( counts['escalated']))) rv.extend([ (reverse('reviewers.apps.queue_moderated'), 'moderated', _('Moderated Reviews ({0})', counts['moderated']) .format(counts['moderated'])), (reverse('reviewers.apps.apps_reviewing'), 'reviewing', _('Reviewing ({0})').format(len(apps_reviewing))), ]) if acl.action_allowed(request, 'Apps', 'ReviewRegionCN'): url_ = reverse('reviewers.apps.queue_region', args=[mkt.regions.CN.slug]) rv.append((url_, 'region', _('China ({0})').format(counts['region_cn']))) if acl.action_allowed(request, 'Apps', 'ReviewTarako'): url_ = reverse('reviewers.apps.additional_review', args=[QUEUE_TARAKO]) rv.append((url_, 'additional', _('Tarako ({0})').format(counts['additional_tarako']))) else: rv = [] if 'pro' in request.GET: device_srch = device_queue_search(request) rv.append((reverse('reviewers.apps.queue_device'), 'device', _('Device ({0})').format(device_srch.count()),)) return rv
def queue_tabnav(context): """ Returns tuple of tab navigation for the queue pages. Each tuple contains three elements: (url, tab_code, tab_text) """ request = context['request'] counts = context['queue_counts'] apps_reviewing = AppsReviewing(request).get_apps() # Apps. if acl.action_allowed(request, 'Apps', 'Review'): rv = [ (reverse('reviewers.apps.queue_pending'), 'pending', _('Apps ({0})', counts['pending']).format(counts['pending'])), (reverse('reviewers.apps.queue_rereview'), 'rereview', _('Re-reviews ({0})', counts['rereview']).format(counts['rereview'])), (reverse('reviewers.apps.queue_updates'), 'updates', _('Updates ({0})', counts['updates']).format(counts['updates'])), ] if acl.action_allowed(request, 'Apps', 'ReviewEscalated'): rv.append((reverse('reviewers.apps.queue_escalated'), 'escalated', _('Escalations ({0})', counts['escalated']).format(counts['escalated']))) rv.extend([ (reverse('reviewers.apps.queue_moderated'), 'moderated', _('Moderated Reviews ({0})', counts['moderated']).format(counts['moderated'])), (reverse('reviewers.apps.apps_reviewing'), 'reviewing', _('Reviewing ({0})').format(len(apps_reviewing))), ]) if acl.action_allowed(request, 'Apps', 'ReviewRegionCN'): url_ = reverse('reviewers.apps.queue_region', args=[mkt.regions.CN.slug]) rv.append( (url_, 'region', _('China ({0})').format(counts['region_cn']))) if acl.action_allowed(request, 'Apps', 'ReviewTarako'): url_ = reverse('reviewers.apps.additional_review', args=[QUEUE_TARAKO]) rv.append((url_, 'additional', _('Tarako ({0})').format(counts['additional_tarako']))) else: rv = [] if 'pro' in request.GET: device_srch = device_queue_search(request) rv.append(( reverse('reviewers.apps.queue_device'), 'device', _('Device ({0})').format(device_srch.count()), )) return rv
def queue_tabnav(context): """ Returns tuple of tab navigation for the queue pages. Each tuple contains three elements: (url, tab_code, tab_text) """ request = context['request'] counts = context['queue_counts'] apps_reviewing = AppsReviewing(request).get_apps() # Apps. if acl.action_allowed(request, 'Apps', 'Review'): rv = [ (reverse('reviewers.apps.queue_pending'), 'pending', pgettext(counts['pending'], 'Apps ({0})').format(counts['pending'])), (reverse('reviewers.apps.queue_rereview'), 'rereview', pgettext(counts['rereview'], 'Re-reviews ({0})').format(counts['rereview'])), (reverse('reviewers.apps.queue_updates'), 'updates', pgettext(counts['updates'], 'Updates ({0})').format(counts['updates'])), ] if acl.action_allowed(request, 'Apps', 'ReviewEscalated'): rv.append( (reverse('reviewers.apps.queue_escalated'), 'escalated', pgettext(counts['escalated'], 'Escalations ({0})').format(counts['escalated']))) rv.append((reverse('reviewers.apps.apps_reviewing'), 'reviewing', _('Reviewing ({0})').format(len(apps_reviewing))), ) rv.append((reverse('reviewers.apps.queue_homescreen'), 'homescreen', pgettext(counts['homescreen'], 'Homescreens ({0})').format( counts['homescreen'])), ) else: rv = [] if acl.action_allowed(request, 'Apps', 'ModerateReview'): rv.append( (reverse('reviewers.apps.queue_moderated'), 'moderated', pgettext(counts['moderated'], 'Moderated Reviews ({0})').format( counts['moderated'])), ) if acl.action_allowed(request, 'Apps', 'ReadAbuse'): rv.append((reverse('reviewers.apps.queue_abuse'), 'abuse', pgettext(counts['abuse'], 'Abuse Reports ({0})').format( counts['abuse'])), ) if acl.action_allowed(request, 'Websites', 'ReadAbuse'): rv.append((reverse('reviewers.websites.queue_abuse'), 'abusewebsites', pgettext(counts['abusewebsites'], 'Website Abuse Reports ({0})').format( counts['abusewebsites'])), ) return rv
def wrapper(request, *args, **kw): reviewer_perm = acl.check_reviewer(request) moderator_perm = (moderator and acl.action_allowed(request, 'Apps', 'ModerateReview')) view_only = (request.method == 'GET' and acl.action_allowed(request, 'ReviewerTools', 'View')) if (reviewer_perm or moderator_perm or view_only): return f(request, *args, **kw) else: raise PermissionDenied
def app_header(context, app, page_type=''): t = env.get_template('lookup/helpers/app_header.html') is_author = acl.check_ownership(context['request'], app) is_operator = any(g.name == 'Operators' for g in context['request'].groups) is_admin = acl.action_allowed(context['request'], 'Users', 'Edit') is_staff = acl.action_allowed(context['request'], 'Apps', 'Configure') is_reviewer = acl.check_reviewer(context['request']) return jinja2.Markup(t.render({'app': app, 'page_type': page_type, 'is_admin': is_admin, 'is_staff': is_staff, 'is_reviewer': is_reviewer, 'is_author': is_author, 'is_operator': is_operator}))
def logs_tabnav(context): """ Returns tuple of tab navigation for the log pages. Each tuple contains three elements: (named url, tab_code, tab_text) """ request = context["request"] if acl.action_allowed(request, "Apps", "Review"): rv = [("reviewers.apps.logs", "logs", _("Reviews"))] else: rv = [] if acl.action_allowed(request, "Apps", "ModerateReview"): rv.append(("reviewers.apps.moderatelog", "moderatelog", _("Moderated Reviews"))) return rv
def user_can_delete_review(request, review): """Return whether or not the request.user can delete reviews. People who can delete reviews: * The original review author. * Reviewers, but only if they aren't listed as an author of the add-on. * Users in a group with "Users:Edit" privileges. * Users in a group with "Apps:ModerateReview" privileges. """ is_editor = acl.check_reviewer(request) is_author = review.addon.has_author(request.user) return (review.user_id == request.user.id or not is_author and (is_editor or acl.action_allowed(request, 'Users', 'Edit') or acl.action_allowed(request, 'Apps', 'ModerateReview')))
def logs_tabnav(context): """ Returns tuple of tab navigation for the log pages. Each tuple contains three elements: (named url, tab_code, tab_text) """ request = context['request'] if acl.action_allowed(request, 'Apps', 'Review'): rv = [('reviewers.apps.logs', 'logs', _('Reviews'))] else: rv = [] if acl.action_allowed(request, 'Apps', 'ModerateReview'): rv.append(('reviewers.apps.moderatelog', 'moderatelog', _('Moderated Reviews'))) return rv
def filter_queryset(self, qs): """Filter GET requests with active=True, unless we have the permissions to do differently.""" if self.request.method == 'GET': active_parameter = self.request.GET.get('active') fxos_version_parameter = self.request.GET.get('fxos_version') if 'pk' in self.kwargs: # No filtering at all if we're trying to see a detail page: the # permission_classes mechanism will handle the rest for us. It # reveals the existence of the langpack but that's OK. return qs # Handle 'active' filtering. if active_parameter in ('null', 'false'): if action_allowed(self.request, 'LangPacks', '%'): # If active=null, we don't need to filter at all (we show # all langpacks regardless of their 'active' flag value). # If it's false, we only show inactive langpacks. if active_parameter == 'false': qs = qs.filter(active=False) else: # We don't have the permission, but the parameter to filter # was passed, return a permission denied, someone is trying # to see things he shouldn't be able to see. self.permission_denied(self.request) else: qs = qs.filter(active=True) # Handle 'fxos_version' filtering if necessary. if fxos_version_parameter: qs = qs.filter(fxos_version=fxos_version_parameter) return qs
def moderatelog_detail(request, eventlog_id): log = get_object_or_404( ActivityLog.objects.editor_events(), pk=eventlog_id) review = None if len(log.arguments) > 1 and isinstance(log.arguments[1], Review): review = log.arguments[1] form = ModerateLogDetailForm(request.POST or None) is_admin = acl.action_allowed(request, 'ReviewerAdminTools', 'View') can_undelete = review and review.deleted and ( is_admin or request.user.pk == log.user.pk) if (request.method == 'POST' and form.is_valid() and form.cleaned_data['action'] == 'undelete'): if not can_undelete: if not review: raise RuntimeError('Review doesn`t exist.') elif not review.deleted: raise RuntimeError('Review isn`t deleted.') else: raise PermissionDenied ReviewerScore.award_moderation_points( log.user, review.addon, review.id, undo=True) review.undelete() return redirect('reviewers.apps.moderatelog.detail', eventlog_id) data = context(request, log=log, form=form, review=review, can_undelete=can_undelete) return render(request, 'reviewers/moderatelog_detail.html', data)
def get_tags(self, addon): if acl.action_allowed(self.request, 'Apps', 'Edit'): return list(addon.tags.values_list('tag_text', flat=True)) else: return list( addon.tags.filter(restricted=False).values_list('tag_text', flat=True))
def process_disable(self): """ Bans app from Marketplace, clears app from all queues. Changes status to Disabled. Creates Banned/Disabled note. """ if not acl.action_allowed(self.request, 'Apps', 'Edit'): return # Disable disables all files, not just those in this version. self.set_files(mkt.STATUS_DISABLED, File.objects.filter(version__addon=self.addon), hide_disabled_file=True) self.addon.update(status=mkt.STATUS_DISABLED) if self.in_escalate: EscalationQueue.objects.filter(addon=self.addon).delete() if self.in_rereview: RereviewQueue.objects.filter(addon=self.addon).delete() if waffle.switch_is_active('iarc-upgrade-v2'): iarc_unpublish.delay(self.addon.pk) else: set_storefront_data.delay(self.addon.pk, disable=True) self.create_note(mkt.LOG.APP_DISABLED) log.info(u'App %s has been banned by a reviewer.' % self.addon)
def user_summary(request, user_id): user = get_object_or_404(UserProfile, pk=user_id) is_admin = acl.action_allowed(request, 'Users', 'Edit') app_summary = _app_summary(user.pk) # All refunds that this user has requested (probably as a consumer). req = Refund.objects.filter(contribution__user=user) # All instantly-approved refunds that this user has requested. appr = req.filter(status=mkt.REFUND_APPROVED_INSTANT) refund_summary = {'approved': appr.count(), 'requested': req.count()} user_addons = user.addons.order_by('-created') user_addons = paginate(request, user_addons, per_page=15) payment_data = (AddonPaymentData.objects.filter(addon__authors=user) .values(*AddonPaymentData.address_fields()) .distinct()) # If the user is deleted, get the log detailing the delete. try: delete_log = ActivityLog.objects.for_user(user).filter( action=mkt.LOG.DELETE_USER_LOOKUP.id)[0] except IndexError: delete_log = None group_membership_formset = APIGroupMembershipFormSet() provider_portals = get_payment_provider_portals(user=user) return render(request, 'lookup/user_summary.html', {'account': user, 'app_summary': app_summary, 'delete_form': DeleteUserForm(), 'delete_log': delete_log, 'is_admin': is_admin, 'refund_summary': refund_summary, 'user_addons': user_addons, 'payment_data': payment_data, 'provider_portals': provider_portals, 'group_membership_formset': group_membership_formset})
def save(self, addon, commit=False): # We ignore `commit`, since we need it to be `False` so we can save # the ManyToMany fields on our own. addonform = super(AppFormBasic, self).save(commit=False) addonform.save() if 'manifest_url' in self.changed_data: before_url = self.old_manifest_url after_url = self.cleaned_data['manifest_url'] # If a non-admin edited the manifest URL, add to Re-review Queue. if not acl.action_allowed(self.request, 'Admin', '%'): log.info(u'[Webapp:%s] (Re-review) Manifest URL changed ' u'from %s to %s' % (self.instance, before_url, after_url)) msg = (_(u'Manifest URL changed from {before_url} to ' u'{after_url}') .format(before_url=before_url, after_url=after_url)) RereviewQueue.flag(self.instance, amo.LOG.REREVIEW_MANIFEST_URL_CHANGE, msg) # Refetch the new manifest. log.info('Manifest %s refreshed for %s' % (addon.manifest_url, addon)) update_manifests.delay([self.instance.id]) return addonform
def validate_status(self, attrs, source): if not self.object: raise serializers.ValidationError(u'Error getting app.') if source not in attrs: return attrs # Admins can change any status, skip validation for them. # It's dangerous, but with great powers comes great responsability. if ('request' in self.context and self.context['request'].user and acl.action_allowed(self.context['request'], 'Admin', '%')): return attrs # An incomplete app's status can not be changed. if not self.object.is_fully_complete(): raise serializers.ValidationError( self.object.completion_error_msgs()) # Only some specific changes are possible depending on the app current # status. if (self.object.status not in self.allowed_statuses or attrs[source] not in self.allowed_statuses[self.object.status]): raise serializers.ValidationError( 'App status can not be changed to the one you specified.') return attrs
def wrapper(request, addon, *args, **kw): # If there is a 'token' in request.GET we either return 200 or 403. # Otherwise we treat it like a normal django view and redirect to a # login page or check for Apps:Review permissions. allowed = False token = request.GET.get('token') if token and Token.pop(token, data={'app_id': addon.id}): log.info('Token for app:%s was successfully used' % addon.id) allowed = True elif not token and not request.user.is_authenticated(): return redirect_for_login(request) elif acl.action_allowed(request, 'Apps', 'Review'): allowed = True if allowed: if token: log.info('Token provided for app:%s and all was happy' % addon.id) else: log.info('Apps:Review (no token) all happy for app:%s' % addon.id) return f(request, addon, *args, **kw) else: if token: log.info('Token provided for app:%s but was not valid' % addon.id) else: log.info('Apps:Review permissions not met for app:%s' % addon.id) raise PermissionDenied
def validate_status(self, attrs, source): if not self.object: raise serializers.ValidationError(u"Error getting app.") if source not in attrs: return attrs # Admins can change any status, skip validation for them. # It's dangerous, but with great powers comes great responsability. if ( "request" in self.context and self.context["request"].user and acl.action_allowed(self.context["request"], "Admin", "%") ): return attrs # An incomplete app's status can not be changed. if not self.object.is_fully_complete(): raise serializers.ValidationError(self.object.completion_error_msgs()) # Only some specific changes are possible depending on the app current # status. if ( self.object.status not in self.allowed_statuses or attrs[source] not in self.allowed_statuses[self.object.status] ): raise serializers.ValidationError("App status can not be changed to the one you specified.") return attrs
def filter_queryset(self, qs): """Filter GET requests with active=True, unless we have the permissions to do differently.""" if self.request.method == "GET": active_parameter = self.request.GET.get("active") fxos_version_parameter = self.request.GET.get("fxos_version") if "pk" in self.kwargs: # No filtering at all if we're trying to see a detail page: the # permission_classes mechanism will handle the rest for us. It # reveals the existence of the langpack but that's OK. return qs # Handle 'active' filtering. if active_parameter in ("null", "false"): if action_allowed(self.request, "LangPacks", "%"): # If active=null, we don't need to filter at all (we show # all langpacks regardless of their 'active' flag value). # If it's false, we only show inactive langpacks. if active_parameter == "false": qs = qs.filter(active=False) else: # We don't have the permission, but the parameter to filter # was passed, return a permission denied, someone is trying # to see things he shouldn't be able to see. self.permission_denied(self.request) else: qs = qs.filter(active=True) # Handle 'fxos_version' filtering if necessary. if fxos_version_parameter: qs = qs.filter(fxos_version=fxos_version_parameter) return qs
def user_summary(request, user_id): user = get_object_or_404(UserProfile, pk=user_id) is_admin = acl.action_allowed(request, 'Users', 'Edit') app_summary = _app_summary(user.pk) # All refunds that this user has requested (probably as a consumer). req = Refund.objects.filter(contribution__user=user) # All instantly-approved refunds that this user has requested. appr = req.filter(status=amo.REFUND_APPROVED_INSTANT) refund_summary = {'approved': appr.count(), 'requested': req.count()} # TODO: This should return all `addon` types and not just webapps. # -- currently get_details_url() fails on non-webapps so this is a # temp fix. user_addons = (user.addons.filter(type=amo.ADDON_WEBAPP) .order_by('-created')) user_addons = paginate(request, user_addons, per_page=15) payment_data = (AddonPaymentData.objects.filter(addon__authors=user) .values(*AddonPaymentData.address_fields()) .distinct()) # If the user is deleted, get the log detailing the delete. try: delete_log = ActivityLog.objects.for_user(user).filter( action=amo.LOG.DELETE_USER_LOOKUP.id)[0] except IndexError: delete_log = None provider_portals = get_payment_provider_portals(user=user) return render(request, 'lookup/user_summary.html', {'account': user, 'app_summary': app_summary, 'delete_form': DeleteUserForm(), 'delete_log': delete_log, 'is_admin': is_admin, 'refund_summary': refund_summary, 'user_addons': user_addons, 'payment_data': payment_data, 'provider_portals': provider_portals})
def moderatelog_detail(request, eventlog_id): log = get_object_or_404(ActivityLog.objects.editor_events(), pk=eventlog_id) review = None if len(log.arguments) > 1 and isinstance(log.arguments[1], Review): review = log.arguments[1] form = ModerateLogDetailForm(request.POST or None) is_admin = acl.action_allowed(request, 'ReviewerAdminTools', 'View') can_undelete = review and review.deleted and (is_admin or request.user.pk == log.user.pk) if (request.method == 'POST' and form.is_valid() and form.cleaned_data['action'] == 'undelete'): if not can_undelete: if not review: raise RuntimeError('Review doesn`t exist.') elif not review.deleted: raise RuntimeError('Review isn`t deleted.') else: raise PermissionDenied ReviewerScore.award_moderation_points(log.user, review.addon, review.id, undo=True) review.undelete() return redirect('reviewers.apps.moderatelog.detail', eventlog_id) data = context(request, log=log, form=form, review=review, can_undelete=can_undelete) return render(request, 'reviewers/moderatelog_detail.html', data)
def save(self, addon, commit=False): # We ignore `commit`, since we need it to be `False` so we can save # the ManyToMany fields on our own. addonform = super(AppFormBasic, self).save(commit=False) addonform.save() if 'manifest_url' in self.changed_data: before_url = self.old_manifest_url after_url = self.cleaned_data['manifest_url'] # If a non-admin edited the manifest URL, add to Re-review Queue. if not acl.action_allowed(self.request, 'Admin', '%'): log.info(u'[Webapp:%s] (Re-review) Manifest URL changed ' u'from %s to %s' % (self.instance, before_url, after_url)) msg = (_(u'Manifest URL changed from {before_url} to ' u'{after_url}').format(before_url=before_url, after_url=after_url)) RereviewQueue.flag(self.instance, amo.LOG.REREVIEW_MANIFEST_URL_CHANGE, msg) # Refetch the new manifest. log.info('Manifest %s refreshed for %s' % (addon.manifest_url, addon)) update_manifests.delay([self.instance.id]) return addonform
def wrapper(request, webapp, *args, **kw): from mkt.submit.views import _resume def fun(): return f(request, webapp_id=webapp.id, webapp=webapp, *args, **kw) if allow_editors and acl.check_reviewer(request): return fun() if staff and (acl.action_allowed(request, 'Apps', 'Configure') or acl.action_allowed(request, 'Apps', 'ViewConfiguration')): return fun() if support: # Let developers and support people do their thangs. if (acl.check_webapp_ownership(request, webapp, support=True) or acl.check_webapp_ownership(request, webapp, dev=True)): return fun() else: # Require an owner or dev for POST requests. if request.method == 'POST': if acl.check_webapp_ownership(request, webapp, dev=not owner_for_post): return fun() # Ignore disabled so they can view their add-on. elif acl.check_webapp_ownership(request, webapp, viewer=True, ignore_disabled=True): if not skip_submit_check: try: # If it didn't go through the app submission # checklist. Don't die. This will be useful for # creating apps with an API later. step = webapp.appsubmissionchecklist.get_next() except ObjectDoesNotExist: step = None # Redirect to the submit flow if they're not done. if not getattr(f, 'submitting', False) and step: return _resume(webapp, step) return fun() raise PermissionDenied
def wrapper(request, addon, *args, **kw): from mkt.submit.views import _resume fun = lambda: f( request, addon_id=addon.id, addon=addon, *args, **kw) if allow_editors and acl.check_reviewer(request): return fun() if staff and (acl.action_allowed(request, 'Apps', 'Configure') or acl.action_allowed(request, 'Apps', 'ViewConfiguration')): return fun() if support: # Let developers and support people do their thangs. if (acl.check_addon_ownership(request, addon, support=True) or acl.check_addon_ownership(request, addon, dev=True)): return fun() else: # Require an owner or dev for POST requests. if request.method == 'POST': if acl.check_addon_ownership(request, addon, dev=not owner_for_post): return fun() # Ignore disabled so they can view their add-on. elif acl.check_addon_ownership(request, addon, viewer=True, ignore_disabled=True): if not skip_submit_check: try: # If it didn't go through the app submission # checklist. Don't die. This will be useful for # creating apps with an API later. step = addon.appsubmissionchecklist.get_next() except ObjectDoesNotExist: step = None # Redirect to the submit flow if they're not done. if not getattr(f, 'submitting', False) and step: return _resume(addon, step) return fun() raise PermissionDenied
def user_can_delete_review(request, review): """Return whether or not the request.user can delete reviews. People who can delete reviews: * The original review author. * Editors, but only if they aren't listed as an author of the add-on. * Users in a group with "Users:Edit" privileges. * Users in a group with "Addons:Edit" privileges. TODO: Make this more granular when we have multiple reviewer types, e.g. persona reviewers shouldn't be able to delete add-on reviews. """ is_editor = acl.check_reviewer(request) is_author = review.addon.has_author(request.user) return (review.user_id == request.user.id or not is_author and (is_editor or acl.action_allowed(request, 'Users', 'Edit') or acl.action_allowed(request, 'Apps', 'Edit')))
def _view_on_get(request): """Returns whether the user can access this page. If the user is in a group with rule 'ReviewerTools:View' and the request is a GET request, they are allowed to view. """ return (request.method == 'GET' and acl.action_allowed(request, 'ReviewerTools', 'View'))
def user_purchases(request, user_id): """Shows the purchase page for another user.""" user = get_object_or_404(UserProfile, pk=user_id) is_admin = acl.action_allowed(request, 'Users', 'Edit') products = purchase_list(request, user) return render(request, 'lookup/user_purchases.html', {'pager': products, 'account': user, 'is_admin': is_admin, 'single': bool(None), 'show_link': False})
def queue_tabnav(context): """ Returns tuple of tab navigation for the queue pages. Each tuple contains three elements: (url, tab_code, tab_text) """ request = context['request'] counts = context['queue_counts'] apps_reviewing = AppsReviewing(request).get_apps() # Apps. if acl.action_allowed(request, 'Apps', 'Review'): rv = [ (reverse('reviewers.apps.queue_pending'), 'pending', _('Apps ({0})', counts['pending']).format(counts['pending'])), (reverse('reviewers.apps.queue_rereview'), 'rereview', _('Re-reviews ({0})', counts['rereview']).format(counts['rereview'])), (reverse('reviewers.apps.queue_updates'), 'updates', _('Updates ({0})', counts['updates']).format(counts['updates'])), ] if acl.action_allowed(request, 'Apps', 'ReviewEscalated'): rv.append((reverse('reviewers.apps.queue_escalated'), 'escalated', _('Escalations ({0})', counts['escalated']).format(counts['escalated']))) rv.append((reverse('reviewers.apps.apps_reviewing'), 'reviewing', _('Reviewing ({0})').format(len(apps_reviewing))), ) if acl.action_allowed(request, 'Apps', 'ReviewRegionCN'): url_ = reverse('reviewers.apps.queue_region', args=[mkt.regions.CHN.slug]) rv.append( (url_, 'region', _('China ({0})').format(counts['region_cn']))) if acl.action_allowed(request, 'Apps', 'ReviewTarako'): url_ = reverse('reviewers.apps.additional_review', args=[QUEUE_TARAKO]) rv.append((url_, 'additional', _('Tarako ({0})').format(counts['additional_tarako']))) rv.append((reverse('reviewers.apps.queue_homescreen'), 'homescreen', _('Homescreens ({0})', counts['homescreen']).format( counts['homescreen'])), ) else: rv = [] if acl.action_allowed(request, 'Apps', 'ModerateReview'): rv.append((reverse('reviewers.apps.queue_moderated'), 'moderated', _('Moderated Reviews ({0})', counts['moderated']).format( counts['moderated'])), ) if acl.action_allowed(request, 'Apps', 'ReadAbuse'): rv.append((reverse('reviewers.apps.queue_abuse'), 'abuse', _('Abuse Reports ({0})', counts['abuse']).format( counts['abuse'])), ) if acl.action_allowed(request, 'Websites', 'ReadAbuse'): rv.append( (reverse('reviewers.websites.queue_abuse'), 'abusewebsites', _('Website Abuse Reports ({0})', counts['abusewebsites']).format( counts['abusewebsites'])), ) return rv
def user_can_delete_review(request, review): """Return whether or not the request.user can delete reviews. People who can delete reviews: * The original review author. * Reviewers, but only if they aren't listed as an author of the add-on. * Users in a group with "Users:Edit" privileges. * Users in a group with "Apps:ModerateReview" privileges. """ is_editor = acl.check_reviewer(request) is_author = review.addon.has_author(request.user) return ( review.user_id == request.user.id or not is_author and ( is_editor or acl.action_allowed(request, 'Users', 'Edit') or acl.action_allowed(request, 'Apps', 'ModerateReview')))
def motd(request): form = None motd = unmemoized_get_config('mkt_reviewers_motd') if acl.action_allowed(request, 'AppReviewerMOTD', 'Edit'): form = MOTDForm(request.POST or None, initial={'motd': motd}) if form and request.method == 'POST' and form.is_valid(): set_config(u'mkt_reviewers_motd', form.cleaned_data['motd']) messages.success(request, _('Changes successfully saved.')) return redirect(reverse('reviewers.apps.motd')) data = context(request, form=form) return render(request, 'reviewers/motd.html', data)
def user_can_delete_review(request, review): """Return whether or not the request.user can delete reviews. People who can delete reviews: * The original review author. * Editors, but only if they aren't listed as an author of the add-on. * Users in a group with "Users:Edit" privileges. * Users in a group with "Addons:Edit" privileges. TODO: Make this more granular when we have multiple reviewer types, e.g. persona reviewers shouldn't be able to delete add-on reviews. """ is_editor = acl.check_reviewer(request) is_author = review.addon.has_author(request.user) return ( review.user_id == request.user.id or not is_author and ( is_editor or acl.action_allowed(request, 'Users', 'Edit') or acl.action_allowed(request, 'Apps', 'Edit')))
def download(request, langpack_id, **kwargs): langpack = get_object_or_404(LangPack, pk=langpack_id) if langpack.active or action_allowed(request, "LangPacks", "%"): log.info("Downloading package: %s from %s" % (langpack.pk, langpack.file_path)) langpack_etag = hashlib.sha256() langpack_etag.update(langpack.pk) langpack_etag.update(unicode(langpack.file_version)) return HttpResponseSendFile( request, langpack.file_path, content_type="application/zip", etag=langpack_etag.hexdigest() ) else: raise Http404
def edit(request, addon_id, addon): data = { "page": "edit", "addon": addon, "valid_slug": addon.app_slug, "tags": addon.tags.not_blacklisted().values_list("tag_text", flat=True), "previews": addon.get_previews(), "version": addon.current_version or addon.latest_version, } if not addon.is_packaged and data["version"]: data["feature_list"] = [unicode(f) for f in data["version"].features.to_list()] if acl.action_allowed(request, "Apps", "Configure"): data["admin_settings_form"] = forms.AdminSettingsForm(instance=addon, request=request) return render(request, "developers/apps/edit.html", data)
def download(request, langpack_id, **kwargs): langpack = get_object_or_404(LangPack, pk=langpack_id) if langpack.active or action_allowed(request, 'LangPacks', '%'): log.info('Downloading package: %s from %s' % ( langpack.pk, langpack.file_path)) langpack_etag = hashlib.sha256() langpack_etag.update(langpack.pk) langpack_etag.update(unicode(langpack.file_version)) return HttpResponseSendFile(request, langpack.file_path, content_type='application/zip', etag=langpack_etag.hexdigest()) else: raise Http404
def download(request, langpack_id, **kwargs): langpack = get_object_or_404(LangPack, pk=langpack_id) if langpack.active or action_allowed(request, 'LangPacks', '%'): log.info('Downloading package: %s from %s' % ( langpack.pk, langpack.file_path)) langpack_etag = hashlib.sha256() langpack_etag.update(langpack.pk) langpack_etag.update(unicode(langpack.file_version)) return get_file_response(request, langpack.file_path, content_type='application/zip', etag=langpack_etag.hexdigest(), public=True) else: raise Http404
def edit(request, addon_id, addon): data = { 'page': 'edit', 'addon': addon, 'valid_slug': addon.app_slug, 'tags': addon.tags.not_blocked().values_list('tag_text', flat=True), 'previews': addon.get_previews(), 'version': addon.current_version or addon.latest_version } if not addon.is_packaged and data['version']: data['feature_list'] = data['version'].features.to_names() if acl.action_allowed(request, 'Apps', 'Configure'): data['admin_settings_form'] = forms.AdminSettingsForm(instance=addon, request=request) return render(request, 'developers/apps/edit.html', data)
def get_permissions(self, obj): request = self.context["request"] allowed = partial(acl.action_allowed, request) permissions = { "admin": allowed("Admin", "%"), "developer": request.user.is_developer, "localizer": allowed("Localizers", "%"), "lookup": allowed("AccountLookup", "%"), "curator": allowed("Collections", "Curate") or allowed("Feed", "Curate"), "reviewer": acl.action_allowed(request, "Apps", "Review"), "webpay": (allowed("Transaction", "NotifyFailure") and allowed("ProductIcon", "Create")), "stats": allowed("Stats", "View"), "revenue_stats": allowed("RevenueStats", "View"), } return permissions
def clean_tags(request, tags): target = [slugify(t, spaces=True, lower=True) for t in tags.split(',')] target = set(filter(None, target)) min_len = amo.MIN_TAG_LENGTH max_len = Tag._meta.get_field('tag_text').max_length max_tags = amo.MAX_TAGS total = len(target) blacklisted = (Tag.objects.values_list('tag_text', flat=True).filter( tag_text__in=target, blacklisted=True)) if blacklisted: # L10n: {0} is a single tag or a comma-separated list of tags. msg = ngettext('Invalid tag: {0}', 'Invalid tags: {0}', len(blacklisted)).format(', '.join(blacklisted)) raise forms.ValidationError(msg) restricted = (Tag.objects.values_list('tag_text', flat=True).filter( tag_text__in=target, restricted=True)) if not acl.action_allowed(request, 'Apps', 'Edit'): if restricted: # L10n: {0} is a single tag or a comma-separated list of tags. msg = ngettext('"{0}" is a reserved tag and cannot be used.', '"{0}" are reserved tags and cannot be used.', len(restricted)).format('", "'.join(restricted)) raise forms.ValidationError(msg) else: # Admin's restricted tags don't count towards the limit. total = len(target - set(restricted)) if total > max_tags: num = total - max_tags msg = ngettext('You have {0} too many tags.', 'You have {0} too many tags.', num).format(num) raise forms.ValidationError(msg) if any(t for t in target if len(t) > max_len): raise forms.ValidationError( _('All tags must be %s characters ' 'or less after invalid characters are removed.' % max_len)) if any(t for t in target if len(t) < min_len): msg = ngettext("All tags must be at least {0} character.", "All tags must be at least {0} characters.", min_len).format(min_len) raise forms.ValidationError(msg) return target
def clean_tags(request, tags): target = [slugify(t, spaces=True, lower=True) for t in tags.split(',')] target = set(filter(None, target)) min_len = mkt.MIN_TAG_LENGTH max_len = Tag._meta.get_field('tag_text').max_length max_tags = mkt.MAX_TAGS total = len(target) blocked = (Tag.objects.values_list('tag_text', flat=True) .filter(tag_text__in=target, blocked=True)) if blocked: # L10n: {0} is a single tag or a comma-separated list of tags. msg = ngettext('Invalid tag: {0}', 'Invalid tags: {0}', len(blocked)).format(', '.join(blocked)) raise forms.ValidationError(msg) restricted = (Tag.objects.values_list('tag_text', flat=True) .filter(tag_text__in=target, restricted=True)) if not acl.action_allowed(request, 'Apps', 'Edit'): if restricted: # L10n: {0} is a single tag or a comma-separated list of tags. msg = ngettext('"{0}" is a reserved tag and cannot be used.', '"{0}" are reserved tags and cannot be used.', len(restricted)).format('", "'.join(restricted)) raise forms.ValidationError(msg) else: # Admin's restricted tags don't count towards the limit. total = len(target - set(restricted)) if total > max_tags: num = total - max_tags msg = ngettext('You have {0} too many tags.', 'You have {0} too many tags.', num).format(num) raise forms.ValidationError(msg) if any(t for t in target if len(t) > max_len): raise forms.ValidationError( _('All tags must be %s characters ' 'or less after invalid characters are removed.' % max_len)) if any(t for t in target if len(t) < min_len): msg = ngettext("All tags must be at least {0} character.", "All tags must be at least {0} characters.", min_len).format(min_len) raise forms.ValidationError(msg) return target
def user_activity(request, user_id): """Shows the user activity page for another user.""" user = get_object_or_404(UserProfile, pk=user_id) products = purchase_list(request, user) is_admin = acl.action_allowed(request, 'Users', 'Edit') user_items = ActivityLog.objects.for_user(user).exclude( action__in=mkt.LOG_HIDE_DEVELOPER) admin_items = ActivityLog.objects.for_user(user).filter( action__in=mkt.LOG_HIDE_DEVELOPER) mkt.log(mkt.LOG.ADMIN_VIEWED_LOG, request.user, user=user) return render(request, 'lookup/user_activity.html', {'pager': products, 'account': user, 'is_admin': is_admin, 'single': bool(None), 'user_items': user_items, 'admin_items': admin_items, 'show_link': False})
def get_permissions(self, obj): request = self.context['request'] allowed = partial(acl.action_allowed, request) permissions = { 'admin': allowed('Admin', '%'), 'developer': request.user.is_developer, 'localizer': allowed('Localizers', '%'), 'lookup': allowed('AccountLookup', '%'), 'curator': allowed('Collections', 'Curate') or allowed('Feed', 'Curate'), 'reviewer': acl.action_allowed(request, 'Apps', 'Review'), 'webpay': (allowed('Transaction', 'NotifyFailure') and allowed('ProductIcon', 'Create')), 'stats': allowed('Stats', 'View'), 'revenue_stats': allowed('RevenueStats', 'View'), } return permissions
def manifest(request, uuid): """Returns the "mini" manifest for a langpack.""" try: uuid_hex = UUID(uuid).hex except ValueError: raise Http404 langpack = get_object_or_404(LangPack, pk=uuid_hex) if langpack.active or action_allowed(request, 'LangPacks', '%'): manifest_contents, langpack_etag = langpack.get_minifest_contents() @condition(last_modified_func=lambda request: langpack.modified, etag_func=lambda request: langpack_etag) def _inner_view(request): return HttpResponse(manifest_contents, content_type=MANIFEST_CONTENT_TYPE) return _inner_view(request) raise Http404
def save(self, addon, commit=False): # We ignore `commit`, since we need it to be `False` so we can save # the ManyToMany fields on our own. addonform = super(AppFormBasic, self).save(commit=False) addonform.save() if 'manifest_url' in self.changed_data: before_url = self.old_manifest_url after_url = self.cleaned_data['manifest_url'] # If a non-admin edited the manifest URL, add to Re-review Queue. if not acl.action_allowed(self.request, 'Admin', '%'): log.info(u'[Webapp:%s] (Re-review) Manifest URL changed ' u'from %s to %s' % (self.instance, before_url, after_url)) msg = (_(u'Manifest URL changed from {before_url} to ' u'{after_url}') .format(before_url=before_url, after_url=after_url)) RereviewQueue.flag(self.instance, mkt.LOG.REREVIEW_MANIFEST_URL_CHANGE, msg) # Refetch the new manifest. log.info('Manifest %s refreshed for %s' % (addon.manifest_url, addon)) update_manifests.delay([self.instance.id]) tags_new = self.cleaned_data['tags'] tags_old = [slugify(t, spaces=True) for t in self.get_tags(addon)] add_tags = set(tags_new) - set(tags_old) del_tags = set(tags_old) - set(tags_new) # Add new tags. for t in add_tags: Tag(tag_text=t).save_tag(addon) # Remove old tags. for t in del_tags: Tag(tag_text=t).remove_tag(addon) return addonform
def performance(request, username=None): is_admin = acl.action_allowed(request, 'Admin', '%') if username: if username == request.user.username: user = request.user elif is_admin: user = get_object_or_404(UserProfile, username=username) else: raise http.Http404 else: user = request.user today = datetime.date.today() month_ago = today - datetime.timedelta(days=30) year_ago = today - datetime.timedelta(days=365) total = ReviewerScore.get_total(user) totals = ReviewerScore.get_performance(user) months = ReviewerScore.get_performance_since(user, month_ago) years = ReviewerScore.get_performance_since(user, year_ago) def _sum(iter): return sum(s.total or 0 for s in iter) performance = { 'month': _sum(months), 'year': _sum(years), 'total': _sum(totals), } ctx = context( request, **{ 'profile': user, 'total': total, 'performance': performance, }) return render(request, 'reviewers/performance.html', ctx)