import { Router } from 'express'; import fs from 'fs'; import path from 'path'; import { requireAuth } from '../../auth-connector/source/server/auth'; import { checkAccess } from '../projectAccess'; import { ROOT } from '../rootDir'; const router = Router(); router.use( requireAuth ); const LAYOUTS_DIR = path.join( ROOT, 'build', 'data', 'storage', 'layouts' ); function safeId( s: string ): string { return s.replace( /[^a-zA-Z0-9_-]/g, '_' ); } function resolveLayoutPath( req: any ): string | null { const deviceId = req.query.deviceId as string; if ( !deviceId ) return null; const projectId = req.query.projectId as string | undefined; const localRoot = req.query.localRoot as string | undefined; const remoteProject = req.query.remoteProject as string | undefined; if ( projectId ) { const dir = path.join( ROOT, 'build', 'data', 'storage', projectId, 'root', '.roject' ); if ( !fs.existsSync( dir ) ) fs.mkdirSync( dir, { recursive: true } ); return path.join( dir, `layout-${ safeId( deviceId ) }.json` ); } if ( localRoot ) { const resolved = path.resolve( localRoot ); const dir = path.join( resolved, '.roject' ); if ( !fs.existsSync( dir ) ) fs.mkdirSync( dir, { recursive: true } ); return path.join( dir, `layout-${ safeId( deviceId ) }.json` ); } if ( remoteProject ) { // Remote project opened in Electron: store locally, keyed by device + remote project id const userId = req.auth!.userId; const dir = path.join( LAYOUTS_DIR, safeId( userId ) ); if ( !fs.existsSync( dir ) ) fs.mkdirSync( dir, { recursive: true } ); return path.join( dir, `${ safeId( deviceId ) }-${ safeId( remoteProject ) }.json` ); } return null; } router.get( '/', ( req, res ) => { const projectId = req.query.projectId as string | undefined; if ( projectId ) { const denied = checkAccess( projectId, req.auth!, 'view' ); if ( denied ) { res.status( denied.status ).json( { error: denied.error } ); return; } } const fp = resolveLayoutPath( req ); if ( !fp ) { res.json( null ); return; } if ( !fs.existsSync( fp ) ) { res.json( null ); return; } try { res.json( JSON.parse( fs.readFileSync( fp, 'utf8' ) ) ); } catch { res.json( null ); } } ); router.put( '/', ( req, res ) => { const projectId = req.query.projectId as string | undefined; if ( projectId ) { const denied = checkAccess( projectId, req.auth!, 'edit' ); if ( denied ) { res.status( denied.status ).json( { error: denied.error } ); return; } } const fp = resolveLayoutPath( req ); if ( !fp ) { res.status( 400 ).json( { error: 'Missing project identifier or deviceId' } ); return; } try { fs.writeFileSync( fp, JSON.stringify( req.body ), 'utf8' ); res.json( { ok: true } ); } catch ( e ) { res.status( 500 ).json( { error: String( e ) } ); } } ); export default router;