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
21 changes: 21 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copy this file to .env and fill values before running docker-compose

# Postgres DB credentials (used by the DB container)
POSTGRES_USER=
POSTGRES_PASSWORD=
POSTGRES_DB=
DB_HOST_PORT=

# Server settings (the server container will read DB_* vars)
NODE_ENV=
NODE_PORT=
DB_HOST=
DB_PORT=
DB_NAME=
DB_USER=
DB_PASSWORD=
CLIENT_HOST=

# Client (Vite) settings
CLIENT_PORT=
HOST=
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.DS_Store
.env.local
.env.development
.env.development
.env
21 changes: 20 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,23 @@ To run client and server together use the following commands:

In the custom-3D folder
- Run the command `npm run install:all`
- Run the command `npm run start:all`
- Run the command `npm run start:all`

**Alternatively using Docker:**

- Copy the example env and fill values (this repository gitignores `.env`):
```bash
cp .env.example .env
```

Then start services with docker-compose:
- Build and start all services
```bash
docker-compose up --build
```

- Seed/run server tasks
```bash
docker-compose exec server npm run knex:dev -- migrate:latest
docker-compose exec server npm run seed
```
4 changes: 4 additions & 0 deletions client/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
dist
.DS_Store
.env
7 changes: 7 additions & 0 deletions client/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FROM node:20
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 9000
CMD ["npm", "run", "dev"]
1 change: 1 addition & 0 deletions client/vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export default defineConfig({
plugins: [react()],
server: {
port: 9000,
host: "0.0.0.0",
},
build: {
// Relative to the root
Expand Down
58 changes: 58 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
version: "3.8"
services:
db:
image: postgres:14
restart: unless-stopped
env_file:
- .env
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
volumes:
- db-data:/var/lib/postgresql/data
ports:
- "${DB_HOST_PORT:-5432}:5432"

server:
build: ./server
command: npm run start:dev
volumes:
- ./server:/usr/src/app
- /usr/src/app/node_modules
environment:
NODE_ENV: ${NODE_ENV}
NODE_PORT: ${NODE_PORT}
FILE_PATH: /usr/src/app/src
DB_HOST: db
DB_PORT: ${DB_PORT}
DB_NAME: ${DB_NAME}
DB_USER: ${DB_USER}
DB_PASSWORD: ${DB_PASSWORD}
CLIENT_HOST: ${CLIENT_HOST}
env_file:
- .env
depends_on:
- db
ports:
- "3000:3000"

client:
build: ./client
command: npm run dev
volumes:
- ./client:/usr/src/app
- /usr/src/app/node_modules
environment:
PORT: ${CLIENT_PORT}
HOST: ${HOST}
env_file:
- .env
- ./client/.env
depends_on:
- server
ports:
- "9000:9000"

volumes:
db-data:
6 changes: 6 additions & 0 deletions server/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules
.env
dist
coverage
uploads
.DS_Store
10 changes: 10 additions & 0 deletions server/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"singleQuote": false,
"trailingComma": "all",
"semi": true,
"tabWidth": 2,
"arrowParens": "always",
"useTabs": false,
"bracketSpacing": true,
"printWidth": 150
}
7 changes: 7 additions & 0 deletions server/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FROM node:18
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "run", "start:dev"]
16 changes: 11 additions & 5 deletions server/src/api/objects.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const { errorHandler } = require("../utils");
const { HttpError } = require("../error");
const uploadFile = require("../middleware/upload");
const fs = require("fs");
const path = require("path");

/**
* Get Object by id
Expand Down Expand Up @@ -90,13 +91,18 @@ const uploadFileAndSaveObject = errorHandler(async (req, res) => {
// Uploads the file in the server folder
await uploadFile(req, res);

if (req.file === undefined) {
// Get the file from formidable (req.files is an object with arrays)
const fileArray = req.files?.file;
if (!fileArray || fileArray.length === 0) {
throw new HttpError(400, "Please upload a file!");
}

const filepath = req.params.projectId + "/" + req.file.originalname;
const objectId = req.body.id;
const objectName = req.body.objectName;
const file = fileArray[0];
// formidable v3 uses 'newFilename', v2 uses path, filepath, newFilename
const filename = file.newFilename || path.basename(file.filepath) || file.filename;
const filepath = req.params.projectId + "/" + filename;
const objectId = Array.isArray(req.body.id) ? req.body.id[0] : req.body.id;
const objectName = Array.isArray(req.body.objectName) ? req.body.objectName[0] : req.body.objectName;
const projectId = req.params.projectId;

// Checks if the object is present in the database
Expand All @@ -107,7 +113,7 @@ const uploadFileAndSaveObject = errorHandler(async (req, res) => {
await ObjectsController.saveObject(objectId, objectName, projectId, filepath);
}

return { message: "Uploaded the file successfully: " + req.file.originalname };
return { message: "Uploaded the file successfully: " + filename };
});

module.exports = { getObjectById, getObjectsPathByProjectId, deleteObject, uploadFileAndSaveObject, getObjectsByProjectId };
3 changes: 3 additions & 0 deletions server/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ app.get("/", (req, res) => {
res.send("Hello World");
});

// Serve static files before auth middleware
app.use("/uploads", express.static(path.join(__dirname, "/public/uploads")));

app.use("/api/", require("./routes/auth"));
app.use(verifyToken);
app.use("/api/", require("./routes/users"));
Expand Down
42 changes: 26 additions & 16 deletions server/src/middleware/upload.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,36 @@ const formidable = require("formidable");
const fs = require("fs");
const path = require("path");

const uploadFileMiddleware = (req, res, next) => {
const dir = path.join(process.env.FILE_PATH, "/public/uploads/", req.params.projectId);
const uploadFileMiddleware = (req, res) => {
return new Promise((resolve, reject) => {
const baseDir = process.env.FILE_PATH || process.cwd();
const projectDir = req.params.projectId;
const dir = path.join(baseDir, "public", "uploads", projectDir);

if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
// Ensure directory exists
if (!fs.existsSync(dir)) {
try {
fs.mkdirSync(dir, { recursive: true });
} catch (err) {
console.error("Failed to create directory:", err);
return reject(err);
}
}

const form = new formidable.IncomingForm({
uploadDir: dir,
keepExtensions: true, // Keep original file extensions
});
const form = new formidable.IncomingForm({
uploadDir: dir,
keepExtensions: true,
});

form.parse(req, (err, fields, files) => {
if (err) {
return next(err);
}
form.parse(req, (err, fields, files) => {
if (err) {
return reject(err);
}

req.files = files; // Attach files to the request object for further processing
req.body = fields; // Attach other form fields if needed
next();
req.files = files;
req.body = fields;
resolve();
});
});
};

Expand Down