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