Initial Laravel setup

This commit is contained in:
joeplikestocode
2026-02-17 23:30:56 +01:00
commit 09b2b988f7
88 changed files with 15450 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
<?php
namespace App\Actions\Fortify;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Laravel\Fortify\Contracts\CreatesNewUsers;
class CreateNewUser implements CreatesNewUsers
{
use PasswordValidationRules;
/**
* Validate and create a newly registered user.
*
* @param array<string, string> $input
*/
public function create(array $input): User
{
Validator::make($input, [
'name' => ['required', 'string', 'max:255'],
'email' => [
'required',
'string',
'email',
'max:255',
Rule::unique(User::class),
],
'password' => $this->passwordRules(),
])->validate();
return User::create([
'name' => $input['name'],
'email' => $input['email'],
'password' => Hash::make($input['password']),
]);
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace App\Actions\Fortify;
use Illuminate\Validation\Rules\Password;
trait PasswordValidationRules
{
/**
* Get the validation rules used to validate passwords.
*
* @return array<int, \Illuminate\Contracts\Validation\Rule|array<mixed>|string>
*/
protected function passwordRules(): array
{
return ['required', 'string', Password::default(), 'confirmed'];
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace App\Actions\Fortify;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Laravel\Fortify\Contracts\ResetsUserPasswords;
class ResetUserPassword implements ResetsUserPasswords
{
use PasswordValidationRules;
/**
* Validate and reset the user's forgotten password.
*
* @param array<string, string> $input
*/
public function reset(User $user, array $input): void
{
Validator::make($input, [
'password' => $this->passwordRules(),
])->validate();
$user->forceFill([
'password' => Hash::make($input['password']),
])->save();
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Actions\Fortify;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Laravel\Fortify\Contracts\UpdatesUserPasswords;
class UpdateUserPassword implements UpdatesUserPasswords
{
use PasswordValidationRules;
/**
* Validate and update the user's password.
*
* @param array<string, string> $input
*/
public function update(User $user, array $input): void
{
Validator::make($input, [
'current_password' => ['required', 'string', 'current_password:web'],
'password' => $this->passwordRules(),
], [
'current_password.current_password' => __('The provided password does not match your current password.'),
])->validateWithBag('updatePassword');
$user->forceFill([
'password' => Hash::make($input['password']),
])->save();
}
}

View File

@@ -0,0 +1,58 @@
<?php
namespace App\Actions\Fortify;
use App\Models\User;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Laravel\Fortify\Contracts\UpdatesUserProfileInformation;
class UpdateUserProfileInformation implements UpdatesUserProfileInformation
{
/**
* Validate and update the given user's profile information.
*
* @param array<string, string> $input
*/
public function update(User $user, array $input): void
{
Validator::make($input, [
'name' => ['required', 'string', 'max:255'],
'email' => [
'required',
'string',
'email',
'max:255',
Rule::unique('users')->ignore($user->id),
],
])->validateWithBag('updateProfileInformation');
if ($input['email'] !== $user->email &&
$user instanceof MustVerifyEmail) {
$this->updateVerifiedUser($user, $input);
} else {
$user->forceFill([
'name' => $input['name'],
'email' => $input['email'],
])->save();
}
}
/**
* Update the given verified user's profile information.
*
* @param array<string, string> $input
*/
protected function updateVerifiedUser(User $user, array $input): void
{
$user->forceFill([
'name' => $input['name'],
'email' => $input['email'],
'email_verified_at' => null,
])->save();
$user->sendEmailVerificationNotification();
}
}

View File

@@ -0,0 +1,83 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use WorkOS\UserManagement;
use WorkOS\WorkOS;
class WorkosController extends Controller
{
private function bootWorkOS(): void
{
WorkOS::setApiKey(config('services.workos.api_key'));
WorkOS::setClientId(config('services.workos.client_id'));
}
public function redirect(Request $request): RedirectResponse
{
$this->bootWorkOS();
$userManagement = new UserManagement();
$redirectUri = route('workos.callback');
$state = [
'return_to' => url('/'),
];
$authorizationUrl = $userManagement->getAuthorizationUrl(
$redirectUri,
$state,
UserManagement::AUTHORIZATION_PROVIDER_GOOGLE_OAUTH
);
return redirect()->away($authorizationUrl);
}
public function callback(Request $request): RedirectResponse
{
$this->bootWorkOS();
$code = (string) $request->query('code');
if ($code === '') {
abort(400, 'Missing code');
}
$userManagement = new UserManagement();
$auth = $userManagement->authenticateWithCode(
config('services.workos.client_id'),
$code,
$request->ip(),
$request->userAgent()
);
$workosUser = $auth->user;
$name = trim(($workosUser->firstName ?? '') . ' ' . ($workosUser->lastName ?? ''));
if ($name === '') {
$name = $workosUser->email;
}
$user = User::updateOrCreate(
['email' => $workosUser->email],
[
'name' => $name,
'workos_user_id' => $workosUser->id,
]
);
Auth::login($user, true);
$stateRaw = $request->query('state');
$state = is_string($stateRaw) ? json_decode($stateRaw, true) : null;
$returnTo = is_array($state) && isset($state['return_to']) ? $state['return_to'] : url('/');
return redirect()->to($returnTo);
}
}

View File

@@ -0,0 +1,8 @@
<?php
namespace App\Http\Controllers;
abstract class Controller
{
//
}

10
app/Models/Category.php Normal file
View File

@@ -0,0 +1,10 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
//
}

10
app/Models/Crew.php Normal file
View File

@@ -0,0 +1,10 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Crew extends Model
{
//
}

10
app/Models/CrewMember.php Normal file
View File

@@ -0,0 +1,10 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class CrewMember extends Model
{
//
}

10
app/Models/CrewPatch.php Normal file
View File

@@ -0,0 +1,10 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class CrewPatch extends Model
{
//
}

View File

@@ -0,0 +1,10 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class CrewPatchCompletion extends Model
{
//
}

View File

@@ -0,0 +1,10 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class CrewPatchCompletionReaction extends Model
{
//
}

10
app/Models/Image.php Normal file
View File

@@ -0,0 +1,10 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Image extends Model
{
//
}

10
app/Models/Patch.php Normal file
View File

@@ -0,0 +1,10 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Patch extends Model
{
//
}

48
app/Models/User.php Normal file
View File

@@ -0,0 +1,48 @@
<?php
namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
/** @use HasFactory<\Database\Factories\UserFactory> */
use HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var list<string>
*/
protected $fillable = [
'name',
'email',
'password',
];
/**
* The attributes that should be hidden for serialization.
*
* @var list<string>
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
//
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
//
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace App\Providers;
use App\Actions\Fortify\CreateNewUser;
use App\Actions\Fortify\ResetUserPassword;
use App\Actions\Fortify\UpdateUserPassword;
use App\Actions\Fortify\UpdateUserProfileInformation;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Str;
use Laravel\Fortify\Actions\RedirectIfTwoFactorAuthenticatable;
use Laravel\Fortify\Fortify;
class FortifyServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
//
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Fortify::createUsersUsing(CreateNewUser::class);
Fortify::updateUserProfileInformationUsing(UpdateUserProfileInformation::class);
Fortify::updateUserPasswordsUsing(UpdateUserPassword::class);
Fortify::resetUserPasswordsUsing(ResetUserPassword::class);
Fortify::redirectUserForTwoFactorAuthenticationUsing(RedirectIfTwoFactorAuthenticatable::class);
RateLimiter::for('login', function (Request $request) {
$throttleKey = Str::transliterate(Str::lower($request->input(Fortify::username())).'|'.$request->ip());
return Limit::perMinute(5)->by($throttleKey);
});
RateLimiter::for('two-factor', function (Request $request) {
return Limit::perMinute(5)->by($request->session()->get('login.id'));
});
}
}