Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend/src/controllers/DeviceController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
8 changes: 4 additions & 4 deletions backend/src/repositories/PrismaDeviceRepository.ts
Original file line number Diff line number Diff line change
@@ -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";

Expand Down Expand Up @@ -108,16 +108,16 @@ export class PrismaDeviceRepository implements IDeviceRepository {
});
}

async unbookDevice(deviceId: number, userId: number): Promise<Device | null> {
async unbookDevice(deviceId: number, userId: number, accountType: AccountType): Promise<Device | null> {
return await this.prisma.$transaction(async (tx) => {
// check if device is already booked
const current = await tx.device.findUnique({
where: { id: deviceId },
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");
}

Expand Down
6 changes: 3 additions & 3 deletions backend/src/services/DeviceService.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -58,7 +58,7 @@ export class DeviceService implements IDeviceService {
return this.deviceRepository.bookDevice(deviceId, userId);
}

async unbookDevice(deviceId: number, userId: number): Promise<Device | null> {
return this.deviceRepository.unbookDevice(deviceId, userId);
async unbookDevice(deviceId: number, userId: number, accountType: AccountType): Promise<Device | null> {
return this.deviceRepository.unbookDevice(deviceId, userId, accountType);
}
}
6 changes: 3 additions & 3 deletions backend/src/types/classInterfaces.ts
Original file line number Diff line number Diff line change
@@ -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";

Expand Down Expand Up @@ -55,7 +55,7 @@ export interface IDeviceRepository {
findByType(deviceType: DeviceType): Promise<Device[]>;
findByIcon(deviceIcon: IconType): Promise<Device[]>;
bookDevice(deviceId: number, userId: number): Promise<Device | null>;
unbookDevice(deviceId: number, userId: number): Promise<Device | null>;
unbookDevice(deviceId: number, userId: number, accountType: AccountType): Promise<Device | null>;
}

export interface IDeviceService {
Expand All @@ -69,7 +69,7 @@ export interface IDeviceService {
getDevicesByType(deviceType: DeviceType): Promise<Device[]>;
getDevicesByIcon(deviceIcon: IconType): Promise<Device[]>;
bookDevice(deviceId: number, userId: number): Promise<Device | null>;
unbookDevice(deviceId: number, userId: number): Promise<Device | null>;
unbookDevice(deviceId: number, userId: number, accountType: AccountType): Promise<Device | null>;
}

export interface IConnectionRepository {
Expand Down
47 changes: 31 additions & 16 deletions frontend/src/hooks/useLinkOperations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};

Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/lib/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down