- Implemented OAuth 2.0 Authorization Server endpoints per RFCs, including token, introspection, revocation, and metadata discovery. - Added user consent submission, listing, and revocation APIs alongside frontend integration for improved UX. - Enforced stricter OAuth security measures (PKCE, state validation, scopes). - Refactored schemas and services for consistency and expanded coverage of OAuth workflows. - Updated documentation and type definitions for new API behaviors.
583 lines
14 KiB
TypeScript
583 lines
14 KiB
TypeScript
/**
|
|
* Auto-generated MSW Handlers
|
|
*
|
|
* ⚠️ DO NOT EDIT THIS FILE MANUALLY
|
|
*
|
|
* This file is automatically generated from the OpenAPI specification.
|
|
* To regenerate: npm run generate:api
|
|
*
|
|
* For custom handler behavior, use src/mocks/handlers/overrides.ts
|
|
*
|
|
* Generated: 2025-11-26T12:21:51.098Z
|
|
*/
|
|
|
|
import { http, HttpResponse, delay } from 'msw';
|
|
import {
|
|
validateCredentials,
|
|
setCurrentUser,
|
|
updateCurrentUser,
|
|
currentUser,
|
|
sampleUsers,
|
|
} from '../data/users';
|
|
import {
|
|
sampleOrganizations,
|
|
getUserOrganizations,
|
|
getOrganizationMembersList,
|
|
} from '../data/organizations';
|
|
import { adminStats } from '../data/stats';
|
|
|
|
const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:8000';
|
|
const NETWORK_DELAY = 300; // ms - simulate realistic network delay
|
|
|
|
/**
|
|
* Auto-generated request handlers
|
|
* Covers all endpoints defined in OpenAPI spec
|
|
*/
|
|
export const generatedHandlers = [
|
|
/**
|
|
* Register User
|
|
*/
|
|
http.post(`${API_BASE_URL}/api/v1/auth/register`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
const body = (await request.json()) as any;
|
|
|
|
const newUser = {
|
|
id: `new-user-${Date.now()}`,
|
|
email: body.email,
|
|
first_name: body.first_name,
|
|
last_name: body.last_name || null,
|
|
phone_number: body.phone_number || null,
|
|
is_active: true,
|
|
is_superuser: false,
|
|
created_at: new Date().toISOString(),
|
|
updated_at: new Date().toISOString(),
|
|
last_login: null,
|
|
organization_count: 0,
|
|
};
|
|
|
|
setCurrentUser(newUser);
|
|
|
|
return HttpResponse.json({
|
|
user: newUser,
|
|
access_token: `demo-access-${Date.now()}`,
|
|
refresh_token: `demo-refresh-${Date.now()}`,
|
|
token_type: 'bearer',
|
|
expires_in: 900,
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Login
|
|
*/
|
|
http.post(`${API_BASE_URL}/api/v1/auth/login`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
const body = (await request.json()) as any;
|
|
const user = validateCredentials(body.email, body.password);
|
|
|
|
if (!user) {
|
|
return HttpResponse.json(
|
|
{ detail: 'Incorrect email or password' },
|
|
{ status: 401 }
|
|
);
|
|
}
|
|
|
|
const accessToken = `demo-access-${user.id}-${Date.now()}`;
|
|
const refreshToken = `demo-refresh-${user.id}-${Date.now()}`;
|
|
|
|
setCurrentUser(user);
|
|
|
|
return HttpResponse.json({
|
|
access_token: accessToken,
|
|
refresh_token: refreshToken,
|
|
token_type: 'bearer',
|
|
expires_in: 900,
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Refresh Token
|
|
*/
|
|
http.post(`${API_BASE_URL}/api/v1/auth/refresh`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
access_token: `demo-access-refreshed-${Date.now()}`,
|
|
refresh_token: `demo-refresh-refreshed-${Date.now()}`,
|
|
token_type: 'bearer',
|
|
expires_in: 900,
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Request Password Reset
|
|
*/
|
|
http.post(`${API_BASE_URL}/api/v1/auth/password-reset/request`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Operation successful',
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Confirm Password Reset
|
|
*/
|
|
http.post(`${API_BASE_URL}/api/v1/auth/password-reset/confirm`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Operation successful',
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Logout from Current Device
|
|
*/
|
|
http.post(`${API_BASE_URL}/api/v1/auth/logout`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Operation successful',
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Logout from All Devices
|
|
*/
|
|
http.post(`${API_BASE_URL}/api/v1/auth/logout-all`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Operation successful',
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* List Users
|
|
*/
|
|
http.get(`${API_BASE_URL}/api/v1/users`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Operation successful'
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Get Current User
|
|
*/
|
|
http.get(`${API_BASE_URL}/api/v1/users/me`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
if (!currentUser) {
|
|
return HttpResponse.json({ detail: 'Not authenticated' }, { status: 401 });
|
|
}
|
|
return HttpResponse.json(currentUser);
|
|
}),
|
|
|
|
/**
|
|
* Update Current User
|
|
*/
|
|
http.patch(`${API_BASE_URL}/api/v1/users/me`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
if (!currentUser) {
|
|
return HttpResponse.json({ detail: 'Not authenticated' }, { status: 401 });
|
|
}
|
|
const body = (await request.json()) as any;
|
|
updateCurrentUser(body);
|
|
return HttpResponse.json(currentUser);
|
|
}),
|
|
|
|
/**
|
|
* Get User by ID
|
|
*/
|
|
http.get(`${API_BASE_URL}/api/v1/users/:user_id`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Operation successful'
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Update User
|
|
*/
|
|
http.patch(`${API_BASE_URL}/api/v1/users/:user_id`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Operation successful'
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Delete User
|
|
*/
|
|
http.delete(`${API_BASE_URL}/api/v1/users/:user_id`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Operation successful'
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Change Current User Password
|
|
*/
|
|
http.patch(`${API_BASE_URL}/api/v1/users/me/password`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Operation successful'
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* List My Active Sessions
|
|
*/
|
|
http.get(`${API_BASE_URL}/api/v1/sessions/me`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Operation successful'
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Revoke Specific Session
|
|
*/
|
|
http.delete(`${API_BASE_URL}/api/v1/sessions/:session_id`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Operation successful'
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Cleanup Expired Sessions
|
|
*/
|
|
http.delete(`${API_BASE_URL}/api/v1/sessions/me/expired`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Operation successful'
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Admin: Get Dashboard Stats
|
|
*/
|
|
http.get(`${API_BASE_URL}/api/v1/admin/stats`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
if (!currentUser?.is_superuser) {
|
|
return HttpResponse.json({ detail: 'Admin access required' }, { status: 403 });
|
|
}
|
|
return HttpResponse.json(adminStats);
|
|
}),
|
|
|
|
/**
|
|
* Admin: List All Users
|
|
*/
|
|
http.get(`${API_BASE_URL}/api/v1/admin/users`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
if (!currentUser?.is_superuser) {
|
|
return HttpResponse.json({ detail: 'Admin access required' }, { status: 403 });
|
|
}
|
|
const url = new URL(request.url);
|
|
const page = parseInt(url.searchParams.get('page') || '1');
|
|
const pageSize = parseInt(url.searchParams.get('page_size') || '50');
|
|
|
|
const start = (page - 1) * pageSize;
|
|
const end = start + pageSize;
|
|
const paginatedUsers = sampleUsers.slice(start, end);
|
|
|
|
return HttpResponse.json({
|
|
data: paginatedUsers,
|
|
pagination: {
|
|
total: sampleUsers.length,
|
|
page,
|
|
page_size: pageSize,
|
|
total_pages: Math.ceil(sampleUsers.length / pageSize),
|
|
has_next: end < sampleUsers.length,
|
|
has_prev: page > 1,
|
|
},
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Admin: Create User
|
|
*/
|
|
http.post(`${API_BASE_URL}/api/v1/admin/users`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Operation successful'
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Admin: Get User Details
|
|
*/
|
|
http.get(`${API_BASE_URL}/api/v1/admin/users/:user_id`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Operation successful'
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Admin: Update User
|
|
*/
|
|
http.put(`${API_BASE_URL}/api/v1/admin/users/:user_id`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Operation successful'
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Admin: Delete User
|
|
*/
|
|
http.delete(`${API_BASE_URL}/api/v1/admin/users/:user_id`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Operation successful'
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Admin: Activate User
|
|
*/
|
|
http.post(`${API_BASE_URL}/api/v1/admin/users/:user_id/activate`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Operation successful'
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Admin: Deactivate User
|
|
*/
|
|
http.post(`${API_BASE_URL}/api/v1/admin/users/:user_id/deactivate`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Operation successful'
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Admin: Bulk User Action
|
|
*/
|
|
http.post(`${API_BASE_URL}/api/v1/admin/users/bulk-action`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Operation successful'
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Admin: List Organizations
|
|
*/
|
|
http.get(`${API_BASE_URL}/api/v1/admin/organizations`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
if (!currentUser?.is_superuser) {
|
|
return HttpResponse.json({ detail: 'Admin access required' }, { status: 403 });
|
|
}
|
|
const url = new URL(request.url);
|
|
const page = parseInt(url.searchParams.get('page') || '1');
|
|
const pageSize = parseInt(url.searchParams.get('page_size') || '50');
|
|
|
|
const start = (page - 1) * pageSize;
|
|
const end = start + pageSize;
|
|
const paginatedOrgs = sampleOrganizations.slice(start, end);
|
|
|
|
return HttpResponse.json({
|
|
data: paginatedOrgs,
|
|
pagination: {
|
|
total: sampleOrganizations.length,
|
|
page,
|
|
page_size: pageSize,
|
|
total_pages: Math.ceil(sampleOrganizations.length / pageSize),
|
|
has_next: end < sampleOrganizations.length,
|
|
has_prev: page > 1,
|
|
},
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Admin: Create Organization
|
|
*/
|
|
http.post(`${API_BASE_URL}/api/v1/admin/organizations`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Operation successful'
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Admin: Get Organization Details
|
|
*/
|
|
http.get(`${API_BASE_URL}/api/v1/admin/organizations/:org_id`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Operation successful'
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Admin: Update Organization
|
|
*/
|
|
http.put(`${API_BASE_URL}/api/v1/admin/organizations/:org_id`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Operation successful'
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Admin: Delete Organization
|
|
*/
|
|
http.delete(`${API_BASE_URL}/api/v1/admin/organizations/:org_id`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Operation successful'
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Admin: List Organization Members
|
|
*/
|
|
http.get(`${API_BASE_URL}/api/v1/admin/organizations/:org_id/members`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Operation successful'
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Admin: Add Member to Organization
|
|
*/
|
|
http.post(`${API_BASE_URL}/api/v1/admin/organizations/:org_id/members`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Operation successful'
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Admin: Remove Member from Organization
|
|
*/
|
|
http.delete(`${API_BASE_URL}/api/v1/admin/organizations/:org_id/members/:user_id`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Operation successful'
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Admin: List All Sessions
|
|
*/
|
|
http.get(`${API_BASE_URL}/api/v1/admin/sessions`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Operation successful'
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Get My Organizations
|
|
*/
|
|
http.get(`${API_BASE_URL}/api/v1/organizations/me`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Operation successful'
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Get Organization Details
|
|
*/
|
|
http.get(`${API_BASE_URL}/api/v1/organizations/:organization_id`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Operation successful'
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Update Organization
|
|
*/
|
|
http.put(`${API_BASE_URL}/api/v1/organizations/:organization_id`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Operation successful'
|
|
});
|
|
}),
|
|
|
|
/**
|
|
* Get Organization Members
|
|
*/
|
|
http.get(`${API_BASE_URL}/api/v1/organizations/:organization_id/members`, async ({ request, params }) => {
|
|
await delay(NETWORK_DELAY);
|
|
|
|
return HttpResponse.json({
|
|
success: true,
|
|
message: 'Operation successful'
|
|
});
|
|
}),
|
|
];
|