@@ -6,13 +6,14 @@ const { Container, Service, HTTPService, TransportService, DnsService, Node, Sit
66const { requireAuth } = require ( '../middlewares' ) ;
77const ProxmoxApi = require ( '../utils/proxmox-api' ) ;
88const serviceMap = require ( '../data/services.json' ) ;
9+ // Imported from utils as requested
10+ const { isApiRequest } = require ( '../utils/http-utils' ) ;
911
1012/**
1113 * Normalize a Docker image reference to full format: host/org/image:tag
1214 */
1315function normalizeDockerRef ( ref ) {
1416 // If this looks like a git URL (starts with http/https/git), return as is
15- // (Though with the fix below, this shouldn't be called for git repos anymore)
1617 if ( ref . startsWith ( 'http://' ) || ref . startsWith ( 'https://' ) || ref . startsWith ( 'git@' ) ) {
1718 return ref ;
1819 }
@@ -54,16 +55,9 @@ function normalizeDockerRef(ref) {
5455 return `${ host } /${ org } /${ image } :${ tag } ` ;
5556}
5657
57- // Helper to detect API bearer requests
58- function isApiRequest ( req ) {
59- const accept = ( req . get ( 'accept' ) || '' ) . toLowerCase ( ) ;
60- return accept . includes ( 'application/json' ) || accept . includes ( 'application/vnd.api+json' ) ;
61- }
62-
6358// GET /sites/:siteId/containers/new - List available templates via API or HTML form
6459router . get ( '/new' , requireAuth , async ( req , res ) => {
6560 const siteId = parseInt ( req . params . siteId , 10 ) ;
66- // Check if this is an API request (requires the helper function defined earlier)
6761 const isApi = isApiRequest ( req ) ;
6862
6963 // verify site exists
@@ -131,48 +125,39 @@ router.get('/new', requireAuth, async (req, res) => {
131125} ) ;
132126
133127// GET /sites/:siteId/containers
134- router . get ( '/' , async ( req , res ) => {
135- if ( isApiRequest ( req ) ) {
136- try {
137- const siteId = parseInt ( req . params . siteId , 10 ) ;
138- const site = await Site . findByPk ( siteId ) ;
139- if ( ! site ) return res . status ( 404 ) . json ( [ ] ) ;
140-
141- const nodes = await Node . findAll ( { where : { siteId } , attributes : [ 'id' ] } ) ;
142- const nodeIds = nodes . map ( n => n . id ) ;
143-
144- const { hostname } = req . query ;
145- const where = { } ;
146- if ( hostname ) where . hostname = hostname ;
147- where . nodeId = nodeIds ;
148-
149- const containers = await Container . findAll ( { where, include : [ { association : 'node' , attributes : [ 'id' , 'name' ] } ] } ) ;
150- const out = containers . map ( c => ( { id : c . id , hostname : c . hostname , ipv4Address : c . ipv4Address , macAddress : c . macAddress , node : c . node ? { id : c . node . id , name : c . node . name } : null , createdAt : c . createdAt } ) ) ;
151- return res . json ( out ) ;
152- } catch ( err ) {
153- console . error ( 'API GET /sites/:siteId/containers error:' , err ) ;
154- return res . status ( 500 ) . json ( { error : 'Internal server error' } ) ;
155- }
156- }
157-
158- await new Promise ( resolve => requireAuth ( req , res , resolve ) ) ;
159- if ( res . headersSent ) return ;
160-
128+ // Added requireAuth to ensure API keys and Sessions are validated
129+ router . get ( '/' , requireAuth , async ( req , res ) => {
161130 const siteId = parseInt ( req . params . siteId , 10 ) ;
162131 const site = await Site . findByPk ( siteId ) ;
132+
133+ // Unified Error Handling for Site 404
163134 if ( ! site ) {
135+ if ( isApiRequest ( req ) ) {
136+ return res . status ( 404 ) . json ( { error : 'Site not found' } ) ;
137+ }
164138 await req . flash ( 'error' , 'Site not found' ) ;
165139 return res . redirect ( '/sites' ) ;
166140 }
167141
168142 const nodes = await Node . findAll ( { where : { siteId } , attributes : [ 'id' ] } ) ;
169143 const nodeIds = nodes . map ( n => n . id ) ;
170144
145+ // Determine current user (support Session or API Token via requireAuth)
146+ const currentUser = req . session ?. user || req . user ?. username ;
147+
148+ // Build query
149+ const whereClause = {
150+ username : currentUser ,
151+ nodeId : nodeIds
152+ } ;
153+
154+ // Support hostname filtering for API requests if provided
155+ if ( req . query . hostname ) {
156+ whereClause . hostname = req . query . hostname ;
157+ }
158+
171159 const containers = await Container . findAll ( {
172- where : {
173- username : req . session . user ,
174- nodeId : nodeIds
175- } ,
160+ where : whereClause ,
176161 include : [
177162 {
178163 association : 'services' ,
@@ -191,19 +176,28 @@ router.get('/', async (req, res) => {
191176 const sshPort = ssh ?. transportService ?. externalPort || null ;
192177 const http = services . find ( s => s . type === 'http' ) ;
193178 const httpPort = http ? http . internalPort : null ;
179+
180+ // Common object structure for both API and View
194181 return {
195182 id : c . id ,
196183 hostname : c . hostname ,
197184 ipv4Address : c . ipv4Address ,
185+ // API might want raw MacAddress, View might not need it, but including it doesn't hurt
186+ macAddress : c . macAddress ,
198187 status : c . status ,
199188 template : c . template ,
200189 creationJobId : c . creationJobId ,
201190 sshPort,
202191 httpPort,
203- nodeName : c . node ? c . node . name : '-'
192+ nodeName : c . node ? c . node . name : '-' ,
193+ createdAt : c . createdAt
204194 } ;
205195 } ) ;
206196
197+ if ( isApiRequest ( req ) ) {
198+ return res . json ( { containers : rows } ) ;
199+ }
200+
207201 return res . render ( 'containers/index' , { rows, site, req } ) ;
208202} ) ;
209203
0 commit comments