Initial commit

This commit is contained in:
2025-08-01 22:04:00 +02:00
commit d1f466d1d4
155 changed files with 15995 additions and 0 deletions

42
app/Models/Award.php Normal file
View File

@@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
namespace App\Models;
use App\Models\Contracts\BelongsToUser;
use App\Models\Traits\UserScopedModel;
use Database\Factories\AwardFactory;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
final class Award extends Model implements BelongsToUser
{
/** @use HasFactory<AwardFactory> */
use HasFactory;
use HasUuids;
use UserScopedModel;
protected $fillable = [
'resume_id',
'title',
'awarded_at',
'awarder',
'summary',
];
/** @return BelongsTo<Resume, $this> */
public function resume(): BelongsTo
{
return $this->belongsTo(Resume::class);
}
protected function casts(): array
{
return [
'awarded_at' => 'date',
];
}
}

View File

@@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
namespace App\Models;
use App\Models\Contracts\BelongsToUser;
use App\Models\Traits\UserScopedModel;
use Database\Factories\CertificateFactory;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
final class Certificate extends Model implements BelongsToUser
{
/** @use HasFactory<CertificateFactory> */
use HasFactory;
use HasUuids;
use UserScopedModel;
protected $fillable = [
'resume_id',
'name',
'issued_at',
'issuer',
'url',
];
/** @return BelongsTo<Resume, $this> */
public function resume(): BelongsTo
{
return $this->belongsTo(Resume::class);
}
protected function casts(): array
{
return [
'issued_at' => 'date',
];
}
}

View File

@@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace App\Models\Contracts;
interface BelongsToUser
{
public function getUserColumnId(): string;
}

46
app/Models/Education.php Normal file
View File

@@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace App\Models;
use App\Models\Contracts\BelongsToUser;
use App\Models\Traits\UserScopedModel;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
final class Education extends Model implements BelongsToUser
{
use HasUuids;
use UserScopedModel;
protected $table = 'educations';
protected $fillable = [
'resume_id',
'institution',
'url',
'area',
'study_type',
'start_date',
'end_date',
'score',
'courses',
];
/** @return BelongsTo<Resume, $this> */
public function resume(): BelongsTo
{
return $this->belongsTo(Resume::class);
}
protected function casts(): array
{
return [
'start_date' => 'date',
'end_date' => 'date',
'courses' => 'array',
];
}
}

40
app/Models/Interest.php Normal file
View File

@@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace App\Models;
use App\Models\Contracts\BelongsToUser;
use App\Models\Traits\UserScopedModel;
use Database\Factories\InterestFactory;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
final class Interest extends Model implements BelongsToUser
{
/** @use HasFactory<InterestFactory> */
use HasFactory;
use HasUuids;
use UserScopedModel;
protected $fillable = [
'resume_id',
'name',
'keywords',
];
/** @return BelongsTo<Resume, $this> */
public function resume(): BelongsTo
{
return $this->belongsTo(Resume::class);
}
protected function casts(): array
{
return [
'keywords' => 'array',
];
}
}

33
app/Models/Language.php Normal file
View File

@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace App\Models;
use App\Models\Contracts\BelongsToUser;
use App\Models\Traits\UserScopedModel;
use Database\Factories\LanguageFactory;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
final class Language extends Model implements BelongsToUser
{
/** @use HasFactory<LanguageFactory> */
use HasFactory;
use HasUuids;
use UserScopedModel;
protected $fillable = [
'resume_id',
'name',
'fluency',
];
/** @return BelongsTo<Resume, $this> */
public function resume(): BelongsTo
{
return $this->belongsTo(Resume::class);
}
}

28
app/Models/Network.php Normal file
View File

@@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
namespace App\Models;
use Database\Factories\NetworkFactory;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
final class Network extends Model
{
/** @use HasFactory<NetworkFactory> */
use HasFactory;
use HasUuids;
protected $fillable = [
'name',
];
/** @return HasMany<Profile, $this> */
public function profiles(): HasMany
{
return $this->hasMany(Profile::class);
}
}

40
app/Models/Profile.php Normal file
View File

@@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace App\Models;
use App\Models\Contracts\BelongsToUser;
use App\Models\Traits\UserScopedModel;
use Database\Factories\ProfileFactory;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
final class Profile extends Model implements BelongsToUser
{
/** @use HasFactory<ProfileFactory> */
use HasFactory;
use HasUuids;
use UserScopedModel;
protected $fillable = [
'network_id',
'resume_id',
'username',
'url',
];
/** @return BelongsTo<Network, $this> */
public function network(): BelongsTo
{
return $this->belongsTo(Network::class);
}
/** @return BelongsTo<Resume, $this> */
public function resume(): BelongsTo
{
return $this->belongsTo(Resume::class);
}
}

