diff --git a/backend/src/controllers/DeviceController.ts b/backend/src/controllers/DeviceController.ts index ca51445..e572438 100644 --- a/backend/src/controllers/DeviceController.ts +++ b/backend/src/controllers/DeviceController.ts @@ -162,7 +162,7 @@ export class DeviceController { try { const { id } = req.params; // will have a payload user id otherwise this request is not authenticated through middleware - const device = await this.deviceService.unbookDevice(parseInt(id), req.jwt_payload?.id!); + const device = await this.deviceService.unbookDevice(parseInt(id), req.jwt_payload?.id!, req.jwt_payload?.accountType!); // we successfully unbooked the device if (device) { diff --git a/backend/src/repositories/PrismaDeviceRepository.ts b/backend/src/repositories/PrismaDeviceRepository.ts index a119bac..d96e198 100644 --- a/backend/src/repositories/PrismaDeviceRepository.ts +++ b/backend/src/repositories/PrismaDeviceRepository.ts @@ -1,4 +1,4 @@ -import { DeviceType, IconType, PrismaClient, type Device } from "@prisma/client"; +import { AccountType, DeviceType, IconType, PrismaClient, type Device } from "@prisma/client"; import bcrypt from 'bcryptjs'; import { IDeviceRepository } from "../types/classInterfaces"; @@ -108,7 +108,7 @@ export class PrismaDeviceRepository implements IDeviceRepository { }); } - async unbookDevice(deviceId: number, userId: number): Promise { + async unbookDevice(deviceId: number, userId: number, accountType: AccountType): Promise { return await this.prisma.$transaction(async (tx) => { // check if device is already booked const current = await tx.device.findUnique({ @@ -116,8 +116,8 @@ export class PrismaDeviceRepository implements IDeviceRepository { select: { userId: true } }); - // only allow unbooking of device if userIds match - if (current?.userId !== userId) { + // only allow unbooking of device if userIds match AND account type is not admin or owner + if (accountType !== 'ADMIN' && accountType !== 'OWNER' && current?.userId !== userId) { throw new Error("UNAUTHORIZED"); } diff --git a/backend/src/services/DeviceService.ts b/backend/src/services/DeviceService.ts index e6be06b..83248e7 100644 --- a/backend/src/services/DeviceService.ts +++ b/backend/src/services/DeviceService.ts @@ -1,4 +1,4 @@ -import type { Device, DeviceType, IconType } from "@prisma/client"; +import type { AccountType, Device, DeviceType, IconType } from "@prisma/client"; import { IDeviceRepository, IDeviceService } from "../types/classInterfaces"; export class DeviceService implements IDeviceService { @@ -58,7 +58,7 @@ export class DeviceService implements IDeviceService { return this.deviceRepository.bookDevice(deviceId, userId); } - async unbookDevice(deviceId: number, userId: number): Promise { - return this.deviceRepository.unbookDevice(deviceId, userId); + async unbookDevice(deviceId: number, userId: number, accountType: AccountType): Promise { + return this.deviceRepository.unbookDevice(deviceId, userId, accountType); } } \ No newline at end of file diff --git a/backend/src/types/classInterfaces.ts b/backend/src/types/classInterfaces.ts index 3ef05ef..de4b6a4 100644 --- a/backend/src/types/classInterfaces.ts +++ b/backend/src/types/classInterfaces.ts @@ -1,5 +1,5 @@ // holds interfaces similar to C# -import { AppConfig, AppUser, Connection, Device, DeviceType, IconType, Topology } from "@prisma/client"; +import { AccountType, AppConfig, AppUser, Connection, Device, DeviceType, IconType, Topology } from "@prisma/client"; import type { CreateConnectionRequestPayload, CreateTopologyRequestPayload, RegisterUserRequestPayload } from "common"; import { UpdateTopologyDTO } from "./types"; @@ -55,7 +55,7 @@ export interface IDeviceRepository { findByType(deviceType: DeviceType): Promise; findByIcon(deviceIcon: IconType): Promise; bookDevice(deviceId: number, userId: number): Promise; - unbookDevice(deviceId: number, userId: number): Promise; + unbookDevice(deviceId: number, userId: number, accountType: AccountType): Promise; } export interface IDeviceService { @@ -69,7 +69,7 @@ export interface IDeviceService { getDevicesByType(deviceType: DeviceType): Promise; getDevicesByIcon(deviceIcon: IconType): Promise; bookDevice(deviceId: number, userId: number): Promise; - unbookDevice(deviceId: number, userId: number): Promise; + unbookDevice(deviceId: number, userId: number, accountType: AccountType): Promise; } export interface IConnectionRepository { diff --git a/frontend/src/hooks/useLinkOperations.ts b/frontend/src/hooks/useLinkOperations.ts index 30c52d1..930edec 100644 --- a/frontend/src/hooks/useLinkOperations.ts +++ b/frontend/src/hooks/useLinkOperations.ts @@ -32,6 +32,8 @@ export function useLinkOperationsBase() { } const interconnectDevices = await authenticatedApiClient.getDevicesByType('INTERCONNECT'); + // only two devices here so find is okay + // TODO might have to make this more robust return interconnectDevices.data?.find(d => d.name === connectionInfo.interconnectDeviceName); }; @@ -57,7 +59,7 @@ export function useLinkOperationsBase() { return true; }; - const removePortNumber = (port: string) => port.replace(/\/\d+$/, '/'); + const removePortNumber = (port?: string) => port?.split('|')[0]; const calculateOffsetPort = (port: string, deviceNumber: number) => { // splits off interface number and calculates offset @@ -103,29 +105,41 @@ export function useLinkOperationsBase() { } // Prepare link payload - const interconnect1Prefix = removePortNumber(firstConnectionInfo.interconnectDevicePort); - const interconnect2Prefix = removePortNumber(secondConnectionInfo.interconnectDevicePort); + // Get the correct interconnect information based on the device number for the interconnect + const [interconnect1, interconnect2] = firstInterconnectInfo?.deviceNumber === 1 + ? [firstInterconnectInfo, secondInterconnectInfo] + : [secondInterconnectInfo, firstInterconnectInfo]; - const offsetPort1 = calculateOffsetPort( - firstConnectionInfo.interconnectDevicePort, - firstInterconnectInfo!.deviceNumber! - ); + const interconnect1Prefix = removePortNumber(interconnect1?.ports); + const interconnect2Prefix = removePortNumber(interconnect2?.ports); - const offsetPort2 = calculateOffsetPort( - secondConnectionInfo.interconnectDevicePort, - secondInterconnectInfo!.deviceNumber! - ); + // if ports is undefined + if (!interconnect1Prefix || !interconnect2Prefix) { + return false; + } + + const [offsetPort1, offsetPort2] = firstInterconnectInfo?.deviceNumber === 1 + ? + [ + calculateOffsetPort(firstConnectionInfo.interconnectDevicePort, firstInterconnectInfo!.deviceNumber!), + calculateOffsetPort(secondConnectionInfo.interconnectDevicePort, secondInterconnectInfo!.deviceNumber!) + ] + : + [ + calculateOffsetPort(secondConnectionInfo.interconnectDevicePort, secondInterconnectInfo!.deviceNumber!), + calculateOffsetPort(firstConnectionInfo.interconnectDevicePort, firstInterconnectInfo!.deviceNumber!) + ] const linkPayload: LinkRequest = { - interconnect1IP: firstInterconnectInfo!.ipAddress, + interconnect1IP: interconnect1!.ipAddress, interconnect1Prefix, - interconnect2IP: secondInterconnectInfo!.ipAddress, + interconnect2IP: interconnect2!.ipAddress, interconnect2Prefix, interconnectPortID1: offsetPort1, interconnectPortID2: offsetPort2, - username: firstInterconnectInfo!.username!, - password: firstInterconnectInfo!.password!, - secret: firstInterconnectInfo!.secretPassword! + username: interconnect1!.username!, + password: interconnect1!.password!, + secret: interconnect1!.secretPassword! }; // Perform the requested operation @@ -305,6 +319,7 @@ export function useLinkOperations() { // Override the base methods to include ReactFlow operations const createLink = async (params: LinkOperationParams, createToastPerLink: boolean = true) => { + console.log(params); const edgeId = `edge-${params.firstDeviceName}-${params.firstDevicePort}-${params.secondDeviceName}-${params.secondDevicePort}`; createEdge(params); const result = await baseOperations.createLink(params, createToastPerLink); diff --git a/frontend/src/lib/helpers.ts b/frontend/src/lib/helpers.ts index 62df851..245ce27 100644 --- a/frontend/src/lib/helpers.ts +++ b/frontend/src/lib/helpers.ts @@ -68,12 +68,12 @@ export const getCurvedPath = ( }; export function substringFromFirstNumber(port: string) { - const idx = port.search(/\d/); + const idx = port.search(/\d/); // find the index of the first number if (idx !== -1) { - return port.substring(0, 3) + port.substring(idx); + return port.substring(0, idx) + port.substring(idx); // concatenate prefix and the rest } return ""; -}; +} // validate email format export function validateEmail(email: string) {