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
96 changes: 48 additions & 48 deletions src/lib/interfaces/IDeviceService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,51 +5,51 @@ import type { DeviceWithJoins } from '../repositories/DeviceRepository';
* Service interface for device operations
*/
export interface IDeviceService {
/**
* Get a device by its EUI
* @param devEui The device EUI
*/
getDeviceByEui(devEui: string): Promise<Device | null>;
/**
* Get a device with its type information
* @param devEui The device EUI
*/
getDeviceWithTypeByEui(devEui: string): Promise<DeviceWithType | null>;
/**
* Get all devices
*/
getAllDevices(): Promise<Device[]>;
/**
* Get devices by location ID
* @param locationId The location ID
*/
getDevicesByLocation(locationId: number): Promise<DeviceWithJoins[]>;
/**
* Get devices by type ID
* @param typeId The device type ID
*/
getDevicesByType(typeId: number): Promise<Device[]>;
/**
* Create a new device
* @param device The device to create
*/
createDevice(device: DeviceInsert): Promise<Device>;
/**
* Update an existing device
* @param devEui The device EUI
* @param device The device with updated values
*/
updateDevice(devEui: string, device: DeviceUpdate): Promise<Device | null>;
/**
* Delete a device
* @param devEui The device EUI
*/
deleteDevice(devEui: string): Promise<boolean>;
}
/**
* Get a device by its EUI
* @param devEui The device EUI
*/
getDeviceByEui(devEui: string): Promise<Device | null>;

/**
* Get a device with its type information
* @param devEui The device EUI
*/
getDeviceWithTypeByEui(devEui: string): Promise<DeviceWithType | null>;

/**
* Get all devices
*/
getAllDevices(user_id: string): Promise<Device[] | null>;

/**
* Get devices by location ID
* @param locationId The location ID
*/
getDevicesByLocation(locationId: number): Promise<DeviceWithJoins[]>;

/**
* Get devices by type ID
* @param typeId The device type ID
*/
getDevicesByType(typeId: number): Promise<Device[]>;

/**
* Create a new device
* @param device The device to create
*/
createDevice(device: DeviceInsert): Promise<Device>;

/**
* Update an existing device
* @param devEui The device EUI
* @param device The device with updated values
*/
updateDevice(devEui: string, device: DeviceUpdate): Promise<Device | null>;

/**
* Delete a device
* @param devEui The device EUI
*/
deleteDevice(devEui: string): Promise<boolean>;
}
35 changes: 35 additions & 0 deletions src/lib/repositories/DeviceRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,41 @@ export class DeviceRepository extends BaseRepository<Device, string> {
return (data as Device[]) || [];
}

/**
* Find a device owner entry
* @param devEui The device EUI
* @param userId The user ID
*/
async findAllDevicesByOwner(userId: string): Promise<Device[] | null> {
// 1) Owned devices (cw_devices rows)
const { data: owned, error: ownedErr } = await this.supabase
.from('cw_devices')
.select('*')
.eq('user_id', userId);

if (ownedErr) return null;

// 2) Shared devices the user has perms for.
// Prefer a JOIN via the relationship so you get cw_devices rows directly.
// Assumes a FK cw_device_owners(dev_eui) -> cw_devices(dev_eui).
const { data: shared, error: sharedErr } = await this.supabase
.from('cw_device_owners')
.select('cw_devices(*)') // returns rows shaped like { cw_devices: Device }
.eq('user_id', userId)
.lte('permission_level', 3); // pl <= 3 as per your policy

if (sharedErr) return null;

// Flatten shared to Device[]
const sharedDevices: Device[] = (shared ?? []).map((r: any) => r.cw_devices).filter(Boolean);

// Merge & dedupe by dev_eui
const byDevEui = new Map<string, Device>();
for (const d of [...(owned ?? []), ...sharedDevices]) byDevEui.set(d.dev_eui, d);

return Array.from(byDevEui.values());
}

/**
* Find a device owner entry
* @param devEui The device EUI
Expand Down
6 changes: 4 additions & 2 deletions src/lib/services/DeviceService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@ export class DeviceService implements IDeviceService {
/**
* Get all devices
*/
async getAllDevices(): Promise<Device[]> {
return this.deviceRepository.findAll();
async getAllDevices(user_id: string): Promise<Device[] | null> {
const devices = this.deviceRepository.findAllDevicesByOwner(user_id);

return devices;
}

/**
Expand Down
10 changes: 9 additions & 1 deletion src/routes/app/all-devices/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,15 @@ export const load: PageServerLoad = async ({ locals: { supabase } }) => {
const errorHandler = new ErrorHandlingService();
const deviceRepository = new DeviceRepository(supabase, errorHandler);
const deviceService = new DeviceService(deviceRepository);
const allDevicesPromise = deviceService.getAllDevices();
const allDevicesNoPerm = await deviceService.getAllDevices(user.id);

if (!allDevicesNoPerm) {
throw fail(500, { message: 'Could not fetch devices' });
}

// Double check the user only gets their own devices
const allDevicesPromise = allDevicesNoPerm.filter((d) => d.user_id && d.user_id === user.id);

// If you still want `allDevices` in the page, return both:
return { allDevicesPromise };
};
6 changes: 3 additions & 3 deletions static/build-info.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"commit": "38664e2",
"commit": "283f16e",
"branch": "style-fixes",
"author": "Kevin Cantrell",
"date": "2025-09-16T08:35:24.572Z",
"date": "2025-09-18T01:50:29.049Z",
"builder": "kevin@kevin-desktop",
"ipAddress": "192.168.1.100",
"timestamp": 1758011724573
"timestamp": 1758160229050
}
3 changes: 3 additions & 0 deletions svelte.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ const config = {
serviceWorker: {
register: false // Let PWA plugin handle registration
}
},
vitePlugin: {
inspector: true
}
};

Expand Down