From b8753deff1663efbc891cdf37157dd60898657f4 Mon Sep 17 00:00:00 2001 From: Anna Grund Date: Wed, 27 Sep 2023 22:16:59 +0300 Subject: [PATCH] [AJP-2] --- ajapaik/ajapaik/forms.py | 19 +-- ajapaik/ajapaik/models.py | 13 +- .../static/css/ajp-geotagger-plugin.css | 6 - .../js/ajp-picture-category-retrival.js | 2 +- ajapaik/ajapaik/views.py | 121 ++++++++++-------- ajapaik/ajapaik_object_categorization/urls.py | 2 +- ajapaik/settings/.DS_Store | Bin 0 -> 6148 bytes ajapaik/settings/local.py | 77 ----------- 8 files changed, 78 insertions(+), 162 deletions(-) create mode 100644 ajapaik/settings/.DS_Store delete mode 100644 ajapaik/settings/local.py diff --git a/ajapaik/ajapaik/forms.py b/ajapaik/ajapaik/forms.py index 3ba71e504..f56360108 100644 --- a/ajapaik/ajapaik/forms.py +++ b/ajapaik/ajapaik/forms.py @@ -417,17 +417,15 @@ class VideoStillCaptureForm(forms.Form): class UserPhotoUploadForm(forms.ModelForm): - images = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True})) - def __init__(self, *args, **kwargs): super(UserPhotoUploadForm, self).__init__(*args, **kwargs) self.fields['licence'].queryset = Licence.objects.filter(is_public=True) class Meta: model = Photo - fields = ('images', 'description', 'uploader_is_author', 'author', 'licence') + fields = ('image', 'description', 'uploader_is_author', 'author', 'licence') labels = { - 'images': _('Picture files'), + 'image': _('Picture file'), 'description': _('Description'), 'uploader_is_author': _('I am the author'), 'author': _('Author'), @@ -450,17 +448,10 @@ class Meta: 'author': forms.TextInput(attrs={'placeholder': _('Author name')}), } - def clean_images(self): - images = self.cleaned_data.get('images') - - if not images: - raise forms.ValidationError(_('At least one image file is required.')) - - return images - def clean(self): super(UserPhotoUploadForm, self).clean() - + if not self.cleaned_data.get('image'): + self.errors['image'] = [_('Missing image')] if not self.cleaned_data.get('description'): self.errors['description'] = [_('Missing description')] if not self.cleaned_data.get('uploader_is_author') and not self.cleaned_data.get('licence'): @@ -674,4 +665,4 @@ class ApiWikidocsAlbumSearchForm(forms.Form): class CsvImportForm(forms.Form): zip_file = forms.FileField(required=False) - csv_file = forms.FileField() + csv_file = forms.FileField() \ No newline at end of file diff --git a/ajapaik/ajapaik/models.py b/ajapaik/ajapaik/models.py index ee17fef87..32d81b0f4 100644 --- a/ajapaik/ajapaik/models.py +++ b/ajapaik/ajapaik/models.py @@ -2090,6 +2090,7 @@ class PhotoModelSuggestionResult(Suggestion): viewpoint_elevation = PositiveSmallIntegerField(_('Viewpoint elevation'), choices=VIEWPOINT_ELEVATION_CHOICES, blank=True, null=True) scene = PositiveSmallIntegerField(_('Scene'), choices=SCENE_CHOICES, blank=True, null=True) + class PhotoModelSuggestionAlternativeCategory(Suggestion): INTERIOR, EXTERIOR = range(2) GROUND_LEVEL, RAISED, AERIAL = range(3) @@ -2102,10 +2103,13 @@ class PhotoModelSuggestionAlternativeCategory(Suggestion): (RAISED, _('Raised')), (AERIAL, _('Aerial')) ) - viewpoint_elevation_alternation = PositiveSmallIntegerField(_('Viewpoint elevation'), choices=VIEWPOINT_ELEVATION_CHOICES, blank=True, null=True) + viewpoint_elevation_alternation = PositiveSmallIntegerField(_('Viewpoint elevation'), + choices=VIEWPOINT_ELEVATION_CHOICES, blank=True, + null=True) scene_alternation = PositiveSmallIntegerField(_('Scene'), choices=SCENE_CHOICES, blank=True, null=True) - proposer = ForeignKey('Profile', blank=True, null=True, related_name='photo_scene_suggestions_alternation', on_delete=CASCADE) + proposer = ForeignKey('Profile', blank=True, null=True, related_name='photo_scene_suggestions_alternation', + on_delete=CASCADE) def validate_unique(self, exclude=None): super().validate_unique(exclude) @@ -2116,11 +2120,6 @@ def validate_unique(self, exclude=None): photo_id=self.photo_id ).exclude(pk=self.pk) - print(f"QUERY SET IS {queryset}") - print(type(self.scene_alternation)) - print(self.scene_alternation in ['0', '1']) - print(queryset.exists()) - if self.scene_alternation in ['0', '1'] and queryset.exists(): raise ValidationError('Only one record with scene_alternation 0 or 1 is allowed.') diff --git a/ajapaik/ajapaik/static/css/ajp-geotagger-plugin.css b/ajapaik/ajapaik/static/css/ajp-geotagger-plugin.css index 2ce48211d..75a601e6a 100644 --- a/ajapaik/ajapaik/static/css/ajp-geotagger-plugin.css +++ b/ajapaik/ajapaik/static/css/ajp-geotagger-plugin.css @@ -381,12 +381,6 @@ border-radius: 0; } -.ajp-button { - bottom: 3% !important; - right: 3% !important; - min-width: 150px; - border-radius: 0; -} #ajp-geotagging-container div.gm-style-mtc > div:nth-of-type(2) { bottom: auto; diff --git a/ajapaik/ajapaik/static/js/ajp-picture-category-retrival.js b/ajapaik/ajapaik/static/js/ajp-picture-category-retrival.js index 1d61f7b04..9bd2d73ce 100644 --- a/ajapaik/ajapaik/static/js/ajp-picture-category-retrival.js +++ b/ajapaik/ajapaik/static/js/ajp-picture-category-retrival.js @@ -68,4 +68,4 @@ function sendCategoryFeedback(photoId, category, categoryValue) { constants.translations.queries.POST_CATEGORY_CONFIRMATION_FAILED, onSuccess ); -} \ No newline at end of file +} diff --git a/ajapaik/ajapaik/views.py b/ajapaik/ajapaik/views.py index debc17d6a..d4df2b1b8 100644 --- a/ajapaik/ajapaik/views.py +++ b/ajapaik/ajapaik/views.py @@ -92,7 +92,7 @@ from ajapaik.utils import get_etag, calculate_thumbnail_size, convert_to_degrees, calculate_thumbnail_size_max_height, \ distance_in_meters, angle_diff, last_modified, suggest_photo_edit from .fotis_utils import parse_fotis_timestamp_data -from .utils import get_comment_replies, get_pagination_parameters +from .utils import get_comment_replies, get_pagination_parameters, ImportBlacklistService log = logging.getLogger(__name__) @@ -1531,10 +1531,10 @@ def photoslug(request, photo_id=None, pseudo_slug=None): next_similar_photo = next_photo compare_photos_url = request.build_absolute_uri( reverse('compare-photos', args=(photo_obj.id, next_similar_photo.id))) - imageSimilarities = ImageSimilarity.objects.filter(from_photo_id=photo_obj.id).exclude(similarity_type=0) - if imageSimilarities.exists(): + image_similarities = ImageSimilarity.objects.filter(from_photo_id=photo_obj.id).exclude(similarity_type=0) + if image_similarities.exists(): compare_photos_url = request.build_absolute_uri( - reverse('compare-photos', args=(photo_obj.id, imageSimilarities.first().to_photo_id))) + reverse('compare-photos', args=(photo_obj.id, image_similarities.first().to_photo_id))) people = [x.name for x in photo_obj.people] similar_photos = ImageSimilarity.objects.filter(from_photo=photo_obj.id).exclude(similarity_type=0) @@ -2336,11 +2336,22 @@ def curator_photo_upload_handler(request): # 15 => unknown copyright unknown_licence = Licence.objects.get(pk=15) flickr_licence = Licence.objects.filter(url='https://www.flickr.com/commons/usage/').first() + import_blacklist_service = ImportBlacklistService() + for k, v in selection.items(): upload_form = CuratorPhotoUploadForm(v) created_album_photo_links = [] awarded_curator_points = [] if upload_form.is_valid(): + source_key = upload_form.cleaned_data['identifyingNumber'] + + if source_key and import_blacklist_service.is_blacklisted(source_key): + context['photos'][k] = { + 'error': _( + f'Could not import picture, as it is blacklisted from being imported: {upload_form.cleaned_data["imageUrl"]}')} + context['photos'][k]['success'] = False + continue + if not upload_form.cleaned_data['institution']: licence = unknown_licence source = Source.objects.get(name='AJP') @@ -2378,7 +2389,7 @@ def curator_photo_upload_handler(request): existing_photo = None if upload_form.cleaned_data['id'] and upload_form.cleaned_data['id'] != '': if upload_form.cleaned_data['collections'] == 'DIGAR': - incoming_muis_id = upload_form.cleaned_data['identifyingNumber'] + incoming_muis_id = source_key else: incoming_muis_id = upload_form.cleaned_data['id'] if 'ETERA' in upload_form.cleaned_data['institution']: @@ -2392,7 +2403,7 @@ def curator_photo_upload_handler(request): muis_id = incoming_muis_id muis_media_id = None if upload_form.cleaned_data['collections'] == 'DIGAR': - upload_form.cleaned_data['identifyingNumber'] = \ + source_key = \ f'nlib-digar:{upload_form.cleaned_data["identifyingNumber"]}' muis_media_id = 1 try: @@ -2422,7 +2433,7 @@ def curator_photo_upload_handler(request): licence=licence, external_id=muis_id, external_sub_id=muis_media_id, - source_key=upload_form.cleaned_data['identifyingNumber'], + source_key=source_key, source_url=upload_form.cleaned_data['urlToRecord'], flip=upload_form.cleaned_data['flip'], invert=upload_form.cleaned_data['invert'], @@ -2605,9 +2616,8 @@ def curator_photo_upload_handler(request): ap.delete() for cp in awarded_curator_points: cp.delete() - context['photos'][k] = {} - context['photos'][k]['error'] = _('Error uploading file: %s (%s)' % - (e, upload_form.cleaned_data['imageUrl'])) + context['photos'][k] = {'error': _('Error uploading file: %s (%s)' % + (e, upload_form.cleaned_data['imageUrl']))} else: if general_albums.exists(): for a in general_albums: @@ -2745,6 +2755,7 @@ def csv_import(request): not_found_list = [] profile = request.get_user().profile skipped_list = [] + blacklisted_list = [] success = None unique_album_list = [] upload_folder = f'{settings.MEDIA_ROOT}/uploads/' @@ -2785,6 +2796,8 @@ def del_evenReadonly(action, name, exc): existing_photos = Photo.objects.filter(image__in=file_list).values_list('image', flat=True) + import_blacklist_service = ImportBlacklistService() + # TODO: map over row fields instead to directly set attributes of photo with setattr # before doing so remove any exceptions like album, source, licence or start using only ids for row in csv.DictReader(decoded_file, delimiter=',', quotechar='"'): @@ -2832,6 +2845,11 @@ def del_evenReadonly(action, name, exc): source = Source.objects.filter(id=row['source']).first() if 'source_key' in row.keys(): source_key = row['source_key'] + + if source_key and import_blacklist_service.is_blacklisted(source_key): + blacklisted_list.append(row['file']) + continue + if 'source_url' in row.keys(): source_url = row['source_url'] if 'date_text' in row.keys(): @@ -2984,6 +3002,9 @@ def del_evenReadonly(action, name, exc): if len(skipped_list) > 0: already_exists_error = "Some imports were skipped since they already exist on Ajapaik:" errors.append({'message': already_exists_error, 'list': list(set(skipped_list))}) + if len(blacklisted_list) > 0: + blacklisted_error = "Some images are blacklisted from Ajapaik, they were not added" + errors.append({'message': blacklisted_error, 'list': list(set(blacklisted_list))}) if len(errors) < 1: success = 'OK' @@ -3306,67 +3327,55 @@ def compare_photos_generic(request, photo_id=None, photo_id_2=None, view='compar } return render(request, 'compare_photos/compare_photos.html', context) -@csrf_exempt + def user_upload(request): context = { 'ajapaik_facebook_link': settings.AJAPAIK_FACEBOOK_LINK, 'is_user_upload': True, 'show_albums_error': False } - if request.method == 'POST': + form = UserPhotoUploadForm(request.POST, request.FILES) albums = request.POST.getlist('albums') - uploaded_images = request.FILES.getlist('images') - - if uploaded_images: - for uploaded_file in uploaded_images: - form = UserPhotoUploadForm(request.POST, request.FILES) - if form.is_valid(): - photo = form.save(commit=False) - photo.user = request.user.profile - if photo.uploader_is_author: - photo.author = request.user.profile.get_display_name() - photo.licence = Licence.objects.get(id=17) # CC BY 4.0 - photo.image = uploaded_file - photo.save() - photo.set_aspect_ratio() - photo.find_similar() - - album_photos = [] - for album_id in albums: - album = Album.objects.filter(id=album_id).first() - if album: - album_photos.append( - AlbumPhoto( - photo=photo, - album=album, - type=AlbumPhoto.UPLOADED, - profile=request.user.profile - ) - ) - AlbumPhoto.objects.bulk_create(album_photos) - - for album_id in albums: - album = Album.objects.filter(id=album_id).first() - if album: - album.set_calculated_fields() - album.light_save() - - photo.add_to_source_album() - + if form.is_valid() and albums is not None and len(albums) > 0: + photo = form.save(commit=False) + photo.user = request.user.profile + if photo.uploader_is_author: + photo.author = request.user.profile.get_display_name + photo.licence = Licence.objects.get(id=17) # CC BY 4.0 + photo.save() + photo.set_aspect_ratio() + photo.find_similar() + albums = request.POST.getlist('albums') + album_photos = [] + for each in albums: + album_photos.append( + AlbumPhoto(photo=photo, + album=Album.objects.filter(id=each).first(), + type=AlbumPhoto.UPLOADED, + profile=request.user.profile + )) + AlbumPhoto.objects.bulk_create(album_photos) + for a in albums: + album = Album.objects.filter(id=a).first() + if album is not None: + album.set_calculated_fields() + album.light_save() + form = UserPhotoUploadForm() + photo.add_to_source_album() if request.POST.get('geotag') == 'true': return redirect(f'{reverse("frontpage_photos")}?photo={str(photo.id)}&locationToolsOpen=1') else: - context['message'] = _('Photos uploaded') - form = UserPhotoUploadForm() # Clear the form for a new upload - else: - context['show_albums_error'] = True # Display error if no images are uploaded + context['message'] = _('Photo uploaded') + if albums is None or len(albums) < 1: + context['show_albums_error'] = True else: form = UserPhotoUploadForm() - context['form'] = form + return render(request, 'user_upload/user_upload.html', context) + def user_upload_add_album(request): context = { 'ajapaik_facebook_link': settings.AJAPAIK_FACEBOOK_LINK @@ -3902,4 +3911,4 @@ class MyConnectionsView(LoginRequiredMixin, ConnectionsView): class MyEmailView(LoginRequiredMixin, EmailView): - success_url = reverse_lazy('user_settings') + success_url = reverse_lazy('user_settings') \ No newline at end of file diff --git a/ajapaik/ajapaik_object_categorization/urls.py b/ajapaik/ajapaik_object_categorization/urls.py index a95d291c1..294b048ee 100644 --- a/ajapaik/ajapaik_object_categorization/urls.py +++ b/ajapaik/ajapaik_object_categorization/urls.py @@ -20,4 +20,4 @@ urlpatterns += [ url(r'^api/v1/annotation/(?P\d+)/$', api.Category.as_view(), name='object_categorization_api_category'), -] \ No newline at end of file +] diff --git a/ajapaik/settings/.DS_Store b/ajapaik/settings/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0