diff --git a/Caddyfile b/Caddyfile new file mode 100644 index 0000000..067a8db --- /dev/null +++ b/Caddyfile @@ -0,0 +1,18 @@ +{ + # Enable the FrankenPHP module globally + frankenphp + # Disable the admin API to prevent host conflicts on Render + admin off +} + +# Listen on port 8080 (unprivileged port for Render) +:8080 { + root * /app/public + encode gzip + + # Enable the FrankenPHP server + php_server + + # Handle static files + file_server +} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 33ebb3e..f87b121 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,8 +4,9 @@ FROM dunglas/frankenphp:1.4-php8.4-alpine ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \ PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser \ COMPOSER_ALLOW_SUPERUSER=1 \ - SERVER_NAME=:80 \ - PUBLIC_ROOT=/app/public + SERVER_NAME=:8080 \ + PUBLIC_ROOT=/app/public \ + LOG_CHANNEL=stderr # Install system dependencies RUN apk add --no-cache \ @@ -25,7 +26,8 @@ RUN apk add --no-cache \ postgresql-dev \ git \ unzip \ - bash + bash \ + libcap # Install PHP extensions RUN docker-php-ext-configure gd --with-freetype --with-jpeg \ @@ -40,7 +42,9 @@ RUN docker-php-ext-configure gd --with-freetype --with-jpeg \ RUN apk add --no-cache --virtual .build-deps $PHPIZE_DEPS \ && pecl install redis \ && docker-php-ext-enable redis \ - && apk del .build-deps + && apk del .build-deps \ + && setcap -r /usr/local/bin/frankenphp \ + && apk del libcap # Set working directory WORKDIR /app @@ -75,7 +79,15 @@ RUN { \ echo 'opcache.enable_cli=1'; \ } > /usr/local/etc/php/conf.d/opcache-recommended.ini -# Expose port 80 -EXPOSE 80 +# Copy custom Caddyfile +COPY Caddyfile /etc/caddy/Caddyfile -# The entrypoint is already set to frankenphp in the base image +# Copy entrypoint script and set permissions +COPY entrypoint.sh /usr/local/bin/entrypoint.sh +RUN chmod +x /usr/local/bin/entrypoint.sh + +# Expose port 8080 +EXPOSE 8080 + +# Use the entrypoint script to run migrations and start the server +CMD ["/usr/local/bin/entrypoint.sh"] diff --git a/app/View/Components/AdminDashboard.php b/app/View/Components/AdminDashboard.php index c69f8af..5df31c7 100644 --- a/app/View/Components/AdminDashboard.php +++ b/app/View/Components/AdminDashboard.php @@ -40,16 +40,23 @@ public function __construct() $this->totalcarpoolVehicles = CarpoolVehicle::count('id'); // Request approval rate - $this->requestApprovalRate = number_format((TransportRequest::where('status', 'Approved')->count() / $this->totalTransportRequests) * 100, 2); + $total = $this->totalTransportRequests; + $this->requestApprovalRate = $total > 0 + ? number_format((TransportRequest::where('status', 'Approved')->count() / $total) * 100, 2) + : 0; // Peak request month - $this->peakRequestMonth = TransportRequest::selectRaw('EXTRACT(MONTH FROM event_date) as month, count(*) as requests') + $peak = TransportRequest::selectRaw('EXTRACT(MONTH FROM event_date) as month, count(*) as requests') ->groupBy('month') ->orderBy('requests', 'desc') ->first(); // Return the month name - $this->peakRequestMonth = date('F', mktime(0, 0, 0, $this->peakRequestMonth->month, 10)); + if ($peak && $peak->month) { + $this->peakRequestMonth = date('F', mktime(0, 0, 0, $peak->month, 10)); + } else { + $this->peakRequestMonth = 'N/A'; + } } /** diff --git a/bootstrap/app.php b/bootstrap/app.php index f8cd7be..ce89ddc 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -13,6 +13,7 @@ health: '/up', ) ->withMiddleware(function (Middleware $middleware) { + $middleware->trustProxies(at: '*'); $middleware->append([ \App\Http\Middleware\SecurityHeaders::class, \App\Http\Middleware\CheckIfActive::class, diff --git a/database/seeders/RolePermissionSeeder.php b/database/seeders/RolePermissionSeeder.php index e1d497d..e8691ab 100644 --- a/database/seeders/RolePermissionSeeder.php +++ b/database/seeders/RolePermissionSeeder.php @@ -6,6 +6,7 @@ use Illuminate\Database\Seeder; use Spatie\Permission\Models\Permission; use Spatie\Permission\Models\Role; +use Spatie\Permission\PermissionRegistrar; class RolePermissionSeeder extends Seeder { @@ -14,6 +15,9 @@ class RolePermissionSeeder extends Seeder */ public function run(): void { + // Reset cache + app(PermissionRegistrar::class)->forgetCachedPermissions(); + // Create permissions $permissions = [ 'view student dashboard', @@ -33,7 +37,7 @@ public function run(): void ]; foreach ($permissions as $permission) { - Permission::create(['name' => $permission]); + Permission::firstOrCreate(['name' => $permission]); } /* Create roles and assign permissions */ @@ -74,8 +78,10 @@ public function run(): void ]; foreach ($rolePermissions as $roleName => $permissions) { - $role = Role::create(['name' => $roleName]); - $role->givePermissionTo($permissions); + $role = Role::firstOrCreate(['name' => $roleName]); + + // Sync permissions + $role->syncPermissions($permissions); } diff --git a/database/seeders/UserSeeder.php b/database/seeders/UserSeeder.php index e035352..c8536cb 100644 --- a/database/seeders/UserSeeder.php +++ b/database/seeders/UserSeeder.php @@ -30,14 +30,16 @@ public function run(): void foreach ($users as $userData) { $password = Str::random(12); - $user = User::create([ - 'name' => $userData['name'], - 'email' => $userData['email'], - 'password' => bcrypt($password), - 'phone' => '+254712345678', - 'account_status' => 'active', - 'email_verified_at' => now(), - ]); + $user = User::firstOrCreate( + ['email' => $userData['email']], + [ + 'name' => $userData['name'], + 'password' => bcrypt($password), + 'phone' => '+254700000000', + 'account_status' => 'active', + 'email_verified_at' => now(), + ] + ); if ($userData['role']) { $user->assignRole($userData['role']); diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..9a0cd28 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -e + +# Run migrations automatically on startup +echo "[ENTRYPOINT] Running migrations..." +php artisan migrate --force + +# Run RolePermissionSeeder +echo "[ENTRYPOINT] Running RolePermissionSeeder..." +php artisan db:seed --class=RolePermissionSeeder --force + +# Run UserSeeder +echo "[ENTRYPOINT] Running UserSeeder..." +php artisan db:seed --class=UserSeeder --force + +# Execute the main container command (FrankenPHP) +echo "[ENTRYPOINT] Starting FrankenPHP..." +exec frankenphp run --config /etc/caddy/Caddyfile diff --git a/package-lock.json b/package-lock.json index ec1890e..e32ffd7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1295,9 +1295,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001695", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001695.tgz", - "integrity": "sha512-vHyLade6wTgI2u1ec3WQBxv+2BrTERV28UXQu9LO6lZ9pYeMk34vjXFLOxo1A4UBA8XTL4njRQZdno/yYaSmWw==", + "version": "1.0.30001788", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001788.tgz", + "integrity": "sha512-6q8HFp+lOQtcf7wBK+uEenxymVWkGKkjFpCvw5W25cmMwEDU45p1xQFBQv8JDlMMry7eNxyBaR+qxgmTUZkIRQ==", "dev": true, "funding": [ { diff --git a/resources/views/home.blade.php b/resources/views/home.blade.php index fe36fcd..8f60d62 100644 --- a/resources/views/home.blade.php +++ b/resources/views/home.blade.php @@ -26,7 +26,7 @@

StrathPort

+ class="max-w-2xl mb-6 font-light text-gray-800 dark:text-gray-500 lg:mb-8 md:text-lg lg:text-xl"> Sign up now to take a step towards a smoother, safer, journey!