You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
242 lines
10 KiB
242 lines
10 KiB
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use Carbon\Carbon;
|
|
use App\Models\Task;
|
|
use App\Models\Work;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Http\Response;
|
|
use Spatie\QueryBuilder\QueryBuilder;
|
|
use Spatie\QueryBuilder\AllowedFilter;
|
|
|
|
class WorkController extends Controller
|
|
{
|
|
public function index($business, Request $request)
|
|
{
|
|
permit('businessAccess');
|
|
$per_page = $request->limit > 100 ? 10 : $request->limit;
|
|
$workQ = $this->indexFiltering($business)
|
|
->when($request->filled('group'), function ($q) use ($request) {
|
|
return $request->group == 'user' ? $q->report() : $q->reportByDate();
|
|
});
|
|
|
|
return $request->filled('group') ? $workQ->get() :
|
|
$workQ->defaultSort('-id')
|
|
->allowedSorts('id', 'started_at')->paginate($per_page);
|
|
}
|
|
|
|
public function indexFiltering($business)
|
|
{
|
|
$query = Work::where('works.business_id', $business);
|
|
$workQ = queryBuilder::for($query)
|
|
->join('tasks', 'tasks.id', 'works.task_id')
|
|
->select('works.*', 'tasks.title', 'tasks.sprint_id', 'tasks.system_id')
|
|
->allowedFilters([
|
|
AllowedFilter::exact('project_id'),
|
|
AllowedFilter::exact('tasks.sprint_id', null, false),
|
|
AllowedFilter::exact('tasks.system_id', null, false),
|
|
AllowedFilter::exact('user_id'),
|
|
AllowedFilter::scope('started_at_in'),
|
|
AllowedFilter::scope('started_at'),
|
|
AllowedFilter::scope('spent_time_from'),
|
|
AllowedFilter::scope('spent_time_to'),
|
|
]);
|
|
if (\request('_business_info')['info']['users'][\auth()->id()]['level'] != enum('levels.owner.id')) {
|
|
$requested_projects = isset(\request('filter')['project_id']) ?
|
|
array_unique(explode(',',\request('filter')['project_id'] ?? null )) :
|
|
null;
|
|
$requested_projects = collect($requested_projects)->keyBy(null)->toArray();
|
|
$project_ids = $this->myStateProjects($requested_projects);
|
|
$workQ->where(function ($q) use ($project_ids) {
|
|
$q->whereIn('project_id', $project_ids['non_guest_ids'])
|
|
->orWhere(function ($q) use ($project_ids) {
|
|
$q->whereIn('project_id', $project_ids['guest_ids'])
|
|
->where('assignee_id', auth()->id());
|
|
});
|
|
});
|
|
}
|
|
return $workQ;
|
|
}
|
|
|
|
public function myStateProjects($requested_projects)
|
|
{
|
|
$non_guest_ids = [];
|
|
$guest_ids = [];
|
|
$is_empty = empty($requested_projects);
|
|
|
|
foreach (\request('_business_info')['info']['projects'] as $p_id => $p) {
|
|
|
|
$level = \request('_business_info')['info']['projects'][$p_id]['members'][\auth()->id()]['level'];
|
|
|
|
if (( $is_empty || isset($requested_projects[$p_id]))
|
|
&& $level > enum('levels.guest.id')) {
|
|
array_push($non_guest_ids, $p_id);
|
|
}
|
|
if (( $is_empty || isset($requested_projects[$p_id]))
|
|
&& $level == enum('levels.guest.id')) {
|
|
array_push($guest_ids, $p_id);
|
|
}
|
|
}
|
|
|
|
return ['non_guest_ids' => $non_guest_ids, 'guest_ids' => $guest_ids];
|
|
}
|
|
|
|
public function show($business, $project, $task, $work)
|
|
{
|
|
permit('projectAccess', ['project_id' => $project]);
|
|
$work = Work::where([['project_id', $project ], ['task_id', $task], ['id', $work]])->firstOrFail();
|
|
if (can('isDefiniteGuestInProject', ['project_id' => $project])){ // is guest in project (only guest)
|
|
return $work->user_id == \auth()->id() ? $work : abort(Response::HTTP_FORBIDDEN); // not allowed
|
|
} else {
|
|
return $work;
|
|
}
|
|
}
|
|
/**
|
|
* Rule's:
|
|
* 1) only assignee_id can store work
|
|
* 2) started_at after task created_at
|
|
* 3) ended_at after started_at
|
|
* 4) not any work before in this work
|
|
*/
|
|
public function store($business, $project, $task, Request $request)
|
|
{
|
|
$taskModel = Task::findOrFail($task);
|
|
if ($taskModel->assignee_id != auth()->id()) {
|
|
abort(Response::HTTP_FORBIDDEN); // not allowed
|
|
}
|
|
|
|
$end = Carbon::createFromFormat('Y-m-d H:i', $request->ended_at);
|
|
$start = Carbon::createFromFormat('Y-m-d H:i', $request->started_at);
|
|
$diff_in_min = $end->diffInMinutes($start);
|
|
$work = Work::create($request->merge([
|
|
'business_id' => $business,
|
|
'project_id' => $project,
|
|
'task_id' => $task,
|
|
'user_id' => auth()->id(),
|
|
'minute_sum' => $diff_in_min,
|
|
'task' => [
|
|
'spent_time' => $taskModel->spent_time + $diff_in_min
|
|
]
|
|
])->except('_business_info'));
|
|
$taskModel->refresh();
|
|
// $taskModel->update([
|
|
// 'work_start' => Work::where('task_id', $taskModel->id)->orderBy('started_at')->first()->started_at ?? null,
|
|
// 'spent_time' => $taskModel->spent_time + $diff_in_min
|
|
// ]);
|
|
return $taskModel->load(['tagTask'=> fn($q) => $q->select('id', 'tag_id', 'task_id'), 'works', 'comments']);
|
|
}
|
|
|
|
public function storeValidation($request, $taskModel)
|
|
{
|
|
$this->validate($request, [
|
|
'message' => 'nullable|string|min:3|max:225',
|
|
'started_at' => 'required|date_format:Y-m-d H:i|after:'.$taskModel->created_at,
|
|
'ended_at' => 'required|date_format:Y-m-d H:i|after:started_at',
|
|
]);
|
|
$state = \request('_business_info')['workflows'][$taskModel->workflow_id]['statuses'][$taskModel->status_id]['state'] ?? null;
|
|
if ($state == enum('status.states.close.id') || $state == enum('status.states.done.id')) {
|
|
throw ValidationException::withMessages(['task' => 'The selected task is invalid.']);
|
|
}
|
|
$works = Work::where([
|
|
['ended_at', '>', $request->started_at],
|
|
['ended_at', '<', $request->ended_at],
|
|
])->orWhere([
|
|
['started_at', '>', $request->started_at],
|
|
['started_at', '<', $request->ended_at],
|
|
])->orWhere([
|
|
['started_at', '>=', $request->started_at],
|
|
['ended_at', '<=', $request->ended_at],
|
|
])->exists();
|
|
if ($works) {
|
|
throw ValidationException::withMessages(['work' => 'The selected work is invalid.']);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Rule's:
|
|
* 1) only assignee_id can store work
|
|
* 2) started_at after task created_at
|
|
* 3) ended_at after started_at
|
|
* 4) not any work before in this work
|
|
*/
|
|
public function update($business, $project, $task, $work, Request $request)
|
|
{
|
|
$taskModel = Task::findOrFail($task);
|
|
$workModel = Work::findOrFail($work);
|
|
if ($taskModel->assignee_id != auth()->id()) {
|
|
abort(Response::HTTP_FORBIDDEN); // not allowed
|
|
}
|
|
|
|
$end = Carbon::createFromFormat('Y-m-d H:i', $request->ended_at);
|
|
$start = Carbon::createFromFormat('Y-m-d H:i', $request->started_at);
|
|
$new_diff_in_min = $end->diffInMinutes($start);
|
|
$old_diff_in_min = $workModel->minute_sum;
|
|
$workModel->update($request->merge([
|
|
'business_id' => $business,
|
|
'project_id' => $project,
|
|
'task_id' => $task,
|
|
'user_id' => auth()->id(),
|
|
'minute_sum' => $new_diff_in_min,
|
|
'task' => [
|
|
'spent_time' => ($taskModel->spent_time - $old_diff_in_min) + $new_diff_in_min
|
|
]
|
|
])->except('_business_info'));
|
|
$taskModel->refresh();
|
|
// $taskModel->update([
|
|
// 'work_start' => Work::where('task_id', $taskModel->id)->orderBy('started_at')->first()->started_at ?? null,
|
|
// 'spent_time' => ($taskModel->spent_time - $old_diff_in_min) + $new_diff_in_min
|
|
// ]);
|
|
return $taskModel->load(['tagTask'=> fn($q) => $q->select('id', 'tag_id', 'task_id'), 'works', 'comments']);
|
|
}
|
|
|
|
public function updateValidation($request, $taskModel, $workModel)
|
|
{
|
|
$this->validate($request, [
|
|
'message' => 'nullable|string|min:3|max:225',
|
|
'started_at' => 'nullable|date_format:Y-m-d H:i|after:'.$taskModel->created_at,
|
|
'ended_at' => 'nullable|date_format:Y-m-d H:i|after:started_at',
|
|
]);
|
|
//ToDo: is needed to check status is active or idea??
|
|
$works = false;
|
|
if ($request->filled('started_at') || $request->filled('ended_at')) {
|
|
$started_at = $request->started_at ?? $workModel->started_at->format('Y-m-d H:i');
|
|
$ended_at = $request->ended_at ?? $workModel->ended_at->format('Y-m-d H:i');
|
|
if (strtotime($ended_at) <= strtotime($started_at)) {
|
|
throw ValidationException::withMessages(['ended_at' => 'The ended at must be a date after started at.']);
|
|
}
|
|
$works = Work::where([
|
|
['ended_at', '>', $started_at],
|
|
['ended_at', '<', $ended_at],
|
|
])->orWhere([
|
|
['started_at', '>', $started_at],
|
|
['started_at', '<', $ended_at],
|
|
])->orWhere([
|
|
['started_at', '>=', $started_at],
|
|
['ended_at', '<=', $ended_at],
|
|
])->where('id', '!=', $workModel->id)->exists();
|
|
$end = Carbon::createFromFormat('Y-m-d H:i', $ended_at);
|
|
$start = Carbon::createFromFormat('Y-m-d H:i', $started_at);
|
|
\request()->merge(['minute_sum' => $end->diffInMinutes($start)]);
|
|
}
|
|
if ($works) {
|
|
throw ValidationException::withMessages(['work' => 'The selected work is invalid.']);
|
|
}
|
|
}
|
|
|
|
public function destroy($business, $project, $task, $work)
|
|
{
|
|
$taskModel = Task::findOrFail($task);
|
|
$workModel = Work::findOrFail($work);
|
|
if ($taskModel->assignee_id != auth()->id()) {
|
|
abort(Response::HTTP_FORBIDDEN); // not allowed
|
|
}
|
|
$diff_in_min = $workModel->minute_sum;
|
|
$workModel->delete();
|
|
$taskModel->update([
|
|
'work_start' => Work::where('task_id', $taskModel->id)->orderBy('started_at')->first()->started_at ?? null,
|
|
'spent_time' => ($taskModel->spent_time - $diff_in_min)
|
|
]);
|
|
return $taskModel->load(['tagTask'=> fn($q) => $q->select('id', 'tag_id', 'task_id'), 'works','comments']);
|
|
}
|
|
}
|