571 lines
22 KiB
PHP
571 lines
22 KiB
PHP
<?php
|
||
|
||
namespace App\Http\Controllers\Api;
|
||
|
||
use App;
|
||
use App\Enums\Role;
|
||
use App\Enums\ScreenshotsState;
|
||
use App\Http\Requests\User\ListUsersRequest;
|
||
use App\Scopes\UserAccessScope;
|
||
use Settings;
|
||
use Carbon\Carbon;
|
||
use Exception;
|
||
use Filter;
|
||
use App\Mail\UserCreated;
|
||
use App\Models\User;
|
||
use Illuminate\Database\Eloquent\Builder;
|
||
use Illuminate\Database\Eloquent\Model;
|
||
use Illuminate\Http\JsonResponse;
|
||
use Illuminate\Http\Request;
|
||
use CatEvent;
|
||
use Mail;
|
||
use App\Http\Requests\User\CreateUserRequest;
|
||
use App\Http\Requests\User\EditUserRequest;
|
||
use App\Http\Requests\User\SendInviteUserRequest;
|
||
use App\Http\Requests\User\ShowUserRequest;
|
||
use App\Http\Requests\User\DestroyUserRequest;
|
||
use App\Models\Setting;
|
||
use Illuminate\Support\Str;
|
||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||
use Throwable;
|
||
|
||
class UserController extends ItemController
|
||
{
|
||
protected const MODEL = User::class;
|
||
|
||
/**
|
||
* @throws Exception
|
||
* @api {get, post} /users/list List
|
||
* @apiDescription Get list of Users with any params
|
||
*
|
||
* @apiVersion 4.0.0
|
||
* @apiName GetUserList
|
||
* @apiGroup User
|
||
*
|
||
* @apiUse AuthHeader
|
||
*
|
||
* @apiPermission users_list
|
||
* @apiPermission users_full_access
|
||
*
|
||
* @apiSuccess {Object[]} users List of users.
|
||
* @apiSuccess {Integer} users.id The unique ID of the user.
|
||
* @apiSuccess {String} users.full_name Full name of the user.
|
||
* @apiSuccess {String} users.email Email address of the user.
|
||
* @apiSuccess {String} users.url URL associated with the user.
|
||
* @apiSuccess {Integer} users.company_id ID of the company the user belongs to.
|
||
* @apiSuccess {String} users.avatar URL of the user's avatar image.
|
||
* @apiSuccess {Integer} users.screenshots_state The current state of screenshot monitoring.
|
||
* @apiSuccess {Boolean} users.manual_time Indicates if manual time tracking is allowed.
|
||
* @apiSuccess {Integer} users.computer_time_popup Time in seconds before showing a time popup.
|
||
* @apiSuccess {Boolean} users.blur_screenshots Indicates if screenshots are blurred.
|
||
* @apiSuccess {Boolean} users.web_and_app_monitoring Indicates if web and app monitoring is enabled.
|
||
* @apiSuccess {Integer} users.screenshots_interval Interval in minutes for taking screenshots.
|
||
* @apiSuccess {Boolean} users.active Indicates if the user is active.
|
||
* @apiSuccess {String} users.deleted_at Deletion timestamp, or `null` if the user is not deleted.
|
||
* @apiSuccess {String} users.created_at Creation timestamp of the user.
|
||
* @apiSuccess {String} users.updated_at Last update timestamp of the user.
|
||
* @apiSuccess {String} users.timezone The timezone of the user, or `null`.
|
||
* @apiSuccess {Boolean} users.important Indicates if the user is marked as important.
|
||
* @apiSuccess {Boolean} users.change_password Indicates if the user must change their password.
|
||
* @apiSuccess {Integer} users.role_id ID of the user's role.
|
||
* @apiSuccess {String} users.user_language Language preference of the user.
|
||
* @apiSuccess {String} users.type The user type, e.g., "employee".
|
||
* @apiSuccess {Boolean} users.invitation_sent Indicates if an invitation has been sent.
|
||
* @apiSuccess {Integer} users.nonce Nonce value for secure actions.
|
||
* @apiSuccess {Boolean} users.client_installed Indicates if the client software is installed.
|
||
* @apiSuccess {Boolean} users.permanent_screenshots Indicates if permanent screenshots are enabled.
|
||
* @apiSuccess {String} users.last_activity The last recorded activity timestamp.
|
||
* @apiSuccess {Boolean} users.screenshots_state_locked Indicates if screenshot state is locked.
|
||
* @apiSuccess {Boolean} users.online Indicates if the user is currently online.
|
||
* @apiSuccess {Boolean} users.can_view_team_tab Indicates if the user can view the team tab.
|
||
* @apiSuccess {Boolean} users.can_create_task Indicates if the user can create tasks.
|
||
*
|
||
* @apiSuccessExample {json} Response Example
|
||
* HTTP/1.1 200 OK
|
||
* {
|
||
* [
|
||
* {
|
||
* "id": 1,
|
||
* "full_name": "Admin",
|
||
* "email": "admin@cattr.app",
|
||
* "url": "",
|
||
* "company_id": 1,
|
||
* "avatar": "",
|
||
* "screenshots_state": 1,
|
||
* "manual_time": 0,
|
||
* "computer_time_popup": 300,
|
||
* "blur_screenshots": false,
|
||
* "web_and_app_monitoring": true,
|
||
* "screenshots_interval": 5,
|
||
* "active": 1,
|
||
* "deleted_at": null,
|
||
* "created_at": "2023-10-26T10:26:17.000000Z",
|
||
* "updated_at": "2024-08-19T10:42:18.000000Z",
|
||
* "timezone": null,
|
||
* "important": 0,
|
||
* "change_password": 0,
|
||
* "role_id": 0,
|
||
* "user_language": "en",
|
||
* "type": "employee",
|
||
* "invitation_sent": false,
|
||
* "nonce": 0,
|
||
* "client_installed": 0,
|
||
* "permanent_screenshots": 0,
|
||
* "last_activity": "2024-08-19 10:42:18",
|
||
* "screenshots_state_locked": false,
|
||
* "online": false,
|
||
* "can_view_team_tab": true,
|
||
* "can_create_task": true
|
||
* },
|
||
* {
|
||
* "id": 2,
|
||
* "full_name": "Fabiola Mertz",
|
||
* "email": "projectManager@example.com",
|
||
* "url": "",
|
||
* "company_id": 1,
|
||
* "avatar": "",
|
||
* "screenshots_state": 2,
|
||
* "manual_time": 0,
|
||
* "computer_time_popup": 300,
|
||
* "blur_screenshots": false,
|
||
* "web_and_app_monitoring": true,
|
||
* "screenshots_interval": 5,
|
||
* "active": 1,
|
||
* "deleted_at": null,
|
||
* "created_at": "2023-10-26T10:26:17.000000Z",
|
||
* "updated_at": "2023-10-26T10:26:17.000000Z",
|
||
* "timezone": null,
|
||
* "important": 0,
|
||
* "change_password": 0,
|
||
* "role_id": 2,
|
||
* "user_language": "en",
|
||
* "type": "employee",
|
||
* "invitation_sent": false,
|
||
* "nonce": 0,
|
||
* "client_installed": 0,
|
||
* "permanent_screenshots": 0,
|
||
* "last_activity": "2023-10-26 09:44:17",
|
||
* "screenshots_state_locked": false,
|
||
* "online": false,
|
||
* "can_view_team_tab": false,
|
||
* "can_create_task": false
|
||
* },...
|
||
* ]
|
||
* }
|
||
* @apiUse 400Error
|
||
* @apiUse UnauthorizedError
|
||
* @apiUse ForbiddenError
|
||
*/
|
||
public function index(ListUsersRequest $request): JsonResponse
|
||
{
|
||
return $this->_index($request);
|
||
}
|
||
|
||
/**
|
||
* @api {post} /users/create Create
|
||
* @apiDescription Create User Entity
|
||
*
|
||
* @apiVersion 4.0.0
|
||
* @apiName CreateUser
|
||
* @apiGroup User
|
||
*
|
||
* @apiUse AuthHeader
|
||
*
|
||
* @apiPermission users_create
|
||
* @apiPermission users_full_access
|
||
*
|
||
* @apiParam {String} user_language The language of the new user (e.g., "en")
|
||
* @apiParam {String} timezone The timezone of the new user (e.g., "Europe/Moscow")
|
||
* @apiParam {Integer} role_id ID of the role of the new user
|
||
* @apiParam {Integer} active Will new user be active or not `(1 - active, 0 - not)`
|
||
* @apiParam {Integer} screenshots_state State of screenshots monitoring (e.g., 1 for enabled)
|
||
* @apiParam {Boolean} send_invite Whether to send an invitation to the new user (true - send, false - do not send)
|
||
* @apiParam {Boolean} manual_time Whether manual time tracking is enabled for the new user
|
||
* @apiParam {Integer} screenshots_interval Interval in minutes for taking screenshots
|
||
* @apiParam {Integer} computer_time_popup Time in minutes before showing a time popup
|
||
* @apiParam {String} type The type of user (e.g., "employee")
|
||
* @apiParam {Boolean} web_and_app_monitoring Whether web and app monitoring is enabled
|
||
* @apiParam {String} email New user email
|
||
* @apiParam {String} password New user password
|
||
* @apiParam {String} full_name New user name
|
||
* @apiParamExample {json} Request Example
|
||
* {
|
||
* "user_language" : "en",
|
||
* "timezone" : "Europe/Moscow",
|
||
* "role_id" : 2,
|
||
* "active" : true,
|
||
* "screenshots_state" : 1,
|
||
* "send_invite" : 1,
|
||
* "manual_time" : 1,
|
||
* "screenshots_interval" : 10,
|
||
* "computer_time_popup" : 3,
|
||
* "type" : "employee",
|
||
* "web_and_app_monitoring" : 1,
|
||
* "email" : "123@cattr.app",
|
||
* "password" : "password",
|
||
* "full_name" : "name"
|
||
* }
|
||
* @apiSuccess {String} full_name Full name of the user.
|
||
* @apiSuccess {String} email Email address of the user.
|
||
* @apiSuccess {String} user_language Language of the user.
|
||
* @apiSuccess {Boolean} active Whether the user is active.
|
||
* @apiSuccess {Integer} screenshots_state State of screenshots monitoring.
|
||
* @apiSuccess {Boolean} manual_time Whether manual time tracking is enabled.
|
||
* @apiSuccess {Integer} screenshots_interval Interval in minutes for taking screenshots.
|
||
* @apiSuccess {Integer} computer_time_popup Time in minutes before showing a time popup.
|
||
* @apiSuccess {String} timezone Timezone of the user.
|
||
* @apiSuccess {Integer} role_id ID of the role assigned to the user.
|
||
* @apiSuccess {String} type Type of the user (e.g., "employee").
|
||
* @apiSuccess {Boolean} web_and_app_monitoring Whether web and app monitoring is enabled.
|
||
* @apiSuccess {Boolean} screenshots_state_locked Whether the screenshot state is locked.
|
||
* @apiSuccess {Boolean} invitation_sent Whether an invitation has been sent.
|
||
* @apiSuccess {String} updated_at Timestamp of the last update.
|
||
* @apiSuccess {String} created_at Timestamp of when the user was created.
|
||
* @apiSuccess {Integer} id ID of the created user.
|
||
* @apiSuccess {Boolean} online Whether the user is currently online.
|
||
* @apiSuccess {Boolean} can_view_team_tab Whether the user can view the team tab.
|
||
* @apiSuccess {Boolean} can_create_task Whether the user can create tasks.
|
||
*
|
||
*
|
||
* @apiSuccessExample {json} Response Example
|
||
* HTTP/1.1 200 OK
|
||
* {
|
||
* "full_name": "name",
|
||
* "email": "123@cattr.app",
|
||
* "user_language": "en",
|
||
* "active": 1,
|
||
* "screenshots_state": 1,
|
||
* "manual_time": 1,
|
||
* "screenshots_interval": 10,
|
||
* "computer_time_popup": 3,
|
||
* "timezone": "Europe/Moscow",
|
||
* "role_id": 2,
|
||
* "type": "employee",
|
||
* "web_and_app_monitoring": true,
|
||
* "screenshots_state_locked": true,
|
||
* "invitation_sent": true,
|
||
* "updated_at": "2024-08-21T14:29:06.000000Z",
|
||
* "created_at": "2024-08-21T14:29:06.000000Z",
|
||
* "id": 10,
|
||
* "online": false,
|
||
* "can_view_team_tab": false,
|
||
* "can_create_task": false
|
||
* }
|
||
*
|
||
* @apiUse 400Error
|
||
* @apiUse ValidationError
|
||
* @apiUse UnauthorizedError
|
||
* @apiUse ForbiddenError
|
||
*/
|
||
/**
|
||
* @param CreateUserRequest $request
|
||
* @return JsonResponse
|
||
* @throws Throwable
|
||
*/
|
||
public function create(CreateUserRequest $request): JsonResponse
|
||
{
|
||
Filter::listen(Filter::getRequestFilterName(), static function ($requestData) use ($request) {
|
||
$requestData['screenshots_state_locked'] = $request->user()->isAdmin() && ScreenshotsState::tryFrom($requestData['screenshots_state'])->mustBeInherited();
|
||
|
||
return $requestData;
|
||
});
|
||
|
||
return $this->_create($request);
|
||
}
|
||
|
||
/**
|
||
* @api {post} /users/edit Edit
|
||
* @apiDescription Edit User
|
||
*
|
||
* @apiVersion 4.0.0
|
||
* @apiName EditUser
|
||
* @apiGroup User
|
||
*
|
||
* @apiUse AuthHeader
|
||
*
|
||
* @apiPermission users_edit
|
||
* @apiPermission users_full_access
|
||
* @apiParam {String} user_language The language of the new user (e.g., "en")
|
||
* @apiParam {String} timezone The timezone of the new user (e.g., "Europe/Moscow")
|
||
* @apiParam {Integer} role_id ID of the role of the new user
|
||
* @apiParam {Integer} id The ID of the user being edited.
|
||
* @apiParam {String} full_name New user name
|
||
* @apiParam {String} email New user email
|
||
* @apiParam {String} url URL associated with the user
|
||
* @apiParam {Integer} company_id The ID of the company to which the user belongs
|
||
* @apiParam {String} avatar The URL of the user’s avatar
|
||
* @apiParam {Integer} screenshots_state State of screenshots monitoring (e.g., 1 for enabled)
|
||
* @apiParam {Boolean} manual_time Whether manual time tracking is enabled for the new user
|
||
* @apiParam {Integer} computer_time_popup Time in minutes before showing a time popup
|
||
* @apiParam {Boolean} blur_screenshots Indicates if screenshots are blurred
|
||
* @apiParam {Boolean} web_and_app_monitoring Whether web and app monitoring is enabled
|
||
* @apiParam {Integer} screenshots_interval Interval in minutes for taking screenshots
|
||
* @apiParam {Integer} active Will new user be active or not `(1 - active, 0 - not)`
|
||
* @apiParam {String} deleted_at Deletion timestamp, or `null` if the user is not deleted.
|
||
* @apiParam {Boolean} send_invite Whether to send an invitation to the new user (true - send, false - do not send)
|
||
*
|
||
*
|
||
*
|
||
* @apiParam {String} type The type of user (e.g., "employee")
|
||
*
|
||
* @apiParam {String} password New user password
|
||
*
|
||
*
|
||
* @apiParamExample {json} Request Example
|
||
* {
|
||
* "user_language" : "en",
|
||
* "timezone" : "Europe/Moscow",
|
||
* "role_id" : 2,
|
||
* "id" : 3,
|
||
* "full_name" : "Rachael Reichert",
|
||
* "email": "projectAuditor@example.com",
|
||
* "url" : null,
|
||
* "company_id" : 1,
|
||
* "avatar" : null,
|
||
* "screenshots_state" : 1,
|
||
* "manual_time" : 0,
|
||
* "computer_time_popup" : 300,
|
||
* "blur_screenshots" : false,
|
||
* "web_and_app_monitoring" : true,
|
||
* "screenshots_interval" : 5,
|
||
* "active" : true,
|
||
* "deleted_at" : null,
|
||
* "created_at" : "2023-10-26T10:26:42.000000Z",
|
||
* "updated_at" : "2023-10-26T10:26:42.000000Z",
|
||
* "important" : 0,
|
||
* "change_password" : 0,
|
||
* "type" : "employee",
|
||
* "invitation_sent" : false,
|
||
* "nonce" : 0,
|
||
* "client_installed" : 0,
|
||
* "permanent_screenshots" : 0,
|
||
* "last_activity" : "2023-10-26 10:05:42",
|
||
* "screenshots_state_locked" : false,
|
||
* "online" : false,
|
||
* "can_view_team_tab" : false,
|
||
* "can_create_task" : false
|
||
* }
|
||
* @apiUse UserObject
|
||
* @apiUse 400Error
|
||
* @apiUse ValidationError
|
||
* @apiUse UnauthorizedError
|
||
* @apiUse ItemNotFoundError
|
||
*/
|
||
/**
|
||
* @param EditUserRequest $request
|
||
* @return JsonResponse
|
||
* @throws Throwable
|
||
*/
|
||
public function edit(EditUserRequest $request): JsonResponse
|
||
{
|
||
Filter::listen(Filter::getActionFilterName(), static function (User $user) use ($request) {
|
||
if ($user->screenshots_state_locked && !$request->user()->isAdmin()) {
|
||
$user->screenshots_state = $user->getOriginal('screenshots_state');
|
||
return $user;
|
||
}
|
||
|
||
$user->screenshots_state_locked = $request->user()->isAdmin() && ScreenshotsState::tryFrom($user->screenshots_state)->mustBeInherited();
|
||
|
||
return $user;
|
||
});
|
||
|
||
return $this->_edit($request);
|
||
}
|
||
|
||
/**
|
||
* @api {get, post} /users/show Show User
|
||
* @apiDescription Retrieves detailed information about a specific user.
|
||
*
|
||
* @apiVersion 4.0.0
|
||
* @apiName ShowUser
|
||
* @apiGroup User
|
||
*
|
||
* @apiUse AuthHeader
|
||
*
|
||
* @apiPermission users_show
|
||
* @apiPermission users_full_access
|
||
*
|
||
* @apiParam {Integer} id User id
|
||
*
|
||
* @apiParamExample {json} Request Example:
|
||
* {
|
||
* "id": 1
|
||
* }
|
||
* @apiUse UserObject
|
||
*
|
||
* @apiUse 400Error
|
||
* @apiUse UnauthorizedError
|
||
* @apiUse ItemNotFoundError
|
||
* @apiUse ForbiddenError
|
||
* @apiUse ValidationError
|
||
*/
|
||
|
||
/**
|
||
* @param ShowUserRequest $request
|
||
* @return JsonResponse
|
||
* @throws Exception
|
||
* @throws Throwable
|
||
*/
|
||
public function show(ShowUserRequest $request): JsonResponse
|
||
{
|
||
return $this->_show($request);
|
||
}
|
||
|
||
/**
|
||
* @throws Throwable
|
||
* @api {post} /users/remove Destroy
|
||
* @apiDescription Destroy User
|
||
*
|
||
* @apiVersion 4.0.0
|
||
* @apiName DestroyUser
|
||
* @apiGroup User
|
||
*
|
||
* @apiUse AuthHeader
|
||
*
|
||
* @apiPermission users_remove
|
||
* @apiPermission users_full_access
|
||
*
|
||
* @apiParam {Integer} id ID of the target user
|
||
*
|
||
* @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
|
||
*/
|
||
public function destroy(DestroyUserRequest $request): JsonResponse
|
||
{
|
||
return $this->_destroy($request);
|
||
}
|
||
/**
|
||
* @throws Exception
|
||
* @api {get,post} /users/count Count
|
||
* @apiDescription Count Users
|
||
*
|
||
* @apiVersion 4.0.0
|
||
* @apiName Count
|
||
* @apiGroup User
|
||
*
|
||
* @apiUse AuthHeader
|
||
*
|
||
* @apiPermission users_count
|
||
* @apiPermission users_full_access
|
||
*
|
||
* @apiSuccess {String} total Amount of users that we have
|
||
*
|
||
* @apiSuccessExample {json} Response Example
|
||
* HTTP/1.1 200 OK
|
||
* {
|
||
* "total": 2
|
||
* }
|
||
*
|
||
* @apiUse 400Error
|
||
* @apiUse ForbiddenError
|
||
* @apiUse UnauthorizedError
|
||
*/
|
||
public function count(ListUsersRequest $request): JsonResponse
|
||
{
|
||
return $this->_count($request);
|
||
}
|
||
|
||
/**
|
||
* @param SendInviteUserRequest $request
|
||
* @return JsonResponse
|
||
* @throws Throwable
|
||
*/
|
||
/**
|
||
* @api {post} /api/users/send-invite Send User Invitation
|
||
* @apiDescription Sends an invitation to a user by generating a password, marking the invitation as sent, and dispatching relevant events.
|
||
*
|
||
* @apiVersion 4.0.0
|
||
* @apiName SendUserInvite
|
||
* @apiGroup User
|
||
*
|
||
* @apiUse AuthHeader
|
||
*
|
||
* @apiPermission users_invite
|
||
*
|
||
* @apiParam {Integer} id The ID of the user to whom the invitation will be sent.
|
||
*
|
||
* @apiParamExample {json} Request Example:
|
||
* {
|
||
* "id": 1
|
||
* }
|
||
*
|
||
* @apiSuccess {String} message A confirmation that the invite was sent successfully.
|
||
*
|
||
* @apiSuccessExample {json} Success Response:
|
||
* HTTP/1.1 204 No Content
|
||
*
|
||
* @apiUse 400Error
|
||
* @apiUse ForbiddenError
|
||
* @apiUse UnauthorizedError
|
||
*/
|
||
public function sendInvite(SendInviteUserRequest $request): JsonResponse
|
||
{
|
||
$requestId = Filter::process(Filter::getRequestFilterName(), $request->validated('id'));
|
||
|
||
$itemsQuery = $this->getQuery(['id' => $requestId]);
|
||
|
||
CatEvent::dispatch(Filter::getBeforeActionEventName(), $requestId);
|
||
|
||
$item = Filter::process(Filter::getActionFilterName(), $itemsQuery->first());
|
||
|
||
$password = Str::random();
|
||
$item->password = $password;
|
||
$item->invitation_sent = true;
|
||
$item->save();
|
||
|
||
throw_unless($item, new NotFoundHttpException);
|
||
|
||
CatEvent::dispatch(Filter::getAfterActionEventName(), [$requestId, $item]);
|
||
|
||
$language = Settings::scope('core')->get('language', 'en');
|
||
|
||
Mail::to($item->email)->locale($language)->send(new UserCreated($item->email, $password));
|
||
|
||
return responder()->success()->respond(204);
|
||
}
|
||
|
||
/**
|
||
* @api {patch} /users/activity Activity
|
||
* @apiDescription Updates the time of the user's last activity
|
||
*
|
||
* @apiVersion 4.0.0
|
||
* @apiName Activity
|
||
* @apiGroup User
|
||
*
|
||
* @apiUse AuthHeader
|
||
*
|
||
* @apiSuccessExample {json} Response Example
|
||
* HTTP/1.1 204 No Content
|
||
* {
|
||
* }
|
||
*
|
||
* @apiUse UnauthorizedError
|
||
*/
|
||
public function updateActivity(): JsonResponse
|
||
{
|
||
$user = request()->user();
|
||
|
||
CatEvent::dispatch(Filter::getBeforeActionEventName(), $user);
|
||
|
||
Filter::process(Filter::getActionFilterName(), $user)->update(['last_activity' => Carbon::now()]);
|
||
|
||
CatEvent::dispatch(Filter::getAfterActionEventName(), $user);
|
||
|
||
return responder()->success()->respond(204);
|
||
}
|
||
}
|