From de7a6446f81ff22314f8b7a3603a4379dda2ed18 Mon Sep 17 00:00:00 2001
From: viktorstrate <viktorstrate@gmail.com>
Date: Thu, 1 Aug 2019 23:57:00 +0200
Subject: [PATCH] Fix docker bugs + improvements

---
 api/.env                   |  8 ++--
 api/src/config.js          |  2 +-
 api/src/index.js           | 91 ++++++++------------------------------
 api/src/routes/images.js   | 78 ++++++++++++++++++++++++++++++++
 docker-compose.example.yml |  7 ++-
 ui/Dockerfile              |  4 +-
 6 files changed, 108 insertions(+), 82 deletions(-)
 create mode 100644 api/src/routes/images.js

diff --git a/api/.env b/api/.env
index dd906d0..8c6b272 100644
--- a/api/.env
+++ b/api/.env
@@ -1,8 +1,8 @@
 NEO4J_URI=bolt://localhost:7687
 NEO4J_USER=neo4j
 NEO4J_PASSWORD=letmein
-GRAPHQL_LISTEN_PORT=4001
-GRAPHQL_URI=http://localhost:4001/graphql
-HOST=http://localhost:4001
 
-JWT_SECRET=topSecretEpicJWTKEYThing
\ No newline at end of file
+GRAPHQL_LISTEN_PORT=4001
+GRAPHQL_LISTEN_HOST=http://localhost/
+
+JWT_SECRET=You-sh0uld_Change-Th1s
\ No newline at end of file
diff --git a/api/src/config.js b/api/src/config.js
index d708f69..02b9dc3 100644
--- a/api/src/config.js
+++ b/api/src/config.js
@@ -2,5 +2,5 @@ import path from 'path'
 
 export default {
   cachePath: path.resolve(__dirname, 'cache'),
-  host: process.env.HOST || 'http://localhost:4001/',
+  host: new URL(process.env.GRAPHQL_LISTEN_HOST || 'http://localhost:4001/'),
 }
diff --git a/api/src/index.js b/api/src/index.js
index 3b49dcb..ecf0f65 100644
--- a/api/src/index.js
+++ b/api/src/index.js
@@ -10,7 +10,6 @@ import dotenv from 'dotenv'
 import http from 'http'
 import PhotoScanner from './scanner/Scanner'
 import _ from 'lodash'
-import config from './config'
 
 import { getUserFromToken, getTokenFromBearer } from './token'
 
@@ -39,7 +38,6 @@ import usersResolver from './resolvers/users'
 import scannerResolver from './resolvers/scanner'
 import photosResolver from './resolvers/photos'
 import siteInfoResolver from './resolvers/siteInfo'
