Skip to content

Commit ab508dd

Browse files
Cleaned up api path structure.
1 parent 84688d0 commit ab508dd

File tree

7 files changed

+270
-0
lines changed

7 files changed

+270
-0
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { NextResponse } from 'next/server'
2+
3+
export async function GET() {
4+
return NextResponse.json({
5+
publicKey: process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY,
6+
})
7+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { NextResponse } from 'next/server'
2+
import { PrismaClient } from '@prisma/client'
3+
import webpush, { WebPushError } from 'web-push'
4+
import { messaging } from 'firebase-admin'
5+
import { sendNotification, SubscriptionRecord } from '../../../../lib/notifications'
6+
7+
const prisma = new PrismaClient()
8+
9+
export async function POST(request: Request) {
10+
try {
11+
const { title, body, url } = await request.json()
12+
13+
if (!title || !body || !url) {
14+
return NextResponse.json({ error: 'Missing required fields' }, { status: 400 })
15+
}
16+
17+
// Retrieve all subscriptions for sending notifications
18+
const subscriptions = await prisma.subscription.findMany()
19+
20+
// Build your unified payload object
21+
const notificationPayload = {
22+
title: `${title}`,
23+
body: body,
24+
url: url,
25+
icon: 'https://new.codebuilder.org/images/logo2.png',
26+
badge: 'https://new.codebuilder.org/images/logo2.png',
27+
}
28+
29+
// Loop and send notifications concurrently
30+
const notificationPromises = subscriptions.map((sub) =>
31+
sendNotification(sub, notificationPayload)
32+
)
33+
34+
// Wait for all notifications to complete
35+
await Promise.all(notificationPromises)
36+
37+
return NextResponse.json({ success: true, message: 'Notifications sent successfully' })
38+
} catch (error) {
39+
console.error('Error sending notifications:', error)
40+
return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 })
41+
}
42+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { NextRequest, NextResponse } from 'next/server'
2+
import { PrismaClient } from '@prisma/client'
3+
4+
const prisma = new PrismaClient()
5+
6+
export async function POST(req: NextRequest) {
7+
try {
8+
const subscription = await req.json()
9+
10+
console.log('Subscription data:', subscription)
11+
12+
// Validate required fields
13+
if (!subscription.endpoint || !subscription.type) {
14+
return NextResponse.json({ error: 'Invalid subscription data.' }, { status: 400 })
15+
}
16+
17+
if (subscription.type === 'fcm') {
18+
if (!subscription.keys?.token) {
19+
return NextResponse.json(
20+
{ error: 'Invalid FCM subscription data: missing token.' },
21+
{ status: 400 }
22+
)
23+
}
24+
} else if (subscription.type === 'web') {
25+
if (!subscription.keys?.p256dh || !subscription.keys?.auth) {
26+
return NextResponse.json(
27+
{ error: 'Invalid web-push subscription data: missing keys.' },
28+
{ status: 400 }
29+
)
30+
}
31+
}
32+
33+
// Get the IP address from the headers
34+
const forwardedFor = req.headers.get('x-forwarded-for') || ''
35+
const ipAddress = forwardedFor.split(',')[0].trim() || 'Unknown'
36+
37+
// Serialize keys if necessary
38+
const keys = subscription.keys ?? {}
39+
40+
// Declare the variable outside the if-else block
41+
let newSubscription
42+
43+
// Save the subscription to the database
44+
const existingSubscription = await prisma.subscription.findFirst({
45+
where: {
46+
endpoint: subscription.endpoint,
47+
type: subscription.type,
48+
},
49+
})
50+
51+
if (existingSubscription) {
52+
// Update the existing record
53+
newSubscription = await prisma.subscription.update({
54+
where: { id: existingSubscription.id },
55+
data: { ipAddress, keys },
56+
})
57+
} else {
58+
// Create a new record
59+
newSubscription = await prisma.subscription.create({
60+
data: {
61+
type: subscription.type,
62+
endpoint: subscription.endpoint,
63+
ipAddress,
64+
keys,
65+
},
66+
})
67+
}
68+
69+
// Respond with the new subscription
70+
return NextResponse.json(
71+
{ message: 'Subscription added.', data: newSubscription },
72+
{ status: 201 }
73+
)
74+
} catch (error) {
75+
console.log(error.stack)
76+
console.log('Error saving subscription:', error)
77+
return NextResponse.json({ error: 'Failed to save subscription.' }, { status: 500 })
78+
} finally {
79+
await prisma.$disconnect()
80+
}
81+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { NextResponse } from 'next/server'
2+
import { checkRedditMessages } from '@/lib/reddit'
3+
4+
export async function GET() {
5+
try {
6+
const newMessages = await checkRedditMessages()
7+
return NextResponse.json({
8+
success: true,
9+
count: newMessages.length,
10+
messages: newMessages,
11+
})
12+
} catch (error) {
13+
return NextResponse.json({ success: false, error: error.message }, { status: 500 })
14+
}
15+
}
16+
17+
export const dynamic = 'force-dynamic'

src/app/api/reddit/messages/route.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { NextResponse } from 'next/server'
2+
import prisma from '@/lib/db'
3+
4+
export async function GET(request: Request) {
5+
const { searchParams } = new URL(request.url)
6+
const type = searchParams.get('type')
7+
8+
const messages = await prisma.redditMessage.findMany({
9+
where: type ? { type } : undefined,
10+
orderBy: { createdAt: 'desc' },
11+
take: 50,
12+
})
13+
14+
return NextResponse.json(messages)
15+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { NextRequest, NextResponse } from 'next/server'
2+
import { fetchRedditPosts } from '@/lib/reddit'
3+
import webpush from 'web-push'
4+
import { sendNotification } from '@/lib/notifications'
5+
import prisma from '@/lib/db'
6+
7+
// List of subreddits to monitor for new posts
8+
const SUBREDDITS = [
9+
'forhire',
10+
'jobs4bitcoins',
11+
'freelance',
12+
'remotejs',
13+
'jobs4dogecoins',
14+
'jobs4crypto',
15+
]
16+
17+
// Set up web-push VAPID keys for push notifications
18+
webpush.setVapidDetails(
19+
20+
process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY!,
21+
process.env.VAPID_PRIVATE_KEY!
22+
)
23+
24+
export async function GET(req: NextRequest) {
25+
try {
26+
// Fetch posts from the specified subreddits
27+
const posts = await fetchRedditPosts(SUBREDDITS)
28+
29+
// Retrieve all subscriptions for sending notifications
30+
const subscriptions = await prisma.subscription.findMany()
31+
32+
for (const post of posts) {
33+
// Check if the post is marked with '[Hiring]'
34+
if (!post.title.includes('[Hiring]')) continue
35+
36+
// Ensure the post is not already in the database
37+
const existingPost = await prisma.post.findUnique({
38+
where: { url: post.url },
39+
})
40+
if (existingPost) continue
41+
42+
// Add the post to the database if it's new
43+
const createdPost = await prisma.post.create({ data: post })
44+
45+
// 2. Build your unified payload object
46+
const notificationPayload = {
47+
title: `${createdPost.title} (${createdPost.subreddit} - ${createdPost.author})`,
48+
body: `${createdPost.title}`,
49+
url: createdPost.url,
50+
icon: 'https://new.codebuilder.org/images/logo2.png',
51+
badge: 'https://new.codebuilder.org/images/logo2.png',
52+
}
53+
54+
// 3. Loop and send notifications concurrently
55+
const notificationPromises = subscriptions.map((sub) =>
56+
sendNotification(sub, notificationPayload)
57+
)
58+
59+
// 4. Wait for all notifications to complete
60+
await Promise.all(notificationPromises)
61+
}
62+
63+
// Respond with success if posts fetched and processed successfully
64+
return NextResponse.json({ message: 'Posts fetched and stored successfully.' })
65+
} catch (error) {
66+
// Log any errors and respond with a 500 status code
67+
console.log(error) //error()
68+
return NextResponse.json({ error: 'An error occurred while fetching posts.' }, { status: 500 })
69+
} finally {
70+
// Ensure the Prisma client is disconnected after execution
71+
await prisma.$disconnect()
72+
}
73+
}

src/app/api/reddit/posts/route.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { NextRequest, NextResponse } from 'next/server'
2+
import prisma from '@/lib/db'
3+
4+
export async function GET(request: NextRequest) {
5+
try {
6+
// Parse query parameters for pagination
7+
const { searchParams } = new URL(request.url)
8+
const page = parseInt(searchParams.get('page') || '1', 10)
9+
const pageSize = parseInt(searchParams.get('pageSize') || '10', 10)
10+
11+
// Calculate skip value
12+
const skip = (page - 1) * pageSize
13+
14+
// Fetch paginated posts from Prisma
15+
const posts = await prisma.post.findMany({
16+
orderBy: { createdAt: 'desc' },
17+
skip,
18+
take: pageSize,
19+
// select: { id: true, title: true, ... } // You can choose which fields to return
20+
})
21+
22+
// Optionally, get the total number of posts to return along with pagination info
23+
const totalCount = await prisma.post.count()
24+
25+
return NextResponse.json({
26+
data: posts,
27+
page,
28+
pageSize,
29+
totalCount,
30+
})
31+
} catch (error) {
32+
// Handle any errors
33+
return NextResponse.json({ error: (error as Error).message }, { status: 500 })
34+
}
35+
}

0 commit comments

Comments
 (0)