From cd1b80d582edd79a603a29bf7005c0a1b5da453c Mon Sep 17 00:00:00 2001 From: nuxsmin Date: Mon, 12 Mar 2018 14:26:43 +0100 Subject: [PATCH] * [ADD] API module. Work in progress. --- .../api/Controllers/AccountController.php | 91 ++++++++++++++++ .../api/Controllers/ControllerBase.php | 89 +++++++++++++++ .../api/Controllers/Traits/ResponseTrait.php | 72 +++++++++++++ lib/SP/Api/ApiResponse.php | 80 ++++++++++++++ lib/SP/Api/JsonRpcResponse.php | 66 ++++++++++++ lib/SP/Services/ApiService/ApiService.php | 102 ++++++++++++++++++ .../Services/AuthToken/AuthTokenService.php | 35 +++--- lib/SP/Services/Service.php | 6 +- 8 files changed, 526 insertions(+), 15 deletions(-) create mode 100644 app/modules/api/Controllers/AccountController.php create mode 100644 app/modules/api/Controllers/ControllerBase.php create mode 100644 app/modules/api/Controllers/Traits/ResponseTrait.php create mode 100644 lib/SP/Api/ApiResponse.php create mode 100644 lib/SP/Api/JsonRpcResponse.php create mode 100644 lib/SP/Services/ApiService/ApiService.php diff --git a/app/modules/api/Controllers/AccountController.php b/app/modules/api/Controllers/AccountController.php new file mode 100644 index 00000000..e918d5b4 --- /dev/null +++ b/app/modules/api/Controllers/AccountController.php @@ -0,0 +1,91 @@ +. + */ + +namespace SP\Modules\Api\Controllers; + +use SP\Api\ApiResponse; +use SP\Core\Acl\ActionsInterface; +use SP\Core\Events\Event; +use SP\Core\Events\EventMessage; +use SP\Core\Exceptions\ValidationException; +use SP\Modules\Api\Controllers\Traits\ResponseTrait; +use SP\Modules\Web\Forms\AccountForm; +use SP\Services\Account\AccountService; + +/** + * Class AccountController + * @package api\Controllers + */ +class AccountController extends ControllerBase +{ + use ResponseTrait; + + /** + * @var AccountService + */ + protected $accountService; + + /** + * Saves create action + */ + public function createAction() + { + try { + $form = new AccountForm(); + $form->validate(ActionsInterface::ACCOUNT_CREATE); + + $itemData = $form->getItemData(); + $itemData->userId = $this->context->getUserData()->getId(); + + $accountId = $this->accountService->create($itemData); + + $accountDetails = $this->accountService->getById($accountId)->getAccountVData(); + + $this->eventDispatcher->notifyEvent('create.account', + new Event($this, + EventMessage::factory() + ->addDescription(__u('Cuenta creada')) + ->addDetail(__u('Cuenta'), $accountDetails->getName()) + ->addDetail(__u('Cliente'), $accountDetails->getClientName())) + ); + + $this->returnResponse(new ApiResponse(__('Cuenta creada'), ApiResponse::RESULT_SUCCESS), $accountId); + } catch (ValidationException $e) { + $this->returnResponseException($e); + } catch (\Exception $e) { + $this->returnResponseException($e); + + processException($e); + } + } + + /** + * @throws \DI\DependencyException + * @throws \DI\NotFoundException + */ + protected function initialize() + { + $this->accountService = $this->dic->get(AccountService::class); + } +} \ No newline at end of file diff --git a/app/modules/api/Controllers/ControllerBase.php b/app/modules/api/Controllers/ControllerBase.php new file mode 100644 index 00000000..dde00655 --- /dev/null +++ b/app/modules/api/Controllers/ControllerBase.php @@ -0,0 +1,89 @@ +. + */ + +namespace SP\Modules\Api\Controllers; + +use DI\Container; +use SP\Core\Context\ApiContext; +use SP\Core\Events\EventDispatcher; + +/** + * Class ControllerBase + * @package SP\Modules\Api\Controllers + */ +abstract class ControllerBase +{ + /** + * @var Container + */ + protected $dic; + /** + * @var string + */ + protected $controllerName; + /** + * @var + */ + protected $actionName; + /** + * @var ApiContext + */ + protected $context; + /** + * @var EventDispatcher + */ + protected $eventDispatcher; + + /** + * Constructor + * + * @param Container $container + * @param $actionName + * @throws \Psr\Container\ContainerExceptionInterface + * @throws \Psr\Container\NotFoundExceptionInterface + */ + public final function __construct(Container $container, $actionName) + { + $this->dic = $container; + $this->context = $container->get(ApiContext::class); + $this->eventDispatcher = $container->get(EventDispatcher::class); + + $this->controllerName = $this->getControllerName(); + $this->actionName = $actionName; + + if (method_exists($this, 'initialize')) { + $this->initialize(); + } + } + + /** + * @return string + */ + protected function getControllerName() + { + $class = static::class; + + return substr($class, strrpos($class, '\\') + 1, -strlen('Controller')) ?: ''; + } +} \ No newline at end of file diff --git a/app/modules/api/Controllers/Traits/ResponseTrait.php b/app/modules/api/Controllers/Traits/ResponseTrait.php new file mode 100644 index 00000000..1dd7bc5c --- /dev/null +++ b/app/modules/api/Controllers/Traits/ResponseTrait.php @@ -0,0 +1,72 @@ +. + */ + +namespace SP\Modules\Api\Controllers\Traits; + +use Klein\Klein; +use SP\Api\ApiResponse; +use SP\Api\JsonRpcResponse; +use SP\Core\Exceptions\SPException; + +/** + * Trait ResponseTrait + * @package SP\Modules\Api\Controllers\Traits + * @property Klein $router + */ +trait ResponseTrait +{ + /** + * Devuelve una respuesta en formato JSON con el estado y el mensaje. + * + * {"jsonrpc": "2.0", "result": 19, "id": 3} + * + * @param ApiResponse $apiResponse + * @param int $id + * @return string La cadena en formato JSON + */ + protected function returnResponse(ApiResponse $apiResponse, $id = 0) + { + $this->router->response()->headers()->set('Content-type', 'application/json; charset=utf-8'); + + try { + exit(JsonRpcResponse::getResponse($apiResponse, $id)); + } catch (SPException $e) { + processException($e); + + exit(JsonRpcResponse::getResponseException($e, $id)); + } + } + + /** + * @param \Exception $e + * @param int $id + * @return string + */ + protected function returnResponseException(\Exception $e, $id = 0) + { + $this->router->response()->headers()->set('Content-type', 'application/json; charset=utf-8'); + + exit(JsonRpcResponse::getResponseException($e, $id)); + } +} \ No newline at end of file diff --git a/lib/SP/Api/ApiResponse.php b/lib/SP/Api/ApiResponse.php new file mode 100644 index 00000000..dca5483b --- /dev/null +++ b/lib/SP/Api/ApiResponse.php @@ -0,0 +1,80 @@ +. + */ + +namespace SP\Api; + +/** + * Class ApiResponse + * @package SP\Api + */ +class ApiResponse +{ + const RESULT_SUCCESS = 0; + const RESULT_ERROR = 1; + + /** + * @var mixed + */ + private $result; + /** + * @var int + */ + private $resultCode; + /** + * @var null + */ + private $itemId; + + /** + * ApiResponse constructor. + * @param mixed $result + * @param int $resultCode + * @param null $itemId + */ + public function __construct($result, $resultCode = self::RESULT_SUCCESS, $itemId = null) + { + $this->result = $result; + $this->resultCode = $resultCode; + $this->itemId = $itemId; + } + + /** + * @return array + */ + public function getResponse() + { + if ($this->itemId) { + return [ + 'itemId' => $this->itemId, + 'result' => $this->result, + 'resultCode' => $this->resultCode + ]; + } + + return [ + 'result' => $this->result, + 'resultCode' => $this->resultCode + ]; + } +} \ No newline at end of file diff --git a/lib/SP/Api/JsonRpcResponse.php b/lib/SP/Api/JsonRpcResponse.php new file mode 100644 index 00000000..e4077ff5 --- /dev/null +++ b/lib/SP/Api/JsonRpcResponse.php @@ -0,0 +1,66 @@ +. + */ + +namespace SP\Api; + +use SP\Util\Json; + +/** + * Class JsonRpcResponse + * @package SP\Api + */ +class JsonRpcResponse +{ + /** + * @param ApiResponse $apiResponse + * @param $id + * @return string + * @throws \SP\Core\Exceptions\SPException + */ + public static function getResponse(ApiResponse $apiResponse, $id) + { + return Json::getJson([ + 'jsonrpc' => '2.0', + 'result' => $apiResponse->getResponse(), + 'id' => $id + ]); + } + + /** + * @param \Exception $e + * @param $id + * @return string + */ + public static function getResponseException(\Exception $e, $id) + { + return json_encode([ + 'jsonrpc' => '2.0', + 'result' => [ + 'exception' => __($e->getMessage()), + 'code' => $e->getCode() + ], + 'id' => $id + ], JSON_PARTIAL_OUTPUT_ON_ERROR); + } +} \ No newline at end of file diff --git a/lib/SP/Services/ApiService/ApiService.php b/lib/SP/Services/ApiService/ApiService.php new file mode 100644 index 00000000..a2a9f30f --- /dev/null +++ b/lib/SP/Services/ApiService/ApiService.php @@ -0,0 +1,102 @@ +. + */ + +namespace SP\Services\ApiService; + +use SP\Services\Auth\AuthException; +use SP\Services\AuthToken\AuthTokenService; +use SP\Services\Service; +use SP\Services\ServiceException; +use SP\Services\Track\TrackService; + +/** + * Class ApiService + * @package SP\Services\ApiService + */ +class ApiService extends Service +{ + /** + * @var AuthTokenService + */ + protected $authTokenService; + /** + * @var TrackService + */ + protected $trackService; + + /** + * @param $actionId + * @param $authToken + * @throws ServiceException + * @throws AuthException + */ + public function authenticate($actionId, $authToken) + { + if (($authToken = $this->authTokenService->getTokenByToken($actionId, $authToken)) === false) { + $this->addTracking(); + + throw new ServiceException(__u('Acceso no permitido')); + } + + +// $this->data = $data; +// +// $this->userId = $this->ApiTokenData->getUserId(); +// +// $this->loadUserData(); +// +// if ($this->passIsNeeded()) { +// $this->doAuth(); +// } +// +// SessionFactory::setSessionType(SessionFactory::SESSION_API); +// +// $this->Log = new Log(); + } + + /** + * Añadir un seguimiento + * + * @throws AuthException + */ + protected function addTracking() + { + try { + $this->trackService->add(TrackService::getTrackRequest('api')); + } catch (\Exception $e) { + throw new AuthException( + __u('Error interno'), + AuthException::ERROR, + null, + -32601 + ); + } + } + + protected function initialize() + { + $this->authTokenService = $this->dic->get(AuthTokenService::class); + $this->trackService = $this->dic->get(TrackService::class); + } +} \ No newline at end of file diff --git a/lib/SP/Services/AuthToken/AuthTokenService.php b/lib/SP/Services/AuthToken/AuthTokenService.php index e495bd58..d5d93ff2 100644 --- a/lib/SP/Services/AuthToken/AuthTokenService.php +++ b/lib/SP/Services/AuthToken/AuthTokenService.php @@ -51,16 +51,6 @@ class AuthTokenService extends Service */ protected $authTokenRepository; - - /** - * @throws \Psr\Container\ContainerExceptionInterface - * @throws \Psr\Container\NotFoundExceptionInterface - */ - protected function initialize() - { - $this->authTokenRepository = $this->dic->get(AuthTokenRepository::class); - } - /** * @param ItemSearchData $itemSearchData * @return mixed @@ -133,7 +123,7 @@ class AuthTokenService extends Service * Injects secure data for token * * @param AuthTokenData $authTokenData - * @param string $token + * @param string $token * @throws \Defuse\Crypto\Exception\CryptoException * @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException */ @@ -207,7 +197,7 @@ class AuthTokenService extends Service /** * @param AuthTokenData $itemData - * @param string $token + * @param string $token * @return mixed * @throws SPException * @throws \Defuse\Crypto\Exception\CryptoException @@ -221,6 +211,18 @@ class AuthTokenService extends Service return $this->authTokenRepository->update($itemData); } + /** + * Devolver los datos de un token + * + * @param $actionId int El id de la accion + * @param $token string El token de seguridad + * @return false|AuthTokenData + */ + public function getTokenByToken($actionId, $token) + { + return $this->authTokenRepository->getTokenByToken($actionId, $token); + } + /** * @return array */ @@ -228,4 +230,13 @@ class AuthTokenService extends Service { return $this->authTokenRepository->getAll(); } + + /** + * @throws \Psr\Container\ContainerExceptionInterface + * @throws \Psr\Container\NotFoundExceptionInterface + */ + protected function initialize() + { + $this->authTokenRepository = $this->dic->get(AuthTokenRepository::class); + } } \ No newline at end of file diff --git a/lib/SP/Services/Service.php b/lib/SP/Services/Service.php index 74a7d707..23397dc0 100644 --- a/lib/SP/Services/Service.php +++ b/lib/SP/Services/Service.php @@ -27,7 +27,7 @@ namespace SP\Services; use DI\Container; use Psr\Container\ContainerInterface; use SP\Config\Config; -use SP\Core\Context\SessionContext; +use SP\Core\Context\ContextInterface; use SP\Core\Events\EventDispatcher; /** @@ -44,7 +44,7 @@ abstract class Service */ protected $config; /** - * @var SessionContext + * @var ContextInterface */ protected $session; /** @@ -67,7 +67,7 @@ abstract class Service { $this->dic = $dic; $this->config = $dic->get(Config::class); - $this->session = $dic->get(SessionContext::class); + $this->session = $dic->get(ContextInterface::class); $this->eventDispatcher = $dic->get(EventDispatcher::class); if (method_exists($this, 'initialize')) {