From 37f1db6b2bb6ec02098fc282b89450bf5d5cf2d7 Mon Sep 17 00:00:00 2001 From: giancarlo Date: Tue, 9 Apr 2024 19:08:40 +0800 Subject: [PATCH] Refactor admin action naming and move user assertions Renamed the admin actions to have a more uniform approach with "Action" suffixed. This makes the action function's purpose clear in the codebase. Also, moved the `assertUserIsNotCurrentSuperAdmin` method to a more suitable place in the code, arranging it in a private scope. This helps in maintaining clean code architecture and enhances readibility. --- apps/web/app/layout.tsx | 11 ++-- .../lemon-squeezy-webhook-handler.service.ts | 2 +- .../src/components/admin-ban-user-dialog.tsx | 4 +- .../admin-delete-account-dialog.tsx | 4 +- .../components/admin-delete-user-dialog.tsx | 4 +- .../admin-impersonate-user-dialog.tsx | 4 +- .../admin-reactivate-user-dialog.tsx | 4 +- .../src/lib/server/admin-server-actions.ts | 20 +++---- .../services/admin-auth-user.service.ts | 56 +++++++++++++------ 9 files changed, 67 insertions(+), 42 deletions(-) diff --git a/apps/web/app/layout.tsx b/apps/web/app/layout.tsx index 7c200e984..9bf8a1fdb 100644 --- a/apps/web/app/layout.tsx +++ b/apps/web/app/layout.tsx @@ -42,10 +42,13 @@ function getClassName() { const theme = themeCookie ?? appConfig.theme; const dark = theme === 'dark'; - return cn('min-h-screen bg-background antialiased', { - dark, - [sans.className]: true, - }); + return cn( + 'min-h-screen bg-background antialiased', + { + dark, + }, + sans.className, + ); } export const metadata = { diff --git a/packages/billing/lemon-squeezy/src/services/lemon-squeezy-webhook-handler.service.ts b/packages/billing/lemon-squeezy/src/services/lemon-squeezy-webhook-handler.service.ts index 113831ea9..205ae1453 100644 --- a/packages/billing/lemon-squeezy/src/services/lemon-squeezy-webhook-handler.service.ts +++ b/packages/billing/lemon-squeezy/src/services/lemon-squeezy-webhook-handler.service.ts @@ -1,5 +1,5 @@ import { getOrder, getVariant } from '@lemonsqueezy/lemonsqueezy.js'; -import { createHmac, timingSafeEqual } from 'crypto'; +import { createHmac, timingSafeEqual } from 'node:crypto'; import { BillingConfig, diff --git a/packages/features/admin/src/components/admin-ban-user-dialog.tsx b/packages/features/admin/src/components/admin-ban-user-dialog.tsx index 412b7ca15..c7bc47a36 100644 --- a/packages/features/admin/src/components/admin-ban-user-dialog.tsx +++ b/packages/features/admin/src/components/admin-ban-user-dialog.tsx @@ -25,7 +25,7 @@ import { } from '@kit/ui/form'; import { Input } from '@kit/ui/input'; -import { banUser } from '../lib/server/admin-server-actions'; +import { banUserAction } from '../lib/server/admin-server-actions'; import { BanUserSchema } from '../lib/server/schema/admin-actions.schema'; export function AdminBanUserDialog( @@ -58,7 +58,7 @@ export function AdminBanUserDialog(
{ - return banUser(data); + return banUserAction(data); })} > { - return deleteAccount(data); + return deleteAccountAction(data); })} > { - return deleteUser(data); + return deleteUserAction(data); })} > { - const tokens = await impersonateUser(data); + const tokens = await impersonateUserAction(data); setTokens(tokens); })} diff --git a/packages/features/admin/src/components/admin-reactivate-user-dialog.tsx b/packages/features/admin/src/components/admin-reactivate-user-dialog.tsx index 43619226a..82acdf1eb 100644 --- a/packages/features/admin/src/components/admin-reactivate-user-dialog.tsx +++ b/packages/features/admin/src/components/admin-reactivate-user-dialog.tsx @@ -25,7 +25,7 @@ import { } from '@kit/ui/form'; import { Input } from '@kit/ui/input'; -import { reactivateUser } from '../lib/server/admin-server-actions'; +import { reactivateUserAction } from '../lib/server/admin-server-actions'; import { ReactivateUserSchema } from '../lib/server/schema/admin-actions.schema'; export function AdminReactivateUserDialog( @@ -58,7 +58,7 @@ export function AdminReactivateUserDialog( { - return reactivateUser(data); + return reactivateUserAction(data); })} > { const service = getAdminAuthService(); @@ -41,10 +41,10 @@ export const banUser = enhanceAdminAction( ); /** - * @name reactivateUser + * @name reactivateUserAction * @description Reactivate a user in the system. */ -export const reactivateUser = enhanceAdminAction( +export const reactivateUserAction = enhanceAdminAction( enhanceAction( async ({ userId }) => { const service = getAdminAuthService(); @@ -64,10 +64,10 @@ export const reactivateUser = enhanceAdminAction( ); /** - * @name impersonateUser + * @name impersonateUserAction * @description Impersonate a user in the system. */ -export const impersonateUser = enhanceAdminAction( +export const impersonateUserAction = enhanceAdminAction( enhanceAction( async ({ userId }) => { const service = getAdminAuthService(); @@ -81,10 +81,10 @@ export const impersonateUser = enhanceAdminAction( ); /** - * @name deleteUser + * @name deleteUserAction * @description Delete a user from the system. */ -export const deleteUser = enhanceAdminAction( +export const deleteUserAction = enhanceAdminAction( enhanceAction( async ({ userId }) => { const service = getAdminAuthService(); @@ -102,10 +102,10 @@ export const deleteUser = enhanceAdminAction( ); /** - * @name deleteAccount + * @name deleteAccountAction * @description Delete an account from the system. */ -export const deleteAccount = enhanceAdminAction( +export const deleteAccountAction = enhanceAdminAction( enhanceAction( async ({ accountId }) => { const service = getAdminAccountsService(); diff --git a/packages/features/admin/src/lib/server/services/admin-auth-user.service.ts b/packages/features/admin/src/lib/server/services/admin-auth-user.service.ts index b07df03bf..23893c5af 100644 --- a/packages/features/admin/src/lib/server/services/admin-auth-user.service.ts +++ b/packages/features/admin/src/lib/server/services/admin-auth-user.service.ts @@ -1,7 +1,7 @@ -import 'server-only'; - import { SupabaseClient } from '@supabase/supabase-js'; +import 'server-only'; + import { Database } from '@kit/supabase/database'; /** @@ -15,21 +15,10 @@ export class AdminAuthUserService { private readonly adminClient: SupabaseClient, ) {} - async assertUserIsNotCurrentSuperAdmin(targetUserId: string) { - const { data: user } = await this.client.auth.getUser(); - const currentUserId = user.user?.id; - - if (!currentUserId) { - throw new Error(`Error fetching user`); - } - - if (currentUserId === targetUserId) { - throw new Error( - `You cannot perform a destructive action on your own account as a Super Admin`, - ); - } - } - + /** + * Delete a user by deleting the user record and auth record. + * @param userId + */ async deleteUser(userId: string) { await this.assertUserIsNotCurrentSuperAdmin(userId); @@ -41,19 +30,33 @@ export class AdminAuthUserService { } } + /** + * Ban a user by setting the ban duration to `876600h` (100 years). + * @param userId + */ async banUser(userId: string) { await this.assertUserIsNotCurrentSuperAdmin(userId); return this.setBanDuration(userId, `876600h`); } + /** + * Reactivate a user by setting the ban duration to `none`. + * @param userId + */ async reactivateUser(userId: string) { await this.assertUserIsNotCurrentSuperAdmin(userId); return this.setBanDuration(userId, `none`); } + /** + * Impersonate a user by generating a magic link and returning the access and refresh tokens. + * @param userId + */ async impersonateUser(userId: string) { + await this.assertUserIsNotCurrentSuperAdmin(userId); + const { data: { user }, error, @@ -110,6 +113,25 @@ export class AdminAuthUserService { }; } + /** + * Assert that the target user is not the current user. + * @param targetUserId + */ + private async assertUserIsNotCurrentSuperAdmin(targetUserId: string) { + const { data: user } = await this.client.auth.getUser(); + const currentUserId = user.user?.id; + + if (!currentUserId) { + throw new Error(`Error fetching user`); + } + + if (currentUserId === targetUserId) { + throw new Error( + `You cannot perform a destructive action on your own account as a Super Admin`, + ); + } + } + private async setBanDuration(userId: string, banDuration: string) { await this.adminClient.auth.admin.updateUserById(userId, { ban_duration: banDuration,