From 69a6bb656e5611876195b9c69702293889cd3923 Mon Sep 17 00:00:00 2001 From: gibbyb Date: Thu, 17 Oct 2024 15:47:39 -0500 Subject: [PATCH] Server is done --- .../checkRelationshipStatus/route.ts | 37 ++++++++++ .../api/relationships/createRequest/route.ts | 38 ++++++++++ .../api/relationships/updateStatus/route.ts | 40 +++++++++++ src/app/api/users/createUser/route.ts | 36 ++++++++++ .../users/getInitialDataByAppleId/route.ts | 25 +++++++ src/app/api/users/search/route.ts | 38 ++++++++++ src/app/api/users/updatePfp/route.ts | 71 +++++++++++++++++++ src/app/api/users/updatePushToken/route.ts | 39 ++++++++++ src/middleware.ts | 22 ++++++ src/server/db/schema.ts | 26 +++---- src/server/functions.ts | 11 +++ 11 files changed, 370 insertions(+), 13 deletions(-) create mode 100644 src/app/api/relationships/checkRelationshipStatus/route.ts create mode 100644 src/app/api/relationships/createRequest/route.ts create mode 100644 src/app/api/relationships/updateStatus/route.ts create mode 100644 src/app/api/users/createUser/route.ts create mode 100644 src/app/api/users/getInitialDataByAppleId/route.ts create mode 100644 src/app/api/users/search/route.ts create mode 100644 src/app/api/users/updatePfp/route.ts create mode 100644 src/app/api/users/updatePushToken/route.ts create mode 100644 src/middleware.ts diff --git a/src/app/api/relationships/checkRelationshipStatus/route.ts b/src/app/api/relationships/checkRelationshipStatus/route.ts new file mode 100644 index 0000000..21edde4 --- /dev/null +++ b/src/app/api/relationships/checkRelationshipStatus/route.ts @@ -0,0 +1,37 @@ +'use server'; +import { NextResponse } from 'next/server'; +import type { NextRequest } from 'next/server'; +import { checkRelationshipStatus } from '~/server/functions'; +import { middleware } from '~/middleware'; +import type { RelationshipData } from '~/server/types'; + +export const GET = async (request: NextRequest) => { + const middlewareResponse = await middleware(request); + if (middlewareResponse) return middlewareResponse; + try { + const url = new URL(request.url); + const userId = Number.parseInt(url.searchParams.get('userId') ?? ''); + if (!userId || isNaN(userId)) + return NextResponse.json( + { message: 'Missing userId' }, { status: 400 } + ); + const relationshipData: RelationshipData | null = await checkRelationshipStatus(userId); + if (!relationshipData) { + return NextResponse.json( + { message: 'No relationship data found' }, { status: 404 } + ); + } + return NextResponse.json(relationshipData); + } catch (error) { + console.error('Error checking relationship status:', error); + if (error instanceof Error) { + return NextResponse.json( + { message: error.message }, { status: 500 } + ); + } else { + return NextResponse.json( + { message: 'Unknown error occurred' }, { status: 500 } + ); + } + } +}; diff --git a/src/app/api/relationships/createRequest/route.ts b/src/app/api/relationships/createRequest/route.ts new file mode 100644 index 0000000..fa454bf --- /dev/null +++ b/src/app/api/relationships/createRequest/route.ts @@ -0,0 +1,38 @@ +'use server'; +import { NextResponse } from 'next/server'; +import type { NextRequest } from 'next/server'; +import { createRelationshipRequest } from '~/server/functions'; +import { middleware } from '~/middleware'; +import type { RelationshipData } from '~/server/types'; + +export const POST = async (request: NextRequest) => { + const middlewareResponse = await middleware(request); + if (middlewareResponse) return middlewareResponse; + try { + const url = new URL(request.url); + const userId = Number.parseInt(url.searchParams.get('userId') ?? ''); + const partnerId = Number.parseInt(url.searchParams.get('partnerId') ?? ''); + if (!userId || !partnerId || isNaN(userId) || isNaN(partnerId)) + return NextResponse.json( + { message: 'Missing userId or partnerId' }, { status: 400 } + ); + const relationshipData: RelationshipData | null = await createRelationshipRequest(userId, partnerId); + if (!relationshipData) { + return NextResponse.json( + { message: 'Error creating relationship request' }, { status: 500 } + ); + } + return NextResponse.json(relationshipData); + } catch (error) { + console.error('Error creating relationship request:', error); + if (error instanceof Error) { + return NextResponse.json( + { message: error.message }, { status: 500 } + ); + } else { + return NextResponse.json( + { message: 'Unknown error occurred' }, { status: 500 } + ); + } + } +}; diff --git a/src/app/api/relationships/updateStatus/route.ts b/src/app/api/relationships/updateStatus/route.ts new file mode 100644 index 0000000..8abce18 --- /dev/null +++ b/src/app/api/relationships/updateStatus/route.ts @@ -0,0 +1,40 @@ +'use server'; +import { NextResponse } from 'next/server'; +import type { NextRequest } from 'next/server'; +import { updateRelationshipStatus } from '~/server/functions'; +import { middleware } from '~/middleware'; +import type { RelationshipData } from '~/server/types'; + +export const POST = async (request: NextRequest) => { + const middlewareResponse = await middleware(request); + if (middlewareResponse) return middlewareResponse; + try { + const url = new URL(request.url); + const userId = Number.parseInt(url.searchParams.get('userId') ?? ''); + const status = url.searchParams.get('status'); + if (!userId || !status || isNaN(userId)) + return NextResponse.json( + { message: 'Missing userId or status' }, { status: 400 } + ); + const theStatus = status === 'accepted' ? 'accepted' : 'rejected'; + const relationshipData: RelationshipData | null | undefined = + await updateRelationshipStatus(userId, theStatus); + if (!relationshipData || relationshipData === undefined) { + return NextResponse.json( + { message: 'Error updating relationship status' }, { status: 500 } + ); + } + return NextResponse.json(relationshipData); + } catch (error) { + console.error('Error updating relationship status:', error); + if (error instanceof Error) { + return NextResponse.json( + { message: error.message }, { status: 500 } + ); + } else { + return NextResponse.json( + { message: 'Unknown error occurred' }, { status: 500 } + ); + } + } +}; diff --git a/src/app/api/users/createUser/route.ts b/src/app/api/users/createUser/route.ts new file mode 100644 index 0000000..38cbff8 --- /dev/null +++ b/src/app/api/users/createUser/route.ts @@ -0,0 +1,36 @@ +'use server'; +import { NextResponse } from 'next/server'; +import type { NextRequest } from 'next/server'; +import { createUser } from '~/server/functions'; +import { middleware } from '~/middleware'; +import type { User } from '~/server/types'; + +export const POST = async (request: NextRequest) => { + const middlewareResponse = await middleware(request); + if (middlewareResponse) return middlewareResponse; + try { + const url = new URL(request.url); + const appleId = url.searchParams.get('appleId'); + const email = url.searchParams.get('email'); + const fullName = url.searchParams.get('fullName'); + const pushToken = url.searchParams.get('pushToken'); + if (!appleId || !email || !fullName || !pushToken) + return NextResponse.json( + { message: 'Missing required parameters' }, { status: 400 } + ); + const newUser: User | null = await createUser(appleId, email, fullName, pushToken); + if (!newUser) { + return NextResponse.json( + { message: 'Error creating user' }, { status: 500 } + ); + } + return NextResponse.json(newUser); + } catch (error) { + console.error('Error creating user:', error); + if (error instanceof Error) { + return NextResponse.json({ message: error.message }, { status: 500 }); + } else { + return NextResponse.json({ message: 'Unknown error occurred' }, { status: 500 }); + } + } +}; diff --git a/src/app/api/users/getInitialDataByAppleId/route.ts b/src/app/api/users/getInitialDataByAppleId/route.ts new file mode 100644 index 0000000..62f28a7 --- /dev/null +++ b/src/app/api/users/getInitialDataByAppleId/route.ts @@ -0,0 +1,25 @@ +'use server'; +import { NextResponse } from 'next/server'; +import type { NextRequest } from 'next/server'; +import { getInitialDataByAppleId } from '~/server/functions'; +import { middleware } from '~/middleware'; +import type { InitialData } from '~/server/types'; + +export const GET = async (request: NextRequest) => { + const middlewareResponse = await middleware(request); + if (middlewareResponse) return middlewareResponse; + try { + const url = new URL(request.url); + const appleId = url.searchParams.get('appleId'); + if (!appleId) + return NextResponse.json({ message: 'Missing appleId' }, { status: 400 }); + const initialData: InitialData | null = await getInitialDataByAppleId(appleId); + if (!initialData) { + return NextResponse.json({ message: 'No initial data found' }, { status: 404 }); + } + return NextResponse.json(initialData); + } catch (error) { + console.error('Error parsing request:', error); + return NextResponse.json({ message: 'Invalid request' }, { status: 400 }); + } +}; diff --git a/src/app/api/users/search/route.ts b/src/app/api/users/search/route.ts new file mode 100644 index 0000000..d001240 --- /dev/null +++ b/src/app/api/users/search/route.ts @@ -0,0 +1,38 @@ +'use server'; +import { NextResponse } from 'next/server'; +import type { NextRequest } from 'next/server'; +import { searchUsers } from '~/server/functions'; +import { middleware } from '~/middleware'; +import type { User } from '~/server/types'; + +export const GET = async (request: NextRequest) => { + const middlewareResponse = await middleware(request); + if (middlewareResponse) return middlewareResponse; + try { + const url = new URL(request.url); + const userId = Number.parseInt(url.searchParams.get('userId') ?? ''); + const searchTerm = url.searchParams.get('searchTerm'); + if (!userId || !searchTerm || isNaN(userId)) + return NextResponse.json( + { message: 'Missing userId or searchTerm' }, { status: 400 } + ); + const users: User[] | undefined = await searchUsers(userId, searchTerm); + if (users === undefined) { + return NextResponse.json( + { message: 'No users found' }, { status: 404 } + ); + } + return NextResponse.json(users); + } catch (error) { + console.error('Error searching users:', error); + if (error instanceof Error) { + return NextResponse.json( + { message: error.message }, { status: 500 } + ); + } else { + return NextResponse.json( + { message: 'Unknown error occurred' }, { status: 500 } + ); + } + } +}; diff --git a/src/app/api/users/updatePfp/route.ts b/src/app/api/users/updatePfp/route.ts new file mode 100644 index 0000000..60a3219 --- /dev/null +++ b/src/app/api/users/updatePfp/route.ts @@ -0,0 +1,71 @@ +'use server'; +import { NextResponse } from 'next/server'; +import type { NextRequest } from 'next/server'; +import { updatePfpUrl, getPfpUrl, getUser } from '~/server/functions'; +import { middleware } from '~/middleware'; +import fs from 'fs/promises'; +import path from 'path'; +import type { User } from '~/server/types'; + +const UPLOAD_DIR = path.join(process.cwd(), `public/${process.env.UPLOAD_DIR}`); + +export const POST = async (request: NextRequest) => { + const middlewareResponse = await middleware(request); + if (middlewareResponse) { + console.log('Middleware rejected the request'); + return middlewareResponse; + } + try { + const formData = await request.formData(); + const file = formData.get('file') as File | null; + const userId = formData.get('userId') as number | null; + if (!file || !userId) + return NextResponse.json({ message: 'Missing file or userId' }, { status: 400 }); + if (!file.type.startsWith('image/')) + return NextResponse.json({ message: 'Invalid file type' }, { status: 400 }); + await fs.mkdir(UPLOAD_DIR, { recursive: true }); + + // Generate name for the uploaded file + const fileExtension = path.extname(file.name); + const fileName = `${userId}_${Date.now()}${fileExtension}`; + const filePath = path.join(UPLOAD_DIR, fileName); + + // Write the file to the upload directory + const buffer = Buffer.from(await file.arrayBuffer()); + await fs.writeFile(filePath, buffer); + const pfpUrl = `/${process.env.UPLOAD_DIR}/${fileName}`; + + // Delete the old pfp file if it exists + const oldPfpUrl = await getPfpUrl(userId); + if (oldPfpUrl) { + const oldFilePath = path.join(process.cwd(), 'public', oldPfpUrl); + await fs.unlink(oldFilePath).catch((error) => { + console.error('Error deleting old pfp file:', error); + }); + } else { + console.log('No old pfp file found'); + } + // Update the pfpUrl in the database + const result = await updatePfpUrl(userId, pfpUrl); + if (!result) { + console.log('Error updating pfp url in database'); + return NextResponse.json({ message: 'Error updating pfp url in database' }, { status: 500 }); + } + // Get the updated user + const user: User | null = await getUser(userId); + if (!user) { + console.log('Error getting user from database'); + return NextResponse.json({ message: 'Error getting user from database' }, { status: 500 }); + } + // Return the updated user + return NextResponse.json(user); + + } catch (error) { + console.error('Error updating pfp:', error); + if (error instanceof Error) { + return NextResponse.json({ message: error.message }, { status: 500 }); + } else { + return NextResponse.json({ message: 'Unknown error occurred' }, { status: 500 }); + } + } +}; diff --git a/src/app/api/users/updatePushToken/route.ts b/src/app/api/users/updatePushToken/route.ts new file mode 100644 index 0000000..fb3d27f --- /dev/null +++ b/src/app/api/users/updatePushToken/route.ts @@ -0,0 +1,39 @@ +'use server'; +import { NextResponse } from 'next/server'; +import type { NextRequest } from 'next/server'; +import { updatePushToken } from '~/server/functions'; +import { middleware } from '~/middleware'; + +export const POST = async (request: NextRequest) => { + const middlewareResponse = await middleware(request); + if (middlewareResponse) return middlewareResponse; + try { + const url = new URL(request.url); + const userId = Number.parseInt(url.searchParams.get('userId') ?? ''); + const pushToken = url.searchParams.get('pushToken'); + if (!userId || !pushToken || isNaN(userId)) + return NextResponse.json( + { message: 'Missing userId or pushToken' }, { status: 400 } + ); + const result = await updatePushToken(userId, pushToken); + if (!result) { + return NextResponse.json( + { message: 'Error updating push token' }, { status: 500 } + ); + } + return NextResponse.json( + { message: 'Push token updated successfully' }, { status: 200 } + ); + } catch (error) { + console.error('Error updating push token:', error); + if (error instanceof Error) { + return NextResponse.json( + { message: error.message }, { status: 500 } + ); + } else { + return NextResponse.json( + { message: 'Unknown error occurred' }, { status: 500 } + ); + } + } +}; diff --git a/src/middleware.ts b/src/middleware.ts new file mode 100644 index 0000000..721a5cb --- /dev/null +++ b/src/middleware.ts @@ -0,0 +1,22 @@ +import { NextResponse } from 'next/server'; +import type { NextRequest } from 'next/server'; + +export async function middleware(request: NextRequest): Promise { + try { + const apiKey = request.headers.get('x-api-key'); + + if (!apiKey || apiKey !== process.env.API_KEY) { + return NextResponse.json({ message: 'Invalid API key' }, { status: 401 }); + } + + // If the API key is valid, we don't return anything, allowing the request to proceed + return undefined; + } catch (error) { + console.error('Middleware error:', error); + return NextResponse.json({ message: 'Internal server error' }, { status: 500 }); + } +} + +export const config = { + matcher: '/api/:path*', +}; diff --git a/src/server/db/schema.ts b/src/server/db/schema.ts index 7ead117..a0cf622 100644 --- a/src/server/db/schema.ts +++ b/src/server/db/schema.ts @@ -28,9 +28,9 @@ export const users = pgTable( metadata: jsonb('metadata'), }, (table) => ({ - appleIdIndex: index('apple_id_idx').on(table.appleId), - emailIndex: index('email_idx').on(table.email), - fullNameIndex: index('full_name_idx').on(table.fullName), + appleIdIndex: index('users_apple_id_idx').on(table.appleId), + emailIndex: index('users_email_idx').on(table.email), + fullNameIndex: index('users_full_name_idx').on(table.fullName), }) ); @@ -46,7 +46,7 @@ export const relationships = pgTable( .default(sql`CURRENT_TIMESTAMP`).notNull(), }, (table) => ({ - requestorIdIndex: index('requestor_id_idx').on(table.requestorId), + requestorIdIndex: index('relationships_requestor_id_idx').on(table.requestorId), }) ); @@ -58,8 +58,8 @@ export const userRelationships = pgTable( relationshipId: integer('relationship_id').references(() => relationships.id).notNull(), }, (table) => ({ - userIdIndex: index('user_id_idx').on(table.userId), - relationshipIdIndex: index('relationship_id_idx').on(table.relationshipId), + userIdIndex: index('user_relationships_user_id_idx').on(table.userId), + relationshipIdIndex: index('user_relationships_relationship_id_idx').on(table.relationshipId), }) ); @@ -75,7 +75,7 @@ export const countdowns = pgTable( .default(sql`CURRENT_TIMESTAMP`).notNull(), }, (table) => ({ - relationshipIdIndex: index('relationship_id_idx').on(table.relationshipId), + relationshipIdIndex: index('countdowns_relationship_id_idx').on(table.relationshipId), }) ); @@ -94,8 +94,8 @@ export const messages = pgTable( hasQuickReply: boolean('has_quick_reply').default(false), }, (table) => ({ - senderIdIndex: index('sender_id_idx').on(table.senderId), - receiverIdIndex: index('receiver_id_idx').on(table.receiverId), + senderIdIndex: index('messages_sender_id_idx').on(table.senderId), + receiverIdIndex: index('messages_receiver_id_idx').on(table.receiverId), }) ); @@ -115,7 +115,7 @@ export const media = pgTable( order: integer('order'), }, (table) => ({ - messageIdIndex: index('message_id_idx').on(table.messageId), + messageIdIndex: index('media_message_id_idx').on(table.messageId), }) ); @@ -128,7 +128,7 @@ export const locations = pgTable( longitude: numeric('longitude').notNull(), }, (table) => ({ - messageIdIndex: index('message_id_idx').on(table.messageId), + messageIdIndex: index('locations_message_id_idx').on(table.messageId), }) ); @@ -145,7 +145,7 @@ export const quickReplies = pgTable( keepIt: boolean('keep_it').default(false), }, (table) => ({ - messageIdIndex: index('message_id_idx').on(table.messageId), + messageIdIndex: index('quick_replies_message_id_idx').on(table.messageId), }) ); @@ -158,6 +158,6 @@ export const quickReplyOptions = pgTable( value: varchar('value', { length: 100 }).notNull(), }, (table) => ({ - quickReplyIdIndex: index('quick_reply_id_idx').on(table.quickReplyId), + quickReplyIdIndex: index('qr_options_quick_reply_id_idx').on(table.quickReplyId), }) ); diff --git a/src/server/functions.ts b/src/server/functions.ts index 3971403..1efae5b 100644 --- a/src/server/functions.ts +++ b/src/server/functions.ts @@ -140,6 +140,17 @@ export const updatePushToken = async (userId: number, pushToken: string): Promis } }; +export const getPfpUrl = async (userId: number) => { + try { + const users = await db.select().from(schema.users) + .where(eq(schema.users.id, userId)) + const user = users[0] as User; + return (users === undefined) ? user.pfpUrl : null; + } catch (error) { + console.error('Error getting pfp url:', error); + } +}; + export const updatePfpUrl = async (userId: number, pfpUrl: string) => { try { const result = await db.update(schema.users)