248 строки
8.5 KiB
Python
248 строки
8.5 KiB
Python
from django.core.exceptions import ObjectDoesNotExist
|
|
from django.db import transaction
|
|
from django.shortcuts import redirect
|
|
from django.utils.translation.trans_real import to_language
|
|
|
|
import commonware.log
|
|
import jingo
|
|
import waffle
|
|
|
|
import amo
|
|
from amo.decorators import login_required
|
|
from amo.urlresolvers import reverse
|
|
from addons.models import Addon, AddonUser
|
|
from files.models import Platform
|
|
from lib.metrics import record_action
|
|
from users.models import UserProfile
|
|
|
|
import mkt
|
|
from mkt.constants import DEVICE_LOOKUP
|
|
from mkt.developers import tasks
|
|
from mkt.developers.decorators import dev_required
|
|
from mkt.developers.forms import AppFormMedia, CategoryForm, PreviewFormSet
|
|
from mkt.submit.forms import AppDetailsBasicForm
|
|
from mkt.submit.models import AppSubmissionChecklist
|
|
from mkt.webapps.models import AddonExcludedRegion
|
|
|
|
from . import forms
|
|
from .decorators import read_dev_agreement_required, submit_step
|
|
|
|
|
|
log = commonware.log.getLogger('z.submit')
|
|
|
|
|
|
def submit(request):
|
|
"""Determine which step to redirect user to."""
|
|
if not request.user.is_authenticated():
|
|
return proceed(request)
|
|
# If dev has already agreed, continue to next step.
|
|
user = UserProfile.objects.get(pk=request.user.id)
|
|
if not user.read_dev_agreement:
|
|
return redirect('submit.app.terms')
|
|
return manifest(request)
|
|
|
|
|
|
def proceed(request):
|
|
"""
|
|
This is a fake "Terms" view that we overlay the login.
|
|
We link here from the Developer Hub landing page.
|
|
"""
|
|
if request.user.is_authenticated():
|
|
return submit(request)
|
|
agreement_form = forms.DevAgreementForm({'read_dev_agreement': True},
|
|
instance=None)
|
|
return jingo.render(request, 'submit/terms.html', {
|
|
'step': 'terms',
|
|
'agreement_form': agreement_form,
|
|
'proceed': True,
|
|
})
|
|
|
|
|
|
@login_required
|
|
@submit_step('terms')
|
|
def terms(request):
|
|
# If dev has already agreed, continue to next step.
|
|
if (getattr(request, 'amo_user', None) and
|
|
request.amo_user.read_dev_agreement):
|
|
return manifest(request)
|
|
|
|
agreement_form = forms.DevAgreementForm(
|
|
request.POST or {'read_dev_agreement': True},
|
|
instance=request.amo_user)
|
|
if request.POST and agreement_form.is_valid():
|
|
agreement_form.save()
|
|
return redirect('submit.app')
|
|
return jingo.render(request, 'submit/terms.html', {
|
|
'step': 'terms',
|
|
'agreement_form': agreement_form,
|
|
})
|
|
|
|
|
|
@login_required
|
|
@read_dev_agreement_required
|
|
@submit_step('manifest')
|
|
@transaction.commit_on_success
|
|
def manifest(request):
|
|
form = forms.NewWebappForm(request.POST or None, request=request)
|
|
|
|
features_form = forms.AppFeaturesForm(request.POST or None)
|
|
features_form_valid = (True if not waffle.switch_is_active('buchets') else
|
|
features_form.is_valid())
|
|
|
|
if (request.method == 'POST' and form.is_valid() and features_form_valid):
|
|
|
|
addon = Addon.from_upload(
|
|
form.cleaned_data['upload'],
|
|
[Platform.objects.get(id=amo.PLATFORM_ALL.id)],
|
|
is_packaged=form.is_packaged())
|
|
|
|
# Set the device type.
|
|
for device in form.get_devices():
|
|
addon.addondevicetype_set.get_or_create(device_type=device.id)
|
|
|
|
# Set the premium type, only bother if it's not free.
|
|
premium = form.get_paid()
|
|
if premium:
|
|
addon.update(premium_type=premium)
|
|
|
|
if addon.has_icon_in_manifest():
|
|
# Fetch the icon, do polling.
|
|
addon.update(icon_type='image/png')
|
|
tasks.fetch_icon.delay(addon)
|
|
else:
|
|
# In this case there is no need to do any polling.
|
|
addon.update(icon_type='')
|
|
|
|
AddonUser(addon=addon, user=request.amo_user).save()
|
|
# Checking it once. Checking it twice.
|
|
AppSubmissionChecklist.objects.create(addon=addon, terms=True,
|
|
manifest=True)
|
|
|
|
# Create feature profile.
|
|
if waffle.switch_is_active('buchets'):
|
|
addon.current_version.features.update(**features_form.cleaned_data)
|
|
|
|
return redirect('submit.app.details', addon.app_slug)
|
|
|
|
return jingo.render(request, 'submit/manifest.html', {
|
|
'step': 'manifest',
|
|
'features_form': features_form,
|
|
'form': form,
|
|
'DEVICE_LOOKUP': DEVICE_LOOKUP
|
|
})
|
|
|
|
|
|
@dev_required
|
|
@submit_step('details')
|
|
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)
|
|
|
|
tasks.generate_image_assets.delay(addon)
|
|
|
|
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)
|
|
|
|
|
|
@dev_required
|
|
def done(request, addon_id, addon):
|
|
# No submit step forced on this page, we don't really care.
|
|
return jingo.render(request, 'submit/done.html',
|
|
{'step': 'done', 'addon': addon})
|
|
|
|
|
|
@dev_required
|
|
def resume(request, addon_id, addon):
|
|
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
|
|
|
|
return _resume(addon, step)
|
|
|
|
|
|
def _resume(addon, step):
|
|
if step:
|
|
if step in ['terms', 'manifest']:
|
|
return redirect('submit.app.%s' % step)
|
|
return redirect(reverse('submit.app.%s' % step,
|
|
args=[addon.app_slug]))
|
|
|
|
return redirect(addon.get_dev_url('edit'))
|