mirror of
https://github.com/Mintplex-Labs/anything-llm.git
synced 2024-11-19 12:40:09 +01:00
29df483a27
* initial commit for chrome extension * wip browser extension backend * wip frontend browser extension settings * fix typo for browserExtension route * implement verification codes + frontend panel for browser extension keys * reorganize + state management for all connection states * implement embed to workspace * add send page to anythingllm extension option + refactor * refactor connection string auth + update context menus + organize background.js into models * popup extension from main app and save if successful * fix hebrew translation misspelling * fetch custom logo inside chrome extension * delete api keys on disconnect of extension * use correct apiUrl constant in frontend + remove unneeded comments * remove upload-link endpoint and send inner text html to raw text collector endpoint * update readme * fix readme link * fix readme typo * update readme * handle deletion of browser keys with key id and DELETE endpoint * move event string to constant * remove tablename and writable fields from BrowserExtensionApiKey backend model * add border-none to all buttons and inputs for desktop compatibility * patch prisma injections * update delete endpoints to delete keys by id * remove unused prop * add button to attempt browser extension connection + remove max active keys * wip multi user mode support * multi user mode support * clean up backend + show created by in frotend browser extension page * show multi user warning message on key creation + hide context menus when no workspaces * show browser extension options to managers * small backend changes and refactors * extension cleanup * rename submodule * extension updates & docs * dev docker build --------- Co-authored-by: shatfield4 <seanhatfield5@gmail.com>
225 lines
6.8 KiB
JavaScript
225 lines
6.8 KiB
JavaScript
const { Workspace } = require("../models/workspace");
|
|
const { BrowserExtensionApiKey } = require("../models/browserExtensionApiKey");
|
|
const { Document } = require("../models/documents");
|
|
const {
|
|
validBrowserExtensionApiKey,
|
|
} = require("../utils/middleware/validBrowserExtensionApiKey");
|
|
const { CollectorApi } = require("../utils/collectorApi");
|
|
const { reqBody, multiUserMode, userFromSession } = require("../utils/http");
|
|
const { validatedRequest } = require("../utils/middleware/validatedRequest");
|
|
const {
|
|
flexUserRoleValid,
|
|
ROLES,
|
|
} = require("../utils/middleware/multiUserProtected");
|
|
const { Telemetry } = require("../models/telemetry");
|
|
|
|
function browserExtensionEndpoints(app) {
|
|
if (!app) return;
|
|
|
|
app.get(
|
|
"/browser-extension/check",
|
|
[validBrowserExtensionApiKey],
|
|
async (request, response) => {
|
|
try {
|
|
const user = await userFromSession(request, response);
|
|
const workspaces = multiUserMode(response)
|
|
? await Workspace.whereWithUser(user)
|
|
: await Workspace.where();
|
|
|
|
const apiKeyId = response.locals.apiKey.id;
|
|
response.status(200).json({
|
|
connected: true,
|
|
workspaces,
|
|
apiKeyId,
|
|
});
|
|
} catch (error) {
|
|
console.error(error);
|
|
response
|
|
.status(500)
|
|
.json({ connected: false, error: "Failed to fetch workspaces" });
|
|
}
|
|
}
|
|
);
|
|
|
|
app.delete(
|
|
"/browser-extension/disconnect",
|
|
[validBrowserExtensionApiKey],
|
|
async (_request, response) => {
|
|
try {
|
|
const apiKeyId = response.locals.apiKey.id;
|
|
const { success, error } =
|
|
await BrowserExtensionApiKey.delete(apiKeyId);
|
|
if (!success) throw new Error(error);
|
|
response.status(200).json({ success: true });
|
|
} catch (error) {
|
|
console.error(error);
|
|
response
|
|
.status(500)
|
|
.json({ error: "Failed to disconnect and revoke API key" });
|
|
}
|
|
}
|
|
);
|
|
|
|
app.get(
|
|
"/browser-extension/workspaces",
|
|
[validBrowserExtensionApiKey],
|
|
async (request, response) => {
|
|
try {
|
|
const user = await userFromSession(request, response);
|
|
const workspaces = multiUserMode(response)
|
|
? await Workspace.whereWithUser(user)
|
|
: await Workspace.where();
|
|
|
|
response.status(200).json({ workspaces });
|
|
} catch (error) {
|
|
console.error(error);
|
|
response.status(500).json({ error: "Failed to fetch workspaces" });
|
|
}
|
|
}
|
|
);
|
|
|
|
app.post(
|
|
"/browser-extension/embed-content",
|
|
[validBrowserExtensionApiKey],
|
|
async (request, response) => {
|
|
try {
|
|
const { workspaceId, textContent, metadata } = reqBody(request);
|
|
const user = await userFromSession(request, response);
|
|
const workspace = multiUserMode(response)
|
|
? await Workspace.getWithUser(user, { id: parseInt(workspaceId) })
|
|
: await Workspace.get({ id: parseInt(workspaceId) });
|
|
|
|
if (!workspace) {
|
|
response.status(404).json({ error: "Workspace not found" });
|
|
return;
|
|
}
|
|
|
|
const Collector = new CollectorApi();
|
|
const { success, reason, documents } = await Collector.processRawText(
|
|
textContent,
|
|
metadata
|
|
);
|
|
|
|
if (!success) {
|
|
response.status(500).json({ success: false, error: reason });
|
|
return;
|
|
}
|
|
|
|
const { failedToEmbed = [], errors = [] } = await Document.addDocuments(
|
|
workspace,
|
|
[documents[0].location],
|
|
user?.id
|
|
);
|
|
|
|
if (failedToEmbed.length > 0) {
|
|
response.status(500).json({ success: false, error: errors[0] });
|
|
return;
|
|
}
|
|
|
|
await Telemetry.sendTelemetry("browser_extension_embed_content");
|
|
response.status(200).json({ success: true });
|
|
} catch (error) {
|
|
console.error(error);
|
|
response.status(500).json({ error: "Failed to embed content" });
|
|
}
|
|
}
|
|
);
|
|
|
|
app.post(
|
|
"/browser-extension/upload-content",
|
|
[validBrowserExtensionApiKey],
|
|
async (request, response) => {
|
|
try {
|
|
const { textContent, metadata } = reqBody(request);
|
|
const Collector = new CollectorApi();
|
|
const { success, reason } = await Collector.processRawText(
|
|
textContent,
|
|
metadata
|
|
);
|
|
|
|
if (!success) {
|
|
response.status(500).json({ success: false, error: reason });
|
|
return;
|
|
}
|
|
|
|
await Telemetry.sendTelemetry("browser_extension_upload_content");
|
|
response.status(200).json({ success: true });
|
|
} catch (error) {
|
|
console.error(error);
|
|
response.status(500).json({ error: "Failed to embed content" });
|
|
}
|
|
}
|
|
);
|
|
|
|
// Internal endpoints for managing API keys
|
|
app.get(
|
|
"/browser-extension/api-keys",
|
|
[validatedRequest, flexUserRoleValid([ROLES.admin, ROLES.manager])],
|
|
async (request, response) => {
|
|
try {
|
|
const user = await userFromSession(request, response);
|
|
const apiKeys = multiUserMode(response)
|
|
? await BrowserExtensionApiKey.whereWithUser(user)
|
|
: await BrowserExtensionApiKey.where();
|
|
|
|
response.status(200).json({ success: true, apiKeys });
|
|
} catch (error) {
|
|
console.error(error);
|
|
response
|
|
.status(500)
|
|
.json({ success: false, error: "Failed to fetch API keys" });
|
|
}
|
|
}
|
|
);
|
|
|
|
app.post(
|
|
"/browser-extension/api-keys/new",
|
|
[validatedRequest, flexUserRoleValid([ROLES.admin, ROLES.manager])],
|
|
async (request, response) => {
|
|
try {
|
|
const user = await userFromSession(request, response);
|
|
const { apiKey, error } = await BrowserExtensionApiKey.create(
|
|
user?.id || null
|
|
);
|
|
if (error) throw new Error(error);
|
|
response.status(200).json({
|
|
apiKey: apiKey.key,
|
|
});
|
|
} catch (error) {
|
|
console.error(error);
|
|
response.status(500).json({ error: "Failed to create API key" });
|
|
}
|
|
}
|
|
);
|
|
|
|
app.delete(
|
|
"/browser-extension/api-keys/:id",
|
|
[validatedRequest, flexUserRoleValid([ROLES.admin, ROLES.manager])],
|
|
async (request, response) => {
|
|
try {
|
|
const { id } = request.params;
|
|
const user = await userFromSession(request, response);
|
|
|
|
if (multiUserMode(response) && user.role !== ROLES.admin) {
|
|
const apiKey = await BrowserExtensionApiKey.get({
|
|
id: parseInt(id),
|
|
user_id: user?.id,
|
|
});
|
|
if (!apiKey) {
|
|
return response.status(403).json({ error: "Unauthorized" });
|
|
}
|
|
}
|
|
|
|
const { success, error } = await BrowserExtensionApiKey.delete(id);
|
|
if (!success) throw new Error(error);
|
|
response.status(200).json({ success: true });
|
|
} catch (error) {
|
|
console.error(error);
|
|
response.status(500).json({ error: "Failed to revoke API key" });
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
module.exports = { browserExtensionEndpoints };
|