add assignment completion api
This commit is contained in:
parent
916f070455
commit
350d2ec0b7
11 changed files with 281 additions and 16 deletions
|
|
@ -5,6 +5,7 @@ namespace App\Schedule;
|
|||
use App\User\User;
|
||||
use DateTimeImmutable;
|
||||
use DateTimeZone;
|
||||
use DomainException;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class EloquentScheduleRepository implements ScheduleRepository
|
||||
|
|
@ -29,6 +30,7 @@ class EloquentScheduleRepository implements ScheduleRepository
|
|||
'scheduled_date' => $assignmentDto->scheduledDate
|
||||
->format('Y-m-d'),
|
||||
'position' => $assignmentDto->position,
|
||||
'completed_at' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -77,6 +79,7 @@ class EloquentScheduleRepository implements ScheduleRepository
|
|||
->where('schedule_assignments.scheduled_date', $date->format(
|
||||
'Y-m-d',
|
||||
))
|
||||
->whereNull('schedule_assignments.completed_at')
|
||||
->with('schedule')
|
||||
->orderByDesc('schedules.id')
|
||||
->orderBy('schedule_assignments.position')
|
||||
|
|
@ -95,6 +98,50 @@ class EloquentScheduleRepository implements ScheduleRepository
|
|||
return $assignments;
|
||||
}
|
||||
|
||||
public function findAssignmentForUser(
|
||||
int $id,
|
||||
User $user,
|
||||
): ?ScheduleAssignment {
|
||||
$model = ScheduleAssignmentModel::query()
|
||||
->select('schedule_assignments.*')
|
||||
->join(
|
||||
'schedules',
|
||||
'schedules.id',
|
||||
'=',
|
||||
'schedule_assignments.schedule_id',
|
||||
)
|
||||
->where('schedule_assignments.id', $id)
|
||||
->where('schedules.user_id', $user->getId())
|
||||
->first();
|
||||
|
||||
return $model === null
|
||||
? null
|
||||
: $this->assignmentToDomain($model);
|
||||
}
|
||||
|
||||
public function updateAssignment(
|
||||
ScheduleAssignment $assignment,
|
||||
): ScheduleAssignment {
|
||||
$query = ScheduleAssignmentModel::query()
|
||||
->whereKey($assignment->getId());
|
||||
if ($assignment->getCompletedAt() === null) {
|
||||
$query->update(['completed_at' => null]);
|
||||
} else {
|
||||
$query->whereNull('completed_at')->update([
|
||||
'completed_at' => $assignment->getCompletedAt(),
|
||||
]);
|
||||
}
|
||||
|
||||
$model = ScheduleAssignmentModel::find($assignment->getId());
|
||||
if ($model === null) {
|
||||
throw new DomainException(
|
||||
"Assignment with id {$assignment->getId()} not found",
|
||||
);
|
||||
}
|
||||
|
||||
return $this->assignmentToDomain($model);
|
||||
}
|
||||
|
||||
private function toDomain(ScheduleModel $model, User $user): Schedule
|
||||
{
|
||||
$assignmentModels = ScheduleAssignmentModel::query()
|
||||
|
|
@ -129,6 +176,9 @@ class EloquentScheduleRepository implements ScheduleRepository
|
|||
path: $model->element_path,
|
||||
scheduledDate: $this->date($model->scheduled_date),
|
||||
position: $model->position,
|
||||
completedAt: $model->completed_at === null
|
||||
? null
|
||||
: $this->dateTime($model->completed_at),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -136,4 +186,10 @@ class EloquentScheduleRepository implements ScheduleRepository
|
|||
{
|
||||
return new DateTimeImmutable($value, new DateTimeZone('UTC'));
|
||||
}
|
||||
|
||||
private function dateTime(DateTimeImmutable $value): DateTimeImmutable
|
||||
{
|
||||
return DateTimeImmutable::createFromInterface($value)
|
||||
->setTimezone(new DateTimeZone('UTC'));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ namespace App\Schedule;
|
|||
|
||||
use DateTimeImmutable;
|
||||
|
||||
final readonly class ScheduleAssignment
|
||||
final class ScheduleAssignment
|
||||
{
|
||||
/**
|
||||
* @param list<string> $path
|
||||
|
|
@ -16,6 +16,7 @@ final readonly class ScheduleAssignment
|
|||
private array $path,
|
||||
private DateTimeImmutable $scheduledDate,
|
||||
private int $position,
|
||||
private ?DateTimeImmutable $completedAt,
|
||||
) {}
|
||||
|
||||
public function getId(): int
|
||||
|
|
@ -50,4 +51,21 @@ final readonly class ScheduleAssignment
|
|||
{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
public function getCompletedAt(): ?DateTimeImmutable
|
||||
{
|
||||
return $this->completedAt;
|
||||
}
|
||||
|
||||
public function complete(DateTimeImmutable $completedAt): void
|
||||
{
|
||||
if ($this->completedAt === null) {
|
||||
$this->completedAt = $completedAt;
|
||||
}
|
||||
}
|
||||
|
||||
public function reopen(): void
|
||||
{
|
||||
$this->completedAt = null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Schedule;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
|
@ -15,6 +16,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|||
* @property list<string> $element_path
|
||||
* @property string $scheduled_date
|
||||
* @property int $position
|
||||
* @property DateTimeImmutable|null $completed_at
|
||||
* @property-read ScheduleModel $schedule
|
||||
*
|
||||
* @method static Builder<static>|ScheduleAssignmentModel newModelQuery()
|
||||
|
|
@ -30,6 +32,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|||
'element_path',
|
||||
'scheduled_date',
|
||||
'position',
|
||||
'completed_at',
|
||||
])]
|
||||
class ScheduleAssignmentModel extends Model
|
||||
{
|
||||
|
|
@ -46,6 +49,7 @@ class ScheduleAssignmentModel extends Model
|
|||
'schedule_id' => 'integer',
|
||||
'element_path' => 'array',
|
||||
'position' => 'integer',
|
||||
'completed_at' => 'immutable_datetime',
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,4 +23,13 @@ interface ScheduleRepository
|
|||
User $user,
|
||||
DateTimeImmutable $date,
|
||||
): array;
|
||||
|
||||
public function findAssignmentForUser(
|
||||
int $id,
|
||||
User $user,
|
||||
): ?ScheduleAssignment;
|
||||
|
||||
public function updateAssignment(
|
||||
ScheduleAssignment $assignment,
|
||||
): ScheduleAssignment;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
namespace App\Schedule\UseCases\SetAssignmentCompletion;
|
||||
|
||||
use App\Auth\Clock;
|
||||
use App\Exceptions\BadRequestException;
|
||||
use App\Exceptions\NotFoundException;
|
||||
use App\Schedule\ScheduleAssignment;
|
||||
use App\Schedule\ScheduleRepository;
|
||||
|
||||
class SetAssignmentCompletion
|
||||
{
|
||||
public function __construct(
|
||||
private ScheduleRepository $scheduleRepository,
|
||||
private Clock $clock,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @throws BadRequestException
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function execute(
|
||||
SetAssignmentCompletionRequest $request,
|
||||
): ScheduleAssignment {
|
||||
if ($request->completed === null) {
|
||||
throw new BadRequestException(
|
||||
'completed must be a boolean',
|
||||
);
|
||||
}
|
||||
|
||||
$assignment = $this->scheduleRepository->findAssignmentForUser(
|
||||
$request->assignmentId,
|
||||
$request->user,
|
||||
);
|
||||
if ($assignment === null) {
|
||||
throw new NotFoundException('assignment not found');
|
||||
}
|
||||
|
||||
if ($request->completed) {
|
||||
$assignment->complete($this->clock->now());
|
||||
} else {
|
||||
$assignment->reopen();
|
||||
}
|
||||
|
||||
return $this->scheduleRepository->updateAssignment($assignment);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
namespace App\Schedule\UseCases\SetAssignmentCompletion;
|
||||
|
||||
use App\User\User;
|
||||
|
||||
final readonly class SetAssignmentCompletionRequest
|
||||
{
|
||||
public function __construct(
|
||||
public int $assignmentId,
|
||||
public User $user,
|
||||
public ?bool $completed,
|
||||
) {}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue