diff --git a/src/pretix/api/serializers/item.py b/src/pretix/api/serializers/item.py index 57ea732748..58ebf999e5 100644 --- a/src/pretix/api/serializers/item.py +++ b/src/pretix/api/serializers/item.py @@ -31,7 +31,7 @@ # Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations under the License. - +import os.path from decimal import Decimal from django.core.exceptions import ValidationError @@ -245,7 +245,10 @@ class ItemSerializer(I18nAwareModelSerializer): addons_data = validated_data.pop('addons') if 'addons' in validated_data else {} bundles_data = validated_data.pop('bundles') if 'bundles' in validated_data else {} meta_data = validated_data.pop('meta_data', None) + picture = validated_data.pop('picture', None) item = Item.objects.create(**validated_data) + if picture: + item.picture.save(os.path.basename(picture.name), picture) for variation_data in variations_data: require_membership_types = variation_data.pop('require_membership_types') @@ -269,7 +272,10 @@ class ItemSerializer(I18nAwareModelSerializer): def update(self, instance, validated_data): meta_data = validated_data.pop('meta_data', None) + picture = validated_data.pop('picture', None) item = super().update(instance, validated_data) + if picture: + item.picture.save(os.path.basename(picture.name), picture) # Meta data if meta_data is not None: diff --git a/src/tests/api/test_events.py b/src/tests/api/test_events.py index 1d39283197..000c22da7a 100644 --- a/src/tests/api/test_events.py +++ b/src/tests/api/test_events.py @@ -1396,6 +1396,7 @@ def test_patch_event_settings_file(token_client, organizer, event): ) assert resp.status_code == 200 assert resp.data['logo_image'].startswith('http') + assert '/pub/' in resp.data['logo_image'] resp = token_client.patch( '/api/v1/organizers/{}/events/{}/settings/'.format(organizer.slug, event.slug), diff --git a/src/tests/api/test_items.py b/src/tests/api/test_items.py index 96153ef52f..5b7861cc77 100644 --- a/src/tests/api/test_items.py +++ b/src/tests/api/test_items.py @@ -31,13 +31,15 @@ # Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations under the License. - +import os import time from datetime import datetime, timedelta from decimal import Decimal from unittest import mock import pytest +from django.conf import settings +from django.core.files.base import ContentFile from django_countries.fields import Country from django_scopes import scopes_disabled from pytz import UTC @@ -1024,6 +1026,80 @@ def test_item_update(token_client, organizer, event, item, category, item2, cate assert resp.content.decode() == '{"meta_data":["Item meta data property \'foo\' does not exist."]}' +@pytest.mark.django_db +def test_item_file_upload(token_client, organizer, event, item): + r = token_client.post( + '/api/v1/upload', + data={ + 'media_type': 'image/png', + 'file': ContentFile('file.png', 'invalid png content') + }, + format='upload', + HTTP_CONTENT_DISPOSITION='attachment; filename="file.png"', + ) + assert r.status_code == 201 + file_id_png = r.data['id'] + + resp = token_client.patch( + '/api/v1/organizers/{}/events/{}/items/{}/'.format(organizer.slug, event.slug, item.pk), + { + "picture": file_id_png, + }, + format='json' + ) + assert resp.status_code == 200 + assert resp.data['picture'].startswith('http') + assert '/pub/' in resp.data['picture'] + assert os.path.exists(os.path.join(settings.MEDIA_ROOT, resp.data['picture'].split('/media/')[1])) + + r = token_client.post( + '/api/v1/upload', + data={ + 'media_type': 'image/png', + 'file': ContentFile('file.png', 'invalid png content') + }, + format='upload', + HTTP_CONTENT_DISPOSITION='attachment; filename="file.png"', + ) + assert r.status_code == 201 + file_id_png = r.data['id'] + + resp = token_client.post( + '/api/v1/organizers/{}/events/{}/items/'.format(organizer.slug, event.slug), + { + "name": { + "en": "Ticket" + }, + "active": True, + "sales_channels": ["web", "pretixpos"], + "picture": file_id_png, + "description": None, + "default_price": "23.00", + "free_price": False, + "admission": True, + "issue_giftcard": False, + "position": 0, + "available_from": None, + "available_until": None, + "require_voucher": False, + "hide_without_voucher": False, + "allow_cancel": True, + "min_per_order": None, + "max_per_order": None, + "checkin_attention": False, + "has_variations": True, + "meta_data": { + "day": "Wednesday" + } + }, + format='json' + ) + assert resp.status_code == 201 + assert resp.data['picture'].startswith('http') + assert '/pub/' in resp.data['picture'] + assert os.path.exists(os.path.join(settings.MEDIA_ROOT, resp.data['picture'].split('/media/')[1])) + + @pytest.mark.django_db def test_item_update_with_variation(token_client, organizer, event, item): resp = token_client.patch(