Skip to content

Commit

Permalink
Return an error message when an admin try to remove the admin user gr…
Browse files Browse the repository at this point in the history
…oup from the only admin account of the application
  • Loading branch information
monsieurswag committed Apr 2, 2024
1 parent bcd05c5 commit 27034e5
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 7 deletions.
18 changes: 15 additions & 3 deletions backend/core/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@

from django.db import models

from iam.models import User, RoleAssignment, Folder
from iam.models import User, UserGroup, RoleAssignment, Folder

User = get_user_model()

Expand Down Expand Up @@ -835,10 +835,22 @@ def get_queryset(self):
# TODO: Implement a proper filter for the queryset
return User.objects.all()

def update(self, request: Request, *args, **kwargs) -> Response:
user = self.get_object()
if user.is_admin() :
number_of_admin_users = User.get_admin_users().count()
admin_group = UserGroup.get_admin_group()
if number_of_admin_users == 1 :
new_user_groups = set(request.data["user_groups"])
if str(admin_group.pk) not in new_user_groups :
return Response({"error":"You can't remove the admin user group from the only admin user of the application."},status=HTTP_403_FORBIDDEN)

return super().update(request, *args, **kwargs)

def destroy(self, request, *args, **kwargs):
user = self.get_object()
if user.user_groups.filter(name="BI-UG-ADM").exists() :
number_of_admin_users = User.objects.filter(user_groups__name="BI-UG-ADM").distinct().count()
if user.is_admin() :
number_of_admin_users = User.get_admin_users().count()
if number_of_admin_users == 1 :
return Response({"error":"You can't delete the only admin account of your application."},status=HTTP_403_FORBIDDEN)

Expand Down
12 changes: 10 additions & 2 deletions backend/iam/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Inspired from Azure IAM model """

from collections import defaultdict
from typing import Any, List, Self, Tuple
from typing import Any, List, Self, Tuple, Self
import uuid
from django.utils import timezone
from django.db import models
Expand Down Expand Up @@ -236,6 +236,9 @@ def get_user_groups(user):
user_group_list.append(user_group)
return user_group_list

@staticmethod
def get_admin_group():
return UserGroup.objects.get(name="BI-UG-ADM",builtin=True)

class UserManager(BaseUserManager):
use_in_migrations = True
Expand Down Expand Up @@ -291,7 +294,6 @@ def create_superuser(self, email, password=None, **extra_fields):
UserGroup.objects.get(name="BI-UG-ADM").user_set.add(superuser)
return superuser


class User(AbstractBaseUser, AbstractBaseModel, FolderMixin):
"""a user is a principal corresponding to a human"""

Expand Down Expand Up @@ -471,6 +473,12 @@ def permissions(self):
def set_username(self, username):
self.email = username

@staticmethod
def get_admin_users() -> List[Self] :
return User.objects.filter(user_groups__name="BI-UG-ADM",user_groups__builtin=True)

def is_admin(self) -> bool :
return self.user_groups.filter(name="BI-UG-ADM",builtin=True).exists()

class Role(NameDescriptionMixin, FolderMixin):
"""A role is a list of permissions"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ export const actions: Actions = {
if (!res.ok) {
const response = await res.json();
console.error('server response:', response);
if (response.error) {
setFlash({ type: 'error', message: response.error }, event);
return fail(403, { form: form });
}
if (response.non_field_errors) {
setError(form, 'non_field_errors', response.non_field_errors);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { BASE_API_URL } from '$lib/utils/constants';
import { UserEditSchema } from '$lib/utils/schemas';
import { setError, superValidate } from 'sveltekit-superforms/server';
import type { PageServerLoad } from './$types';
import { redirect, type Actions } from '@sveltejs/kit';
import { fail } from 'assert';
import { redirect, fail, type Actions } from '@sveltejs/kit';
import { getModelInfo } from '$lib/utils/crud';
import { setFlash } from 'sveltekit-flash-message/server';
import * as m from '$paraglide/messages';
Expand Down Expand Up @@ -58,6 +57,10 @@ export const actions: Actions = {
if (!res.ok) {
const response = await res.json();
console.error('server response:', response);
if (response.error) {
setFlash({ type: 'error', message: response.error }, event);
return fail(403, { form: form });
}
if (response.non_field_errors) {
setError(form, 'non_field_errors', response.non_field_errors);
}
Expand Down

0 comments on commit 27034e5

Please sign in to comment.