Browse Source

文件上传和政策文件

master
ma-zhongxu 10 months ago
parent
commit
cb1a907007
  1. 5
      collector/index.js
  2. 9
      frontend/src/pages/PolicyLibrary/index.jsx
  3. 22
      server/endpoints/system.js
  4. 168
      server/endpoints/workspaces.js
  5. 4
      server/models/documents.js
  6. 1
      server/models/workspace.js
  7. 260
      server/utils/files/index.js

5
collector/index.js

@ -69,6 +69,9 @@ app.post(
console.log("文件名:", filename);
try {
const targetFilename = path
.normalize(filename)
.replace(/^(\.\.(\/|\\|$))+/, "");
const inputPath = path.resolve("./hotdir");
const sourceFile = path.join(inputPath, filename); // 拼接文件路径
console.log("源文件路径:", sourceFile);
@ -87,7 +90,7 @@ app.post(
const fileContentBase64 = fileContent.toString("base64"); // 将文件内容转换为 Base64 字符串
// 处理文件并返回结果
const { success, reason, documents = [] } = await processSingleFile(sourceFile, options);
const { success, reason, documents = [] } = await processSingleFile(targetFilename, options);
response.status(200).json({
filename: sourceFile,

9
frontend/src/pages/PolicyLibrary/index.jsx

@ -48,9 +48,12 @@ function Directory({
useEffect(() => {
async function fetchUsers() {
const nodata = await System.localFiles();
const emo = nodata.items[0].items
setFDataTo(emo)
console.log(2222,emo);
const em0 = nodata.items[0].items
const em1 = nodata.items[1].items
const em2 = nodata.items[2].items
const em = [...em0,...em1,...em2]
setFDataTo(em)
console.log(2222,nodata);
}
fetchUsers();
}, []);

22
server/endpoints/system.js

@ -56,6 +56,7 @@ const {
} = require("../utils/middleware/chatHistoryViewable");
const { simpleSSOEnabled } = require("../utils/middleware/simpleSSOEnabled");
const { TemporaryAuthToken } = require("../models/temporaryAuthToken");
const { DeptUsers } = require("../models/deptUsers");
function systemEndpoints(app) {
if (!app) return;
@ -420,12 +421,29 @@ function systemEndpoints(app) {
}
);
// app.get(
// "/system/local-files",
// [validatedRequest, flexUserRoleValid([ROLES.admin, ROLES.manager])],
// async (_, response) => {
// try {
// const localFiles = await viewLocalFiles();
// response.status(200).json({ localFiles });
// } catch (e) {
// console.error(e.message, e);
// response.sendStatus(500).end();
// }
// }
// );
app.get(
"/system/local-files",
[validatedRequest, flexUserRoleValid([ROLES.admin, ROLES.manager])],
async (_, response) => {
async (request, response) => {
const currUser = await userFromSession(request, response);
const deptusers = DeptUsers.get({ userId: currUser.id });
const deptId = (await deptusers).deptUser.deptId;
try {
const localFiles = await viewLocalFiles();
const localFiles = await viewLocalFiles(deptId);
response.status(200).json({ localFiles });
} catch (e) {
console.error(e.message, e);

168
server/endpoints/workspaces.js

@ -162,87 +162,87 @@ function workspaceEndpoints(app) {
// }
// );
app.post(
"/workspace/:slug/upload",
[
validatedRequest,
flexUserRoleValid([ROLES.admin, ROLES.manager]),
handleFileUpload,
],
async function (request, response) {
try {
const user = await userFromSession(request, response);
const deptUserRecord = await DeptUsers.get({ userId: user.id });
if (!deptUserRecord.deptUser) {
return response.status(500).json({ success: false, error: "没有发现用户组织机构" });
}
const Collector = new CollectorApi();
const { originalname } = request.file;
const processingOnline = await Collector.online();
if (!processingOnline) {
response
.status(500)
.json({
success: false,
error: `Document processing API is not online. Document ${originalname} will not be processed automatically.`,
})
.end();
return;
}
const { success, reason, documents } =
await Collector.processDocument(originalname);
if (!success) {
response.status(500).json({ success: false, error: reason }).end();
return;
}
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// 假设路径字符串
const location = documents[0].location;
// 将路径中的反斜杠替换为正斜杠(可选,但通常更通用)
const unixStylePath = location.replace(/\\/g, '/');
// 找到最后一个目录分隔符的位置
const lastIndex = unixStylePath.lastIndexOf('/');
// 提取文件名
const parsedFileName = unixStylePath.substring(lastIndex + 1);
const fileExtension = path.extname(request.file.path).toLowerCase();
const sourceFile = path.resolve(__dirname, request.file.destination, request.file.originalname);
const targetDir =
process.env.NODE_ENV === "development"
? path.resolve(__dirname, `../../server/storage/localFile`)
: path.resolve(process.env.STORAGE_DIR, `../../server/storage/localFile`);
const newFileName = uuidv4() + fileExtension; // 新文件名
moveAndRenameFile(sourceFile, targetDir, newFileName);
const deptDocData = {
deptId: deptUserRecord.deptUser.deptId,
parsedFileName: parsedFileName,
parsedFilePath: location,
realFileName: originalname,
realFileAlias: newFileName,
realFilePath: targetDir,
};
await DeptDocument.create(deptDocData);
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Collector.log(
`Document ${originalname} uploaded processed and successfully. It is now available in documents.`
);
await Telemetry.sendTelemetry("document_uploaded");
await EventLogs.logEvent(
"document_uploaded",
{
documentName: originalname,
},
response.locals?.user?.id
);
response.status(200).json({ success: true, error: null });
} catch (e) {
console.error(e.message, e);
response.sendStatus(500).end();
}
}
);
// app.post(
// "/workspace/:slug/upload",
// [
// validatedRequest,
// flexUserRoleValid([ROLES.admin, ROLES.manager]),
// handleFileUpload,
// ],
// async function (request, response) {
// try {
// const user = await userFromSession(request, response);
// const deptUserRecord = await DeptUsers.get({ userId: user.id });
// if (!deptUserRecord.deptUser) {
// return response.status(500).json({ success: false, error: "没有发现用户组织机构" });
// }
// const Collector = new CollectorApi();
// const { originalname } = request.file;
// const processingOnline = await Collector.online();
//
// if (!processingOnline) {
// response
// .status(500)
// .json({
// success: false,
// error: `Document processing API is not online. Document ${originalname} will not be processed automatically.`,
// })
// .end();
// return;
// }
//
// const { success, reason, documents } =
// await Collector.processDocument(originalname);
// if (!success) {
// response.status(500).json({ success: false, error: reason }).end();
// return;
// }
// // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// // 假设路径字符串
// const location = documents[0].location;
// // 将路径中的反斜杠替换为正斜杠(可选,但通常更通用)
// const unixStylePath = location.replace(/\\/g, '/');
// // 找到最后一个目录分隔符的位置
// const lastIndex = unixStylePath.lastIndexOf('/');
// // 提取文件名
// const parsedFileName = unixStylePath.substring(lastIndex + 1);
// const fileExtension = path.extname(request.file.path).toLowerCase();
// const sourceFile = path.resolve(__dirname, request.file.destination, request.file.originalname);
// const targetDir =
// process.env.NODE_ENV === "development"
// ? path.resolve(__dirname, `../../server/storage/localFile`)
// : path.resolve(process.env.STORAGE_DIR, `../../server/storage/localFile`);
// const newFileName = uuidv4() + fileExtension; // 新文件名
// moveAndRenameFile(sourceFile, targetDir, newFileName);
// const deptDocData = {
// deptId: deptUserRecord.deptUser.deptId,
// parsedFileName: parsedFileName,
// parsedFilePath: location,
// realFileName: originalname,
// realFileAlias: newFileName,
// realFilePath: targetDir,
// };
// await DeptDocument.create(deptDocData);
// // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Collector.log(
// `Document ${originalname} uploaded processed and successfully. It is now available in documents.`
// );
// await Telemetry.sendTelemetry("document_uploaded");
// await EventLogs.logEvent(
// "document_uploaded",
// {
// documentName: originalname,
// },
// response.locals?.user?.id
// );
// response.status(200).json({ success: true, error: null });
// } catch (e) {
// console.error(e.message, e);
// response.sendStatus(500).end();
// }
// }
// );
@ -255,6 +255,7 @@ function workspaceEndpoints(app) {
],
async function (request, response) {
try {
const user = await userFromSession(request, response);
const deptUserRecord = await DeptUsers.get({ userId: user.id });
if (!deptUserRecord.deptUser) {
return response.status(500).json({ success: false, error: "没有发现用户组织机构" });
@ -314,6 +315,7 @@ function workspaceEndpoints(app) {
realFileName: originalname,
realFileAlias: newFileName,
realFilePath: targetDir,
// parsedFileId: targetDir,
};
await DeptDocument.create(deptDocData);
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@ -395,6 +397,8 @@ function workspaceEndpoints(app) {
? await Workspace.getWithUser(user, { slug })
: await Workspace.get({ slug });
console.log("adds===============", adds);
if (!currWorkspace) {
response.sendStatus(400).end();
return;
@ -539,7 +543,7 @@ function workspaceEndpoints(app) {
const workspace = multiUserMode(response)
? await Workspace.getWithUser(user, { slug })
: await Workspace.get({ slug });
console.log("workspace++++++++++++++++++++++++++++", workspace);
response.status(200).json({ workspace });
} catch (e) {
console.error(e.message, e);

4
server/models/documents.js

@ -89,6 +89,8 @@ const Document = {
for (const path of additions) {
const data = await fileData(path);
console.log("data+++++++++++++++++++++++++++++++++", data);
console.log("path.split(\"/\")+++++++++++++++++++++++++++++++++", path.split("/"));
if (!data) continue;
const docId = uuidv4();
@ -117,6 +119,8 @@ const Document = {
continue;
}
console.log("newDoc+++++++++++++++++++++++++++++++++", newDoc);
try {
await prisma.workspace_documents.create({ data: newDoc });
embedded.push(path);

1
server/models/workspace.js

@ -278,6 +278,7 @@ const Workspace = {
documents: true,
},
});
console.log("0000000000000000000000000000000000000000000000000000000000000000",workspace);
return workspace || null;
} catch (error) {

260
server/utils/files/index.js

@ -3,6 +3,8 @@ const path = require("path");
const { v5: uuidv5 } = require("uuid");
const { Document } = require("../../models/documents");
const { DocumentSyncQueue } = require("../../models/documentSyncQueue");
const { userFromSession } = require("../http");
const { DeptDocument } = require("../../models/deptDocument");
const documentsPath =
process.env.NODE_ENV === "development"
? path.resolve(__dirname, `../../storage/documents`)
@ -24,71 +26,221 @@ async function fileData(filePath = null) {
return JSON.parse(data);
}
async function viewLocalFiles() {
if (!fs.existsSync(documentsPath)) fs.mkdirSync(documentsPath);
const liveSyncAvailable = await DocumentSyncQueue.enabled();
// async function viewLocalFiles() {
// if (!fs.existsSync(documentsPath)) fs.mkdirSync(documentsPath);
// const liveSyncAvailable = await DocumentSyncQueue.enabled();
// const directory = {
// name: "documents",
// type: "folder",
// items: [],
// };
// for (const file of fs.readdirSync(documentsPath)) {
// // console.log("file:", file);
// if (path.extname(file) === ".md") continue;
// const folderPath = path.resolve(documentsPath, file);
// const isFolder = fs.lstatSync(folderPath).isDirectory();
// if (isFolder) {
// const subdocs = {
// name: file,
// type: "folder",
// items: [],
// };
// const subfiles = fs.readdirSync(folderPath);
// const filenames = {};
// for (const subfile of subfiles) {
// if (path.extname(subfile) !== ".json") continue;
// const filePath = path.join(folderPath, subfile);
// const rawData = fs.readFileSync(filePath, "utf8");
// // console.log("rawData:", rawData);
// const cachefilename = `${file}/${subfile}`;
// const { pageContent, ...metadata } = JSON.parse(rawData);
// subdocs.items.push({
// name: subfile,
// type: "file",
// ...metadata,
// cached: await cachedVectorInformation(cachefilename, true),
// canWatch: liveSyncAvailable
// ? DocumentSyncQueue.canWatch(metadata)
// : false,
// // pinnedWorkspaces: [], // This is the list of workspaceIds that have pinned this document
// // watched: false, // boolean to indicate if this document is watched in ANY workspace
// });
// filenames[cachefilename] = subfile;
// }
//
// // Grab the pinned workspaces and watched documents for this folder's documents
// // at the time of the query so we don't have to re-query the database for each file
// const pinnedWorkspacesByDocument =
// await getPinnedWorkspacesByDocument(filenames);
// const watchedDocumentsFilenames =
// await getWatchedDocumentFilenames(filenames);
// for (const item of subdocs.items) {
// item.pinnedWorkspaces = pinnedWorkspacesByDocument[item.name] || [];
// item.watched =
// watchedDocumentsFilenames.hasOwnProperty(item.name) || false;
// }
//
// directory.items.push(subdocs);
// }
// }
//
// // Make sure custom-documents is always the first folder in picker
// directory.items = [
// directory.items.find((folder) => folder.name === "custom-documents"),
// ...directory.items.filter((folder) => folder.name !== "custom-documents"),
// ].filter((i) => !!i);
//
// return directory;
// }
// async function viewLocalFiles(deptId) {
// const directory = {
// name: "documents",
// type: "folder",
// items: [],
// };
// if (!fs.existsSync(documentsPath)) fs.mkdirSync(documentsPath);
// const liveSyncAvailable = await DocumentSyncQueue.enabled();
//
// // 查询 deptDocuments
// const deptDocuments = await DeptDocument.where({ deptId: deptId, delTag: false });
// if (!deptDocuments || deptDocuments.length === 0) {
// return directory;
// }
//
// // 初始化分类对象
// const publicd = {
// name: "公开",
// type: "folder",
// items: [],
// };
// const privated = {
// name: "私有",
// type: "folder",
// items: [],
// };
// const temp = {
// name: "临时",
// type: "folder",
// items: [],
// };
//
// // 遍历 deptDocuments
// for (const doc of deptDocuments) {
// try {
// const filePath = doc.parsedFilePath; // 获取文件路径
// if (!fs.existsSync(filePath)) continue; // 如果文件不存在,跳过
//
// // 读取文件内容
// const rawData = fs.readFileSync(filePath, 'utf8');
// const { pageContent, ...metadata } = JSON.parse(rawData);
//
// // 构造文件信息对象(保持与原方法一致的字段)
// const fileInfo = {
// name: path.basename(filePath), // 文件名
// type: "file",
// ...metadata,
// cached: await cachedVectorInformation(filePath, true),
// canWatch: liveSyncAvailable
// ? DocumentSyncQueue.canWatch(metadata)
// : false,
// pinnedWorkspaces: [], // 初始化为空数组
// watched: false, // 初始化为 false
// };
//
// // 根据 isPublic 属性分类
// if (doc.isPublic === 0) {
// publicd.items.push(fileInfo);
// } else if (doc.isPublic === 1) {
// privated.items.push(fileInfo);
// } else {
// temp.items.push(fileInfo);
// }
// } catch (error) {
// console.error(`Error processing file ${doc.parsedFilePath}:`, error);
// }
// }
//
// directory.items = [publicd, privated, temp];
// // 返回嵌套结构
// return directory;
// }
async function viewLocalFiles(deptId) {
const directory = {
name: "documents",
type: "folder",
items: [],
};
// console.log("111111111111111111111111111111111111111111111111111111111111111111111111111111111");
for (const file of fs.readdirSync(documentsPath)) {
// console.log("file:", file);
if (path.extname(file) === ".md") continue;
const folderPath = path.resolve(documentsPath, file);
const isFolder = fs.lstatSync(folderPath).isDirectory();
if (isFolder) {
const subdocs = {
name: file,
type: "folder",
items: [],
if (!fs.existsSync(documentsPath)) fs.mkdirSync(documentsPath);
const liveSyncAvailable = await DocumentSyncQueue.enabled();
// 查询 deptDocuments
const deptDocuments = await DeptDocument.where({ deptId: deptId, delTag: false });
if (!deptDocuments || deptDocuments.length === 0) {
return directory;
}
// 初始化分类对象
const publicd = {
name: "公开",
type: "folder",
items: [],
};
const privated = {
name: "私有",
type: "folder",
items: [],
};
const temp = {
name: "临时",
type: "folder",
items: [],
};
// 遍历 deptDocuments
for (const doc of deptDocuments) {
try {
const filePath = doc.parsedFilePath; // 获取文件路径
if (!fs.existsSync(filePath)) continue; // 如果文件不存在,跳过
// 读取文件内容
const rawData = fs.readFileSync(filePath, 'utf8');
const { pageContent, ...metadata } = JSON.parse(rawData);
// 计算相对路径,并将路径分隔符统一为 `/`
const relativePath = path.relative(documentsPath, filePath).replace(/\\/g, '/');
// 构造文件信息对象(保持与原方法一致的字段)
const fileInfo = {
name: path.basename(filePath), // 文件名
type: "file",
...metadata,
cached: await cachedVectorInformation(filePath, true),
canWatch: liveSyncAvailable
? DocumentSyncQueue.canWatch(metadata)
: false,
pinnedWorkspaces: [], // 初始化为空数组
watched: false, // 初始化为 false
relativePath: relativePath, // 新增字段:相对路径(使用 `/` 分隔符)
};
const subfiles = fs.readdirSync(folderPath);
const filenames = {};
for (const subfile of subfiles) {
if (path.extname(subfile) !== ".json") continue;
const filePath = path.join(folderPath, subfile);
const rawData = fs.readFileSync(filePath, "utf8");
// console.log("rawData:", rawData);
const cachefilename = `${file}/${subfile}`;
const { pageContent, ...metadata } = JSON.parse(rawData);
subdocs.items.push({
name: subfile,
type: "file",
...metadata,
cached: await cachedVectorInformation(cachefilename, true),
canWatch: liveSyncAvailable
? DocumentSyncQueue.canWatch(metadata)
: false,
// pinnedWorkspaces: [], // This is the list of workspaceIds that have pinned this document
// watched: false, // boolean to indicate if this document is watched in ANY workspace
});
filenames[cachefilename] = subfile;
}
// Grab the pinned workspaces and watched documents for this folder's documents
// at the time of the query so we don't have to re-query the database for each file
const pinnedWorkspacesByDocument =
await getPinnedWorkspacesByDocument(filenames);
const watchedDocumentsFilenames =
await getWatchedDocumentFilenames(filenames);
for (const item of subdocs.items) {
item.pinnedWorkspaces = pinnedWorkspacesByDocument[item.name] || [];
item.watched =
watchedDocumentsFilenames.hasOwnProperty(item.name) || false;
// 根据 isPublic 属性分类
if (doc.isPublic === 0) {
publicd.items.push(fileInfo);
} else if (doc.isPublic === 1) {
privated.items.push(fileInfo);
} else {
temp.items.push(fileInfo);
}
directory.items.push(subdocs);
} catch (error) {
console.error(`Error processing file ${doc.parsedFilePath}:`, error);
}
}
// Make sure custom-documents is always the first folder in picker
directory.items = [
directory.items.find((folder) => folder.name === "custom-documents"),
...directory.items.filter((folder) => folder.name !== "custom-documents"),
].filter((i) => !!i);
directory.items = [publicd, privated, temp];
// 返回嵌套结构
return directory;
}

Loading…
Cancel
Save