From 5fbe2ed7e4c4474969685649c03eea1b396db935 Mon Sep 17 00:00:00 2001 From: Fame Date: Sun, 11 Aug 2024 04:34:01 +0200 Subject: [PATCH 01/14] Fursuit API implementation --- .../API/AuthenticationMiddleware.php | 27 ++++++++++++++++ app/Http/Resources/FursuitCollection.php | 17 ++++++++++ app/Http/Resources/FursuitResource.php | 31 +++++++++++++++++++ app/Models/User.php | 15 +-------- bootstrap/app.php | 1 + config/api.php | 17 ++++++++++ routes/api.php | 6 ++++ 7 files changed, 100 insertions(+), 14 deletions(-) create mode 100644 app/Http/Middleware/API/AuthenticationMiddleware.php create mode 100644 app/Http/Resources/FursuitCollection.php create mode 100644 app/Http/Resources/FursuitResource.php create mode 100644 config/api.php create mode 100644 routes/api.php diff --git a/app/Http/Middleware/API/AuthenticationMiddleware.php b/app/Http/Middleware/API/AuthenticationMiddleware.php new file mode 100644 index 0000000..09054e1 --- /dev/null +++ b/app/Http/Middleware/API/AuthenticationMiddleware.php @@ -0,0 +1,27 @@ +bearerToken() !== config("api.api_middleware_bearer_token") || config("api.api_middleware_bearer_token") === null) { + return response()->json([ + 'message' => 'Forbidden.' + ], 403); + } + + return $next($request); + } +} diff --git a/app/Http/Resources/FursuitCollection.php b/app/Http/Resources/FursuitCollection.php new file mode 100644 index 0000000..6963180 --- /dev/null +++ b/app/Http/Resources/FursuitCollection.php @@ -0,0 +1,17 @@ + $this->collection, + ]; + } +} diff --git a/app/Http/Resources/FursuitResource.php b/app/Http/Resources/FursuitResource.php new file mode 100644 index 0000000..8ca016a --- /dev/null +++ b/app/Http/Resources/FursuitResource.php @@ -0,0 +1,31 @@ + $this->id, + "reg_id" => (int) $this->user->attendee_id, + 'status' => $this->status, + 'name' => $this->name, + 'published' => $this->published, + 'catch_em_all' => $this->catch_em_all, + 'image_url' => $this->image_url, + 'badges_count' => $this->badges_count, + + "species" => $this->species->only(["id", "name", "type"]), + ]; + } +} diff --git a/app/Models/User.php b/app/Models/User.php index 6297e5b..1dbbc61 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -36,7 +36,6 @@ class User extends Authenticatable implements FilamentUser, Wallet, WalletFloat, * @var array */ protected $hidden = [ - 'password', 'remember_token', 'token', 'token_expires_at', @@ -50,21 +49,9 @@ class User extends Authenticatable implements FilamentUser, Wallet, WalletFloat, 'refresh_token_expires_at' => 'datetime', 'token' => 'encrypted', 'token_expires_at' => 'datetime', + 'attendee_id' => 'integer', ]; - /** - * Get the attributes that should be cast. - * - * @return array - */ - protected function casts(): array - { - return [ - 'email_verified_at' => 'datetime', - 'password' => 'hashed', - ]; - } - public function badges() { return $this->hasManyThrough(Badge::class, Fursuit::class); diff --git a/bootstrap/app.php b/bootstrap/app.php index e30d6cb..f2531e1 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -8,6 +8,7 @@ return Application::configure(basePath: dirname(__DIR__)) ->withRouting( web: __DIR__.'/../routes/web.php', + api: __DIR__.'/../routes/api.php', commands: __DIR__.'/../routes/console.php', health: '/up', ) diff --git a/config/api.php b/config/api.php new file mode 100644 index 0000000..ceda1d3 --- /dev/null +++ b/config/api.php @@ -0,0 +1,17 @@ + env('API_MIDDLEWARE_BEARER_TOKEN', null), +]; diff --git a/routes/api.php b/routes/api.php new file mode 100644 index 0000000..8dd9109 --- /dev/null +++ b/routes/api.php @@ -0,0 +1,6 @@ +middleware(AuthenticationMiddleware::class)->name('api.fursuits.index'); From ca1f2c6ea2adb4a6d602c0da9235cda04fae1afd Mon Sep 17 00:00:00 2001 From: Fame Date: Sun, 11 Aug 2024 04:56:45 +0200 Subject: [PATCH 02/14] Fursuit API implementation --- .../Controllers/API/FursuitController.php | 52 +++++++++++++++++++ .../Requests/API/FursuitSearchRequest.php | 25 +++++++++ database/seeders/BalentySeeder.php | 22 ++++++++ 3 files changed, 99 insertions(+) create mode 100644 app/Http/Controllers/API/FursuitController.php create mode 100644 app/Http/Requests/API/FursuitSearchRequest.php create mode 100644 database/seeders/BalentySeeder.php diff --git a/app/Http/Controllers/API/FursuitController.php b/app/Http/Controllers/API/FursuitController.php new file mode 100644 index 0000000..57d3bcf --- /dev/null +++ b/app/Http/Controllers/API/FursuitController.php @@ -0,0 +1,52 @@ +validated("reg_id"); + $name = $request->validated("name"); + $status = $request->validated("status") ?? Approved::$name; + + // start building Query + $query = Fursuit::query()->withCount("badges")->with("species")->with("user"); + + // Search for reg_id + if ($request->exists("reg_id")) + $query->whereHas("user", function(Builder $query) use ($regID) { + $query->where("attendee_id", "=", $regID); + }); + + // Search for Fursuit Name + if ($request->exists("name")) + $query->where("name", 'like', '%'.$name.'%'); + + // Search for status (approved by default) and not filtered when "any" + if ($status != 'any') + $query->where("status", '=', $status); + + // returns the results paginated and filteres by FursuitCollection + return new FursuitCollection($query->paginate($this->pageSize)); + } +} diff --git a/app/Http/Requests/API/FursuitSearchRequest.php b/app/Http/Requests/API/FursuitSearchRequest.php new file mode 100644 index 0000000..8723783 --- /dev/null +++ b/app/Http/Requests/API/FursuitSearchRequest.php @@ -0,0 +1,25 @@ + ['max:64', 'string', 'nullable'], + 'reg_id' => ['integer', 'nullable', 'exists:users,attendee_id'], + 'status' => ['string', 'nullable', Rule::in([Pending::$name, Approved::$name, Rejected::$name, 'any'])], + ]; + } +} diff --git a/database/seeders/BalentySeeder.php b/database/seeders/BalentySeeder.php new file mode 100644 index 0000000..c207345 --- /dev/null +++ b/database/seeders/BalentySeeder.php @@ -0,0 +1,22 @@ +recycle($event)->create(); + } +} From fcb3a7f72201a626af46e41b6c3b440ac95bd46d Mon Sep 17 00:00:00 2001 From: Balenty Date: Mon, 26 Aug 2024 05:24:24 +0200 Subject: [PATCH 03/14] Fursuit Catch Code generating + seeder --- .../Controllers/API/FursuitController.php | 2 +- app/Models/Fursuit/Fursuit.php | 12 +++++++ app/Models/Fursuit/FursuitCatchCode.php | 26 ++++++++++++++ config/app.php | 11 ++++++ database/seeders/FursuitCatchCodeSeeder.php | 35 +++++++++++++++++++ 5 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 app/Models/Fursuit/FursuitCatchCode.php create mode 100644 database/seeders/FursuitCatchCodeSeeder.php diff --git a/app/Http/Controllers/API/FursuitController.php b/app/Http/Controllers/API/FursuitController.php index 57d3bcf..ea3776b 100644 --- a/app/Http/Controllers/API/FursuitController.php +++ b/app/Http/Controllers/API/FursuitController.php @@ -46,7 +46,7 @@ public function index(FursuitSearchRequest $request) { if ($status != 'any') $query->where("status", '=', $status); - // returns the results paginated and filteres by FursuitCollection + // returns the results paginated and filtered by FursuitCollection return new FursuitCollection($query->paginate($this->pageSize)); } } diff --git a/app/Models/Fursuit/Fursuit.php b/app/Models/Fursuit/Fursuit.php index 5c2c790..b8d4680 100644 --- a/app/Models/Fursuit/Fursuit.php +++ b/app/Models/Fursuit/Fursuit.php @@ -112,4 +112,16 @@ public function isClaimedBySelf(User $user) { return (int) cache()->get($this->getClaimCacheKey()) == $user->id; } + + public static function booted() + { + static::saving(function (Fursuit $fursuit) { + // Only generate if required and not existing + if (!$fursuit->catch_em_all || $fursuit->catch_code <> null) + return; + + // Generate an unique Catch Code before saving the fursuit + $fursuit->catch_code = (new FursuitCatchCode(Fursuit::class, 'catch_code'))->generate(); + }); + } } diff --git a/app/Models/Fursuit/FursuitCatchCode.php b/app/Models/Fursuit/FursuitCatchCode.php new file mode 100644 index 0000000..3d061bf --- /dev/null +++ b/app/Models/Fursuit/FursuitCatchCode.php @@ -0,0 +1,26 @@ +model::where($this->column, $identifier)->exists()); + + return $identifier; + } +} diff --git a/config/app.php b/config/app.php index 5d36186..1804d61 100644 --- a/config/app.php +++ b/config/app.php @@ -123,4 +123,15 @@ 'store' => env('APP_MAINTENANCE_STORE', 'database'), ], + /* + |-------------------------------------------------------------------------- + | Fursuit Catch Code Length + |-------------------------------------------------------------------------- + | + | Length of characters and digits the code of fursuits for the catch em all feature + | Printed on the ordered fursuit badges + | + */ + + 'fursuit_catch_code_length' => env('FURSUIT_CATCH_CODE_LENGTH', 5), ]; diff --git a/database/seeders/FursuitCatchCodeSeeder.php b/database/seeders/FursuitCatchCodeSeeder.php new file mode 100644 index 0000000..fcac6a7 --- /dev/null +++ b/database/seeders/FursuitCatchCodeSeeder.php @@ -0,0 +1,35 @@ +update(['catch_code' => null]); + + // removing of codes of these who unregistered from the system + if ($purgeCodesOfNonParticipants) + Fursuit::where('catch_em_all', 0)->update(['catch_code' => null]); + + // Iterate and save manually to trigger Fursuit::saving() + foreach (Fursuit::all() as $fursuit) { + if (!$fursuit->catch_em_all || $fursuit->catch_code <> null) + continue; + + $fursuit->save(); + } + } +} From 0bf5a0536f1ae9a609485718fe63f54affcf67a6 Mon Sep 17 00:00:00 2001 From: Balenty Date: Mon, 26 Aug 2024 17:46:51 +0200 Subject: [PATCH 04/14] Fursuit Catch Code database migration --- ...6_151326_add_catch_code_to_fursuits_table.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 database/migrations/2024_08_26_151326_add_catch_code_to_fursuits_table.php diff --git a/database/migrations/2024_08_26_151326_add_catch_code_to_fursuits_table.php b/database/migrations/2024_08_26_151326_add_catch_code_to_fursuits_table.php new file mode 100644 index 0000000..88fe2ae --- /dev/null +++ b/database/migrations/2024_08_26_151326_add_catch_code_to_fursuits_table.php @@ -0,0 +1,16 @@ +after('catch_em_all', function (Blueprint $table) { + $table->string('catch_code', length: 255)->nullable()->unique(); + }); + }); + } +}; From c7c1981b1cd9237f4edfc5c1abd936a68d5ea5c8 Mon Sep 17 00:00:00 2001 From: Balenty Date: Wed, 28 Aug 2024 15:45:10 +0200 Subject: [PATCH 05/14] FCEA - Logging and User Ranking - Database Part --- .../Controllers/FCEA/DashboardController.php | 99 +++++++++++++++++++ app/Http/Requests/UserCatchRequest.php | 16 +++ app/Http/Resources/user_catch_logResource.php | 25 +++++ app/Models/FCEA/UserCatchLog.php | 40 ++++++++ app/Models/FCEA/UserFursuitCatch.php | 33 +++++++ .../FCEA/UserFursuitCatchesUserRanking.php | 17 ++++ app/Models/Fursuit/Fursuit.php | 6 ++ app/Models/Fursuit/FursuitCatchCode.php | 2 +- app/Models/User.php | 6 ++ app/Policies/UserCatchLogPolicy.php | 47 +++++++++ app/Rules/FursuitCatchCodeRule.php | 17 ++++ bootstrap/app.php | 4 + config/app.php | 12 --- config/fcea.php | 28 ++++++ .../FCEA/UserFursuitCatchFactory.php | 26 +++++ ...27_225952_create_user_catch_logs_table.php | 25 +++++ ...1438_create_user_fursuit_catches_table.php | 25 +++++ ...er_fursuit_catches_user_rankings_table.php | 24 +++++ database/seeders/BalentySeeder.php | 2 + database/seeders/FursuitCatchCodeSeeder.php | 4 +- resources/css/fcea.css | 24 +++++ resources/js/Pages/FCEA/Dashboard.vue | 94 ++++++++++++++++++ resources/js/Pages/POS/Dashboard.vue | 2 +- routes/fcea.php | 10 ++ 24 files changed, 573 insertions(+), 15 deletions(-) create mode 100644 app/Http/Controllers/FCEA/DashboardController.php create mode 100644 app/Http/Requests/UserCatchRequest.php create mode 100644 app/Http/Resources/user_catch_logResource.php create mode 100644 app/Models/FCEA/UserCatchLog.php create mode 100644 app/Models/FCEA/UserFursuitCatch.php create mode 100644 app/Models/FCEA/UserFursuitCatchesUserRanking.php create mode 100644 app/Policies/UserCatchLogPolicy.php create mode 100644 app/Rules/FursuitCatchCodeRule.php create mode 100644 config/fcea.php create mode 100644 database/factories/FCEA/UserFursuitCatchFactory.php create mode 100644 database/migrations/2024_08_27_225952_create_user_catch_logs_table.php create mode 100644 database/migrations/2024_08_28_021438_create_user_fursuit_catches_table.php create mode 100644 database/migrations/2024_08_28_050324_create_user_fursuit_catches_user_rankings_table.php create mode 100644 resources/css/fcea.css create mode 100644 resources/js/Pages/FCEA/Dashboard.vue create mode 100644 routes/fcea.php diff --git a/app/Http/Controllers/FCEA/DashboardController.php b/app/Http/Controllers/FCEA/DashboardController.php new file mode 100644 index 0000000..670b217 --- /dev/null +++ b/app/Http/Controllers/FCEA/DashboardController.php @@ -0,0 +1,99 @@ +validated("catch_code"); + $logEntry = new UserCatchLog(); + $logEntry->user_id = Auth::id(); + $logEntry->catch_code = $catch_code; + $logEntry->is_successful = false; + $logEntry->already_caught = false; + + if (!$logEntry->FursuitExist()) + { + $logEntry->save(); + return Inertia::render('FCEA/Dashboard'); + } + + $logEntry->already_caught = + UserFursuitCatch::where('user_id', Auth::id()) + ->where('fursuit_id', $logEntry->tryGetFursuit()->id) + ->exists(); // Entry exists + + if ($logEntry->already_caught) + { + $logEntry->save(); + return Inertia::render('FCEA/Dashboard'); + } + + $logEntry->is_successful = true; + $logEntry->save(); + + $UserFursuitCatchEntry = new UserFursuitCatch(); + $UserFursuitCatchEntry->user_id = Auth::id(); + $UserFursuitCatchEntry->fursuit_id = $logEntry->tryGetFursuit()->id; + $UserFursuitCatchEntry->save(); + $this->RefreshUserRanking(); + return Inertia::render('FCEA/Dashboard'); + } + + public function RefreshUserRanking() { + $catchersOrdered = User::query() + ->withCount("fursuitsCatched") + ->orderByDesc("fursuits_catched_count") + ->get(); + + // How many users do we have in totel (Users with 0 score are counted too) + $maxCount = $catchersOrdered->count(); + + // Save required informations for iteration + $current = array( + 'count' => 1, + 'rank' => 1, + 'score' => $catchersOrdered->first()->fursuits_catched_count + ); + + // Need to have stats of previous Rank + $previous = $current; + + // Clean Ranking + UserFursuitCatchesUserRanking::truncate(); + + // Iterate all users to build Ranking (players with same score have same ranking) + foreach ($catchersOrdered as $catcher) { + // Increase Rank when Score updates (players get same rank with same score) + if ($current['score'] > $catcher->fursuits_catched_count) { + $previous = $current; + $current['rank']++; + $current['score'] = $catcher->fursuits_catched_count; + } + + $rankingEntry = new UserFursuitCatchesUserRanking(); + $rankingEntry->user_id = $catcher->id; + $rankingEntry->rank = $current['rank']; + $rankingEntry->catches = $catcher->fursuits_catched_count; + $rankingEntry->catches_till_next = $previous['score'] - $current['score']; + $rankingEntry->users_behind = $maxCount - $previous['count']; + $rankingEntry->save(); + $current['count']++; + } + } +} diff --git a/app/Http/Requests/UserCatchRequest.php b/app/Http/Requests/UserCatchRequest.php new file mode 100644 index 0000000..23b327e --- /dev/null +++ b/app/Http/Requests/UserCatchRequest.php @@ -0,0 +1,16 @@ + ['required','string', 'min:'.config("fcea.fursuit_catch_code_length"), 'max:'.config("fcea.fursuit_catch_code_length"), new FursuitCatchCodeRule()] + ]; + } +} diff --git a/app/Http/Resources/user_catch_logResource.php b/app/Http/Resources/user_catch_logResource.php new file mode 100644 index 0000000..aaff0b4 --- /dev/null +++ b/app/Http/Resources/user_catch_logResource.php @@ -0,0 +1,25 @@ + $this->created_at, + 'updated_at' => $this->updated_at, + 'id' => $this->id, + 'catch_code' => $this->catch_code, + 'is_successful' => $this->is_successful, + 'already_caught' => $this->already_caught, + + 'user_id' => $this->user_id, + 'user_id' => $this->user_id, + ]; + } +} diff --git a/app/Models/FCEA/UserCatchLog.php b/app/Models/FCEA/UserCatchLog.php new file mode 100644 index 0000000..46ef07c --- /dev/null +++ b/app/Models/FCEA/UserCatchLog.php @@ -0,0 +1,40 @@ + 'boolean', + 'already_caught' => 'boolean', + ]; + + public function user() : BelongsTo + { + return $this->belongsTo(User::class); + } + + // Look if a Fursuit Exist with the given catch code - might be null + public function tryGetFursuit() : Fursuit|null + { + // If Fursuit not found yet ot catch_code not correct -> lookup Fursuit + if (!$this->fursuit || $this->fursuit->catch_code != $this->catch_code) + $this->fursuit = Fursuit::where("catch_code", $this->catch_code)->first();; + return $this->fursuit; + } + + // True means tryGetFursuit() will give an result. False means tryGetFursuit() will give null. + public function FursuitExist() : bool + { + return $this->TryGetFursuit() != null; + } +} diff --git a/app/Models/FCEA/UserFursuitCatch.php b/app/Models/FCEA/UserFursuitCatch.php new file mode 100644 index 0000000..5da0c99 --- /dev/null +++ b/app/Models/FCEA/UserFursuitCatch.php @@ -0,0 +1,33 @@ +belongsTo(User::class); + } + + public function fursuit(): BelongsTo + { + return $this->belongsTo(Fursuit::class); + } + + public function getActivitylogOptions(): LogOptions + { + return LogOptions::defaults() + ->logOnly(['user_id', 'fursuit_id']); + // Chain fluent methods for configuration options + } +} diff --git a/app/Models/FCEA/UserFursuitCatchesUserRanking.php b/app/Models/FCEA/UserFursuitCatchesUserRanking.php new file mode 100644 index 0000000..8d2f9d6 --- /dev/null +++ b/app/Models/FCEA/UserFursuitCatchesUserRanking.php @@ -0,0 +1,17 @@ +belongsTo(User::class); + } +} diff --git a/app/Models/Fursuit/Fursuit.php b/app/Models/Fursuit/Fursuit.php index b8d4680..29e3dfd 100644 --- a/app/Models/Fursuit/Fursuit.php +++ b/app/Models/Fursuit/Fursuit.php @@ -4,6 +4,7 @@ use App\Models\Badge\Badge; use App\Models\Event; +use App\Models\FCEA\UserFursuitCatch; use App\Models\Fursuit\States\FursuitStatusState; use App\Models\Species; use App\Models\User; @@ -113,6 +114,11 @@ public function isClaimedBySelf(User $user) return (int) cache()->get($this->getClaimCacheKey()) == $user->id; } + public function catchedByUsers() + { + return $this->hasMany(UserFursuitCatch::class); + } + public static function booted() { static::saving(function (Fursuit $fursuit) { diff --git a/app/Models/Fursuit/FursuitCatchCode.php b/app/Models/Fursuit/FursuitCatchCode.php index 3d061bf..57b6fca 100644 --- a/app/Models/Fursuit/FursuitCatchCode.php +++ b/app/Models/Fursuit/FursuitCatchCode.php @@ -14,7 +14,7 @@ public function generate(): string { do { $identifier = strtoupper(Str::password( - $length = config("app.fursuit_catch_code_length"), // by default 5 + $length = config("fcea.fursuit_catch_code_length"), // by default 5 $letters = true, $numbers = true, $symbols = false, diff --git a/app/Models/User.php b/app/Models/User.php index 1dbbc61..eacc24b 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -4,6 +4,7 @@ // use Illuminate\Contracts\Auth\MustVerifyEmail; use App\Models\Badge\Badge; +use App\Models\FCEA\UserFursuitCatch; use App\Models\Fursuit\Fursuit; use Bavix\Wallet\Interfaces\Customer; use Bavix\Wallet\Interfaces\Wallet; @@ -62,6 +63,11 @@ public function fursuits() return $this->hasMany(Fursuit::class); } + public function fursuitsCatched() + { + return $this->hasMany(UserFursuitCatch::class); + } + public function canAccessPanel(Panel $panel): bool { return $this->is_admin || $this->is_reviewer; diff --git a/app/Policies/UserCatchLogPolicy.php b/app/Policies/UserCatchLogPolicy.php new file mode 100644 index 0000000..67077ed --- /dev/null +++ b/app/Policies/UserCatchLogPolicy.php @@ -0,0 +1,47 @@ +is_admin; + } + + public function view(User $user, UserCatchLog $user_catch_log): bool + { + return $user->is_admin; + } + + public function create(User $user): bool + { + return false; + } + + public function update(User $user, UserCatchLog $user_catch_log): bool + { + return $user->is_admin; + } + + public function delete(User $user, UserCatchLog $user_catch_log): bool + { + return false; + } + + public function restore(User $user, UserCatchLog $user_catch_log): bool + { + return $user->is_admin; + } + + public function forceDelete(User $user, UserCatchLog $user_catch_log): bool + { + return $user->is_admin; + } +} diff --git a/app/Rules/FursuitCatchCodeRule.php b/app/Rules/FursuitCatchCodeRule.php new file mode 100644 index 0000000..e9a3abd --- /dev/null +++ b/app/Rules/FursuitCatchCodeRule.php @@ -0,0 +1,17 @@ +name('fcea.') + ->middleware('web') + ->group(base_path('routes/fcea.php')); \Illuminate\Support\Facades\Route::middleware(['auth:machine','auth:machine-user']) ->prefix('pos/') ->name('pos.') diff --git a/config/app.php b/config/app.php index 1804d61..e233b03 100644 --- a/config/app.php +++ b/config/app.php @@ -122,16 +122,4 @@ 'driver' => env('APP_MAINTENANCE_DRIVER', 'file'), 'store' => env('APP_MAINTENANCE_STORE', 'database'), ], - - /* - |-------------------------------------------------------------------------- - | Fursuit Catch Code Length - |-------------------------------------------------------------------------- - | - | Length of characters and digits the code of fursuits for the catch em all feature - | Printed on the ordered fursuit badges - | - */ - - 'fursuit_catch_code_length' => env('FURSUIT_CATCH_CODE_LENGTH', 5), ]; diff --git a/config/fcea.php b/config/fcea.php new file mode 100644 index 0000000..4439ca5 --- /dev/null +++ b/config/fcea.php @@ -0,0 +1,28 @@ + env('FURSUIT_CATCH_CODE_LENGTH', 5), + + /* + |-------------------------------------------------------------------------- + | Fursuit Catch Attempts per Minute + |-------------------------------------------------------------------------- + | + | Amount of times per 60 seconds a user can submit a Fursuit Catch Code + | in attempt to catch a fursuiter. Will respond "429 Too Many Requests" if triggered. + | Used to prevent bruteforcing attempts. + | + */ + + 'fursuit_catch_attempts_per_minute' => env('FURSUIT_CATCH_ATTEMPTS_PER_MINUTE', 20), +]; diff --git a/database/factories/FCEA/UserFursuitCatchFactory.php b/database/factories/FCEA/UserFursuitCatchFactory.php new file mode 100644 index 0000000..9b5c2cb --- /dev/null +++ b/database/factories/FCEA/UserFursuitCatchFactory.php @@ -0,0 +1,26 @@ + Carbon::now(), + 'updated_at' => Carbon::now(), + + 'user_id' => User::factory(), + 'fursuit_id' => Fursuit::factory(), + ]; + } +} diff --git a/database/migrations/2024_08_27_225952_create_user_catch_logs_table.php b/database/migrations/2024_08_27_225952_create_user_catch_logs_table.php new file mode 100644 index 0000000..010c9da --- /dev/null +++ b/database/migrations/2024_08_27_225952_create_user_catch_logs_table.php @@ -0,0 +1,25 @@ +id(); + $table->foreignIdFor(User::class)->constrained()->cascadeOnDelete(); + $table->string('catch_code', 255); + $table->boolean('is_successful'); + $table->boolean('already_caught'); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('user_catch_logs'); + } +}; diff --git a/database/migrations/2024_08_28_021438_create_user_fursuit_catches_table.php b/database/migrations/2024_08_28_021438_create_user_fursuit_catches_table.php new file mode 100644 index 0000000..af31b76 --- /dev/null +++ b/database/migrations/2024_08_28_021438_create_user_fursuit_catches_table.php @@ -0,0 +1,25 @@ +id(); + $table->foreignIdFor(User::class)->constrained()->cascadeOnDelete(); + $table->foreignIdFor(Fursuit::class)->constrained()->cascadeOnDelete(); + $table->timestamps(); + $table->unique(['user_id', 'fursuit_id']); + }); + } + + public function down(): void + { + Schema::dropIfExists('user_fursuit_catches'); + } +}; diff --git a/database/migrations/2024_08_28_050324_create_user_fursuit_catches_user_rankings_table.php b/database/migrations/2024_08_28_050324_create_user_fursuit_catches_user_rankings_table.php new file mode 100644 index 0000000..56d944e --- /dev/null +++ b/database/migrations/2024_08_28_050324_create_user_fursuit_catches_user_rankings_table.php @@ -0,0 +1,24 @@ +integer('rank'); + $table->foreignIdFor(User::class)->constrained()->cascadeOnDelete(); + $table->integer('catches'); + $table->integer('catches_till_next'); + $table->integer('users_behind'); + }); + } + + public function down(): void + { + Schema::dropIfExists('user_fursuit_catches_user_rankings'); + } +}; diff --git a/database/seeders/BalentySeeder.php b/database/seeders/BalentySeeder.php index c207345..521f0fa 100644 --- a/database/seeders/BalentySeeder.php +++ b/database/seeders/BalentySeeder.php @@ -4,6 +4,7 @@ use App\Models\Badge\Badge; use App\Models\Event; +use App\Models\FCEA\UserFursuitCatch; use Illuminate\Database\Console\Seeds\WithoutModelEvents; use Illuminate\Database\Seeder; use Illuminate\Support\Facades\Artisan; @@ -18,5 +19,6 @@ public function run(): void Artisan::call("event:state preorder"); $event = Event::first(); Badge::factory(30)->recycle($event)->create(); + UserFursuitCatch::factory(30)->recycle($event)->create(); } } diff --git a/database/seeders/FursuitCatchCodeSeeder.php b/database/seeders/FursuitCatchCodeSeeder.php index fcac6a7..81dcd61 100644 --- a/database/seeders/FursuitCatchCodeSeeder.php +++ b/database/seeders/FursuitCatchCodeSeeder.php @@ -2,8 +2,10 @@ namespace Database\Seeders; +use App\Models\Badge\Badge; +use App\Models\Event; +use App\Models\FCEA\UserFursuitCatch; use App\Models\Fursuit\Fursuit; -use App\Models\Fursuit\FursuitCatchCode; use Illuminate\Database\Seeder; class FursuitCatchCodeSeeder extends Seeder diff --git a/resources/css/fcea.css b/resources/css/fcea.css new file mode 100644 index 0000000..7bf31e3 --- /dev/null +++ b/resources/css/fcea.css @@ -0,0 +1,24 @@ +.card { + border: 1px solid #ccc; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); +} + +h3 { + font-family: 'Arial', sans-serif; + font-weight: bold; +} + +.card-header { + background-color: #f8f9fa; +} + +.list-group-item { + display: flex; + justify-content: space-between; + font-weight: bold; +} + +.text-center { + font-family: 'Arial', sans-serif; + margin-top: 10px; +} diff --git a/resources/js/Pages/FCEA/Dashboard.vue b/resources/js/Pages/FCEA/Dashboard.vue new file mode 100644 index 0000000..82760cf --- /dev/null +++ b/resources/js/Pages/FCEA/Dashboard.vue @@ -0,0 +1,94 @@ + + + + + + diff --git a/resources/js/Pages/POS/Dashboard.vue b/resources/js/Pages/POS/Dashboard.vue index 2abd47a..854117e 100644 --- a/resources/js/Pages/POS/Dashboard.vue +++ b/resources/js/Pages/POS/Dashboard.vue @@ -13,7 +13,7 @@ const buttons = [ { label: "Cash Register", route: '#', icon: 'pi pi-euro' }, { label: "Logout", route: '#', icon: 'pi pi-wallet' }, ]; -sd +