init commit

This commit is contained in:
unurled 2025-06-23 23:12:40 +02:00
commit c9d982669a
461 changed files with 30317 additions and 0 deletions

View file

@ -0,0 +1,66 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class BreakPeriod extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'competition_id',
'field_id',
'name',
'description',
'start_time',
'end_time',
'type',
'status',
'round',
'match_slot',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'start_time' => 'datetime',
'end_time' => 'datetime',
];
/**
* Get the competition that this break period belongs to.
*/
public function competition(): BelongsTo
{
return $this->belongsTo(Competition::class);
}
/**
* Get the field that this break period belongs to.
*/
public function field(): BelongsTo
{
return $this->belongsTo(Field::class);
}
/**
* Get the teams that are on break during this period.
*/
public function teams(): BelongsToMany
{
return $this->belongsToMany(Team::class)
->withTimestamps();
}
}

View file

@ -0,0 +1,90 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Competition extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
'description',
'start_date',
'end_date',
'status',
'location',
'max_teams',
'current_scheduling_mode_id',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'start_date' => 'date',
'end_date' => 'date',
];
/**
* Get the teams participating in the competition.
*/
public function teams(): BelongsToMany
{
return $this->belongsToMany(Team::class)
->withTimestamps()
->withPivot('status');
}
/**
* Get the scheduling modes available for this competition.
*/
public function schedulingModes(): HasMany
{
return $this->hasMany(SchedulingMode::class);
}
/**
* Get the current scheduling mode for this competition.
*/
public function currentSchedulingMode()
{
return $this->belongsTo(SchedulingMode::class, 'current_scheduling_mode_id');
}
/**
* Get the matches for this competition.
*/
public function matches(): HasMany
{
return $this->hasMany(MatchGame::class);
}
/**
* Get the break periods for this competition.
*/
public function breakPeriods(): HasMany
{
return $this->hasMany(BreakPeriod::class);
}
/**
* Get the fields used in this competition.
*/
public function fields(): BelongsToMany
{
return $this->belongsToMany(Field::class)
->withTimestamps();
}
}

64
app/Models/Field.php Normal file
View file

@ -0,0 +1,64 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Field extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
'location',
'description',
'status',
'capacity',
'surface_type',
'indoor',
'dimensions',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'indoor' => 'boolean',
'dimensions' => 'array',
];
/**
* Get the competitions that use this field.
*/
public function competitions(): BelongsToMany
{
return $this->belongsToMany(Competition::class)
->withTimestamps();
}
/**
* Get the matches scheduled on this field.
*/
public function matches(): HasMany
{
return $this->hasMany(MatchGame::class);
}
/**
* Get the break periods scheduled on this field.
*/
public function breakPeriods(): HasMany
{
return $this->hasMany(BreakPeriod::class);
}
}

105
app/Models/MatchGame.php Normal file
View file

@ -0,0 +1,105 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class MatchGame extends Model
{
use HasFactory;
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'matches';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'competition_id',
'scheduling_mode_id',
'home_team_id',
'away_team_id',
'field_id',
'start_time',
'end_time',
'home_team_score',
'away_team_score',
'status',
'round',
'group',
'match_number',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'start_time' => 'datetime',
'end_time' => 'datetime',
'home_team_score' => 'integer',
'away_team_score' => 'integer',
];
/**
* Get the competition that the match belongs to.
*/
public function competition(): BelongsTo
{
return $this->belongsTo(Competition::class);
}
/**
* Get the scheduling mode that this match is part of.
*/
public function schedulingMode(): BelongsTo
{
return $this->belongsTo(SchedulingMode::class);
}
/**
* Get the home team.
*/
public function homeTeam(): BelongsTo
{
return $this->belongsTo(Team::class, 'home_team_id');
}
/**
* Get the away team.
*/
public function awayTeam(): BelongsTo
{
return $this->belongsTo(Team::class, 'away_team_id');
}
/**
* Get the field where the match is played.
*/
public function field(): BelongsTo
{
return $this->belongsTo(Field::class);
}
/**
* Determine if this match is during a break period.
*
* @return bool
*/
public function hasBankPeriod()
{
return BreakPeriod::where('competition_id', $this->competition_id)
->where('start_time', '<=', $this->start_time)
->where('end_time', '>=', $this->end_time)
->exists();
}
}

42
app/Models/Permission.php Normal file
View file

@ -0,0 +1,42 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Permission extends Model
{
use HasFactory;
protected $fillable = [
'name',
'display_name',
'description',
'is_wildcard'
];
protected $casts = [
'is_wildcard' => 'boolean'
];
public function roles()
{
return $this->belongsToMany(Role::class)->withpivot('granted')->withTimestamps();
}
public function users()
{
return $this->belongsToMany(User::class)->withPivot('granted')->withTimestamps();
}
public function matches($permission)
{
if (!$this->is_wildcard) {
return $this->name === $permission;
}
$pattern = str_replace('*', '.*', $this->name);
return preg_match('/^' . $pattern . '$/', $permission);
}
}

47
app/Models/Role.php Normal file
View file

@ -0,0 +1,47 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Role extends Model
{
use HasFactory;
protected $fillable = [
'name',
'display_name',
'description'
];
public function permissions()
{
return $this->belongsToMany(Permission::class)->withPivot('granted')->withTimestamps();
}
public function users()
{
return $this->belongsToMany(User::class)->withTimestamps();
}
public function hasPermission($permission)
{
return $this->permissions->where('pivot.granted', true)->contains('name', $permission) ||
$this->hasWildcardPermission($permission);
}
private function hasWildcardPermission($permission)
{
$wildcardPermissions = $this->permissions->where('is_wildcard', true)->where('pivot.granted', true);
foreach ($wildcardPermissions as $wildcardPermission) {
$pattern = str_replace('*', '.*', $wildcardPermission->name);
if (preg_match('/^' . $pattern . '$/', $permission)) {
return true;
}
}
return false;
}
}

