diff --git a/components/Modal/AddCollection.tsx b/components/Modal/AddCollection.tsx
index 26c5d3b..dba8e7a 100644
--- a/components/Modal/AddCollection.tsx
+++ b/components/Modal/AddCollection.tsx
@@ -10,6 +10,7 @@ import useCollectionStore from "@/store/collections";
import { NewCollection } from "@/types/global";
import { useSession } from "next-auth/react";
import RequiredBadge from "../RequiredBadge";
+import getPublicUserDataByEmail from "@/lib/client/getPublicUserDataByEmail";
type Props = {
toggleCollectionModal: Function;
@@ -36,14 +37,6 @@ export default function AddCollection({ toggleCollectionModal }: Props) {
if (response) toggleCollectionModal();
};
- const getUserByEmail = async (email: string) => {
- const response = await fetch(`/api/routes/users?email=${email}`);
-
- const data = await response.json();
-
- return data.response;
- };
-
return (
New Collection
@@ -107,7 +100,7 @@ export default function AddCollection({ toggleCollectionModal }: Props) {
memberEmail.trim() !== ownerEmail
) {
// Lookup, get data/err, list ...
- const user = await getUserByEmail(memberEmail.trim());
+ const user = await getPublicUserDataByEmail(memberEmail.trim());
if (user.email) {
const newMember = {
diff --git a/components/Modal/ChangePassword.tsx b/components/Modal/ChangePassword.tsx
index 2ccb4e7..110315e 100644
--- a/components/Modal/ChangePassword.tsx
+++ b/components/Modal/ChangePassword.tsx
@@ -4,9 +4,7 @@
// You should have received a copy of the GNU General Public License along with this program. If not, see
.
import React, { useState } from "react";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { AccountSettings } from "@/types/global";
-import { faPenToSquare } from "@fortawesome/free-regular-svg-icons";
type Props = {
togglePasswordFormModal: Function;
@@ -70,8 +68,7 @@ export default function AddCollection({
className="mx-auto mt-2 text-white flex items-center gap-2 py-2 px-5 rounded-md select-none font-bold duration-100 bg-sky-500 hover:bg-sky-400 cursor-pointer"
onClick={submit}
>
-
- Change Password
+ Save
diff --git a/components/Modal/UserSettings.tsx b/components/Modal/UserSettings.tsx
index 06e7b47..45fe518 100644
--- a/components/Modal/UserSettings.tsx
+++ b/components/Modal/UserSettings.tsx
@@ -29,6 +29,9 @@ export default function UserSettings({ toggleSettingsModal }: Props) {
profilePic: null,
});
+ const [whitelistedUsersTextbox, setWhiteListedUsersTextbox] = useState(
+ user.whitelistedUsers.join(", ")
+ );
const [passwordFormModal, setPasswordFormModal] = useState(false);
const togglePasswordFormModal = () => {
@@ -49,6 +52,21 @@ export default function UserSettings({ toggleSettingsModal }: Props) {
determineProfilePicSource();
}, []);
+ useEffect(() => {
+ setUser({
+ ...user,
+ whitelistedUsers: stringToArray(whitelistedUsersTextbox),
+ });
+ }, [whitelistedUsersTextbox]);
+
+ const stringToArray = (str: string) => {
+ const stringWithoutSpaces = str.replace(/\s+/g, "");
+
+ const wordsArray = stringWithoutSpaces.split(",");
+
+ return wordsArray;
+ };
+
const handleImageUpload = async (e: any) => {
const file: File = e.target.files[0];
@@ -77,6 +95,8 @@ export default function UserSettings({ toggleSettingsModal }: Props) {
};
const submit = async () => {
+ console.log(user);
+
await updateAccount({
...user,
profilePic:
@@ -134,6 +154,14 @@ export default function UserSettings({ toggleSettingsModal }: Props) {
Change Password
+
+ {user.newPassword && user.oldPassword ? (
+
+ Password modified. Please click{" "}
+ "Apply Settings" to
+ apply the changes..
+
+ ) : null}
@@ -204,23 +232,33 @@ export default function UserSettings({ toggleSettingsModal }: Props) {
Privacy Settings
- setUser({ ...user, collectionProtection: !user.collectionProtection })
- }
+ onClick={() => setUser({ ...user, isPrivate: !user.isPrivate })}
/>
- {user.collectionProtection ? (
+
+ This will limit who can find and add you to other Collections.
+
+
+ {user.isPrivate ? (
+
+ Whitelisted Users
+
- Please enter the email addresses of the users who are allowed to add
- you to additional collections in the box below, separated by spaces.
+ Please provide the Email addresses of the users you wish to grant
+ visibility to your profile. Separate the addresses with a comma.
+ Users not included will be unable to view your profile.
) : null}
diff --git a/lib/api/controllers/users/getUsers.ts b/lib/api/controllers/users/getUsers.ts
index 4237b18..582fdfd 100644
--- a/lib/api/controllers/users/getUsers.ts
+++ b/lib/api/controllers/users/getUsers.ts
@@ -5,14 +5,26 @@
import { prisma } from "@/lib/api/db";
-export default async function (lookupEmail: string, isSelf: boolean) {
+export default async function (
+ lookupEmail: string,
+ isSelf: boolean,
+ userEmail: string
+) {
const user = await prisma.user.findUnique({
where: {
email: lookupEmail,
},
});
- if (!user) return { response: "User not found." || null, status: 404 };
+ if (!user) return { response: "User not found.", status: 404 };
+
+ if (
+ !isSelf &&
+ user?.isPrivate &&
+ !user.whitelistedUsers.includes(userEmail)
+ ) {
+ return { response: "This profile is private.", status: 401 };
+ }
const { password, ...unsensitiveInfo } = user;
diff --git a/lib/api/controllers/users/updateUser.ts b/lib/api/controllers/users/updateUser.ts
index 203cb70..2630867 100644
--- a/lib/api/controllers/users/updateUser.ts
+++ b/lib/api/controllers/users/updateUser.ts
@@ -44,7 +44,7 @@ export default async function (user: AccountSettings, userId: number) {
data: {
name: user.name,
email: user.email,
- collectionProtection: user.collectionProtection,
+ isPrivate: user.isPrivate,
whitelistedUsers: user.whitelistedUsers,
},
});
diff --git a/lib/client/getPublicUserDataByEmail.ts b/lib/client/getPublicUserDataByEmail.ts
index a91fa07..d386918 100644
--- a/lib/client/getPublicUserDataByEmail.ts
+++ b/lib/client/getPublicUserDataByEmail.ts
@@ -8,5 +8,7 @@ export default async function (email: string) {
const data = await response.json();
+ console.log(data);
+
return data.response;
}
diff --git a/pages/api/avatar/[id].ts b/pages/api/avatar/[id].ts
index ae85c21..cd3aa87 100644
--- a/pages/api/avatar/[id].ts
+++ b/pages/api/avatar/[id].ts
@@ -6,23 +6,41 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { getServerSession } from "next-auth/next";
import { authOptions } from "pages/api/auth/[...nextauth]";
+import { prisma } from "@/lib/api/db";
import path from "path";
import fs from "fs";
export default async function (req: NextApiRequest, res: NextApiResponse) {
- if (!req.query.id)
- return res.status(401).json({ response: "Invalid parameters." });
-
const session = await getServerSession(req, res, authOptions);
- if (!session?.user?.email)
+ const userId = session?.user.id;
+ const userEmail = session?.user.email;
+ const queryId = Number(req.query.id);
+
+ if (!queryId)
+ return res.status(401).json({ response: "Invalid parameters." });
+
+ if (!userId || !userEmail)
return res.status(401).json({ response: "You must be logged in." });
- // TODO: If profile is private, hide it to other users...
+ if (userId !== queryId) {
+ const targetUser = await prisma.user.findUnique({
+ where: {
+ id: queryId,
+ },
+ });
+
+ if (
+ targetUser?.isPrivate &&
+ !targetUser.whitelistedUsers.includes(userEmail)
+ ) {
+ return res.status(401).json({ response: "This profile is private." });
+ }
+ }
const filePath = path.join(
process.cwd(),
- `data/uploads/avatar/${req.query.id}.jpg`
+ `data/uploads/avatar/${queryId}.jpg`
);
console.log(filePath);
diff --git a/pages/api/routes/users/index.ts b/pages/api/routes/users/index.ts
index 75ca851..4af3e19 100644
--- a/pages/api/routes/users/index.ts
+++ b/pages/api/routes/users/index.ts
@@ -20,7 +20,7 @@ export default async function (req: NextApiRequest, res: NextApiResponse) {
const isSelf = session.user.email === lookupEmail ? true : false;
if (req.method === "GET") {
- const users = await getUsers(lookupEmail, isSelf);
+ const users = await getUsers(lookupEmail, isSelf, session.user.email);
return res.status(users.status).json({ response: users.response });
} else if (req.method === "PUT" && !req.body.password) {
const updated = await updateUser(req.body, session.user.id);
diff --git a/prisma/migrations/20230522122002_init/migration.sql b/prisma/migrations/20230523040650_init/migration.sql
similarity index 98%
rename from prisma/migrations/20230522122002_init/migration.sql
rename to prisma/migrations/20230523040650_init/migration.sql
index 770d6a9..351f017 100644
--- a/prisma/migrations/20230522122002_init/migration.sql
+++ b/prisma/migrations/20230523040650_init/migration.sql
@@ -4,7 +4,7 @@ CREATE TABLE "User" (
"name" TEXT NOT NULL,
"email" TEXT NOT NULL,
"password" TEXT NOT NULL,
- "collectionProtection" BOOLEAN NOT NULL DEFAULT false,
+ "isPrivate" BOOLEAN NOT NULL DEFAULT false,
"whitelistedUsers" TEXT[] DEFAULT ARRAY[]::TEXT[],
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index 5930434..f80505e 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -20,7 +20,7 @@ model User {
collections Collection[]
tags Tag[]
collectionsJoined UsersAndCollections[]
- collectionProtection Boolean @default(false)
+ isPrivate Boolean @default(false)
whitelistedUsers String[] @default([])
createdAt DateTime @default(now())
}