[FEAT] Ability to set workspace profile image (#847)
* WIP workspace pfp, CRUD functions complete * implement fetching workspace pfp in UserIcon component * update UI for workspace settings pfp * minor css refactor * WIP fixes to workspace pfp * create responseCache for workspace pfp blob to improve performance * fix cache not clearing when removing workspace pfp and remove unneeded util * load workspace image once, dont reload --------- Co-authored-by: timothycarambat <rambat1010@gmail.com>
This commit is contained in:
parent
d9fce5f65e
commit
04399b1328
@ -31,15 +31,7 @@ const HistoricalMessage = ({
|
|||||||
className={`py-8 px-4 w-full flex gap-x-5 md:max-w-[800px] flex-col`}
|
className={`py-8 px-4 w-full flex gap-x-5 md:max-w-[800px] flex-col`}
|
||||||
>
|
>
|
||||||
<div className="flex gap-x-5">
|
<div className="flex gap-x-5">
|
||||||
<Jazzicon
|
<ProfileImage role={role} workspace={workspace} />
|
||||||
size={36}
|
|
||||||
user={{
|
|
||||||
uid:
|
|
||||||
role === "user" ? userFromStorage()?.username : workspace.slug,
|
|
||||||
}}
|
|
||||||
role={role}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{error ? (
|
{error ? (
|
||||||
<div className="p-2 rounded-lg bg-red-50 text-red-500">
|
<div className="p-2 rounded-lg bg-red-50 text-red-500">
|
||||||
<span className={`inline-block `}>
|
<span className={`inline-block `}>
|
||||||
@ -76,4 +68,28 @@ const HistoricalMessage = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function ProfileImage({ role, workspace }) {
|
||||||
|
if (role === "assistant" && workspace.pfpUrl) {
|
||||||
|
return (
|
||||||
|
<div className="relative w-[35px] h-[35px] rounded-full flex-shrink-0 overflow-hidden">
|
||||||
|
<img
|
||||||
|
src={workspace.pfpUrl}
|
||||||
|
alt="Workspace profile picture"
|
||||||
|
className="absolute top-0 left-0 w-full h-full object-cover rounded-full bg-white"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Jazzicon
|
||||||
|
size={36}
|
||||||
|
user={{
|
||||||
|
uid: role === "user" ? userFromStorage()?.username : workspace.slug,
|
||||||
|
}}
|
||||||
|
role={role}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default memo(HistoricalMessage);
|
export default memo(HistoricalMessage);
|
||||||
|
|||||||
@ -14,7 +14,6 @@ const PromptReply = ({
|
|||||||
closed = true,
|
closed = true,
|
||||||
}) => {
|
}) => {
|
||||||
const assistantBackgroundColor = "bg-historical-msg-system";
|
const assistantBackgroundColor = "bg-historical-msg-system";
|
||||||
|
|
||||||
if (!reply && sources.length === 0 && !pending && !error) return null;
|
if (!reply && sources.length === 0 && !pending && !error) return null;
|
||||||
|
|
||||||
if (pending) {
|
if (pending) {
|
||||||
@ -24,11 +23,7 @@ const PromptReply = ({
|
|||||||
>
|
>
|
||||||
<div className="py-8 px-4 w-full flex gap-x-5 md:max-w-[800px] flex-col">
|
<div className="py-8 px-4 w-full flex gap-x-5 md:max-w-[800px] flex-col">
|
||||||
<div className="flex gap-x-5">
|
<div className="flex gap-x-5">
|
||||||
<Jazzicon
|
<WorkspaceProfileImage workspace={workspace} />
|
||||||
size={36}
|
|
||||||
user={{ uid: workspace.slug }}
|
|
||||||
role="assistant"
|
|
||||||
/>
|
|
||||||
<div className="mt-3 ml-5 dot-falling"></div>
|
<div className="mt-3 ml-5 dot-falling"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -43,11 +38,7 @@ const PromptReply = ({
|
|||||||
>
|
>
|
||||||
<div className="py-8 px-4 w-full flex gap-x-5 md:max-w-[800px] flex-col">
|
<div className="py-8 px-4 w-full flex gap-x-5 md:max-w-[800px] flex-col">
|
||||||
<div className="flex gap-x-5">
|
<div className="flex gap-x-5">
|
||||||
<Jazzicon
|
<WorkspaceProfileImage workspace={workspace} />
|
||||||
size={36}
|
|
||||||
user={{ uid: workspace.slug }}
|
|
||||||
role="assistant"
|
|
||||||
/>
|
|
||||||
<span
|
<span
|
||||||
className={`inline-block p-2 rounded-lg bg-red-50 text-red-500`}
|
className={`inline-block p-2 rounded-lg bg-red-50 text-red-500`}
|
||||||
>
|
>
|
||||||
@ -68,7 +59,7 @@ const PromptReply = ({
|
|||||||
>
|
>
|
||||||
<div className="py-8 px-4 w-full flex gap-x-5 md:max-w-[800px] flex-col">
|
<div className="py-8 px-4 w-full flex gap-x-5 md:max-w-[800px] flex-col">
|
||||||
<div className="flex gap-x-5">
|
<div className="flex gap-x-5">
|
||||||
<Jazzicon size={36} user={{ uid: workspace.slug }} role="assistant" />
|
<WorkspaceProfileImage workspace={workspace} />
|
||||||
<span
|
<span
|
||||||
className={`reply flex flex-col gap-y-1 mt-2`}
|
className={`reply flex flex-col gap-y-1 mt-2`}
|
||||||
dangerouslySetInnerHTML={{ __html: renderMarkdown(reply) }}
|
dangerouslySetInnerHTML={{ __html: renderMarkdown(reply) }}
|
||||||
@ -80,4 +71,20 @@ const PromptReply = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function WorkspaceProfileImage({ workspace }) {
|
||||||
|
if (!!workspace.pfpUrl) {
|
||||||
|
return (
|
||||||
|
<div className="relative w-[35px] h-[35px] rounded-full flex-shrink-0 overflow-hidden">
|
||||||
|
<img
|
||||||
|
src={workspace.pfpUrl}
|
||||||
|
alt="Workspace profile picture"
|
||||||
|
className="absolute top-0 left-0 w-full h-full object-cover rounded-full bg-white"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <Jazzicon size={36} user={{ uid: workspace.slug }} role="assistant" />;
|
||||||
|
}
|
||||||
|
|
||||||
export default memo(PromptReply);
|
export default memo(PromptReply);
|
||||||
|
|||||||
@ -238,6 +238,54 @@ const Workspace = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
threads: WorkspaceThread,
|
threads: WorkspaceThread,
|
||||||
|
|
||||||
|
uploadPfp: async function (formData, slug) {
|
||||||
|
return await fetch(`${API_BASE}/workspace/${slug}/upload-pfp`, {
|
||||||
|
method: "POST",
|
||||||
|
body: formData,
|
||||||
|
headers: baseHeaders(),
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
if (!res.ok) throw new Error("Error uploading pfp.");
|
||||||
|
return { success: true, error: null };
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.log(e);
|
||||||
|
return { success: false, error: e.message };
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
fetchPfp: async function (slug) {
|
||||||
|
return await fetch(`${API_BASE}/workspace/${slug}/pfp`, {
|
||||||
|
method: "GET",
|
||||||
|
cache: "no-cache",
|
||||||
|
headers: baseHeaders(),
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
if (res.ok && res.status !== 204) return res.blob();
|
||||||
|
throw new Error("Failed to fetch pfp.");
|
||||||
|
})
|
||||||
|
.then((blob) => (blob ? URL.createObjectURL(blob) : null))
|
||||||
|
.catch((e) => {
|
||||||
|
console.log(e);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
removePfp: async function (slug) {
|
||||||
|
return await fetch(`${API_BASE}/workspace/${slug}/remove-pfp`, {
|
||||||
|
method: "DELETE",
|
||||||
|
headers: baseHeaders(),
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
if (res.ok) return { success: true, error: null };
|
||||||
|
throw new Error("Failed to remove pfp.");
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.log(e);
|
||||||
|
return { success: false, error: e.message };
|
||||||
|
});
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Workspace;
|
export default Workspace;
|
||||||
|
|||||||
@ -19,7 +19,7 @@ export default function WorkspaceChat() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function ShowWorkspaceChat() {
|
function ShowWorkspaceChat() {
|
||||||
const { slug, threadSlug = null } = useParams();
|
const { slug } = useParams();
|
||||||
const [workspace, setWorkspace] = useState(null);
|
const [workspace, setWorkspace] = useState(null);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
@ -32,9 +32,11 @@ function ShowWorkspaceChat() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const suggestedMessages = await Workspace.getSuggestedMessages(slug);
|
const suggestedMessages = await Workspace.getSuggestedMessages(slug);
|
||||||
|
const pfpUrl = await Workspace.fetchPfp(slug);
|
||||||
setWorkspace({
|
setWorkspace({
|
||||||
..._workspace,
|
..._workspace,
|
||||||
suggestedMessages,
|
suggestedMessages,
|
||||||
|
pfpUrl,
|
||||||
});
|
});
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -101,7 +101,7 @@ export default function SuggestedChatMessages({ slug }) {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<div className="w-screen">
|
<div className="w-screen mt-6">
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<label className="block input-label">Suggested Chat Messages</label>
|
<label className="block input-label">Suggested Chat Messages</label>
|
||||||
<p className="text-white text-opacity-60 text-xs font-medium py-1.5">
|
<p className="text-white text-opacity-60 text-xs font-medium py-1.5">
|
||||||
|
|||||||
@ -0,0 +1,96 @@
|
|||||||
|
import Workspace from "@/models/workspace";
|
||||||
|
import showToast from "@/utils/toast";
|
||||||
|
import { Plus } from "@phosphor-icons/react";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
export default function WorkspacePfp({ workspace, slug }) {
|
||||||
|
const [pfp, setPfp] = useState(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
async function fetchWorkspace() {
|
||||||
|
const pfpUrl = await Workspace.fetchPfp(slug);
|
||||||
|
setPfp(pfpUrl);
|
||||||
|
}
|
||||||
|
fetchWorkspace();
|
||||||
|
}, [slug]);
|
||||||
|
|
||||||
|
const handleFileUpload = async (event) => {
|
||||||
|
const file = event.target.files[0];
|
||||||
|
if (!file) return false;
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("file", file);
|
||||||
|
const { success, error } = await Workspace.uploadPfp(
|
||||||
|
formData,
|
||||||
|
workspace.slug
|
||||||
|
);
|
||||||
|
if (!success) {
|
||||||
|
showToast(`Failed to upload profile picture: ${error}`, "error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pfpUrl = await Workspace.fetchPfp(workspace.slug);
|
||||||
|
setPfp(pfpUrl);
|
||||||
|
showToast("Profile picture uploaded.", "success");
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRemovePfp = async () => {
|
||||||
|
const { success, error } = await Workspace.removePfp(workspace.slug);
|
||||||
|
if (!success) {
|
||||||
|
showToast(`Failed to remove profile picture: ${error}`, "error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setPfp(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mt-6">
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<label className="block input-label">Assistant Profile Image</label>
|
||||||
|
<p className="text-white text-opacity-60 text-xs font-medium py-1.5">
|
||||||
|
Customize the profile image of the assistant for this workspace.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col md:flex-row items-center gap-8">
|
||||||
|
<div className="flex flex-col items-center">
|
||||||
|
<label className="w-36 h-36 flex flex-col items-center justify-center bg-zinc-900/50 transition-all duration-300 rounded-full mt-8 border-2 border-dashed border-white border-opacity-60 cursor-pointer hover:opacity-60">
|
||||||
|
<input
|
||||||
|
id="workspace-pfp-upload"
|
||||||
|
type="file"
|
||||||
|
accept="image/*"
|
||||||
|
className="hidden"
|
||||||
|
onChange={handleFileUpload}
|
||||||
|
/>
|
||||||
|
{pfp ? (
|
||||||
|
<img
|
||||||
|
src={pfp}
|
||||||
|
alt="User profile picture"
|
||||||
|
className="w-36 h-36 rounded-full object-cover bg-white"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div className="flex flex-col items-center justify-center p-3">
|
||||||
|
<Plus className="w-8 h-8 text-white/80 m-2" />
|
||||||
|
<span className="text-white text-opacity-80 text-xs font-semibold">
|
||||||
|
Workspace Image
|
||||||
|
</span>
|
||||||
|
<span className="text-white text-opacity-60 text-xs">
|
||||||
|
800 x 800
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</label>
|
||||||
|
{pfp && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={handleRemovePfp}
|
||||||
|
className="mt-3 text-white text-opacity-60 text-sm font-medium hover:underline"
|
||||||
|
>
|
||||||
|
Remove Workspace Image
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -6,6 +6,7 @@ import VectorCount from "./VectorCount";
|
|||||||
import WorkspaceName from "./WorkspaceName";
|
import WorkspaceName from "./WorkspaceName";
|
||||||
import SuggestedChatMessages from "./SuggestedChatMessages";
|
import SuggestedChatMessages from "./SuggestedChatMessages";
|
||||||
import DeleteWorkspace from "./DeleteWorkspace";
|
import DeleteWorkspace from "./DeleteWorkspace";
|
||||||
|
import WorkspacePfp from "./WorkspacePfp";
|
||||||
|
|
||||||
export default function GeneralInfo({ slug }) {
|
export default function GeneralInfo({ slug }) {
|
||||||
const [workspace, setWorkspace] = useState(null);
|
const [workspace, setWorkspace] = useState(null);
|
||||||
@ -66,9 +67,8 @@ export default function GeneralInfo({ slug }) {
|
|||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</form>
|
</form>
|
||||||
<div className="mt-6">
|
<SuggestedChatMessages slug={workspace.slug} />
|
||||||
<SuggestedChatMessages slug={workspace.slug} />
|
<WorkspacePfp workspace={workspace} slug={slug} />
|
||||||
</div>
|
|
||||||
<DeleteWorkspace workspace={workspace} />
|
<DeleteWorkspace workspace={workspace} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -548,8 +548,6 @@ function systemEndpoints(app) {
|
|||||||
|
|
||||||
const userRecord = await User.get({ id: user.id });
|
const userRecord = await User.get({ id: user.id });
|
||||||
const oldPfpFilename = userRecord.pfpFilename;
|
const oldPfpFilename = userRecord.pfpFilename;
|
||||||
|
|
||||||
console.log("oldPfpFilename", oldPfpFilename);
|
|
||||||
if (oldPfpFilename) {
|
if (oldPfpFilename) {
|
||||||
const oldPfpPath = path.join(
|
const oldPfpPath = path.join(
|
||||||
__dirname,
|
__dirname,
|
||||||
|
|||||||
@ -19,10 +19,21 @@ const { validWorkspaceSlug } = require("../utils/middleware/validWorkspace");
|
|||||||
const { convertToChatHistory } = require("../utils/helpers/chat/responses");
|
const { convertToChatHistory } = require("../utils/helpers/chat/responses");
|
||||||
const { CollectorApi } = require("../utils/collectorApi");
|
const { CollectorApi } = require("../utils/collectorApi");
|
||||||
const { handleUploads } = setupMulter();
|
const { handleUploads } = setupMulter();
|
||||||
|
const { setupPfpUploads } = require("../utils/files/multer");
|
||||||
|
const { normalizePath } = require("../utils/files");
|
||||||
|
const { handlePfpUploads } = setupPfpUploads();
|
||||||
|
const path = require("path");
|
||||||
|
const fs = require("fs");
|
||||||
|
const {
|
||||||
|
determineWorkspacePfpFilepath,
|
||||||
|
fetchPfp,
|
||||||
|
} = require("../utils/files/pfp");
|
||||||
|
|
||||||
function workspaceEndpoints(app) {
|
function workspaceEndpoints(app) {
|
||||||
if (!app) return;
|
if (!app) return;
|
||||||
|
|
||||||
|
const responseCache = new Map();
|
||||||
|
|
||||||
app.post(
|
app.post(
|
||||||
"/workspace/new",
|
"/workspace/new",
|
||||||
[validatedRequest, flexUserRoleValid([ROLES.admin, ROLES.manager])],
|
[validatedRequest, flexUserRoleValid([ROLES.admin, ROLES.manager])],
|
||||||
@ -422,6 +433,138 @@ function workspaceEndpoints(app) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
app.get(
|
||||||
|
"/workspace/:slug/pfp",
|
||||||
|
[validatedRequest, flexUserRoleValid([ROLES.all])],
|
||||||
|
async function (request, response) {
|
||||||
|
try {
|
||||||
|
const { slug } = request.params;
|
||||||
|
const cachedResponse = responseCache.get(slug);
|
||||||
|
|
||||||
|
if (cachedResponse) {
|
||||||
|
response.writeHead(200, {
|
||||||
|
"Content-Type": cachedResponse.mime || "image/png",
|
||||||
|
});
|
||||||
|
response.end(cachedResponse.buffer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pfpPath = await determineWorkspacePfpFilepath(slug);
|
||||||
|
|
||||||
|
if (!pfpPath) {
|
||||||
|
response.sendStatus(204).end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { found, buffer, mime } = fetchPfp(pfpPath);
|
||||||
|
if (!found) {
|
||||||
|
response.sendStatus(204).end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
responseCache.set(slug, { buffer, mime });
|
||||||
|
|
||||||
|
response.writeHead(200, {
|
||||||
|
"Content-Type": mime || "image/png",
|
||||||
|
});
|
||||||
|
response.end(buffer);
|
||||||
|
return;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error processing the logo request:", error);
|
||||||
|
response.status(500).json({ message: "Internal server error" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
app.post(
|
||||||
|
"/workspace/:slug/upload-pfp",
|
||||||
|
[validatedRequest, flexUserRoleValid([ROLES.admin, ROLES.manager])],
|
||||||
|
handlePfpUploads.single("file"),
|
||||||
|
async function (request, response) {
|
||||||
|
try {
|
||||||
|
const { slug } = request.params;
|
||||||
|
const uploadedFileName = request.randomFileName;
|
||||||
|
if (!uploadedFileName) {
|
||||||
|
return response.status(400).json({ message: "File upload failed." });
|
||||||
|
}
|
||||||
|
|
||||||
|
const workspaceRecord = await Workspace.get({
|
||||||
|
slug,
|
||||||
|
});
|
||||||
|
|
||||||
|
const oldPfpFilename = workspaceRecord.pfpFilename;
|
||||||
|
if (oldPfpFilename) {
|
||||||
|
const oldPfpPath = path.join(
|
||||||
|
__dirname,
|
||||||
|
`../storage/assets/pfp/${normalizePath(
|
||||||
|
workspaceRecord.pfpFilename
|
||||||
|
)}`
|
||||||
|
);
|
||||||
|
|
||||||
|
if (fs.existsSync(oldPfpPath)) fs.unlinkSync(oldPfpPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { workspace, message } = await Workspace.update(
|
||||||
|
workspaceRecord.id,
|
||||||
|
{
|
||||||
|
pfpFilename: uploadedFileName,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return response.status(workspace ? 200 : 500).json({
|
||||||
|
message: workspace
|
||||||
|
? "Profile picture uploaded successfully."
|
||||||
|
: message,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error processing the profile picture upload:", error);
|
||||||
|
response.status(500).json({ message: "Internal server error" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
app.delete(
|
||||||
|
"/workspace/:slug/remove-pfp",
|
||||||
|
[validatedRequest, flexUserRoleValid([ROLES.admin, ROLES.manager])],
|
||||||
|
async function (request, response) {
|
||||||
|
try {
|
||||||
|
const { slug } = request.params;
|
||||||
|
const workspaceRecord = await Workspace.get({
|
||||||
|
slug,
|
||||||
|
});
|
||||||
|
const oldPfpFilename = workspaceRecord.pfpFilename;
|
||||||
|
|
||||||
|
if (oldPfpFilename) {
|
||||||
|
const oldPfpPath = path.join(
|
||||||
|
__dirname,
|
||||||
|
`../storage/assets/pfp/${normalizePath(oldPfpFilename)}`
|
||||||
|
);
|
||||||
|
|
||||||
|
if (fs.existsSync(oldPfpPath)) fs.unlinkSync(oldPfpPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { workspace, message } = await Workspace.update(
|
||||||
|
workspaceRecord.id,
|
||||||
|
{
|
||||||
|
pfpFilename: null,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Clear the cache
|
||||||
|
responseCache.delete(slug);
|
||||||
|
|
||||||
|
return response.status(workspace ? 200 : 500).json({
|
||||||
|
message: workspace
|
||||||
|
? "Profile picture removed successfully."
|
||||||
|
: message,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error processing the profile picture removal:", error);
|
||||||
|
response.status(500).json({ message: "Internal server error" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { workspaceEndpoints };
|
module.exports = { workspaceEndpoints };
|
||||||
|
|||||||
@ -19,6 +19,7 @@ const Workspace = {
|
|||||||
"chatModel",
|
"chatModel",
|
||||||
"topN",
|
"topN",
|
||||||
"chatMode",
|
"chatMode",
|
||||||
|
"pfpFilename",
|
||||||
],
|
],
|
||||||
|
|
||||||
new: async function (name = null, creatorId = null) {
|
new: async function (name = null, creatorId = null) {
|
||||||
|
|||||||
@ -0,0 +1,2 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "workspaces" ADD COLUMN "pfpFilename" TEXT;
|
||||||
@ -100,6 +100,7 @@ model workspaces {
|
|||||||
chatModel String?
|
chatModel String?
|
||||||
topN Int? @default(4)
|
topN Int? @default(4)
|
||||||
chatMode String? @default("chat")
|
chatMode String? @default("chat")
|
||||||
|
pfpFilename String?
|
||||||
workspace_users workspace_users[]
|
workspace_users workspace_users[]
|
||||||
documents workspace_documents[]
|
documents workspace_documents[]
|
||||||
workspace_suggested_messages workspace_suggested_messages[]
|
workspace_suggested_messages workspace_suggested_messages[]
|
||||||
|
|||||||
@ -3,6 +3,7 @@ const fs = require("fs");
|
|||||||
const { getType } = require("mime");
|
const { getType } = require("mime");
|
||||||
const { User } = require("../../models/user");
|
const { User } = require("../../models/user");
|
||||||
const { normalizePath } = require(".");
|
const { normalizePath } = require(".");
|
||||||
|
const { Workspace } = require("../../models/workspace");
|
||||||
|
|
||||||
function fetchPfp(pfpPath) {
|
function fetchPfp(pfpPath) {
|
||||||
if (!fs.existsSync(pfpPath)) {
|
if (!fs.existsSync(pfpPath)) {
|
||||||
@ -38,7 +39,21 @@ async function determinePfpFilepath(id) {
|
|||||||
return pfpFilepath;
|
return pfpFilepath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function determineWorkspacePfpFilepath(slug) {
|
||||||
|
const workspace = await Workspace.get({ slug });
|
||||||
|
const pfpFilename = workspace?.pfpFilename || null;
|
||||||
|
if (!pfpFilename) return null;
|
||||||
|
|
||||||
|
const basePath = process.env.STORAGE_DIR
|
||||||
|
? path.join(process.env.STORAGE_DIR, "assets/pfp")
|
||||||
|
: path.join(__dirname, "../../storage/assets/pfp");
|
||||||
|
const pfpFilepath = path.join(basePath, normalizePath(pfpFilename));
|
||||||
|
if (!fs.existsSync(pfpFilepath)) return null;
|
||||||
|
return pfpFilepath;
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
fetchPfp,
|
fetchPfp,
|
||||||
determinePfpFilepath,
|
determinePfpFilepath,
|
||||||
|
determineWorkspacePfpFilepath,
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user