Merged in validations-architecture-backend (pull request #17)

Validations architecture backend
This commit is contained in:
Ivan Diaz 2016-07-08 04:01:54 -03:00
commit 48d5cf9226
11 changed files with 142 additions and 64 deletions

View File

@ -1,7 +1,8 @@
{
"require": {
"slim/slim": "~2.0",
"gabordemooij/redbean": "~4.2"
"gabordemooij/redbean": "~4.2",
"respect/validation": "^1.1"
},
"require-dev": {
"phpunit/phpunit": "5.0.*"

View File

@ -1,5 +1,7 @@
<?php
use Respect\Validation\Validator as DataValidator;
class CreateController extends Controller {
const PATH = '/create';
@ -8,44 +10,36 @@ class CreateController extends Controller {
private $departmentId;
private $language;
public function handler() {
$this->requestTicketData();
$validateResult = $this->validateData();
if ($validateResult !== true) {
Response::respondError($validateResult);
} else {
$this->storeTicket();
Response::respondSuccess();
}
public function validations() {
return [
'permission' => 'any',
'requestData' => [
'title' => [
'validation' => DataValidator::length(3, 30),
'error' => ERRORS::INVALID_TITLE
],
'content' => [
'validation' => DataValidator::length(10, 500),
'error' => ERRORS::INVALID_CONTENT
]
]
];
}
private function requestTicketData() {
public function handler() {
$this->storeRequestData();
$this->storeTicket();
Response::respondSuccess();
}
private function storeRequestData() {
$this->title = Controller::request('title');
$this->content = Controller::request('content');
$this->departmentId = Controller::request('departmentId');
$this->language = Controller::request('language');
}
private function validateData() {
if (strlen($this->title) < 3) {
return ERRORS::SHORT_TITLE;
}
if (strlen($this->title) > 30) {
return ERRORS::LONG_TITLE;
}
if (strlen($this->content) < 5) {
return ERRORS::SHORT_CONTENT;
}
if (strlen($this->content) > 500) {
return ERRORS::LONG_CONTENT;
}
return true;
}
private function storeTicket() {
$ticket = new Ticket();
$ticket->setProperties(array(
@ -55,7 +49,7 @@ class CreateController extends Controller {
'language' => $this->language,
'department' => $this->departmentId,
'file' => '',
'date' => date("F j, Y, g:i a"),
'date' => date('F j, Y, g:i a'),
'unread' => false,
'closed' => false,
'author' => '',

View File

@ -5,6 +5,13 @@ class LoginController extends Controller {
private $userInstance;
private $session;
public function validations() {
return [
'permission' => 'any',
'requestData' => []
];
}
public function handler() {
if ($this->isAlreadyLoggedIn()) {

View File

@ -2,6 +2,13 @@
class LogoutController extends Controller {
const PATH = '/logout';
public function validations() {
return [
'permission' => 'any',
'requestData' => []
];
}
public function handler() {
$session = Session::getInstance();
$session->closeSession();

View File

@ -3,6 +3,13 @@
class SignUpController extends Controller {
const PATH = '/signup';
public function validations() {
return [
'permission' => 'any',
'requestData' => []
];
}
public function handler() {
$email = Controller::request('email');
$password = Controller::request('password');

View File

@ -20,13 +20,13 @@ spl_autoload_register(function ($class) {
$classPath = "models/{$class}.php";
if(file_exists($classPath)) {
include $classPath;
include_once $classPath;
}
});
// LOAD CONTROLLERS
foreach (glob('controllers/*.php') as $controller) {
include $controller;
include_once $controller;
}
$app->run();

View File

@ -1,4 +1,5 @@
<?php
require_once 'libs/Validator.php';
abstract class Controller {
@ -6,40 +7,37 @@ abstract class Controller {
* Instance-related stuff
*/
abstract public function handler();
abstract public function validations();
public function getHandler() {
return function () {
try {
$this->validate();
} catch (ValidationException $exception) {
Response::respondError($exception->getMessage());
return;
}
$this->handler();
};
}
public function validate() {
$validator = new Validator();
$validator->validate($this->validations());
}
public static function request($key) {
$app = self::getAppInstance();
return $app->request()->post($key);
}
public static function checkUserLogged() {
$session = Session::getInstance();
return $session->checkAuthentication(array(
'user_id' => self::request('csrf_userid'),
'token' => self::request('csrf_token')
));
}
public static function getLoggedUser() {
return User::getUser((int)self::request('csrf_userid'));
}
public static function checkStaffLogged() {
return self::checkUserLogged() && (self::getLoggedUser()->admin === 1);
}
public static function checkAdminLogged() {
return self::checkUserLogged() && (self::getLoggedUser()->admin === 2);
}
public static function getAppInstance() {
return \Slim\Slim::getInstance();
}

61
server/libs/Validator.php Normal file
View File

@ -0,0 +1,61 @@
<?php
require_once 'libs/Controller.php';
use Respect\Validation\Validator as DataValidator;
class ValidationException extends Exception {}
class Validator {
public function validate($config) {
$this->validatePermissions($config['permission']);
$this->validateAllRequestData($config['requestData']);
}
private function validatePermissions($permission) {
$permissions = [
'any' => true,
'user' => $this->isUserLogged(),
'staff' => $this->isStaffLogged(),
'admin' => $this->isAdminLogged()
];
if (!$permissions[$permission]) {
throw new ValidationException(ERRORS::NO_PERMISSION);
}
}
private function validateAllRequestData($requestDataValidations) {
foreach ($requestDataValidations as $requestDataKey => $requestDataValidationConfig) {
$requestDataValue = Controller::request($requestDataKey);
$requestDataValidator = $requestDataValidationConfig['validation'];
$requestDataValidationErrorMessage = $requestDataValidationConfig['error'];
$this->validateData($requestDataValue, $requestDataValidator, $requestDataValidationErrorMessage);
}
}
private function validateData($value, DataValidator $dataValidator, $error) {
if (!$dataValidator->validate($value)) {
throw new ValidationException($error);
}
}
private function isUserLogged() {
$session = Session::getInstance();
return $session->checkAuthentication(array(
'userId' => Controller::request('csrf_userid'),
'token' => Controller::request('csrf_token')
));
}
private function isStaffLogged() {
return $this->isUserLogged() && (Controller::getLoggedUser()->admin === 1);
}
private function isAdminLogged() {
return $this->isUserLogged() && (Controller::getLoggedUser()->admin === 2);
}
}

View File

@ -2,8 +2,7 @@
class ERRORS {
const INVALID_CREDENTIALS = 'User or password is not defined';
const SESSION_EXISTS = 'User is already logged in';
const SHORT_TITLE = 'Title is too short';
const LONG_TITLE = 'Title is very long';
const SHORT_CONTENT = 'Content is too short';
const LONG_CONTENT = 'Content is very long';
const NO_PERMISSION = 'You have no permission to access';
const INVALID_TITLE = 'Invalid title';
const INVALID_CONTENT = 'Invalid content';
}

View File

@ -38,8 +38,12 @@ class Session {
}
public function checkAuthentication($data) {
return $this->getStoredData('userId') === $data['userId'] &&
$this->getStoredData('token') === $data['token'];
$userId = $this->getStoredData('userId');
$token = $this->getStoredData('token');
return $userId && $token &&
$userId === $data['userId'] &&
$token === $data['token'];
}
public function isLoggedWithId($userId) {

View File

@ -1,11 +1,11 @@
describe '/user/login' do
describe '/ticket/create' do
it 'should fail if title is too short' do
result = request('/ticket/create',{
result = request('/ticket/create', {
title: 'GG'
})
(result['status']).should.equal('fail')
(result['message']).should.equal('Title is too short')
(result['message']).should.equal('Invalid title')
end
@ -15,7 +15,7 @@ describe '/user/login' do
})
(result['status']).should.equal('fail')
(result['message']).should.equal('Title is very long')
(result['message']).should.equal('Invalid title')
end
@ -26,7 +26,7 @@ describe '/user/login' do
})
(result['status']).should.equal('fail')
(result['message']).should.equal('Content is too short')
(result['message']).should.equal('Invalid content')
end
it 'should fail if content is very long' do
@ -39,7 +39,7 @@ describe '/user/login' do
})
(result['status']).should.equal('fail')
(result['message']).should.equal('Content is very long')
(result['message']).should.equal('Invalid content')
end