Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement addon PUT as full-update or create #19342

Merged
merged 4 commits into from
Jun 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions docs/topics/api/addons.rst
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,27 @@ Note: as form-data can not include objects, and creating an add-on requires the
:reqheader Content-Type: multipart/form-data


--------------------
Put - Create or Edit
--------------------

.. _addon-put:

This endpoint allows a submission of an upload, which will either update an existing add-on and create a new version if the guid already exists, or will create a new add-on if the guid does not exist.
See the :ref:`Add-on Create <addon-create>` documentation for details of the request and restrictions.

.. note::
This API requires :doc:`authentication <auth>`, and for the user to be an author of the add-on if the add-on exists already.

.. note::
The guid in the url must match a guid specified in the manifest.

.. note::
A submission that results in a new add-on will have metadata defaults taken from the manifest (e.g. name), but a submission that updates an existing listing will not use data from the manifest.

.. http:put:: /api/v5/addons/addon/(string:guid)/


------
Delete
------
Expand Down
1 change: 1 addition & 0 deletions docs/topics/api/overview.rst
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,7 @@ These are `v5` specific changes - `v4` changes apply also.
* 2022-05-05: added the ability to delete add-on authors. https://github.com/mozilla/addons-server/issues/19163
* 2022-05-12: added the ability to add new add-on authors, as pending authors. https://github.com/mozilla/addons-server/issues/19164
* 2022-06-02: enabled setting ``default_locale`` via addon submission and edit endpoints. https://github.com/mozilla/addons-server/issues/18235
* 2022-06-16: added the ability to "PUT" an add-on upload to either create or update an add-on. https://github.com/mozilla/addons-server/issues/15353

.. _`#11380`: https://github.com/mozilla/addons-server/issues/11380/
.. _`#11379`: https://github.com/mozilla/addons-server/issues/11379/
Expand Down
28 changes: 22 additions & 6 deletions src/olympia/addons/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from olympia.amo.validators import (
CreateOnlyValidator,
OneOrMoreLetterOrNumberCharacterValidator,
PreventPartialUpdateValidator,
)
from olympia.api.fields import (
EmailTranslationField,
Expand Down Expand Up @@ -79,6 +80,7 @@
from .validators import (
AddonMetadataValidator,
AddonDefaultLocaleValidator,
MatchingGuidValidator,
VersionAddonMetadataValidator,
VersionLicenseValidator,
VerifyMozillaTrademark,
Expand Down Expand Up @@ -862,7 +864,11 @@ class AddonSerializer(serializers.ModelSerializer):
version = DeveloperVersionSerializer(
write_only=True,
# Note: we're purposefully omitting VersionAddonMetadataValidator
validators=(CreateOnlyValidator(), VersionLicenseValidator()),
validators=(
PreventPartialUpdateValidator(),
VersionLicenseValidator(),
MatchingGuidValidator(),
),
)
versions_url = serializers.SerializerMethodField()

Expand Down Expand Up @@ -998,15 +1004,17 @@ def get_ratings(self, obj):
def get_is_source_public(self, obj):
return False

def run_validation(self, *args, **kwargs):
def run_validation(self, data=serializers.empty):
# We want name and summary to be required fields so they're not cleared, but
# *only* if this is an existing add-on with listed versions.
# - see AddonMetadataValidator for new add-ons/versions.
if self.instance and self.instance.has_listed_versions():
self.fields['name'].required = True
self.fields['summary'].required = True
self.fields['categories'].required = True
return super().run_validation(*args, **kwargs)
for field in ('name', 'summary', 'categories'):
if field in data:
self.fields[field].required = True
if self.instance:
self.fields['version'].addon = self.instance
return super().run_validation(data)

def validate_slug(self, value):
slug_validator(value)
Expand Down Expand Up @@ -1083,6 +1091,9 @@ def log(self, instance, validated_data):
if 'tag_list' in validated_data:
# Tag.add_tag and Tag.remove_tag have their own logging so don't repeat it.
validated_data.pop('tag_list')
if 'version' in validated_data:
# version is always a new object, and not a property either
validated_data.pop('version')

if validated_data:
ActivityLog.create(
Expand Down Expand Up @@ -1140,6 +1151,11 @@ def update(self, instance, validated_data):
if 'tag_list' in validated_data:
del instance.tag_list # super.update will have set it.
instance.set_tag_list(validated_data['tag_list'])
if 'version' in validated_data:
self.fields['version'].create(
{**validated_data.get('version', {}), 'addon': instance}
)

self.log(instance, validated_data)
return instance

Expand Down
Loading