diff --git a/client/next.config.mjs b/client/next.config.mjs
index 81b6465..0f8b1d4 100644
--- a/client/next.config.mjs
+++ b/client/next.config.mjs
@@ -1,4 +1,5 @@
import os from "node:os";
+
import isInsideContainer from "is-inside-container";
const isWindowsDevContainer = () =>
@@ -7,6 +8,7 @@ const isWindowsDevContainer = () =>
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
+ output: "standalone",
// dumb fix for windows docker
images: {
unoptimized: process.env.NODE_ENV === "development",
diff --git a/client/package-lock.json b/client/package-lock.json
index 6c5e8fb..432624e 100644
--- a/client/package-lock.json
+++ b/client/package-lock.json
@@ -10,7 +10,8 @@
"dependencies": {
"@hookform/resolvers": "^3.9.0",
"@radix-ui/react-alert-dialog": "^1.1.1",
- "@radix-ui/react-dialog": "^1.1.1",
+ "@radix-ui/react-avatar": "^1.1.1",
+ "@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-dropdown-menu": "^2.1.1",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-label": "^2.1.0",
@@ -36,15 +37,18 @@
"react-dom": "^18.3.1",
"react-hook-form": "^7.52.1",
"react-icons": "^5.2.1",
+ "sonner": "^1.6.1",
"tailwind-merge": "^2.3.0",
"tailwindcss-animate": "^1.0.7",
- "zod": "^3.23.8"
+ "zod": "^3.23.8",
+ "zustand": "^5.0.1",
+ "zustand-persist": "^0.4.0"
},
"devDependencies": {
"@csstools/postcss-oklab-function": "^3.0.16",
"@tanstack/eslint-plugin-query": "^5.43.1",
"@types/js-cookie": "^3.0.6",
- "@types/node": "^20.14.10",
+ "@types/node": "20.17.6",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@typescript-eslint/eslint-plugin": "^7.13.1",
@@ -57,8 +61,9 @@
"postcss": "^8",
"prettier": "^3.3.2",
"prettier-plugin-tailwindcss": "^0.6.5",
+ "sonner": "^1.6.1",
"tailwindcss": "^3.4.1",
- "typescript": "^5.5.2"
+ "typescript": "5.7.2"
}
},
"node_modules/@alloc/quick-lru": {
@@ -724,6 +729,42 @@
}
}
},
+ "node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-dialog": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.1.tgz",
+ "integrity": "sha512-zysS+iU4YP3STKNS6USvFVqI4qqx8EpiwmT5TuCApVEBca+eRCbONi4EgzfNSuVnOXvC5UPHHMjs8RXO6DH9Bg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.0",
+ "@radix-ui/react-compose-refs": "1.1.0",
+ "@radix-ui/react-context": "1.1.0",
+ "@radix-ui/react-dismissable-layer": "1.1.0",
+ "@radix-ui/react-focus-guards": "1.1.0",
+ "@radix-ui/react-focus-scope": "1.1.0",
+ "@radix-ui/react-id": "1.1.0",
+ "@radix-ui/react-portal": "1.1.1",
+ "@radix-ui/react-presence": "1.1.0",
+ "@radix-ui/react-primitive": "2.0.0",
+ "@radix-ui/react-slot": "1.1.0",
+ "@radix-ui/react-use-controllable-state": "1.1.0",
+ "aria-hidden": "^1.1.1",
+ "react-remove-scroll": "2.5.7"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-arrow": {
"version": "1.1.0",
"license": "MIT",
@@ -768,11 +809,12 @@
}
},
"node_modules/@radix-ui/react-avatar": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.0.tgz",
- "integrity": "sha512-Q/PbuSMk/vyAd/UoIShVGZ7StHHeRFYU7wXmi5GV+8cLXflZAEpHL/F697H1klrzxKXNtZ97vWiC0q3RKUH8UA==",
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.1.tgz",
+ "integrity": "sha512-eoOtThOmxeoizxpX6RiEsQZ2wj5r4+zoeqAwO0cBaFQGjJwIH3dIX0OCxNrCyrrdxG+vBweMETh3VziQG7c1kw==",
+ "license": "MIT",
"dependencies": {
- "@radix-ui/react-context": "1.1.0",
+ "@radix-ui/react-context": "1.1.1",
"@radix-ui/react-primitive": "2.0.0",
"@radix-ui/react-use-callback-ref": "1.1.0",
"@radix-ui/react-use-layout-effect": "1.1.0"
@@ -792,6 +834,21 @@
}
}
},
+ "node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-context": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.1.tgz",
+ "integrity": "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-checkbox": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.1.1.tgz",
@@ -928,24 +985,130 @@
}
},
"node_modules/@radix-ui/react-dialog": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.1.tgz",
- "integrity": "sha512-zysS+iU4YP3STKNS6USvFVqI4qqx8EpiwmT5TuCApVEBca+eRCbONi4EgzfNSuVnOXvC5UPHHMjs8RXO6DH9Bg==",
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.2.tgz",
+ "integrity": "sha512-Yj4dZtqa2o+kG61fzB0H2qUvmwBA2oyQroGLyNtBj1beo1khoQ3q1a2AO8rrQYjd8256CO9+N8L9tvsS+bnIyA==",
+ "license": "MIT",
"dependencies": {
"@radix-ui/primitive": "1.1.0",
"@radix-ui/react-compose-refs": "1.1.0",
- "@radix-ui/react-context": "1.1.0",
- "@radix-ui/react-dismissable-layer": "1.1.0",
- "@radix-ui/react-focus-guards": "1.1.0",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-dismissable-layer": "1.1.1",
+ "@radix-ui/react-focus-guards": "1.1.1",
"@radix-ui/react-focus-scope": "1.1.0",
"@radix-ui/react-id": "1.1.0",
- "@radix-ui/react-portal": "1.1.1",
- "@radix-ui/react-presence": "1.1.0",
+ "@radix-ui/react-portal": "1.1.2",
+ "@radix-ui/react-presence": "1.1.1",
"@radix-ui/react-primitive": "2.0.0",
"@radix-ui/react-slot": "1.1.0",
"@radix-ui/react-use-controllable-state": "1.1.0",
"aria-hidden": "^1.1.1",
- "react-remove-scroll": "2.5.7"
+ "react-remove-scroll": "2.6.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-context": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.1.tgz",
+ "integrity": "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-dismissable-layer": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.1.tgz",
+ "integrity": "sha512-QSxg29lfr/xcev6kSz7MAlmDnzbP1eI/Dwn3Tp1ip0KT5CUELsxkekFEMVBEoykI3oV39hKT4TKZzBNMbcTZYQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.0",
+ "@radix-ui/react-compose-refs": "1.1.0",
+ "@radix-ui/react-primitive": "2.0.0",
+ "@radix-ui/react-use-callback-ref": "1.1.0",
+ "@radix-ui/react-use-escape-keydown": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-focus-guards": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.1.tgz",
+ "integrity": "sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-portal": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.2.tgz",
+ "integrity": "sha512-WeDYLGPxJb/5EGBoedyJbT0MpoULmwnIPMJMSldkuiMsBAv7N1cRdsTWZWht9vpPOiN3qyiGAtbK2is47/uMFg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.0.0",
+ "@radix-ui/react-use-layout-effect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-presence": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.1.tgz",
+ "integrity": "sha512-IeFXVi4YS1K0wVZzXNrbaaUvIJ3qdY+/Ih4eHFhWA9SwGR9UDX7Ck8abvL57C4cv3wwMvUE0OG69Qc3NCcTe/A==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.0",
+ "@radix-ui/react-use-layout-effect": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
@@ -962,6 +1125,31 @@
}
}
},
+ "node_modules/@radix-ui/react-dialog/node_modules/react-remove-scroll": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.0.tgz",
+ "integrity": "sha512-I2U4JVEsQenxDAKaVa3VZ/JeJZe0/2DxPWL8Tj8yLKctQJQiZM52pn/GWFpSp8dftjM3pSAHVJZscAnC/y+ySQ==",
+ "license": "MIT",
+ "dependencies": {
+ "react-remove-scroll-bar": "^2.3.6",
+ "react-style-singleton": "^2.2.1",
+ "tslib": "^2.1.0",
+ "use-callback-ref": "^1.3.0",
+ "use-sidecar": "^1.1.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-direction": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz",
@@ -1993,12 +2181,13 @@
"license": "MIT"
},
"node_modules/@types/node": {
- "version": "20.14.10",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz",
- "integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==",
+ "version": "20.17.6",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.6.tgz",
+ "integrity": "sha512-VEI7OdvK2wP7XHnsuXbAJnEpEkF6NjSN45QJlL4VGqZSXsnicpesdTWsg9RISeSdYd3yeRj/y3k5KGjUXYnFwQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "undici-types": "~5.26.4"
+ "undici-types": "~6.19.2"
}
},
"node_modules/@types/prop-types": {
@@ -7290,6 +7479,17 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/sonner": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/sonner/-/sonner-1.7.0.tgz",
+ "integrity": "sha512-W6dH7m5MujEPyug3lpI2l3TC3Pp1+LTgK0Efg+IHDrBbtEjyCmCHHo6yfNBOsf1tFZ6zf+jceWwB38baC8yO9g==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc",
+ "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ }
+ },
"node_modules/source-map-js": {
"version": "1.2.0",
"license": "BSD-3-Clause",
@@ -7785,7 +7985,9 @@
}
},
"node_modules/typescript": {
- "version": "5.5.3",
+ "version": "5.7.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz",
+ "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==",
"dev": true,
"license": "Apache-2.0",
"bin": {
@@ -7811,7 +8013,9 @@
}
},
"node_modules/undici-types": {
- "version": "5.26.5",
+ "version": "6.19.8",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
+ "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
"dev": true,
"license": "MIT"
},
@@ -8103,6 +8307,45 @@
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
+ },
+ "node_modules/zustand": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.1.tgz",
+ "integrity": "sha512-pRET7Lao2z+n5R/HduXMio35TncTlSW68WsYBq2Lg1ASspsNGjpwLAsij3RpouyV6+kHMwwwzP0bZPD70/Jx/w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.20.0"
+ },
+ "peerDependencies": {
+ "@types/react": ">=18.0.0",
+ "immer": ">=9.0.6",
+ "react": ">=18.0.0",
+ "use-sync-external-store": ">=1.2.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "immer": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ },
+ "use-sync-external-store": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/zustand-persist": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/zustand-persist/-/zustand-persist-0.4.0.tgz",
+ "integrity": "sha512-u6bBIc4yZRpSKBKuTNhoqvoIb09gGHk2NkiPg4K7MPIWTYZg70PlpBn48QEDnKZwfNurnf58TaW5BuMGIMf5hw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "zustand": ">=3.6.3"
+ }
}
}
}
diff --git a/client/package.json b/client/package.json
index bbdfce3..08cb1d8 100644
--- a/client/package.json
+++ b/client/package.json
@@ -12,7 +12,7 @@
"format": "prettier -w src",
"format:check": "prettier -c src",
"typecheck": "tsc --noEmit",
- "prepare": "cd .. && husky client/.husky"
+ "prepare": "if [ \"$NODE_ENV\" != \"production\" ]; then cd .. && husky client/.husky; fi"
},
"dependencies": {
"@hookform/resolvers": "^3.9.0",
@@ -55,7 +55,7 @@
"@csstools/postcss-oklab-function": "^3.0.16",
"@tanstack/eslint-plugin-query": "^5.43.1",
"@types/js-cookie": "^3.0.6",
- "@types/node": "^20.14.10",
+ "@types/node": "20.17.6",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@typescript-eslint/eslint-plugin": "^7.13.1",
@@ -68,7 +68,8 @@
"postcss": "^8",
"prettier": "^3.3.2",
"prettier-plugin-tailwindcss": "^0.6.5",
+ "sonner": "^1.6.1",
"tailwindcss": "^3.4.1",
- "typescript": "^5.5.2"
+ "typescript": "5.7.2"
}
-}
+}
\ No newline at end of file
diff --git a/client/src/components/main/header/Navbar.tsx b/client/src/components/main/header/Navbar.tsx
index fd219dc..7bb6b8c 100644
--- a/client/src/components/main/header/Navbar.tsx
+++ b/client/src/components/main/header/Navbar.tsx
@@ -25,7 +25,7 @@ function Links({ isHiddenWhenLg }: { isHiddenWhenLg: boolean }) {
Upcoming Events
-
+
About Us
diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml
new file mode 100644
index 0000000..4e6f853
--- /dev/null
+++ b/docker-compose.prod.yml
@@ -0,0 +1,71 @@
+services:
+ db:
+ container_name: coexist-db
+ image: postgres:16
+ restart: unless-stopped
+ env_file: ./server/.env
+ volumes:
+ - db-data:/var/lib/postgresql/data
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready -U postgres"]
+ interval: 3s
+ timeout: 3s
+ retries: 5
+ ports:
+ - "5432:5432"
+
+ server:
+ container_name: coexist-server
+ image: ghcr.io/codersforcauses/coexist-server
+ # build:
+ # context: .
+ # dockerfile: ./docker/server/Dockerfile
+ restart: unless-stopped
+ volumes:
+ - /var/www/coexist.codersforcauses.org/static:/var/www/coexist.codersforcauses.org/static
+ env_file: ./server/.env
+ depends_on:
+ - db
+ ports:
+ - "8000:8000"
+
+ client:
+ container_name: coexist-client
+ image: ghcr.io/codersforcauses/coexist-client
+ # build:
+ # context: .
+ # dockerfile: ./docker/client/Dockerfile.prod
+ restart: unless-stopped
+ env_file: ./client/.env
+ environment:
+ - APP_ENV=PRODUCTION
+ depends_on:
+ - server
+ ports:
+ - "3000:3000"
+
+ nginx:
+ # build:
+ # context: ./docker/nginx
+ # dockerfile: Dockerfile
+ image: ghcr.io/codersforcauses/coexist-nginx:latest
+ container_name: coexist-nginx
+ restart: unless-stopped
+ volumes:
+ - /var/www/coexist.codersforcauses.org/static:/var/www/coexist.codersforcauses.org/static
+ ports:
+ - "80:80"
+ depends_on:
+ - server
+
+ watchtower:
+ image: containrrr/watchtower
+ container_name: coexist_watchtower
+ restart: unless-stopped
+ volumes:
+ - /var/run/docker.sock:/var/run/docker.sock
+ - $HOME/.docker/config.json:/config.json
+ command: --interval 30
+
+volumes:
+ db-data:
\ No newline at end of file
diff --git a/docker/client/Dockerfile b/docker/client/Dockerfile
index e7492aa..7de3587 100644
--- a/docker/client/Dockerfile
+++ b/docker/client/Dockerfile
@@ -8,9 +8,6 @@ COPY /docker/client/entrypoint.sh /entrypoint.sh
COPY ./client/package.json ./client/package-lock.json ./
-# Install ALL Dependencies
-RUN npm install
-
# Copy Application code into a directory called `app`
COPY ./client /app
@@ -21,5 +18,3 @@ COPY ./client /app
# CMD commands get executed at container runtime!
RUN chmod +x /entrypoint.sh
CMD ["/entrypoint.sh"]
-
-# TODO: Production
\ No newline at end of file
diff --git a/docker/client/Dockerfile.prod b/docker/client/Dockerfile.prod
new file mode 100644
index 0000000..0b560a3
--- /dev/null
+++ b/docker/client/Dockerfile.prod
@@ -0,0 +1,43 @@
+# Step 1: Build Stage
+FROM node:20-slim as build-stage
+
+# Set working directory
+WORKDIR /app
+
+# Copy package.json and package-lock.json
+COPY ./client/package.json ./client/package-lock.json ./
+
+# echo hi
+RUN echo "Building the application..."
+
+# Install dependencies
+RUN npm install
+
+# Copy application code
+COPY ./client /app
+
+# Ensure .next/cache directory exists and is writable
+RUN mkdir -p /app/.next/cache && chmod -R 755 /app/.next/cache
+
+# Build the application in standalone mode
+RUN npm run build
+
+# Create build timestamp
+RUN date -u > /app/build_timestamp.txt
+
+# Step 2: Production Stage
+FROM node:20-slim as production-stage
+
+# Set working directory
+WORKDIR /app
+
+# Copy the built files from the build stage
+COPY --from=build-stage /app/.next/standalone /app
+COPY --from=build-stage /app/.next/static /app/.next/static
+COPY --from=build-stage /app/public /app/public
+COPY --from=build-stage /app/build_timestamp.txt /app/build_timestamp.txt
+
+# run the web server.
+CMD ["node", "server.js"]
+
+LABEL org.opencontainers.image.source https://github.com/codersforcauses/coexist
\ No newline at end of file
diff --git a/docker/client/entrypoint.sh b/docker/client/entrypoint.sh
index 0173c5c..3cf1a9f 100644
--- a/docker/client/entrypoint.sh
+++ b/docker/client/entrypoint.sh
@@ -1,58 +1,39 @@
-#!/bin/bash
+#!/bin/sh
-echo "${APP_NAME^^} - NextJS CONTAINER STARTING..."
-echo $APP_NAME
+set -e
-# Display Docker Image / CI / Release details
-echo "Image Build Date/Time: " "$(cat /app/build_timestamp.txt)" "UTC"
+echo "$APP_NAME - NextJS CONTAINER STARTING..."
+echo "APP_NAME: $APP_NAME"
+
+# Display Build Date/Time if available
+if [ -f /app/build_timestamp.txt ]; then
+ echo "Image Build Date/Time: $(cat /app/build_timestamp.txt) UTC"
+fi
echo "-----------------------------------------------------------"
echo "APP_ENV: ${APP_ENV}"
-# # ====================================================================================
-# # Debug / Sanity check info
-# # ====================================================================================
-# echo " "
-# echo "======= Current Dir / Files (Debug) ============================================================================="
-# pwd
-# ls -al
-
-# echo " "
-# echo "======= Env Vars (Debug) ========================================================================================"
-# if [ "${APP_ENV^^}" != "PRODUCTION" ]; then
-# # Only print environment vars in non-prod environments to prevent sensitive variables being sent to logging system
-# printenv
-# fi
-
-# echo " "
-# echo "======= Linux version (Debug) ==================================================================================="
-# cat /etc/os-release
-
-# echo " "
-# echo "======= Node Path & Version (Debug) ==========================================================================="
-# node -v
-
-# Check for required env vars, exit as failure if missing these critical env vars.
-if [[ -z "${APP_ENV}" ]]; then
+# Check for required env vars
+if [ -z "${APP_ENV}" ]; then
echo "█████████████████████████████████████████████████████████████████████████████████████████████████████████████"
- echo "█ CRITICAL ERROR: Missing 'APP_ENV' environment variables."
+ echo "█ CRITICAL ERROR: Missing 'APP_ENV' environment variable."
echo "█████████████████████████████████████████████████████████████████████████████████████████████████████████████"
- echo "APP_ENV=" $APP_ENV
- echo "░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░"
- exit
+ echo "APP_ENV=${APP_ENV}"
+ exit 1
fi
-# CI TEST DOWN THE TRACK
-
-# ====================================================================================
-# Run inbuilt nextjs server if ENV is LOCAL
-# ====================================================================================
-if [ "${APP_ENV^^}" = "DEVELOPMENT" ]; then
- # Install dependencies (idk why it's not installing the latest ones in the docker image)
+# Start the application based on APP_ENV
+if [ "${APP_ENV}" = "PRODUCTION" ]; then
+ echo "Starting Next.js application in production mode"
+ # Build and run for prod
+ npm install
+ npm run build
+ npm start
+elif [ "${APP_ENV}" = "DEVELOPMENT" ]; then
+ echo "Starting Next.js application in development mode"
npm install
- # Run developments
- echo " "
- echo "======= Starting inbuilt nextjs webserver ==================================================================="
npm run dev
- exit
-fi
\ No newline at end of file
+else
+ echo "Unknown APP_ENV: ${APP_ENV}"
+ exit 1
+fi
diff --git a/docker/nginx/Dockerfile b/docker/nginx/Dockerfile
new file mode 100644
index 0000000..2642a0f
--- /dev/null
+++ b/docker/nginx/Dockerfile
@@ -0,0 +1,4 @@
+FROM nginx:latest
+
+RUN rm /etc/nginx/conf.d/default.conf
+COPY ./docker/nginx/conf.d/ /etc/nginx/conf.d/
diff --git a/docker/nginx/conf.d/default.conf b/docker/nginx/conf.d/default.conf
new file mode 100644
index 0000000..7046d00
--- /dev/null
+++ b/docker/nginx/conf.d/default.conf
@@ -0,0 +1,53 @@
+server {
+ listen 80;
+ server_name coexistapi.codersforcauses.org;
+
+ real_ip_header CF-Connecting-IP;
+ set_real_ip_from 103.21.244.0/22;
+ set_real_ip_from 103.22.200.0/22;
+ set_real_ip_from 103.31.4.0/22;
+ set_real_ip_from 104.16.0.0/12;
+ set_real_ip_from 108.162.192.0/18;
+ set_real_ip_from 131.0.72.0/22;
+ set_real_ip_from 141.101.64.0/18;
+ set_real_ip_from 162.158.0.0/15;
+ set_real_ip_from 172.64.0.0/13;
+ set_real_ip_from 173.245.48.0/20;
+ set_real_ip_from 188.114.96.0/20;
+ set_real_ip_from 190.93.240.0/20;
+ set_real_ip_from 197.234.240.0/22;
+ set_real_ip_from 198.41.128.0/17;
+ real_ip_recursive on;
+
+ location /api {
+ proxy_http_version 1.1;
+ proxy_pass http://coexist-server:8000;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection 'upgrade';
+ proxy_set_header Host $host;
+ proxy_cache_bypass $http_upgrade;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ }
+
+ location /static/ {
+ alias /var/www/coexist.codersforcauses.org/static/;
+ autoindex on;
+ }
+
+ location /admin {
+ proxy_pass http://coexist-server:8000;
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection 'upgrade';
+ proxy_set_header Host $host;
+ proxy_cache_bypass $http_upgrade;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ }
+
+ access_log /var/log/nginx/api-coexist.access.log;
+ error_log /var/log/nginx/api-coexist.error.log;
+}
diff --git a/docker/server/Dockerfile b/docker/server/Dockerfile
index 3e886bd..bd3ce08 100644
--- a/docker/server/Dockerfile
+++ b/docker/server/Dockerfile
@@ -1,21 +1,45 @@
+# Use the official Python image
FROM python:3.12-slim
-RUN apt-get update && apt-get install --yes --no-install-recommends postgresql-client g++ libssl-dev && rm -rf /var/lib/apt/lists/*
+# Install system dependencies
+RUN apt-get update && \
+ apt-get install --yes --no-install-recommends \
+ build-essential \
+ libssl-dev \
+ libpq-dev \
+ postgresql-client && \
+ rm -rf /var/lib/apt/lists/*
-RUN pip install --upgrade pip && pip install poetry
+# Set work directory
+WORKDIR /app
-RUN poetry config virtualenvs.in-project false
-RUN poetry config virtualenvs.create false
+# Install Poetry
+RUN pip install --upgrade pip && \
+ pip install poetry
-WORKDIR /app
+# Configure Poetry
+RUN poetry config virtualenvs.create false
-COPY ./docker/server/entrypoint.sh /entrypoint.sh
+RUN mkdir -p /var/log/accesslogs
+# Copy the application files
COPY ./server/pyproject.toml ./server/poetry.lock ./
+RUN poetry install --without dev --no-root --no-interaction --no-ansi
-RUN poetry install
+COPY ./server/ ./
-COPY ./server ./
+# Collect static files
+RUN python manage.py collectstatic --noinput --verbosity 2
+# Create log directory
+RUN mkdir -p /var/log/accesslogs && \
+ chmod -R 755 /var/log/accesslogs
+
+# Copy entrypoint script
+COPY ./docker/server/entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
-CMD ["/entrypoint.sh"]
\ No newline at end of file
+
+# Start the application
+ENTRYPOINT ["/entrypoint.sh"]
+
+LABEL org.opencontainers.image.source=https://github.com/codersforcauses/coexist
\ No newline at end of file
diff --git a/docker/server/entrypoint.sh b/docker/server/entrypoint.sh
index 5d36abf..93d568b 100644
--- a/docker/server/entrypoint.sh
+++ b/docker/server/entrypoint.sh
@@ -1,5 +1,9 @@
#!/bin/bash
+set -e
+
+export DJANGO_SETTINGS_MODULE=api.settings
+
# Wait until Database is available before continuing
printf "\n" && echo "Checking Database is up"
# using psql
@@ -17,9 +21,11 @@ python manage.py migrate --noinput
echo "Collecting static files"
python manage.py collectstatic --noinput
-# Create Django Superuser
-echo "Creating Django Superuser"
-python manage.py createsuperuser --noinput
+# Check if superuser exists
+if [ "$APP_ENV" = "DEVELOPMENT" ]; then
+ echo "Creating Django Superuser"
+ python manage.py createsuperuser --noinput || true
+fi
# Run inbuilt Django server if ENV is development
if [ "${APP_ENV^^}" = "DEVELOPMENT" ]; then
@@ -43,5 +49,5 @@ if [ "${APP_ENV^^}" = "PRODUCTION" ]; then
# Run Gunicorn / Django
printf "\n" && echo " Running Gunicorn / Django"
echo "Running: gunicorn api.wsgi -b 0.0.0.0:8000 --workers=6 --keep-alive 20 --log-file=- --log-level debug --access-logfile=/var/log/accesslogs/gunicorn --capture-output --timeout 50"
- gunicorn api.wsgi -b 0.0.0.0:8000 --workers=6 --keep-alive 20 --log-file=- --log-level debug --access-logfile=/var/log/accesslogs/gunicorn --capture-output --timeout 50
+ poetry run gunicorn api.wsgi -b 0.0.0.0:8000 --workers=6 --keep-alive 20 --log-file=- --log-level debug --access-logfile=/var/log/accesslogs/gunicorn --capture-output --timeout 50
fi
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..015be09
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,476 @@
+{
+ "name": "coexist",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "dependencies": {
+ "sharp": "^0.33.5"
+ }
+ },
+ "node_modules/@emnapi/runtime": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.3.1.tgz",
+ "integrity": "sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@img/sharp-darwin-arm64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz",
+ "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-arm64": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-darwin-x64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz",
+ "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-x64": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-libvips-darwin-arm64": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz",
+ "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-darwin-x64": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz",
+ "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-arm": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz",
+ "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==",
+ "cpu": [
+ "arm"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-arm64": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz",
+ "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-s390x": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz",
+ "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==",
+ "cpu": [
+ "s390x"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-x64": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz",
+ "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linuxmusl-arm64": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz",
+ "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linuxmusl-x64": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz",
+ "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-linux-arm": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz",
+ "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==",
+ "cpu": [
+ "arm"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm": "1.0.5"
+ }
+ },
+ "node_modules/@img/sharp-linux-arm64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz",
+ "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm64": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-s390x": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz",
+ "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==",
+ "cpu": [
+ "s390x"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-s390x": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-x64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz",
+ "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-x64": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-linuxmusl-arm64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz",
+ "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==",
+ "cpu": [
+ "arm64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-arm64": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-linuxmusl-x64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz",
+ "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-x64": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-wasm32": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz",
+ "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==",
+ "cpu": [
+ "wasm32"
+ ],
+ "optional": true,
+ "dependencies": {
+ "@emnapi/runtime": "^1.2.0"
+ },
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-ia32": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz",
+ "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-x64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz",
+ "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==",
+ "cpu": [
+ "x64"
+ ],
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/color": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
+ "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
+ "dependencies": {
+ "color-convert": "^2.0.1",
+ "color-string": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=12.5.0"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+ },
+ "node_modules/color-string": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
+ "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
+ "dependencies": {
+ "color-name": "^1.0.0",
+ "simple-swizzle": "^0.2.2"
+ }
+ },
+ "node_modules/detect-libc": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
+ "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-arrayish": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
+ "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
+ },
+ "node_modules/semver": {
+ "version": "7.6.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+ "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/sharp": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz",
+ "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "color": "^4.2.3",
+ "detect-libc": "^2.0.3",
+ "semver": "^7.6.3"
+ },
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-darwin-arm64": "0.33.5",
+ "@img/sharp-darwin-x64": "0.33.5",
+ "@img/sharp-libvips-darwin-arm64": "1.0.4",
+ "@img/sharp-libvips-darwin-x64": "1.0.4",
+ "@img/sharp-libvips-linux-arm": "1.0.5",
+ "@img/sharp-libvips-linux-arm64": "1.0.4",
+ "@img/sharp-libvips-linux-s390x": "1.0.4",
+ "@img/sharp-libvips-linux-x64": "1.0.4",
+ "@img/sharp-libvips-linuxmusl-arm64": "1.0.4",
+ "@img/sharp-libvips-linuxmusl-x64": "1.0.4",
+ "@img/sharp-linux-arm": "0.33.5",
+ "@img/sharp-linux-arm64": "0.33.5",
+ "@img/sharp-linux-s390x": "0.33.5",
+ "@img/sharp-linux-x64": "0.33.5",
+ "@img/sharp-linuxmusl-arm64": "0.33.5",
+ "@img/sharp-linuxmusl-x64": "0.33.5",
+ "@img/sharp-wasm32": "0.33.5",
+ "@img/sharp-win32-ia32": "0.33.5",
+ "@img/sharp-win32-x64": "0.33.5"
+ }
+ },
+ "node_modules/simple-swizzle": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
+ "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
+ "dependencies": {
+ "is-arrayish": "^0.3.1"
+ }
+ },
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "optional": true
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..bd15579
--- /dev/null
+++ b/package.json
@@ -0,0 +1,5 @@
+{
+ "dependencies": {
+ "sharp": "^0.33.5"
+ }
+}
diff --git a/server/.env.example b/server/.env.example
index 69d13e0..9d052ba 100644
--- a/server/.env.example
+++ b/server/.env.example
@@ -2,7 +2,7 @@ APP_NAME=DjangoAPI
APP_ENV=DEVELOPMENT
API_SECRET_KEY="supersecretkey"
-API_ALLOWED_HOSTS=".localhost 127.0.0.1 [::1]"
+API_ALLOWED_HOSTS=".localhost 127.0.0.1 [::1] coexist-server"
POSTGRES_HOST=db
POSTGRES_NAME=postgres
@@ -14,4 +14,6 @@ DJANGO_SUPERUSER_PASSWORD=Password123
DJANGO_SUPERUSER_EMAIL=admin@test.com
DJANGO_SUPERUSER_USERNAME=admin
-FRONTEND_URL="http://localhost:3000"
\ No newline at end of file
+FRONTEND_URL="http://localhost:3000"
+
+DJANGO_PROJECT_ROOT="/server" # Only applies in production at the moment
diff --git a/server/api/settings.py b/server/api/settings.py
index 87f084d..0ffbbc4 100644
--- a/server/api/settings.py
+++ b/server/api/settings.py
@@ -11,6 +11,8 @@
"""
import os
+import datetime
+
from pathlib import Path
from dotenv import load_dotenv
@@ -81,10 +83,17 @@
"corsheaders.middleware.CorsMiddleware",
]
-CORS_ALLOWED_ORIGINS = [
- "http://localhost:3000",
- "http://127.0.0.1:3000",
-]
+CORS_ALLOWED_ORIGINS = (
+ os.environ.get("CORS_ALLOWED_ORIGINS").split()
+ if os.environ.get("CORS_ALLOWED_ORIGINS")
+ else []
+)
+
+CSRF_TRUSTED_ORIGINS = (
+ os.environ.get("CSRF_ALLOWED_ORIGINS").split()
+ if os.environ.get("CSRF_ALLOWED_ORIGINS")
+ else []
+)
ROOT_URLCONF = "api.urls"
@@ -155,18 +164,23 @@
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.2/howto/static-files/
-PROJECT_ROOT = os.path.dirname(
- os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-) # <- '/' directory
-
STATIC_URL = "/static/"
-# STATIC_ROOT is where the static files get copied to when "collectstatic" is run.
-# STATIC_ROOT = os.path.join(PROJECT_ROOT, "server", "static")
+def get_project_root() -> str:
+ if os.environ.get("APP_ENV") == "DEVELOPMENT":
+ return os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+ else:
+ return os.environ.get("DJANGO_PROJECT_ROOT")
+
+PROJECT_ROOT = get_project_root()
+
+# Will need to configure this for actual deployment
+STATIC_ROOT = "/var/www/coexist.codersforcauses.org/static/"
+
+STATICFILES_DIRS = [
+ os.path.join(BASE_DIR, "static")
+]
-# This is where to _find_ static files when 'collectstatic' is run.
-# These files are then copied to the STATIC_ROOT location.
-STATICFILES_DIRS = (os.path.join(PROJECT_ROOT, "server", "static"),)
# Default primary key field type
# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field
@@ -175,7 +189,7 @@
# DRF Simple JWT Configuration
-SIMPLE_JWT = {
- # "ACCESS_TOKEN_LIFETIME": datetime.timedelta(seconds=10),
- # "REFRESH_TOKEN_LIFETIME": datetime.timedelta(seconds=30),
-}
+# SIMPLE_JWT = {
+# "ACCESS_TOKEN_LIFETIME": datetime.timedelta(seconds=10),
+# "REFRESH_TOKEN_LIFETIME": datetime.timedelta(seconds=30),
+# }
\ No newline at end of file
diff --git a/server/api/wsgi.py b/server/api/wsgi.py
index af988b5..7fc622a 100644
--- a/server/api/wsgi.py
+++ b/server/api/wsgi.py
@@ -11,6 +11,6 @@
from django.core.wsgi import get_wsgi_application
-os.environ.setdefault("DJANGO_SETTINGS_MODULE", "server.settings")
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "api.settings")
application = get_wsgi_application()
diff --git a/server/static/images/AintGotSubstanceCover.jpg b/server/static/images/AintGotSubstanceCover.jpg
deleted file mode 100644
index ed447bb..0000000
Binary files a/server/static/images/AintGotSubstanceCover.jpg and /dev/null differ
diff --git a/server/static/images/Fantasy_Art_sJQOgWS.jpg b/server/static/images/Fantasy_Art_sJQOgWS.jpg
deleted file mode 100644
index 7bf06ca..0000000
Binary files a/server/static/images/Fantasy_Art_sJQOgWS.jpg and /dev/null differ
diff --git a/server/static/images/anime_garden.jpg b/server/static/images/anime_garden.jpg
deleted file mode 100644
index d8308d7..0000000
Binary files a/server/static/images/anime_garden.jpg and /dev/null differ
diff --git a/server/static/images/battleofthebots.png b/server/static/images/battleofthebots.png
deleted file mode 100644
index 6ea0edd..0000000
Binary files a/server/static/images/battleofthebots.png and /dev/null differ
diff --git a/server/static/images/vintage.jpg b/server/static/images/vintage.jpg
deleted file mode 100644
index 7e62349..0000000
Binary files a/server/static/images/vintage.jpg and /dev/null differ