remove add-on packager from marketplace devhub (bug 733126)

This commit is contained in:
Chris Van 2012-03-06 18:30:33 -08:00
Родитель fb629575ea
Коммит 9b1b99dbfb
6 изменённых файлов: 4 добавлений и 464 удалений

Просмотреть файл

@ -1,15 +1,12 @@
# -*- coding: utf-8 -*-
import os
import re
import socket
from django import forms
from django.conf import settings
from django.db.models import Q
from django.forms.models import modelformset_factory
from django.forms.formsets import formset_factory, BaseFormSet
from django.utils.safestring import mark_safe
from django.utils.encoding import force_unicode
import commonware
import happyforms
@ -26,11 +23,11 @@ from addons.models import (Addon, AddonDependency, AddonUpsell, AddonUser,
from amo.helpers import loc
from amo.forms import AMOModelForm
from amo.urlresolvers import reverse
from amo.utils import raise_required, slugify
from amo.utils import raise_required
from applications.models import Application, AppVersion
from files.models import File, FileUpload, Platform
from files.utils import parse_addon, VERSION_RE
from files.utils import parse_addon
from market.models import AddonPremium, Price, AddonPaymentData
from mkt.site.forms import AddonChoiceField, APP_UPSELL_CHOICES
from payments.models import InappConfig
@ -749,208 +746,6 @@ class AdminForm(happyforms.ModelForm):
}
class InlineRadioRenderer(forms.widgets.RadioFieldRenderer):
def render(self):
return mark_safe(''.join(force_unicode(w) for w in self))
class PackagerBasicForm(forms.Form):
name = forms.CharField(min_length=5, max_length=50,
help_text=_lazy(u'Give your add-on a name. The most successful '
'add-ons give some indication of their function in '
'their name.'))
description = forms.CharField(required=False, widget=forms.Textarea,
help_text=_lazy(u'Briefly describe your add-on in one sentence. '
'This appears in the Add-ons Manager.'))
version = forms.CharField(max_length=32,
help_text=_lazy(u'Enter your initial version number. Depending on the '
'number of releases and your preferences, this is '
'usually 0.1 or 1.0'))
id = forms.CharField(
help_text=_lazy(u'Each add-on requires a unique ID in the form of a '
'UUID or an email address, such as '
'addon-name@developer.com. The email address does not '
'have to be valid.'))
package_name = forms.CharField(min_length=5, max_length=50,
help_text=_lazy(u'The package name of your add-on used within the '
'browser. This should be a short form of its name '
'(for example, Test Extension might be '
'test_extension).'))
author_name = forms.CharField(
help_text=_lazy(u'Enter the name of the person or entity to be '
'listed as the author of this add-on.'))
contributors = forms.CharField(required=False, widget=forms.Textarea,
help_text=_lazy(u'Enter the names of any other contributors to this '
'extension, one per line.'))
def clean_name(self):
name = self.cleaned_data['name']
addons.forms.clean_name(name)
name_regex = re.compile('(mozilla|firefox|thunderbird)', re.I)
if name_regex.match(name):
raise forms.ValidationError(
_('Add-on names should not contain Mozilla trademarks.'))
return name
def clean_package_name(self):
slug = self.cleaned_data['package_name']
if slugify(slug, ok='_', lower=False, delimiter='_') != slug:
raise forms.ValidationError(
_('Enter a valid package name consisting of letters, numbers, '
'or underscores.'))
if Addon.objects.filter(slug=slug).exists():
raise forms.ValidationError(
_('This package name is already in use.'))
if BlacklistedSlug.blocked(slug):
raise forms.ValidationError(
_(u'The package name cannot be: %s.' % slug))
return slug
def clean_id(self):
id_regex = re.compile(
"""(\{[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}\} | # GUID
[a-z0-9-\.\+_]*\@[a-z0-9-\._]+) # Email format""",
re.I | re.X)
if not id_regex.match(self.cleaned_data['id']):
raise forms.ValidationError(
_('The add-on ID must be a UUID string or an email '
'address.'))
return self.cleaned_data['id']
def clean_version(self):
if not VERSION_RE.match(self.cleaned_data['version']):
raise forms.ValidationError(_('The version string is invalid.'))
return self.cleaned_data['version']
class PackagerCompatForm(forms.Form):
enabled = forms.BooleanField(required=False)
min_ver = forms.ModelChoiceField(AppVersion.objects.none(),
empty_label=None, required=False,
label=_lazy(u'Minimum'))
max_ver = forms.ModelChoiceField(AppVersion.objects.none(),
empty_label=None, required=False,
label=_lazy(u'Maximum'))
def __init__(self, *args, **kwargs):
super(PackagerCompatForm, self).__init__(*args, **kwargs)
if not self.initial:
return
self.app = self.initial['application']
qs = (AppVersion.objects.filter(application=self.app.id)
.order_by('-version_int'))
self.fields['enabled'].label = self.app.pretty
if self.app == amo.FIREFOX:
self.fields['enabled'].widget.attrs['checked'] = True
# Don't allow version ranges as the minimum version.
self.fields['min_ver'].queryset = qs.filter(~Q(version__contains='*'))
self.fields['max_ver'].queryset = qs.all()
# Unreasonably hardcode a reasonable default minVersion.
if self.app in (amo.FIREFOX, amo.MOBILE, amo.THUNDERBIRD):
try:
self.fields['min_ver'].initial = qs.filter(
version=settings.DEFAULT_MINVER)[0]
except (IndexError, AttributeError):
pass
def clean_min_ver(self):
if self.cleaned_data['enabled'] and not self.cleaned_data['min_ver']:
raise_required()
return self.cleaned_data['min_ver']
def clean_max_ver(self):
if self.cleaned_data['enabled'] and not self.cleaned_data['max_ver']:
raise_required()
return self.cleaned_data['max_ver']
def clean(self):
if self.errors:
return
data = self.cleaned_data
if data['enabled']:
min_ver = data['min_ver']
max_ver = data['max_ver']
if not (min_ver and max_ver):
raise forms.ValidationError(_('Invalid version range.'))
if min_ver.version_int > max_ver.version_int:
raise forms.ValidationError(
_('Min version must be less than Max version.'))
# Pass back the app name and GUID.
data['min_ver'] = str(min_ver)
data['max_ver'] = str(max_ver)
data['name'] = self.app.pretty
data['guid'] = self.app.guid
return data
class PackagerCompatBaseFormSet(BaseFormSet):
def __init__(self, *args, **kw):
super(PackagerCompatBaseFormSet, self).__init__(*args, **kw)
self.initial = [{'application': a} for a in amo.APP_USAGE]
self._construct_forms()
def clean(self):
if any(self.errors):
return
if (not self.forms or not
any(f.cleaned_data.get('enabled') for f in self.forms
if f.app == amo.FIREFOX)):
# L10n: {0} is Firefox.
raise forms.ValidationError(
_(u'{0} is a required target application.')
.format(amo.FIREFOX.pretty))
return self.cleaned_data
PackagerCompatFormSet = formset_factory(PackagerCompatForm,
formset=PackagerCompatBaseFormSet, extra=0)
class PackagerFeaturesForm(forms.Form):
about_dialog = forms.BooleanField(
required=False,
label=_lazy(u'About dialog'),
help_text=_lazy(u'Creates a standard About dialog for your '
'extension'))
preferences_dialog = forms.BooleanField(
required=False,
label=_lazy(u'Preferences dialog'),
help_text=_lazy(u'Creates an example Preferences window'))
toolbar = forms.BooleanField(
required=False,
label=_lazy(u'Toolbar'),
help_text=_lazy(u'Creates an example toolbar for your extension'))
toolbar_button = forms.BooleanField(
required=False,
label=_lazy(u'Toolbar button'),
help_text=_lazy(u'Creates an example button on the browser '
'toolbar'))
main_menu_command = forms.BooleanField(
required=False,
label=_lazy(u'Main menu command'),
help_text=_lazy(u'Creates an item on the Tools menu'))
context_menu_command = forms.BooleanField(
required=False,
label=_lazy(u'Context menu command'),
help_text=_lazy(u'Creates a context menu item for images'))
sidebar_support = forms.BooleanField(
required=False,
label=_lazy(u'Sidebar support'),
help_text=_lazy(u'Creates an example sidebar panel'))
class CheckCompatibilityForm(happyforms.Form):
application = forms.ChoiceField(
label=_lazy(u'Application'),

Просмотреть файл

@ -22,7 +22,7 @@ import validator.constants as validator_constants
import amo
from amo.decorators import write, set_modified_on
from amo.utils import guard, resize_image, remove_icons, strip_bom
from amo.utils import resize_image, remove_icons, strip_bom
from addons.models import Addon
from applications.management.commands import dump_apps
from applications.models import Application, AppVersion
@ -280,32 +280,6 @@ def convert_purified(ids, **kw):
addon.save()
@task
def packager(data, feature_set, **kw):
"""Build an add-on based on input data."""
log.info('[1@None] Packaging add-on')
from mkt.developers.views import packager_path
dest = packager_path(data['slug'])
with guard(u'mkt.developers.packager.%s' % dest) as locked:
if locked:
log.error(u'Packaging in progress: %s' % dest)
return
with statsd.timer('mkt.developers.packager'):
from packager.main import packager
log.info('Starting packaging: %s' % dest)
features = set([k for k, v in feature_set.items() if v])
try:
packager(data, dest, features)
except Exception, err:
log.error(u'Failed to package add-on: %s' % err)
raise
if os.path.exists(dest):
log.info(u'Package saved: %s' % dest)
def failed_validation(*messages):
"""Return a validation object that looks like the add-on validator."""
m = []

Просмотреть файл

@ -1,111 +0,0 @@
{% extends "developers/base.html" %}
{% from "includes/forms.html" import pretty_field %}
{% set title = _('Add-on Packager') %}
{% block title %}{{ hub_page_title(title) }}{% endblock %}
{% block bodyclass %}packager inverse {{ super() }}{% endblock %}
{% block content %}
<section class="primary">
<header>
{{ hub_breadcrumbs(addon, items=[(None, title)]) }}
<h2>{{ title }}</h2>
</header>
<form method="post" id="packager" class="item" action="">
{{ csrf() }}
<p class="summary">
{% trans %}
Enter some basic information about your add-on below and select which
interface components to start with, and your custom-built add-on will be
ready for download.
{% endtrans %}
</p>
<fieldset>
<legend>{{ _('Describe your add-on') }}</legend>
<p>
{% trans %}
First, you need to enter some basic information about your add-on. This
will be displayed in the Add-ons Manager when your extension is installed.
{% endtrans %}
</p>
{{ basic_form.non_field_errors() }}
<ul>
{{ pretty_field(basic_form.name, _('Add-on Name'), req=True) }}
{{ pretty_field(basic_form.description, _('Description')) }}
{{ pretty_field(basic_form.version, _('Add-on Version'), req=True) }}
{{ pretty_field(basic_form.id, _('Unique ID'), req=True) }}
{{ pretty_field(basic_form.package_name, _('Package Name'), req=True) }}
</ul>
</fieldset>
<fieldset>
<legend>{{ _("Who's working on your add-on?") }}</legend>
<p>
{% trans %}
Tell us about the people or companies behind this add-on. This information
appears in the add-on's About dialog.
{% endtrans %}
</p>
<ul>
{{ pretty_field(basic_form.author_name, _('Primary Author'), req=True) }}
{{ pretty_field(basic_form.contributors, _('Contributors')) }}
</ul>
</fieldset>
<fieldset>
<legend>{{ _('Where will your add-on run?') }}</legend>
<p>
{% trans %}
Select the applications and versions that your add-on will support. The
versions that you select will be the only versions that your add-on will
be installable on. Make sure you only select applications and versions
that you intend to test your add-on with.
{% endtrans %}
</p>
<div id="supported-apps">
<label>{{ _('Supported Applications and Versions') }}</label>
{{ compat_forms.management_form }}
{{ compat_forms.non_form_errors() }}
<ul class="choices">
{% for compat in compat_forms %}
<li class="row">
{{ pretty_field(compat.enabled, tag=None, class='app ' + compat.app.short) }}
{{ pretty_field(compat.min_ver, tag='span') }}
{{ pretty_field(compat.max_ver, tag='span') }}
{{ compat.non_field_errors() }}
</li>
{% endfor %}
</ul>
</div>
</fieldset>
<fieldset>
<legend>{{ _('Choose pre-built features') }}</legend>
<p>
{% trans %}
Get started quickly by selecting user interface components to include in
your add-on package. We'll include documented code for each item you
select so your extension will work out of the box.
{% endtrans %}
</p>
<ul class="choices">
{% for feature in features_form %}
{{ pretty_field(feature) }}
{% endfor %}
</ul>
</fieldset>
<footer>
<button>{{ _('Submit and Build') }}</button>
</footer>
</form>
</section>
<aside class="secondary">
<div class="highlight">
<h3>{{ _('Advanced Building') }}</h3>
<p>
{% trans url="http://www.mozdev.org/projects/wizard/" %}
Want to create XULRunner applications, XPCOM components, and other advanced
skeletons? Visit the <a href="{{ url }}">MozDev Project Wizard</a>.
{% endtrans %}
</p>
</div>
</aside>
{% endblock content %}

Просмотреть файл

@ -1,41 +0,0 @@
{% extends "developers/base.html" %}
{% set title = _('Add-on Packager') %}
{% block title %}{{ hub_page_title(title) }}{% endblock %}
{% block content %}
<header>
{{ hub_breadcrumbs(addon, items=[(None, title)]) }}
<h2>{{ title }}</h2>
<h3>{{ _('Add-on packaged successfully!') }}</h3>
</header>
<section>
<p>
{% trans %}
Use the download link below to save a copy of your extension's compressed
source. To install as an extension in Firefox or another compatible
application, simply rename the <kbd>.zip</kbd> extension to <kbd>.xpi</kbd>.
{% endtrans %}
</p>
<div id="packager-download"
data-downloadurl="{{ url('mkt.developers.package_addon_json', package_name) }}">
<span>{{ _('Please wait&hellip;') }}</span>
<noscript>
{% trans %}
JavaScript needs to be enabled to fetch the packaged add-on.
{% endtrans %}
</noscript>
</div>
<h3>{{ _('What do I do next?') }}</h3>
<p>
{% trans gs_url=url('mkt.developers.docs', 'getting-started'),
ht_url=url('mkt.developers.docs', 'how-to') %}
Now that you've got an extension skeleton, the fun part begins: hacking on
the extension to make it do what you want. If you need some help, check out
our <a href="{{ gs_url }}">Getting Started</a> page for the basics, or
visit the <a href="{{ ht_url }}">How-to Library</a> for tutorials and
documentation.
{% endtrans %}
</p>
</section>
{% endblock content %}

Просмотреть файл

@ -9,8 +9,6 @@ from mkt.developers.decorators import use_apps
from webapps.urls import APP_SLUG
from . import views
PACKAGE_NAME = '(?P<package_name>[_\w]+)'
def paypal_patterns(prefix):
return patterns('',
@ -149,16 +147,6 @@ ajax_patterns = patterns('',
name='mkt.developers.file_perf_tests_start'),
)
packager_patterns = patterns('',
url('^$', views.package_addon, name='mkt.developers.package_addon'),
url('^download/%s.zip$' % PACKAGE_NAME, views.package_addon_download,
name='mkt.developers.package_addon_download'),
url('^json/%s$' % PACKAGE_NAME, views.package_addon_json,
name='mkt.developers.package_addon_json'),
url('^success/%s$' % PACKAGE_NAME, views.package_addon_success,
name='mkt.developers.package_addon_success'),
)
urlpatterns = decorate(write, patterns('',
url('^$', views.index, name='mkt.developers.index'),
@ -177,9 +165,6 @@ urlpatterns = decorate(write, patterns('',
views.compat_application_versions,
name='mkt.developers.compat_application_versions'),
# Add-on packager
url('^tools/package/', include(packager_patterns)),
# Redirect to /addons/ at the base.
url('^addon$',
lambda r: redirect('mkt.developers.addons', permanent=True)),

Просмотреть файл

@ -30,7 +30,7 @@ from amo import messages
from amo.decorators import (json_view, login_required, no_login_required,
post_required, write)
from amo.helpers import loc
from amo.utils import escape_all, HttpResponseSendFile
from amo.utils import escape_all
from amo.urlresolvers import reverse
from access import acl
from addons import forms as addon_forms
@ -603,68 +603,6 @@ def file_perf_tests_start(request, addon_id, addon, file_id):
return {'success': True}
def packager_path(name):
return os.path.join(settings.PACKAGER_PATH, '%s.zip' % name)
@anonymous_csrf
def package_addon(request):
basic_form = forms.PackagerBasicForm(request.POST or None)
features_form = forms.PackagerFeaturesForm(request.POST or None)
compat_forms = forms.PackagerCompatFormSet(request.POST or None)
# Process requests, but also avoid short circuiting by using all().
if (request.method == 'POST' and
all([basic_form.is_valid(),
features_form.is_valid(),
compat_forms.is_valid()])):
basic_data = basic_form.cleaned_data
compat_data = compat_forms.cleaned_data
data = {'id': basic_data['id'],
'version': basic_data['version'],
'name': basic_data['name'],
'slug': basic_data['package_name'],
'description': basic_data['description'],
'author_name': basic_data['author_name'],
'contributors': basic_data['contributors'],
'targetapplications': [c for c in compat_data if c['enabled']]}
tasks.packager.delay(data, features_form.cleaned_data)
return redirect('mkt.developers.package_addon_success',
basic_data['package_name'])
return jingo.render(request, 'developers/package_addon.html',
{'basic_form': basic_form,
'compat_forms': compat_forms,
'features_form': features_form})
def package_addon_success(request, package_name):
"""Return the success page for the add-on packager."""
return jingo.render(request, 'developers/package_addon_success.html',
{'package_name': package_name})
@json_view
def package_addon_json(request, package_name):
"""Return the URL of the packaged add-on."""
path_ = packager_path(package_name)
if os.path.isfile(path_):
url = reverse('mkt.developers.package_addon_download',
args=[package_name])
return {'download_url': url, 'filename': os.path.basename(path_),
'size': round(os.path.getsize(path_) / 1024, 1)}
def package_addon_download(request, package_name):
"""Serve a packaged add-on."""
path_ = packager_path(package_name)
if not os.path.isfile(path_):
raise http.Http404()
return HttpResponseSendFile(request, path_, content_type='application/zip')
@login_required
@post_required
def upload(request, addon_slug=None, is_standalone=False):