ajoute le portail Laravel : connexion prof/élève, session unique, gestion de classe, salle d'attente

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Adam Belkacemi 2026-10-08 02:01:58 +02:00
parent aa31b6112f
commit 30e14b1c54
191 changed files with 25324 additions and 0 deletions

View file

@ -0,0 +1,61 @@
<?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;
use Illuminate\Support\Str;
class Classe extends Model
{
use HasFactory;
protected $fillable = ['etablissement_id', 'user_id', 'nom', 'formation', 'code_classe'];
protected $casts = [
'archivee_a' => 'datetime',
];
protected static function booted(): void
{
static::creating(function (Classe $classe) {
$classe->code_classe ??= static::genererCodeUnique();
});
}
public static function genererCodeUnique(): string
{
do {
$code = Str::upper(Str::random(6));
} while (static::where('code_classe', $code)->exists());
return $code;
}
public function etablissement(): BelongsTo
{
return $this->belongsTo(Etablissement::class);
}
public function prof(): BelongsTo
{
return $this->belongsTo(User::class, 'user_id');
}
public function eleves(): HasMany
{
return $this->hasMany(Eleve::class);
}
public function seances(): HasMany
{
return $this->hasMany(Seance::class);
}
public function estArchivee(): bool
{
return $this->archivee_a !== null;
}
}

View file

@ -0,0 +1,31 @@
<?php
namespace App\Models\Concerns;
use Illuminate\Support\Str;
/**
* Une seule session active par compte (étape 8) : la précédente est coupée
* et son porteur en est averti à sa prochaine requête (voir
* App\Http\Middleware\VerifieSessionUnique).
*/
trait GereSessionUnique
{
public function demarreNouvelleSession(): string
{
$jeton = Str::random(40);
$this->forceFill(['jeton_session_actif' => $jeton])->save();
return $jeton;
}
public function sessionEstEncoreValide(?string $jeton): bool
{
return $jeton !== null && $jeton === $this->jeton_session_actif;
}
public function terminerSession(): void
{
$this->forceFill(['jeton_session_actif' => null])->save();
}
}

View file

@ -0,0 +1,46 @@
<?php
namespace App\Models;
use App\Models\Concerns\GereSessionUnique;
use Illuminate\Auth\Authenticatable;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Eleve extends Model implements AuthenticatableContract
{
use Authenticatable, GereSessionUnique, HasFactory;
protected $fillable = ['classe_id', 'prenom', 'nom', 'identifiant', 'code_secret', 'jeton_qr'];
protected $hidden = ['code_secret', 'jeton_session_actif', 'jeton_qr'];
protected $casts = [
'derniere_connexion_a' => 'datetime',
];
public function getAuthPasswordName(): string
{
return 'code_secret';
}
public function classe(): BelongsTo
{
return $this->belongsTo(Classe::class);
}
public function labSessions(): HasMany
{
return $this->hasMany(LabSession::class);
}
public function nomAffiche(): string
{
return $this->nom
? $this->prenom.' '.mb_substr($this->nom, 0, 1).'.'
: $this->prenom;
}
}

View file

@ -0,0 +1,24 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Etablissement extends Model
{
use HasFactory;
protected $fillable = ['nom', 'ville', 'uai'];
public function profs(): HasMany
{
return $this->hasMany(User::class);
}
public function classes(): HasMany
{
return $this->hasMany(Classe::class);
}
}

View file

@ -0,0 +1,19 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Lab extends Model
{
use HasFactory;
protected $fillable = ['identifiant', 'titre', 'niveau', 'duree_min'];
public function seances(): HasMany
{
return $this->hasMany(Seance::class);
}
}

View file

@ -0,0 +1,43 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class LabSession extends Model
{
use HasFactory;
public const EN_ATTENTE = 'en_attente';
public const ADMIS = 'admis';
public const ACTIF = 'actif';
public const TERMINE = 'termine';
public const EXPIRE = 'expire';
protected $fillable = ['seance_id', 'eleve_id', 'lab_id', 'stack_id', 'etat', 'expire_a'];
protected $casts = [
'expire_a' => 'datetime',
];
public function seance(): BelongsTo
{
return $this->belongsTo(Seance::class);
}
public function eleve(): BelongsTo
{
return $this->belongsTo(Eleve::class);
}
public function lab(): BelongsTo
{
return $this->belongsTo(Lab::class);
}
}

View file

@ -0,0 +1,43 @@
<?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 Seance extends Model
{
use HasFactory;
public const PLANIFIEE = 'planifiee';
public const SALLE_ATTENTE = 'salle_attente';
public const EN_COURS = 'en_cours';
public const TERMINEE = 'terminee';
protected $fillable = ['classe_id', 'lab_id', 'statut', 'demarree_a', 'terminee_a'];
protected $casts = [
'demarree_a' => 'datetime',
'terminee_a' => 'datetime',
];
public function classe(): BelongsTo
{
return $this->belongsTo(Classe::class);
}
public function lab(): BelongsTo
{
return $this->belongsTo(Lab::class);
}
public function labSessions(): HasMany
{
return $this->hasMany(LabSession::class);
}
}

View file

@ -0,0 +1,45 @@
<?php
namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use App\Models\Concerns\GereSessionUnique;
use Database\Factories\UserFactory;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Attributes\Hidden;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
#[Fillable(['name', 'email', 'password', 'etablissement_id'])]
#[Hidden(['password', 'remember_token', 'jeton_session_actif'])]
class User extends Authenticatable
{
/** @use HasFactory<UserFactory> */
use GereSessionUnique, HasFactory, Notifiable;
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
public function etablissement(): BelongsTo
{
return $this->belongsTo(Etablissement::class);
}
public function classes(): HasMany
{
return $this->hasMany(Classe::class);
}
}