fix(users): refactor user admin actions to return status objects instead of throwing to prevent production error obfuscation
All checks were successful
Staging Build / build (push) Successful in 3m29s

This commit is contained in:
DanielS
2026-07-03 13:51:00 +02:00
parent 12d06e46ad
commit 38651037bc
3 changed files with 154 additions and 94 deletions

View File

@@ -96,12 +96,17 @@ export function UserDialog({ companies }: UserDialogProps) {
first_name: values.first_name || undefined,
last_name: values.last_name || undefined,
}
await createUser(payload)
const res = await createUser(payload)
if (res.success) {
setOpen(false)
form.reset()
router.refresh()
} else {
alert(res.error || 'Fehler beim Erstellen des Benutzers.')
}
} catch (error) {
console.error('Error creating user:', error)
alert('Ein unerwarteter Fehler ist aufgetreten.')
}
}

View File

@@ -63,17 +63,22 @@ export function UserList({ initialUsers, companies }: UserListProps) {
if (confirm('Möchten Sie diesen Benutzer wirklich löschen?')) {
setLoadingId(id)
try {
await deleteUser(id)
const res = await deleteUser(id)
if (res.success) {
router.refresh()
} catch (e: any) {
console.error('Fehler beim Löschen des Benutzers:', e)
if (e.message?.includes('Belege')) {
} else {
console.error('Fehler beim Löschen des Benutzers:', res.error)
if (res.error?.includes('Belege')) {
if (confirm('Löschen nicht möglich! Auf diesen User existieren bereits Belege. Möchten Sie diesen Benutzer stattdessen sperren?')) {
await handleRoleChange(id, 'gesperrt')
}
} else {
alert('Fehler beim Löschen: ' + (e.message || JSON.stringify(e)))
alert('Fehler beim Löschen: ' + res.error)
}
}
} catch (e: any) {
console.error('Fehler beim Löschen des Benutzers:', e)
alert('Fehler beim Löschen: ' + (e.message || JSON.stringify(e)))
} finally {
setLoadingId(null)
}
@@ -83,10 +88,15 @@ export function UserList({ initialUsers, companies }: UserListProps) {
const handleRoleChange = async (id: string, newRole: Role) => {
setLoadingId(id + '-role')
try {
await updateUserRole(id, newRole)
const res = await updateUserRole(id, newRole)
if (res.success) {
router.refresh()
} catch (e) {
} else {
alert(res.error || 'Fehler beim Ändern der Rolle.')
}
} catch (e: any) {
console.error('Fehler beim Ändern der Rolle:', e)
alert('Fehler beim Ändern der Rolle: ' + (e.message || JSON.stringify(e)))
} finally {
setLoadingId(null)
}
@@ -96,10 +106,15 @@ export function UserList({ initialUsers, companies }: UserListProps) {
const newRole = currentRole === 'gesperrt' ? 'partner' : 'gesperrt'
setLoadingId(id + '-lock')
try {
await updateUserRole(id, newRole)
const res = await updateUserRole(id, newRole)
if (res.success) {
router.refresh()
} catch (e) {
} else {
alert(res.error || 'Fehler beim Sperren/Entsperren.')
}
} catch (e: any) {
console.error('Fehler beim Sperren/Entsperren:', e)
alert('Fehler beim Sperren/Entsperren: ' + (e.message || JSON.stringify(e)))
} finally {
setLoadingId(null)
}
@@ -241,10 +256,15 @@ export function UserList({ initialUsers, companies }: UserListProps) {
const val = e.target.value.trim()
if (val !== (user.first_name || '')) {
try {
await updateUserProfile(user.id, { first_name: val || null, last_name: user.last_name })
const res = await updateUserProfile(user.id, { first_name: val || null, last_name: user.last_name })
if (res.success) {
router.refresh()
} catch (err) {
} else {
alert(res.error || 'Fehler beim Aktualisieren des Vornamens.')
}
} catch (err: any) {
console.error('Failed to update first name:', err)
alert('Fehler beim Aktualisieren des Vornamens: ' + (err.message || JSON.stringify(err)))
}
}
}}
@@ -263,10 +283,15 @@ export function UserList({ initialUsers, companies }: UserListProps) {
const val = e.target.value.trim()
if (val !== (user.last_name || '')) {
try {
await updateUserProfile(user.id, { first_name: user.first_name, last_name: val || null })
const res = await updateUserProfile(user.id, { first_name: user.first_name, last_name: val || null })
if (res.success) {
router.refresh()
} catch (err) {
} else {
alert(res.error || 'Fehler beim Aktualisieren des Nachnamens.')
}
} catch (err: any) {
console.error('Failed to update last name:', err)
alert('Fehler beim Aktualisieren des Nachnamens: ' + (err.message || JSON.stringify(err)))
}
}
}}

View File

@@ -50,20 +50,27 @@ export async function getUsers() {
}
export async function createUser(data: { email: string; role?: 'admin' | 'partner' | 'verwaltung'; email_confirm?: boolean; company_id?: string; first_name?: string; last_name?: string }) {
try {
const admin = createAdminClient();
const { data: { user }, error } = await admin.auth.admin.createUser({
email: data.email,
password: Math.random().toString(36).slice(-10) + Math.random().toString(36).slice(-10),
email_confirm: data.email_confirm ?? true,
});
if (error) throw error;
if (!user) throw new Error('Benutzer konnte nicht erstellt werden.');
if (error) {
return { success: false, error: error.message };
}
if (!user) {
return { success: false, error: 'Benutzer konnte nicht erstellt werden.' };
}
const role = data.role || 'partner';
const { error: dbError } = await admin
.from('users')
.upsert({ id: user.id, role, company_id: data.company_id || null }, { onConflict: 'id' });
if (dbError) throw dbError;
if (dbError) {
return { success: false, error: dbError.message };
}
const { error: profileError } = await admin
.from('profiles')
@@ -72,7 +79,9 @@ export async function createUser(data: { email: string; role?: 'admin' | 'partne
first_name: data.first_name || null,
last_name: data.last_name || null,
}, { onConflict: 'id' });
if (profileError) throw profileError;
if (profileError) {
return { success: false, error: profileError.message };
}
// Generate recovery link to let user set password
try {
@@ -107,7 +116,11 @@ export async function createUser(data: { email: string; role?: 'admin' | 'partne
}
revalidatePath('/admin/users');
return user;
return { success: true, user };
} catch (err: any) {
console.error('Error creating user in action:', err);
return { success: false, error: err.message || 'Ein unerwarteter Fehler ist aufgetreten.' };
}
}
export async function deleteUser(id: string) {
@@ -125,35 +138,44 @@ export async function deleteUser(id: string) {
}
if (count && count > 0) {
throw new Error('Auf diesen User gibt es bereits Belege. Sperren möglich.');
return { success: false, error: 'Auf diesen User gibt es bereits Belege. Sperren möglich.' };
}
// Delete from public.users first to satisfy foreign key constraints
const { error: dbError } = await admin.from('users').delete().eq('id', id);
if (dbError) {
console.error('Database delete user error:', dbError);
throw new Error(`Datenbank-Fehler beim Löschen des Benutzers: ${dbError.message}`);
return { success: false, error: `Datenbank-Fehler beim Löschen des Benutzers: ${dbError.message}` };
}
const { error } = await admin.auth.admin.deleteUser(id);
if (error) {
console.error('Auth delete user error:', error);
throw new Error(`Auth-Fehler beim Löschen des Benutzers: ${error.message}`);
return { success: false, error: `Auth-Fehler beim Löschen des Benutzers: ${error.message}` };
}
revalidatePath('/admin/users');
return { success: true };
} catch (err: any) {
console.error('deleteUser Server Action failed:', err);
throw new Error(err.message || 'Benutzer konnte nicht gelöscht werden.');
return { success: false, error: err.message || 'Benutzer konnte nicht gelöscht werden.' };
}
}
export async function updateUserRole(id: string, role: 'admin' | 'partner' | 'verwaltung' | 'gesperrt') {
try {
const admin = createAdminClient();
const { error } = await admin
.from('users')
.upsert({ id, role }, { onConflict: 'id' });
if (error) throw error;
if (error) {
return { success: false, error: error.message };
}
revalidatePath('/admin/users');
return { success: true };
} catch (err: any) {
console.error('updateUserRole Server Action failed:', err);
return { success: false, error: err.message || 'Rolle konnte nicht aktualisiert werden.' };
}
}
export async function updateUserStatus(id: string, ban: boolean) {
@@ -224,12 +246,20 @@ export async function getPartners() {
}
export async function updateUserProfile(id: string, data: { first_name: string | null; last_name: string | null }) {
try {
const admin = createAdminClient();
const { error } = await admin
.from('profiles')
.upsert({ id, first_name: data.first_name, last_name: data.last_name }, { onConflict: 'id' });
if (error) throw error;
if (error) {
return { success: false, error: error.message };
}
revalidatePath('/admin/users');
return { success: true };
} catch (err: any) {
console.error('updateUserProfile Server Action failed:', err);
return { success: false, error: err.message || 'Profil konnte nicht aktualisiert werden.' };
}
}
function getBeautifulEmailHtml(title: string, messageHtml: string, buttonText?: string, buttonUrl?: string) {