Loading trapper/pyproject.toml +1 −1 Original line number Diff line number Diff line Loading @@ -51,7 +51,7 @@ dependencies = [ "rest-pandas==1.1.0", "sentry-sdk>=1.15,<1.16", "azure-storage-blob==1.5.0", "django-polymorphic==3.1.0", "django-polymorphic>=3.1.0", "dacite==1.6.0", "frictionless[parquet]==5.18.1", "boto3==1.26.95", Loading trapper/trapper-project/conf/settings/base.py +2 −3 Original line number Diff line number Diff line Loading @@ -699,9 +699,8 @@ NOCAPTCHA = True # Django allauth settings ACCOUNT_ADAPTER = "trapper.apps.accounts.adapters.TrapperAdapter" ACCOUNT_USERNAME_REQUIRED = False ACCOUNT_AUTHENTICATION_METHOD = "email" ACCOUNT_EMAIL_REQUIRED = True ACCOUNT_LOGIN_METHODS = {"email"} ACCOUNT_SIGNUP_FIELDS = ["email*", "password1*", "password2*"] ACCOUNT_SESSION_REMEMBER = False ACCOUNT_EMAIL_VERIFICATION = "none" ACCOUNT_LOGOUT_ON_GET = True Loading trapper/trapper-project/trapper/apps/accounts/admin.py +13 −1 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ from trapper.apps.accounts.models import ( UserRemoteTask, UserDataPackage, UserFTPAccount, UserHttpUploaderAccount, ) from trapper.apps.media_classification.models import ( ClassificationProjectRole, Loading Loading @@ -348,7 +349,7 @@ class TrapperUserAdmin(UserAdmin): n_users = len(queryset) for user in queryset: try: user.userftpaccount.delete() user.ftp_account.delete() except ObjectDoesNotExist: pass user.userprofile.has_ftp_account = False Loading Loading @@ -487,6 +488,17 @@ class UserFTPAccountAdmin(admin.ModelAdmin): ] @admin.register(UserHttpUploaderAccount) class UserHttpUploaderAccountAdmin(admin.ModelAdmin): list_display = ("user", "quota_files", "quota_size", "created_at", "updated_at") search_fields = ("user__username", "user__email") readonly_fields = [ "created_at", "updated_at", ] raw_id_fields = ("user",) admin.site.register(User, TrapperUserAdmin) admin.site.register(UserProfile) admin.site.register(UserTask) Loading trapper/trapper-project/trapper/apps/accounts/migrations/0028_alter_userftpaccount_quota_files_and_more.py 0 → 100644 +45 −0 Original line number Diff line number Diff line # Generated by Django 4.2.17 on 2025-10-13 17:22 from django.conf import settings from django.db import migrations, models import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ ('accounts', '0027_userprofile_demo_alter_userprofile_timezone'), ] operations = [ migrations.AlterField( model_name='userftpaccount', name='quota_files', field=models.IntegerField(default=0, help_text='Max number of files user can upload'), ), migrations.AlterField( model_name='userftpaccount', name='quota_size', field=models.BigIntegerField(default=0, help_text='Max size (in bytes) user can upload'), ), migrations.AlterField( model_name='userftpaccount', name='user', field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='ftp_account', to=settings.AUTH_USER_MODEL), ), migrations.CreateModel( name='UserHttpUploaderAccount', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('quota_files', models.IntegerField(default=0, help_text='Max number of files user can upload')), ('quota_size', models.BigIntegerField(default=0, help_text='Max size (in bytes) user can upload')), ('created_at', models.DateTimeField(auto_now_add=True)), ('updated_at', models.DateTimeField(auto_now=True)), ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='http_uploader_account', to=settings.AUTH_USER_MODEL)), ], options={ 'verbose_name': 'User HTTP uploader account', 'verbose_name_plural': 'User HTTP uploader accounts', }, ), ] trapper/trapper-project/trapper/apps/accounts/models.py +30 −6 Original line number Diff line number Diff line Loading @@ -142,8 +142,8 @@ class User(AbstractUser): # Delete user avatar and user FTP access user_profile.avatar.delete() if hasattr(user, "userftpaccount"): user.userftpaccount.delete() if hasattr(user, "ftp_account"): user.ftp_account.delete() # Delete user historical tasks, data packages and team memberships user.userremotetask_set.all().delete() Loading Loading @@ -454,14 +454,20 @@ def submission_delete(sender, instance, **kwargs): class UserFTPAccount(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) user = models.OneToOneField( User, on_delete=models.CASCADE, related_name="ftp_account" ) username = models.CharField(max_length=255, unique=True) password = models.CharField(max_length=255) uid = models.SmallIntegerField(default=-1) gid = models.SmallIntegerField(default=-1) dir = models.CharField(max_length=255) quota_files = models.IntegerField(default=-1) quota_size = models.BigIntegerField(default=-1) quota_files = models.IntegerField( default=0, help_text=_("Max number of files user can upload") ) quota_size = models.BigIntegerField( default=0, help_text=_("Max size (in bytes) user can upload") ) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) Loading @@ -470,7 +476,25 @@ class UserFTPAccount(models.Model): verbose_name_plural = _("User FTP accounts") # Automatically mark citizen sciene useres as demo when DEMO_MODE is active. class UserHttpUploaderAccount(models.Model): user = models.OneToOneField( User, on_delete=models.CASCADE, related_name="http_uploader_account" ) quota_files = models.IntegerField( default=0, help_text=_("Max number of files user can upload") ) quota_size = models.BigIntegerField( default=0, help_text=_("Max size (in bytes) user can upload") ) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: verbose_name = _("User HTTP uploader account") verbose_name_plural = _("User HTTP uploader accounts") # Automatically mark citizen science users as demo when DEMO_MODE is active. @receiver(post_save, sender=UserProfile) def ensure_demo_flag(sender, instance, created, **kwargs): """ Loading Loading
trapper/pyproject.toml +1 −1 Original line number Diff line number Diff line Loading @@ -51,7 +51,7 @@ dependencies = [ "rest-pandas==1.1.0", "sentry-sdk>=1.15,<1.16", "azure-storage-blob==1.5.0", "django-polymorphic==3.1.0", "django-polymorphic>=3.1.0", "dacite==1.6.0", "frictionless[parquet]==5.18.1", "boto3==1.26.95", Loading
trapper/trapper-project/conf/settings/base.py +2 −3 Original line number Diff line number Diff line Loading @@ -699,9 +699,8 @@ NOCAPTCHA = True # Django allauth settings ACCOUNT_ADAPTER = "trapper.apps.accounts.adapters.TrapperAdapter" ACCOUNT_USERNAME_REQUIRED = False ACCOUNT_AUTHENTICATION_METHOD = "email" ACCOUNT_EMAIL_REQUIRED = True ACCOUNT_LOGIN_METHODS = {"email"} ACCOUNT_SIGNUP_FIELDS = ["email*", "password1*", "password2*"] ACCOUNT_SESSION_REMEMBER = False ACCOUNT_EMAIL_VERIFICATION = "none" ACCOUNT_LOGOUT_ON_GET = True Loading
trapper/trapper-project/trapper/apps/accounts/admin.py +13 −1 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ from trapper.apps.accounts.models import ( UserRemoteTask, UserDataPackage, UserFTPAccount, UserHttpUploaderAccount, ) from trapper.apps.media_classification.models import ( ClassificationProjectRole, Loading Loading @@ -348,7 +349,7 @@ class TrapperUserAdmin(UserAdmin): n_users = len(queryset) for user in queryset: try: user.userftpaccount.delete() user.ftp_account.delete() except ObjectDoesNotExist: pass user.userprofile.has_ftp_account = False Loading Loading @@ -487,6 +488,17 @@ class UserFTPAccountAdmin(admin.ModelAdmin): ] @admin.register(UserHttpUploaderAccount) class UserHttpUploaderAccountAdmin(admin.ModelAdmin): list_display = ("user", "quota_files", "quota_size", "created_at", "updated_at") search_fields = ("user__username", "user__email") readonly_fields = [ "created_at", "updated_at", ] raw_id_fields = ("user",) admin.site.register(User, TrapperUserAdmin) admin.site.register(UserProfile) admin.site.register(UserTask) Loading
trapper/trapper-project/trapper/apps/accounts/migrations/0028_alter_userftpaccount_quota_files_and_more.py 0 → 100644 +45 −0 Original line number Diff line number Diff line # Generated by Django 4.2.17 on 2025-10-13 17:22 from django.conf import settings from django.db import migrations, models import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ ('accounts', '0027_userprofile_demo_alter_userprofile_timezone'), ] operations = [ migrations.AlterField( model_name='userftpaccount', name='quota_files', field=models.IntegerField(default=0, help_text='Max number of files user can upload'), ), migrations.AlterField( model_name='userftpaccount', name='quota_size', field=models.BigIntegerField(default=0, help_text='Max size (in bytes) user can upload'), ), migrations.AlterField( model_name='userftpaccount', name='user', field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='ftp_account', to=settings.AUTH_USER_MODEL), ), migrations.CreateModel( name='UserHttpUploaderAccount', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('quota_files', models.IntegerField(default=0, help_text='Max number of files user can upload')), ('quota_size', models.BigIntegerField(default=0, help_text='Max size (in bytes) user can upload')), ('created_at', models.DateTimeField(auto_now_add=True)), ('updated_at', models.DateTimeField(auto_now=True)), ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='http_uploader_account', to=settings.AUTH_USER_MODEL)), ], options={ 'verbose_name': 'User HTTP uploader account', 'verbose_name_plural': 'User HTTP uploader accounts', }, ), ]
trapper/trapper-project/trapper/apps/accounts/models.py +30 −6 Original line number Diff line number Diff line Loading @@ -142,8 +142,8 @@ class User(AbstractUser): # Delete user avatar and user FTP access user_profile.avatar.delete() if hasattr(user, "userftpaccount"): user.userftpaccount.delete() if hasattr(user, "ftp_account"): user.ftp_account.delete() # Delete user historical tasks, data packages and team memberships user.userremotetask_set.all().delete() Loading Loading @@ -454,14 +454,20 @@ def submission_delete(sender, instance, **kwargs): class UserFTPAccount(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) user = models.OneToOneField( User, on_delete=models.CASCADE, related_name="ftp_account" ) username = models.CharField(max_length=255, unique=True) password = models.CharField(max_length=255) uid = models.SmallIntegerField(default=-1) gid = models.SmallIntegerField(default=-1) dir = models.CharField(max_length=255) quota_files = models.IntegerField(default=-1) quota_size = models.BigIntegerField(default=-1) quota_files = models.IntegerField( default=0, help_text=_("Max number of files user can upload") ) quota_size = models.BigIntegerField( default=0, help_text=_("Max size (in bytes) user can upload") ) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) Loading @@ -470,7 +476,25 @@ class UserFTPAccount(models.Model): verbose_name_plural = _("User FTP accounts") # Automatically mark citizen sciene useres as demo when DEMO_MODE is active. class UserHttpUploaderAccount(models.Model): user = models.OneToOneField( User, on_delete=models.CASCADE, related_name="http_uploader_account" ) quota_files = models.IntegerField( default=0, help_text=_("Max number of files user can upload") ) quota_size = models.BigIntegerField( default=0, help_text=_("Max size (in bytes) user can upload") ) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: verbose_name = _("User HTTP uploader account") verbose_name_plural = _("User HTTP uploader accounts") # Automatically mark citizen science users as demo when DEMO_MODE is active. @receiver(post_save, sender=UserProfile) def ensure_demo_flag(sender, instance, created, **kwargs): """ Loading