diff --git a/.husky/pre-commit b/.husky/pre-commit index 16d0a6a1..169c6212 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -3,5 +3,8 @@ staged=$(git diff --name-only --staged --diff-filter=d) export NIXPKGS_ALLOW_INSECURE=1 -nix develop --impure --command bash -c "yarn format && pre-commit run --all-files" +nix develop --impure \ + --extra-experimental-features nix-command \ + --extra-experimental-features flakes \ + --command bash -c "yarn format && pre-commit run --all-files" git add ${staged} diff --git a/apps/event-service-next/middleware.ts b/apps/event-service-next/middleware.ts index 78f5efbd..a412a83c 100644 --- a/apps/event-service-next/middleware.ts +++ b/apps/event-service-next/middleware.ts @@ -8,7 +8,8 @@ export async function middleware(request: NextRequest) { // Handle preflight requests if (request.method === 'OPTIONS') { - return NextResponse.next(); + const res = NextResponse.next(); + return res; } if ( diff --git a/apps/podium-service/middleware.ts b/apps/podium-service/middleware.ts index 4987d9d1..5be14c81 100644 --- a/apps/podium-service/middleware.ts +++ b/apps/podium-service/middleware.ts @@ -1,10 +1,34 @@ import { getEnv } from '@hibiscus/env'; +import { + createClient, + SupabaseClient, + UserResponse, +} from '@supabase/supabase-js'; import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; export async function middleware(req: NextRequest) { const path = req.nextUrl; + // Handle preflight requests + if (req.method === 'OPTIONS') { + const res = NextResponse.next(); + + // add the CORS headers to the response + res.headers.append('Access-Control-Allow-Credentials', 'true'); + res.headers.append('Access-Control-Allow-Origin', '*'); // Allow all origins + res.headers.append( + 'Access-Control-Allow-Methods', + 'GET,DELETE,PATCH,POST,PUT' + ); + res.headers.append( + 'Access-Control-Allow-Headers', + 'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Authorization, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version' + ); + + return res; + } + if ( path.pathname.startsWith('/api/error') || path.pathname.startsWith('/api/health') @@ -41,9 +65,9 @@ export async function middleware(req: NextRequest) { return NextResponse.next(); } - const res = await fetch(`${authServiceUrl}/verify-token/${accessToken}`); + const res = await verifyToken(accessToken); - if (res.status !== 200) { + if (res.error != null) { req.nextUrl.searchParams.set('status', '401'); req.nextUrl.searchParams.set('message', 'Invalid access token'); req.nextUrl.pathname = '/api/error'; @@ -53,6 +77,7 @@ export async function middleware(req: NextRequest) { const judgeRoutes = [ { route: '/verticals', methods: ['GET'] }, { route: '/projects', methods: ['GET'] }, + { route: '/projects/[verticalId]', methods: ['GET'] }, { route: '/ranking/[verticalId]/[userId]', methods: ['POST', 'GET', 'DELETE'], @@ -73,12 +98,17 @@ export async function middleware(req: NextRequest) { }); try { - const data = await res.json(); - const role = data.role; + const supabase = createSupabaseServiceClient(); + const roleRes = await supabase + .from('user_profiles') + .select('role') + .eq('user_id', res.data.user.id) + .maybeSingle(); + const role = roleRes.data.role; - if (role === 'SUPERADMIN') { + if (role === 1) { return NextResponse.next(); - } else if (isAccessingJudgeRoute && role === 'JUDGE') { + } else if (isAccessingJudgeRoute && role === 7) { return NextResponse.next(); } else { req.nextUrl.searchParams.set('status', '403'); @@ -100,3 +130,19 @@ export async function middleware(req: NextRequest) { export const config = { matcher: '/api/:path*', }; + +async function verifyToken(access_token: string): Promise { + const supabase = createSupabaseServiceClient(); + + // Verify access token + const userRes = await supabase.auth.getUser(access_token); + + return userRes; +} + +function createSupabaseServiceClient(): SupabaseClient { + return createClient( + getEnv().Hibiscus.Supabase.apiUrl, + getEnv().Hibiscus.Supabase.serviceKey + ); +} diff --git a/apps/podium-service/next.config.js b/apps/podium-service/next.config.js index 84124f67..062ef279 100644 --- a/apps/podium-service/next.config.js +++ b/apps/podium-service/next.config.js @@ -12,6 +12,28 @@ const nextConfig = { // See: https://github.com/gregberge/svgr svgr: false, }, + + async headers() { + return [ + { + // matching all API routes + source: '/api/:path*', + headers: [ + { key: 'Access-Control-Allow-Credentials', value: 'true' }, + { key: 'Access-Control-Allow-Origin', value: '*' }, + { + key: 'Access-Control-Allow-Methods', + value: 'GET,OPTIONS,PATCH,DELETE,POST,PUT', + }, + { + key: 'Access-Control-Allow-Headers', + value: + 'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Authorization, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version', + }, + ], + }, + ]; + }, }; module.exports = withNx(nextConfig); diff --git a/apps/podium-service/pages/api/add_projects.ts b/apps/podium-service/pages/api/add_projects.ts index 4d0ceb8f..765e4daf 100644 --- a/apps/podium-service/pages/api/add_projects.ts +++ b/apps/podium-service/pages/api/add_projects.ts @@ -1,13 +1,32 @@ import { supabase } from 'apps/podium-service/libs/supabase'; import { NextApiRequest, NextApiResponse } from 'next'; -export default async function handler(req: NextApiRequest, res: NextApiResponse) { +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { const { method, body } = req; switch (method) { + case 'OPTIONS': + return res.status(200).send('ok'); case 'POST': - const fields = ['name', 'teamMembers', 'description', 'imageUrl', 'devpostUrl', 'videoUrl']; - const fieldsDB = ['name', 'team', 'description', 'image_url', 'devpost_url', 'video_url']; + const fields = [ + 'name', + 'teamMembers', + 'description', + 'imageUrl', + 'devpostUrl', + 'videoUrl', + ]; + const fieldsDB = [ + 'name', + 'team', + 'description', + 'image_url', + 'devpost_url', + 'video_url', + ]; const addProjects = []; const verticals = {}; @@ -24,17 +43,26 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) } catch (error) { return res.status(500).json({ error: 'Internal Server Error' }); } - + try { const { data } = body; data.forEach((p) => { - if (!p.vertical || typeof p.vertical !== 'string' || typeof p.name !== 'string') { - return res.status(400).json({ error: 'Invalid request! Name and vertical are required and must be strings.'}); + if ( + !p.vertical || + typeof p.vertical !== 'string' || + typeof p.name !== 'string' + ) { + return res.status(400).json({ + error: + 'Invalid request! Name and vertical are required and must be strings.', + }); } else if (!verticals?.[p.vertical]) { - return res.status(400).json({ error: 'The specified vertical does not exist.' }); + return res + .status(400) + .json({ error: 'The specified vertical does not exist.' }); } - + const project = {}; project['vertical_id'] = verticals[p.vertical]; @@ -45,11 +73,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) } addProjects.push(project); - }) + }); - const { error } = await supabase - .from('projects') - .insert(addProjects); + const { error } = await supabase.from('projects').insert(addProjects); if (error) { throw new Error('Failed to add new projects'); diff --git a/apps/podium-service/pages/api/comments/[projectId].ts b/apps/podium-service/pages/api/comments/[projectId].ts index 8e3fadc7..314b9ced 100644 --- a/apps/podium-service/pages/api/comments/[projectId].ts +++ b/apps/podium-service/pages/api/comments/[projectId].ts @@ -1,11 +1,16 @@ import { supabase } from 'apps/podium-service/libs/supabase'; import { NextApiRequest, NextApiResponse } from 'next'; -export default async function handler(req: NextApiRequest, res: NextApiResponse) { +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { const { method, query, body } = req; const projectId = query.projectId as string; switch (method) { + case 'OPTIONS': + return res.status(200).send('ok'); case 'GET': try { const { data: commentsData, error: commentsError } = await supabase @@ -34,7 +39,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) // For faster lookup later const judgesMap = new Map(); judgeData.forEach((judge) => { - judgesMap.set(judge.user_id, `${judge.first_name} ${judge.last_name}`); + judgesMap.set( + judge.user_id, + `${judge.first_name} ${judge.last_name}` + ); }); const comments: CommentData[] = commentsData.map((c: any) => ({ @@ -53,4 +61,4 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) res.status(405).end(); break; } -} \ No newline at end of file +} diff --git a/apps/podium-service/pages/api/comments/[projectId]/user/[userId].ts b/apps/podium-service/pages/api/comments/[projectId]/user/[userId].ts index 203d8823..a50d2b74 100644 --- a/apps/podium-service/pages/api/comments/[projectId]/user/[userId].ts +++ b/apps/podium-service/pages/api/comments/[projectId]/user/[userId].ts @@ -1,26 +1,31 @@ import { supabase } from 'apps/podium-service/libs/supabase'; import { NextApiRequest, NextApiResponse } from 'next'; -export default async function handler(req: NextApiRequest, res: NextApiResponse) { +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { const { method, query, body } = req; const projectId = query.projectId as string; const userId = query.userId as string; switch (method) { + case 'OPTIONS': + return res.status(200).send('ok'); case 'POST': try { const { comment } = body; if (!comment || typeof comment !== 'string') { - return res.status(400).json({ error: 'Invalid request! Comment is required and must be a string.'}); + return res.status(400).json({ + error: 'Invalid request! Comment is required and must be a string.', + }); } - const { error } = await supabase - .from('comments') - .insert({ - project_id: projectId, - user_id: userId, - comment: comment - }); + const { error } = await supabase.from('comments').insert({ + project_id: projectId, + user_id: userId, + comment: comment, + }); if (error) { throw new Error('Failed to add new comment'); diff --git a/apps/podium-service/pages/api/comments/id/[commentId].ts b/apps/podium-service/pages/api/comments/id/[commentId].ts index c827a8f8..497abf14 100644 --- a/apps/podium-service/pages/api/comments/id/[commentId].ts +++ b/apps/podium-service/pages/api/comments/id/[commentId].ts @@ -1,16 +1,23 @@ import { supabase } from 'apps/podium-service/libs/supabase'; import { NextApiRequest, NextApiResponse } from 'next'; -export default async function handler(req: NextApiRequest, res: NextApiResponse) { +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { const { method, query, body } = req; const commentId = query.commentId as string; switch (method) { + case 'OPTIONS': + return res.status(200).send('ok'); case 'PUT': try { const { comment } = body; if (!comment || typeof comment !== 'string') { - return res.status(400).json({ error: 'Invalid request! Comment is required and must be a string.'}); + return res.status(400).json({ + error: 'Invalid request! Comment is required and must be a string.', + }); } const { error } = await supabase diff --git a/apps/podium-service/pages/api/judges.ts b/apps/podium-service/pages/api/judges.ts index 27676cb7..04dbb86e 100644 --- a/apps/podium-service/pages/api/judges.ts +++ b/apps/podium-service/pages/api/judges.ts @@ -1,10 +1,15 @@ import { supabase } from 'apps/podium-service/libs/supabase'; import { NextApiRequest, NextApiResponse } from 'next'; -export default async function handler(req: NextApiRequest, res: NextApiResponse) { +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { const { method, body } = req; switch (method) { + case 'OPTIONS': + return res.status(200).send('ok'); case 'GET': try { const { data: judgeData, error: judgeError } = await supabase @@ -13,9 +18,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) .select('*') .eq('role', 7); - const { data: judgeVerticalData, error: judgeVerticalError } = await supabase - .from('judges') - .select('*, verticals!inner(name)'); + const { data: judgeVerticalData, error: judgeVerticalError } = + await supabase.from('judges').select('*, verticals!inner(name)'); if (judgeError || judgeVerticalError) { throw new Error('Failed to fetch judges'); @@ -45,7 +49,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) judge.verticalId = j.vertical_id; judge.verticalName = j.verticals.name; } - }) + }); return res.json({ judges }); } catch (error) { diff --git a/apps/podium-service/pages/api/judges/[judgeId].ts b/apps/podium-service/pages/api/judges/[judgeId].ts index 528cc714..25256220 100644 --- a/apps/podium-service/pages/api/judges/[judgeId].ts +++ b/apps/podium-service/pages/api/judges/[judgeId].ts @@ -1,11 +1,16 @@ import { supabase } from 'apps/podium-service/libs/supabase'; import { NextApiRequest, NextApiResponse } from 'next'; -export default async function handler(req: NextApiRequest, res: NextApiResponse) { +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { const { method, query, body } = req; const judgeId = query.judgeId as string; switch (method) { + case 'OPTIONS': + return res.status(200).send('ok'); case 'GET': try { const { data, error } = await supabase @@ -29,18 +34,22 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) return res.json(judge); } catch (error) { + console.log(error); return res.status(500).json({ error: 'Internal Server Error' }); } case 'POST': try { const { verticalId } = body; if (!verticalId || typeof verticalId !== 'string') { - return res.status(400).json({ error: 'Invalid request! Vertical ID is required and must be a string.'}); + return res.status(400).json({ + error: + 'Invalid request! Vertical ID is required and must be a string.', + }); } const { error } = await supabase .from('judges') - .upsert({ 'user_id': judgeId, 'vertical_id': verticalId }); + .upsert({ user_id: judgeId, vertical_id: verticalId }); if (error) { throw new Error('Failed to set judge vertical'); diff --git a/apps/podium-service/pages/api/judges/bulk.ts b/apps/podium-service/pages/api/judges/bulk.ts index 0710fad5..77d2476f 100644 --- a/apps/podium-service/pages/api/judges/bulk.ts +++ b/apps/podium-service/pages/api/judges/bulk.ts @@ -1,9 +1,14 @@ import { NextApiRequest, NextApiResponse } from 'next'; -export default async function handler(req: NextApiRequest, res: NextApiResponse) { +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { const { method } = req; switch (method) { + case 'OPTIONS': + return res.status(200).send('ok'); case 'POST': return res.status(501).json({ error: 'Not implemented' }); default: diff --git a/apps/podium-service/pages/api/judges/invite.ts b/apps/podium-service/pages/api/judges/invite.ts new file mode 100644 index 00000000..0f46fa7b --- /dev/null +++ b/apps/podium-service/pages/api/judges/invite.ts @@ -0,0 +1,42 @@ +import { supabase } from 'apps/podium-service/libs/supabase'; +import { NextApiRequest, NextApiResponse } from 'next'; + +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { + const { method, body } = req; + + switch (method) { + case 'OPTIONS': + return res.status(200).send('ok'); + case 'POST': + try { + const { judgeEmail } = body; + + if (!judgeEmail) { + return res.status(400).json({ + error: 'Invalid Email!', + }); + } + + const { data, error } = await supabase.auth.admin.inviteUserByEmail( + judgeEmail + ); + + console.log(error); + + if (error) { + throw new Error('Failed to send invitation email'); + } + + return res.status(201).end(); + } catch (error) { + console.log(error); + return res.status(500).json({ error: error }); + } + default: + res.status(405).end(); + break; + } +} diff --git a/apps/podium-service/pages/api/lock/[verticalId].ts b/apps/podium-service/pages/api/lock/[verticalId].ts index 9eb62bf2..00a8c457 100644 --- a/apps/podium-service/pages/api/lock/[verticalId].ts +++ b/apps/podium-service/pages/api/lock/[verticalId].ts @@ -2,18 +2,23 @@ import { calculateRankings } from 'apps/podium-service/libs/calculateRankings'; import { supabase } from 'apps/podium-service/libs/supabase'; import { NextApiRequest, NextApiResponse } from 'next'; -export default async function handler(req: NextApiRequest, res: NextApiResponse) { +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { const { method, query, body } = req; const verticalId = query.verticalId as string; switch (method) { + case 'OPTIONS': + return res.status(200).send('ok'); case 'GET': try { const { data, error } = await supabase .from('ranking_locks') .select() .eq('vertical_id', verticalId); - + if (error) { throw new Error('Failed to fetch lockings'); } diff --git a/apps/podium-service/pages/api/notes/[verticalId]/[projectId]/[userId].ts b/apps/podium-service/pages/api/notes/[verticalId]/[projectId]/[userId].ts index f6394b43..58fcdcc1 100644 --- a/apps/podium-service/pages/api/notes/[verticalId]/[projectId]/[userId].ts +++ b/apps/podium-service/pages/api/notes/[verticalId]/[projectId]/[userId].ts @@ -1,13 +1,18 @@ import { supabase } from 'apps/podium-service/libs/supabase'; import { NextApiRequest, NextApiResponse } from 'next'; -export default async function handler(req: NextApiRequest, res: NextApiResponse) { +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { const { method, query, body } = req; const verticalId = query.verticalId as string; const projectId = query.projectId as string; const userId = query.userId as string; switch (method) { + case 'OPTIONS': + return res.status(200).send('ok'); case 'GET': try { const { data, error } = await supabase @@ -15,7 +20,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) .select('notes') .eq('project_id', projectId) .eq('user_id', userId); - + if (error) { throw new Error('Failed to fetch notes'); } @@ -34,16 +39,16 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) try { const { notes } = body; if (!notes || typeof notes !== 'string') { - return res.status(400).json({ error: 'Invalid request! Notes are required and must be a string.'}); + return res.status(400).json({ + error: 'Invalid request! Notes are required and must be a string.', + }); } - const { error } = await supabase - .from('notes') - .insert({ - project_id: projectId, - user_id: userId, - notes: notes - }); + const { error } = await supabase.from('notes').insert({ + project_id: projectId, + user_id: userId, + notes: notes, + }); if (error) { throw new Error('Failed to add notes'); diff --git a/apps/podium-service/pages/api/projects.ts b/apps/podium-service/pages/api/projects.ts index eab94577..10f5d9a6 100644 --- a/apps/podium-service/pages/api/projects.ts +++ b/apps/podium-service/pages/api/projects.ts @@ -1,10 +1,15 @@ import { supabase } from 'apps/podium-service/libs/supabase'; import { NextApiRequest, NextApiResponse } from 'next'; -export default async function handler(req: NextApiRequest, res: NextApiResponse) { +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { const { method, body } = req; switch (method) { + case 'OPTIONS': + return res.status(200).send('ok'); case 'GET': try { const { data, error } = await supabase.from('projects').select('*'); diff --git a/apps/podium-service/pages/api/projects/[verticalId].ts b/apps/podium-service/pages/api/projects/[verticalId].ts index cb7ec8ad..a963e4fa 100644 --- a/apps/podium-service/pages/api/projects/[verticalId].ts +++ b/apps/podium-service/pages/api/projects/[verticalId].ts @@ -1,11 +1,16 @@ import { supabase } from 'apps/podium-service/libs/supabase'; import { NextApiRequest, NextApiResponse } from 'next'; -export default async function handler(req: NextApiRequest, res: NextApiResponse) { +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { const { method, query, body } = req; const verticalId = query.verticalId as string; switch (method) { + case 'OPTIONS': + return res.status(200).send('ok'); case 'GET': try { const { data, error } = await supabase @@ -37,9 +42,23 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) } catch (error) { return res.status(500).json({ error: 'Internal Server Error' }); } - case 'POST': - const fields = ['name', 'teamMembers', 'description', 'imageUrl', 'devpostUrl', 'videoUrl']; - const fieldsDB = ['name', 'team', 'description', 'image_url', 'devpost_url', 'video_url']; + case 'POST': { + const fields = [ + 'name', + 'teamMembers', + 'description', + 'imageUrl', + 'devpostUrl', + 'videoUrl', + ]; + const fieldsDB = [ + 'name', + 'team', + 'description', + 'image_url', + 'devpost_url', + 'video_url', + ]; const addProject = {}; try { @@ -59,10 +78,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) } addProject['vertical_id'] = verticalId; - - const { error } = await supabase - .from('projects') - .insert(addProject); + + const { error } = await supabase.from('projects').insert(addProject); if (error) { throw new Error('Failed to add new project'); @@ -72,6 +89,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) } catch (error) { return res.status(500).json({ error: 'Internal Server Error' }); } + } default: res.status(405).end(); break; diff --git a/apps/podium-service/pages/api/projects/[verticalId]/[projectId].ts b/apps/podium-service/pages/api/projects/[verticalId]/[projectId].ts index 9bac7467..2328417c 100644 --- a/apps/podium-service/pages/api/projects/[verticalId]/[projectId].ts +++ b/apps/podium-service/pages/api/projects/[verticalId]/[projectId].ts @@ -1,12 +1,17 @@ import { supabase } from 'apps/podium-service/libs/supabase'; import { NextApiRequest, NextApiResponse } from 'next'; -export default async function handler(req: NextApiRequest, res: NextApiResponse) { +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { const { method, query, body } = req; - const verticalId = query.verticalId as string; + const verticalId = query.verticalId as string; const projectId = query.projectId as string; switch (method) { + case 'OPTIONS': + return res.status(200).send('ok'); case 'GET': try { const { data, error } = await supabase @@ -30,8 +35,22 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) return res.status(500).json({ error: 'Internal Server Error' }); } case 'PUT': - const fields = ['name', 'teamMembers', 'description', 'imageUrl', 'devpostUrl', 'videoUrl']; - const fieldsDB = ['name',' team', 'description', 'image_url', 'devpost_url', 'video_url']; + const fields = [ + 'name', + 'teamMembers', + 'description', + 'imageUrl', + 'devpostUrl', + 'videoUrl', + ]; + const fieldsDB = [ + 'name', + ' team', + 'description', + 'image_url', + 'devpost_url', + 'video_url', + ]; const updateProject: Partial = {}; try { diff --git a/apps/podium-service/pages/api/ranking.ts b/apps/podium-service/pages/api/ranking.ts index 3e6b411c..7830db6d 100644 --- a/apps/podium-service/pages/api/ranking.ts +++ b/apps/podium-service/pages/api/ranking.ts @@ -1,10 +1,15 @@ import { supabase } from 'apps/podium-service/libs/supabase'; import { NextApiRequest, NextApiResponse } from 'next'; -export default async function handler(req: NextApiRequest, res: NextApiResponse) { +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { const { method, body } = req; switch (method) { + case 'OPTIONS': + return res.status(200).send('ok'); case 'GET': try { const { data, error } = await supabase.from('ranking').select('*'); diff --git a/apps/podium-service/pages/api/ranking/[verticalId].ts b/apps/podium-service/pages/api/ranking/[verticalId].ts index b65aa9a1..a4553c32 100644 --- a/apps/podium-service/pages/api/ranking/[verticalId].ts +++ b/apps/podium-service/pages/api/ranking/[verticalId].ts @@ -3,23 +3,30 @@ import { isLocked } from 'apps/podium-service/libs/isLocked'; import { supabase } from 'apps/podium-service/libs/supabase'; import { NextApiRequest, NextApiResponse } from 'next'; -export default async function handler(req: NextApiRequest, res: NextApiResponse) { +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { const { method, query, body } = req; const verticalId = query.verticalId as string; switch (method) { + case 'OPTIONS': + return res.status(200).send('ok'); case 'GET': try { // If the vertical is not locked, then calculate the overall rankings first if (!isLocked(verticalId)) { calculateRankings(verticalId); } - + const { data, error } = await supabase .from('projects') - .select(`*, + .select( + `*, ranking_final( rank ), - verticals( name )`) + verticals( name )` + ) .eq('vertical_id', verticalId); if (error) { diff --git a/apps/podium-service/pages/api/ranking/[verticalId]/[userId].ts b/apps/podium-service/pages/api/ranking/[verticalId]/[userId].ts index 20f18fb5..e349eb6f 100644 --- a/apps/podium-service/pages/api/ranking/[verticalId]/[userId].ts +++ b/apps/podium-service/pages/api/ranking/[verticalId]/[userId].ts @@ -1,12 +1,17 @@ import { supabase } from 'apps/podium-service/libs/supabase'; import { NextApiRequest, NextApiResponse } from 'next'; -export default async function handler(req: NextApiRequest, res: NextApiResponse) { +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { const { method, query, body } = req; const verticalId = query.verticalId as string; const userId = query.userId as string; switch (method) { + case 'OPTIONS': + return res.status(200).send('ok'); case 'GET': try { const { data, error } = await supabase @@ -27,15 +32,17 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) return res.status(404).json({ error: 'No rankings found' }); } - const projects = data.map((p: any) => ({ - projectId: p.project_id, - projectName: p.name, - verticalId: p.vertical_id, - verticalName: p.verticals.name, - rank: p.ranking.length > 0 ? p.ranking[0].rank : null, - })); + const projects = data + .map((p: any) => ({ + projectId: p.project_id, + projectName: p.name, + verticalId: p.vertical_id, + verticalName: p.verticals.name, + rank: p.ranking.length > 0 ? p.ranking[0].rank : null, + })) + .filter((p) => p.rank != null); - return res.json({ projects }); + return res.json({ rankings: projects }); } catch (error) { return res.status(500).json({ error: 'Internal Server Error' }); } diff --git a/apps/podium-service/pages/api/verticals.ts b/apps/podium-service/pages/api/verticals.ts index ea24fcc0..39a48369 100644 --- a/apps/podium-service/pages/api/verticals.ts +++ b/apps/podium-service/pages/api/verticals.ts @@ -1,10 +1,15 @@ import { supabase } from 'apps/podium-service/libs/supabase'; import { NextApiRequest, NextApiResponse } from 'next'; -export default async function handler(req: NextApiRequest, res: NextApiResponse) { +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { const { method, body } = req; switch (method) { + case 'OPTIONS': + return res.status(200).send('ok'); case 'GET': try { const { data, error } = await supabase.from('verticals').select('*'); @@ -31,7 +36,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) try { const { name, description } = body; if (!name || typeof name !== 'string') { - return res.status(400).json({ error: 'Invalid request! Name is required and must be a string.'}); + return res.status(400).json({ + error: 'Invalid request! Name is required and must be a string.', + }); } const { error } = await supabase diff --git a/apps/podium-service/pages/api/verticals/[verticalId].ts b/apps/podium-service/pages/api/verticals/[verticalId].ts index fac2880b..1245677a 100644 --- a/apps/podium-service/pages/api/verticals/[verticalId].ts +++ b/apps/podium-service/pages/api/verticals/[verticalId].ts @@ -1,27 +1,29 @@ import { supabase } from 'apps/podium-service/libs/supabase'; import { NextApiRequest, NextApiResponse } from 'next'; -export default async function handler(req: NextApiRequest, res: NextApiResponse) { +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { const { method, query, body } = req; const verticalId = query.verticalId as string; const projectId = query.projectId as string; switch (method) { + case 'OPTIONS': + return res.status(200).send('ok'); case 'PUT': const fields = ['name', 'description']; const updateVertical = {}; try { - const { - name, - description, - } = body; + const { name, description } = body; fields.forEach((field) => { if (typeof body[field] !== undefined) { updateVertical[field] = body[field]; } - }) + }); const { error } = await supabase .from('verticals') diff --git a/apps/podium-service/project.json b/apps/podium-service/project.json index 1699d7e2..a059a284 100644 --- a/apps/podium-service/project.json +++ b/apps/podium-service/project.json @@ -29,7 +29,8 @@ "configurations": { "development": { "buildTarget": "podium-service:build:development", - "dev": true + "dev": true, + "port": 8080 }, "production": { "buildTarget": "podium-service:build:production", diff --git a/apps/podium/utils/getJudgeDetails.ts b/apps/podium/utils/getJudgeDetails.ts index ee595a85..76e8d209 100644 --- a/apps/podium/utils/getJudgeDetails.ts +++ b/apps/podium/utils/getJudgeDetails.ts @@ -7,6 +7,7 @@ export const getJudgeDetails = async ( accessToken: string ): Promise => { try { + console.log(accessToken); const response = await axios.get( `${HIBISCUS_PODIUM_API_URL}/judges/${userId}`, { headers: { Authorization: `Bearer ${accessToken}` } } diff --git a/apps/podium/utils/getProjects.ts b/apps/podium/utils/getProjects.ts index 39ca183e..e98db89c 100644 --- a/apps/podium/utils/getProjects.ts +++ b/apps/podium/utils/getProjects.ts @@ -71,19 +71,19 @@ const getProjects = async ( verticalId: string, accessToken: string ) => { - let unranked = []; - let ranked = []; + const unranked = []; + const ranked = []; const allProjects = await getVerticalProjects(verticalId, accessToken); const rankedBasic = await getRanked(userId, verticalId, accessToken); const rankedIds = rankedBasic.map((p) => p.projectId); - + allProjects.forEach((p) => { rankedIds.includes(p.projectId) ? ranked.push(p) : unranked.push(p); - }) + }); return [unranked, ranked]; }; -export default getProjects; \ No newline at end of file +export default getProjects;