just the start, create an app (bug 753570)

This commit is contained in:
Andy McKay 2012-05-18 14:52:30 +01:00
Родитель c3346ea621
Коммит cdcbc6ba97
7 изменённых файлов: 170 добавлений и 7 удалений

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

@ -288,6 +288,13 @@ class AMOPaths(object):
os.makedirs(os.path.dirname(file.file_path))
shutil.copyfile(self.xpi_path(name), file.file_path)
def manifest_path(self, name):
return os.path.join(settings.ROOT,
'mkt/submit/tests/webapps/%s' % name)
def manifest_copy_over(self, dest, name):
shutil.copyfile(self.manifest_path(name), dest)
@staticmethod
def sample_key():
path = 'mkt/webapps/tests/sample.key'

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

@ -206,6 +206,11 @@ ADDON_PREMIUM_TYPES = {
ADDON_PREMIUM_OTHER: _("Premium, but I'll use my own payments system")
}
# Non-locale versions for the API.
ADDON_PREMIUM_API = {
ADDON_FREE: 'free',
}
ADDON_PREMIUMS = (ADDON_PREMIUM, ADDON_PREMIUM_INAPP)
ADDON_FREES = (ADDON_FREE, ADDON_FREE_INAPP)
ADDON_INAPPS = (ADDON_PREMIUM_INAPP, ADDON_FREE_INAPP)

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

@ -5,8 +5,11 @@ from tastypie.bundle import Bundle
from tastypie.resources import ModelResource
from tastypie.utils import dict_strip_unicode_keys
from translations.fields import PurifiedField, TranslatedField
class MarketplaceResource(ModelResource):
def get_resource_uri(self, bundle_or_obj):
# Fix until my pull request gets pulled into tastypie.
# https://github.com/toastdriven/django-tastypie/pull/490
@ -49,5 +52,13 @@ class MarketplaceResource(ModelResource):
response_class=http.HttpCreated,
location=location)
@classmethod
def should_skip_field(cls, field):
# We don't want to skip translated fields.
if isinstance(field, (PurifiedField, TranslatedField)):
return False
return True if getattr(field, 'rel') else False
def form_errors(self, form):
return json.dumps({'error_message': dict(form.errors.items())})

23
mkt/api/forms.py Normal file
Просмотреть файл

@ -0,0 +1,23 @@
from django import forms
import happyforms
from files.models import FileUpload
class UploadForm(happyforms.Form):
manifest = forms.CharField(max_length=32, min_length=32)
def clean_manifest(self):
uuid = self.cleaned_data.get('manifest')
try:
upload = FileUpload.objects.get(uuid=uuid)
except FileUpload.DoesNotExist:
raise forms.ValidationError('No upload found.')
if not upload.valid:
raise forms.ValidationError('Upload not valid.')
self.obj = upload
return uuid

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

@ -1,17 +1,23 @@
import json
from django.db import transaction
from django.forms import ValidationError
import commonware.log
from tastypie import http
from tastypie.exceptions import ImmediateHttpResponse
from files.models import FileUpload
from mkt.developers import tasks
from mkt.developers.forms import NewManifestForm
from addons.models import AddonUser
import amo
from amo.decorators import write
from files.models import FileUpload, Platform
from mkt.api.authentication import (OwnerAuthorization,
MarketplaceAuthentication)
from mkt.api.base import MarketplaceResource
from mkt.api.forms import UploadForm
from mkt.developers import tasks
from mkt.developers.forms import NewManifestForm
from mkt.webapps.models import Webapp
log = commonware.log.getLogger('z.api')
@ -30,6 +36,8 @@ class ValidationResource(MarketplaceResource):
authorization = OwnerAuthorization()
resource_name = 'validation'
@write
@transaction.commit_on_success
def obj_create(self, bundle, request=None, **kwargs):
form = NewManifestForm(bundle.data)
if not form.is_valid():
@ -65,3 +73,42 @@ class ValidationResource(MarketplaceResource):
bundle.data['processed'] = (bool(bundle.obj.valid or
bundle.obj.validation))
return bundle
class AppResource(MarketplaceResource):
class Meta:
queryset = Webapp.objects.valid().no_transforms()
fields = ['name', 'description', 'homepage', 'status', 'summary',
'support_email', 'support_url']
list_allowed_methods = ['post']
allowed_methods = []
always_return_data = True
authentication = MarketplaceAuthentication()
authorization = OwnerAuthorization()
resource_name = 'app'
@write
@transaction.commit_on_success
def obj_create(self, bundle, request, **kwargs):
form = UploadForm(bundle.data)
if not form.is_valid():
raise ValidationError(self.form_errors(form))
if not (OwnerAuthorization()
.is_authorized(request, object=form.obj)):
raise ImmediateHttpResponse(response=http.HttpUnauthorized())
plats = [Platform.objects.get(id=amo.PLATFORM_ALL.id)]
# Create app, user and fetch the icon.
bundle.obj = Webapp.from_upload(form.obj, plats)
AddonUser(addon=bundle.obj, user=request.amo_user).save()
tasks.fetch_icon.delay(bundle.obj,)
return bundle
def dehydrate(self, bundle):
obj = bundle.obj
bundle.data['slug'] = obj.app_slug
bundle.data['premium_type'] = amo.ADDON_PREMIUM_API[obj.premium_type]
return bundle

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

