Skip to content

Commit

Permalink
Fix role updating for discord users (#1739)
Browse files Browse the repository at this point in the history
The pattern is really confusing: the `username` saved in the python
backend for discord users is their discord id, but what we have in the
frontend users db is randomly generated.

And so we cannot refer to users from the backend using their id
immediately, we have to do another query to another table, which is not
good!

We might need some migration scripts in the future if we want to
simplify this.
  • Loading branch information
AbdBarho committed Feb 19, 2023
1 parent 4802b48 commit b701e4f
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 12 deletions.
20 changes: 17 additions & 3 deletions website/src/lib/users.ts
Expand Up @@ -15,7 +15,7 @@ const LOCALE_SET = new Set(i18n.locales);
* the i18n module.
* 3. "en" as a final fallback.
*/
const getUserLanguage = (req: NextApiRequest): string => {
export const getUserLanguage = (req: NextApiRequest): string => {
const cookieLanguage = req.cookies["NEXT_LOCALE"];
if (cookieLanguage) {
return cookieLanguage;
Expand All @@ -33,7 +33,7 @@ const getUserLanguage = (req: NextApiRequest): string => {
* @param {string} id The user's web auth id.
*
*/
const getBackendUserCore = async (id: string): Promise<BackendUserCore | null> => {
export const getBackendUserCore = async (id: string): Promise<BackendUserCore | null> => {
const user = await prisma.user.findUnique({
where: { id },
select: {
Expand Down Expand Up @@ -66,4 +66,18 @@ const getBackendUserCore = async (id: string): Promise<BackendUserCore | null> =
};
};

export { getBackendUserCore, getUserLanguage };
/**
* The frontend user id for discord users is saved differently from the email users
*
* this functions gets the "correct" user id for interacting with the frontend db, more specifically
* the users table, when calling `prisma.user....`
*
* Ideally, this function does not need to exist, but this might require huge migrations
*
* @param {string} id the id of the user, this field is called 'username' in the python backend's user table
* not to be confused with the user's UUID
*/
export const getFrontendUserIdForDiscordUser = async (id: string) => {
const { userId } = await prisma.account.findFirst({ where: { provider: "discord", providerAccountId: id } });
return userId;
};
25 changes: 18 additions & 7 deletions website/src/pages/admin/manage_user/[id].tsx
Expand Up @@ -30,10 +30,12 @@ import { Role, RoleSelect } from "src/components/RoleSelect";
import { get, post } from "src/lib/api";
import { userlessApiClient } from "src/lib/oasst_client_factory";
import prisma from "src/lib/prismadb";
import { getFrontendUserIdForDiscordUser } from "src/lib/users";
import { FetchUserMessagesCursorResponse } from "src/types/Conversation";
import { User } from "src/types/Users";
import useSWRImmutable from "swr/immutable";
import useSWRMutation from "swr/mutation";

interface UserForm {
user_id: string;
id: string;
Expand Down Expand Up @@ -175,20 +177,29 @@ export const getServerSideProps: GetServerSideProps<{ user: User<Role> }, { id:
params,
locale = "en",
}) => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const backend_user = await userlessApiClient.fetch_user(params!.id as string);

const backend_user = await userlessApiClient.fetch_user(params.id as string);
if (!backend_user) {
return {
notFound: true,
};
}

let frontendUserId = backend_user.id;
if (backend_user.auth_method === "discord") {
frontendUserId = await getFrontendUserIdForDiscordUser(backend_user.id);
}

const local_user = await prisma.user.findUnique({
where: { id: backend_user.id },
select: {
role: true,
},
where: { id: frontendUserId },
select: { role: true },
});

if (!local_user) {
return {
notFound: true,
};
}

const user = {
...backend_user,
role: (local_user?.role || "general") as Role,
Expand Down
13 changes: 11 additions & 2 deletions website/src/pages/api/admin/update_user.ts
Expand Up @@ -2,19 +2,28 @@ import { ROLES } from "src/components/RoleSelect";
import { withAnyRole } from "src/lib/auth";
import { createApiClient } from "src/lib/oasst_client_factory";
import prisma from "src/lib/prismadb";
import { getFrontendUserIdForDiscordUser } from "src/lib/users";

/**
* Update's the user's data in the database. Accessible only to admins.
*/
const handler = withAnyRole(["admin", "moderator"], async (req, res, token) => {
const { id, user_id, notes, role, show_on_leaderboard } = req.body;
// id is the 'username' from python backend, user_id is 'id' from the backend
const { id, user_id, notes, role, show_on_leaderboard, auth_method } = req.body;

// mod can't update user role to mod or admin
if (token.role === ROLES.MODERATOR && (role === ROLES.MODERATOR || role === ROLES.ADMIN)) {
return res.status(403).json({});
}

let frontendUserId = id;
if (auth_method === "discord") {
frontendUserId = await getFrontendUserIdForDiscordUser(id);
}

const oasstApiClient = await createApiClient(token);
await prisma.user.update({
where: { id },
where: { id: frontendUserId },
data: { role },
});

Expand Down

0 comments on commit b701e4f

Please sign in to comment.