def handle_upload(self, request, addon, version_string): if "upload" in request.FILES: filedata = request.FILES["upload"] else: raise forms.ValidationError(_(u'Missing "upload" key in multipart file data.'), status.HTTP_400_BAD_REQUEST) # Parse the file to get and validate package data with the addon. pkg = parse_addon(filedata, addon) if not acl.submission_allowed(request.user, pkg): raise forms.ValidationError(_(u"You cannot submit this type of add-on"), status.HTTP_400_BAD_REQUEST) version_string = version_string or pkg["version"] if version_string and pkg["version"] != version_string: raise forms.ValidationError(_("Version does not match the manifest file."), status.HTTP_400_BAD_REQUEST) if addon is not None and addon.versions.filter(version=version_string).exists(): raise forms.ValidationError(_("Version already exists."), status.HTTP_409_CONFLICT) dont_allow_no_guid = not addon and not pkg.get("guid", None) and not pkg.get("is_webextension", False) if dont_allow_no_guid: raise forms.ValidationError( _("Only WebExtensions are allowed to omit the GUID"), status.HTTP_400_BAD_REQUEST ) if addon is None: addon = Addon.create_addon_from_upload_data(data=pkg, user=request.user, upload=filedata, is_listed=False) created = True else: created = False file_upload = handle_upload(filedata=filedata, user=request.user, addon=addon, submit=True) return file_upload, created
def handle_upload(self, request, addon, version_string): if 'upload' in request.FILES: filedata = request.FILES['upload'] else: raise forms.ValidationError( _(u'Missing "upload" key in multipart file data.'), status.HTTP_400_BAD_REQUEST) # Parse the file to get and validate package data with the addon. pkg = parse_addon(filedata, addon) if not acl.submission_allowed(request.user, pkg): raise forms.ValidationError( _(u'You cannot submit this type of add-on'), status.HTTP_400_BAD_REQUEST) version_string = version_string or pkg['version'] if version_string and pkg['version'] != version_string: raise forms.ValidationError( _('Version does not match the manifest file.'), status.HTTP_400_BAD_REQUEST) if (addon is not None and addon.versions.filter(version=version_string).exists()): raise forms.ValidationError( _('Version already exists.'), status.HTTP_409_CONFLICT) dont_allow_no_guid = ( not addon and not pkg.get('guid', None) and not pkg.get('is_webextension', False)) if dont_allow_no_guid: raise forms.ValidationError( _('Only WebExtensions are allowed to omit the GUID'), status.HTTP_400_BAD_REQUEST) if addon is None: addon = Addon.create_addon_from_upload_data( data=pkg, user=request.user, upload=filedata, is_listed=False) created = True channel = amo.RELEASE_CHANNEL_UNLISTED else: created = False last_version = addon.find_latest_version_including_rejected() if last_version: channel = last_version.channel else: # TODO: we need to properly handle channels here and fail if # no previous version to guess with. Also need to allow the # channel to be selected for versions. channel = (amo.RELEASE_CHANNEL_LISTED if addon.is_listed else amo.RELEASE_CHANNEL_UNLISTED) file_upload = handle_upload( filedata=filedata, user=request.user, addon=addon, submit=True, channel=channel) return file_upload, created
def handle_upload(self, request, addon, version_string): if 'upload' in request.FILES: filedata = request.FILES['upload'] else: raise forms.ValidationError( _(u'Missing "upload" key in multipart file data.'), status.HTTP_400_BAD_REQUEST) # Parse the file to get and validate package data with the addon. pkg = parse_addon(filedata, addon) if not acl.submission_allowed(request.user, pkg): raise forms.ValidationError( _(u'You cannot submit this type of add-on'), status.HTTP_400_BAD_REQUEST) version_string = version_string or pkg['version'] if version_string and pkg['version'] != version_string: raise forms.ValidationError( _('Version does not match the manifest file.'), status.HTTP_400_BAD_REQUEST) if (addon is not None and addon.versions.filter(version=version_string).exists()): raise forms.ValidationError( _('Version already exists.'), status.HTTP_409_CONFLICT) dont_allow_no_guid = ( not addon and not pkg.get('guid', None) and not pkg.get('is_webextension', False)) if dont_allow_no_guid: raise forms.ValidationError( _('Only WebExtensions are allowed to omit the GUID'), status.HTTP_400_BAD_REQUEST) if addon is None: addon = Addon.create_addon_from_upload_data( data=pkg, user=request.user, upload=filedata, is_listed=False) created = True else: created = False no_prelim = waffle.flag_is_active(request, 'no-prelim-review') file_upload = handle_upload( filedata=filedata, user=request.user, addon=addon, submit=True, disallow_preliminary_review=no_prelim) return file_upload, created
def put(self, request, addon, version_string): if 'upload' in request.FILES: filedata = request.FILES['upload'] else: return Response( {'error': _('Missing "upload" key in multipart file data.')}, status=status.HTTP_400_BAD_REQUEST) try: # Parse the file to get and validate package data with the addon. pkg = parse_addon(filedata, addon) if not acl.submission_allowed(request.user, pkg): raise forms.ValidationError( _(u'You cannot submit this type of add-on')) except forms.ValidationError as e: return Response({'error': e.message}, status=status.HTTP_400_BAD_REQUEST) if pkg['version'] != version_string: return Response( {'error': _('Version does not match the manifest file.')}, status=status.HTTP_400_BAD_REQUEST) elif (addon is not None and addon.versions.filter(version=version_string).exists()): return Response({'error': _('Version already exists.')}, status=status.HTTP_409_CONFLICT) if addon is None: addon = Addon.create_addon_from_upload_data( data=pkg, user=request.user, is_listed=False) status_code = status.HTTP_201_CREATED else: status_code = status.HTTP_202_ACCEPTED file_upload = handle_upload( filedata=filedata, user=request.user, addon=addon, submit=True) return Response(FileUploadSerializer(file_upload).data, status=status_code)
def handle_upload(self, request, addon, version_string, guid=None): if 'upload' in request.FILES: filedata = request.FILES['upload'] else: raise forms.ValidationError( ugettext(u'Missing "upload" key in multipart file data.'), status.HTTP_400_BAD_REQUEST) # Parse the file to get and validate package data with the addon. pkg = parse_addon(filedata, addon) if not acl.submission_allowed(request.user, pkg): raise forms.ValidationError( ugettext(u'You cannot submit this type of add-on'), status.HTTP_400_BAD_REQUEST) if not addon and not system_addon_submission_allowed( request.user, pkg): raise forms.ValidationError( ugettext(u'You cannot submit an add-on with a guid ending ' u'"@mozilla.org"'), status.HTTP_400_BAD_REQUEST) if not mozilla_signed_extension_submission_allowed(request.user, pkg): raise forms.ValidationError( ugettext(u'You cannot submit a Mozilla Signed Extension')) if addon is not None and addon.status == amo.STATUS_DISABLED: msg = ugettext( 'You cannot add versions to an addon that has status: %s.' % amo.STATUS_CHOICES_ADDON[amo.STATUS_DISABLED]) raise forms.ValidationError(msg, status.HTTP_400_BAD_REQUEST) version_string = version_string or pkg['version'] if version_string and pkg['version'] != version_string: raise forms.ValidationError( ugettext('Version does not match the manifest file.'), status.HTTP_400_BAD_REQUEST) if (addon is not None and addon.versions.filter(version=version_string).exists()): raise forms.ValidationError( ugettext('Version already exists.'), status.HTTP_409_CONFLICT) package_guid = pkg.get('guid', None) dont_allow_no_guid = ( not addon and not package_guid and not pkg.get('is_webextension', False)) if dont_allow_no_guid: raise forms.ValidationError( ugettext('Only WebExtensions are allowed to omit the GUID'), status.HTTP_400_BAD_REQUEST) if guid is not None and not addon and not package_guid: # No guid was present in the package, but one was provided in the # URL, so we take it instead of generating one ourselves. But # first, validate it properly. if not amo.ADDON_GUID_PATTERN.match(guid): raise forms.ValidationError( ugettext('Invalid GUID in URL'), status.HTTP_400_BAD_REQUEST) pkg['guid'] = guid # channel will be ignored for new addons. if addon is None: channel = amo.RELEASE_CHANNEL_UNLISTED # New is always unlisted. addon = Addon.create_addon_from_upload_data( data=pkg, user=request.user, upload=filedata, channel=channel) created = True else: created = False channel_param = request.POST.get('channel') channel = amo.CHANNEL_CHOICES_LOOKUP.get(channel_param) if not channel: last_version = ( addon.find_latest_version(None, exclude=())) if last_version: channel = last_version.channel else: channel = amo.RELEASE_CHANNEL_UNLISTED # Treat as new. will_have_listed = channel == amo.RELEASE_CHANNEL_LISTED if not addon.has_complete_metadata( has_listed_versions=will_have_listed): raise forms.ValidationError( ugettext('You cannot add a listed version to this addon ' 'via the API due to missing metadata. ' 'Please submit via the website'), status.HTTP_400_BAD_REQUEST) file_upload = handle_upload( filedata=filedata, user=request.user, addon=addon, submit=True, channel=channel) return file_upload, created
def check_xpi_info(xpi_info, addon=None, xpi_file=None, user=None): from olympia.addons.models import Addon, DeniedGuid guid = xpi_info['guid'] is_webextension = xpi_info.get('is_webextension', False) # If we allow the guid to be omitted we assume that one was generated # or existed before and use that one. # An example are WebExtensions that don't require a guid but we generate # one once they're uploaded. Now, if you update that WebExtension we # just use the original guid. if addon and not guid and is_webextension: xpi_info['guid'] = guid = addon.guid if not guid and not is_webextension: raise forms.ValidationError(ugettext('Could not find an add-on ID.')) if guid: current_user = core.get_user() if current_user: deleted_guid_clashes = Addon.unfiltered.exclude( authors__id=current_user.id).filter(guid=guid) else: deleted_guid_clashes = Addon.unfiltered.filter(guid=guid) if addon and addon.guid != guid: msg = ugettext( 'The add-on ID in your manifest.json or install.rdf (%s) ' 'does not match the ID of your add-on on AMO (%s)') raise forms.ValidationError(msg % (guid, addon.guid)) if (not addon and # Non-deleted add-ons. (Addon.objects.filter(guid=guid).exists() or # DeniedGuid objects for deletions for Mozilla disabled add-ons DeniedGuid.objects.filter(guid=guid).exists() or # Deleted add-ons that don't belong to the uploader. deleted_guid_clashes.exists())): raise forms.ValidationError(ugettext('Duplicate add-on ID found.')) if len(xpi_info['version']) > 32: raise forms.ValidationError( ugettext('Version numbers should have fewer than 32 characters.')) if not VERSION_RE.match(xpi_info['version']): raise forms.ValidationError( ugettext('Version numbers should only contain letters, numbers, ' 'and these punctuation characters: +*.-_.')) if is_webextension and xpi_info.get('type') == amo.ADDON_STATICTHEME: if not waffle.switch_is_active('allow-static-theme-uploads'): raise forms.ValidationError(ugettext( 'WebExtension theme uploads are currently not supported.')) if xpi_file: # Make sure we pass in a copy of `xpi_info` since # `resolve_webext_translations` modifies data in-place translations = Addon.resolve_webext_translations( xpi_info.copy(), xpi_file) verify_mozilla_trademark(translations['name'], core.get_user()) # Parse the file to get and validate package data with the addon. if not acl.submission_allowed(user, xpi_info): raise forms.ValidationError( ugettext(u'You cannot submit this type of add-on')) if not addon and not system_addon_submission_allowed( user, xpi_info): guids = ' or '.join( '"' + guid + '"' for guid in amo.SYSTEM_ADDON_GUIDS) raise forms.ValidationError( ugettext(u'You cannot submit an add-on with a guid ending ' u'%s' % guids)) if not mozilla_signed_extension_submission_allowed(user, xpi_info): raise forms.ValidationError( ugettext(u'You cannot submit a Mozilla Signed Extension')) return xpi_info
def handle_upload(self, request, addon, version_string, guid=None): if 'upload' in request.FILES: filedata = request.FILES['upload'] else: raise forms.ValidationError( _(u'Missing "upload" key in multipart file data.'), status.HTTP_400_BAD_REQUEST) # Parse the file to get and validate package data with the addon. pkg = parse_addon(filedata, addon) if not acl.submission_allowed(request.user, pkg): raise forms.ValidationError( _(u'You cannot submit this type of add-on'), status.HTTP_400_BAD_REQUEST) if not addon and not system_addon_submission_allowed( request.user, pkg): raise forms.ValidationError( _(u'You cannot submit an add-on with a guid ending ' u'"@mozilla.org"'), status.HTTP_400_BAD_REQUEST) if addon is not None and addon.status == amo.STATUS_DISABLED: raise forms.ValidationError( _('You cannot add versions to an addon that has status: %s.' % amo.STATUS_CHOICES_ADDON[amo.STATUS_DISABLED]), status.HTTP_400_BAD_REQUEST) version_string = version_string or pkg['version'] if version_string and pkg['version'] != version_string: raise forms.ValidationError( _('Version does not match the manifest file.'), status.HTTP_400_BAD_REQUEST) if (addon is not None and addon.versions.filter(version=version_string).exists()): raise forms.ValidationError(_('Version already exists.'), status.HTTP_409_CONFLICT) package_guid = pkg.get('guid', None) dont_allow_no_guid = (not addon and not package_guid and not pkg.get('is_webextension', False)) if dont_allow_no_guid: raise forms.ValidationError( _('Only WebExtensions are allowed to omit the GUID'), status.HTTP_400_BAD_REQUEST) if guid is not None and not addon and not package_guid: # No guid was present in the package, but one was provided in the # URL, so we take it instead of generating one ourselves. But # first, validate it properly. if not amo.ADDON_GUID_PATTERN.match(guid): raise forms.ValidationError(_('Invalid GUID in URL'), status.HTTP_400_BAD_REQUEST) pkg['guid'] = guid # channel will be ignored for new addons. if addon is None: channel = amo.RELEASE_CHANNEL_UNLISTED # New is always unlisted. addon = Addon.create_addon_from_upload_data(data=pkg, user=request.user, upload=filedata, channel=channel) created = True else: created = False channel_param = request.POST.get('channel') channel = amo.CHANNEL_CHOICES_LOOKUP.get(channel_param) if not channel: last_version = (addon.find_latest_version(None, exclude=())) if last_version: channel = last_version.channel else: channel = amo.RELEASE_CHANNEL_UNLISTED # Treat as new. will_have_listed = channel == amo.RELEASE_CHANNEL_LISTED if not addon.has_complete_metadata( has_listed_versions=will_have_listed): raise forms.ValidationError( _('You cannot add a listed version to this addon ' 'via the API due to missing metadata. ' 'Please submit via the website'), status.HTTP_400_BAD_REQUEST) file_upload = handle_upload(filedata=filedata, user=request.user, addon=addon, submit=True, channel=channel) return file_upload, created
def check_xpi_info(xpi_info, addon=None, xpi_file=None, user=None): from olympia.addons.models import Addon, DeniedGuid guid = xpi_info['guid'] is_webextension = xpi_info.get('is_webextension', False) # If we allow the guid to be omitted we assume that one was generated # or existed before and use that one. # An example are WebExtensions that don't require a guid but we generate # one once they're uploaded. Now, if you update that WebExtension we # just use the original guid. if addon and not guid and is_webextension: xpi_info['guid'] = guid = addon.guid if not guid and not is_webextension: raise forms.ValidationError(ugettext('Could not find an add-on ID.')) if guid: current_user = core.get_user() if current_user: deleted_guid_clashes = Addon.unfiltered.exclude( authors__id=current_user.id).filter(guid=guid) else: deleted_guid_clashes = Addon.unfiltered.filter(guid=guid) if addon and addon.guid != guid: msg = ugettext( 'The add-on ID in your manifest.json or install.rdf (%s) ' 'does not match the ID of your add-on on AMO (%s)') raise forms.ValidationError(msg % (guid, addon.guid)) if (not addon and # Non-deleted add-ons. ( Addon.objects.filter(guid=guid).exists() or # DeniedGuid objects for deletions for Mozilla disabled add-ons DeniedGuid.objects.filter(guid=guid).exists() or # Deleted add-ons that don't belong to the uploader. deleted_guid_clashes.exists())): raise forms.ValidationError(ugettext('Duplicate add-on ID found.')) if len(xpi_info['version']) > 32: raise forms.ValidationError( ugettext('Version numbers should have fewer than 32 characters.')) if not VERSION_RE.match(xpi_info['version']): raise forms.ValidationError( ugettext('Version numbers should only contain letters, numbers, ' 'and these punctuation characters: +*.-_.')) if is_webextension and xpi_info.get('type') == amo.ADDON_STATICTHEME: if not waffle.switch_is_active('allow-static-theme-uploads'): raise forms.ValidationError( ugettext( 'WebExtension theme uploads are currently not supported.')) if xpi_file: # Make sure we pass in a copy of `xpi_info` since # `resolve_webext_translations` modifies data in-place translations = Addon.resolve_webext_translations( xpi_info.copy(), xpi_file) verify_mozilla_trademark(translations['name'], core.get_user()) # Parse the file to get and validate package data with the addon. if not acl.submission_allowed(user, xpi_info): raise forms.ValidationError( ugettext(u'You cannot submit this type of add-on')) if not addon and not system_addon_submission_allowed(user, xpi_info): guids = ' or '.join('"' + guid + '"' for guid in amo.SYSTEM_ADDON_GUIDS) raise forms.ValidationError( ugettext(u'You cannot submit an add-on with a guid ending ' u'%s' % guids)) if not mozilla_signed_extension_submission_allowed(user, xpi_info): raise forms.ValidationError( ugettext(u'You cannot submit a Mozilla Signed Extension')) return xpi_info
def handle_upload(self, request, addon, version_string): if 'upload' in request.FILES: filedata = request.FILES['upload'] else: raise forms.ValidationError( _(u'Missing "upload" key in multipart file data.'), status.HTTP_400_BAD_REQUEST) # Parse the file to get and validate package data with the addon. pkg = parse_addon(filedata, addon) if not acl.submission_allowed(request.user, pkg): raise forms.ValidationError( _(u'You cannot submit this type of add-on'), status.HTTP_400_BAD_REQUEST) if addon is not None and addon.status == amo.STATUS_DISABLED: raise forms.ValidationError( _('You cannot add versions to an addon that has status: %s.' % amo.STATUS_CHOICES_ADDON[amo.STATUS_DISABLED]), status.HTTP_400_BAD_REQUEST) version_string = version_string or pkg['version'] if version_string and pkg['version'] != version_string: raise forms.ValidationError( _('Version does not match the manifest file.'), status.HTTP_400_BAD_REQUEST) if (addon is not None and addon.versions.filter(version=version_string).exists()): raise forms.ValidationError(_('Version already exists.'), status.HTTP_409_CONFLICT) dont_allow_no_guid = (not addon and not pkg.get('guid', None) and not pkg.get('is_webextension', False)) if dont_allow_no_guid: raise forms.ValidationError( _('Only WebExtensions are allowed to omit the GUID'), status.HTTP_400_BAD_REQUEST) # channel will be ignored for new addons and while waffle # 'mixed-listed-unlisted' is disabled. if addon is None: channel = amo.RELEASE_CHANNEL_UNLISTED # New is always unlisted. addon = Addon.create_addon_from_upload_data(data=pkg, user=request.user, upload=filedata, channel=channel) created = True else: created = False if waffle.switch_is_active('mixed-listed-unlisted'): channel_param = request.POST.get('channel') channel = amo.CHANNEL_CHOICES_LOOKUP.get(channel_param) if not channel: last_version = ( addon.find_latest_version_including_rejected(None)) if last_version: channel = last_version.channel else: channel = amo.RELEASE_CHANNEL_UNLISTED # Treat as new. else: # Don't allow channel choice until rest of AMO supports it. channel = (amo.RELEASE_CHANNEL_LISTED if addon.is_listed else amo.RELEASE_CHANNEL_UNLISTED) will_have_listed = channel == amo.RELEASE_CHANNEL_LISTED if not addon.has_complete_metadata( has_listed_versions=will_have_listed): raise forms.ValidationError( _('You cannot add a listed version to this addon ' 'via the API due to missing metadata. ' 'Please submit via the website'), status.HTTP_400_BAD_REQUEST) file_upload = handle_upload(filedata=filedata, user=request.user, addon=addon, submit=True, channel=channel) return file_upload, created