@ -1,12 +1,16 @@
import json
import tempfile
from django.conf import settings
from mock import patch
from nose.tools import eq_
from addons.models import Addon
from amo.tests import AMOPaths
from files.models import FileUpload
from mkt.api.tests.test_oauth import BaseOAuth
from mkt.webapps.models import Webapp
from users.models import UserProfile
@ -113,3 +117,67 @@ class TestGetValidationHandler(ValidationHandler):
eq_(data['processed'], True)
eq_(data['valid'], False)
eq_(data['validation'], json.loads(error))
class CreateHandler(BaseOAuth):
fixtures = ['base/user_2519', 'base/users', 'base/platforms']
def setUp(self):
super(CreateHandler, self).setUp()
self.list_url = ('api_dispatch_list', {'resource_name': 'app'})
self.user = UserProfile.objects.get(pk=2519)
self.file = tempfile.NamedTemporaryFile('w', suffix='.webapp').name
self.manifest_copy_over(self.file, 'mozball-nice-slug.webapp')
def create(self):
return FileUpload.objects.create(user=self.user, path=self.file,
name=self.file, valid=True)
def get_error(self, response):
return json.loads(response.content)['error_message']
@patch.object(settings, 'SITE_URL', 'http://api/')
class TestAppCreateHandler(CreateHandler, AMOPaths):
def count(self):
return Addon.objects.count()
def test_not_valid(self):
obj = self.create()
obj.update(valid=False)
res = self.client.post(self.list_url,
body=json.dumps({'manifest': obj.uuid}))
eq_(res.status_code, 400)
eq_(self.get_error(res)['manifest'], ['Upload not valid.'])
eq_(self.count(), 0)
def test_not_there(self):
res = self.client.post(self.list_url,
body=json.dumps({'manifest':
'some-random-32-character-stringy'}))
eq_(res.status_code, 400)
eq_(self.get_error(res)['manifest'], ['No upload found.'])
eq_(self.count(), 0)
def test_not_yours(self):
obj = self.create()
obj.update(user=UserProfile.objects.get(email='admin@mozilla.com'))
res = self.client.post(self.list_url,
body=json.dumps({'manifest': obj.uuid}))
eq_(res.status_code, 401)
eq_(self.count(), 0)
def test_create(self):
obj = self.create()
res = self.client.post(self.list_url,
body=json.dumps({'manifest': obj.uuid}))
eq_(res.status_code, 201)
content = json.loads(res.content)
eq_(content['status'], 0)
eq_(content['slug'], u'mozillaball')
eq_(content['support_email'], None)
eq_(self.count(), 1)
app = Webapp.objects.get(app_slug=content['slug'])
eq_(set(app.authors.all()), set([self.user]))

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

@ -1,11 +1,13 @@
from django.conf.urls.defaults import include, patterns, url
from tastypie.api import Api
from mkt.api.resources import ValidationResource
from mkt.api.resources import AppResource, ValidationResource
api = Api(api_name='apps')
api.register(ValidationResource())
api.register(AppResource())
validation = Api(api_name='apps')
validation.register(ValidationResource())
urlpatterns = patterns('',
url(r'^', include(validation.urls)),
url(r'^', include(api.urls)),
)