109 lines
3.6 KiB
TypeScript
109 lines
3.6 KiB
TypeScript
import {
|
|
appUserReadSchema,
|
|
catalogInterfaceSchema,
|
|
userBindingSchema,
|
|
type AppUserCreate,
|
|
type AppUserRead,
|
|
type AppUserUpdate,
|
|
type CatalogInterface,
|
|
type UserBinding,
|
|
type UserBindingCreate,
|
|
} from "@mmapp/contracts/users"
|
|
import { z } from "zod"
|
|
import { requestJson, requestBlob } from "@/shared/api/http-client"
|
|
import type { AppUser, CatalogIface, InterfaceBinding } from "@/lib/users"
|
|
|
|
const usersListPayload = z.object({ users: z.array(appUserReadSchema).refine(rows => new Set(rows.map(row => row.id)).size === rows.length, "Повторяющиеся пользователи в ответе API") })
|
|
const userPayload = z.object({ user: appUserReadSchema })
|
|
const bindingPayload = z.object({ binding: userBindingSchema })
|
|
const catalogPayload = z.object({ interfaces: z.array(catalogInterfaceSchema) })
|
|
|
|
export function toFrontendBinding(b: UserBinding): InterfaceBinding {
|
|
return {
|
|
id: b.id,
|
|
userId: b.userId,
|
|
serverId: String(b.serverId),
|
|
serverName: b.serverName,
|
|
serverSite: b.serverSite,
|
|
serverCountry: b.serverCountry,
|
|
interfaceName: b.interfaceName,
|
|
interfaceType: b.interfaceType,
|
|
peerPublicKey: b.peerPublicKey || undefined,
|
|
peerName: b.peerName || undefined,
|
|
comment: b.comment,
|
|
}
|
|
}
|
|
|
|
export function toFrontendUser(u: AppUserRead): AppUser {
|
|
return {
|
|
id: u.id,
|
|
name: u.name,
|
|
login: u.login,
|
|
email: u.email,
|
|
role: u.role,
|
|
last: u.lastSeen ?? "—",
|
|
avatar: u.avatar,
|
|
active: u.active,
|
|
sections: u.sections,
|
|
servers: u.servers,
|
|
bindings: u.bindings.map(toFrontendBinding),
|
|
}
|
|
}
|
|
|
|
export async function listAppUsers(baseUrl: string, init?: RequestInit): Promise<AppUser[]> {
|
|
const payload = await requestJson<unknown>(baseUrl, "/api/users", init)
|
|
return usersListPayload.parse(payload).users.map(toFrontendUser)
|
|
}
|
|
|
|
export async function createAppUser(baseUrl: string, data: AppUserCreate): Promise<AppUser> {
|
|
const payload = await requestJson<unknown>(baseUrl, "/api/users", {
|
|
method: "POST",
|
|
body: JSON.stringify(data),
|
|
})
|
|
return toFrontendUser(userPayload.parse(payload).user)
|
|
}
|
|
|
|
export async function updateAppUser(baseUrl: string, id: string, data: AppUserUpdate): Promise<AppUser> {
|
|
const payload = await requestJson<unknown>(baseUrl, `/api/users/${id}`, {
|
|
method: "PATCH",
|
|
body: JSON.stringify(data),
|
|
})
|
|
return toFrontendUser(userPayload.parse(payload).user)
|
|
}
|
|
|
|
export async function deleteAppUser(baseUrl: string, id: string, init?: RequestInit): Promise<void> {
|
|
const response = await requestBlob(baseUrl, "/api/users/" + encodeURIComponent(id), { ...init, method: "DELETE" })
|
|
if (response.status !== 204) throw new Error("Удаление пользователя не подтверждено: ожидается HTTP 204.")
|
|
}
|
|
|
|
export async function createUserBinding(
|
|
baseUrl: string,
|
|
userId: string,
|
|
data: UserBindingCreate,
|
|
): Promise<InterfaceBinding> {
|
|
const payload = await requestJson<unknown>(baseUrl, `/api/users/${userId}/bindings`, {
|
|
method: "POST",
|
|
body: JSON.stringify(data),
|
|
})
|
|
return toFrontendBinding(bindingPayload.parse(payload).binding)
|
|
}
|
|
|
|
export async function deleteUserBinding(
|
|
baseUrl: string,
|
|
userId: string,
|
|
bindingId: string,
|
|
): Promise<void> {
|
|
await requestJson<void>(baseUrl, `/api/users/${userId}/bindings/${bindingId}`, { method: "DELETE" })
|
|
}
|
|
|
|
export async function listInterfaceCatalog(
|
|
baseUrl: string,
|
|
serverId: string,
|
|
): Promise<CatalogIface[]> {
|
|
const payload = await requestJson<unknown>(
|
|
baseUrl,
|
|
`/api/users/interface-catalog?serverId=${encodeURIComponent(serverId)}`,
|
|
)
|
|
return catalogPayload.parse(payload).interfaces as CatalogInterface[]
|
|
}
|