diff --git a/.env.docker b/.env.docker index 55b4bb46..24925b69 100644 --- a/.env.docker +++ b/.env.docker @@ -12,7 +12,7 @@ FILESYSTEM_DRIVER=local BROADCAST_CONNECTION=log CACHE_STORE=redis QUEUE_CONNECTION=redis -SESSION_DRIVER=file +SESSION_DRIVER=redis SESSION_LIFETIME=120 MAIL_MAILER=log diff --git a/README.md b/README.md index 0c8de9f2..ca25af7b 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,31 @@ It takes 1 minute to try out the builder for free. You'll have high availability ## Installation +### Environment Setup + +Before you can run the application, you need to set up the environment variables. We have provided a script that will automate the process of creating your `.env` files from the provided examples. + +Follow these steps to set up your environment: + +1. Make sure you have `openssl` installed, as it is required by the setup script to generate secure keys. + +2. Run the setup script from the root of the project: + + ```bash + chmod +x ./scripts/setup-env.sh + ./scripts/setup-env.sh + ``` + + **If you are using Docker** and want to prepare a Docker-specific environment, run the script with the `--docker` flag: + + ```bash + ./scripts/setup-env.sh --docker + ``` + +3. After running the script, review the `.env` and `client/.env` files to ensure all settings are correct for your environment. + +Remember to never commit your `.env` files to version control. They should be kept private as they contain sensitive information. + ### Docker Installation 🐳 OpnForm can be easily set up using Docker. Pre-built images are available on Docker Hub, which is the recommended method for most users. @@ -78,6 +103,7 @@ OpnForm can be easily set up using Docker. Pre-built images are available on Doc #### Quick Start 1. Clone the repository: +<<<<<<< HEAD ``` git clone https://github.com/JhumanJ/OpnForm.git @@ -89,6 +115,18 @@ OpnForm can be easily set up using Docker. Pre-built images are available on Doc ``` cp .env.docker .env cp client/.env.docker client/.env +======= + + ``` + git clone https://github.com/JhumanJ/OpnForm.git + cd OpnForm + ``` + +2. Set up environment files by running the provided setup script. For detailed instructions, refer to the [Environment Setup](#environment-setup) section above: + + ```bash + ./scripts/setup-env.sh --docker +>>>>>>> 0a9400492674212cdabcd4821ee87483b28735e5 ``` 3. Start the application: @@ -114,7 +152,7 @@ OpnForm can be easily set up using Docker. Pre-built images are available on Doc docker-compose up -d ``` -### Initial Login +#### Initial Login After installation, use these credentials to access the admin panel: @@ -125,7 +163,7 @@ After installation, use these credentials to access the admin panel: Note: Public registration is disabled in the self-hosted version. Use the admin account to invite additional users. -### Building from Source +#### Building from Source For development or customization, you can build the Docker images locally: @@ -159,6 +197,14 @@ For development or customization, you can build the Docker images locally: This method allows you to make changes to the source code and rebuild the images as needed. +#### Clearing all resources + +To completely remove all Docker containers, networks, and volumes created by `docker-compose` and also remove all images used by these services, you can use the following command: + +```bash +docker-compose down -v --rmi all +``` + ### Using Laravel Valet This section explains how to get started locally with the project. It's most likely relevant if you're trying to work on the project. diff --git a/app/Integrations/Google/Sheets/SpreadsheetManager.php b/app/Integrations/Google/Sheets/SpreadsheetManager.php index 5c674ad8..77e73bce 100644 --- a/app/Integrations/Google/Sheets/SpreadsheetManager.php +++ b/app/Integrations/Google/Sheets/SpreadsheetManager.php @@ -129,7 +129,7 @@ class SpreadsheetManager public function buildRow(array $submissionData): array { - $formatter = (new FormSubmissionFormatter($this->integration->form, $submissionData))->outputStringsOnly(); + $formatter = (new FormSubmissionFormatter($this->integration->form, $submissionData))->useSignedUrlForFiles()->outputStringsOnly(); $fields = $formatter->getFieldsWithValue(); diff --git a/app/Service/Forms/FormSubmissionFormatter.php b/app/Service/Forms/FormSubmissionFormatter.php index a9a2465c..b2131770 100644 --- a/app/Service/Forms/FormSubmissionFormatter.php +++ b/app/Service/Forms/FormSubmissionFormatter.php @@ -145,7 +145,7 @@ class FormSubmissionFormatter } else { $returnArray[$field['name']] = $val; } - } elseif ($field['type'] == 'files') { + } elseif (in_array($field['type'], ['files', 'signature'])) { if ($this->outputStringsOnly) { $formId = $this->form->id; $returnArray[$field['name']] = implode( @@ -219,7 +219,7 @@ class FormSubmissionFormatter } else { $field['value'] = $val; } - } elseif ($field['type'] == 'files') { + } elseif (in_array($field['type'], ['files', 'signature'])) { if ($this->outputStringsOnly) { $formId = $this->form->id; $field['value'] = implode( diff --git a/client/.env.docker b/client/.env.docker index a8ad68f3..21938a89 100644 --- a/client/.env.docker +++ b/client/.env.docker @@ -1,7 +1,7 @@ NUXT_LOG_LEVEL= NUXT_PUBLIC_APP_URL=/ NUXT_PUBLIC_API_BASE=/api -NUXT_PRIVATE_API_BASE=http://localhost/api +NUXT_PRIVATE_API_BASE=http://ingress/api NUXT_PUBLIC_AI_FEATURES_ENABLED=false NUXT_PUBLIC_AMPLITUDE_CODE= NUXT_PUBLIC_CRISP_WEBSITE_ID= @@ -10,5 +10,4 @@ NUXT_PUBLIC_ENV=local NUXT_PUBLIC_GOOGLE_ANALYTICS_CODE= NUXT_PUBLIC_H_CAPTCHA_SITE_KEY= NUXT_PUBLIC_PAID_PLANS_ENABLED= -NUXT_PUBLIC_S3_ENABLED=false -NUXT_API_SECRET= +NUXT_PUBLIC_S3_ENABLED=false \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index d0e75c3d..d12906c5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,8 +10,6 @@ services: DB_USERNAME: ${DB_USERNAME:-forge} DB_PASSWORD: ${DB_PASSWORD:-forge} DB_CONNECTION: ${DB_CONNECTION:-pgsql} - LOG_LEVEL: ${LOG_LEVEL:-debug} - LOG_CHANNEL: ${LOG_CHANNEL:-errorlog} AWS_ENDPOINT: http://minio:9000 AWS_ACCESS_KEY_ID: ${MINIO_ACCESS_KEY:-minio} AWS_SECRET_ACCESS_KEY: ${MINIO_SECRET_KEY:-minio123} @@ -23,11 +21,13 @@ services: env_file: ./.env volumes: - laravel-persist:/persist - - secrets-config:/secrets + - ./storage/logs:/usr/share/nginx/html/storage/logs api-worker: <<: *api command: ./artisan queue:work + volumes: + - ./storage/logs:/usr/share/nginx/html/storage/logs ui: image: jhumanj/opnform-client:latest @@ -38,11 +38,8 @@ services: env_file: - ./client/.env volumes: - - secrets-config:/secrets - ./client/.env:/app/.env - - redis: image: redis:7 @@ -65,4 +62,3 @@ services: volumes: laravel-persist: postgres-data: - secrets-config: diff --git a/docker/Dockerfile.api b/docker/Dockerfile.api index 318caa45..35a65ffd 100644 --- a/docker/Dockerfile.api +++ b/docker/Dockerfile.api @@ -40,8 +40,6 @@ RUN chmod 777 -R storage RUN php artisan package:discover --ansi COPY docker/php-fpm-entrypoint /usr/local/bin/opnform-entrypoint -COPY docker/generate-api-secret.sh /usr/local/bin/ -RUN ln -s /secrets/api.env .env RUN chmod a+x /usr/local/bin/* diff --git a/docker/Dockerfile.client b/docker/Dockerfile.client index 97930e47..b8d68c9c 100644 --- a/docker/Dockerfile.client +++ b/docker/Dockerfile.client @@ -26,7 +26,6 @@ FROM node:20-alpine WORKDIR /app COPY --from=javascript-builder /app/.output/ /app/ RUN ls /app/ -RUN ln -s /secrets/client.env .env ADD ./docker/node-entrypoint /entrypoint.sh RUN chmod a+x /entrypoint.sh diff --git a/docker/generate-api-secret.sh b/docker/generate-api-secret.sh deleted file mode 100644 index 7ea95ed2..00000000 --- a/docker/generate-api-secret.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/bash -e - -main() { - generate_api_secrets -} - -generate_api_secrets() { - if ! is_configured; then - echo "Generating shared secret..." - SECRET="$(random_string)" - add_secret_to_env_file /secrets/client.env NUXT_API_SECRET "$SECRET" - add_secret_to_env_file /secrets/api.env FRONT_API_SECRET "$SECRET" - fi -} - -random_string() { - array=() - for i in {a..z} {A..Z} {0..9}; - do - array[$RANDOM]=$i - done - printf %s ${array[@]::8} $'\n' -} - -add_secret_to_env_file() { - FILE=$1 - TEMP_FILE=/tmp/env.$$ - VAR=$2 - VAL=$3 - - grep -q "^$VAR=" "$FILE" 2>/dev/null || ( echo "$VAR=" >> "$FILE" ) - - cp $FILE $TEMP_FILE - sed "s/^$VAR=.*$/$VAR=$VAL/" -i $TEMP_FILE - cat $TEMP_FILE > $FILE -} - -is_configured() { - grep -q "FRONT_API_SECRET=.\+" .env 2>/dev/null -} - -main diff --git a/docker/node-entrypoint b/docker/node-entrypoint index 7ce865c3..12eb9e0f 100644 --- a/docker/node-entrypoint +++ b/docker/node-entrypoint @@ -1,13 +1,9 @@ #!/bin/sh main() { - if [ "$1" == "bash" ]; then + if [ "$1" = "bash" ]; then "$@" else - wait_for_api_secret - if [ ! -f .env ] && [ -f /secrets/client.env ]; then - ln -sf /secrets/client.env .env - fi if [ -f .env ]; then . .env else @@ -16,15 +12,10 @@ main() { run_server "$@" fi } -wait_for_api_secret() { - until [ -f /secrets/configured ]; do - echo "Waiting for api secret..." - sleep 1 - done -} + run_server() { - echo "Running " node "$@" + echo "Running node $@" "$@" } -main "$@" +main "$@" \ No newline at end of file diff --git a/docker/php-fpm-entrypoint b/docker/php-fpm-entrypoint index aab78ee4..1ad0eaa9 100644 --- a/docker/php-fpm-entrypoint +++ b/docker/php-fpm-entrypoint @@ -1,61 +1,22 @@ #!/bin/bash main() { - read_env prep_file_permissions prep_storage - if is_master "$@"; then - prep_laravel_secrets - wait_for_db - apply_db_migrations - run_init_project - mark_ready - else - wait_for_ready - wait_for_db - fi - read_env + wait_for_db + apply_db_migrations + run_init_project run_server "$@" } + is_master() { echo "$@" | grep -q php-fpm } -read_env() { - #set +x - [ -f .env ] || touch .env - . .env - #set -x -} prep_file_permissions() { chmod a+x ./artisan } -prep_laravel_secrets() { - read_env - - [ "x$APP_KEY" != "x" ] || { - echo "Generating Laravel key..." - grep -q "APP_KEY=" .env || { - echo "APP_KEY=" >> .env - } - ./artisan key:generate - read_env - } - [ "x$JWT_SECRET" != "x" ] || { - echo "Generating Laravel Secret..." - ./artisan jwt:secret -f - read_env - } - - [ "x$FRONT_API_SECRET" != "x" ] || { - echo "Generating Shared Client Secret..." - /usr/local/bin/generate-api-secret.sh - read_env - } - echo "Done with secrets" -} - apply_db_migrations() { echo "Running DB Migrations" ./artisan migrate @@ -66,28 +27,15 @@ run_init_project() { ./artisan app:init-project } -wait_for_ready() { - echo "Checking keys have been generated" - until [ -f /secrets/configured ]; do - sleep 1; - echo "Waiting for keys to generate" - done -} - -mark_ready() { - touch /secrets/configured -} - wait_for_db() { + echo "Waiting for DB to be ready" until ./artisan migrate:status 2>&1 | grep -q -E "(Migration table not found|Migration name)"; do - echo "Waiting for DB to bootup" sleep 1 done } run_server() { - echo "Booting $@" - read_env + echo "Starting server $@" /usr/local/bin/docker-php-entrypoint "$@" } @@ -112,4 +60,4 @@ prep_storage() { ln -t . -sf /persist/storage } -main "$@" +main "$@" \ No newline at end of file diff --git a/scripts/setup-env.sh b/scripts/setup-env.sh new file mode 100755 index 00000000..8b92e0d9 --- /dev/null +++ b/scripts/setup-env.sh @@ -0,0 +1,88 @@ +#!/bin/bash + +set -e + +# Welcome to the OpnForm environment setup script! + +# Paths to the environment files +ENV_FILE=".env" +CLIENT_ENV_FILE="client/.env" + +# Paths to the environment templates +ENV_EXAMPLE=".env.example" +CLIENT_ENV_EXAMPLE="client/.env.example" + +# Check for the --docker flag to use Docker-specific environment settings +USE_DOCKER_ENV=false +for arg in "$@"; do + if [ "$arg" == "--docker" ]; then + USE_DOCKER_ENV=true + ENV_EXAMPLE=".env.docker" + CLIENT_ENV_EXAMPLE="client/.env.docker" + echo "OpnForm setup detected the --docker flag. Preparing Docker-specific environment..." + break + fi +done + +# Function to generate a random string for secrets +generate_secret() { + LC_ALL=C tr -dc A-Za-z0-9 > "$file" + fi +} + +# Check if the main .env file exists +if [ -f "$ENV_FILE" ]; then + echo "OpnForm's main .env file is already in place. No further action is needed." +else + echo "Creating OpnForm's main .env file from the template..." + cp "$ENV_EXAMPLE" "$ENV_FILE" + + # Secure your OpnForm instance with a unique APP_KEY + APP_KEY=$(generate_base64_key) + set_env_value "$ENV_FILE" "APP_KEY" "base64:$APP_KEY" + + # Generate a JWT_SECRET to sign your tokens + JWT_SECRET=$(generate_secret) + set_env_value "$ENV_FILE" "JWT_SECRET" "$JWT_SECRET" + + # Generate a shared secret for the client + SHARED_SECRET=$(generate_secret) + set_env_value "$ENV_FILE" "FRONT_API_SECRET" "$SHARED_SECRET" +fi + +# Check if the client .env file exists +if [ -f "$CLIENT_ENV_FILE" ]; then + echo "OpnForm's client .env file is already configured. Moving on..." +else + echo "Creating OpnForm's client .env file from the template..." + cp "$CLIENT_ENV_EXAMPLE" "$CLIENT_ENV_FILE" + set_env_value "$CLIENT_ENV_FILE" "NUXT_API_SECRET" "$SHARED_SECRET" +fi + +echo "✅ OpnForm environment setup is now complete. Enjoy building your forms!" \ No newline at end of file diff --git a/storage/logs/.gitignore b/storage/logs/.gitignore index d6b7ef32..c96a04f0 100644 --- a/storage/logs/.gitignore +++ b/storage/logs/.gitignore @@ -1,2 +1,2 @@ * -!.gitignore +!.gitignore \ No newline at end of file