Skip to content

Commit

Permalink
feat: add premium routes and handle webhook
Browse files Browse the repository at this point in the history
  • Loading branch information
Vann-Dev committed Apr 30, 2024
1 parent 3f1c412 commit 20f15a8
Show file tree
Hide file tree
Showing 14 changed files with 474 additions and 21 deletions.
10 changes: 6 additions & 4 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { FastifyPluginAsync } from 'fastify';
import { fileURLToPath } from 'url'
import cors from '@fastify/cors'
import Middie from '@fastify/middie'
import { bypassMiddleware } from './constant/bypassMiddleware.js';

const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
Expand Down Expand Up @@ -33,10 +34,12 @@ const app: FastifyPluginAsync<AppOptions> = async (

async function middleWareSystem() {
fastify.addHook('onRequest', async (request, reply) => {
const token = request.headers.authorization;
if (!bypassMiddleware.some((route) => request.url.includes(route))) {
const token = request.headers.authorization;

if (!token) return reply.unauthorized();
if (token !== process.env.AUTH) return reply.unauthorized();
if (!token) return reply.unauthorized();
if (token !== process.env.AUTH) return reply.unauthorized();
}
})
}

Expand All @@ -58,7 +61,6 @@ const app: FastifyPluginAsync<AppOptions> = async (
options: opts,
forceESM: true
})

};

export default app;
Expand Down
5 changes: 5 additions & 0 deletions src/constant/bypassMiddleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const bypassMiddleware = [
"/checkout/",
"/webhook/",
"/premium/"
]
6 changes: 6 additions & 0 deletions src/constant/premiumCount.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const premiumCount = {
FREE: 0,
SILVER: 1,
GOLD: 4,
DIAMOND: 6
}
13 changes: 0 additions & 13 deletions src/routes/guild/editable.ts

This file was deleted.

7 changes: 5 additions & 2 deletions src/routes/guild/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ export async function get(request: FastifyRequest, reply: FastifyReply) {
guildId: params.id
},
create: {
guildId: params.id
guildId: params.id,
},
update: {}
update: {},
include: {
subscription: true
}
})

return reply.send({ data: guilds });
Expand Down
2 changes: 0 additions & 2 deletions src/routes/guild/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@ import { FastifyPluginAsync } from "fastify"
import { get } from "./get.js";
import { post } from "./post.js";
import { put } from "./put.js";
import { editable } from "./editable.js";
import { info } from "./info.js";

const route: FastifyPluginAsync = async (fastify, opts): Promise<void> => {
fastify.get('/:id', get)
fastify.post('/:id', post)
fastify.put('/:id', put)

fastify.get('/editable/:id', editable)

fastify.get('/info/:id', info)
}
Expand Down
4 changes: 4 additions & 0 deletions src/routes/guild/info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ export async function info(request: FastifyRequest, reply: FastifyReply) {
}
})

if (!response.ok) {
return reply.status(404).send({ message: 'Guild not found' });
}

const data = await response.json()

return reply.send({ data: data });
Expand Down
47 changes: 47 additions & 0 deletions src/routes/user/guild.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { FastifyReply, FastifyRequest } from "fastify";
import prisma from "../../lib/prisma.js";

export async function guild(request: FastifyRequest, reply: FastifyReply) {
const params = request.params as { id: string };
const body = request.body as {
data: {
guildId: string;
}[],
premiumCount: number;
}

const data = await prisma.subscription.update({
where: {
userId: params.id
},
data: {
premiumGuild: {
set: body.data
},
premiumCount: {
set: body.premiumCount
}
},
select: {
premiumGuild: true,
userId: true
}
})

if (data.premiumGuild.length < body.data.length) {
await prisma.subscription.update({
where: {
userId: params.id
},
data: {
premiumCount: {
set: body.data.length - data.premiumGuild.length + body.premiumCount
}
}
})
}

return reply.send({
data: data.userId
});
}
10 changes: 10 additions & 0 deletions src/routes/user/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { FastifyPluginAsync } from "fastify"
import { tier } from "./tier.js";
import { guild } from "./guild.js";

const route: FastifyPluginAsync = async (fastify, opts): Promise<void> => {
fastify.get("/tier/:id", tier)
fastify.post("/guild/:id", guild)
}

