Skip to content

Commit

Permalink
feat: can now toggle admin status (#179)
Browse files Browse the repository at this point in the history
  • Loading branch information
NicholasG04 authored Mar 22, 2022
1 parent a50fc88 commit 083b703
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 13 deletions.
51 changes: 38 additions & 13 deletions src/pages/admin/[id]/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import type { NextPage } from 'next';
import {
Button,
Flex,
Heading, Text,
Heading,
Text,
useToast,
} from '@chakra-ui/react';
import BaseLayout from 'components/Layouts/Base';
import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';
import { useCallback, useEffect, useState } from 'react';
import { useUser } from '@supabase/supabase-auth-helpers/react';
import Error from 'next/error';
import type { UserWithTicket } from 'types/user';
Expand All @@ -17,22 +20,42 @@ const ManageSpecificUser: NextPage = () => {
const [managedUser, setManagedUser] = useState<null | UserWithTicket>(null);
const [errorCode, setErrorCode] = useState<false | number>(false);
const { user } = useUser();
const toast = useToast();

const getUser = useCallback(async (): Promise<void> => {
const res = await fetch(`/api/getUser/${router.query.id}`);
if (!res.ok) {
setErrorCode(res.status);
return;
}
const data: UserWithTicket = await res.json();
setManagedUser(data);
setIsLoading(false);
}, [router]);

useEffect(() => {
if (!router?.query?.id || !user) return;

const getUser = async (): Promise<void> => {
const res = await fetch(`/api/getUser/${router.query.id}`);
if (!res.ok) {
setErrorCode(res.status);
return;
}
const data: UserWithTicket = await res.json();
setManagedUser(data);
setIsLoading(false);
};
getUser();
}, [router, user]);
}, [router, user, getUser]);

const toggleAdmin = async () => {
const res = await fetch(`/api/user/${router?.query?.id}/toggleAdmin`);
if (!res.ok) {
toast({
title: 'Failed to toggle admin',
status: 'error',
});
return;
}
const data = await res.json();
toast({
title: 'Admin status toggled',
description: `New admin status: ${data.is_admin}`,
status: 'success',
});
getUser();
};

if (errorCode) return <Error statusCode={errorCode} />;

Expand All @@ -50,6 +73,8 @@ const ManageSpecificUser: NextPage = () => {
<QR jwt={managedUser?.jwt} />
</>
)}

<Button mt={3} onClick={toggleAdmin}>Toggle Admin</Button>
</Flex>
</BaseLayout>
);
Expand Down
32 changes: 32 additions & 0 deletions src/pages/api/user/[id]/toggleAdmin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { withAuthRequired, supabaseClient as userSupabase } from '@supabase/supabase-auth-helpers/nextjs';
import { createClient } from '@supabase/supabase-js';
import { withSentry } from '@sentry/nextjs';

interface Return {
id: string;
is_admin: boolean;
}

export default withAuthRequired(withSentry(async (req: NextApiRequest, res: NextApiResponse<Return | string>): Promise<void> => {
if (!req.query.id) return res.status(400).send('No user id provided');
const { data: calledUser, error: calledUserError } = await userSupabase.auth.api.getUserByCookie(req, res);

if (calledUserError) return res.status(calledUserError.status).send(calledUserError.message);
if (!calledUser.user_metadata.admin) return res.status(403).send('Unauthorised');

const serverSupabase = createClient(process.env.NEXT_PUBLIC_SUPABASE_URL, process.env.SUPABASE_SERVICE_ROLE);

const { data } = await serverSupabase.rpc<Return>('toggle_admin', { user_id: req.query.id }).single();

return res.status(200).json({
id: data.id,
is_admin: data.is_admin,
});
}));

export const config = {
api: {
externalResolver: true,
},
};

1 comment on commit 083b703

@vercel
Copy link

@vercel vercel bot commented on 083b703 Mar 22, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.