46
app/Models/Project.php Normal file
View File

@@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace App\Models;
use App\Models\Contracts\BelongsToUser;
use App\Models\Traits\UserScopedModel;
use Database\Factories\ProjectFactory;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
final class Project extends Model implements BelongsToUser
{
/** @use HasFactory<ProjectFactory> */
use HasFactory;
use HasUuids;
use UserScopedModel;
protected $fillable = [
'resume_id',
'name',
'start_date',
'end_date',
'description',
'url',
'highlights',
];
/** @return BelongsTo<Resume, $this> */
public function resume(): BelongsTo
{
return $this->belongsTo(Resume::class);
}
protected function casts(): array
{
return [
'start_date' => 'date',
'end_date' => 'date',
'highlights' => 'array',
];
}
}

View File

@@ -0,0 +1,43 @@
<?php
declare(strict_types=1);
namespace App\Models;
use App\Models\Contracts\BelongsToUser;
use App\Models\Traits\UserScopedModel;
use Database\Factories\PublicationFactory;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
final class Publication extends Model implements BelongsToUser
{
/** @use HasFactory<PublicationFactory> */
use HasFactory;
use HasUuids;
use UserScopedModel;
protected $fillable = [
'resume_id',
'name',
'publisher',
'released_at',
'url',
'summary',
];
/** @return BelongsTo<Resume, $this> */
public function resume(): BelongsTo
{
return $this->belongsTo(Resume::class);
}
protected function casts(): array
{
return [
'released_at' => 'date',
];
}
}

33
app/Models/Reference.php Normal file
View File

@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace App\Models;
use App\Models\Contracts\BelongsToUser;
use App\Models\Traits\UserScopedModel;
use Database\Factories\ReferenceFactory;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
final class Reference extends Model implements BelongsToUser
{
/** @use HasFactory<ReferenceFactory> */
use HasFactory;
use HasUuids;
use UserScopedModel;
protected $fillable = [
'resume_id',
'name',
'reference',
];
/** @return BelongsTo<Resume, $this> */
public function resume(): BelongsTo
{
return $this->belongsTo(Resume::class);
}
}

119
app/Models/Resume.php Normal file
View File

@@ -0,0 +1,119 @@
<?php
declare(strict_types=1);
namespace App\Models;
use App\Models\Contracts\BelongsToUser;
use App\Models\Traits\UserScopedModel;
use Database\Factories\ResumeFactory;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
final class Resume extends Model implements BelongsToUser
{
/** @use HasFactory<ResumeFactory> */
use HasFactory;
use HasUuids;
use UserScopedModel;
protected $fillable = [
'user_id',
'name',
'label',
'email',
'phone',
'url',
'address',
'postal_code',
'city',
'country_code',
'region',
];
public function getUserColumnId(): string
{
return 'user_id';
}
/** @return BelongsTo<User, $this> */
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
/** @return HasMany<Profile, $this> */
public function profiles(): HasMany
{
return $this->hasMany(Profile::class);
}
/** @return HasMany<WorkExperience, $this> */
public function workExperiences(): HasMany
{
return $this->hasMany(WorkExperience::class);
}
/** @return HasMany<Language, $this> */
public function languages(): HasMany
{
return $this->hasMany(Language::class);
}
/** @return HasMany<Education, $this> */
public function educations(): HasMany
{
return $this->hasMany(Education::class);
}
/** @return HasMany<Skill, $this> */
public function skills(): HasMany
{
return $this->hasMany(Skill::class);
}
/** @return HasMany<VolunteerExperience, $this> */
public function volunteerExperiences(): HasMany
{
return $this->hasMany(VolunteerExperience::class);
}
/** @return HasMany<Interest, $this> */
public function interests(): HasMany
{
return $this->hasMany(Interest::class);
}
/** @return HasMany<Award, $this> */
public function awards(): HasMany
{
return $this->hasMany(Award::class);
}
/** @return HasMany<Certificate, $this> */
public function certificates(): HasMany
{
return $this->hasMany(Certificate::class);
}
/** @return HasMany<Publication, $this> */
public function publications(): HasMany
{
return $this->hasMany(Publication::class);
}
/** @return HasMany<Reference, $this> */
public function references(): HasMany
{
return $this->hasMany(Reference::class);
}
/** @return HasMany<Project, $this> */
public function projects(): HasMany
{
return $this->hasMany(Project::class);
}
}

