Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -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}
3 changes: 2 additions & 1 deletion apps/event-service-next/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down
58 changes: 52 additions & 6 deletions apps/podium-service/middleware.ts
Original file line number Diff line number Diff line change
@@ -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')
Expand Down Expand Up @@ -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';
Expand All @@ -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'],
Expand All @@ -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');
Expand All @@ -100,3 +130,19 @@ export async function middleware(req: NextRequest) {
export const config = {
matcher: '/api/:path*',
};

async function verifyToken(access_token: string): Promise<UserResponse> {
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
);
}
22 changes: 22 additions & 0 deletions apps/podium-service/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
50 changes: 38 additions & 12 deletions apps/podium-service/pages/api/add_projects.ts
Original file line number Diff line number Diff line change
@@ -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 = {};

Expand All @@ -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];

Expand All @@ -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');
Expand Down
14 changes: 11 additions & 3 deletions apps/podium-service/pages/api/comments/[projectId].ts
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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) => ({
Expand All @@ -53,4 +61,4 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
res.status(405).end();
break;
}
}
}
Original file line number Diff line number Diff line change
@@ -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');
Expand Down
11 changes: 9 additions & 2 deletions apps/podium-service/pages/api/comments/id/[commentId].ts
Original file line number Diff line number Diff line change
@@ -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
Expand Down
14 changes: 9 additions & 5 deletions apps/podium-service/pages/api/judges.ts
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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');
Expand Down Expand Up @@ -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) {
Expand Down
Loading
Loading