export default route;
28 changes: 28 additions & 0 deletions src/routes/user/tier.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { FastifyReply, FastifyRequest } from "fastify";
import prisma from "../../lib/prisma.js";

export async function tier(request: FastifyRequest, reply: FastifyReply) {
const params = request.params as { id: string };

const subscription = await prisma.subscription.findFirst({
where: {
userId: params.id
},
select: {
premiumTier: true,
premiumCount: true,
premiumGuild: true
}
})

const tier = subscription ? subscription.premiumTier : "FREE";
const count = subscription ? subscription.premiumCount : 0;

return reply.send({
data: {
tier: tier,
count: count,
premiumGuild: subscription?.premiumGuild
}
});
}
10 changes: 10 additions & 0 deletions src/routes/webhook/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { FastifyPluginAsync } from "fastify"
import { paymentComplete } from "./paymentComplete.js";
import { recurringEnd } from "./recurringEnd.js";

const route: FastifyPluginAsync = async (fastify, opts): Promise<void> => {
fastify.post("/payment-complete", paymentComplete)
fastify.post("/recurring-end", recurringEnd)
}

export default route;
62 changes: 62 additions & 0 deletions src/routes/webhook/paymentComplete.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { FastifyReply, FastifyRequest } from "fastify";
import { PaymentCompleteWebhook } from "../../typings/index.js";
import prisma from "../../lib/prisma.js";
import { premiumCount } from "../../constant/premiumCount.js";
import crypto from "crypto";

export async function paymentComplete(request: FastifyRequest, reply: FastifyReply) {
const body = request.body as PaymentCompleteWebhook;

const bodyHash = crypto
.createHash('sha256')
.update(JSON.stringify(request.body), 'utf-8')
.digest('hex');

const finalHash = crypto.createHmac('sha256', process.env.TEBEX_SECRET as string)
.update(bodyHash)
.digest('hex');

if (finalHash !== request.headers["x-signature"]) {
return reply.notFound();
}

// used for verifying the webhook
if (body.type === "validation.webhook") {
return reply.send({
"id": body.id
});
}

const subscription = await prisma.subscription.findFirst({
where: {
userId: body.subject.customer.username.id
}
})

const tierBody = body.subject.products[0].name.toUpperCase() as keyof typeof premiumCount;
const oldTier = subscription ? subscription.premiumTier : "FREE";
const newTier = (premiumCount[oldTier] > premiumCount[tierBody]) ? oldTier : tierBody;

await prisma.subscription.upsert({
where: {
userId: body.subject.customer.username.id
},
create: {
purchasedAt: new Date(),
userId: body.subject.customer.username.id,
premiumCount: premiumCount[tierBody],
premiumTier: newTier
},
update: {
purchasedAt: new Date(),
premiumCount: {
increment: premiumCount[tierBody],
},
premiumTier: newTier
}
})

return reply.send({
"id": body.id
});
}
52 changes: 52 additions & 0 deletions src/routes/webhook/recurringEnd.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { FastifyReply, FastifyRequest } from "fastify";
import { RecurringEndWebhook } from "../../typings/index.js";
import prisma from "../../lib/prisma.js";
import crypto from "crypto";

export async function recurringEnd(request: FastifyRequest, reply: FastifyReply) {
const body = request.body as RecurringEndWebhook;

const bodyHash = crypto
.createHash('sha256')
.update(JSON.stringify(request.body), 'utf-8')
.digest('hex');

const finalHash = crypto.createHmac('sha256', process.env.TEBEX_SECRET as string)
.update(bodyHash)
.digest('hex');

if (finalHash !== request.headers["x-signature"]) {
return reply.notFound();
}

// used for verifying the webhook
if (body.type === "validation.webhook") {
return reply.send({
"id": body.id
});
}

await prisma.subscription.update({
where: {
userId: body.subject.initial_payment.customer.username.id
},
data: {
premiumGuild: {
set: []
}
}
})

await prisma.subscription.delete({
where: {
userId: body.subject.initial_payment.customer.username.id
},
include: {
premiumGuild: true,
}
})

return reply.send({
"id": body.id
});
}
Loading

0 comments on commit 20f15a8

Please sign in to comment.