diff --git a/.gitea/workflows/build-and-deploy.yml b/.gitea/workflows/build-and-deploy.yml index a450e43..8dfa671 100644 --- a/.gitea/workflows/build-and-deploy.yml +++ b/.gitea/workflows/build-and-deploy.yml @@ -11,10 +11,8 @@ concurrency: env: NODE_VERSION: "20" - # Gitea built-in container registry (HTTPS on port 443) REGISTRY_HOST: 192.168.3.80 DOCKERFILE_PATH: Dockerfile.production - # VPS deployment target DEPLOY_ROOT: /opt/rentaldrivego jobs: @@ -26,8 +24,6 @@ jobs: docker_image: ${{ steps.image-meta.outputs.full }} steps: - uses: actions/checkout@v4 - env: - GIT_SSL_NO_VERIFY: "true" - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 @@ -35,7 +31,6 @@ jobs: - name: Docker image metadata id: image-meta run: | - # Gitea container registry path: host/owner/repo REPO="${{ gitea.repository }}" TAG="${{ gitea.sha }}" echo "repository=${REPO}" >> "$GITHUB_OUTPUT" @@ -45,25 +40,48 @@ jobs: - name: Check Docker registry credentials id: registry-check run: | - if [ -n "${{ secrets.REGISTRY_TOKEN }}" ]; then + if [ -n "${{ secrets.REGISTRY_USERNAME }}" ] && [ -n "${{ secrets.REGISTRY_PASSWORD }}" ]; then echo "available=true" >> "$GITHUB_OUTPUT" else + echo "::warning::REGISTRY_USERNAME or REGISTRY_PASSWORD secrets not set — push will be skipped" echo "available=false" >> "$GITHUB_OUTPUT" fi - - name: Install Docker CLI - if: steps.registry-check.outputs.available == 'true' + - name: Validate public URLs + shell: bash + env: + NEXT_PUBLIC_API_URL: ${{ secrets.NEXT_PUBLIC_API_URL }} + NEXT_PUBLIC_MARKETPLACE_URL: ${{ secrets.NEXT_PUBLIC_MARKETPLACE_URL }} + NEXT_PUBLIC_DASHBOARD_URL: ${{ secrets.NEXT_PUBLIC_DASHBOARD_URL }} + NEXT_PUBLIC_ADMIN_URL: ${{ secrets.NEXT_PUBLIC_ADMIN_URL }} run: | - apt-get update -qq - apt-get install -y -qq docker.io + for variable in \ + NEXT_PUBLIC_API_URL \ + NEXT_PUBLIC_MARKETPLACE_URL \ + NEXT_PUBLIC_DASHBOARD_URL \ + NEXT_PUBLIC_ADMIN_URL + do + value="${!variable}" + if [ -z "$value" ]; then + echo "::error::$variable is missing — add it to Gitea Actions secrets" + exit 1 + fi + case "$value" in + http://*|https://*) ;; + *) + echo "::error::$variable must be an absolute URL (got: $value)" + exit 1 + ;; + esac + done - name: Log in to Gitea Container Registry if: steps.registry-check.outputs.available == 'true' - run: | - echo "${{ secrets.REGISTRY_TOKEN }}" | \ - docker login "$REGISTRY_HOST" \ - -u "${{ gitea.actor }}" \ - --password-stdin + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY_HOST }} + username: ${{ secrets.REGISTRY_USERNAME }} + password: ${{ secrets.REGISTRY_PASSWORD }} - name: Build and push uses: docker/build-push-action@v6 @@ -92,8 +110,6 @@ jobs: IMAGE_REPOSITORY: ${{ needs.build-image.outputs.image_repository }} steps: - uses: actions/checkout@v4 - env: - GIT_SSL_NO_VERIFY: "true" - name: Check deploy credentials id: check-creds @@ -143,14 +159,14 @@ jobs: - name: Run deploy script on VPS if: steps.check-creds.outputs.skip == 'false' run: | - REGISTRY_PASSWORD_B64="$(printf '%s' "${{ secrets.REGISTRY_TOKEN }}" | base64 | tr -d '\n')" + REGISTRY_PASSWORD_B64="$(printf '%s' "${{ secrets.REGISTRY_PASSWORD }}" | base64 | tr -d '\n')" ssh "${{ secrets.VPS_USER }}@${{ secrets.VPS_IP }}" " set -e cd '$DEPLOY_ROOT' APP_IMAGE='$IMAGE_REPOSITORY' \ APP_VERSION='${{ gitea.sha }}' \ REGISTRY_HOST='$REGISTRY_HOST' \ - REGISTRY_USER='${{ gitea.actor }}' \ + REGISTRY_USER='${{ secrets.REGISTRY_USERNAME }}' \ REGISTRY_PASSWORD=\$(printf '%s' '$REGISTRY_PASSWORD_B64' | base64 -d) \ bash scripts/docker-prod-deploy.sh " diff --git a/Dockerfile.production b/Dockerfile.production index fa3a9c9..2eae5b3 100644 --- a/Dockerfile.production +++ b/Dockerfile.production @@ -28,7 +28,7 @@ ENV API_INTERNAL_URL=$API_INTERNAL_URL \ NEXT_PUBLIC_DASHBOARD_URL=$NEXT_PUBLIC_DASHBOARD_URL \ NEXT_PUBLIC_ADMIN_URL=$NEXT_PUBLIC_ADMIN_URL -RUN npm install +RUN npm ci RUN npm run db:generate RUN npm run build diff --git a/apps/api/src/modules/auth/auth.account.service.ts b/apps/api/src/modules/auth/auth.account.service.ts index 58f339d..831524d 100644 --- a/apps/api/src/modules/auth/auth.account.service.ts +++ b/apps/api/src/modules/auth/auth.account.service.ts @@ -97,23 +97,26 @@ export async function startAccount(body: AccountStartInput) { ) const verifyUrl = `${dashboardUrl}/verify-email?token=${encodeURIComponent(verificationToken)}` - const emailSubjects: Record = { + const emailSubjects: Record<'en' | 'fr' | 'ar', string> = { en: 'Verify your email — RentalDriveGo', fr: 'Vérifiez votre email — RentalDriveGo', ar: 'تحقق من بريدك الإلكتروني — RentalDriveGo', } - const emailBodies: Record = { + const emailBodies: Record<'en' | 'fr' | 'ar', string> = { en: `