View File

@@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace App\Models\Scopes;
use App\Models\Contracts\BelongsToUser;
use App\Models\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
use Webmozart\Assert\Assert;
class UserScope implements Scope
{
public function apply(Builder $builder, Model $model): void
{
if (
! $model instanceof BelongsToUser
|| ! Auth::check()
) {
return;
}
/** @var User $user */
$user = Auth::user();
Assert::notNull($user);
$userId = $user->getKey();
$userColumnPath = $model->getUserColumnId();
if (! Str::contains($userColumnPath, '.')) {
$builder->where($model->getTable().'.'.$userColumnPath, $userId);
return;
}
$relationPath = Str::beforeLast($userColumnPath, '.');
$column = Str::afterLast($userColumnPath, '.');
$builder->whereHas($relationPath, fn (Builder $query) => $query->where($column, $userId));
}
}

41
app/Models/Skill.php Normal file
View File

@@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
namespace App\Models;
use App\Models\Contracts\BelongsToUser;
use App\Models\Traits\UserScopedModel;
use Database\Factories\SkillFactory;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
final class Skill extends Model implements BelongsToUser
{
/** @use HasFactory<SkillFactory> */
use HasFactory;
use HasUuids;
use UserScopedModel;
protected $fillable = [
'resume_id',
'name',
'level',
'keywords',
];
/** @return BelongsTo<Resume, $this> */
public function resume(): BelongsTo
{
return $this->belongsTo(Resume::class);
}
protected function casts(): array
{
return [
'keywords' => 'array',
];
}
}

View File

@@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
namespace App\Models\Traits;
use App\Models\User;
use App\Services\UserScopeApplier;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;
use Webmozart\Assert\Assert;
trait UserScopedModel
{
public function getUserColumnId(): string
{
return 'resume.user_id';
}
protected static function bootUserScopedModel(): void
{
$scopeApplier = app(UserScopeApplier::class);
$scopeApplier->applyScope(new static());
if ((new static())->getUserColumnId() === 'user_id') {
static::creating(function (Model $model) {
/** @var User $user */
$user = Auth::user();
Assert::notNull($user);
$model->fill(['user_id' => $user->getKey()]);
});
}
}
}

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

@@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
namespace App\Models;
use Database\Factories\UserFactory;
use Filament\Models\Contracts\FilamentUser;
use Filament\Panel;
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 implements FilamentUser
{
/** @use HasFactory<UserFactory> */
use HasFactory;
use HasUuids;
use Notifiable;
/** @var list<string> */
protected $fillable = [
'name',
'email',
'password',
];
/** @var list<string> */
protected $hidden = [
'password',
'remember_token',
];
/** @return array<string, string> */
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
public function canAccessPanel(Panel $panel): bool
{
return true;
}
}

View File

@@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
namespace App\Models;
use App\Models\Contracts\BelongsToUser;
use App\Models\Traits\UserScopedModel;
use Database\Factories\VolunteerExperienceFactory;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
final class VolunteerExperience extends Model implements BelongsToUser
{
/** @use HasFactory<VolunteerExperienceFactory> */
use HasFactory;
use HasUuids;
use UserScopedModel;
protected $fillable = [
'resume_id',
'organization',
'position',
'url',
'start_date',
'end_date',
'summary',
'highlights',
];
/** @return BelongsTo<Resume, $this> */
public function resume(): BelongsTo
{
return $this->belongsTo(Resume::class);
}
protected function casts(): array
{
return [
'start_date' => 'date',
'end_date' => 'date',
'highlights' => 'array',
];
}
}

View File

@@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
namespace App\Models;
use App\Models\Contracts\BelongsToUser;
use App\Models\Traits\UserScopedModel;
use Database\Factories\WorkExperienceFactory;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
final class WorkExperience extends Model implements BelongsToUser
{
/** @use HasFactory<WorkExperienceFactory> */
use HasFactory;
use HasUuids;
use UserScopedModel;
protected $fillable = [
'resume_id',
'name',
'position',
'url',
'start_date',
'end_date',
'summary',
'highlights',
];
/** @return BelongsTo<Resume, $this> */
public function resume(): BelongsTo
{
return $this->belongsTo(Resume::class);
}
protected function casts(): array
{
return [
'start_date' => 'date',
'end_date' => 'date',
'highlights' => 'array',
];
}
}