Files
sam-api/app/Models/UserInvitation.php

178 lines
3.7 KiB
PHP
Raw Normal View History

<?php
namespace App\Models;
use App\Models\Members\User;
use App\Models\Permissions\Role;
use App\Models\Tenants\Tenant;
use App\Traits\Auditable;
use App\Traits\BelongsToTenant;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Str;
class UserInvitation extends Model
{
use Auditable, BelongsToTenant;
// 상태 상수
public const STATUS_PENDING = 'pending';
public const STATUS_ACCEPTED = 'accepted';
public const STATUS_EXPIRED = 'expired';
public const STATUS_CANCELLED = 'cancelled';
// 기본 만료 기간 (일)
public const DEFAULT_EXPIRES_DAYS = 7;
protected $fillable = [
'tenant_id',
'email',
'role_id',
'message',
'token',
'status',
'invited_by',
'expires_at',
'accepted_at',
];
protected $casts = [
'expires_at' => 'datetime',
'accepted_at' => 'datetime',
];
/**
* 테넌트 관계
*/
public function tenant(): BelongsTo
{
return $this->belongsTo(Tenant::class);
}
/**
* 역할 관계
*/
public function role(): BelongsTo
{
return $this->belongsTo(Role::class);
}
/**
* 초대한 사용자 관계
*/
public function inviter(): BelongsTo
{
return $this->belongsTo(User::class, 'invited_by');
}
/**
* 토큰 생성
*/
public static function generateToken(): string
{
return Str::random(64);
}
/**
* 만료 일시 계산
*/
public static function calculateExpiresAt(int $days = self::DEFAULT_EXPIRES_DAYS): \DateTime
{
return now()->addDays($days);
}
/**
* 만료 여부 확인
*/
public function isExpired(): bool
{
return $this->expires_at->isPast();
}
/**
* 수락 가능 여부 확인
*/
public function canAccept(): bool
{
return $this->status === self::STATUS_PENDING && ! $this->isExpired();
}
/**
* 취소 가능 여부 확인
*/
public function canCancel(): bool
{
return $this->status === self::STATUS_PENDING;
}
/**
* 초대 수락 처리
*/
public function markAsAccepted(): void
{
$this->status = self::STATUS_ACCEPTED;
$this->accepted_at = now();
$this->save();
}
/**
* 초대 만료 처리
*/
public function markAsExpired(): void
{
$this->status = self::STATUS_EXPIRED;
$this->save();
}
/**
* 초대 취소 처리
*/
public function markAsCancelled(): void
{
$this->status = self::STATUS_CANCELLED;
$this->save();
}
/**
* Scope: 대기 중인 초대만
*/
public function scopePending($query)
{
return $query->where('status', self::STATUS_PENDING);
}
/**
* Scope: 만료된 초대 (상태 업데이트 대상)
*/
public function scopeExpiredPending($query)
{
return $query->where('status', self::STATUS_PENDING)
->where('expires_at', '<', now());
}
/**
* Scope: 특정 이메일 초대
*/
public function scopeForEmail($query, string $email)
{
return $query->where('email', $email);
}
/**
* 상태 라벨 반환
*/
public function getStatusLabelAttribute(): string
{
return match ($this->status) {
self::STATUS_PENDING => '대기중',
self::STATUS_ACCEPTED => '수락됨',
self::STATUS_EXPIRED => '만료됨',
self::STATUS_CANCELLED => '취소됨',
default => $this->status,
};
}
}