feat: implement create functionality for WapServers across server, sysadmin, and CLI layers
This commit is contained in:
Binary file not shown.
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
CreateWapServerParams,
|
||||
FindWapServerParams,
|
||||
IWapServer,
|
||||
IWapServerAdapter,
|
||||
@@ -28,6 +29,10 @@ export class WapServerAdapterMongoose implements IWapServerAdapter {
|
||||
this.serverList = model<IWapServerDocument>("WapServer", this.schema);
|
||||
}
|
||||
|
||||
public async create(data: CreateWapServerParams): Promise<IWapServer> {
|
||||
return await this.serverList.create(data);
|
||||
}
|
||||
|
||||
public async find(data: FindWapServerParams): Promise<IWapServer[]> {
|
||||
return this.serverList.find(data).exec();
|
||||
}
|
||||
|
||||
@@ -114,6 +114,16 @@ export type UpdateWapServerParams = {
|
||||
active?: boolean;
|
||||
};
|
||||
|
||||
export type CreateWapServerParams = {
|
||||
name: string;
|
||||
ipv4: string;
|
||||
port: number;
|
||||
maxBots: number;
|
||||
ipv6?: string;
|
||||
description?: string;
|
||||
active?: boolean;
|
||||
};
|
||||
|
||||
export type PaginateWapServerParams = FindWapServerParams & {
|
||||
page: number;
|
||||
limit: number;
|
||||
@@ -206,6 +216,10 @@ export type SysAdminGetWapServerParams = PaginateWapServerParams & {
|
||||
payload: IPayload;
|
||||
};
|
||||
|
||||
export type SysAdminCreateWapServerParams = CreateWapServerParams & {
|
||||
payload: IPayload;
|
||||
};
|
||||
|
||||
export type SysAdminUpdateWapServerParams = UpdateWapServerParams & {
|
||||
payload: IPayload;
|
||||
};
|
||||
@@ -227,6 +241,7 @@ export type SysAdminWapServerOrganizationActionRequest = SysAdminWapServerOrgani
|
||||
};
|
||||
|
||||
export interface IWapServerAdapter {
|
||||
create(data: CreateWapServerParams): Promise<IWapServer>;
|
||||
find(data: FindWapServerParams): Promise<IWapServer[]>;
|
||||
findOne(data: FindWapServerParams): Promise<IWapServerDocument | null>;
|
||||
delete(id: string): Promise<void>;
|
||||
@@ -249,6 +264,7 @@ export interface IWapServerManager {
|
||||
getQr(data: BotEventParams): Promise<string>;
|
||||
sendMessage(data: SendBotMessageParams): Promise<void>;
|
||||
sysAdminGetWapServers(data: PaginateWapServerParams): Promise<PaginateWapServerResults>;
|
||||
sysAdminCreateWapServer(data: CreateWapServerParams): Promise<IWapServer>;
|
||||
sysAdminUpdateWapServer(data: UpdateWapServerParams): Promise<IWapServer>;
|
||||
sysAdminAuditWapServer(data: SysAdminWapServerAuditParams): Promise<SysAdminWapServerAuditResult>;
|
||||
sysAdminRecalculateWapServerCount(data: SysAdminWapServerRecalculateCountParams): Promise<SysAdminWapServerRecalculateCountResult>;
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
BOT_STATE,
|
||||
SERVER_STATE,
|
||||
BOT_SESSION_STATUS,
|
||||
CreateWapServerParams,
|
||||
VALIDATE_BOT_ENVENT_ERRORS,
|
||||
PaginateWapServerResults,
|
||||
PaginateWapServerParams,
|
||||
@@ -981,6 +982,35 @@ class WapServerManager implements IWapServerManager {
|
||||
return servers;
|
||||
}
|
||||
|
||||
public async sysAdminCreateWapServer(data: CreateWapServerParams): Promise<IWapServer> {
|
||||
if (!data.name || !String(data.name).trim()) {
|
||||
throw new Error("Name is required");
|
||||
}
|
||||
|
||||
if (!data.ipv4 || !String(data.ipv4).trim()) {
|
||||
throw new Error("IPv4 is required");
|
||||
}
|
||||
|
||||
if (!Number.isFinite(data.port) || data.port < 0) {
|
||||
throw new Error("Port must be a finite non-negative number");
|
||||
}
|
||||
|
||||
if (!Number.isFinite(data.maxBots) || data.maxBots < 0) {
|
||||
throw new Error("Max bots must be a finite non-negative number");
|
||||
}
|
||||
|
||||
return await this.servers.create({
|
||||
name: String(data.name).trim(),
|
||||
description: data.description ? String(data.description).trim() : "",
|
||||
ipv4: this.normalizeBotAdminApiUrl(data.ipv4),
|
||||
ipv6: data.ipv6 ? String(data.ipv6).trim() : "",
|
||||
countBots: 0,
|
||||
port: data.port,
|
||||
maxBots: data.maxBots,
|
||||
active: data.active === undefined ? true : Boolean(data.active),
|
||||
} as CreateWapServerParams & { countBots: number });
|
||||
}
|
||||
|
||||
public async sysAdminUpdateWapServer(data: UpdateWapServerParams): Promise<IWapServer> {
|
||||
if (!data.serverId) {
|
||||
throw new Error("Server id is required");
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
PaginateWapServerResults,
|
||||
SysAdminCreateWapServerParams,
|
||||
SysAdminDeleteWapServerRequest,
|
||||
SysAdminDeleteWapServerResult,
|
||||
SysAdminAuditWapServerParams,
|
||||
@@ -55,6 +56,27 @@ const getErrorDesc = (error: unknown): string => {
|
||||
return fallback || "Unknown error while auditing WAP server";
|
||||
};
|
||||
|
||||
@Route("sysadmin/wapserver/create")
|
||||
export class SysAdminWapServerCreateController extends Controller {
|
||||
@Response<ApiValidationError>(500, "Ha ocurrido un error")
|
||||
@SuccessResponse(200, "Done")
|
||||
@Post()
|
||||
@Middlewares(sysAdminAuthMiddleware)
|
||||
public async sysAdminCreateWapServer(
|
||||
@Body() requestBody: SysAdminCreateWapServerParams,
|
||||
): Promise<IWapServer | ApiValidationError> {
|
||||
try {
|
||||
const { payload, ...cleanRequestBody } = requestBody as any;
|
||||
const result = await new SA_WapServerService().sysAdminCreateWapServer(cleanRequestBody);
|
||||
this.setStatus(200);
|
||||
return result;
|
||||
} catch (e) {
|
||||
this.setStatus(500);
|
||||
return new ApiValidationError(500, getErrorDesc(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Route("sysadmin/wapserver/get")
|
||||
export class SysAdminWapServerGetController extends Controller {
|
||||
@Response<ApiValidationError>(500, "Ha ocurrido un error")
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { connect } from "mongoose";
|
||||
|
||||
import {
|
||||
CreateWapServerParams,
|
||||
PaginateWapServerParams,
|
||||
PaginateWapServerResults,
|
||||
SysAdminDeleteWapServerParams,
|
||||
@@ -23,6 +24,11 @@ export class SA_WapServerService {
|
||||
return await WapServerList.sysAdminGetWapServers(data);
|
||||
}
|
||||
|
||||
public async sysAdminCreateWapServer(data: CreateWapServerParams) {
|
||||
await connect(`${process.env.DATABASE_CONNECTION}`);
|
||||
return await WapServerList.sysAdminCreateWapServer(data);
|
||||
}
|
||||
|
||||
public async sysAdminUpdateWapServer(data: UpdateWapServerParams) {
|
||||
await connect(`${process.env.DATABASE_CONNECTION}`);
|
||||
return await WapServerList.sysAdminUpdateWapServer(data);
|
||||
|
||||
@@ -196,6 +196,21 @@ export type UpdateWapServerPayload = {
|
||||
active?: boolean;
|
||||
};
|
||||
|
||||
export type CreateWapServerPayload = {
|
||||
name: string;
|
||||
ipv4: string;
|
||||
port: number;
|
||||
maxBots: number;
|
||||
ipv6?: string;
|
||||
description?: string;
|
||||
active?: boolean;
|
||||
};
|
||||
|
||||
export const createWapServer = async (data: CreateWapServerPayload): Promise<WapServer> => {
|
||||
const res = await sysadminApi.post('/wap/create', data);
|
||||
return res.data;
|
||||
};
|
||||
|
||||
export const updateWapServer = async (data: UpdateWapServerPayload): Promise<WapServer> => {
|
||||
const res = await sysadminApi.post('/wap/update', data);
|
||||
return res.data;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { Search, RotateCcw, CheckCircle, XCircle, Server, ServerOff, ClipboardList, Calculator, X, MoreVertical, Play, Pause, Power, Trash2, Unlink, QrCode, RotateCw, Edit3 } from 'lucide-react';
|
||||
import { auditWapServer, deleteWapBot, deleteWapServer, detachWapOrganizationServer, fetchWapServers, getWapBotQr, recalculateWapServerCount, restartWapBot, startWapBot, stopWapBot, updateWapServer, type WapContainerDto, type WapServerAuditResult, type WapServerQrResult, type WapServerRecalculateCountResult } from '../api/sysadmin';
|
||||
import { Search, RotateCcw, CheckCircle, XCircle, Server, ServerOff, ClipboardList, Calculator, X, MoreVertical, Play, Pause, Power, Trash2, Unlink, QrCode, RotateCw, Edit3, Plus } from 'lucide-react';
|
||||
import { auditWapServer, createWapServer, deleteWapBot, deleteWapServer, detachWapOrganizationServer, fetchWapServers, getWapBotQr, recalculateWapServerCount, restartWapBot, startWapBot, stopWapBot, updateWapServer, type WapContainerDto, type WapServerAuditResult, type WapServerQrResult, type WapServerRecalculateCountResult } from '../api/sysadmin';
|
||||
|
||||
const getErrorMessage = (error: unknown, fallback: string): string => {
|
||||
const responseData = (error as any)?.response?.data;
|
||||
@@ -30,6 +30,7 @@ export const WapServersPage = () => {
|
||||
const [openActionsServerId, setOpenActionsServerId] = useState<string | null>(null);
|
||||
const [openAuditActionKey, setOpenAuditActionKey] = useState<string | null>(null);
|
||||
const [editingServer, setEditingServer] = useState<any | null>(null);
|
||||
const [serverFormMode, setServerFormMode] = useState<'create' | 'edit'>('edit');
|
||||
const [editForm, setEditForm] = useState({ name: '', ipv4: '', port: '', maxBots: '', active: true });
|
||||
|
||||
// Filters
|
||||
@@ -103,6 +104,7 @@ export const WapServersPage = () => {
|
||||
};
|
||||
|
||||
const openEditServer = (server: any) => {
|
||||
setServerFormMode('edit');
|
||||
setEditingServer(server);
|
||||
setEditForm({
|
||||
name: server.name || '',
|
||||
@@ -113,11 +115,17 @@ export const WapServersPage = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const openCreateServer = () => {
|
||||
setServerFormMode('create');
|
||||
setEditingServer({});
|
||||
setEditForm({ name: '', ipv4: '', port: '', maxBots: '', active: true });
|
||||
};
|
||||
|
||||
const handleSaveServer = async (event: React.FormEvent) => {
|
||||
event.preventDefault();
|
||||
if (!editingServer) return;
|
||||
|
||||
const serverId = getServerId(editingServer);
|
||||
const serverId = serverFormMode === 'edit' ? getServerId(editingServer) : 'create';
|
||||
const port = Number(editForm.port);
|
||||
const maxBots = Number(editForm.maxBots);
|
||||
|
||||
@@ -128,6 +136,16 @@ export const WapServersPage = () => {
|
||||
|
||||
setActionServerId(serverId);
|
||||
try {
|
||||
if (serverFormMode === 'create') {
|
||||
await createWapServer({
|
||||
name: editForm.name,
|
||||
ipv4: editForm.ipv4,
|
||||
port,
|
||||
maxBots,
|
||||
active: editForm.active,
|
||||
});
|
||||
setActionMessage('Servidor WAP creado.');
|
||||
} else {
|
||||
await updateWapServer({
|
||||
serverId,
|
||||
name: editForm.name,
|
||||
@@ -137,6 +155,7 @@ export const WapServersPage = () => {
|
||||
active: editForm.active,
|
||||
});
|
||||
setActionMessage('Servidor WAP actualizado.');
|
||||
}
|
||||
setEditingServer(null);
|
||||
await loadServers();
|
||||
} catch (e) {
|
||||
@@ -282,6 +301,9 @@ export const WapServersPage = () => {
|
||||
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} className="animate-fade-in users-page-container" style={{ display: 'flex', flexDirection: 'column', height: '100%', overflow: 'hidden' }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '1rem', flexShrink: 0 }}>
|
||||
<h1 style={{ fontSize: '2rem', fontWeight: '700' }}>Servidores WAP</h1>
|
||||
<button type="button" className="btn-primary" onClick={openCreateServer} style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
||||
<Plus size={18} /> Nuevo servidor
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Filters Bar */}
|
||||
@@ -567,8 +589,8 @@ export const WapServersPage = () => {
|
||||
<form className="edit-server-modal glass-panel" onSubmit={handleSaveServer} onClick={(event) => event.stopPropagation()}>
|
||||
<div className="audit-modal-header">
|
||||
<div>
|
||||
<h2>Editar servidor</h2>
|
||||
<p>{editingServer.name || getServerId(editingServer)}</p>
|
||||
<h2>{serverFormMode === 'create' ? 'Nuevo servidor' : 'Editar servidor'}</h2>
|
||||
<p>{serverFormMode === 'create' ? 'Crear servidor WAP' : editingServer.name || getServerId(editingServer)}</p>
|
||||
</div>
|
||||
<button type="button" className="btn-secondary" onClick={() => setEditingServer(null)} aria-label="Cerrar edición">
|
||||
<X size={18} />
|
||||
@@ -602,7 +624,7 @@ export const WapServersPage = () => {
|
||||
|
||||
<div className="edit-server-actions">
|
||||
<button type="button" className="btn-secondary" onClick={() => setEditingServer(null)}>Cancelar</button>
|
||||
<button type="submit" className="btn-primary" disabled={actionServerId === getServerId(editingServer)}>Guardar cambios</button>
|
||||
<button type="submit" className="btn-primary" disabled={actionServerId === (serverFormMode === 'create' ? 'create' : getServerId(editingServer))}>{serverFormMode === 'create' ? 'Crear servidor' : 'Guardar cambios'}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import axios from "axios";
|
||||
import { Request, Response } from "express";
|
||||
import { WapService } from "../services/wap.service";
|
||||
import { PaginateWapServerParams, UpdateWapServerParams, WapServerByIdParams, WapServerOrganizationActionParams } from "src/models/WapServers.Model";
|
||||
import { CreateWapServerParams, PaginateWapServerParams, UpdateWapServerParams, WapServerByIdParams, WapServerOrganizationActionParams } from "src/models/WapServers.Model";
|
||||
|
||||
const wapService = new WapService();
|
||||
|
||||
@@ -58,6 +58,17 @@ export class WapController {
|
||||
}
|
||||
};
|
||||
|
||||
public createServer = async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const result = await wapService.createWapServer(req.body as CreateWapServerParams);
|
||||
res.json(result);
|
||||
} catch (error) {
|
||||
console.error("Error creating wap server:", error);
|
||||
const message = getErrorMessage(error);
|
||||
res.status(getErrorStatus(error)).json({ success: false, message, desc: message });
|
||||
}
|
||||
};
|
||||
|
||||
public recalculateCount = async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const data: WapServerByIdParams = req.body as WapServerByIdParams;
|
||||
|
||||
@@ -33,6 +33,16 @@ export type UpdateWapServerParams = {
|
||||
active?: boolean;
|
||||
};
|
||||
|
||||
export type CreateWapServerParams = {
|
||||
name: string;
|
||||
ipv4: string;
|
||||
port: number;
|
||||
maxBots: number;
|
||||
ipv6?: string;
|
||||
description?: string;
|
||||
active?: boolean;
|
||||
};
|
||||
|
||||
export type PaginateWapServerParams = FindWapServerParams & {
|
||||
page: number;
|
||||
limit: number;
|
||||
|
||||
@@ -5,6 +5,7 @@ const router = Router();
|
||||
const wapController = new WapController();
|
||||
|
||||
router.post("/paginate", wapController.getServers);
|
||||
router.post("/create", wapController.createServer);
|
||||
router.post("/update", wapController.updateServer);
|
||||
router.post("/audit", wapController.auditServer);
|
||||
router.post("/recalculate-count", wapController.recalculateCount);
|
||||
|
||||
@@ -3,6 +3,7 @@ import { getApiHost } from "../helpers/GetApiHost";
|
||||
import axios from "axios";
|
||||
import { getPayload } from "../helpers/GetPayload";
|
||||
import {
|
||||
CreateWapServerParams,
|
||||
PaginateWapServerParams,
|
||||
PaginateWapServerResults,
|
||||
WapServerAuditResult,
|
||||
@@ -45,6 +46,18 @@ export class WapService {
|
||||
return response.data as WapServerAuditResult;
|
||||
}
|
||||
|
||||
public async createWapServer(data: CreateWapServerParams): Promise<IWapServer> {
|
||||
const nonce = await getSysAdminNonce();
|
||||
const postData = { ...data, ...{ payload: getPayload(nonce) } };
|
||||
|
||||
const response = await axios.post(`${getApiHost()}/sysadmin/wapserver/create`, postData, {
|
||||
headers: { "Content-Type": "application/json" },
|
||||
timeout: 5000,
|
||||
});
|
||||
|
||||
return response.data as IWapServer;
|
||||
}
|
||||
|
||||
public async updateWapServer(data: UpdateWapServerParams): Promise<IWapServer> {
|
||||
const nonce = await getSysAdminNonce();
|
||||
const postData = { ...data, ...{ payload: getPayload(nonce) } };
|
||||
|
||||
Reference in New Issue
Block a user