fix: MedSchedule ESM import for Router and data table links resolution
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { Router } from "express";
|
||||
import type { Express, Request, Response, NextFunction } from "express";
|
||||
import type { Response as ExpressResponse } from "express";
|
||||
import { authenticateToken, type AuthenticatedRequest } from "../middleware/auth.middleware";
|
||||
@@ -52,7 +53,7 @@ function parseDate(value: unknown): Date | null {
|
||||
}
|
||||
|
||||
export function registerMedScheduleRoutes(app: Express) {
|
||||
const router = require("express").Router();
|
||||
const router = Router();
|
||||
router.use(authenticateToken);
|
||||
router.use(tenantIsolation);
|
||||
router.use(medOrgResolver());
|
||||
|
||||
@@ -707,6 +707,151 @@ export function registerDataTableRoutes(app: import("express").Express): void {
|
||||
}
|
||||
);
|
||||
|
||||
// =====================================================
|
||||
// DATA TABLE LINKS API (подсправочники)
|
||||
// =====================================================
|
||||
|
||||
// Get subdirectories for a parent table
|
||||
app.get(['/api/tables/:id/subdirectories', '/api/directories/:id/subdirectories'],
|
||||
authenticateToken,
|
||||
tenantIsolation,
|
||||
async (req: AuthenticatedRequest, res) => {
|
||||
try {
|
||||
const tableId = parseInt(req.params.id);
|
||||
const table = await storage.getDataTable(tableId, req.organizationId!);
|
||||
if (!table) {
|
||||
return res.status(404).json({ error: 'Таблица не найдена' });
|
||||
}
|
||||
|
||||
const role = await storage.getUserTableRole(tableId, req.user!.id, table.createdBy, req.organizationId!);
|
||||
if (!role) {
|
||||
return res.status(403).json({ error: 'Нет доступа к таблице' });
|
||||
}
|
||||
|
||||
const links = await storage.getDataTableLinks(tableId, req.organizationId!);
|
||||
res.json({ subdirectories: links });
|
||||
} catch (error) {
|
||||
console.error('Get subdirectories error:', error);
|
||||
res.status(500).json({ error: 'Ошибка получения подсправочников' });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Create a subdirectory link
|
||||
app.post(['/api/tables/:id/subdirectories', '/api/directories/:id/subdirectories'],
|
||||
authenticateToken,
|
||||
tenantIsolation,
|
||||
async (req: AuthenticatedRequest, res) => {
|
||||
try {
|
||||
const tableId = parseInt(req.params.id);
|
||||
const table = await storage.getDataTable(tableId, req.organizationId!);
|
||||
if (!table) {
|
||||
return res.status(404).json({ error: 'Таблица не найдена' });
|
||||
}
|
||||
|
||||
const role = await storage.getUserTableRole(tableId, req.user!.id, table.createdBy, req.organizationId!);
|
||||
if (role !== 'admin') {
|
||||
return res.status(403).json({ error: 'Нет прав для управления таблицей' });
|
||||
}
|
||||
|
||||
const { childTableId, parentColumnIndex, childColumnIndex, parentValues } = req.body;
|
||||
if (!childTableId || typeof childTableId !== 'number') {
|
||||
return res.status(400).json({ error: 'Необходимо указать подсправочник (childTableId)' });
|
||||
}
|
||||
|
||||
const childTable = await storage.getDataTable(childTableId, req.organizationId!);
|
||||
if (!childTable) {
|
||||
return res.status(404).json({ error: 'Подсправочник не найден' });
|
||||
}
|
||||
|
||||
const link = await storage.createDataTableLink({
|
||||
organizationId: req.organizationId!,
|
||||
parentTableId: tableId,
|
||||
childTableId,
|
||||
parentColumnIndex: parentColumnIndex ?? 0,
|
||||
childColumnIndex: childColumnIndex ?? 0,
|
||||
parentValues: Array.isArray(parentValues) ? parentValues : [],
|
||||
});
|
||||
|
||||
res.status(201).json({ link });
|
||||
} catch (error: any) {
|
||||
console.error('Create subdirectory error:', error);
|
||||
res.status(400).json({ error: error.message || 'Ошибка создания подсправочника' });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Update a subdirectory link
|
||||
app.patch(['/api/tables/:id/subdirectories/:linkId', '/api/directories/:id/subdirectories/:linkId'],
|
||||
authenticateToken,
|
||||
tenantIsolation,
|
||||
async (req: AuthenticatedRequest, res) => {
|
||||
try {
|
||||
const tableId = parseInt(req.params.id);
|
||||
const linkId = parseInt(req.params.linkId);
|
||||
const table = await storage.getDataTable(tableId, req.organizationId!);
|
||||
if (!table) {
|
||||
return res.status(404).json({ error: 'Таблица не найдена' });
|
||||
}
|
||||
|
||||
const role = await storage.getUserTableRole(tableId, req.user!.id, table.createdBy, req.organizationId!);
|
||||
if (role !== 'admin') {
|
||||
return res.status(403).json({ error: 'Нет прав для управления таблицей' });
|
||||
}
|
||||
|
||||
const existing = await storage.getDataTableLink(linkId, req.organizationId!);
|
||||
if (!existing || existing.parentTableId !== tableId) {
|
||||
return res.status(404).json({ error: 'Связь не найдена' });
|
||||
}
|
||||
|
||||
const { childTableId, parentColumnIndex, childColumnIndex, parentValues } = req.body;
|
||||
const updates: Partial<import("@shared/schema").DataTableLink> = {};
|
||||
if (childTableId !== undefined) updates.childTableId = childTableId;
|
||||
if (parentColumnIndex !== undefined) updates.parentColumnIndex = parentColumnIndex;
|
||||
if (childColumnIndex !== undefined) updates.childColumnIndex = childColumnIndex;
|
||||
if (parentValues !== undefined) updates.parentValues = Array.isArray(parentValues) ? parentValues : [];
|
||||
|
||||
const link = await storage.updateDataTableLink(linkId, req.organizationId!, updates);
|
||||
res.json({ link });
|
||||
} catch (error: any) {
|
||||
console.error('Update subdirectory error:', error);
|
||||
res.status(400).json({ error: error.message || 'Ошибка обновления подсправочника' });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Delete a subdirectory link
|
||||
app.delete(['/api/tables/:id/subdirectories/:linkId', '/api/directories/:id/subdirectories/:linkId'],
|
||||
authenticateToken,
|
||||
tenantIsolation,
|
||||
async (req: AuthenticatedRequest, res) => {
|
||||
try {
|
||||
const tableId = parseInt(req.params.id);
|
||||
const linkId = parseInt(req.params.linkId);
|
||||
const table = await storage.getDataTable(tableId, req.organizationId!);
|
||||
if (!table) {
|
||||
return res.status(404).json({ error: 'Таблица не найдена' });
|
||||
}
|
||||
|
||||
const role = await storage.getUserTableRole(tableId, req.user!.id, table.createdBy, req.organizationId!);
|
||||
if (role !== 'admin') {
|
||||
return res.status(403).json({ error: 'Нет прав для управления таблицей' });
|
||||
}
|
||||
|
||||
const existing = await storage.getDataTableLink(linkId, req.organizationId!);
|
||||
if (!existing || existing.parentTableId !== tableId) {
|
||||
return res.status(404).json({ error: 'Связь не найдена' });
|
||||
}
|
||||
|
||||
await storage.deleteDataTableLink(linkId, req.organizationId!);
|
||||
res.json({ success: true });
|
||||
} catch (error: any) {
|
||||
console.error('Delete subdirectory error:', error);
|
||||
res.status(400).json({ error: error.message || 'Ошибка удаления подсправочника' });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Log data table Excel/CSV export
|
||||
app.post(['/api/tables/:tableId/export', '/api/directories/:tableId/export'],
|
||||
authenticateToken,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { users, dataTables, dataTableRows, dataTablePermissions, dataTableAccessRules, formFields, forms, formAccessRules, roleMembers, type DataTable, type DataTableRow, type DataTablePermission, type InsertDataTable, type InsertDataTableRow, type InsertDataTablePermission, type DataTableFull, type DataTableAccessRule, type InsertDataTableAccessRule } from "@shared/schema";
|
||||
import { users, dataTables, dataTableRows, dataTablePermissions, dataTableAccessRules, dataTableLinks, formFields, forms, formAccessRules, roleMembers, type DataTable, type DataTableRow, type DataTablePermission, type InsertDataTable, type InsertDataTableRow, type InsertDataTablePermission, type DataTableFull, type DataTableAccessRule, type InsertDataTableAccessRule, type DataTableLink, type DataTableSubdirectory } from "@shared/schema";
|
||||
import { db } from "../db";
|
||||
import { eq, and, desc, sql, inArray } from "drizzle-orm";
|
||||
import { BotsStorage } from "./bots.storage";
|
||||
@@ -56,17 +56,53 @@ export class DataTablesCoreStorage extends BotsStorage {
|
||||
return tablesWithAccess;
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// DATA TABLE LINKS (подсправочники)
|
||||
// =====================================================
|
||||
|
||||
async getDataTableLinks(parentTableId: number, organizationId: number): Promise<DataTableSubdirectory[]> {
|
||||
const links = await db
|
||||
.select({
|
||||
id: dataTableLinks.id,
|
||||
organizationId: dataTableLinks.organizationId,
|
||||
parentTableId: dataTableLinks.parentTableId,
|
||||
childTableId: dataTableLinks.childTableId,
|
||||
parentColumnIndex: dataTableLinks.parentColumnIndex,
|
||||
childColumnIndex: dataTableLinks.childColumnIndex,
|
||||
parentValues: dataTableLinks.parentValues,
|
||||
createdAt: dataTableLinks.createdAt,
|
||||
updatedAt: dataTableLinks.updatedAt,
|
||||
childTable: {
|
||||
id: dataTables.id,
|
||||
name: dataTables.name,
|
||||
columns: dataTables.columns,
|
||||
},
|
||||
})
|
||||
.from(dataTableLinks)
|
||||
.innerJoin(dataTables, eq(dataTableLinks.childTableId, dataTables.id))
|
||||
.where(and(
|
||||
eq(dataTableLinks.parentTableId, parentTableId),
|
||||
eq(dataTableLinks.organizationId, organizationId),
|
||||
eq(dataTables.isDeleted, false)
|
||||
))
|
||||
.orderBy(dataTableLinks.id);
|
||||
|
||||
return links as DataTableSubdirectory[];
|
||||
}
|
||||
|
||||
async getDataTableFull(id: number, organizationId: number): Promise<DataTableFull | undefined> {
|
||||
const table = await this.getDataTable(id, organizationId);
|
||||
if (!table) return undefined;
|
||||
|
||||
const rows = await this.getDataTableRows(id, organizationId);
|
||||
const permissions = await this.getDataTablePermissions(id, organizationId);
|
||||
const subdirectories = await this.getDataTableLinks(id, organizationId);
|
||||
|
||||
return {
|
||||
...table,
|
||||
rows,
|
||||
permissions,
|
||||
subdirectories,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -312,6 +348,66 @@ export class DataTablesCoreStorage extends BotsStorage {
|
||||
.where(eq(dataTableRows.tableId, tableId));
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// DATA TABLE LINKS (подсправочники)
|
||||
// =====================================================
|
||||
|
||||
async getDataTableLink(id: number, organizationId: number): Promise<DataTableLink | undefined> {
|
||||
const [link] = await db
|
||||
.select()
|
||||
.from(dataTableLinks)
|
||||
.where(and(
|
||||
eq(dataTableLinks.id, id),
|
||||
eq(dataTableLinks.organizationId, organizationId)
|
||||
));
|
||||
return link || undefined;
|
||||
}
|
||||
|
||||
async createDataTableLink(data: { organizationId: number; parentTableId: number; childTableId: number; parentColumnIndex?: number; childColumnIndex?: number; parentValues?: string[] }): Promise<DataTableLink> {
|
||||
const [link] = await db
|
||||
.insert(dataTableLinks)
|
||||
.values({
|
||||
organizationId: data.organizationId,
|
||||
parentTableId: data.parentTableId,
|
||||
childTableId: data.childTableId,
|
||||
parentColumnIndex: data.parentColumnIndex ?? 0,
|
||||
childColumnIndex: data.childColumnIndex ?? 0,
|
||||
parentValues: data.parentValues ?? [],
|
||||
})
|
||||
.onConflictDoUpdate({
|
||||
target: [dataTableLinks.parentTableId, dataTableLinks.childTableId],
|
||||
set: {
|
||||
parentColumnIndex: data.parentColumnIndex ?? 0,
|
||||
childColumnIndex: data.childColumnIndex ?? 0,
|
||||
parentValues: data.parentValues ?? [],
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
})
|
||||
.returning();
|
||||
return link;
|
||||
}
|
||||
|
||||
async updateDataTableLink(id: number, organizationId: number, updates: Partial<DataTableLink>): Promise<DataTableLink> {
|
||||
const [link] = await db
|
||||
.update(dataTableLinks)
|
||||
.set({ ...updates, updatedAt: new Date() })
|
||||
.where(and(
|
||||
eq(dataTableLinks.id, id),
|
||||
eq(dataTableLinks.organizationId, organizationId)
|
||||
))
|
||||
.returning();
|
||||
return link;
|
||||
}
|
||||
|
||||
async deleteDataTableLink(id: number, organizationId: number): Promise<void> {
|
||||
await db
|
||||
.delete(dataTableLinks)
|
||||
.where(and(
|
||||
eq(dataTableLinks.id, id),
|
||||
eq(dataTableLinks.organizationId, organizationId)
|
||||
));
|
||||
}
|
||||
|
||||
async applyDataTableSync(
|
||||
tableId: number,
|
||||
deleted: { id: number }[],
|
||||
|
||||
Reference in New Issue
Block a user