diff --git a/ajapaik/ajapaik/migrations/0026_photomodelsuggestionalternativecategory_photomodelsuggestionresult.py b/ajapaik/ajapaik/migrations/0026_photomodelsuggestionalternativecategory_photomodelsuggestionresult.py deleted file mode 100644 index 79cae98b7..000000000 --- a/ajapaik/ajapaik/migrations/0026_photomodelsuggestionalternativecategory_photomodelsuggestionresult.py +++ /dev/null @@ -1,42 +0,0 @@ -# Generated by Django 3.2.7 on 2023-10-14 14:43 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('ajapaik', '0025_importblacklist'), - ] - - operations = [ - migrations.CreateModel( - name='PhotoModelSuggestionResult', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('created', models.DateTimeField(auto_now_add=True, db_index=True)), - ('viewpoint_elevation', models.PositiveSmallIntegerField(blank=True, choices=[(0, 'Ground'), (1, 'Raised'), (2, 'Aerial')], null=True, verbose_name='Viewpoint elevation')), - ('scene', models.PositiveSmallIntegerField(blank=True, choices=[(0, 'Interior'), (1, 'Exterior')], null=True, verbose_name='Scene')), - ('photo', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ajapaik.photo')), - ], - options={ - 'abstract': False, - }, - ), - migrations.CreateModel( - name='PhotoModelSuggestionAlternativeCategory', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('created', models.DateTimeField(auto_now_add=True, db_index=True)), - ('viewpoint_elevation_alternation', models.PositiveSmallIntegerField(blank=True, choices=[(0, 'Ground'), (1, 'Raised'), (2, 'Aerial')], null=True, verbose_name='Viewpoint elevation')), - ('scene_alternation', models.PositiveSmallIntegerField(blank=True, choices=[(0, 'Interior'), (1, 'Exterior')], null=True, verbose_name='Scene')), - ('photo', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ajapaik.photo')), - ('proposer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='photo_scene_suggestions_alternation', to='ajapaik.profile')), - ], - options={ - 'db_table': 'ajapaik_photomodelsuggestionalternativecategory', - 'unique_together': {('proposer', 'photo_id', 'scene_alternation'), ('proposer', 'photo_id', 'viewpoint_elevation_alternation')}, - }, - ), - ] diff --git a/ajapaik/ajapaik/models.py b/ajapaik/ajapaik/models.py index 30664bf95..2f4d7da2c 100644 --- a/ajapaik/ajapaik/models.py +++ b/ajapaik/ajapaik/models.py @@ -28,7 +28,8 @@ from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.core.files.uploadedfile import InMemoryUploadedFile from django.core.validators import MaxValueValidator, MinValueValidator -from django.db.models import CASCADE, DateField, FileField, Lookup, Transform, OneToOneField, Q, F, Sum, Index +from django.db.models import CASCADE, DateField, FileField, Lookup, Transform, OneToOneField, Q, F, Sum, Index, \ + UniqueConstraint from django.db.models.fields import Field from django.db.models.query import QuerySet from django.db.models.signals import post_save @@ -53,6 +54,18 @@ # https://wiki.postgresql.org/wiki/Count_estimate # https://stackoverflow.com/questions/41467751/how-to-override-queryset-count-method-in-djangos-admin-list +INTERIOR, EXTERIOR = range(2) +GROUND_LEVEL, RAISED, AERIAL = range(3) +SCENE_CHOICES = ( + (INTERIOR, _('Interior')), + (EXTERIOR, _('Exterior')) +) +VIEWPOINT_ELEVATION_CHOICES = ( + (GROUND_LEVEL, _('Ground')), + (RAISED, _('Raised')), + (AERIAL, _('Aerial')) +) + class EstimatedCountQuerySet(QuerySet): # Get count from cache if it is available @@ -638,18 +651,7 @@ class Photo(Model): similar_photos = ManyToManyField('self', through='ImageSimilarity', symmetrical=False) back_of = ForeignKey('self', blank=True, null=True, related_name='back', on_delete=CASCADE) front_of = ForeignKey('self', blank=True, null=True, related_name='front', on_delete=CASCADE) - INTERIOR, EXTERIOR = range(2) - SCENE_CHOICES = ( - (INTERIOR, _('Interior')), - (EXTERIOR, _('Exterior')) - ) scene = PositiveSmallIntegerField(_('Scene'), choices=SCENE_CHOICES, blank=True, null=True) - GROUND_LEVEL, RAISED, AERIAL = range(3) - VIEWPOINT_ELEVATION_CHOICES = ( - (GROUND_LEVEL, _('Ground')), - (RAISED, _('Raised')), - (AERIAL, _('Aerial')) - ) viewpoint_elevation = PositiveSmallIntegerField(_('Viewpoint elevation'), choices=VIEWPOINT_ELEVATION_CHOICES, blank=True, null=True) description_original_language = CharField(_('Description original language'), max_length=255, blank=True, null=True) @@ -2053,85 +2055,51 @@ class Meta: class PhotoSceneSuggestion(Suggestion): - INTERIOR, EXTERIOR = range(2) - SCENE_CHOICES = ( - (INTERIOR, _('Interior')), - (EXTERIOR, _('Exterior')) - ) scene = PositiveSmallIntegerField(_('Scene'), choices=SCENE_CHOICES, blank=True, null=True) proposer = ForeignKey('Profile', blank=True, null=True, related_name='photo_scene_suggestions', on_delete=CASCADE) class PhotoViewpointElevationSuggestion(Suggestion): - GROUND_LEVEL, RAISED, AERIAL = range(3) - VIEWPOINT_ELEVATION_CHOICES = ( - (GROUND_LEVEL, _('Ground')), - (RAISED, _('Raised')), - (AERIAL, _('Aerial')) - ) viewpoint_elevation = PositiveSmallIntegerField(_('Viewpoint elevation'), choices=VIEWPOINT_ELEVATION_CHOICES, blank=True, null=True) proposer = ForeignKey('Profile', blank=True, null=True, related_name='photo_viewpoint_elevation_suggestions', on_delete=CASCADE) class PhotoModelSuggestionResult(Suggestion): - INTERIOR, EXTERIOR = range(2) - GROUND_LEVEL, RAISED, AERIAL = range(3) - SCENE_CHOICES = ( - (INTERIOR, _('Interior')), - (EXTERIOR, _('Exterior')) - ) - VIEWPOINT_ELEVATION_CHOICES = ( - (GROUND_LEVEL, _('Ground')), - (RAISED, _('Raised')), - (AERIAL, _('Aerial')) - ) 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) - SCENE_CHOICES = ( - (INTERIOR, _('Interior')), - (EXTERIOR, _('Exterior')) - ) - VIEWPOINT_ELEVATION_CHOICES = ( - (GROUND_LEVEL, _('Ground')), - (RAISED, _('Raised')), - (AERIAL, _('Aerial')) - ) - viewpoint_elevation_alternation = PositiveSmallIntegerField(_('Viewpoint elevation'), + + viewpoint_elevation = PositiveSmallIntegerField(_('Viewpoint elevation'), choices=VIEWPOINT_ELEVATION_CHOICES, blank=True, null=True) - scene_alternation = PositiveSmallIntegerField(_('Scene'), choices=SCENE_CHOICES, blank=True, null=True) + scene = 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) + class Meta: + constraints = [ + UniqueConstraint( + fields=['proposer', 'viewpoint_elevation'], + condition=Q(scene__isnull=True), + name='unique_proposer_viewpoint_elevation_without_scene' + ), + UniqueConstraint( + fields=['proposer', 'scene'], + condition=Q(viewpoint_elevation__isnull=True), + name='unique_proposer_scene_without_viewpoint_elevation' + ), + ] def validate_unique(self, exclude=None): - # super().validate_unique(exclude) - queryset = self.__class__._default_manager.filter( - Q(scene_alternation=0) | Q(scene_alternation=1), - proposer=self.proposer, - photo_id=self.photo_id - ).exclude(pk=self.pk) - - if self.scene_alternation in ['0', '1'] and queryset.exists(): - return False - return True + super().validate_unique(exclude) def save(self, *args, **kwargs): if self.validate_unique(): super().save(*args, **kwargs) - class Meta: - db_table = 'ajapaik_photomodelsuggestionalternativecategory' - unique_together = (('proposer', 'photo_id', 'scene_alternation'), - ('proposer', 'photo_id', 'viewpoint_elevation_alternation')) - - class PhotoFlipSuggestion(Suggestion): proposer = ForeignKey('Profile', blank=True, null=True, related_name='photo_flip_suggestions', on_delete=CASCADE) flip = BooleanField(null=True) diff --git a/ajapaik/ajapaik/static/js/constants.js b/ajapaik/ajapaik/static/js/constants.js index b35319a7e..d2ceb6e6c 100644 --- a/ajapaik/ajapaik/static/js/constants.js +++ b/ajapaik/ajapaik/static/js/constants.js @@ -81,7 +81,6 @@ var constants = { }, }, queries: { - GET_CATEGORY_FAILED: gettext('Failed to load object category'), POST_CATEGORY_CONFIRMATION_SUCCESS: gettext( 'Successfully posted object category confirmation' ), diff --git a/ajapaik/ajapaik_object_categorization/service/object_categorization/object_categorization_service.py b/ajapaik/ajapaik_object_categorization/service/object_categorization/object_categorization_service.py index 9a51114bf..82e5a362b 100644 --- a/ajapaik/ajapaik_object_categorization/service/object_categorization/object_categorization_service.py +++ b/ajapaik/ajapaik_object_categorization/service/object_categorization/object_categorization_service.py @@ -10,13 +10,11 @@ def get_latest_category_from_result_table(photo_id=None): result = PhotoModelSuggestionResult.objects.filter(photo_id=photo_id).order_by('-created') - result_categories = [] if result.exists(): categories = serializers.serialize('python', result) - result_categories.append(categories) return categories - return result_categories + return [] def get_uncategorized_photos(): diff --git a/ajapaik/ajapaik_object_categorization/views.py b/ajapaik/ajapaik_object_categorization/views.py index 4b08eb710..c48ae3a39 100644 --- a/ajapaik/ajapaik_object_categorization/views.py +++ b/ajapaik/ajapaik_object_categorization/views.py @@ -29,8 +29,8 @@ def propose_alternative_category(request: HttpRequest) -> HttpResponse: return response.not_supported() alternative = PhotoModelSuggestionAlternativeCategory() - alternative.viewpoint_elevation_alternation = request.POST.get("viewpoint_elevation_to_alternate", None) - alternative.scene_alternation = request.POST.get("scene_to_alternate", None) + alternative.viewpoint_elevation = request.POST.get("viewpoint_elevation_to_alternate", None) + alternative.scene = request.POST.get("scene_to_alternate", None) alternative.photo_id = request.POST.get("photo_id", None) alternative.proposer = request.user.profile alternative.save() diff --git a/ajapaik/settings/default.py b/ajapaik/settings/default.py index 03471ba60..37e0a3a66 100644 --- a/ajapaik/settings/default.py +++ b/ajapaik/settings/default.py @@ -399,7 +399,7 @@ ACCOUNT_AUTHENTICATION_METHOD = 'email' ACCOUNT_EMAIL_REQUIRED = True ACCOUNT_UNIQUE_EMAIL = True -ACCOUNT_EMAIL_VERIFICATION = 'none' +ACCOUNT_EMAIL_VERIFICATION = 'mandatory' ACCOUNT_USERNAME_REQUIRED = False ACCOUNT_AUTHENTICATED_LOGIN_REDIRECTS = False SOCIALACCOUNT_EMAIL_VERIFICATION = 'none'