Welcome to RentalDriveGo!

Click the link below to verify your email and activate your account:

Verify Email

If you did not create this account, you can safely ignore this email.

`, fr: `

Bienvenue sur RentalDriveGo !

Cliquez sur le lien ci-dessous pour vérifier votre email et activer votre compte :

Vérifier l'email

Si vous n'avez pas créé ce compte, ignorez cet email.

`, ar: `

مرحباً بك في RentalDriveGo!

انقر على الرابط أدناه للتحقق من بريدك الإلكتروني وتفعيل حسابك:

تحقق من البريد الإلكتروني

إذا لم تقم بإنشاء هذا الحساب، يمكنك تجاهل هذا البريد الإلكتروني.

`, } - const emailTexts: Record = { + const emailTexts: Record<'en' | 'fr' | 'ar', string> = { en: `Welcome to RentalDriveGo!\n\nVerify your email by visiting:\n${verifyUrl}\n\nIf you did not create this account, you can safely ignore this email.`, fr: `Bienvenue sur RentalDriveGo !\n\nVérifiez votre email en visitant :\n${verifyUrl}\n\nSi vous n'avez pas créé ce compte, ignorez cet email.`, ar: `مرحباً بك في RentalDriveGo!\n\nتحقق من بريدك الإلكتروني بزيارة:\n${verifyUrl}\n\nإذا لم تقم بإنشاء هذا الحساب، يمكنك تجاهل هذا البريد الإلكتروني.`, } - const lang = (body.preferredLanguage === 'ar' || body.preferredLanguage === 'fr') ? body.preferredLanguage : 'en' + const lang: 'en' | 'fr' | 'ar' = + body.preferredLanguage === 'ar' || body.preferredLanguage === 'fr' + ? body.preferredLanguage + : 'en' await sendTransactionalEmail({ to: body.email, diff --git a/apps/api/src/modules/auth/auth.employee.service.ts b/apps/api/src/modules/auth/auth.employee.service.ts index c4f22e9..40200d4 100644 --- a/apps/api/src/modules/auth/auth.employee.service.ts +++ b/apps/api/src/modules/auth/auth.employee.service.ts @@ -211,8 +211,12 @@ export async function resendVerification(email: string) { ) const verifyUrl = `${dashboardUrl}/verify-email?token=${encodeURIComponent(verificationToken)}` - const lang = (employee.preferredLanguage === 'ar' || employee.preferredLanguage === 'fr') ? employee.preferredLanguage : 'en' - const emailSubjects: Record = { + const lang: 'en' | 'fr' | 'ar' = + employee.preferredLanguage === 'ar' || employee.preferredLanguage === 'fr' + ? employee.preferredLanguage + : 'en' + + const emailSubjects: Record<'en' | 'fr' | 'ar', string> = { en: 'Verify your email — RentalDriveGo', fr: 'Vérifiez votre email — RentalDriveGo', ar: 'تحقق من بريدك الإلكتروني — RentalDriveGo',