'use server' import type { ChangeUserPasswordInput, ChangeUserPasswordResult } from './types' import { getAuditRequestMetadata } from '@admin/actions/audit/get-audit-request-metadata' import { auth } from '@admin/auth' import { requireRole, UserRole } from '@admin/auth/middleware' import db from '@admin/db' import { user } from '@admin/db/schema' import { runAdminEventHooks } from '@admin/lib/lifecycle-hooks' import { toActionError } from '@admin/utils/error/to-action-error' import { eq } from 'drizzle-orm' import { updateTag } from 'next/cache' import { headers } from 'next/headers' import { usersCacheTags } from './types' export async function changeUserPassword( input: ChangeUserPasswordInput ): Promise { const actor = await requireRole([UserRole.ADMIN]) try { const [targetUser] = await db .select({ id: user.id, email: user.email, name: user.name }) .from(user) .where(eq(user.id, input.userId)) .limit(1) if (!targetUser) { return { success: false, error: 'User not found' } } if (targetUser.id === actor.id) { return { success: false, error: 'Use your profile to change your own password' } } const now = new Date().toISOString() const requestHeaders = await headers() const auditRequestMetadata = await getAuditRequestMetadata() await auth.api.setUserPassword({ body: { userId: input.userId, newPassword: input.newPassword }, headers: requestHeaders }) await auth.api.revokeUserSessions({ body: { userId: input.userId }, headers: requestHeaders }) updateTag(usersCacheTags.all) runAdminEventHooks({ category: 'user', action: 'update', targetType: 'user', targetId: targetUser.id, targetLabel: targetUser.email, user: actor, timestamp: now, sourceType: 'admin_ui' as const, changedFields: ['password'], metadata: { operation: 'password_change' }, ...auditRequestMetadata }) return { success: true } } catch (error) { return { success: false, error: toActionError(error, 'Failed to change user password') } } }