UserController.php 8.41 KB
<?php

namespace App\Controllers;

use App\Auth\UsernameAccountType;
use App\Constants\AclRoles;
use App\Model\Project;
use App\Model\User;
use App\Model\UserProject;
use App\Transformers\UserTransformer;
use PhalconApi\Constants\ErrorCodes;
use PhalconApi\Exception;
use PhalconRest\Mvc\Controllers\CrudResourceController;

class UserController extends CrudResourceController
{
    /**
     * Accessible fields
     *
     * @return array
     */
    public function whitelist()
    {
        return [
            'username',
            'password',
            'email',
            'role'
        ];
    }

    /**
     * Возвращает всех зарегистрированных пользователей c ролью AclRoles::EDITOR
     *
     * @return mixed
     */
    public function editorsAction()
    {
        $current_projects = $this->userService->getDetails()->projects;
        $editors = [];
        foreach ($current_projects as $project)
        {
            foreach ($project->users as $user) {
                if ($user->role == AclRoles::EDITOR)
                {
                    $editors[$project->id][] = $this->createItemResponse($user, new UserTransformer());
                }
            }
        }
        return $this->createResponse($editors);
    }

    /**
     * Возвращает всех зарегистрированных пользователей c ролью AclRoles::AUTHOR
     *
     * @return mixed
     */
    public function authorsAction()
    {
        $current_projects = $this->userService->getDetails()->projects;
        $authors = [];
        foreach ($current_projects as $project)
        {
            foreach ($project->users as $user) {
                if ($user->role == AclRoles::AUTHOR)
                {
                    $authors[$project->id][] = $this->createItemResponse($user, new UserTransformer());
                }
            }
        }
        return $this->createResponse($authors);
    }

    /**
     * Возвращает текущего залогиненного пользователя
     *
     * @return mixed
     */
    public function meAction()
    {
        return $this->createResourceResponse($this->userService->getDetails());
    }

    /**
     * Изменение данных пользователя
     *
     * @param $id
     * @throws Exception
     */
    public function updateAction($id)
    {
        if ($this->userService->getRole() == AclRoles::ADMINISTRATOR || $id == $this->userService->getIdentity())
        {
            return $this->update($id);
        }
        else
        {
            throw new Exception(ErrorCodes::ACCESS_DENIED, 'Operation is not allowed');
        }
    }

    /**
     * Удаление пользователя
     *
     * @param $id
     * @throws Exception
     */
    public function removeAction($id)
    {
        $user_role      = $this->userService->getRole();
        $user_id        = $this->userService->getIdentity();
        $role_to_delete = User::findFirst($id)->role;

        if (AclRoles::access_user_delete($user_role, $role_to_delete) || $user_id == $id)
        {
            return $this->remove($id);
        }
        else
        {
            throw new Exception(ErrorCodes::ACCESS_DENIED, 'Operation is not allowed');
        }
    }

    /**
     * Авторизация пользователя через BasicAuth и возвращает токен доступа
     *
     * @return mixed
     */
    public function authenticateAction()
    {
        $username = $this->request->getUsername();
        $password = $this->request->getPassword();

        $session = $this->authManager->loginWithUsernamePassword(UsernameAccountType::NAME, $username,
            $password);

        $transformer = new UserTransformer;
        $transformer->setModelClass('App\Model\User');

        $user = $this->createItemResponse(User::findFirst($session->getIdentity()), $transformer);

        $response = [
            'token' => $session->getToken(),
            'expires' => $session->getExpirationTime(),
            'user' => $user
        ];

        return $this->createArrayResponse($response, 'data');
    }

    /**
     * Регистрация нового пользователя
     *
     * @return mixed
     */
    public function registerAction()
    {

        $this->beforeHandle();
        $this->beforeHandleWrite();
        $this->beforeHandleCreate();

        $data = $this->getPostedData();

        if (!$data || count($data) == 0) {
            return $this->onNoDataProvided();
        }
        if (!$this->postDataValid($data, false)) {
            return $this->onDataInvalid($data);
        }

        if (!$this->saveAllowed($data) || !$this->createAllowed($data)) {
            return $this->onNotAllowed();
        }

        $data = $this->transformPostData($data);

        $item = $this->createModelInstance();

        $newItem = $this->createItem($item, $data);

        if (!$newItem) {
            return $this->onCreateFailed($item, $data);
        }

        $last_id = $newItem->getWriteConnection()->lastInsertId();
        $responseData = $this->getFindData($last_id);

        $response = $this->getCreateResponse($responseData, $data);

        $this->afterHandleCreate($newItem, $data, $response);
        $this->afterHandleWrite();
        $this->afterHandle();

        return $response;

    }

    /**
     * Приглашение существующего пользователя в проэкт
     *
     * @throws Exception
     */
    public function inviteAction()
    {
        $user_id = $this->request->get('user_id');
        $project_id = $this->request->get('project_id');

        if (empty($user_id) || empty($project_id))
        {
            throw new Exception(ErrorCodes::DATA_NOT_FOUND, 'Empty post-data');
        }
        elseif (!User::findFirst($user_id))
        {
            throw new Exception(ErrorCodes::GENERAL_NOT_FOUND, 'User with requested id not found');
        }
        elseif (!Project::findFirst($project_id))
        {
            throw new Exception(ErrorCodes::GENERAL_NOT_FOUND, 'Project with requested id not found');
        }
        elseif (UserProject::findFirst(["user_id = '$user_id' AND project_id = '$project_id'"]))
        {
            throw new Exception(ErrorCodes::POST_DATA_INVALID, 'User already invited');
        }
        else
        {
            $userProject = new UserProject();
            $data = ['project_id' => $project_id, 'user_id' => $user_id];
            $userProject->user_id = $user_id;
            $userProject->project_id = $project_id;
            if (!$userProject->save())
            {
                return $this->onCreateFailed($userProject, $data);
            }
            else
            {
                return $this->createResponse($data);
            }
        }
    }

    /**
     * Переопределение входных данных
     *
     * @param $data
     * @return array
     * @throws Exception
     */
    protected function transformPostData($data)
    {
        $result = [];

        foreach ($data as $key => $value)
        {
            /** --- Менять роли может только админ ---- **/
            if ($this->userService->getRole() !== AclRoles::ADMINISTRATOR && $key == 'role')
            {
                $msg = 'You have not access for field `role`';
                throw new Exception(
                    ErrorCodes::POST_DATA_INVALID,
                    $msg,
                    ['post data field' => $key, 'value' => $value]
                );
            }
            /** -------------------------------------- **/
            $result[$key] = $this->transformPostDataValue($key, $value, $data);
        }

        return $result;
    }

    /**
     * Хеширование пароля
     *
     * @param $key
     * @param $value
     * @param $data
     * @return string
     */
    protected function transformPostDataValue($key, $value, $data)
    {
        if ($key == 'password') {
            return $this->security->hash($value);
        } else {
            return $value;
        }
    }

    /**
     * Сопутствующее удаление из перелинковочной таблицы проэкт-пользователь
     *
     * @param $id
     */
    protected function beforeHandleRemove($id)
    {
        $junctions = UserProject::findFirst("user_id = '$id'");
        if ($junctions)
        {
            $junctions->delete();
        }
    }
}