def details(request, addon_id, addon): # Name, Slug, Summary, Description, Privacy Policy, # Homepage URL, Support URL, Support Email. form_basic = AppDetailsBasicForm(request.POST or None, instance=addon, request=request) form_cats = CategoryForm(request.POST or None, product=addon, request=request) form_devices = DeviceTypeForm(request.POST or None, addon=addon) form_icon = AppFormMedia(request.POST or None, request.FILES or None, instance=addon, request=request) form_previews = PreviewFormSet(request.POST or None, prefix='files', queryset=addon.get_previews()) # For empty webapp-locale (or no-locale) fields that have # form-locale values, duplicate them to satisfy the requirement. form_locale = request.COOKIES.get("current_locale", "") app_locale = to_language(addon.default_locale) for name, value in request.POST.items(): if value: if name.endswith(form_locale): basename = name[:-len(form_locale)] else: basename = name + '_' othername = basename + app_locale if not request.POST.get(othername, None): request.POST[othername] = value forms = { 'form_basic': form_basic, 'form_devices': form_devices, 'form_cats': form_cats, 'form_icon': form_icon, 'form_previews': form_previews, } if request.POST and all(f.is_valid() for f in forms.itervalues()): addon = form_basic.save(addon) form_devices.save(addon) form_cats.save() form_icon.save(addon) for preview in form_previews.forms: preview.save(addon) tasks.generate_image_assets.delay(addon) AppSubmissionChecklist.objects.get(addon=addon).update(details=True) addon.mark_done() return redirect('submit.app.done', addon.app_slug) ctx = { 'step': 'details', 'addon': addon, } ctx.update(forms) return jingo.render(request, 'submit/details.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} if section not in models: raise http.Http404() tags = image_assets = previews = restricted_tags = [] cat_form = None if section == 'basic': tags = addon.tags.not_blacklisted().values_list('tag_text', flat=True) cat_form = CategoryForm(request.POST or None, product=addon, request=request) restricted_tags = addon.tags.filter(restricted=True) elif section == 'media': image_assets = ImageAssetFormSet( request.POST or None, prefix='images', app=addon) previews = PreviewFormSet( request.POST or None, prefix='files', queryset=addon.get_previews()) elif (section == 'admin' and not acl.action_allowed(request, 'Apps', 'Configure') and not acl.action_allowed(request, 'Apps', 'ViewConfiguration')): raise PermissionDenied # 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) if (form.is_valid() and (not previews or previews.is_valid()) and (not image_assets or image_assets.is_valid())): addon = form.save(addon) 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) if image_assets: image_assets.save() 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 if cat_form: if cat_form.is_valid(): cat_form.save() addon.save() else: editable = True else: form = models[section](instance=addon, request=request) else: form = False data = {'addon': addon, 'webapp': webapp, 'form': form, 'editable': editable, 'tags': tags, 'restricted_tags': restricted_tags, 'image_sizes': APP_IMAGE_SIZES, 'cat_form': cat_form, 'preview_form': previews, 'image_asset_form': image_assets, 'valid_slug': valid_slug, } return jingo.render(request, 'developers/apps/edit/%s.html' % section, data)
def details(request, addon_id, addon): # Name, Slug, Description, Privacy Policy, Homepage URL, Support URL, # Support Email. form_basic = AppDetailsBasicForm(request.POST or None, instance=addon, request=request) form_cats = CategoryForm(request.POST or None, product=addon, request=request) form_icon = AppFormMedia(request.POST or None, request.FILES or None, instance=addon, request=request) form_previews = PreviewFormSet(request.POST or None, prefix='files', queryset=addon.get_previews()) # For empty webapp-locale (or no-locale) fields that have # form-locale values, duplicate them to satisfy the requirement. form_locale = request.COOKIES.get('current_locale', '') app_locale = to_language(addon.default_locale) for name, value in request.POST.items(): if value: if name.endswith(form_locale): basename = name[:-len(form_locale)] else: basename = name + '_' othername = basename + app_locale if not request.POST.get(othername, None): request.POST[othername] = value forms = { 'form_basic': form_basic, 'form_cats': form_cats, 'form_icon': form_icon, 'form_previews': form_previews, } if request.POST and all(f.is_valid() for f in forms.itervalues()): addon = form_basic.save(addon) form_cats.save() form_icon.save(addon) for preview in form_previews.forms: preview.save(addon) # If this is an incomplete app from the legacy submission flow, it may # not have device types set yet - so assume it works everywhere. if not addon.device_types: for device in amo.DEVICE_TYPES: addon.addondevicetype_set.create(device_type=device) AppSubmissionChecklist.objects.get(addon=addon).update(details=True) make_public = (amo.PUBLIC_IMMEDIATELY if form_basic.cleaned_data.get('publish') else amo.PUBLIC_WAIT) # Free apps get pushed for review. if addon.premium_type == amo.ADDON_FREE: # The developer doesn't want the app published immediately upon # review. addon.update(status=amo.STATUS_PENDING, make_public=make_public) else: # Paid apps get STATUS_NULL until payment information has been # entered. addon.update(status=amo.STATUS_NULL, highest_status=amo.STATUS_PENDING, make_public=make_public) # Mark the app as excluded in regions that don't support payments. for region in mkt.regions.ALL_REGIONS: if not region.has_payments: AddonExcludedRegion.objects.get_or_create(addon=addon, region=region.id) record_action('app-submitted', request, {'app-id': addon.pk}) return redirect('submit.app.done', addon.app_slug) ctx = { 'step': 'details', 'addon': addon, } ctx.update(forms) return jingo.render(request, 'submit/details.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 details(request, addon_id, addon): # Name, Slug, Description, Privacy Policy, Homepage URL, Support URL, # Support Email. form_basic = AppDetailsBasicForm(request.POST or None, instance=addon, request=request) form_cats = CategoryForm(request.POST or None, product=addon, request=request) form_icon = AppFormMedia(request.POST or None, request.FILES or None, instance=addon, request=request) form_previews = PreviewFormSet(request.POST or None, prefix='files', queryset=addon.get_previews()) # For empty webapp-locale (or no-locale) fields that have # form-locale values, duplicate them to satisfy the requirement. form_locale = request.COOKIES.get('current_locale', '') app_locale = to_language(addon.default_locale) for name, value in request.POST.items(): if value: if name.endswith(form_locale): basename = name[:-len(form_locale)] else: basename = name + '_' othername = basename + app_locale if not request.POST.get(othername, None): request.POST[othername] = value forms = { 'form_basic': form_basic, 'form_cats': form_cats, 'form_icon': form_icon, 'form_previews': form_previews, } if request.POST and all(f.is_valid() for f in forms.itervalues()): addon = form_basic.save(addon) form_cats.save() form_icon.save(addon) for preview in form_previews.forms: preview.save(addon) # If this is an incomplete app from the legacy submission flow, it may # not have device types set yet - so assume it works everywhere. if not addon.device_types: for device in mkt.DEVICE_TYPES: addon.addondevicetype_set.create(device_type=device) AppSubmissionChecklist.objects.get(addon=addon).update(details=True) if addon.needs_payment(): # Paid apps get STATUS_NULL until payment information and content # ratings entered. addon.update(status=mkt.STATUS_NULL, highest_status=mkt.STATUS_PENDING) # Mark as pending in special regions (i.e., China). # By default, the column is set to pending when the row is inserted. # But we need to set a nomination date so we know to list the app # in the China Review Queue now (and sort it by that date too). for region in mkt.regions.SPECIAL_REGIONS: addon.geodata.set_nominated_date(region, save=True) log.info(u'[Webapp:%s] Setting nomination date to ' u'now for region (%s).' % (addon, region.slug)) record_action('app-submitted', request, {'app-id': addon.pk}) return redirect('submit.app.done', addon.app_slug) ctx = { 'step': 'details', 'addon': addon, } ctx.update(forms) return render(request, 'submit/details.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': addon_forms.AddonFormTechnical} if section not in models: raise http.Http404() tags = previews = restricted_tags = [] cat_form = dependency_form = device_type_form = None if section == 'basic': tags = addon.tags.not_blacklisted().values_list('tag_text', flat=True) cat_form = addon_forms.CategoryFormSet(request.POST or None, addon=addon, request=request) restricted_tags = addon.tags.filter(restricted=True) device_type_form = addon_forms.DeviceTypeForm(request.POST or None, addon=addon) elif section == 'media': previews = PreviewFormSet(request.POST or None, prefix='files', queryset=addon.previews.all()) elif section == 'technical': if not webapp: dependency_form = forms.DependencyFormSet(request.POST or None, queryset=addon.addons_dependencies.all(), addon=addon, prefix='dependencies') # Get the slug before the form alters it to the form data. valid_slug = addon.app_slug if editable: if request.method == 'POST': form = models[section](request.POST, request.FILES, instance=addon, request=request) if form.is_valid() and (not previews or previews.is_valid()): addon = form.save(addon) 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 if cat_form: if cat_form.is_valid(): cat_form.save() addon.save() else: editable = True if device_type_form: if device_type_form.is_valid(): device_type_form.save(addon) addon.save() else: editable = True if dependency_form: if dependency_form.is_valid(): dependency_form.save() else: editable = True else: form = models[section](instance=addon, request=request) else: form = False data = {'addon': addon, 'webapp': webapp, 'form': form, 'editable': editable, 'tags': tags, 'restricted_tags': restricted_tags, 'cat_form': cat_form, 'preview_form': previews, 'dependency_form': dependency_form, 'valid_slug': valid_slug, 'device_type_form': device_type_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': addon_forms.AddonFormTechnical, 'admin': forms.AdminSettingsForm } if section not in models: raise http.Http404() tags = previews = restricted_tags = [] cat_form = device_type_form = None if section == 'basic': tags = addon.tags.not_blacklisted().values_list('tag_text', flat=True) cat_form = addon_forms.CategoryFormSet(request.POST or None, addon=addon, request=request) restricted_tags = addon.tags.filter(restricted=True) device_type_form = addon_forms.DeviceTypeForm(request.POST or None, addon=addon) elif section == 'media': previews = PreviewFormSet(request.POST or None, prefix='files', queryset=addon.get_previews()) elif (section == 'admin' and not acl.action_allowed(request, 'Apps', 'Configure') and not acl.action_allowed(request, 'Apps', 'ViewConfiguration')): return http.HttpResponseForbidden() # 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')): return http.HttpResponseForbidden() form = models[section](request.POST, request.FILES, instance=addon, request=request) if form.is_valid() and (not previews or previews.is_valid()): addon = form.save(addon) 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 if cat_form: if cat_form.is_valid(): cat_form.save() addon.save() else: editable = True if device_type_form: if device_type_form.is_valid(): device_type_form.save(addon) addon.save() else: editable = True else: form = models[section](instance=addon, request=request) else: form = False data = { 'addon': addon, 'webapp': webapp, 'form': form, 'editable': editable, 'tags': tags, 'restricted_tags': restricted_tags, 'cat_form': cat_form, 'preview_form': previews, 'valid_slug': valid_slug, 'device_type_form': device_type_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": addon_forms.AddonFormTechnical, "admin": forms.AdminSettingsForm, } if section not in models: raise http.Http404() tags = previews = restricted_tags = [] cat_form = device_type_form = region_form = None if section == "basic": tags = addon.tags.not_blacklisted().values_list("tag_text", flat=True) cat_form = CategoryForm(request.POST or None, product=addon, request=request) restricted_tags = addon.tags.filter(restricted=True) device_type_form = DeviceTypeForm(request.POST or None, addon=addon) elif section == "media": previews = PreviewFormSet(request.POST or None, prefix="files", queryset=addon.get_previews()) elif section == "details" and settings.REGION_STORES: region_form = RegionForm(request.POST or None, product=addon) elif ( section == "admin" and not acl.action_allowed(request, "Apps", "Configure") and not acl.action_allowed(request, "Apps", "ViewConfiguration") ): return http.HttpResponseForbidden() # 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"): return http.HttpResponseForbidden() form = models[section](request.POST, request.FILES, instance=addon, request=request) if ( form.is_valid() and (not previews or previews.is_valid()) and (not region_form or region_form.is_valid()) ): if region_form: region_form.save() addon = form.save(addon) 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 if cat_form: if cat_form.is_valid(): cat_form.save() addon.save() else: editable = True if device_type_form: if device_type_form.is_valid(): device_type_form.save(addon) addon.save() else: editable = True else: form = models[section](instance=addon, request=request) else: form = False data = { "addon": addon, "webapp": webapp, "form": form, "editable": editable, "tags": tags, "restricted_tags": restricted_tags, "cat_form": cat_form, "preview_form": previews, "valid_slug": valid_slug, "device_type_form": device_type_form, "region_form": region_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() tags = image_assets = previews = restricted_tags = [] cat_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': tags = addon.tags.not_blacklisted().values_list('tag_text', flat=True) cat_form = CategoryForm(request.POST or None, product=addon, request=request) restricted_tags = addon.tags.filter(restricted=True) elif section == 'media': image_assets = ImageAssetFormSet(request.POST or None, prefix='images', app=addon) previews = PreviewFormSet(request.POST or None, prefix='files', queryset=addon.get_previews()) # 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) if (form.is_valid() and (not previews or previews.is_valid()) and (not image_assets or image_assets.is_valid())): addon = form.save(addon) 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) if image_assets: image_assets.save() 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 if cat_form: if cat_form.is_valid(): cat_form.save() addon.save() else: editable = True else: form = models[section](instance=addon, request=request) else: form = False data = { 'addon': addon, 'webapp': webapp, 'form': form, 'editable': editable, 'tags': tags, 'restricted_tags': restricted_tags, 'image_sizes': APP_IMAGE_SIZES, 'cat_form': cat_form, 'preview_form': previews, 'image_asset_form': image_assets, 'valid_slug': valid_slug, } 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)