phase 1 and 2

This commit is contained in:
Doar Mihai
2026-04-03 00:23:01 +03:00
parent 4976742c29
commit 9dcf3c36d7
33 changed files with 2563 additions and 5 deletions
+111
View File
@@ -0,0 +1,111 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\SoftDeletes;
class Job extends Model
{
use SoftDeletes;
protected $fillable = [
'external_id',
'title',
'company',
'description',
'location',
'salary_min',
'salary_max',
'salary_currency',
'job_type',
'job_source_id',
'source_url',
'apply_url',
'posted_at',
'expires_at',
'remote_allowed',
'experience_level',
'job_category_id',
'job_location_id',
'fingerprint',
];
protected $casts = [
'posted_at' => 'datetime',
'expires_at' => 'datetime',
'remote_allowed' => 'boolean',
'salary_min' => 'decimal:2',
'salary_max' => 'decimal:2',
];
/**
* Get the source that provides this job.
*/
public function source(): BelongsTo
{
return $this->belongsTo(JobSource::class, 'job_source_id');
}
/**
* Get the category that this job belongs to.
*/
public function category(): BelongsTo
{
return $this->belongsTo(JobCategory::class, 'job_category_id');
}
/**
* Get the location of this job.
*/
public function jobLocation(): BelongsTo
{
return $this->belongsTo(JobLocation::class, 'job_location_id');
}
/**
* Get the users who saved this job.
*/
public function savedByUsers(): BelongsToMany
{
return $this->belongsToMany(User::class, 'user_saved_jobs')
->withTimestamps();
}
/**
* Scope a query to only include active jobs.
*/
public function scopeActive($query)
{
return $query->where(function ($q) {
$q->whereNull('expires_at')
->orWhere('expires_at', '>', now());
});
}
/**
* Scope a query to only include remote jobs.
*/
public function scopeRemote($query)
{
return $query->where('remote_allowed', true);
}
/**
* Scope a query to filter by job type.
*/
public function scopeOfType($query, string $type)
{
return $query->where('job_type', $type);
}
/**
* Scope a query to filter by experience level.
*/
public function scopeExperienceLevel($query, string $level)
{
return $query->where('experience_level', $level);
}
}
+32
View File
@@ -0,0 +1,32 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class JobCategory extends Model
{
protected $fillable = [
'name',
'slug',
'description',
'icon',
];
/**
* Get the jobs for this category.
*/
public function jobs(): HasMany
{
return $this->hasMany(Job::class, 'job_category_id');
}
/**
* Get the job alerts for this category.
*/
public function jobAlerts(): HasMany
{
return $this->hasMany(UserJobAlert::class, 'job_category_id');
}
}
+45
View File
@@ -0,0 +1,45 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class JobLocation extends Model
{
protected $fillable = [
'city',
'state',
'country',
'country_code',
'latitude',
'longitude',
];
protected $casts = [
'latitude' => 'decimal:7',
'longitude' => 'decimal:7',
];
/**
* Get the jobs for this location.
*/
public function jobs(): HasMany
{
return $this->hasMany(Job::class, 'job_location_id');
}
/**
* Get the full location string.
*/
public function getFullLocationAttribute(): string
{
$parts = array_filter([
$this->city,
$this->state,
$this->country,
]);
return implode(', ', $parts);
}
}
+41
View File
@@ -0,0 +1,41 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class JobSource extends Model
{
protected $fillable = [
'name',
'api_url',
'api_key',
'is_active',
'rate_limit',
'last_fetched_at',
'configuration',
];
protected $casts = [
'is_active' => 'boolean',
'last_fetched_at' => 'datetime',
'configuration' => 'array',
];
/**
* Get the jobs from this source.
*/
public function jobs(): HasMany
{
return $this->hasMany(Job::class, 'job_source_id');
}
/**
* Scope a query to only include active sources.
*/
public function scopeActive($query)
{
return $query->where('is_active', true);
}
}
+19
View File
@@ -7,6 +7,8 @@ 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\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
@@ -29,4 +31,21 @@ class User extends Authenticatable
'password' => 'hashed',
];
}
/**
* Get the jobs saved by this user.
*/
public function savedJobs(): BelongsToMany
{
return $this->belongsToMany(Job::class, 'user_saved_jobs')
->withTimestamps();
}
/**
* Get the job alerts for this user.
*/
public function jobAlerts(): HasMany
{
return $this->hasMany(UserJobAlert::class);
}
}
+48
View File
@@ -0,0 +1,48 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class UserJobAlert extends Model
{
protected $fillable = [
'user_id',
'keywords',
'location',
'job_category_id',
'frequency',
'is_active',
'last_sent_at',
];
protected $casts = [
'is_active' => 'boolean',
'last_sent_at' => 'datetime',
];
/**
* Get the user who created the alert.
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
/**
* Get the category for this alert.
*/
public function category(): BelongsTo
{
return $this->belongsTo(JobCategory::class, 'job_category_id');
}
/**
* Scope a query to only include active alerts.
*/
public function scopeActive($query)
{
return $query->where('is_active', true);
}
}
+30
View File
@@ -0,0 +1,30 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class UserSavedJob extends Model
{
protected $fillable = [
'user_id',
'job_id',
];
/**
* Get the user who saved the job.
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
/**
* Get the saved job.
*/
public function job(): BelongsTo
{
return $this->belongsTo(Job::class);
}
}