def _review(request, addon, version): if (not settings.ALLOW_SELF_REVIEWS and not acl.action_allowed(request, 'Admin', '%') and addon.has_author(request.amo_user)): messages.warning(request, _('Self-reviews are not allowed.')) return redirect(reverse('reviewers.home')) if (addon.status == amo.STATUS_BLOCKED and not acl.action_allowed(request, 'Apps', 'ReviewEscalated')): messages.warning( request, _('Only senior reviewers can review blocklisted apps.')) return redirect(reverse('reviewers.home')) attachment_formset = CommAttachmentFormSet(data=request.POST or None, files=request.FILES or None, prefix='attachment') form = forms.get_review_form(data=request.POST or None, files=request.FILES or None, request=request, addon=addon, version=version, attachment_formset=attachment_formset) postdata = request.POST if request.method == 'POST' else None all_forms = [form, attachment_formset] if version: features_list = [unicode(f) for f in version.features.to_list()] appfeatures_form = AppFeaturesForm(data=postdata, instance=version.features) all_forms.append(appfeatures_form) else: appfeatures_form = None features_list = None queue_type = form.helper.review_type redirect_url = reverse('reviewers.apps.queue_%s' % queue_type) is_admin = acl.action_allowed(request, 'Apps', 'Edit') if request.method == 'POST' and all(f.is_valid() for f in all_forms): old_types = set(o.id for o in addon.device_types) new_types = set(form.cleaned_data.get('device_override')) old_features = set(features_list) new_features = set(unicode(f) for f in appfeatures_form.instance.to_list()) if form.cleaned_data.get('action') == 'public': if old_types != new_types: # The reviewer overrode the device types. We need to not # publish this app immediately. if addon.make_public == amo.PUBLIC_IMMEDIATELY: addon.update(make_public=amo.PUBLIC_WAIT) # And update the device types to what the reviewer set. AddonDeviceType.objects.filter(addon=addon).delete() for device in form.cleaned_data.get('device_override'): addon.addondevicetype_set.create(device_type=device) # Log that the reviewer changed the device types. added_devices = new_types - old_types removed_devices = old_types - new_types msg = _(u'Device(s) changed by ' 'reviewer: {0}').format(', '.join( [_(u'Added {0}').format(unicode(amo.DEVICE_TYPES[d].name)) for d in added_devices] + [_(u'Removed {0}').format( unicode(amo.DEVICE_TYPES[d].name)) for d in removed_devices])) amo.log(amo.LOG.REVIEW_DEVICE_OVERRIDE, addon, addon.current_version, details={'comments': msg}) if old_features != new_features: # The reviewer overrode the requirements. We need to not # publish this app immediately. if addon.make_public == amo.PUBLIC_IMMEDIATELY: addon.update(make_public=amo.PUBLIC_WAIT) appfeatures_form.save(mark_for_rereview=False) # Log that the reviewer changed the minimum requirements. added_features = new_features - old_features removed_features = old_features - new_features fmt = ', '.join( [_(u'Added {0}').format(f) for f in added_features] + [_(u'Removed {0}').format(f) for f in removed_features]) # L10n: {0} is the list of requirements changes. msg = _(u'Requirements changed by reviewer: {0}').format(fmt) amo.log(amo.LOG.REVIEW_FEATURES_OVERRIDE, addon, addon.current_version, details={'comments': msg}) score = form.helper.process() if form.cleaned_data.get('notify'): # TODO: bug 741679 for implementing notifications in Marketplace. EditorSubscription.objects.get_or_create(user=request.amo_user, addon=addon) is_tarako = form.cleaned_data.get('is_tarako', False) if is_tarako: Tag(tag_text='tarako').save_tag(addon) else: Tag(tag_text='tarako').remove_tag(addon) # Success message. if score: score = ReviewerScore.objects.filter(user=request.amo_user)[0] # L10N: {0} is the type of review. {1} is the points they earned. # {2} is the points they now have total. success = _( u'"{0}" successfully processed (+{1} points, {2} total).' .format(unicode(amo.REVIEWED_CHOICES[score.note_key]), score.score, ReviewerScore.get_total(request.amo_user))) else: success = _('Review successfully processed.') messages.success(request, success) return redirect(redirect_url) canned = CannedResponse.objects.all() actions = form.helper.actions.items() try: if not version: raise Version.DoesNotExist show_diff = (addon.versions.exclude(id=version.id) .filter(files__isnull=False, created__lt=version.created, files__status=amo.STATUS_PUBLIC) .latest()) except Version.DoesNotExist: show_diff = None # The actions we should show a minimal form from. actions_minimal = [k for (k, a) in actions if not a.get('minimal')] # We only allow the user to check/uncheck files for "pending" allow_unchecking_files = form.helper.review_type == "pending" versions = (Version.with_deleted.filter(addon=addon) .order_by('-created') .transform(Version.transformer_activity) .transform(Version.transformer)) product_attrs = { 'product': json.dumps( product_as_dict(request, addon, False, 'reviewer'), cls=JSONEncoder), 'manifest_url': addon.manifest_url, } pager = paginate(request, versions, 10) num_pages = pager.paginator.num_pages count = pager.paginator.count ctx = context(request, version=version, product=addon, pager=pager, num_pages=num_pages, count=count, form=form, canned=canned, is_admin=is_admin, status_types=amo.MKT_STATUS_CHOICES, show_diff=show_diff, allow_unchecking_files=allow_unchecking_files, actions=actions, actions_minimal=actions_minimal, tab=queue_type, product_attrs=product_attrs, attachment_formset=attachment_formset, appfeatures_form=appfeatures_form) if features_list is not None: ctx['feature_list'] = features_list return render(request, 'reviewers/review.html', ctx)
def _review(request, addon, version): if (not settings.ALLOW_SELF_REVIEWS and not acl.action_allowed(request, 'Admin', '%') and addon.has_author(request.user)): messages.warning(request, _('Self-reviews are not allowed.')) return redirect(reverse('reviewers.home')) if (addon.status == amo.STATUS_BLOCKED and not acl.action_allowed(request, 'Apps', 'ReviewEscalated')): messages.warning( request, _('Only senior reviewers can review blocklisted apps.')) return redirect(reverse('reviewers.home')) attachment_formset = CommAttachmentFormSet(data=request.POST or None, files=request.FILES or None, prefix='attachment') form = forms.get_review_form(data=request.POST or None, files=request.FILES or None, request=request, addon=addon, version=version, attachment_formset=attachment_formset) postdata = request.POST if request.method == 'POST' else None all_forms = [form, attachment_formset] if version: features_list = [unicode(f) for f in version.features.to_list()] appfeatures_form = AppFeaturesForm(data=postdata, instance=version.features) all_forms.append(appfeatures_form) else: appfeatures_form = None features_list = None queue_type = form.helper.review_type redirect_url = reverse('reviewers.apps.queue_%s' % queue_type) is_admin = acl.action_allowed(request, 'Apps', 'Edit') if request.method == 'POST' and all(f.is_valid() for f in all_forms): old_types = set(o.id for o in addon.device_types) new_types = set(form.cleaned_data.get('device_override')) old_features = set(features_list) new_features = set( unicode(f) for f in appfeatures_form.instance.to_list()) if form.cleaned_data.get('action') == 'public': if old_types != new_types: # The reviewer overrode the device types. We need to not # publish this app immediately. if addon.publish_type == amo.PUBLISH_IMMEDIATE: addon.update(publish_type=amo.PUBLISH_PRIVATE) # And update the device types to what the reviewer set. AddonDeviceType.objects.filter(addon=addon).delete() for device in form.cleaned_data.get('device_override'): addon.addondevicetype_set.create(device_type=device) # Log that the reviewer changed the device types. added_devices = new_types - old_types removed_devices = old_types - new_types msg = _( u'Device(s) changed by ' u'reviewer: {0}' ).format(', '.join([ _(u'Added {0}').format(unicode(amo.DEVICE_TYPES[d].name)) for d in added_devices ] + [ _(u'Removed {0}').format(unicode(amo.DEVICE_TYPES[d].name)) for d in removed_devices ])) log_reviewer_action(addon, request.user, msg, amo.LOG.REVIEW_DEVICE_OVERRIDE) if old_features != new_features: # The reviewer overrode the requirements. We need to not # publish this app immediately. if addon.publish_type == amo.PUBLISH_IMMEDIATE: addon.update(publish_type=amo.PUBLISH_PRIVATE) appfeatures_form.save(mark_for_rereview=False) # Log that the reviewer changed the minimum requirements. added_features = new_features - old_features removed_features = old_features - new_features fmt = ', '.join( [_(u'Added {0}').format(f) for f in added_features] + [_(u'Removed {0}').format(f) for f in removed_features]) # L10n: {0} is the list of requirements changes. msg = _(u'Requirements changed by reviewer: {0}').format(fmt) log_reviewer_action(addon, request.user, msg, amo.LOG.REVIEW_FEATURES_OVERRIDE) score = form.helper.process() if form.cleaned_data.get('notify'): # TODO: bug 741679 for implementing notifications in Marketplace. EditorSubscription.objects.get_or_create(user=request.user, addon=addon) is_tarako = form.cleaned_data.get('is_tarako', False) if is_tarako: Tag(tag_text='tarako').save_tag(addon) else: Tag(tag_text='tarako').remove_tag(addon) # Success message. if score: score = ReviewerScore.objects.filter(user=request.user)[0] # L10N: {0} is the type of review. {1} is the points they earned. # {2} is the points they now have total. success = _( u'"{0}" successfully processed (+{1} points, {2} total).'. format(unicode(amo.REVIEWED_CHOICES[score.note_key]), score.score, ReviewerScore.get_total(request.user))) else: success = _('Review successfully processed.') messages.success(request, success) return redirect(redirect_url) canned = CannedResponse.objects.all() actions = form.helper.actions.items() try: if not version: raise Version.DoesNotExist show_diff = (addon.versions.exclude(id=version.id).filter( files__isnull=False, created__lt=version.created, files__status=amo.STATUS_PUBLIC).latest()) except Version.DoesNotExist: show_diff = None # The actions we should show a minimal form from. actions_minimal = [k for (k, a) in actions if not a.get('minimal')] # We only allow the user to check/uncheck files for "pending" allow_unchecking_files = form.helper.review_type == "pending" versions = (Version.with_deleted.filter( addon=addon).order_by('-created').transform( Version.transformer_activity).transform(Version.transformer)) product_attrs = { 'product': json.dumps(product_as_dict(request, addon, False, 'reviewer'), cls=JSONEncoder), 'manifest_url': addon.manifest_url, } pager = paginate(request, versions, 10) num_pages = pager.paginator.num_pages count = pager.paginator.count ctx = context(request, version=version, product=addon, pager=pager, num_pages=num_pages, count=count, form=form, canned=canned, is_admin=is_admin, status_types=amo.STATUS_CHOICES, show_diff=show_diff, allow_unchecking_files=allow_unchecking_files, actions=actions, actions_minimal=actions_minimal, tab=queue_type, product_attrs=product_attrs, attachment_formset=attachment_formset, appfeatures_form=appfeatures_form) if features_list is not None: ctx['feature_list'] = features_list return render(request, 'reviewers/review.html', ctx)
def addons_section(request, addon_id, addon, section, editable=False): models = { 'basic': AppFormBasic, 'media': AppFormMedia, 'details': AppFormDetails, 'support': AppFormSupport, 'technical': AppFormTechnical, 'admin': forms.AdminSettingsForm } is_dev = acl.check_addon_ownership(request, addon, dev=True) if section not in models: raise http.Http404() version = addon.current_version or addon.latest_version tags, previews, restricted_tags = [], [], [] cat_form = appfeatures = appfeatures_form = version_form = None formdata = request.POST if request.method == 'POST' else None # Permissions checks. # Only app owners can edit any of the details of their apps. # Users with 'Apps:Configure' can edit the admin settings. if (section != 'admin' and not is_dev) or ( section == 'admin' and not acl.action_allowed(request, 'Apps', 'Configure') and not acl.action_allowed(request, 'Apps', 'ViewConfiguration')): raise PermissionDenied if section == 'basic': cat_form = CategoryForm(formdata, product=addon, request=request) # Only show/use the release notes form for hosted apps, packaged apps # can do that from the version edit page. if not addon.is_packaged: version_form = AppVersionForm(formdata, instance=version) elif section == 'media': previews = PreviewFormSet(request.POST or None, prefix='files', queryset=addon.get_previews()) elif section == 'technical': # Only show/use the features form for hosted apps, packaged apps # can do that from the version edit page. if not addon.is_packaged: appfeatures = version.features appfeatures_form = AppFeaturesForm(formdata, instance=appfeatures) elif section == 'admin': tags = addon.tags.not_blacklisted().values_list('tag_text', flat=True) restricted_tags = addon.tags.filter(restricted=True) # Get the slug before the form alters it to the form data. valid_slug = addon.app_slug if editable: if request.method == 'POST': if (section == 'admin' and not acl.action_allowed(request, 'Apps', 'Configure')): raise PermissionDenied form = models[section](formdata, request.FILES, instance=addon, version=version, request=request) all_forms = [form, previews] for additional_form in (appfeatures_form, cat_form, version_form): if additional_form: all_forms.append(additional_form) if all(not f or f.is_valid() for f in all_forms): if cat_form: cat_form.save() addon = form.save(addon) if appfeatures_form: appfeatures_form.save() if version_form: # We are re-using version_form without displaying all its # fields, so we need to override the boolean fields, # otherwise they'd be considered empty and therefore False. version_form.cleaned_data['publish_immediately'] = ( version_form.fields['publish_immediately'].initial) version_form.save() if 'manifest_url' in form.changed_data: addon.update( app_domain=addon.domain_from_url(addon.manifest_url)) update_manifests([addon.pk]) if previews: for preview in previews.forms: preview.save(addon) editable = False if section == 'media': amo.log(amo.LOG.CHANGE_ICON, addon) else: amo.log(amo.LOG.EDIT_PROPERTIES, addon) valid_slug = addon.app_slug else: form = models[section](instance=addon, version=version, request=request) else: form = False data = { 'addon': addon, 'version': version, 'form': form, 'editable': editable, 'tags': tags, 'restricted_tags': restricted_tags, 'cat_form': cat_form, 'version_form': version_form, 'preview_form': previews, 'valid_slug': valid_slug, } if appfeatures_form and appfeatures: data.update({ 'appfeatures': appfeatures, 'feature_list': [unicode(f) for f in appfeatures.to_list()], 'appfeatures_form': appfeatures_form }) return render(request, 'developers/apps/edit/%s.html' % section, data)
def addons_section(request, addon_id, addon, section, editable=False): models = { "basic": AppFormBasic, "media": AppFormMedia, "details": AppFormDetails, "support": AppFormSupport, "technical": AppFormTechnical, "admin": forms.AdminSettingsForm, } is_dev = acl.check_addon_ownership(request, addon, dev=True) if section not in models: raise http.Http404() version = addon.current_version or addon.latest_version tags, previews, restricted_tags = [], [], [] cat_form = appfeatures = appfeatures_form = version_form = None formdata = request.POST if request.method == "POST" else None # Permissions checks. # Only app owners can edit any of the details of their apps. # Users with 'Apps:Configure' can edit the admin settings. if (section != "admin" and not is_dev) or ( section == "admin" and not acl.action_allowed(request, "Apps", "Configure") and not acl.action_allowed(request, "Apps", "ViewConfiguration") ): raise PermissionDenied if section == "basic": cat_form = CategoryForm(formdata, product=addon, request=request) # Only show/use the release notes form for hosted apps, packaged apps # can do that from the version edit page. if not addon.is_packaged: version_form = AppVersionForm(formdata, instance=version) elif section == "media": previews = PreviewFormSet(request.POST or None, prefix="files", queryset=addon.get_previews()) elif section == "technical": # Only show/use the features form for hosted apps, packaged apps # can do that from the version edit page. if not addon.is_packaged: appfeatures = version.features appfeatures_form = AppFeaturesForm(formdata, instance=appfeatures) elif section == "admin": tags = addon.tags.not_blacklisted().values_list("tag_text", flat=True) restricted_tags = addon.tags.filter(restricted=True) # Get the slug before the form alters it to the form data. valid_slug = addon.app_slug if editable: if request.method == "POST": if section == "admin" and not acl.action_allowed(request, "Apps", "Configure"): raise PermissionDenied form = models[section](formdata, request.FILES, instance=addon, version=version, request=request) all_forms = [form, previews] for additional_form in (appfeatures_form, cat_form, version_form): if additional_form: all_forms.append(additional_form) if all(not f or f.is_valid() for f in all_forms): if cat_form: cat_form.save() addon = form.save(addon) if appfeatures_form: appfeatures_form.save() if version_form: # We are re-using version_form without displaying all its # fields, so we need to override the boolean fields, # otherwise they'd be considered empty and therefore False. version_form.cleaned_data["publish_immediately"] = version_form.fields[ "publish_immediately" ].initial version_form.save() if "manifest_url" in form.changed_data: addon.update(app_domain=addon.domain_from_url(addon.manifest_url)) update_manifests([addon.pk]) if previews: for preview in previews.forms: preview.save(addon) editable = False if section == "media": amo.log(amo.LOG.CHANGE_ICON, addon) else: amo.log(amo.LOG.EDIT_PROPERTIES, addon) valid_slug = addon.app_slug else: form = models[section](instance=addon, version=version, request=request) else: form = False data = { "addon": addon, "version": version, "form": form, "editable": editable, "tags": tags, "restricted_tags": restricted_tags, "cat_form": cat_form, "version_form": version_form, "preview_form": previews, "valid_slug": valid_slug, } if appfeatures_form and appfeatures: data.update( { "appfeatures": appfeatures, "feature_list": [unicode(f) for f in appfeatures.to_list()], "appfeatures_form": appfeatures_form, } ) return render(request, "developers/apps/edit/%s.html" % section, data)
def _review(request, addon, version): if ( not settings.ALLOW_SELF_REVIEWS and not acl.action_allowed(request, "Admin", "%") and addon.has_author(request.amo_user) ): messages.warning(request, _("Self-reviews are not allowed.")) return redirect(reverse("reviewers.home")) if addon.status == amo.STATUS_BLOCKED and not acl.action_allowed(request, "Apps", "ReviewEscalated"): messages.warning(request, _("Only senior reviewers can review blocklisted apps.")) return redirect(reverse("reviewers.home")) attachment_formset = forms.AttachmentFormSet( data=request.POST or None, files=request.FILES or None, prefix="attachment" ) form = forms.get_review_form( data=request.POST or None, files=request.FILES or None, request=request, addon=addon, version=version, attachment_formset=attachment_formset, ) postdata = request.POST if request.method == "POST" else None all_forms = [form, attachment_formset] if waffle.switch_is_active("buchets") and version: features_list = [unicode(f) for f in version.features.to_list()] appfeatures_form = AppFeaturesForm(data=postdata, instance=version.features) all_forms.append(appfeatures_form) else: appfeatures_form = None features_list = None queue_type = form.helper.review_type redirect_url = reverse("reviewers.apps.queue_%s" % queue_type) is_admin = acl.action_allowed(request, "Addons", "Edit") if request.method == "POST" and all(f.is_valid() for f in all_forms): old_types = set(o.id for o in addon.device_types) new_types = set(form.cleaned_data.get("device_override")) if waffle.switch_is_active("buchets"): old_features = set(features_list) new_features = set(unicode(f) for f in appfeatures_form.instance.to_list()) if form.cleaned_data.get("action") == "public": if old_types != new_types: # The reviewer overrode the device types. We need to not # publish this app immediately. if addon.make_public == amo.PUBLIC_IMMEDIATELY: addon.update(make_public=amo.PUBLIC_WAIT) # And update the device types to what the reviewer set. AddonDeviceType.objects.filter(addon=addon).delete() for device in form.cleaned_data.get("device_override"): addon.addondevicetype_set.create(device_type=device) # Log that the reviewer changed the device types. added_devices = new_types - old_types removed_devices = old_types - new_types msg = _(u"Device(s) changed by " "reviewer: {0}").format( ", ".join( [_(u"Added {0}").format(unicode(amo.DEVICE_TYPES[d].name)) for d in added_devices] + [_(u"Removed {0}").format(unicode(amo.DEVICE_TYPES[d].name)) for d in removed_devices] ) ) amo.log(amo.LOG.REVIEW_DEVICE_OVERRIDE, addon, addon.current_version, details={"comments": msg}) if waffle.switch_is_active("buchets") and old_features != new_features: # The reviewer overrode the requirements. We need to not # publish this app immediately. if addon.make_public == amo.PUBLIC_IMMEDIATELY: addon.update(make_public=amo.PUBLIC_WAIT) appfeatures_form.save(mark_for_rereview=False) # Log that the reviewer changed the minimum requirements. added_features = new_features - old_features removed_features = old_features - new_features fmt = ", ".join( [_(u"Added {0}").format(f) for f in added_features] + [_(u"Removed {0}").format(f) for f in removed_features] ) # L10n: {0} is the list of requirements changes. msg = _(u"Requirements changed by reviewer: {0}").format(fmt) amo.log(amo.LOG.REVIEW_FEATURES_OVERRIDE, addon, addon.current_version, details={"comments": msg}) form.helper.process() if form.cleaned_data.get("notify"): EditorSubscription.objects.get_or_create(user=request.amo_user, addon=addon) messages.success(request, _("Review successfully processed.")) return redirect(redirect_url) canned = AppCannedResponse.objects.all() actions = form.helper.actions.items() try: if not version: raise Version.DoesNotExist show_diff = ( addon.versions.exclude(id=version.id) .filter(files__isnull=False, created__lt=version.created, files__status=amo.STATUS_PUBLIC) .latest() ) except Version.DoesNotExist: show_diff = None # The actions we should show a minimal form from. actions_minimal = [k for (k, a) in actions if not a.get("minimal")] # We only allow the user to check/uncheck files for "pending" allow_unchecking_files = form.helper.review_type == "pending" versions = ( Version.with_deleted.filter(addon=addon) .order_by("-created") .transform(Version.transformer_activity) .transform(Version.transformer) ) product_attrs = { "product": json.dumps(product_as_dict(request, addon, False, "reviewer"), cls=JSONEncoder), "manifest_url": addon.manifest_url, } pager = paginate(request, versions, 10) num_pages = pager.paginator.num_pages count = pager.paginator.count ctx = context( request, version=version, product=addon, pager=pager, num_pages=num_pages, count=count, flags=Review.objects.filter(addon=addon, flag=True), form=form, canned=canned, is_admin=is_admin, status_types=amo.STATUS_CHOICES, show_diff=show_diff, allow_unchecking_files=allow_unchecking_files, actions=actions, actions_minimal=actions_minimal, tab=queue_type, product_attrs=product_attrs, attachment_formset=attachment_formset, appfeatures_form=appfeatures_form, default_visibility=DEFAULT_ACTION_VISIBILITY, ) if features_list is not None: ctx["feature_list"] = features_list return jingo.render(request, "reviewers/review.html", ctx)
def addons_section(request, addon_id, addon, section, editable=False, webapp=False): basic = AppFormBasic if webapp else addon_forms.AddonFormBasic models = {'basic': basic, 'media': AppFormMedia, 'details': AppFormDetails, 'support': AppFormSupport, 'technical': AppFormTechnical, 'admin': forms.AdminSettingsForm} is_dev = acl.check_addon_ownership(request, addon, dev=True) if section not in models: raise http.Http404() version = addon.current_version or addon.latest_version tags, previews, restricted_tags = [], [], [] cat_form = appfeatures = appfeatures_form = None # Permissions checks. # Only app owners can edit any of the details of their apps. # Users with 'Apps:Configure' can edit the admin settings. if (section != 'admin' and not is_dev) or (section == 'admin' and not acl.action_allowed(request, 'Apps', 'Configure') and not acl.action_allowed(request, 'Apps', 'ViewConfiguration')): raise PermissionDenied if section == 'basic': cat_form = CategoryForm(request.POST or None, product=addon, request=request) elif section == 'media': previews = PreviewFormSet( request.POST or None, prefix='files', queryset=addon.get_previews()) elif section == 'technical': # Only show the list of features if app isn't packaged. if (waffle.switch_is_active('buchets') and not addon.is_packaged and section == 'technical'): appfeatures = version.features formdata = request.POST if request.method == 'POST' else None appfeatures_form = AppFeaturesForm(formdata, instance=appfeatures) elif section == 'admin': tags = addon.tags.not_blacklisted().values_list('tag_text', flat=True) restricted_tags = addon.tags.filter(restricted=True) # Get the slug before the form alters it to the form data. valid_slug = addon.app_slug if editable: if request.method == 'POST': if (section == 'admin' and not acl.action_allowed(request, 'Apps', 'Configure')): raise PermissionDenied form = models[section](request.POST, request.FILES, instance=addon, request=request) all_forms = [form, previews] if appfeatures_form: all_forms.append(appfeatures_form) if cat_form: all_forms.append(cat_form) if all(not f or f.is_valid() for f in all_forms): if cat_form: cat_form.save() addon = form.save(addon) if appfeatures_form: appfeatures_form.save() if 'manifest_url' in form.changed_data: addon.update( app_domain=addon.domain_from_url(addon.manifest_url)) update_manifests([addon.pk]) if previews: for preview in previews.forms: preview.save(addon) editable = False if section == 'media': amo.log(amo.LOG.CHANGE_ICON, addon) else: amo.log(amo.LOG.EDIT_PROPERTIES, addon) valid_slug = addon.app_slug else: form = models[section](instance=addon, request=request) else: form = False data = {'addon': addon, 'webapp': webapp, 'version': version, 'form': form, 'editable': editable, 'tags': tags, 'restricted_tags': restricted_tags, 'cat_form': cat_form, 'preview_form': previews, 'valid_slug': valid_slug, } if appfeatures_form and appfeatures: data.update({ 'appfeatures': appfeatures, 'feature_list': [unicode(f) for f in appfeatures.to_list()], 'appfeatures_form': appfeatures_form }) return jingo.render(request, 'developers/apps/edit/%s.html' % section, data)
def _review(request, addon, version): if (not settings.ALLOW_SELF_REVIEWS and not acl.action_allowed(request, 'Admin', '%') and addon.has_author(request.amo_user)): messages.warning(request, _('Self-reviews are not allowed.')) return redirect(reverse('reviewers.home')) if (addon.status == amo.STATUS_BLOCKED and not acl.action_allowed(request, 'Apps', 'ReviewEscalated')): messages.warning( request, _('Only senior reviewers can review blocklisted apps.')) return redirect(reverse('reviewers.home')) attachment_formset = forms.AttachmentFormSet(data=request.POST or None, files=request.FILES or None, prefix='attachment') form = forms.get_review_form(data=request.POST or None, files=request.FILES or None, request=request, addon=addon, version=version, attachment_formset=attachment_formset) postdata = request.POST if request.method == 'POST' else None all_forms = [form, attachment_formset] if waffle.switch_is_active('buchets') and version: features_list = [unicode(f) for f in version.features.to_list()] appfeatures_form = AppFeaturesForm(data=postdata, instance=version.features) all_forms.append(appfeatures_form) else: appfeatures_form = None features_list = None queue_type = form.helper.review_type redirect_url = reverse('reviewers.apps.queue_%s' % queue_type) is_admin = acl.action_allowed(request, 'Addons', 'Edit') if request.method == 'POST' and all(f.is_valid() for f in all_forms): old_types = set(o.id for o in addon.device_types) new_types = set(form.cleaned_data.get('device_override')) if waffle.switch_is_active('buchets'): old_features = set(features_list) new_features = set(unicode(f) for f in appfeatures_form.instance.to_list()) if form.cleaned_data.get('action') == 'public': if old_types != new_types: # The reviewer overrode the device types. We need to not # publish this app immediately. if addon.make_public == amo.PUBLIC_IMMEDIATELY: addon.update(make_public=amo.PUBLIC_WAIT) # And update the device types to what the reviewer set. AddonDeviceType.objects.filter(addon=addon).delete() for device in form.cleaned_data.get('device_override'): addon.addondevicetype_set.create(device_type=device) # Log that the reviewer changed the device types. added_devices = new_types - old_types removed_devices = old_types - new_types msg = _(u'Device(s) changed by ' 'reviewer: {0}').format(', '.join( [_(u'Added {0}').format(unicode(amo.DEVICE_TYPES[d].name)) for d in added_devices] + [_(u'Removed {0}').format( unicode(amo.DEVICE_TYPES[d].name)) for d in removed_devices])) amo.log(amo.LOG.REVIEW_DEVICE_OVERRIDE, addon, addon.current_version, details={'comments': msg}) if (waffle.switch_is_active('buchets') and old_features != new_features): # The reviewer overrode the requirements. We need to not # publish this app immediately. if addon.make_public == amo.PUBLIC_IMMEDIATELY: addon.update(make_public=amo.PUBLIC_WAIT) appfeatures_form.save(mark_for_rereview=False) # Log that the reviewer changed the minimum requirements. added_features = new_features - old_features removed_features = old_features - new_features fmt = ', '.join( [_(u'Added {0}').format(f) for f in added_features] + [_(u'Removed {0}').format(f) for f in removed_features]) # L10n: {0} is the list of requirements changes. msg = _(u'Requirements changed by reviewer: {0}').format(fmt) amo.log(amo.LOG.REVIEW_FEATURES_OVERRIDE, addon, addon.current_version, details={'comments': msg}) form.helper.process() if form.cleaned_data.get('notify'): EditorSubscription.objects.get_or_create(user=request.amo_user, addon=addon) messages.success(request, _('Review successfully processed.')) return redirect(redirect_url) canned = AppCannedResponse.objects.all() actions = form.helper.actions.items() try: if not version: raise Version.DoesNotExist show_diff = (addon.versions.exclude(id=version.id) .filter(files__isnull=False, created__lt=version.created, files__status=amo.STATUS_PUBLIC) .latest()) except Version.DoesNotExist: show_diff = None # The actions we should show a minimal form from. actions_minimal = [k for (k, a) in actions if not a.get('minimal')] # We only allow the user to check/uncheck files for "pending" allow_unchecking_files = form.helper.review_type == "pending" versions = (Version.with_deleted.filter(addon=addon) .order_by('-created') .transform(Version.transformer_activity) .transform(Version.transformer)) product_attrs = { 'product': json.dumps( product_as_dict(request, addon, False, 'reviewer'), cls=JSONEncoder), 'manifest_url': addon.manifest_url, } pager = paginate(request, versions, 10) num_pages = pager.paginator.num_pages count = pager.paginator.count ctx = context(request, version=version, product=addon, pager=pager, num_pages=num_pages, count=count, flags=Review.objects.filter(addon=addon, flag=True), form=form, canned=canned, is_admin=is_admin, status_types=amo.STATUS_CHOICES, show_diff=show_diff, allow_unchecking_files=allow_unchecking_files, actions=actions, actions_minimal=actions_minimal, tab=queue_type, product_attrs=product_attrs, attachment_formset=attachment_formset, appfeatures_form=appfeatures_form, default_visibility=DEFAULT_ACTION_VISIBILITY) if features_list is not None: ctx['feature_list'] = features_list return jingo.render(request, 'reviewers/review.html', ctx)
def addons_section(request, addon_id, addon, section, editable=False): basic = AppFormBasic models = {'basic': basic, 'media': AppFormMedia, 'details': AppFormDetails, 'support': AppFormSupport, 'technical': AppFormTechnical, 'admin': forms.AdminSettingsForm} is_dev = acl.check_addon_ownership(request, addon, dev=True) if section not in models: raise http.Http404() version = addon.current_version or addon.latest_version tags, previews, restricted_tags = [], [], [] cat_form = appfeatures = appfeatures_form = version_form = None formdata = request.POST if request.method == 'POST' else None # Permissions checks. # Only app owners can edit any of the details of their apps. # Users with 'Apps:Configure' can edit the admin settings. if (section != 'admin' and not is_dev) or (section == 'admin' and not acl.action_allowed(request, 'Apps', 'Configure') and not acl.action_allowed(request, 'Apps', 'ViewConfiguration')): raise PermissionDenied if section == 'basic': cat_form = CategoryForm(formdata, product=addon, request=request) # Only show/use the release notes form for hosted apps, packaged apps # can do that from the version edit page. if not addon.is_packaged: version_form = AppVersionForm(formdata, instance=version) elif section == 'media': previews = PreviewFormSet( request.POST or None, prefix='files', queryset=addon.get_previews()) elif section == 'technical': # Only show/use the features form for hosted apps, packaged apps # can do that from the version edit page. if not addon.is_packaged: appfeatures = version.features appfeatures_form = AppFeaturesForm(formdata, instance=appfeatures) elif section == 'admin': tags = addon.tags.not_blacklisted().values_list('tag_text', flat=True) restricted_tags = addon.tags.filter(restricted=True) # Get the slug before the form alters it to the form data. valid_slug = addon.app_slug if editable: if request.method == 'POST': if (section == 'admin' and not acl.action_allowed(request, 'Apps', 'Configure')): raise PermissionDenied form = models[section](formdata, request.FILES, instance=addon, request=request) all_forms = [form, previews] for additional_form in (appfeatures_form, cat_form, version_form): if additional_form: all_forms.append(additional_form) if all(not f or f.is_valid() for f in all_forms): if cat_form: cat_form.save() addon = form.save(addon) if appfeatures_form: appfeatures_form.save() if version_form: # We are re-using version_form without displaying all its # fields, so we need to override the boolean fields, # otherwise they'd be considered empty and therefore False. version_form.cleaned_data['publish_immediately'] = ( version_form.fields['publish_immediately'].initial) version_form.save() if 'manifest_url' in form.changed_data: addon.update( app_domain=addon.domain_from_url(addon.manifest_url)) update_manifests([addon.pk]) if previews: for preview in previews.forms: preview.save(addon) editable = False if section == 'media': amo.log(amo.LOG.CHANGE_ICON, addon) else: amo.log(amo.LOG.EDIT_PROPERTIES, addon) valid_slug = addon.app_slug else: form = models[section](instance=addon, request=request) else: form = False data = {'addon': addon, 'version': version, 'form': form, 'editable': editable, 'tags': tags, 'restricted_tags': restricted_tags, 'cat_form': cat_form, 'version_form': version_form, 'preview_form': previews, 'valid_slug': valid_slug, } if appfeatures_form and appfeatures: data.update({ 'appfeatures': appfeatures, 'feature_list': [unicode(f) for f in appfeatures.to_list()], 'appfeatures_form': appfeatures_form }) return render(request, 'developers/apps/edit/%s.html' % section, data)
def _review(request, addon, version): if (not settings.ALLOW_SELF_REVIEWS and not acl.action_allowed(request, 'Admin', '%') and addon.has_author(request.user)): messages.warning(request, _('Self-reviews are not allowed.')) return redirect(reverse('reviewers.home')) if (addon.status == mkt.STATUS_BLOCKED and not acl.action_allowed(request, 'Apps', 'ReviewEscalated')): messages.warning( request, _('Only senior reviewers can review blocklisted apps.')) return redirect(reverse('reviewers.home')) attachment_formset = CommAttachmentFormSet(data=request.POST or None, files=request.FILES or None, prefix='attachment') testedon_formset = TestedOnFormSet(data=request.POST or None, prefix='testedon') form = forms.get_review_form(data=request.POST or None, files=request.FILES or None, request=request, addon=addon, version=version, attachment_formset=attachment_formset, testedon_formset=testedon_formset) postdata = request.POST if request.method == 'POST' else None all_forms = [form, attachment_formset, testedon_formset] if version: features_list = version.features.to_names() appfeatures_form = AppFeaturesForm(data=postdata, instance=version.features) all_forms.append(appfeatures_form) else: appfeatures_form = None features_list = None queue_type = form.helper.review_type redirect_url = reverse('reviewers.apps.queue_%s' % queue_type) is_admin = acl.action_allowed(request, 'Apps', 'Edit') if request.method == 'POST' and all(f.is_valid() for f in all_forms): if form.cleaned_data.get('action') == 'public': old_types = set(o.id for o in addon.device_types) new_types = set(form.cleaned_data.get('device_override')) if old_types != new_types: # The reviewer overrode the device types. We need to not # publish this app immediately. if addon.publish_type == mkt.PUBLISH_IMMEDIATE: addon.update(publish_type=mkt.PUBLISH_PRIVATE) # And update the device types to what the reviewer set. AddonDeviceType.objects.filter(addon=addon).delete() for device in form.cleaned_data.get('device_override'): addon.addondevicetype_set.create(device_type=device) # Log that the reviewer changed the device types. added_devices = new_types - old_types removed_devices = old_types - new_types msg_list = [ _(u'Added {0}').format(unicode(mkt.DEVICE_TYPES[d].name)) for d in added_devices ] + [ _(u'Removed {0}').format(unicode(mkt.DEVICE_TYPES[d].name)) for d in removed_devices ] msg = _(u'Device(s) changed by ' u'reviewer: {0}').format(', '.join(msg_list)) log_reviewer_action(addon, request.user, msg, mkt.LOG.REVIEW_DEVICE_OVERRIDE) if appfeatures_form.changed_data: # The reviewer overrode the requirements. We need to not # publish this app immediately. if addon.publish_type == mkt.PUBLISH_IMMEDIATE: addon.update(publish_type=mkt.PUBLISH_PRIVATE) appfeatures_form.save(mark_for_rereview=False) # Log that the reviewer changed the minimum requirements. added_features, removed_features = (appfeatures_form .get_changed_features()) fmt = ', '.join( [_(u'Added {0}').format(f) for f in added_features] + [_(u'Removed {0}').format(f) for f in removed_features]) # L10n: {0} is the list of requirements changes. msg = _(u'Requirements changed by reviewer: {0}').format(fmt) log_reviewer_action(addon, request.user, msg, mkt.LOG.REVIEW_FEATURES_OVERRIDE) score = form.helper.process() if form.cleaned_data.get('is_showcase'): if not addon.tags.filter(tag_text=SHOWCASE_TAG).exists(): Tag(tag_text=SHOWCASE_TAG).save_tag(addon) recipient_list = (settings.APP_CURATION_BOARD_EMAIL,) subject = u'App [%s] nominated to be featured' % addon.name msg = (u'The Marketplace reviewer %s thinks %s (%s%s) is' u'good enough to be a featured app.\n\n' % ( request.user, addon.name, settings.SITE_URL, addon.get_url_path())) send_mail(subject, msg, recipient_list=recipient_list) else: Tag(tag_text=SHOWCASE_TAG).remove_tag(addon) # Success message. if score: score = ReviewerScore.objects.filter(user=request.user)[0] # L10N: {0} is the type of review. {1} is the points they earned. # {2} is the points they now have total. success = _( u'"{0}" successfully processed (+{1} points, {2} total).' .format(unicode(mkt.REVIEWED_CHOICES[score.note_key]), score.score, ReviewerScore.get_total(request.user))) else: success = _('Review successfully processed.') messages.success(request, success) return redirect(redirect_url) canned = CannedResponse.objects.all() actions = form.helper.actions.items() try: if not version: raise Version.DoesNotExist show_diff = (addon.versions.exclude(id=version.id) .filter(files__isnull=False, created__lt=version.created, files__status=mkt.STATUS_PUBLIC) .latest()) except Version.DoesNotExist: show_diff = None # The actions we should show a minimal form from. actions_minimal = [k for (k, a) in actions if not a.get('minimal')] # We only allow the user to check/uncheck files for "pending" allow_unchecking_files = form.helper.review_type == "pending" versions = (Version.with_deleted.filter(addon=addon) .order_by('-created') .transform(Version.transformer_activity) .transform(Version.transformer)) product_attrs = { 'product': json.dumps( product_as_dict(request, addon, False, 'reviewer'), cls=JSONEncoder), 'manifest_url': addon.manifest_url, } pager = paginate(request, versions, 10) num_pages = pager.paginator.num_pages count = pager.paginator.count ctx = context(request, version=version, product=addon, pager=pager, num_pages=num_pages, count=count, form=form, canned=canned, is_admin=is_admin, status_types=mkt.STATUS_CHOICES, show_diff=show_diff, allow_unchecking_files=allow_unchecking_files, actions=actions, actions_minimal=actions_minimal, tab=queue_type, product_attrs=product_attrs, attachment_formset=attachment_formset, appfeatures_form=appfeatures_form, testedon_formset=testedon_formset) if features_list is not None: ctx['feature_list'] = features_list return render(request, 'reviewers/review.html', ctx)
def addons_section(request, addon_id, addon, section, editable=False, webapp=False): basic = AppFormBasic if webapp else addon_forms.AddonFormBasic models = { 'basic': basic, 'media': AppFormMedia, 'details': AppFormDetails, 'support': AppFormSupport, 'technical': AppFormTechnical, 'admin': forms.AdminSettingsForm } is_dev = acl.check_addon_ownership(request, addon, dev=True) if section not in models: raise http.Http404() version = addon.current_version or addon.latest_version tags, previews, restricted_tags = [], [], [] cat_form = appfeatures = appfeatures_form = None # Permissions checks. # Only app owners can edit any of the details of their apps. # Users with 'Apps:Configure' can edit the admin settings. if (section != 'admin' and not is_dev) or ( section == 'admin' and not acl.action_allowed(request, 'Apps', 'Configure') and not acl.action_allowed(request, 'Apps', 'ViewConfiguration')): raise PermissionDenied if section == 'basic': cat_form = CategoryForm(request.POST or None, product=addon, request=request) elif section == 'media': previews = PreviewFormSet(request.POST or None, prefix='files', queryset=addon.get_previews()) elif section == 'technical': # Only show the list of features if app isn't packaged. if (waffle.switch_is_active('buchets') and not addon.is_packaged and section == 'technical'): appfeatures = version.features formdata = request.POST if request.method == 'POST' else None appfeatures_form = AppFeaturesForm(formdata, instance=appfeatures) elif section == 'admin': tags = addon.tags.not_blacklisted().values_list('tag_text', flat=True) restricted_tags = addon.tags.filter(restricted=True) # Get the slug before the form alters it to the form data. valid_slug = addon.app_slug if editable: if request.method == 'POST': if (section == 'admin' and not acl.action_allowed(request, 'Apps', 'Configure')): raise PermissionDenied form = models[section](request.POST, request.FILES, instance=addon, request=request) all_forms = [form, previews] if appfeatures_form: all_forms.append(appfeatures_form) if cat_form: all_forms.append(cat_form) if all(not f or f.is_valid() for f in all_forms): if cat_form: cat_form.save() addon = form.save(addon) if appfeatures_form: appfeatures_form.save() if 'manifest_url' in form.changed_data: addon.update( app_domain=addon.domain_from_url(addon.manifest_url)) update_manifests([addon.pk]) if previews: for preview in previews.forms: preview.save(addon) editable = False if section == 'media': amo.log(amo.LOG.CHANGE_ICON, addon) else: amo.log(amo.LOG.EDIT_PROPERTIES, addon) valid_slug = addon.app_slug else: form = models[section](instance=addon, request=request) else: form = False data = { 'addon': addon, 'webapp': webapp, 'version': version, 'form': form, 'editable': editable, 'tags': tags, 'restricted_tags': restricted_tags, 'cat_form': cat_form, 'preview_form': previews, 'valid_slug': valid_slug, } if appfeatures_form and appfeatures: data.update({ 'appfeatures': appfeatures, 'feature_list': [unicode(f) for f in appfeatures.to_list()], 'appfeatures_form': appfeatures_form }) return jingo.render(request, 'developers/apps/edit/%s.html' % section, data)
def addons_section(request, addon_id, addon, section, editable=False, webapp=False): basic = AppFormBasic if webapp else addon_forms.AddonFormBasic models = { "basic": basic, "media": AppFormMedia, "details": AppFormDetails, "support": AppFormSupport, "technical": AppFormTechnical, "admin": forms.AdminSettingsForm, } is_dev = acl.check_addon_ownership(request, addon, dev=True) if section not in models: raise http.Http404() version = addon.current_version or addon.latest_version tags, previews, restricted_tags = [], [], [] cat_form = appfeatures = appfeatures_form = None # Permissions checks. # Only app owners can edit any of the details of their apps. # Users with 'Apps:Configure' can edit the admin settings. if (section != "admin" and not is_dev) or ( section == "admin" and not acl.action_allowed(request, "Apps", "Configure") and not acl.action_allowed(request, "Apps", "ViewConfiguration") ): raise PermissionDenied if section == "basic": cat_form = CategoryForm(request.POST or None, product=addon, request=request) elif section == "media": previews = PreviewFormSet(request.POST or None, prefix="files", queryset=addon.get_previews()) elif section == "technical": # Only show the list of features if app isn't packaged. if waffle.switch_is_active("buchets") and not addon.is_packaged and section == "technical": appfeatures = version.features formdata = request.POST if request.method == "POST" else None appfeatures_form = AppFeaturesForm(formdata, instance=appfeatures) elif section == "admin": tags = addon.tags.not_blacklisted().values_list("tag_text", flat=True) restricted_tags = addon.tags.filter(restricted=True) # Get the slug before the form alters it to the form data. valid_slug = addon.app_slug if editable: if request.method == "POST": if section == "admin" and not acl.action_allowed(request, "Apps", "Configure"): raise PermissionDenied form = models[section](request.POST, request.FILES, instance=addon, request=request) all_forms = [form, previews] if appfeatures_form: all_forms.append(appfeatures_form) if cat_form: all_forms.append(cat_form) if all(not f or f.is_valid() for f in all_forms): if cat_form: cat_form.save() addon = form.save(addon) if appfeatures_form: appfeatures_form.save() if "manifest_url" in form.changed_data: addon.update(app_domain=addon.domain_from_url(addon.manifest_url)) update_manifests([addon.pk]) if previews: for preview in previews.forms: preview.save(addon) editable = False if section == "media": amo.log(amo.LOG.CHANGE_ICON, addon) else: amo.log(amo.LOG.EDIT_PROPERTIES, addon) valid_slug = addon.app_slug else: form = models[section](instance=addon, request=request) else: form = False data = { "addon": addon, "webapp": webapp, "version": version, "form": form, "editable": editable, "tags": tags, "restricted_tags": restricted_tags, "cat_form": cat_form, "preview_form": previews, "valid_slug": valid_slug, } if appfeatures_form and appfeatures: data.update( { "appfeatures": appfeatures, "feature_list": [unicode(f) for f in appfeatures.to_list()], "appfeatures_form": appfeatures_form, } ) return jingo.render(request, "developers/apps/edit/%s.html" % section, data)