mirror of
https://github.com/zadam/trilium.git
synced 2025-12-05 15:04:24 +01:00
fix(fs_sync): cls errors in router
This commit is contained in:
parent
3da6838395
commit
15bd5aa4e4
@ -1,6 +1,5 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import express from "express";
|
|
||||||
import becca from "../../becca/becca.js";
|
import becca from "../../becca/becca.js";
|
||||||
import BFileSystemMapping from "../../becca/entities/bfile_system_mapping.js";
|
import BFileSystemMapping from "../../becca/entities/bfile_system_mapping.js";
|
||||||
import fileSystemSyncInit from "../../services/file_system_sync_init.js";
|
import fileSystemSyncInit from "../../services/file_system_sync_init.js";
|
||||||
@ -8,8 +7,7 @@ import log from "../../services/log.js";
|
|||||||
import ValidationError from "../../errors/validation_error.js";
|
import ValidationError from "../../errors/validation_error.js";
|
||||||
import fs from "fs-extra";
|
import fs from "fs-extra";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
|
import { router, asyncApiRoute, apiRoute } from "../route_api.js";
|
||||||
const router = express.Router();
|
|
||||||
|
|
||||||
interface FileStat {
|
interface FileStat {
|
||||||
isFile: boolean;
|
isFile: boolean;
|
||||||
@ -19,348 +17,281 @@ interface FileStat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get all file system mappings
|
// Get all file system mappings
|
||||||
router.get("/mappings", (req, res) => {
|
apiRoute("get", "/mappings", () => {
|
||||||
try {
|
const mappings = Object.values(becca.fileSystemMappings || {}).map(mapping => ({
|
||||||
const mappings = Object.values(becca.fileSystemMappings || {}).map(mapping => ({
|
mappingId: mapping.mappingId,
|
||||||
mappingId: mapping.mappingId,
|
noteId: mapping.noteId,
|
||||||
noteId: mapping.noteId,
|
filePath: mapping.filePath,
|
||||||
filePath: mapping.filePath,
|
syncDirection: mapping.syncDirection,
|
||||||
syncDirection: mapping.syncDirection,
|
isActive: mapping.isActive,
|
||||||
isActive: mapping.isActive,
|
includeSubtree: mapping.includeSubtree,
|
||||||
includeSubtree: mapping.includeSubtree,
|
preserveHierarchy: mapping.preserveHierarchy,
|
||||||
preserveHierarchy: mapping.preserveHierarchy,
|
contentFormat: mapping.contentFormat,
|
||||||
contentFormat: mapping.contentFormat,
|
excludePatterns: mapping.excludePatterns,
|
||||||
excludePatterns: mapping.excludePatterns,
|
lastSyncTime: mapping.lastSyncTime,
|
||||||
lastSyncTime: mapping.lastSyncTime,
|
syncErrors: mapping.syncErrors,
|
||||||
syncErrors: mapping.syncErrors,
|
dateCreated: mapping.dateCreated,
|
||||||
dateCreated: mapping.dateCreated,
|
dateModified: mapping.dateModified
|
||||||
dateModified: mapping.dateModified
|
}));
|
||||||
}));
|
|
||||||
|
|
||||||
res.json(mappings);
|
return mappings;
|
||||||
} catch (error) {
|
|
||||||
log.error(`Error getting file system mappings: ${error}`);
|
|
||||||
res.status(500).json({ error: "Failed to get file system mappings" });
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get a specific file system mapping
|
// Get a specific file system mapping
|
||||||
router.get("/mappings/:mappingId", (req, res) => {
|
apiRoute("get", "/mappings/:mappingId", (req) => {
|
||||||
try {
|
const { mappingId } = req.params;
|
||||||
const { mappingId } = req.params;
|
const mapping = becca.fileSystemMappings[mappingId];
|
||||||
const mapping = becca.fileSystemMappings[mappingId];
|
|
||||||
|
|
||||||
if (!mapping) {
|
if (!mapping) {
|
||||||
return res.status(404).json({ error: "Mapping not found" });
|
return [404, { error: "Mapping not found" }];
|
||||||
}
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
mappingId: mapping.mappingId,
|
|
||||||
noteId: mapping.noteId,
|
|
||||||
filePath: mapping.filePath,
|
|
||||||
syncDirection: mapping.syncDirection,
|
|
||||||
isActive: mapping.isActive,
|
|
||||||
includeSubtree: mapping.includeSubtree,
|
|
||||||
preserveHierarchy: mapping.preserveHierarchy,
|
|
||||||
contentFormat: mapping.contentFormat,
|
|
||||||
excludePatterns: mapping.excludePatterns,
|
|
||||||
lastSyncTime: mapping.lastSyncTime,
|
|
||||||
syncErrors: mapping.syncErrors,
|
|
||||||
dateCreated: mapping.dateCreated,
|
|
||||||
dateModified: mapping.dateModified
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
log.error(`Error getting file system mapping: ${error}`);
|
|
||||||
res.status(500).json({ error: "Failed to get file system mapping" });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
mappingId: mapping.mappingId,
|
||||||
|
noteId: mapping.noteId,
|
||||||
|
filePath: mapping.filePath,
|
||||||
|
syncDirection: mapping.syncDirection,
|
||||||
|
isActive: mapping.isActive,
|
||||||
|
includeSubtree: mapping.includeSubtree,
|
||||||
|
preserveHierarchy: mapping.preserveHierarchy,
|
||||||
|
contentFormat: mapping.contentFormat,
|
||||||
|
excludePatterns: mapping.excludePatterns,
|
||||||
|
lastSyncTime: mapping.lastSyncTime,
|
||||||
|
syncErrors: mapping.syncErrors,
|
||||||
|
dateCreated: mapping.dateCreated,
|
||||||
|
dateModified: mapping.dateModified
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create a new file system mapping
|
// Create a new file system mapping
|
||||||
router.post("/mappings", async (req, res) => {
|
asyncApiRoute("post", "/mappings", async (req) => {
|
||||||
try {
|
const {
|
||||||
const {
|
noteId,
|
||||||
noteId,
|
filePath,
|
||||||
filePath,
|
syncDirection = 'bidirectional',
|
||||||
syncDirection = 'bidirectional',
|
isActive = true,
|
||||||
isActive = true,
|
includeSubtree = false,
|
||||||
includeSubtree = false,
|
preserveHierarchy = true,
|
||||||
preserveHierarchy = true,
|
contentFormat = 'auto',
|
||||||
contentFormat = 'auto',
|
excludePatterns = null
|
||||||
excludePatterns = null
|
} = req.body;
|
||||||
} = req.body;
|
|
||||||
|
|
||||||
// Validate required fields
|
// Validate required fields
|
||||||
if (!noteId || !filePath) {
|
if (!noteId || !filePath) {
|
||||||
throw new ValidationError("noteId and filePath are required");
|
throw new ValidationError("noteId and filePath are required");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate note exists
|
// Validate note exists
|
||||||
const note = becca.notes[noteId];
|
const note = becca.notes[noteId];
|
||||||
if (!note) {
|
if (!note) {
|
||||||
throw new ValidationError(`Note ${noteId} not found`);
|
throw new ValidationError(`Note ${noteId} not found`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if mapping already exists for this note
|
// Check if mapping already exists for this note
|
||||||
const existingMapping = becca.getFileSystemMappingByNoteId(noteId);
|
const existingMapping = becca.getFileSystemMappingByNoteId(noteId);
|
||||||
if (existingMapping) {
|
if (existingMapping) {
|
||||||
throw new ValidationError(`File system mapping already exists for note ${noteId}`);
|
throw new ValidationError(`File system mapping already exists for note ${noteId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate file path exists
|
// Validate file path exists
|
||||||
|
const normalizedPath = path.resolve(filePath);
|
||||||
|
if (!await fs.pathExists(normalizedPath)) {
|
||||||
|
throw new ValidationError(`File path does not exist: ${normalizedPath}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate sync direction
|
||||||
|
const validDirections = ['bidirectional', 'trilium_to_disk', 'disk_to_trilium'];
|
||||||
|
if (!validDirections.includes(syncDirection)) {
|
||||||
|
throw new ValidationError(`Invalid sync direction. Must be one of: ${validDirections.join(', ')}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate content format
|
||||||
|
const validFormats = ['auto', 'markdown', 'html', 'raw'];
|
||||||
|
if (!validFormats.includes(contentFormat)) {
|
||||||
|
throw new ValidationError(`Invalid content format. Must be one of: ${validFormats.join(', ')}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the mapping
|
||||||
|
const mapping = new BFileSystemMapping({
|
||||||
|
noteId,
|
||||||
|
filePath: normalizedPath,
|
||||||
|
syncDirection,
|
||||||
|
isActive: isActive ? 1 : 0,
|
||||||
|
includeSubtree: includeSubtree ? 1 : 0,
|
||||||
|
preserveHierarchy: preserveHierarchy ? 1 : 0,
|
||||||
|
contentFormat,
|
||||||
|
excludePatterns: Array.isArray(excludePatterns) ? JSON.stringify(excludePatterns) : excludePatterns
|
||||||
|
}).save();
|
||||||
|
|
||||||
|
log.info(`Created file system mapping ${mapping.mappingId} for note ${noteId} -> ${normalizedPath}`);
|
||||||
|
|
||||||
|
return [201, {
|
||||||
|
mappingId: mapping.mappingId,
|
||||||
|
noteId: mapping.noteId,
|
||||||
|
filePath: mapping.filePath,
|
||||||
|
syncDirection: mapping.syncDirection,
|
||||||
|
isActive: mapping.isActive,
|
||||||
|
includeSubtree: mapping.includeSubtree,
|
||||||
|
preserveHierarchy: mapping.preserveHierarchy,
|
||||||
|
contentFormat: mapping.contentFormat,
|
||||||
|
excludePatterns: mapping.excludePatterns
|
||||||
|
}];
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update a file system mapping
|
||||||
|
asyncApiRoute("put", "/mappings/:mappingId", async (req) => {
|
||||||
|
const { mappingId } = req.params;
|
||||||
|
const mapping = becca.fileSystemMappings[mappingId];
|
||||||
|
|
||||||
|
if (!mapping) {
|
||||||
|
return [404, { error: "Mapping not found" }];
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
filePath,
|
||||||
|
syncDirection,
|
||||||
|
isActive,
|
||||||
|
includeSubtree,
|
||||||
|
preserveHierarchy,
|
||||||
|
contentFormat,
|
||||||
|
excludePatterns
|
||||||
|
} = req.body;
|
||||||
|
|
||||||
|
// Update fields if provided
|
||||||
|
if (filePath !== undefined) {
|
||||||
const normalizedPath = path.resolve(filePath);
|
const normalizedPath = path.resolve(filePath);
|
||||||
if (!await fs.pathExists(normalizedPath)) {
|
if (!await fs.pathExists(normalizedPath)) {
|
||||||
throw new ValidationError(`File path does not exist: ${normalizedPath}`);
|
throw new ValidationError(`File path does not exist: ${normalizedPath}`);
|
||||||
}
|
}
|
||||||
|
mapping.filePath = normalizedPath;
|
||||||
|
}
|
||||||
|
|
||||||
// Validate sync direction
|
if (syncDirection !== undefined) {
|
||||||
const validDirections = ['bidirectional', 'trilium_to_disk', 'disk_to_trilium'];
|
const validDirections = ['bidirectional', 'trilium_to_disk', 'disk_to_trilium'];
|
||||||
if (!validDirections.includes(syncDirection)) {
|
if (!validDirections.includes(syncDirection)) {
|
||||||
throw new ValidationError(`Invalid sync direction. Must be one of: ${validDirections.join(', ')}`);
|
throw new ValidationError(`Invalid sync direction. Must be one of: ${validDirections.join(', ')}`);
|
||||||
}
|
}
|
||||||
|
mapping.syncDirection = syncDirection;
|
||||||
|
}
|
||||||
|
|
||||||
// Validate content format
|
if (isActive !== undefined) {
|
||||||
|
mapping.isActive = !!isActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (includeSubtree !== undefined) {
|
||||||
|
mapping.includeSubtree = !!includeSubtree;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preserveHierarchy !== undefined) {
|
||||||
|
mapping.preserveHierarchy = !!preserveHierarchy;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contentFormat !== undefined) {
|
||||||
const validFormats = ['auto', 'markdown', 'html', 'raw'];
|
const validFormats = ['auto', 'markdown', 'html', 'raw'];
|
||||||
if (!validFormats.includes(contentFormat)) {
|
if (!validFormats.includes(contentFormat)) {
|
||||||
throw new ValidationError(`Invalid content format. Must be one of: ${validFormats.join(', ')}`);
|
throw new ValidationError(`Invalid content format. Must be one of: ${validFormats.join(', ')}`);
|
||||||
}
|
}
|
||||||
|
mapping.contentFormat = contentFormat;
|
||||||
// Create the mapping
|
|
||||||
const mapping = new BFileSystemMapping({
|
|
||||||
noteId,
|
|
||||||
filePath: normalizedPath,
|
|
||||||
syncDirection,
|
|
||||||
isActive: isActive ? 1 : 0,
|
|
||||||
includeSubtree: includeSubtree ? 1 : 0,
|
|
||||||
preserveHierarchy: preserveHierarchy ? 1 : 0,
|
|
||||||
contentFormat,
|
|
||||||
excludePatterns: Array.isArray(excludePatterns) ? JSON.stringify(excludePatterns) : excludePatterns
|
|
||||||
}).save();
|
|
||||||
|
|
||||||
log.info(`Created file system mapping ${mapping.mappingId} for note ${noteId} -> ${normalizedPath}`);
|
|
||||||
|
|
||||||
res.status(201).json({
|
|
||||||
mappingId: mapping.mappingId,
|
|
||||||
noteId: mapping.noteId,
|
|
||||||
filePath: mapping.filePath,
|
|
||||||
syncDirection: mapping.syncDirection,
|
|
||||||
isActive: mapping.isActive,
|
|
||||||
includeSubtree: mapping.includeSubtree,
|
|
||||||
preserveHierarchy: mapping.preserveHierarchy,
|
|
||||||
contentFormat: mapping.contentFormat,
|
|
||||||
excludePatterns: mapping.excludePatterns
|
|
||||||
});
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof ValidationError) {
|
|
||||||
res.status(400).json({ error: error.message });
|
|
||||||
} else {
|
|
||||||
log.error(`Error creating file system mapping: ${error}`);
|
|
||||||
res.status(500).json({ error: "Failed to create file system mapping" });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
// Update a file system mapping
|
if (excludePatterns !== undefined) {
|
||||||
router.put("/mappings/:mappingId", async (req, res) => {
|
mapping.excludePatterns = Array.isArray(excludePatterns) ? excludePatterns : null;
|
||||||
try {
|
|
||||||
const { mappingId } = req.params;
|
|
||||||
const mapping = becca.fileSystemMappings[mappingId];
|
|
||||||
|
|
||||||
if (!mapping) {
|
|
||||||
return res.status(404).json({ error: "Mapping not found" });
|
|
||||||
}
|
|
||||||
|
|
||||||
const {
|
|
||||||
filePath,
|
|
||||||
syncDirection,
|
|
||||||
isActive,
|
|
||||||
includeSubtree,
|
|
||||||
preserveHierarchy,
|
|
||||||
contentFormat,
|
|
||||||
excludePatterns
|
|
||||||
} = req.body;
|
|
||||||
|
|
||||||
// Update fields if provided
|
|
||||||
if (filePath !== undefined) {
|
|
||||||
const normalizedPath = path.resolve(filePath);
|
|
||||||
if (!await fs.pathExists(normalizedPath)) {
|
|
||||||
throw new ValidationError(`File path does not exist: ${normalizedPath}`);
|
|
||||||
}
|
|
||||||
mapping.filePath = normalizedPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (syncDirection !== undefined) {
|
|
||||||
const validDirections = ['bidirectional', 'trilium_to_disk', 'disk_to_trilium'];
|
|
||||||
if (!validDirections.includes(syncDirection)) {
|
|
||||||
throw new ValidationError(`Invalid sync direction. Must be one of: ${validDirections.join(', ')}`);
|
|
||||||
}
|
|
||||||
mapping.syncDirection = syncDirection;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isActive !== undefined) {
|
|
||||||
mapping.isActive = !!isActive;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (includeSubtree !== undefined) {
|
|
||||||
mapping.includeSubtree = !!includeSubtree;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (preserveHierarchy !== undefined) {
|
|
||||||
mapping.preserveHierarchy = !!preserveHierarchy;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (contentFormat !== undefined) {
|
|
||||||
const validFormats = ['auto', 'markdown', 'html', 'raw'];
|
|
||||||
if (!validFormats.includes(contentFormat)) {
|
|
||||||
throw new ValidationError(`Invalid content format. Must be one of: ${validFormats.join(', ')}`);
|
|
||||||
}
|
|
||||||
mapping.contentFormat = contentFormat;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (excludePatterns !== undefined) {
|
|
||||||
mapping.excludePatterns = Array.isArray(excludePatterns) ? excludePatterns : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
mapping.save();
|
|
||||||
|
|
||||||
log.info(`Updated file system mapping ${mappingId}`);
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
mappingId: mapping.mappingId,
|
|
||||||
noteId: mapping.noteId,
|
|
||||||
filePath: mapping.filePath,
|
|
||||||
syncDirection: mapping.syncDirection,
|
|
||||||
isActive: mapping.isActive,
|
|
||||||
includeSubtree: mapping.includeSubtree,
|
|
||||||
preserveHierarchy: mapping.preserveHierarchy,
|
|
||||||
contentFormat: mapping.contentFormat,
|
|
||||||
excludePatterns: mapping.excludePatterns
|
|
||||||
});
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof ValidationError) {
|
|
||||||
res.status(400).json({ error: error.message });
|
|
||||||
} else {
|
|
||||||
log.error(`Error updating file system mapping: ${error}`);
|
|
||||||
res.status(500).json({ error: "Failed to update file system mapping" });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mapping.save();
|
||||||
|
|
||||||
|
log.info(`Updated file system mapping ${mappingId}`);
|
||||||
|
|
||||||
|
return {
|
||||||
|
mappingId: mapping.mappingId,
|
||||||
|
noteId: mapping.noteId,
|
||||||
|
filePath: mapping.filePath,
|
||||||
|
syncDirection: mapping.syncDirection,
|
||||||
|
isActive: mapping.isActive,
|
||||||
|
includeSubtree: mapping.includeSubtree,
|
||||||
|
preserveHierarchy: mapping.preserveHierarchy,
|
||||||
|
contentFormat: mapping.contentFormat,
|
||||||
|
excludePatterns: mapping.excludePatterns
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// Delete a file system mapping
|
// Delete a file system mapping
|
||||||
router.delete("/mappings/:mappingId", (req, res) => {
|
apiRoute("delete", "/mappings/:mappingId", (req) => {
|
||||||
try {
|
const { mappingId } = req.params;
|
||||||
const { mappingId } = req.params;
|
const mapping = becca.fileSystemMappings[mappingId];
|
||||||
const mapping = becca.fileSystemMappings[mappingId];
|
|
||||||
|
|
||||||
if (!mapping) {
|
if (!mapping) {
|
||||||
return res.status(404).json({ error: "Mapping not found" });
|
return [404, { error: "Mapping not found" }];
|
||||||
}
|
|
||||||
|
|
||||||
mapping.markAsDeleted();
|
|
||||||
|
|
||||||
log.info(`Deleted file system mapping ${mappingId}`);
|
|
||||||
|
|
||||||
res.json({ success: true });
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
log.error(`Error deleting file system mapping: ${error}`);
|
|
||||||
res.status(500).json({ error: "Failed to delete file system mapping" });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mapping.markAsDeleted();
|
||||||
|
|
||||||
|
log.info(`Deleted file system mapping ${mappingId}`);
|
||||||
|
|
||||||
|
return { success: true };
|
||||||
});
|
});
|
||||||
|
|
||||||
// Trigger full sync for a mapping
|
// Trigger full sync for a mapping
|
||||||
router.post("/mappings/:mappingId/sync", async (req, res) => {
|
asyncApiRoute("post", "/mappings/:mappingId/sync", async (req) => {
|
||||||
try {
|
const { mappingId } = req.params;
|
||||||
const { mappingId } = req.params;
|
|
||||||
|
|
||||||
if (!fileSystemSyncInit.isInitialized()) {
|
if (!fileSystemSyncInit.isInitialized()) {
|
||||||
return res.status(503).json({ error: "File system sync is not initialized" });
|
return [503, { error: "File system sync is not initialized" }];
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await fileSystemSyncInit.fullSync(mappingId);
|
const result = await fileSystemSyncInit.fullSync(mappingId);
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
res.json(result);
|
return result;
|
||||||
} else {
|
} else {
|
||||||
res.status(400).json(result);
|
return [400, result];
|
||||||
}
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
log.error(`Error triggering sync: ${error}`);
|
|
||||||
res.status(500).json({ error: "Failed to trigger sync" });
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get sync status for all mappings
|
// Get sync status for all mappings
|
||||||
router.get("/status", (req, res) => {
|
apiRoute("get", "/status", () => {
|
||||||
try {
|
return fileSystemSyncInit.getStatus();
|
||||||
const status = fileSystemSyncInit.getStatus();
|
|
||||||
res.json(status);
|
|
||||||
} catch (error) {
|
|
||||||
log.error(`Error getting sync status: ${error}`);
|
|
||||||
res.status(500).json({ error: "Failed to get sync status" });
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Enable/disable file system sync
|
// Enable file system sync
|
||||||
router.post("/enable", async (req, res) => {
|
asyncApiRoute("post", "/enable", async () => {
|
||||||
try {
|
await fileSystemSyncInit.enable();
|
||||||
await fileSystemSyncInit.enable();
|
return { success: true, message: "File system sync enabled" };
|
||||||
res.json({ success: true, message: "File system sync enabled" });
|
|
||||||
} catch (error) {
|
|
||||||
log.error(`Error enabling file system sync: ${error}`);
|
|
||||||
res.status(500).json({ error: "Failed to enable file system sync" });
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post("/disable", async (req, res) => {
|
// Disable file system sync
|
||||||
try {
|
asyncApiRoute("post", "/disable", async () => {
|
||||||
await fileSystemSyncInit.disable();
|
await fileSystemSyncInit.disable();
|
||||||
res.json({ success: true, message: "File system sync disabled" });
|
return { success: true, message: "File system sync disabled" };
|
||||||
} catch (error) {
|
|
||||||
log.error(`Error disabling file system sync: ${error}`);
|
|
||||||
res.status(500).json({ error: "Failed to disable file system sync" });
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Validate file path
|
// Validate file path
|
||||||
router.post("/validate-path", async (req, res) => {
|
asyncApiRoute("post", "/validate-path", async (req) => {
|
||||||
try {
|
const { filePath } = req.body;
|
||||||
const { filePath } = req.body;
|
|
||||||
|
|
||||||
if (!filePath) {
|
if (!filePath) {
|
||||||
throw new ValidationError("filePath is required");
|
throw new ValidationError("filePath is required");
|
||||||
}
|
|
||||||
|
|
||||||
const normalizedPath = path.resolve(filePath);
|
|
||||||
const exists = await fs.pathExists(normalizedPath);
|
|
||||||
|
|
||||||
let stats: FileStat | null = null;
|
|
||||||
if (exists) {
|
|
||||||
const fileStats = await fs.stat(normalizedPath);
|
|
||||||
stats = {
|
|
||||||
isFile: fileStats.isFile(),
|
|
||||||
isDirectory: fileStats.isDirectory(),
|
|
||||||
size: fileStats.size,
|
|
||||||
modified: fileStats.mtime.toISOString()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
path: normalizedPath,
|
|
||||||
exists,
|
|
||||||
stats
|
|
||||||
});
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof ValidationError) {
|
|
||||||
res.status(400).json({ error: error.message });
|
|
||||||
} else {
|
|
||||||
log.error(`Error validating file path: ${error}`);
|
|
||||||
res.status(500).json({ error: "Failed to validate file path" });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const normalizedPath = path.resolve(filePath);
|
||||||
|
const exists = await fs.pathExists(normalizedPath);
|
||||||
|
|
||||||
|
let stats: FileStat | null = null;
|
||||||
|
if (exists) {
|
||||||
|
const fileStats = await fs.stat(normalizedPath);
|
||||||
|
stats = {
|
||||||
|
isFile: fileStats.isFile(),
|
||||||
|
isDirectory: fileStats.isDirectory(),
|
||||||
|
size: fileStats.size,
|
||||||
|
modified: fileStats.mtime.toISOString()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
path: normalizedPath,
|
||||||
|
exists,
|
||||||
|
stats
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user