164 lines
6.4 KiB
PHP
164 lines
6.4 KiB
PHP
<?php
|
|
|
|
namespace App\Events;
|
|
|
|
use App\Enums\Role;
|
|
use App\Models\Project;
|
|
use App\Models\Task;
|
|
use App\Models\TaskComment;
|
|
use App\Models\TimeInterval;
|
|
use App\Models\User;
|
|
use App\Reports\DashboardExport;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Broadcasting\Channel;
|
|
use Illuminate\Broadcasting\InteractsWithSockets;
|
|
use Illuminate\Broadcasting\PrivateChannel;
|
|
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
|
use Illuminate\Contracts\Events\ShouldDispatchAfterCommit;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
|
use Illuminate\Foundation\Events\Dispatchable;
|
|
use Illuminate\Queue\SerializesModels;
|
|
use Settings;
|
|
use Staudenmeir\LaravelAdjacencyList\Eloquent\Builder as AdjacencyListBuilder;
|
|
|
|
class ChangeEvent implements ShouldBroadcast, ShouldDispatchAfterCommit
|
|
{
|
|
use Dispatchable, InteractsWithSockets, SerializesModels;
|
|
|
|
/** @param Task|Project|TimeInterval $model */
|
|
public function __construct(
|
|
protected string $entityType,
|
|
protected string $action,
|
|
protected $model,
|
|
protected int $userId
|
|
) {
|
|
}
|
|
|
|
public function broadcastAs(): string
|
|
{
|
|
return sprintf('%s.%s', $this->entityType, $this->action);
|
|
}
|
|
|
|
public function broadcastWith(): array
|
|
{
|
|
// TODO: [ ] optimize loaded changes - payload too big
|
|
$model = match (true) {
|
|
$this->model instanceof Project && $this->entityType === 'gantt' => $this
|
|
->model
|
|
->setPermissionsUser(User::query()->find($this->userId))
|
|
->load([
|
|
'tasks' => fn(HasMany $queue) => $queue
|
|
->orderBy('start_date')
|
|
->select([
|
|
'id',
|
|
'task_name',
|
|
'priority_id',
|
|
'status_id',
|
|
'estimate',
|
|
'start_date',
|
|
'due_date',
|
|
'project_phase_id',
|
|
'project_id'
|
|
])->with(['status', 'priority'])
|
|
->withSum(['workers as total_spent_time'], 'duration')
|
|
->withSum(['workers as total_offset'], 'offset')
|
|
->withCasts(['start_date' => 'string', 'due_date' => 'string'])
|
|
->whereNotNull('start_date')->whereNotNull('due_date'),
|
|
'phases' => fn(HasMany $queue) => $queue
|
|
->select(['id', 'name', 'project_id'])
|
|
->withMin([
|
|
'tasks as start_date' => fn(AdjacencyListBuilder $q) => $q
|
|
->whereNotNull('start_date')
|
|
->whereNotNull('due_date')
|
|
], 'start_date')
|
|
->withMax([
|
|
'tasks as due_date' => fn(AdjacencyListBuilder $q) => $q
|
|
->whereNotNull('start_date')
|
|
->whereNotNull('due_date')
|
|
], 'due_date'),
|
|
])
|
|
->append('tasks_relations'),
|
|
$this->model instanceof Task => $this->model->setPermissionsUser(User::query()->find($this->userId))
|
|
->load([
|
|
'priority',
|
|
'project',
|
|
'users',
|
|
'status',
|
|
'parents',
|
|
'children',
|
|
'phase:id,name',
|
|
'workers',
|
|
'workers.user:id,full_name',
|
|
'attachmentsRelation',
|
|
'attachmentsRelation.user:id,full_name',
|
|
])
|
|
->append(['can'])
|
|
->loadSum('workers as total_spent_time', 'duration')
|
|
->loadSum('workers as total_offset', 'offset')
|
|
->makeVisible('can'),
|
|
$this->model instanceof TaskComment => $this->model
|
|
->load(
|
|
'user',
|
|
'attachmentsRelation',
|
|
'attachmentsRelation.user:id,full_name'
|
|
),
|
|
$this->model instanceof Project => $this->model->setPermissionsUser(User::query()->find($this->userId))
|
|
->load([
|
|
'users',
|
|
'defaultPriority',
|
|
'statuses',
|
|
'workers',
|
|
'workers.user:id,full_name',
|
|
'workers.task:id,task_name',
|
|
'phases' => fn($q) => $q->withCount('tasks'),
|
|
'group',
|
|
])
|
|
->loadCount('tasks')
|
|
->append(['can'])
|
|
->loadSum('workers as total_spent_time', 'duration')
|
|
->loadSum('workers as total_offset', 'offset')
|
|
->makeVisible('can'),
|
|
// Format a time interval as in the dashboard report
|
|
$this->model instanceof TimeInterval => DashboardExport::init(
|
|
[$this->model->user_id],
|
|
[$this->model->task->project_id],
|
|
Carbon::parse($this->model->start_at)->startOfDay(),
|
|
Carbon::parse($this->model->end_at)->endOfDay(),
|
|
Settings::scope('core')->get('timezone', 'UTC'),
|
|
$this->model->user->timezone ?? Settings::scope('core')->get('timezone', 'UTC'),
|
|
)->collection(['time_intervals.id' => $this->model->id])->first()->first()->toArray(),
|
|
default => $this->model,
|
|
};
|
|
|
|
return ['model' => $model];
|
|
}
|
|
|
|
/** @return Channel[] */
|
|
public function broadcastOn(): array
|
|
{
|
|
return [new PrivateChannel(sprintf('%s.%s', $this->entityType, $this->userId))];
|
|
}
|
|
|
|
/**
|
|
* @param Task|Project|TimeInterval $model
|
|
* @return int[]
|
|
*/
|
|
public static function getRelatedUserIds($model): array
|
|
{
|
|
$userRelation = match (true) {
|
|
$model instanceof Task => 'tasks',
|
|
$model instanceof Project => 'projects',
|
|
$model instanceof TimeInterval => 'timeIntervals',
|
|
default => null,
|
|
};
|
|
|
|
$query = User::query()->where('role_id', Role::ADMIN->value)->orWhere('role_id', Role::MANAGER->value);
|
|
if (isset($userRelation)) {
|
|
$query = $query->orWhereHas($userRelation, fn(Builder $builder) => $builder->where('id', $model->id));
|
|
}
|
|
|
|
return $query->pluck('id')->toArray();
|
|
}
|
|
}
|