Skip to content
21 changes: 15 additions & 6 deletions app/access/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,19 @@

@admin.register(User)
class UserAdmin(admin.ModelAdmin): # type:ignore[type-arg]
'''Admin View for User'''
"""Admin View for User"""

list_display = ('user_id', 'username', 'last_name', 'first_name', 'deleted_at', 'provider')
list_filter = ('deleted_at', ('provider', admin.RelatedOnlyFieldListFilter))
readonly_fields = ('user_id', 'deleted_at', 'created', 'updated')
actions = ('disable',)
list_display = (
"user_id",
"username",
"last_name",
"first_name",
"deleted_at",
"provider",
)
list_filter = ("deleted_at", ("provider", admin.RelatedOnlyFieldListFilter))
readonly_fields = ("user_id", "deleted_at", "created", "updated")
actions = ("disable",)

@admin.action(description="Disable selected users")
def disable(self, request: HttpRequest, queryset: models.QuerySet[User]) -> None:
Expand All @@ -22,6 +29,8 @@ def disable(self, request: HttpRequest, queryset: models.QuerySet[User]) -> None
def get_queryset(self, request: HttpRequest) -> models.QuerySet[User]:
return User.all_objects.get_queryset()

def delete_queryset(self, request: HttpRequest, queryset: models.QuerySet[User]) -> None:
def delete_queryset(
self, request: HttpRequest, queryset: models.QuerySet[User]
) -> None:
for user in queryset:
user.delete()
14 changes: 8 additions & 6 deletions app/access/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def user_to_response(model: User) -> UserSchema:
"users/{username}",
response={200: UserSchema},
exclude_none=True,
auth=PermissionAuth('access.view_user')
auth=PermissionAuth("access.view_user"),
)
def user(request: HttpRequest, username: str) -> UserSchema:
"""
Expand All @@ -49,7 +49,7 @@ def user(request: HttpRequest, username: str) -> UserSchema:
"users",
response={200: UserListSchema},
exclude_none=True,
auth=PermissionAuth('access.view_user')
auth=PermissionAuth("access.view_user"),
)
def users(request: HttpRequest) -> dict[str, list[UserSchema]]:
"""
Expand All @@ -60,7 +60,9 @@ def users(request: HttpRequest) -> dict[str, list[UserSchema]]:
return {"items": responses}


@router.post("users", response={201: UserSchema}, auth=PermissionAuth('access.add_user'))
@router.post(
"users", response={201: UserSchema}, auth=PermissionAuth("access.add_user")
)
def create(request: HttpRequest, user_in: UserSchema) -> UserSchema:
"""Create the given user and return it.

Expand All @@ -80,12 +82,12 @@ def create(request: HttpRequest, user_in: UserSchema) -> UserSchema:
first_name=user_in.first_name,
last_name=user_in.last_name,
email=user_in.email,
provider=provider
provider=provider,
)
return user_to_response(user_out)


@router.delete("users/{username}", auth=PermissionAuth('access.delete_user'))
@router.delete("users/{username}", auth=PermissionAuth("access.delete_user"))
def delete(request: HttpRequest, username: str) -> HttpResponse:
"""
Delete the user with the given username.
Expand All @@ -101,7 +103,7 @@ def delete(request: HttpRequest, username: str) -> HttpResponse:
return HttpResponse(status=204)


@router.put("users/{username}", auth=PermissionAuth('access.change_user'))
@router.put("users/{username}", auth=PermissionAuth("access.change_user"))
def update_user(
request: HttpRequest, username: str, user_in: UserSchema
) -> HttpResponse | UserSchema:
Expand Down
4 changes: 2 additions & 2 deletions app/access/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@


class AccessConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'access'
default_auto_field = "django.db.models.BigAutoField"
name = "access"
32 changes: 19 additions & 13 deletions app/access/migrations/0001_initial.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,38 @@


class Migration(migrations.Migration):

initial = True

dependencies = [
('provider', '0006_alter_provider_acronym_it_alter_provider_acronym_rm_and_more'),
(
"provider",
"0006_alter_provider_acronym_it_alter_provider_acronym_rm_and_more",
),
]

operations = [
migrations.CreateModel(
name='User',
name="User",
fields=[
(
'id',
"id",
models.BigAutoField(
auto_created=True, primary_key=True, serialize=False, verbose_name='ID'
)
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
('username', models.CharField(unique=True, verbose_name='User name')),
('first_name', models.CharField(verbose_name='First name')),
('last_name', models.CharField(verbose_name='Last name')),
('email', models.EmailField(max_length=254, verbose_name='Email')),
("username", models.CharField(unique=True, verbose_name="User name")),
("first_name", models.CharField(verbose_name="First name")),
("last_name", models.CharField(verbose_name="Last name")),
("email", models.EmailField(max_length=254, verbose_name="Email")),
(
'provider',
"provider",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to='provider.provider'
)
on_delete=django.db.models.deletion.CASCADE,
to="provider.provider",
),
),
],
),
Expand Down
11 changes: 6 additions & 5 deletions app/access/migrations/0002_user_deleted_at.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@


class Migration(migrations.Migration):

dependencies = [
('access', '0001_initial'),
("access", "0001_initial"),
]

operations = [
migrations.AddField(
model_name='user',
name='deleted_at',
field=models.DateTimeField(blank=True, null=True, verbose_name='deleted at'),
model_name="user",
name="deleted_at",
field=models.DateTimeField(
blank=True, null=True, verbose_name="deleted at"
),
),
]
21 changes: 12 additions & 9 deletions app/access/migrations/0003_user_user_id.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,31 @@