-import { isRawImage, getImageCachePath } from './scanner/utils'
 
 const resolvers = [
   usersResolver,
@@ -87,9 +85,13 @@ const scanner = new PhotoScanner(driver)
 setInterval(scanner.scanAll, 1000 * 60 * 60 * 4)
 
 // Specify port and path for GraphQL endpoint
-const port = process.env.GRAPHQL_LISTEN_PORT || 4001
 const graphPath = '/graphql'
 
+const endpointUrl = new URL(
+  process.env.GRAPHQL_LISTEN_HOST || 'http://localhost/'
+)
+endpointUrl.port = process.env.GRAPHQL_LISTEN_PORT || 4001
+
 /*
  * Create a new ApolloServer instance, serving the GraphQL schema
  * created using makeAugmentedSchema above and injecting the Neo4j driver
@@ -112,7 +114,7 @@ const server = new ApolloServer({
       scanner,
       user,
       token,
-      endpoint: `http://localhost:${port}`,
+      endpoint: endpointUrl.toString(),
     }
   },
   schema: schema,
@@ -133,82 +135,25 @@ const server = new ApolloServer({
 
 server.applyMiddleware({ app, graphPath })
 
-app.use('/images/:id/:image', async function(req, res) {
-  const { id, image } = req.params
+import loadImageRoutes from './routes/images'
 
-  let user = null
-
-  try {
-    const token = req.cookies.token
-    user = await getUserFromToken(token, driver)
-  } catch (err) {
-    return res.status(401).send(err.message)
-  }
-
-  const session = driver.session()
-
-  const result = await session.run(
-    'MATCH (p:Photo { id: {id} })<-[:CONTAINS]-(a:Album)<-[:OWNS]-(u:User) RETURN p as photo, u.id as userId, a.id as albumId',
-    {
-      id,
-    }
-  )
-
-  if (result.records.length == 0) {
-    return res.status(404).send(`Image not found`)
-  }
-
-  const userId = result.records[0].get('userId')
-  const albumId = result.records[0].get('albumId')
-  const photo = result.records[0].get('photo').properties
-
-  if (userId != user.id) {
-    return res.status(401).send(`Image not owned by you`)
-  }
-
-  session.close()
-
-  let imagePath = path.resolve(getImageCachePath(id, albumId), image)
-
-  if (!(await fs.exists(imagePath))) {
-    if (image == 'thumbnail.jpg') {
-      console.log('Thumbnail not found, generating', photo.path)
-      await scanner.processImage(id)
-
-      if (!(await fs.exists(imagePath))) {
-        throw new Error('Thumbnail not found after image processing')
-      }
-
-      return res.sendFile(imagePath)
-    }
-
-    imagePath = photo.path
-  }
-
-  if (await isRawImage(imagePath)) {
-    console.log('RAW preview image not found, generating', imagePath)
-    await scanner.processImage(id)
-
-    imagePath = path.resolve(config.cachePath, 'images', id, image)
-
-    if (!(await fs.exists(imagePath))) {
-      throw new Error('RAW preview not found after image processing')
-    }
-
-    return res.sendFile(imagePath)
-  }
-
-  res.sendFile(imagePath)
-})
+loadImageRoutes({ app, driver })
 
 const httpServer = http.createServer(app)
 server.installSubscriptionHandlers(httpServer)
 
-httpServer.listen({ port, graphPath }, () => {
+httpServer.listen({ port: endpointUrl.port, graphPath }, () => {
   console.log(
-    `🚀 GraphQL endpoint ready at http://localhost:${port}${server.graphqlPath}`
+    `🚀 GraphQL endpoint ready at ${new URL(server.graphqlPath, endpointUrl)}`
   )
+
+  let subscriptionUrl = endpointUrl
+  subscriptionUrl.protocol = 'ws'
+
   console.log(
-    `🚀 Subscriptions ready at ws://localhost:${port}${server.subscriptionsPath}`
+    `🚀 Subscriptions ready at ${new URL(
+      server.subscriptionsPath,
+      endpointUrl
+    )}`
   )
 })
diff --git a/api/src/routes/images.js b/api/src/routes/images.js
new file mode 100644
index 0000000..a915f02
--- /dev/null
+++ b/api/src/routes/images.js
@@ -0,0 +1,78 @@
+import fs from 'fs-extra'
+import path from 'path'
+import _ from 'lodash'
+import config from '../config'
+import { isRawImage, getImageCachePath } from '../scanner/utils'
+import { getUserFromToken } from '../token'
+
+function loadImageRoutes({ app, driver }) {
+  app.use('/images/:id/:image', async function(req, res) {
+    const { id, image } = req.params
+
+    let user = null
+
+    try {
+      const token = req.cookies.token
+      user = await getUserFromToken(token, driver)
+    } catch (err) {
+      return res.status(401).send(err.message)
+    }
+
+    const session = driver.session()
+
+    const result = await session.run(
+      'MATCH (p:Photo { id: {id} })<-[:CONTAINS]-(a:Album)<-[:OWNS]-(u:User) RETURN p as photo, u.id as userId, a.id as albumId',
+      {
+        id,
+      }
+    )
+
+    if (result.records.length == 0) {
+      return res.status(404).send(`Image not found`)
+    }
+
+    const userId = result.records[0].get('userId')
+    const albumId = result.records[0].get('albumId')
+    const photo = result.records[0].get('photo').properties
+
+    if (userId != user.id) {
+      return res.status(401).send(`Image not owned by you`)
+    }
+
+    session.close()
+
+    let imagePath = path.resolve(getImageCachePath(id, albumId), image)
+
+    if (!(await fs.exists(imagePath))) {
+      if (image == 'thumbnail.jpg') {
+        console.log('Thumbnail not found, generating', photo.path)
+        await scanner.processImage(id)
+
+        if (!(await fs.exists(imagePath))) {
+          throw new Error('Thumbnail not found after image processing')
+        }
+
+        return res.sendFile(imagePath)
+      }
+
+      imagePath = photo.path
+    }
+
+    if (await isRawImage(imagePath)) {
+      console.log('RAW preview image not found, generating', imagePath)
+      await scanner.processImage(id)
+
+      imagePath = path.resolve(config.cachePath, 'images', id, image)
+
+      if (!(await fs.exists(imagePath))) {
+        throw new Error('RAW preview not found after image processing')
+      }
+
+      return res.sendFile(imagePath)
+    }
+
+    res.sendFile(imagePath)
+  })
+}
+
+export default loadImageRoutes
diff --git a/docker-compose.example.yml b/docker-compose.example.yml
index bdd9bf5..cb9c88a 100644
--- a/docker-compose.example.yml
+++ b/docker-compose.example.yml
@@ -20,6 +20,9 @@ services:
     - neo4j
     environment:
       - NEO4J_URI=bolt://neo4j:7687
+      # Change This: The publicly exposed url for the api
+      - GRAPHQL_LISTEN_HOST=http://localhost/
+      - GRAPHQL_LISTEN_PORT=4001
     volumes:
       # Change This: Link photo paths from the host machine
       - ./photos_path:/photos
@@ -28,8 +31,8 @@ services:
     build:
       context: ./ui
       args:
-        # Change This: The publicly exposed url for the api
-        endpoint: http://localhost:4001/graphql
+        # Change This: The publicly exposed url for the graphql api
+        GRAPHQL_ENDPOINT: http://localhost:4001/graphql
     ports:
       - 3000:80
     depends_on:
diff --git a/ui/Dockerfile b/ui/Dockerfile
index 50b55da..5dd3568 100644
--- a/ui/Dockerfile
+++ b/ui/Dockerfile
@@ -1,8 +1,8 @@
 # Build the app
 FROM node:10
 
-ARG endpoint
-ENV REACT_APP_GRAPHQL_URI=${endpoint}
+ARG GRAPHQL_ENDPOINT
+ENV REACT_APP_GRAPHQL_URI=${GRAPHQL_ENDPOINT}
 
 RUN mkdir -p /app
 WORKDIR /app
