mirror of
https://github.com/lordmathis/lemma.git
synced 2025-11-06 16:04:23 +00:00
Migrate admin API to typescript
This commit is contained in:
@@ -1,49 +0,0 @@
|
|||||||
import { apiCall } from './auth';
|
|
||||||
import { API_BASE_URL } from '../utils/constants';
|
|
||||||
|
|
||||||
const ADMIN_BASE_URL = `${API_BASE_URL}/admin`;
|
|
||||||
|
|
||||||
// User Management
|
|
||||||
export const getUsers = async () => {
|
|
||||||
const response = await apiCall(`${ADMIN_BASE_URL}/users`);
|
|
||||||
return response.json();
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createUser = async (userData) => {
|
|
||||||
const response = await apiCall(`${ADMIN_BASE_URL}/users`, {
|
|
||||||
method: 'POST',
|
|
||||||
body: JSON.stringify(userData),
|
|
||||||
});
|
|
||||||
return response.json();
|
|
||||||
};
|
|
||||||
|
|
||||||
export const deleteUser = async (userId) => {
|
|
||||||
const response = await apiCall(`${ADMIN_BASE_URL}/users/${userId}`, {
|
|
||||||
method: 'DELETE',
|
|
||||||
});
|
|
||||||
if (response.status === 204) {
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
throw new Error('Failed to delete user with status: ', response.status);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const updateUser = async (userId, userData) => {
|
|
||||||
const response = await apiCall(`${ADMIN_BASE_URL}/users/${userId}`, {
|
|
||||||
method: 'PUT',
|
|
||||||
body: JSON.stringify(userData),
|
|
||||||
});
|
|
||||||
return response.json();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Workspace Management
|
|
||||||
export const getWorkspaces = async () => {
|
|
||||||
const response = await apiCall(`${ADMIN_BASE_URL}/workspaces`);
|
|
||||||
return response.json();
|
|
||||||
};
|
|
||||||
|
|
||||||
// System Statistics
|
|
||||||
export const getSystemStats = async () => {
|
|
||||||
const response = await apiCall(`${ADMIN_BASE_URL}/stats`);
|
|
||||||
return response.json();
|
|
||||||
};
|
|
||||||
157
app/src/api/admin.ts
Normal file
157
app/src/api/admin.ts
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
import { apiCall } from './api';
|
||||||
|
import { API_BASE_URL, isUser, User } from '../types/authApi';
|
||||||
|
import {
|
||||||
|
CreateUserRequest,
|
||||||
|
isSystemStats,
|
||||||
|
SystemStats,
|
||||||
|
UpdateUserRequest,
|
||||||
|
} from '@/types/adminApi';
|
||||||
|
import { isWorkspace, Workspace } from '@/types/workspace';
|
||||||
|
|
||||||
|
const ADMIN_BASE_URL = `${API_BASE_URL}/admin`;
|
||||||
|
|
||||||
|
// User Management
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches all users from the API
|
||||||
|
* @returns {Promise<User[]>} A promise that resolves to an array of users
|
||||||
|
* @throws {Error} If the API call fails or returns an invalid response
|
||||||
|
* */
|
||||||
|
export const getUsers = async (): Promise<User[]> => {
|
||||||
|
const response = await apiCall(`${ADMIN_BASE_URL}/users`);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const data = await response.json();
|
||||||
|
const errorData = data as { message: string };
|
||||||
|
throw new Error(errorData.message || 'Failed to fetch users');
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
if (!Array.isArray(data)) {
|
||||||
|
throw new Error('Invalid users response received from API');
|
||||||
|
}
|
||||||
|
return data.map((user) => {
|
||||||
|
if (!isUser(user)) {
|
||||||
|
throw new Error('Invalid user object received from API');
|
||||||
|
}
|
||||||
|
return user as User;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new user in the system
|
||||||
|
* @param {CreateUserRequest} userData The data for the new user
|
||||||
|
* @returns {Promise<User>} A promise that resolves to the created user
|
||||||
|
* @throws {Error} If the API call fails or returns an invalid response
|
||||||
|
* */
|
||||||
|
export const createUser = async (
|
||||||
|
userData: CreateUserRequest
|
||||||
|
): Promise<User> => {
|
||||||
|
const response = await apiCall(`${ADMIN_BASE_URL}/users`, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify(userData),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const data = await response.json();
|
||||||
|
const errorData = data as { message: string };
|
||||||
|
throw new Error(errorData.message || 'Failed to create user');
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
if (!isUser(data)) {
|
||||||
|
throw new Error('Invalid user object received from API');
|
||||||
|
}
|
||||||
|
return data as User;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a user from the system
|
||||||
|
* @param {number} userId The ID of the user to delete
|
||||||
|
* @throws {Error} If the API call fails or returns an invalid response
|
||||||
|
* */
|
||||||
|
export const deleteUser = async (userId: number) => {
|
||||||
|
const response = await apiCall(`${ADMIN_BASE_URL}/users/${userId}`, {
|
||||||
|
method: 'DELETE',
|
||||||
|
});
|
||||||
|
if (response.status === 204) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
throw new Error('Failed to delete user with status: ' + response.status);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates an existing user in the system
|
||||||
|
* @param {number} userId The ID of the user to update
|
||||||
|
* @param {UpdateUserRequest} userData The data to update the user with
|
||||||
|
* @returns {Promise<User>} A promise that resolves to the updated user
|
||||||
|
* @throws {Error} If the API call fails or returns an invalid response
|
||||||
|
* */
|
||||||
|
export const updateUser = async (
|
||||||
|
userId: number,
|
||||||
|
userData: UpdateUserRequest
|
||||||
|
): Promise<User> => {
|
||||||
|
const response = await apiCall(`${ADMIN_BASE_URL}/users/${userId}`, {
|
||||||
|
method: 'PUT',
|
||||||
|
body: JSON.stringify(userData),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const data = await response.json();
|
||||||
|
const errorData = data as { message: string };
|
||||||
|
throw new Error(errorData.message || 'Failed to update user');
|
||||||
|
}
|
||||||
|
const data = await response.json();
|
||||||
|
if (!isUser(data)) {
|
||||||
|
throw new Error('Invalid user object received from API');
|
||||||
|
}
|
||||||
|
return data as User;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Workspace Management
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches all workspaces from the API
|
||||||
|
* @returns {Promise<Workspace[]>} A promise that resolves to an array of workspaces
|
||||||
|
* @throws {Error} If the API call fails or returns an invalid response
|
||||||
|
* */
|
||||||
|
export const getWorkspaces = async (): Promise<Workspace[]> => {
|
||||||
|
const response = await apiCall(`${ADMIN_BASE_URL}/workspaces`);
|
||||||
|
if (!response.ok) {
|
||||||
|
const data = await response.json();
|
||||||
|
const errorData = data as { message: string };
|
||||||
|
throw new Error(errorData.message || 'Failed to fetch workspaces');
|
||||||
|
}
|
||||||
|
const data = await response.json();
|
||||||
|
if (!Array.isArray(data)) {
|
||||||
|
throw new Error('Invalid workspaces response received from API');
|
||||||
|
}
|
||||||
|
return data.map((workspace) => {
|
||||||
|
if (!isWorkspace(workspace)) {
|
||||||
|
throw new Error('Invalid workspace object received from API');
|
||||||
|
}
|
||||||
|
return workspace as Workspace;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// System Statistics
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches system-wide statistics from the API
|
||||||
|
* @returns {Promise<SystemStats>} A promise that resolves to the system statistics
|
||||||
|
* @throws {Error} If the API call fails or returns an invalid response
|
||||||
|
* */
|
||||||
|
export const getSystemStats = async (): Promise<SystemStats> => {
|
||||||
|
const response = await apiCall(`${ADMIN_BASE_URL}/stats`);
|
||||||
|
if (!response.ok) {
|
||||||
|
const data = await response.json();
|
||||||
|
const errorData = data as { message: string };
|
||||||
|
throw new Error(errorData.message || 'Failed to fetch system stats');
|
||||||
|
}
|
||||||
|
const data = await response.json();
|
||||||
|
if (!isSystemStats(data)) {
|
||||||
|
throw new Error('Invalid system stats response received from API');
|
||||||
|
}
|
||||||
|
return data as SystemStats;
|
||||||
|
};
|
||||||
60
app/src/types/adminApi.ts
Normal file
60
app/src/types/adminApi.ts
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import { UserRole } from './authApi';
|
||||||
|
|
||||||
|
// CreateUserRequest holds the request fields for creating a new user
|
||||||
|
export interface CreateUserRequest {
|
||||||
|
email: string;
|
||||||
|
displayName: string;
|
||||||
|
password: string;
|
||||||
|
role: UserRole;
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateUserRequest holds the request fields for updating a user
|
||||||
|
export interface UpdateUserRequest {
|
||||||
|
email?: string;
|
||||||
|
displayName?: string;
|
||||||
|
password?: string;
|
||||||
|
role?: UserRole;
|
||||||
|
}
|
||||||
|
|
||||||
|
// WorkspaceStats holds workspace statistics
|
||||||
|
export interface WorkspaceStats {
|
||||||
|
userID: number;
|
||||||
|
userEmail: string;
|
||||||
|
workspaceID: number;
|
||||||
|
workspaceName: string;
|
||||||
|
workspaceCreatedAt: string; // Using ISO string format for time.Time
|
||||||
|
fileCountStats?: FileCountStats;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define FileCountStats based on the Go struct definition of storage.FileCountStats
|
||||||
|
export interface FileCountStats {
|
||||||
|
totalFiles: number;
|
||||||
|
totalSize: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserStats {
|
||||||
|
totalUsers: number;
|
||||||
|
totalWorkspaces: number;
|
||||||
|
activeUsers: number; // Users with activity in last 30 days
|
||||||
|
}
|
||||||
|
|
||||||
|
// SystemStats holds system-wide statistics
|
||||||
|
export interface SystemStats extends FileCountStats, UserStats {}
|
||||||
|
|
||||||
|
// isSystemStats checks if the given object is a valid SystemStats object
|
||||||
|
export function isSystemStats(obj: unknown): obj is SystemStats {
|
||||||
|
return (
|
||||||
|
typeof obj === 'object' &&
|
||||||
|
obj !== null &&
|
||||||
|
'totalUsers' in obj &&
|
||||||
|
typeof (obj as SystemStats).totalUsers === 'number' &&
|
||||||
|
'totalWorkspaces' in obj &&
|
||||||
|
typeof (obj as SystemStats).totalWorkspaces === 'number' &&
|
||||||
|
'activeUsers' in obj &&
|
||||||
|
typeof (obj as SystemStats).activeUsers === 'number' &&
|
||||||
|
'totalFiles' in obj &&
|
||||||
|
typeof (obj as SystemStats).totalFiles === 'number' &&
|
||||||
|
'totalSize' in obj &&
|
||||||
|
typeof (obj as SystemStats).totalSize === 'number'
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -30,3 +30,28 @@ export const DEFAULT_WORKSPACE: Workspace = {
|
|||||||
name: '',
|
name: '',
|
||||||
...DEFAULT_WORKSPACE_SETTINGS,
|
...DEFAULT_WORKSPACE_SETTINGS,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function isWorkspace(obj: unknown): obj is Workspace {
|
||||||
|
return (
|
||||||
|
typeof obj === 'object' &&
|
||||||
|
obj !== null &&
|
||||||
|
'name' in obj &&
|
||||||
|
typeof (obj as Workspace).name === 'string' &&
|
||||||
|
'theme' in obj &&
|
||||||
|
typeof (obj as Workspace).theme === 'string' &&
|
||||||
|
'autoSave' in obj &&
|
||||||
|
typeof (obj as Workspace).autoSave === 'boolean' &&
|
||||||
|
'gitEnabled' in obj &&
|
||||||
|
typeof (obj as Workspace).gitEnabled === 'boolean' &&
|
||||||
|
'gitUrl' in obj &&
|
||||||
|
typeof (obj as Workspace).gitUrl === 'string' &&
|
||||||
|
'gitUser' in obj &&
|
||||||
|
typeof (obj as Workspace).gitUser === 'string' &&
|
||||||
|
'gitToken' in obj &&
|
||||||
|
typeof (obj as Workspace).gitToken === 'string' &&
|
||||||
|
'gitAutoCommit' in obj &&
|
||||||
|
typeof (obj as Workspace).gitAutoCommit === 'boolean' &&
|
||||||
|
'gitCommitMsgTemplate' in obj &&
|
||||||
|
typeof (obj as Workspace).gitCommitMsgTemplate === 'string'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user