first commit

This commit is contained in:
Noor E Ilahi
2026-01-09 12:54:53 +05:30
commit 7ccf44f7da
1070 changed files with 113036 additions and 0 deletions

View File

@@ -0,0 +1,521 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Requests\Project\CreateProjectRequest;
use App\Http\Requests\Project\EditProjectRequest;
use App\Http\Requests\Project\DestroyProjectRequest;
use App\Http\Requests\Project\GanttDataRequest;
use App\Http\Requests\Project\ListProjectRequest;
use App\Http\Requests\Project\PhasesRequest;
use App\Http\Requests\Project\ShowProjectRequest;
use CatEvent;
use Filter;
use App\Models\Project;
use Exception;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Http\JsonResponse;
use DB;
use Staudenmeir\LaravelAdjacencyList\Eloquent\Builder as AdjacencyListBuilder;
use Throwable;
class ProjectController extends ItemController
{
protected const MODEL = Project::class;
/**
* @api {get, post} /projects/list List
* @apiDescription Get list of Projects
*
* @apiVersion 4.0.0
* @apiName GetProjectList
* @apiGroup Project
*
* @apiUse AuthHeader
*
* @apiPermission projects_list
* @apiPermission projects_full_access
*
* @apiUse ProjectParams
*
* @apiParamExample {json} Simple Request Example
* {
* "id": [">", 1],
* "user_id": ["=", [1,2,3]],
* "name": ["like", "%lorem%"],
* "description": ["like", "%lorem%"],
* "created_at": [">", "2019-01-01 00:00:00"],
* "updated_at": ["<", "2019-01-01 00:00:00"]
* }
*
* @apiUse ProjectObject
*
* @apiSuccessExample {json} Response Example
* HTTP/1.1 200 OK
* [
* {
* "id": 1,
* "company_id": 1,
* "name": "Dolores voluptates.",
* "description": "Deleniti maxime fugit nesciunt. Ut maiores deleniti tempora vel. Nisi aut doloremque accusantium tempore aut.",
* "deleted_at": null,
* "created_at": "2023-10-26T10:26:17.000000Z",
* "updated_at": "2023-10-26T10:26:17.000000Z",
* "important": 1,
* "source": "internal",
* "default_priority_id": null
* },
* {
* "id": 2,
* "company_id": 5,
* "name": "Et veniam velit tempore.",
* "description": "Consequatur nulla distinctio reprehenderit rerum omnis debitis. Fugit illum ratione quia harum. Optio porro consequatur enim esse.",
* "deleted_at": null,
* "created_at": "2023-10-26T10:26:42.000000Z",
* "updated_at": "2023-10-26T10:26:42.000000Z",
* "important": 1,
* "source": "internal",
* "default_priority_id": null
* }
* ]
*
* @apiUse 400Error
* @apiUse UnauthorizedError
* @apiUse ForbiddenError
*/
/**
* @param ListProjectRequest $request
* @return JsonResponse
* @throws Exception
*/
public function index(ListProjectRequest $request): JsonResponse
{
return $this->_index($request);
}
/**
* @api {get} /projects/gantt-data Gantt Data
* @apiDescription Получение данных для диаграммы Ганта по проекту
*
* @apiVersion 4.0.0
* @apiName GetGanttData
* @apiGroup Project
*
* @apiUse AuthHeader
* @apiUse ProjectIDParam
*
* @apiSuccess {Integer} id Project ID
* @apiSuccess {Integer} company_id Company ID
* @apiSuccess {String} name Project name
* @apiSuccess {String} description Project description
* @apiSuccess {String} deleted_at Deletion date (null if not deleted)
* @apiSuccess {String} created_at Creation date
* @apiSuccess {String} updated_at Update date
* @apiSuccess {Integer} important Project importance (1 - important, 0 - not important)
* @apiSuccess {String} source Project source (internal/external)
* @apiSuccess {Integer} default_priority_id Default priority ID (null if not set)
* @apiSuccess {Object[]} tasks_relations Task relations
* @apiSuccess {Integer} tasks_relations.parent_id Parent task ID
* @apiSuccess {Integer} tasks_relations.child_id Child task ID
* @apiSuccess {Object[]} tasks List of tasks
* @apiSuccess {Object[]} phases List of project phases
*
* @apiSuccessExample {json} Response Example
* HTTP/1.1 200 OK
* {
* "id": 1,
* "company_id": 1,
* "name": "Dolores voluptates.",
* "description": "Deleniti maxime fugit nesciunt. Ut maiores deleniti tempora vel. Nisi aut doloremque accusantium tempore aut.",
* "deleted_at": null,
* "created_at": "2023-10-26T10:26:17.000000Z",
* "updated_at": "2023-10-26T10:26:17.000000Z",
* "important": 1,
* "source": "internal",
* "default_priority_id": null,
* "tasks_relations": [
* {
* "parent_id": 5,
* "child_id": 1
* }
* ],
* "tasks": [],
* "phases": []
*
* }
*
* @apiUse 400Error
* @apiUse UnauthorizedError
*/
/**
* @param GanttDataRequest $request
* @return JsonResponse
* @throws Exception
* @throws Throwable
*/
public function ganttData(GanttDataRequest $request): JsonResponse
{
Filter::listen(Filter::getQueryFilterName(), static fn(Builder $query) => $query->with([
'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'),
]));
Filter::listen(Filter::getActionFilterName(), static function (Project $item) {
$item->append('tasks_relations');
return $item;
});
return $this->_show($request);
}
/**
* @api {get} /projects/phases Project Phases
* @apiDescription Retrieve project phases along with the number of tasks in each phase.
*
* @apiVersion 4.0.0
* @apiName GetProjectPhases
* @apiGroup Project
*
* @apiUse AuthHeader
* @apiUse ProjectIDParam
* @apiUse ProjectObject
* @apiUse 400Error
* @apiUse UnauthorizedError
*/
/**
* @param PhasesRequest $request
* @return JsonResponse
* @throws Exception
* @throws Throwable
*/
public function phases(PhasesRequest $request): JsonResponse
{
Filter::listen(
Filter::getQueryFilterName(),
static fn(Builder $query) => $query
->with([
'phases'=> fn(HasMany $q) => $q->withCount('tasks')
])
);
return $this->_show($request);
}
/**
* @throws Throwable
* @api {get} /projects/show Project Show
* @apiDescription Retrieve project show along with the number of tasks in each phase.
*
* @apiVersion 4.0.0
* @apiName GetProjectShow
* @apiGroup Project
*
* @apiUse AuthHeader
* @apiUse ProjectIDParam
* @apiUse ProjectObject
* @apiUse 400Error
* @apiUse UnauthorizedError
*/
public function show(ShowProjectRequest $request): JsonResponse
{
Filter::listen(
Filter::getQueryFilterName(),
static fn(Builder $query) => $query
->with([
'phases'=> fn(HasMany $q) => $q->withCount('tasks')
])
);
return $this->_show($request);
}
/**
* @throws Throwable
* @api {post} /projects/create Create Project
* @apiDescription Creates a new project
*
* @apiVersion 4.0.0
* @apiName CreateProject
* @apiGroup Project
*
* @apiUse AuthHeader
*
* @apiParam {Boolean} important Project importance
* @apiParam {Integer} screenshots_state State of the screenshots
* @apiParam {String} name Project name
* @apiParam {String} description Project description
* @apiParam {Integer} default_priority_id Default priority ID
* @apiParam {Object[]} statuses Project statuses
* @apiParam {Integer} statuses.id Status ID
* @apiParam {String} statuses.color Status color
*
* @apiParamExample {json} Request Example
* {
* "important": true,
* "screenshots_state": 1,
* "name": "test",
* "description": "test",
* "default_priority_id": 2,
* "statuses": [
* {
* "id": 2,
* "color": null
* }
* ]
* }
*
* @apiSuccess {String} name Project name
* @apiSuccess {String} description Project description
* @apiSuccess {Boolean} important Project importance
* @apiSuccess {Integer} default_priority_id Default priority ID
* @apiSuccess {Integer} screenshots_state State of the screenshots
* @apiSuccess {String} created_at Creation timestamp
* @apiSuccess {String} updated_at Update timestamp
* @apiSuccess {Object[]} statuses Project statuses
*
* @apiSuccessExample {json} Response Example
* HTTP/1.1 200 OK
* {
* "name": "test",
* "description": "test",
* "important": 1,
* "default_priority_id": 2,
* "screenshots_state": 1,
* "updated_at": "2024-08-06T12:28:07.000000Z",
* "created_at": "2024-08-06T12:28:07.000000Z",
* "id": 161,
* "statuses": []
* }
*
* @apiUse 400Error
* @apiUse ValidationError
* @apiUse UnauthorizedError
* @apiUse ForbiddenError
*/
public function create(CreateProjectRequest $request): JsonResponse
{
Filter::listen(Filter::getRequestFilterName(), static function ($requestData) {
if (isset($requestData['group']) && is_array($requestData['group'])) {
$requestData['group'] = $requestData['group']['id'];
}
return $requestData;
});
CatEvent::listen(Filter::getAfterActionEventName(), static function (Project $project, $requestData) use ($request) {
if ($request->has('statuses')) {
$statuses = [];
foreach ($request->get('statuses') as $status) {
$statuses[$status['id']] = ['color' => $status['color']];
}
$project->statuses()->sync($statuses);
}
if (isset($requestData['phases'])) {
$project->phases()->createMany($requestData['phases']);
}
});
Filter::listen(Filter::getActionFilterName(), static fn($data) => $data->load('statuses'));
return $this->_create($request);
}
/**
* @throws Throwable
* @api {post} /projects/edit Edit
* @apiDescription Edit Project
*
* @apiVersion 4.0.0
* @apiName EditProject
* @apiGroup Project
*
* @apiUse AuthHeader
*
* @apiPermission projects_edit
* @apiPermission projects_full_access
*
* @apiParamExample {json} Request Example
* {
* "id": 1,
* "name": "test",
* "description": "test"
* }
*
* @apiParam {String} id Project id
* @apiParam {String} name Project name
* @apiParam {String} description Project description
*
* @apiSuccess {Integer} id Project ID
* @apiSuccess {Integer} company_id Company ID
* @apiSuccess {String} name Project name
* @apiSuccess {String} description Project description
* @apiSuccess {String} deleted_at Deletion timestamp
* @apiSuccess {String} created_at Creation timestamp
* @apiSuccess {String} updated_at Update timestamp
* @apiSuccess {Boolean} important Project importance
* @apiSuccess {String} source Project source
* @apiSuccess {Integer} default_priority_id Default priority ID
* @apiSuccess {Integer} screenshots_state State of the screenshots
* @apiSuccess {Object[]} statuses Project statuses
*
* @apiSuccessExample {json} Response Example
* {
* "id": 1,
* "company_id": 1,
* "name": "test",
* "description": "test",
* "deleted_at": null,
* "created_at": "2023-10-26T10:26:17.000000Z",
* "updated_at": "2024-08-07T16:47:01.000000Z",
* "important": 1,
* "source": "internal",
* "default_priority_id": null,
* "screenshots_state": 1,
* "statuses": []
* }
*
* @apiUse 400Error
* @apiUse ValidationError
* @apiUse UnauthorizedError
* @apiUse ItemNotFoundError
*/
public function edit(EditProjectRequest $request): JsonResponse
{
Filter::listen(Filter::getRequestFilterName(), static function ($requestData) {
if (isset($requestData['group']) && is_array($requestData['group'])) {
$requestData['group'] = $requestData['group']['id'];
}
return $requestData;
});
CatEvent::listen(Filter::getAfterActionEventName(), static function (Project $project, $requestData) use ($request) {
if ($request->has('statuses')) {
$statuses = [];
foreach ($request->get('statuses') as $status) {
$statuses[$status['id']] = ['color' => $status['color']];
}
$project->statuses()->sync($statuses);
}
if (isset($requestData['phases'])) {
$phases = collect($requestData['phases']);
$project->phases()
->whereNotIn('id', $phases->pluck('id')->filter())
->delete();
$project->phases()->upsert(
$phases->filter(fn (array $val) => isset($val['id']))->toArray(),
['id'],
['name']
);
$project->phases()->createMany($phases->filter(fn (array $val) => !isset($val['id'])));
}
});
Filter::listen(Filter::getActionFilterName(), static fn($data) => $data->load('statuses'));
return $this->_edit($request);
}
/**
* @throws Throwable
* @api {post} /projects/remove Destroy
* @apiDescription Destroy Project
*
* @apiVersion 4.0.0
* @apiName DestroyProject
* @apiGroup Project
*
* @apiUse AuthHeader
*
* @apiPermission projects_remove
* @apiPermission projects_full_access
*
* @apiParam {String} id Project id
*
* @apiParamExample {json} Request Example
* {
* "id": 1
* }
*
* @apiSuccess {String} message Destroy status
*
* @apiSuccessExample {json} Response Example
* HTTP/1.1 204 No Content
* {
* }
*
* @apiUse 400Error
* @apiUse ValidationError
* @apiUse ForbiddenError
* @apiUse UnauthorizedError
* @apiUse ItemNotFoundError
*/
public function destroy(DestroyProjectRequest $request): JsonResponse
{
return $this->_destroy($request);
}
/**
* @throws Exception
* @api {get,post} /projects/count Count
* @apiDescription Count Projects
*
* @apiVersion 4.0.0
* @apiName Count
* @apiGroup Project
*
* @apiUse AuthHeader
*
* @apiPermission projects_count
* @apiPermission projects_full_access
*
* @apiSuccess {Integer} total Amount of projects that we have
*
* @apiSuccessExample {json} Response Example
* HTTP/1.1 200 OK
* {
* "total": 159
* }
*
* @apiUse 400Error
* @apiUse ForbiddenError
* @apiUse UnauthorizedError
*/
public function count(ListProjectRequest $request): JsonResponse
{
return $this->_count($request);
}
}