From e9d81c089a85d71437babf2c1eb36675e376f828 Mon Sep 17 00:00:00 2001 From: i701 Date: Fri, 13 Dec 2024 11:24:13 +0500 Subject: [PATCH] Implement Omada device management and enhance payment processing - Added new omada-actions.ts file to handle fetching and updating device groups in Omada. - Updated authMiddleware to include new payment routes. - Enhanced createPayment function to add devices to a group upon successful payment verification. - Improved payment verification process to include device management. - Refactored PaymentsTable and DevicesToPay components for better UI and state handling. - Removed unused hasSession function from auth-guard.ts for cleaner code. --- actions/omada-actions.ts | 181 ++++++++++++++++++ actions/payment.ts | 39 +++- app/(dashboard)/payments/[paymentId]/page.tsx | 6 +- components/devices-to-pay.tsx | 4 +- components/payments-table.tsx | 5 +- lib/auth-guard.ts | 10 - middleware.ts | 2 +- 7 files changed, 222 insertions(+), 25 deletions(-) create mode 100644 actions/omada-actions.ts diff --git a/actions/omada-actions.ts b/actions/omada-actions.ts new file mode 100644 index 0000000..27245d6 --- /dev/null +++ b/actions/omada-actions.ts @@ -0,0 +1,181 @@ +interface IpAddress { + ip: string; + mask: number; +} + +interface Ipv6Address { + ip: string; + prefix: number; +} + +interface MacAddress { + ruleId?: number; + name: string; + macAddress: string; +} + +interface GroupProfile { + groupId: string; + site?: string; + name: string; + buildIn?: boolean; + ipList?: IpAddress[]; + ipv6List?: Ipv6Address[]; + macAddressList?: MacAddress[]; + count: number; + type: number; + resource: number; +} + +interface OmadaResponse { + errorCode: number; + msg: string; + result: { + data: GroupProfile[]; + }; +} + +async function fetchOmadaGroupProfiles( + omadacId: string, + siteId: string, +): Promise { + if (!omadacId || !siteId) { + throw new Error("omadacId and siteId are required parameters"); + } + + const timestamp: number = Date.now(); + const baseUrl: string = "https://omada.sarlink.link"; + const url: string = `${baseUrl}/${omadacId}/api/v2/sites/${siteId}/setting/profiles/groups?_t=${timestamp}`; + + const headers: HeadersInit = { + accept: "application/json, text/plain, */*", + "accept-language": "en-US,en;q=0.9", + cookie: "TPOMADA_SESSIONID=f30bf82348784089ba90740e59e4aa99", + "csrf-token": "fedc6283e9604372b402f82fdaeba0db", + priority: "u=1, i", + referer: baseUrl, + refresh: "manual", + "sec-ch-ua": '"Brave";v="131", "Chromium";v="131", "Not_A Brand";v="24"', + "sec-ch-ua-mobile": "?0", + "sec-ch-ua-platform": '"Linux"', + "sec-fetch-dest": "empty", + "sec-fetch-mode": "cors", + "sec-fetch-site": "same-origin", + "sec-gpc": "1", + "user-agent": + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36", + "x-requested-with": "XMLHttpRequest", + }; + + try { + const response: Response = await fetch(url, { + method: "GET", + headers: headers, + credentials: "include", + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const data: OmadaResponse = await response.json(); + return data; + } catch (error) { + console.error("Error fetching Omada group profiles:", error); + throw error instanceof Error ? error : new Error("Unknown error occurred"); + } +} + +export { fetchOmadaGroupProfiles, type MacAddress }; + +export async function addDevicesToGroup({ + omadacId, + siteId, + groupId, + newDevices, +}: { + omadacId?: string; + siteId?: string; + groupId?: string; + newDevices: MacAddress[]; +}): Promise { + if (!omadacId || !siteId || !groupId) { + throw new Error("omadacId, siteId, and groupId are required parameters"); + } + + try { + // Fetch the existing group profiles + const groupProfiles: OmadaResponse = await fetchOmadaGroupProfiles( + omadacId, + siteId, + ); + + // Find the group profile with the specified groupId + const groupProfile: GroupProfile | undefined = + groupProfiles.result.data.find((profile) => profile.groupId === groupId); + + if (!groupProfile) { + throw new Error(`Group with ID ${groupId} not found`); + } + + // Create a new array with the existing and new devices + const updatedMacAddressList: MacAddress[] = [ + ...(groupProfile.macAddressList || []), + ...newDevices, + ]; + + // Prepare the request payload + const requestBody = { + name: groupProfile.name, + type: groupProfile.type, + resource: groupProfile.resource, + ipList: groupProfile.ipList, + ipv6List: groupProfile.ipv6List, + macAddressList: updatedMacAddressList, + portList: null, + countryList: null, + portType: null, + portMaskList: null, + domainNamePort: null, + }; + + const timestamp: number = Date.now(); + const baseUrl: string = "https://omada.sarlink.link"; + const url: string = `${baseUrl}/${omadacId}/api/v2/sites/${siteId}/setting/profiles/groups/2/${groupId}?_t=${timestamp}`; + + const headers: HeadersInit = { + accept: "application/json, text/plain, */*", + "accept-language": "en-US,en;q=0.9", + "content-type": "application/json;charset=UTF-8", + cookie: "TPOMADA_SESSIONID=f30bf82348784089ba90740e59e4aa99", + "csrf-token": "fedc6283e9604372b402f82fdaeba0db", + origin: baseUrl, + priority: "u=1, i", + referer: baseUrl, + refresh: "manual", + "sec-ch-ua": '"Brave";v="131", "Chromium";v="131", "Not_A Brand";v="24"', + "sec-ch-ua-mobile": "?0", + "sec-ch-ua-platform": '"Linux"', + "sec-fetch-dest": "empty", + "sec-fetch-mode": "cors", + "sec-fetch-site": "same-origin", + "sec-gpc": "1", + "user-agent": + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36", + "x-requested-with": "XMLHttpRequest", + }; + + const response: Response = await fetch(url, { + method: "PATCH", + headers: headers, + body: JSON.stringify(requestBody), + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + } catch (error) { + console.error("Error adding devices to group:", error); + throw error instanceof Error ? error : new Error("Unknown error occurred"); + } +} diff --git a/actions/payment.ts b/actions/payment.ts index 1ff1204..29eb23e 100644 --- a/actions/payment.ts +++ b/actions/payment.ts @@ -3,6 +3,7 @@ import prisma from "@/lib/db"; import type { PaymentType } from "@/lib/types"; import { revalidatePath } from "next/cache"; +import { addDevicesToGroup } from "./omada-actions"; export async function createPayment(data: PaymentType) { console.log("data", data); @@ -40,6 +41,9 @@ export async function verifyPayment(data: VerifyPaymentType) { where: { id: data.paymentId, }, + include: { + devices: true, + }, }); const response = await fetch( "https://verifypaymentsapi.baraveli.dev/verify-payment", @@ -53,19 +57,38 @@ export async function verifyPayment(data: VerifyPaymentType) { ); const json = await response.json(); console.log(json); + const newDevices = payment?.devices.map((d) => { + return { + name: d.name, + macAddress: d.mac, + }; + }); if (json.success === true) { - await prisma.payment.update({ - where: { - id: payment?.id, - }, - data: { - paid: true, - }, - }); + await Promise.all([ + prisma.payment.update({ + where: { + id: payment?.id, + }, + data: { + paid: true, + }, + }), + addDevicesToGroup({ + groupId: process.env.OMADA_GROUP_ID, + omadacId: process.env.OMADA_CID, + siteId: process.env.OMADA_SITE_ID, + newDevices: newDevices || [], + }), + ]); } + revalidatePath("/payment[paymentId]"); return json; } catch (error) { console.error(error); } } + +export async function addDevicesToOmada() { + console.log("hi"); +} diff --git a/app/(dashboard)/payments/[paymentId]/page.tsx b/app/(dashboard)/payments/[paymentId]/page.tsx index 075605c..27cd24e 100644 --- a/app/(dashboard)/payments/[paymentId]/page.tsx +++ b/app/(dashboard)/payments/[paymentId]/page.tsx @@ -1,7 +1,7 @@ import DevicesToPay from "@/components/devices-to-pay"; import { auth } from "@/lib/auth"; -import { hasSession } from "@/lib/auth-guard"; import prisma from "@/lib/db"; +import { cn } from "@/lib/utils"; import { headers } from "next/headers"; import React from "react"; export default async function PaymentPage({ @@ -26,12 +26,14 @@ export default async function PaymentPage({ devices: true, }, }); - await hasSession(); const formula = await prisma.billFormula.findFirst(); return (

Payment

+ + {payment?.paid ? "Paid" : "Pending"} +
-

+

{!payment?.paid ? "Devices to pay" : "Devices Paid"}

@@ -71,7 +71,7 @@ export default function DevicesToPay({ accountNo="90101400028321000" /> {payment?.paid ? ( - + ) : ( - + {payment.paid ? "Paid" : "Unpaid"}
diff --git a/lib/auth-guard.ts b/lib/auth-guard.ts index 3dcfbdc..720e6aa 100644 --- a/lib/auth-guard.ts +++ b/lib/auth-guard.ts @@ -12,13 +12,3 @@ export async function AdminAuthGuard() { } return true; } - -export async function hasSession() { - const session = await auth.api.getSession({ - headers: await headers(), - }); - if (!session) { - return redirect("/login"); - } - return true; -} diff --git a/middleware.ts b/middleware.ts index 08c97c8..824cea0 100644 --- a/middleware.ts +++ b/middleware.ts @@ -21,5 +21,5 @@ export default async function authMiddleware(request: NextRequest) { } export const config = { - matcher: ["/devices", "/"], + matcher: ["/devices", "/", "/payments", "/payments/:paymentId"], };