Implement Role Management Features and UI Enhancements
- Introduced a new composable `useActiveRole` for managing user roles, including fetching role status and switching roles with server validation. - Updated `RoleSwitcher.vue` to utilize the new composable, enhancing role selection with improved error handling and UI feedback. - Added new API endpoints for role management, including fetching user role status and switching active roles. - Enhanced product visibility logic to filter based on the user's active role, ensuring a tailored experience. - Updated database schema to support last active role tracking for users, improving session management. - Refined UI components across the application to reflect role-based changes and improve user experience.
This commit is contained in:
64
server/api/user/active-role.patch.ts
Normal file
64
server/api/user/active-role.patch.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* PATCH /api/user/active-role
|
||||
*
|
||||
* Switch user's active role (used by RoleSwitcher component)
|
||||
*
|
||||
* Request body:
|
||||
* {
|
||||
* "roleCode": "educator"
|
||||
* }
|
||||
*
|
||||
* Response:
|
||||
* {
|
||||
* "success": true,
|
||||
* "activeRoleCode": "educator"
|
||||
* }
|
||||
*
|
||||
* Validates that user has the requested role before switching
|
||||
* Updates both session (immediate) and database (preference)
|
||||
*/
|
||||
|
||||
import { z } from 'zod'
|
||||
import { setUserActiveRole } from '../../utils/role-session'
|
||||
|
||||
const switchRoleSchema = z.object({
|
||||
roleCode: z.enum(['private', 'educator', 'company'], {
|
||||
errorMap: () => ({ message: 'Ungültige Rolle' }),
|
||||
}),
|
||||
})
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
// Require authentication
|
||||
await requireUserSession(event)
|
||||
|
||||
// Validate request body
|
||||
const body = await readBody(event)
|
||||
const { roleCode } = switchRoleSchema.parse(body)
|
||||
|
||||
try {
|
||||
// Set active role (validates + updates session + saves to DB)
|
||||
await setUserActiveRole(event, roleCode)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
activeRoleCode: roleCode,
|
||||
}
|
||||
} catch (error: any) {
|
||||
// setUserActiveRole throws 403 if user doesn't have role
|
||||
if (error.statusCode === 403) {
|
||||
setResponseStatus(event, 403)
|
||||
return {
|
||||
success: false,
|
||||
message: error.message || 'Du hast diese Rolle nicht',
|
||||
}
|
||||
}
|
||||
|
||||
// Other errors
|
||||
console.error('Role switch error:', error)
|
||||
setResponseStatus(event, 500)
|
||||
return {
|
||||
success: false,
|
||||
message: 'Fehler beim Wechseln der Rolle',
|
||||
}
|
||||
}
|
||||
})
|
||||
69
server/api/user/role-status.get.ts
Normal file
69
server/api/user/role-status.get.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* GET /api/user/role-status
|
||||
*
|
||||
* Get user's active role and all available roles (for RoleSwitcher dropdown)
|
||||
*
|
||||
* Response:
|
||||
* {
|
||||
* "activeRoleCode": "private",
|
||||
* "roles": [
|
||||
* {
|
||||
* "code": "private",
|
||||
* "displayName": "Privatperson",
|
||||
* "description": "Private Nutzung",
|
||||
* "hasRole": true,
|
||||
* "requiresApproval": false
|
||||
* },
|
||||
* {
|
||||
* "code": "educator",
|
||||
* "displayName": "Pädagoge",
|
||||
* "description": "Lehrkräfte und Schulen",
|
||||
* "hasRole": false,
|
||||
* "requiresApproval": true
|
||||
* },
|
||||
* ...
|
||||
* ],
|
||||
* "roleChangedByAdmin": false
|
||||
* }
|
||||
*
|
||||
* - Validates active role with TTL (re-checks DB every 5min)
|
||||
* - Returns ALL roles (approved + not-approved) for dropdown
|
||||
* - Includes "hasRole" flag to show which roles user actually has
|
||||
*/
|
||||
|
||||
import { asc, eq } from 'drizzle-orm'
|
||||
import { roles } from '../../database/schema'
|
||||
import { getUserActiveRole } from '../../utils/role-session'
|
||||
import { getUserApprovedRoleCodes } from '../../utils/roles'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const session = await requireUserSession(event)
|
||||
|
||||
// Get active role (validates with TTL, auto-fallback if revoked)
|
||||
const activeRole = await getUserActiveRole(event)
|
||||
|
||||
// Get user's approved role codes
|
||||
const approvedRoleCodes = await getUserApprovedRoleCodes(session.user.id)
|
||||
|
||||
// Get ALL roles from database (for dropdown: show all, disabled if not approved)
|
||||
const db = useDatabase()
|
||||
const allRoles = await db.query.roles.findMany({
|
||||
where: eq(roles.active, true),
|
||||
orderBy: asc(roles.sortOrder),
|
||||
})
|
||||
|
||||
// Map roles with "hasRole" status
|
||||
const rolesWithStatus = allRoles.map((role) => ({
|
||||
code: role.code,
|
||||
displayName: role.displayName,
|
||||
description: role.description,
|
||||
hasRole: approvedRoleCodes.includes(role.code),
|
||||
requiresApproval: role.requiresApproval,
|
||||
}))
|
||||
|
||||
return {
|
||||
activeRoleCode: activeRole,
|
||||
roles: rolesWithStatus,
|
||||
roleChangedByAdmin: session.roleChangedByAdmin || false,
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user