View file

@ -0,0 +1,128 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
class SchedulingMode extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'competition_id',
'name',
'description',
'algorithm',
'config',
'sequence_order',
'status',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'config' => 'array',
];
/**
* Get the competition that this scheduling mode belongs to.
*/
public function competition(): BelongsTo
{
return $this->belongsTo(Competition::class);
}
/**
* Get the matches associated with this scheduling mode.
*/
public function matches(): HasMany
{
return $this->hasMany(MatchGame::class);
}
/**
* Get competitions that are currently using this scheduling mode.
*/
public function activeCompetitions(): HasMany
{
return $this->hasMany(Competition::class, 'current_scheduling_mode_id');
}
/**
* Check if this is the current active scheduling mode for its competition.
*
* @return bool
*/
public function isActive(): bool
{
return $this->competition->current_scheduling_mode_id === $this->id;
}
/**
* Generate match schedule based on the algorithm defined.
*
* @return array
*/
public function generateSchedule(): array
{
// This would contain the logic to delegate to different scheduling algorithms
// based on the 'algorithm' field
switch ($this->algorithm) {
case 'round_robin':
return $this->generateRoundRobinSchedule();
case 'knockout':
return $this->generateKnockoutSchedule();
case 'group_stage':
return $this->generateGroupStageSchedule();
default:
return [];
}
}
/**
* Example implementation for round-robin scheduling.
*
* @return array
*/
private function generateRoundRobinSchedule(): array
{
// Implementation would go here
return [];
}
/**
* Example implementation for knockout scheduling.
*
* @return array
*/
private function generateKnockoutSchedule(): array
{
// Implementation would go here
return [];
}
/**
* Example implementation for group stage scheduling.
*
* @return array
*/
private function generateGroupStageSchedule(): array
{
// Implementation would go here
return [];
}
}

70
app/Models/Team.php Normal file
View file

@ -0,0 +1,70 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Team extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
'logo',
'nb_players',
'contact_email',
'contact_phone',
'status',
];
/**
* Get the competitions this team is participating in.
*/
public function competitions(): BelongsToMany
{
return $this->belongsToMany(Competition::class)
->withTimestamps()
->withPivot('status');
}
/**
* Get the matches where this team is the home team.
*/
public function homeMatches(): HasMany
{
return $this->hasMany(MatchGame::class, 'home_team_id');
}
/**
* Get the matches where this team is the away team.
*/
public function awayMatches(): HasMany
{
return $this->hasMany(MatchGame::class, 'away_team_id');
}
/**
* Get all matches for this team (both home and away).
*/
public function matches()
{
return $this->homeMatches->merge($this->awayMatches);
}
/**
* Get the break periods assigned to this team.
*/
public function breakPeriods(): BelongsToMany
{
return $this->belongsToMany(BreakPeriod::class)
->withTimestamps();
}
}

158
app/Models/User.php Normal file
View file

@ -0,0 +1,158 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
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, HasUuids;
/**
* The attributes that are mass assignable.
*
* @var list<string>
*/
protected $fillable = [
'name',
'email',
'avatar',
'oidc_id',
];
/**
* 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',
];
}
public function roles()
{
return $this->belongsToMany(Role::class)->withTimestamps();
}
public function permissions()
{
return $this->belongsToMany(Permission::class)->withPivot('granted')->withTimestamps();
}
public function hasRole($role)
{
if (is_string($role)) {
return $this->roles->contains('name', $role);
}
return $this->roles->contains($role);
}
public function hasAnyRole($roles)
{
if (is_array($roles)) {
return $this->roles->whereIn('name', $roles)->isNotEmpty();
}
return $this->hasRole($roles);
}
public function hasPermission($permission)
{
// Check direct permissions
if ($this->hasDirectPermission($permission)) {
return true;
}
// Check role-based permissions
return $this->hasRolePermission($permission);
}
private function hasDirectPermission($permission)
{
// Check exact match with granted
if ($this->permissions->where('pivot.granted', true)->contains('name', $permission)) {
return true;
}
// Check wildcard permissions with granted
$wildcardPermissions = $this->permissions->where('is_wildcard', true)->where('pivot.granted', true);
foreach ($wildcardPermissions as $wildcardPermission) {
if ($wildcardPermission->matches($permission)) {
return true;
}
}
return false;
}
private function hasRolePermission($permission)
{
foreach ($this->roles as $role) {
if ($role->hasPermission($permission)) {
return true;
}
}
return false;
}
public function assignRole($role)
{
if (is_string($role)) {
$role = Role::where('name', $role)->firstOrFail();
}
$this->roles()->syncWithoutDetaching([$role->id]);
return $this;
}
public function removeRole($role)
{
if (is_string($role)) {
$role = Role::where('name', $role)->firstOrFail();
}
$this->roles()->detach($role->id);
return $this;
}
public function givePermission($permission)
{
if (is_string($permission)) {
$permission = Permission::where('name', $permission)->firstOrFail();
}
$this->permissions()->syncWithoutDetaching([$permission->id => ['granted' => true]]);
return $this;
}
public function revokePermission($permission)
{
if (is_string($permission)) {
$permission = Permission::where('name', $permission)->firstOrFail();
}
$this->permissions()->updateExistingPivot($permission->id, ['granted' => false]);
return $this;
}
}