diff --git a/.env.example b/.env.example index a9f88cc..e8bee8f 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,3 @@ APPWRITE_FUNCTION_API_KEY= -NEXT_PUBLIC_APPWRITE_HOST=http://localhost:86/v1 -# Must be the same as in the _APP_STORAGE_LIMIT in the Appwrite env file -NEXT_PUBLIC_MAX_FILE_SIZE=300000000 \ No newline at end of file +PUBLIC_APPWRITE_HOST=http://localhost/v1 +PUBLIC_MAX_FILE_SIZE="300000000" # Must be the same as in the _APP_STORAGE_LIMIT in the Appwrite env file \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 5b76f30..24a68b7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,6 +4,12 @@ WORKDIR /opt/app COPY package.json package-lock.json ./ RUN npm ci +FROM node:16-alpine AS builder +ENV NODE_ENV=production +WORKDIR /opt/app +COPY . . +COPY --from=deps /opt/app/node_modules ./node_modules +RUN npm run build FROM node:16-alpine AS script-builder WORKDIR /opt/app @@ -17,9 +23,11 @@ RUN ncc build index.ts FROM node:16-alpine AS runner WORKDIR /opt/app ENV NODE_ENV=production -COPY . . -COPY --from=deps /opt/app/node_modules ./node_modules +COPY --from=builder /opt/app/next.config.js ./ +COPY --from=builder /opt/app/public ./public +COPY --from=builder /opt/app/.next ./.next +COPY --from=builder /opt/app/node_modules ./node_modules COPY --from=script-builder /opt/app/.setup/dist/index.js ./scripts/setup.js EXPOSE 3000 -CMD npm run build && npm start \ No newline at end of file +CMD ["node_modules/.bin/next", "start"] \ No newline at end of file diff --git a/README.md b/README.md index 02f23d2..594d97c 100644 --- a/README.md +++ b/README.md @@ -30,14 +30,14 @@ First of all you have to start the Docker container. The container is now running. Now you have to setup the Appwrite structure, but no worries I made a setup script. -To start the script run `docker-compose exec pingvin-share node scripts/setup.js`. +To run the script run `docker-compose exec pingvin-share node scripts/setup.js`. You're almost done, now you have to change your environment variables that they fit to your setup. 1. Go to your Appwrite console, visit "API Keys" and copy the "Functions API Key" secret to your clipboard. 2. Paste the key to the `APPWRITE_FUNCTION_API_KEY` variable in the `.env` file -3. Change `NEXT_PUBLIC_APPWRITE_HOST` in the `.env` file to the host where your Appwrite instance runs -4. Change `NEXT_PUBLIC_MAX_FILE_SIZE` in the `.env` file to the max file size limit you want +3. Change `PUBLIC_APPWRITE_HOST` in the `.env` file to the host where your Appwrite instance runs +4. Change `PUBLIC_MAX_FILE_SIZE` in the `.env` file to the max file size limit you want ## Known issues / Limitations @@ -45,7 +45,6 @@ Pingvin Share is currently in beta and there are issues and limitations that sho - `DownloadAll` generates the zip file on the client side. This takes alot of time. Because of that I temporarily limited this function to maximal 150 MB. - If a user knows the share id, he can list and download the files directly from the Appwrite API even if the share is secured by a password or a visitor limit. -- Because NextJS injects environments variables at build time, the website must be rebuilt when an environment variable changes. At the moment the container rebuilts the website after every restart. This takes some time. ## Contribute diff --git a/docker-compose.yml b/docker-compose.yml index 73175a1..36f65eb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,5 +6,5 @@ services: image: stonith404/pingvin-share environment: - APPWRITE_FUNCTION_API_KEY=${APPWRITE_FUNCTION_API_KEY} - - NEXT_PUBLIC_APPWRITE_HOST=${NEXT_PUBLIC_APPWRITE_HOST} - - NEXT_PUBLIC_MAX_FILE_SIZE=${NEXT_PUBLIC_MAX_FILE_SIZE} \ No newline at end of file + - PUBLIC_APPWRITE_HOST=${PUBLIC_APPWRITE_HOST} + - PUBLIC_MAX_FILE_SIZE=${PUBLIC_MAX_FILE_SIZE} \ No newline at end of file diff --git a/package.json b/package.json index 20669b7..b476306 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,6 @@ "build": "next build", "start": "next start", "lint": "next lint", - "start:docker": "docker build -t pingvin-share:latest . && docker run pingvin-share:latest", "init:appwrite": "cd .setup && npm install && npx ts-node index.ts", "deploy": "docker buildx build -t stonith404/pingvin-share --platform linux/amd64,linux/arm64 --push ." }, diff --git a/src/components/upload/Dropzone.tsx b/src/components/upload/Dropzone.tsx index f096a24..3e1dbdf 100644 --- a/src/components/upload/Dropzone.tsx +++ b/src/components/upload/Dropzone.tsx @@ -10,6 +10,7 @@ import { import { Dropzone as MantineDropzone, DropzoneStatus } from "@mantine/dropzone"; import React, { Dispatch, ForwardedRef, SetStateAction, useRef } from "react"; import { CloudUpload, Upload } from "tabler-icons-react"; +import { useConfig } from "../../utils/config.util"; import toast from "../../utils/toast.util"; const useStyles = createStyles((theme) => ({ @@ -52,13 +53,14 @@ const Dropzone = ({ setFiles: Dispatch>; }) => { const theme = useMantineTheme(); + const config = useConfig() const { classes } = useStyles(); const openRef = useRef<() => void>(); return (
{ toast.error(e[0].errors[0].message); }} diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 3edb1fa..6da050e 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -14,7 +14,9 @@ import "../../styles/globals.css"; import ThemeProvider from "../components/mantine/ThemeProvider"; import Header from "../components/navBar/NavBar"; import globalStyle from "../styles/global.style"; +import aw from "../utils/appwrite.util"; import authUtil, { IsSignedInContext } from "../utils/auth.util"; +import configUtil, { ConfigContext } from "../utils/config.util"; import { GlobalLoadingContext } from "../utils/loading.util"; function App(props: AppProps & { colorScheme: ColorScheme }) { @@ -26,13 +28,17 @@ function App(props: AppProps & { colorScheme: ColorScheme }) { const [isLoading, setIsLoading] = useState(true); const [isSignedIn, setIsSignedIn] = useState(false); - const checkIfSignedIn = async () => { + let environmentVariables: any = {}; + + const getInitalData = async () => { setIsLoading(true); + environmentVariables = await configUtil.getGonfig(); + aw.setEndpoint(environmentVariables.APPWRITE_HOST); setIsSignedIn(await authUtil.isSignedIn()); setIsLoading(false); }; useEffect(() => { - checkIfSignedIn(); + getInitalData(); }, []); return ( @@ -44,13 +50,15 @@ function App(props: AppProps & { colorScheme: ColorScheme }) { {isLoading ? ( ) : ( - - -
- - - - + + + +
+ + + + + )} diff --git a/src/pages/api/config.ts b/src/pages/api/config.ts new file mode 100644 index 0000000..45ed923 --- /dev/null +++ b/src/pages/api/config.ts @@ -0,0 +1,15 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +const handler = async (req: NextApiRequest, res: NextApiResponse) => { + let publicEnvironmentVariables: any = {}; + Object.entries(process.env).forEach(([key, value]) => { + if (key.startsWith("PUBLIC")) { + key = key.replace("PUBLIC_", ""); + publicEnvironmentVariables[key] = value; + } + }); + res.setHeader("cache-control", "max-age=100"); + res.status(200).json(publicEnvironmentVariables); +}; + +export default handler; diff --git a/src/utils/appwrite.util.ts b/src/utils/appwrite.util.ts index b940db4..75e6082 100644 --- a/src/utils/appwrite.util.ts +++ b/src/utils/appwrite.util.ts @@ -3,7 +3,6 @@ import { Appwrite } from "appwrite"; // SDK for client side (browser) const aw = new Appwrite(); -aw.setEndpoint(process.env["NEXT_PUBLIC_APPWRITE_HOST"] as string) - .setProject("pingvin-share"); +aw.setProject("pingvin-share"); export default aw; diff --git a/src/utils/appwriteServer.util.ts b/src/utils/appwriteServer.util.ts index dfea00b..f879d0d 100644 --- a/src/utils/appwriteServer.util.ts +++ b/src/utils/appwriteServer.util.ts @@ -5,7 +5,7 @@ const client = new sdk.Client(); client .setEndpoint( - (process.env["NEXT_PUBLIC_APPWRITE_HOST"] as string).replace( + (process.env["PUBLIC_APPWRITE_HOST"] as string).replace( "localhost", process.env.NODE_ENV == "production" ? "host.docker.internal" diff --git a/src/utils/config.util.ts b/src/utils/config.util.ts new file mode 100644 index 0000000..b3c246d --- /dev/null +++ b/src/utils/config.util.ts @@ -0,0 +1,12 @@ +import axios from "axios"; +import { createContext, useContext } from "react"; + +export const ConfigContext = createContext({}); + +export const useConfig = () => useContext(ConfigContext); + +const getGonfig = async() => { + return (await axios.get("/api/config")).data; +}; + +export default { getGonfig };