def populate_user_id(apps: Apps, schema_editor: BaseDatabaseSchemaEditor) -> None:
User = apps.get_model('access', 'User')
User = apps.get_model("access", "User")
for obj in User.objects.all():
obj.user_id = generate_short_id()
obj.save()


class Migration(migrations.Migration):

dependencies = [
('access', '0002_user_deleted_at'),
("access", "0002_user_deleted_at"),
]

operations = [
migrations.AddField(
model_name='user',
name='user_id',
field=models.CharField(default=generate_short_id, null=True, verbose_name='User ID'),
model_name="user",
name="user_id",
field=models.CharField(
default=generate_short_id, null=True, verbose_name="User ID"
),
),
migrations.RunPython(populate_user_id, migrations.RunPython.noop),
migrations.AlterField(
model_name='user',
name='user_id',
field=models.CharField(default=generate_short_id, unique=True, verbose_name='User ID'),
model_name="user",
name="user_id",
field=models.CharField(
default=generate_short_id, unique=True, verbose_name="User ID"
),
),
]
9 changes: 4 additions & 5 deletions app/access/migrations/0004_alter_user_username.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,16 @@


class Migration(migrations.Migration):

dependencies = [
('access', '0003_user_user_id'),
("access", "0003_user_user_id"),
]

operations = [
migrations.AlterField(
model_name='user',
name='username',
model_name="user",
name="username",
field=utils.fields.CustomSlugField(
max_length=100, unique=True, verbose_name='User name'
max_length=100, unique=True, verbose_name="User name"
),
),
]
17 changes: 9 additions & 8 deletions app/access/migrations/0005_user_created_user_updated.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,24 @@


class Migration(migrations.Migration):

dependencies = [
('access', '0004_alter_user_username'),
("access", "0004_alter_user_username"),
]

operations = [
migrations.AddField(
model_name='user',
name='created',
model_name="user",
name="created",
field=models.DateTimeField(
auto_now_add=True, default=django.utils.timezone.now, verbose_name='Created'
auto_now_add=True,
default=django.utils.timezone.now,
verbose_name="Created",
),
preserve_default=False,
),
migrations.AddField(
model_name='user',
name='updated',
field=models.DateTimeField(auto_now=True, verbose_name='Updated'),
model_name="user",
name="updated",
field=models.DateTimeField(auto_now=True, verbose_name="Updated"),
),
]
38 changes: 26 additions & 12 deletions app/access/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@


class CognitoInconsistencyError(Exception):
""" An exception indicating that the state in the database and state in cognito have
"""An exception indicating that the state in the database and state in cognito have
diverged.
"""

Expand Down Expand Up @@ -46,7 +46,9 @@ def __str__(self) -> str:
return str(self.username)

username = CustomSlugField(_(_context, "User name"), unique=True, max_length=100)
user_id = models.CharField(_(_context, "User ID"), unique=True, default=generate_short_id)
user_id = models.CharField(
_(_context, "User ID"), unique=True, default=generate_short_id
)
created = models.DateTimeField(_(_context, "Created"), auto_now_add=True)
updated = models.DateTimeField(_(_context, "Updated"), auto_now=True)
first_name = models.CharField(_(_context, "First name"))
Expand All @@ -70,36 +72,46 @@ def save(
force_insert: bool | tuple[ModelBase, ...] = False,
force_update: bool = False,
using: str | None = None,
update_fields: Iterable[str] | None = None
update_fields: Iterable[str] | None = None,
) -> None:
"""Validates the model before writing it to the database and syncs with cognito."""

self.full_clean()
client = Client()
with transaction.atomic():
if self._state.adding:
super().save(force_insert=True, using=using, update_fields=update_fields)
super().save(
force_insert=True, using=using, update_fields=update_fields
)
if not client.create_user(self.user_id, self.username, self.email):
logger.critical("User %s already exists in cognito, not created", self.user_id)
logger.critical(
"User %s already exists in cognito, not created", self.user_id
)
raise CognitoInconsistencyError()
else:
User.all_objects.select_for_update().filter(pk=self.pk).get()
super().save(force_update=True, using=using, update_fields=update_fields)
super().save(
force_update=True, using=using, update_fields=update_fields
)
if not client.update_user(self.user_id, self.username, self.email):
logger.critical("User %s does not exist in cognito, not updated", self.user_id)
logger.critical(
"User %s does not exist in cognito, not updated", self.user_id
)
raise CognitoInconsistencyError()

def delete(self,
using: str | None = None,
keep_parents: bool = False) -> tuple[int, dict[str, int]]:
def delete(
self, using: str | None = None, keep_parents: bool = False
) -> tuple[int, dict[str, int]]:
"""Deletes the user from the database and cognito."""

client = Client()
with transaction.atomic():
User.all_objects.select_for_update().filter(pk=self.pk).get()
result = super().delete(using=using, keep_parents=keep_parents)
if not client.delete_user(self.user_id):
logger.critical("User %s does not exist in cognito, not deleted", self.user_id)
logger.critical(
"User %s does not exist in cognito, not deleted", self.user_id
)
raise CognitoInconsistencyError()
return result

Expand All @@ -113,5 +125,7 @@ def disable(self) -> None:
self.deleted_at = timezone.now()
super().save(force_update=True)
if not client.disable_user(self.user_id):
logger.critical("User %s does not exist in cognito, not disabled", self.user_id)
logger.critical(
"User %s does not exist in cognito, not disabled", self.user_id
)
raise CognitoInconsistencyError()
1 change: 0 additions & 1 deletion app/access/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@


class UserSchema(Schema):

username: str
first_name: str
last_name: str
Expand Down
4 changes: 2 additions & 2 deletions app/bod/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@


class BodConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'bod'
default_auto_field = "django.db.models.BigAutoField"
name = "bod"
Loading
Loading