Move remaining project metadata ownership to templates

This commit is contained in:
2026-09-08 10:25:52 +00:00
committed by Twyco
parent 04b0d5e316
commit db8855a056
26 changed files with 473 additions and 45 deletions
+10 -1
View File
@@ -2,6 +2,7 @@
namespace App\Models;
use App\Models\Concerns\SyncsProjectTemplateOwnership;
use Database\Factories\BoardColumnFactory;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
@@ -10,11 +11,19 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
#[Fillable(['name', 'position', 'project_id'])]
#[Fillable(['name', 'position', 'project_id', 'project_template_id'])]
class BoardColumn extends Model
{
/** @use HasFactory<BoardColumnFactory> */
use HasFactory;
use SyncsProjectTemplateOwnership;
protected static function booted(): void
{
static::saving(function (self $boardColumn): void {
$boardColumn->syncProjectTemplateOwnership();
});
}
public function project(): BelongsTo
{
@@ -0,0 +1,41 @@
<?php
namespace App\Models\Concerns;
use App\Models\Project;
use App\Models\ProjectTemplate;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
trait SyncsProjectTemplateOwnership
{
protected function syncProjectTemplateOwnership(): void
{
$projectTemplateId = $this->getAttribute('project_template_id');
$projectId = $this->getAttribute('project_id');
if ($projectTemplateId === null && $projectId !== null) {
$projectTemplateId = Project::query()
->whereKey($projectId)
->value('project_template_id');
if ($projectTemplateId !== null) {
$this->setAttribute('project_template_id', $projectTemplateId);
}
}
if ($projectId === null && $projectTemplateId !== null) {
$projectId = ProjectTemplate::query()
->whereKey($projectTemplateId)
->value('project_id');
if ($projectId !== null) {
$this->setAttribute('project_id', $projectId);
}
}
}
public function projectTemplate(): BelongsTo
{
return $this->belongsTo(ProjectTemplate::class);
}
}
+10
View File
@@ -4,6 +4,7 @@ namespace App\Models;
use App\Enums\NotificationChannel;
use App\Enums\NotificationEventType;
use App\Models\Concerns\SyncsProjectTemplateOwnership;
use Database\Factories\NotificationActionFactory;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Attributes\Hidden;
@@ -23,12 +24,14 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
'message_template',
'name',
'project_id',
'project_template_id',
])]
#[Hidden(['delivery_url'])]
class NotificationAction extends Model
{
/** @use HasFactory<NotificationActionFactory> */
use HasFactory;
use SyncsProjectTemplateOwnership;
/**
* @return array<string, string>
@@ -45,6 +48,13 @@ class NotificationAction extends Model
];
}
protected static function booted(): void
{
static::saving(function (self $notificationAction): void {
$notificationAction->syncProjectTemplateOwnership();
});
}
public function scopeEnabled(Builder $query): Builder
{
return $query->where('enabled', true);
+40 -8
View File
@@ -59,51 +59,83 @@ class Project extends Model
public function boardColumns(): HasMany
{
return $this->hasMany(BoardColumn::class)
return $this->hasMany(
BoardColumn::class,
$this->project_template_id === null ? 'project_id' : 'project_template_id',
$this->project_template_id === null ? 'id' : 'project_template_id',
)
->orderBy('position');
}
public function ticketFieldDefinitions(): HasMany
{
return $this->hasMany(TicketFieldDefinition::class)
return $this->hasMany(
TicketFieldDefinition::class,
$this->project_template_id === null ? 'project_id' : 'project_template_id',
$this->project_template_id === null ? 'id' : 'project_template_id',
)
->orderBy('position');
}
public function ticketPriorities(): HasMany
{
return $this->hasMany(TicketPriority::class)
return $this->hasMany(
TicketPriority::class,
$this->project_template_id === null ? 'project_id' : 'project_template_id',
$this->project_template_id === null ? 'id' : 'project_template_id',
)
->orderBy('position');
}
public function ticketLinkTypes(): HasMany
{
return $this->hasMany(TicketLinkType::class)
return $this->hasMany(
TicketLinkType::class,
$this->project_template_id === null ? 'project_id' : 'project_template_id',
$this->project_template_id === null ? 'id' : 'project_template_id',
)
->orderBy('position');
}
public function ticketStatuses(): HasMany
{
return $this->hasMany(TicketStatus::class)
return $this->hasMany(
TicketStatus::class,
$this->project_template_id === null ? 'project_id' : 'project_template_id',
$this->project_template_id === null ? 'id' : 'project_template_id',
)
->orderBy('board_column_id')
->orderBy('position');
}
public function ticketTypes(): HasMany
{
return $this->hasMany(TicketType::class)
return $this->hasMany(
TicketType::class,
$this->project_template_id === null ? 'project_id' : 'project_template_id',
$this->project_template_id === null ? 'id' : 'project_template_id',
)
->orderBy('position');
}
public function repositoryConnections(): HasMany
{
return $this->hasMany(RepositoryConnection::class)
return $this->hasMany(
RepositoryConnection::class,
$this->project_template_id === null ? 'project_id' : 'project_template_id',
$this->project_template_id === null ? 'id' : 'project_template_id',
)
->orderBy('provider')
->orderBy('repository_full_name');
}
public function notificationActions(): HasMany
{
return $this->hasMany(NotificationAction::class)
return $this->hasMany(
NotificationAction::class,
$this->project_template_id === null ? 'project_id' : 'project_template_id',
$this->project_template_id === null ? 'id' : 'project_template_id',
)
->orderBy('name')
->orderBy('id');
}
+10
View File
@@ -4,6 +4,7 @@ namespace App\Models;
use App\Actions\Git\Data\GitRepository;
use App\Actions\Git\GitProviderKey;
use App\Models\Concerns\SyncsProjectTemplateOwnership;
use Database\Factories\RepositoryConnectionFactory;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
@@ -14,6 +15,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
'base_url',
'owner_name',
'project_id',
'project_template_id',
'provider',
'provider_repository_id',
'repository_full_name',
@@ -24,6 +26,7 @@ class RepositoryConnection extends Model
{
/** @use HasFactory<RepositoryConnectionFactory> */
use HasFactory;
use SyncsProjectTemplateOwnership;
/**
* @return array<string, string>
@@ -35,6 +38,13 @@ class RepositoryConnection extends Model
];
}
protected static function booted(): void
{
static::saving(function (self $repositoryConnection): void {
$repositoryConnection->syncProjectTemplateOwnership();
});
}
public function project(): BelongsTo
{
return $this->belongsTo(Project::class);
+10 -1
View File
@@ -2,6 +2,7 @@
namespace App\Models;
use App\Models\Concerns\SyncsProjectTemplateOwnership;
use Database\Factories\TicketFieldDefinitionFactory;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
@@ -9,7 +10,7 @@ use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
#[Fillable(['field_type', 'label', 'position', 'project_id'])]
#[Fillable(['field_type', 'label', 'position', 'project_id', 'project_template_id'])]
class TicketFieldDefinition extends Model
{
/**
@@ -22,6 +23,14 @@ class TicketFieldDefinition extends Model
/** @use HasFactory<TicketFieldDefinitionFactory> */
use HasFactory;
use SyncsProjectTemplateOwnership;
protected static function booted(): void
{
static::saving(function (self $ticketFieldDefinition): void {
$ticketFieldDefinition->syncProjectTemplateOwnership();
});
}
public function project(): BelongsTo
{
+10 -1
View File
@@ -2,6 +2,7 @@
namespace App\Models;
use App\Models\Concerns\SyncsProjectTemplateOwnership;
use Database\Factories\TicketLinkTypeFactory;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
@@ -9,11 +10,19 @@ use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
#[Fillable(['label', 'counterpart_label', 'position', 'project_id'])]
#[Fillable(['label', 'counterpart_label', 'position', 'project_id', 'project_template_id'])]
class TicketLinkType extends Model
{
/** @use HasFactory<TicketLinkTypeFactory> */
use HasFactory;
use SyncsProjectTemplateOwnership;
protected static function booted(): void
{
static::saving(function (self $ticketLinkType): void {
$ticketLinkType->syncProjectTemplateOwnership();
});
}
public function counterpartLabel(): string
{
+10 -1
View File
@@ -2,17 +2,26 @@
namespace App\Models;
use App\Models\Concerns\SyncsProjectTemplateOwnership;
use Database\Factories\TicketPriorityFactory;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
#[Fillable(['name', 'position', 'project_id'])]
#[Fillable(['name', 'position', 'project_id', 'project_template_id'])]
class TicketPriority extends Model
{
/** @use HasFactory<TicketPriorityFactory> */
use HasFactory;
use SyncsProjectTemplateOwnership;
protected static function booted(): void
{
static::saving(function (self $ticketPriority): void {
$ticketPriority->syncProjectTemplateOwnership();
});
}
public function project(): BelongsTo
{
+10 -1
View File
@@ -2,6 +2,7 @@
namespace App\Models;
use App\Models\Concerns\SyncsProjectTemplateOwnership;
use Database\Factories\TicketStatusFactory;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
@@ -11,15 +12,23 @@ use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Str;
#[Fillable(['board_column_id', 'name', 'position', 'project_id', 'slug'])]
#[Fillable(['board_column_id', 'name', 'position', 'project_id', 'project_template_id', 'slug'])]
class TicketStatus extends Model
{
/** @use HasFactory<TicketStatusFactory> */
use HasFactory;
use SyncsProjectTemplateOwnership;
protected static function booted(): void
{
static::saving(function (self $ticketStatus): void {
if ($ticketStatus->project_template_id === null && $ticketStatus->board_column_id !== null) {
$ticketStatus->project_template_id = BoardColumn::query()
->whereKey($ticketStatus->board_column_id)
->value('project_template_id');
}
$ticketStatus->syncProjectTemplateOwnership();
$ticketStatus->slug = Str::slug($ticketStatus->name);
});
}
+10 -1
View File
@@ -2,6 +2,7 @@
namespace App\Models;
use App\Models\Concerns\SyncsProjectTemplateOwnership;
use Database\Factories\TicketTypeFactory;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
@@ -9,11 +10,19 @@ use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
#[Fillable(['name', 'position', 'project_id', 'is_parent'])]
#[Fillable(['name', 'position', 'project_id', 'project_template_id', 'is_parent'])]
class TicketType extends Model
{
/** @use HasFactory<TicketTypeFactory> */
use HasFactory;
use SyncsProjectTemplateOwnership;
protected static function booted(): void
{
static::saving(function (self $ticketType): void {
$ticketType->syncProjectTemplateOwnership();
});
}
protected function casts(): array
{