def download_file(request, file_id, type=None): # Fetch what we need with a minimum amount of queries (Transforms on # Version and Webapp are avoided). This breaks several things like # translations, but it should be fine here, we don't need much to go on. file_ = get_object_or_404(File.objects.select_related('version'), pk=file_id) webapp = get_object_or_404(Webapp.objects.all().no_transforms(), pk=file_.version.addon_id, is_packaged=True) if webapp.is_disabled or file_.status == mkt.STATUS_DISABLED: if not acl.check_addon_ownership(request, webapp, viewer=True, ignore_disabled=True): raise http.Http404() # We treat blocked files like public files so users get the update. if file_.status in [mkt.STATUS_PUBLIC, mkt.STATUS_BLOCKED]: path = file_.signed_file_path else: # This is someone asking for an unsigned packaged app. if not acl.check_addon_ownership(request, webapp, dev=True): raise http.Http404() path = file_.file_path log.info('Downloading package: %s from %s' % (webapp.id, path)) return HttpResponseSendFile(request, path, content_type='application/zip', etag=file_.hash.split(':')[-1])
def download_file(request, file_id, type=None): file = get_object_or_404(File, pk=file_id) webapp = get_object_or_404(Webapp, pk=file.version.addon_id, is_packaged=True) if webapp.is_disabled or file.status == amo.STATUS_DISABLED: if not acl.check_addon_ownership( request, webapp, viewer=True, ignore_disabled=True): raise http.Http404() # We treat blocked files like public files so users get the update. if file.status in [amo.STATUS_PUBLIC, amo.STATUS_BLOCKED]: path = webapp.sign_if_packaged(file.version_id) else: # This is someone asking for an unsigned packaged app. if not acl.check_addon_ownership(request, webapp, dev=True): raise http.Http404() path = file.file_path log.info('Downloading package: %s from %s' % (webapp.id, path)) return HttpResponseSendFile(request, path, content_type='application/zip', etag=file.hash.split(':')[-1])
def setup_viewer(request, file_obj): data = {'file': file_obj, 'version': file_obj.version, 'addon': file_obj.version.addon, 'status': False, 'selected': {}, 'validate_url': ''} if (acl.check_reviewer(request) or acl.check_addon_ownership(request, file_obj.version.addon, viewer=True, ignore_disabled=True)): data['validate_url'] = reverse( 'mkt.developers.apps.json_file_validation', args=[file_obj.version.addon.app_slug, file_obj.id]) if acl.check_reviewer(request): data['file_link'] = {'text': _('Back to review'), 'url': reverse('reviewers.apps.review', args=[data['addon'].app_slug])} else: data['file_link'] = { 'text': _('Back to app'), 'url': reverse('detail', args=[data['addon'].pk]) } return data
def in_app_products(request, addon_id, addon, webapp=True, account=None): owner = acl.check_addon_ownership(request, addon) products = addon.inappproduct_set.all() new_product = InAppProduct(webapp=addon) form = InAppProductForm() if addon.origin: inapp_origin = addon.origin elif addon.guid: # Derive a marketplace specific origin out of the GUID. # This is for apps that do not specify a custom origin. inapp_origin = 'marketplace:{}'.format(addon.guid) else: # Theoretically this is highly unlikely. A hosted app will # always have a domain and a packaged app will always have # a generated GUID. raise TypeError( 'Cannot derive origin: no declared origin, no GUID') list_url = _fix_origin_link(reverse('in-app-products-list', kwargs={'origin': inapp_origin})) detail_url = _fix_origin_link(reverse('in-app-products-detail', # {guid} is replaced in JS. kwargs={'origin': inapp_origin, 'guid': "{guid}"})) return render(request, 'developers/payments/in-app-products.html', {'addon': addon, 'form': form, 'new_product': new_product, 'owner': owner, 'products': products, 'form': form, 'list_url': list_url, 'detail_url': detail_url, 'active_lang': request.LANG.lower()})
def in_app_products(request, addon_id, addon, webapp=True, account=None): owner = acl.check_addon_ownership(request, addon) products = addon.inappproduct_set.all() new_product = InAppProduct(webapp=addon) form = InAppProductForm() list_url = None detail_url = None if addon.origin: list_url = _fix_origin_link(reverse("in-app-products-list", kwargs={"origin": addon.origin})) detail_url = _fix_origin_link( reverse( "in-app-products-detail", # {guid} is replaced in JS. kwargs={"origin": addon.origin, "guid": "{guid}"}, ) ) return render( request, "developers/payments/in-app-products.html", { "addon": addon, "form": form, "new_product": new_product, "owner": owner, "products": products, "form": form, "list_url": list_url, "detail_url": detail_url, "active_lang": request.LANG.lower(), }, )
def setup_viewer(request, file_obj): data = { 'file': file_obj, 'version': file_obj.version, 'addon': file_obj.version.addon, 'status': False, 'selected': {}, 'validate_url': '' } if (acl.check_reviewer(request) or acl.check_addon_ownership( request, file_obj.version.addon, viewer=True, ignore_disabled=True)): data['validate_url'] = reverse( 'mkt.developers.apps.json_file_validation', args=[file_obj.version.addon.app_slug, file_obj.id]) if acl.check_reviewer(request): data['file_link'] = { 'text': _('Back to review'), 'url': reverse('reviewers.apps.review', args=[data['addon'].app_slug]) } else: data['file_link'] = { 'text': _('Back to app'), 'url': reverse('detail', args=[data['addon'].pk]) } return data
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 in_app_products(request, addon_id, addon, webapp=True, account=None): owner = acl.check_addon_ownership(request, addon) products = addon.inappproduct_set.all() new_product = InAppProduct(webapp=addon) form = InAppProductForm() return render(request, 'developers/payments/in-app-products.html', {'addon': addon, 'form': form, 'new_product': new_product, 'owner': owner, 'products': products, 'form': form})
def in_app_products(request, addon_id, addon, webapp=True, account=None): owner = acl.check_addon_ownership(request, addon) products = addon.inappproduct_set.all() new_product = InAppProduct(webapp=addon) form = InAppProductForm() return render( request, "developers/payments/in-app-products.html", {"addon": addon, "form": form, "new_product": new_product, "owner": owner, "products": products, "form": form}, )
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 get_app(self, ident): try: app = Webapp.objects.by_identifier(ident) except Webapp.DoesNotExist: raise Http404 if not app.is_public() and not check_addon_ownership( self.request, app): # App owners and admin can see the app even if it's not public. # Regular users or anonymous users can't. raise PermissionDenied('The app requested is not public') return app
def get_app(self, ident): try: app = Webapp.objects.by_identifier(ident) except Webapp.DoesNotExist: raise Http404 current_region = get_region() if ((not app.is_public() or not app.listed_in(region=current_region)) and not check_addon_ownership(self.request, app)): # App owners and admin can see the app even if it's not public # or not available in the current region. Regular users or # anonymous users can't. raise PermissionDenied('The app requested is not public or not ' 'available in region "%s".' % current_region.slug) return app
def download_file(request, file_id, type=None): file = get_object_or_404(File, pk=file_id) webapp = get_object_or_404(Webapp, pk=file.version.addon_id, is_packaged=True) if webapp.is_disabled or file.status == amo.STATUS_DISABLED: if not acl.check_addon_ownership(request, webapp, viewer=True, ignore_disabled=True): raise http.Http404() # We treat blocked files like public files so users get the update. if file.status in [amo.STATUS_PUBLIC, amo.STATUS_BLOCKED]: path = webapp.sign_if_packaged(file.version_id) else: # This is someone asking for an unsigned packaged app. if not acl.check_addon_ownership(request, webapp, dev=True): raise http.Http404() path = file.file_path log.info('Downloading package: %s from %s' % (webapp.id, path)) return HttpResponseSendFile(request, path, content_type='application/zip', etag=file.hash.split(':')[-1])
def download_file(request, file_id, type=None): # Fetch what we need with a minimum amount of queries (Transforms on # Version and Webapp are avoided). This breaks several things like # translations, but it should be fine here, we don't need much to go on. file_ = get_object_or_404(File.objects.select_related('version'), pk=file_id) webapp = get_object_or_404(Webapp.objects.all().no_transforms(), pk=file_.version.addon_id, is_packaged=True) if webapp.is_disabled or file_.status in [ mkt.STATUS_DISABLED, mkt.STATUS_REJECTED ]: if not acl.check_addon_ownership( request, webapp, viewer=True, ignore_disabled=True): raise http.Http404() # We treat blocked files like public files so users get the update. if file_.status in [mkt.STATUS_PUBLIC, mkt.STATUS_BLOCKED]: path = file_.signed_file_path public = True else: # This is someone asking for an unsigned packaged app. if not acl.check_addon_ownership(request, webapp, dev=True): raise http.Http404() path = file_.file_path public = False log.info('Downloading package: %s from %s' % (webapp.id, path)) return get_file_response(request, path, content_type='application/zip', etag=file_.hash.split(':')[-1], public=public)
def allowed(request, file): allowed = acl.check_reviewer(request) if not allowed: try: addon = file.version.addon except ObjectDoesNotExist: raise http.Http404 if addon.status in amo.REVIEWED_STATUSES: allowed = True else: allowed = acl.check_addon_ownership(request, addon, viewer=True, dev=True) if not allowed: raise PermissionDenied return True
def get_app(self, ident): try: app = Webapp.objects.by_identifier(ident) except Webapp.DoesNotExist: raise Http404 current_region = get_region() if ((not app.is_public() or not app.listed_in(region=current_region)) and not check_addon_ownership(self.request, app)): # App owners and admin can see the app even if it's not public # or not available in the current region. Regular users or # anonymous users can't. raise PermissionDenied( 'The app requested is not public or not available in region ' '"%s".' % current_region.slug) return app
def in_app_config(request, addon_id, addon, webapp=True): """ Allows developers to get a key/secret for doing in-app payments. """ config = get_inapp_config(addon) owner = acl.check_addon_ownership(request, addon) if request.method == "POST": # Reset the in-app secret for the app. (client.api.generic.product(config["resource_pk"]).patch(data={"secret": generate_key(48)})) messages.success(request, _("Changes successfully saved.")) return redirect(reverse("mkt.developers.apps.in_app_config", args=[addon.app_slug])) return render( request, "developers/payments/in-app-config.html", {"addon": addon, "owner": owner, "seller_config": config} )
def in_app_products(request, addon_id, addon, webapp=True, account=None): owner = acl.check_addon_ownership(request, addon) products = addon.inappproduct_set.all() new_product = InAppProduct(webapp=addon) form = InAppProductForm() list_url = None detail_url = None if addon.origin: list_url = _fix_origin_link(reverse('in-app-products-list', kwargs={'origin': addon.origin})) detail_url = _fix_origin_link(reverse('in-app-products-detail', # {guid} is replaced in JS. kwargs={'origin': addon.origin, 'guid': "{guid}"})) return render(request, 'developers/payments/in-app-products.html', {'addon': addon, 'form': form, 'new_product': new_product, 'owner': owner, 'products': products, 'form': form, 'list_url': list_url, 'detail_url': detail_url})
def in_app_config(request, addon_id, addon, webapp=True): """ Allows developers to get a key/secret for doing in-app payments. """ config = get_inapp_config(addon) owner = acl.check_addon_ownership(request, addon) if request.method == 'POST': # Reset the in-app secret for the app. (client.api.generic .product(config['resource_pk']) .patch(data={'secret': generate_key(48)})) messages.success(request, _('Changes successfully saved.')) return redirect(reverse('mkt.developers.apps.in_app_config', args=[addon.app_slug])) return render(request, 'developers/payments/in-app-config.html', {'addon': addon, 'owner': owner, 'seller_config': config})
def in_app_products(request, addon_id, addon, webapp=True, account=None): owner = acl.check_addon_ownership(request, addon) products = addon.inappproduct_set.all() new_product = InAppProduct(webapp=addon) form = InAppProductForm() list_url = None detail_url = None if addon.origin: list_url = _fix_origin_link(reverse('in-app-products-list', kwargs={'origin': addon.origin})) detail_url = _fix_origin_link(reverse('in-app-products-detail', # {guid} is replaced in JS. kwargs={'origin': addon.origin, 'guid': "{guid}"})) return render(request, 'developers/payments/in-app-products.html', {'addon': addon, 'form': form, 'new_product': new_product, 'owner': owner, 'products': products, 'form': form, 'list_url': list_url, 'detail_url': detail_url, 'active_lang': request.LANG.lower()})
def in_app_products(request, addon_id, addon, webapp=True, account=None): owner = acl.check_addon_ownership(request, addon) products = addon.inappproduct_set.all() new_product = InAppProduct(webapp=addon) form = InAppProductForm() if addon.origin: inapp_origin = addon.origin elif addon.guid: # Derive a marketplace specific origin out of the GUID. # This is for apps that do not specify a custom origin. inapp_origin = 'marketplace:{}'.format(addon.guid) else: # Theoretically this is highly unlikely. A hosted app will # always have a domain and a packaged app will always have # a generated GUID. raise TypeError('Cannot derive origin: no declared origin, no GUID') list_url = _fix_origin_link( reverse('in-app-products-list', kwargs={'origin': inapp_origin})) detail_url = _fix_origin_link( reverse( 'in-app-products-detail', # {guid} is replaced in JS. kwargs={ 'origin': inapp_origin, 'guid': "{guid}" })) return render( request, 'developers/payments/in-app-products.html', { 'addon': addon, 'form': form, 'new_product': new_product, 'owner': owner, 'products': products, 'form': form, 'list_url': list_url, 'detail_url': detail_url, 'active_lang': request.LANG.lower() })
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 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)