Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Return an error message when an admin try to delete the only admin account #192

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion 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,6 +835,26 @@ 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.objects.get(name="BI-UG-ADM")
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":"attemptToRemoveOnlyAdminUserGroup"},status=HTTP_403_FORBIDDEN)

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

def destroy(self, request, *args, **kwargs):
user = self.get_object()
if user.is_admin() :
number_of_admin_users = User.get_admin_users().count()
if number_of_admin_users == 1 :
return Response({"error":"attemptToDeleteOnlyAdminAccountError"},status=HTTP_403_FORBIDDEN)

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

class UserGroupViewSet(BaseModelViewSet):
"""
Expand Down
8 changes: 6 additions & 2 deletions backend/iam/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,6 @@ def get_user_groups(user):
user_group_list.append(user_group)
return user_group_list


class UserManager(BaseUserManager):
use_in_migrations = True

Expand Down Expand Up @@ -291,7 +290,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 +469,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")

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

class Role(NameDescriptionMixin, FolderMixin):
"""A role is a list of permissions"""
Expand Down
4 changes: 3 additions & 1 deletion frontend/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -492,5 +492,7 @@
"invalidLibraryFileError": "Invalid library file. Please make sure the format is correct.",
"taintedFormMessage": "Do you want to leave this page? Changes you made may not be saved.",
"riskScenariosStatus": "Risk scenarios status",
"onlineDocs": "Online documentation"
"onlineDocs": "Online documentation",
"attemptToDeleteOnlyAdminAccountError": "You can't delete the only admin account of your application.",
"attemptToRemoveOnlyAdminUserGroup": "You can't remove the only admin user of the application from the admin user group."
}
4 changes: 3 additions & 1 deletion frontend/messages/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -492,5 +492,7 @@
"invalidLibraryFileError": "Fichier de bibliothèque invalide. Veuillez vérifier le format du fichier.",
"taintedFormMessage": "Voulez-vous vraiment quitter cette page ? Toutes les données non enregistrées seront perdues.",
"riskScenariosStatus": "Statut des scénarios de risque",
"onlineDocs": "Documentation en ligne"
"onlineDocs": "Documentation en ligne",
"attemptToDeleteOnlyAdminAccountError": "Vous ne pouvez pas supprimer votre unique compte administrateur de l'application.",
"attemptToRemoveOnlyAdminUserGroup": "Vous ne pouvez pas retirer le seul compte administrateur de l'application du groupe des administrateurs."
}
4 changes: 3 additions & 1 deletion frontend/src/lib/utils/locales.ts
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,9 @@ export function localItems(languageTag: string): LocalItems {
highSOK: m.highSOK({ languageTag: languageTag }),
libraryImportError: m.libraryImportError({ languageTag: languageTag }),
libraryAlreadyExistsError: m.libraryAlreadyImportedError({ languageTag: languageTag }),
invalidLibraryFileError: m.invalidLibraryFileError({ languageTag: languageTag })
invalidLibraryFileError: m.invalidLibraryFileError({ languageTag: languageTag }),
attemptToDeleteOnlyAdminAccountError: m.attemptToDeleteOnlyAdminAccountError({ languageTag: languageTag }),
attemptToRemoveOnlyAdminUserGroup: m.attemptToRemoveOnlyAdminUserGroup({ languageTag: languageTag })
};
return LOCAL_ITEMS;
}
4 changes: 4 additions & 0 deletions frontend/src/routes/(app)/[model=urlmodel]/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,10 @@ export const actions: Actions = {
if (!res.ok) {
const response = await res.json();
console.log(response);
if (response.error) {
setFlash({ type: 'error', message: localItems(languageTag())[response.error] }, event);
return fail(403, { form: deleteForm });
}
if (response.non_field_errors) {
setError(deleteForm, 'non_field_errors', response.non_field_errors);
}
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,11 +2,12 @@ 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';
import { languageTag } from '$paraglide/runtime';
import { localItems } from '$lib/utils/locales';

export const load: PageServerLoad = async ({ params, fetch }) => {
const URLModel = 'users';
Expand Down Expand Up @@ -58,6 +59,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: localItems(languageTag())[response.error] }, event);
return fail(403, { form: form });
}
if (response.non_field_errors) {
setError(form, 'non_field_errors', response.non_field_errors);
}
Expand Down
Loading