feat: Implement user authentication, admin user management, and role-based access control.
This commit is contained in:
parent
8a2ca592bc
commit
38648581ec
19 changed files with 1762 additions and 514 deletions
182
frontend_management/services/user.service.ts
Normal file
182
frontend_management/services/user.service.ts
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
// API Response structure from /api/user/me
|
||||
export interface UserProfileResponse {
|
||||
id: number;
|
||||
username: string;
|
||||
email: string;
|
||||
updated_at: string;
|
||||
created_at: string;
|
||||
role: {
|
||||
code: string;
|
||||
name: {
|
||||
en: string;
|
||||
th: string;
|
||||
};
|
||||
};
|
||||
profile: {
|
||||
prefix: {
|
||||
en: string;
|
||||
th: string;
|
||||
};
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
avatar_url: string | null;
|
||||
birth_date: string | null;
|
||||
phone: string | null;
|
||||
};
|
||||
}
|
||||
|
||||
// Request body for PUT /api/user/me
|
||||
export interface UpdateProfileRequest {
|
||||
prefix?: {
|
||||
en: string;
|
||||
th: string;
|
||||
};
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
phone?: string | null;
|
||||
avatar_url?: string | null;
|
||||
birth_date?: string | null;
|
||||
}
|
||||
|
||||
// Mock profile data for development
|
||||
const MOCK_PROFILES: Record<string, UserProfileResponse> = {
|
||||
'admin@elearning.local': {
|
||||
id: 1,
|
||||
username: 'admin',
|
||||
email: 'admin@elearning.local',
|
||||
updated_at: '2024-01-01T00:00:00Z',
|
||||
created_at: '2024-01-01T00:00:00Z',
|
||||
role: {
|
||||
code: 'ADMIN',
|
||||
name: { en: 'Administrator', th: 'ผู้ดูแลระบบ' }
|
||||
},
|
||||
profile: {
|
||||
prefix: { en: 'Mr.', th: 'นาย' },
|
||||
first_name: 'ผู้ดูแล',
|
||||
last_name: 'ระบบ',
|
||||
avatar_url: null,
|
||||
birth_date: null,
|
||||
phone: '081-234-5678'
|
||||
}
|
||||
},
|
||||
'instructor@elearning.local': {
|
||||
id: 2,
|
||||
username: 'instructor',
|
||||
email: 'instructor@elearning.local',
|
||||
updated_at: '2024-01-01T00:00:00Z',
|
||||
created_at: '2024-01-01T00:00:00Z',
|
||||
role: {
|
||||
code: 'INSTRUCTOR',
|
||||
name: { en: 'Instructor', th: 'ผู้สอน' }
|
||||
},
|
||||
profile: {
|
||||
prefix: { en: 'Mr.', th: 'นาย' },
|
||||
first_name: 'อาจารย์',
|
||||
last_name: 'ทดสอบ',
|
||||
avatar_url: null,
|
||||
birth_date: null,
|
||||
phone: '081-234-5678'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Helper function to get auth token from cookie
|
||||
const getAuthToken = (): string => {
|
||||
const tokenCookie = useCookie('token');
|
||||
return tokenCookie.value || '';
|
||||
};
|
||||
|
||||
export const userService = {
|
||||
async getProfile(): Promise<UserProfileResponse> {
|
||||
const config = useRuntimeConfig();
|
||||
const useMockData = config.public.useMockData as boolean;
|
||||
|
||||
if (useMockData) {
|
||||
return this.mockGetProfile();
|
||||
}
|
||||
|
||||
return this.apiGetProfile();
|
||||
},
|
||||
|
||||
// Mock get profile
|
||||
async mockGetProfile(): Promise<UserProfileResponse> {
|
||||
await new Promise(resolve => setTimeout(resolve, 300));
|
||||
|
||||
const userCookie = useCookie('user');
|
||||
if (!userCookie.value) throw new Error('User not found');
|
||||
|
||||
const user = typeof userCookie.value === 'string'
|
||||
? JSON.parse(userCookie.value)
|
||||
: userCookie.value;
|
||||
const mockProfile = MOCK_PROFILES[user.email];
|
||||
|
||||
if (!mockProfile) {
|
||||
throw new Error('Profile not found');
|
||||
}
|
||||
|
||||
return mockProfile;
|
||||
},
|
||||
|
||||
// Real API get profile
|
||||
async apiGetProfile(): Promise<UserProfileResponse> {
|
||||
const config = useRuntimeConfig();
|
||||
const token = getAuthToken();
|
||||
|
||||
const response = await $fetch<UserProfileResponse>('/api/user/me', {
|
||||
baseURL: config.public.apiBaseUrl as string,
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`
|
||||
}
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
|
||||
async updateProfile(data: UpdateProfileRequest): Promise<UserProfileResponse> {
|
||||
const config = useRuntimeConfig();
|
||||
const useMockData = config.public.useMockData as boolean;
|
||||
|
||||
if (useMockData) {
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
// In mock mode, just return the current profile with updates
|
||||
const profile = await this.mockGetProfile();
|
||||
return { ...profile, profile: { ...profile.profile, ...data } };
|
||||
}
|
||||
|
||||
const token = getAuthToken();
|
||||
const response = await $fetch<UserProfileResponse>('/api/user/me', {
|
||||
method: 'PUT',
|
||||
baseURL: config.public.apiBaseUrl as string,
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`
|
||||
},
|
||||
body: data
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
|
||||
async changePassword(oldPassword: string, newPassword: string): Promise<void> {
|
||||
const config = useRuntimeConfig();
|
||||
const useMockData = config.public.useMockData as boolean;
|
||||
|
||||
if (useMockData) {
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
// In mock mode, just simulate success
|
||||
return;
|
||||
}
|
||||
|
||||
const token = getAuthToken();
|
||||
await $fetch('/api/user/change-password', {
|
||||
method: 'POST',
|
||||
baseURL: config.public.apiBaseUrl as string,
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`
|
||||
},
|
||||
body: {
|
||||
oldPassword,
|
||||
newPassword
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue