diff --git a/Makefile b/Makefile index 51424f906cf5b58dd9b5d72db30ca2b787f7824b..0f5de56e3bd59755b829eb6a38692d8ba3a8df8d 100644 --- a/Makefile +++ b/Makefile @@ -24,6 +24,7 @@ copy_files: Tasker_deploy \~dev_rating/ $(DST_PATH) # server deploy without db fix and stored stuff update +# ToDo: make like sed -i 's/~dev_rating/$target/g' $(DST_PATH)/.htaccess release_no_db: copy_files sed -i 's/~dev_rating//g' $(DST_PATH)/.htaccess sed -i 's/\/~dev_rating//g' $(DST_PATH)/application/bootstrap.php diff --git a/db/migrations/R__api's_procedures.sql b/db/migrations/R__api's_procedures.sql new file mode 100644 index 0000000000000000000000000000000000000000..95fcda9e7580c8c552e3af87fc76f3b95f0147db --- /dev/null +++ b/db/migrations/R__api's_procedures.sql @@ -0,0 +1,25 @@ +START TRANSACTION; + +DELIMITER // + +DROP PROCEDURE IF EXISTS GetDepartmentIdByName// +CREATE PROCEDURE GetDepartmentIdByName( + IN pDepartmentName varchar(200)) + BEGIN + SELECT departments.ID as ID + FROM departments + WHERE departments.Name = pDepartmentName; + END// + +DROP PROCEDURE IF EXISTS GetJobPositionIdByName// +CREATE PROCEDURE GetJobPositionIdByName( + IN pJobPositionName varchar(200)) + BEGIN + SELECT job_positions.ID as ID + FROM job_positions + WHERE job_positions.Name = pJobPositionName; + END// + +DELIMITER ; + +COMMIT ; diff --git a/~dev_rating/application/bootstrap.php b/~dev_rating/application/bootstrap.php index 252f9d6cca7be5637d5b7347c4b85232a46289a7..32df89579d02b4a53a5c3b09496155b7be01abc4 100644 --- a/~dev_rating/application/bootstrap.php +++ b/~dev_rating/application/bootstrap.php @@ -140,6 +140,7 @@ Kohana::modules([ // dedicated routes require APPPATH . 'routes/api.php'; +require APPPATH . 'routes/api/v0.php'; require APPPATH . 'routes/dean_office.php'; diff --git a/~dev_rating/application/classes/Controller/Api/V0/Department.php b/~dev_rating/application/classes/Controller/Api/V0/Department.php new file mode 100644 index 0000000000000000000000000000000000000000..158588bcba734e8ce4438d59cd4cc433242eadbe --- /dev/null +++ b/~dev_rating/application/classes/Controller/Api/V0/Department.php @@ -0,0 +1,18 @@ +<?php + +class Controller_Api_V0_Department extends Controller_Handler_Api +{ + public function action_get_idByName() { + $name = $this->request->query('name'); + + try { + $id = Model_Faculties::getDepartmentIdByName($name); + } + catch (InvalidArgumentException $e) { + $this->notFoundError($e->getMessage()); + } + + return $id; + } + +} diff --git a/~dev_rating/application/classes/Controller/Api/V0/Student.php b/~dev_rating/application/classes/Controller/Api/V0/Student.php new file mode 100644 index 0000000000000000000000000000000000000000..6a984eceafadc7c00caa2f8c1740b781f47a024e --- /dev/null +++ b/~dev_rating/application/classes/Controller/Api/V0/Student.php @@ -0,0 +1,20 @@ +<?php + +class Controller_Api_V0_Student extends Controller_Handler_Api +{ + public function action_get_index() { + $this->response->body( '{ what: get index }' ); + + return '{ what: get index }'; //$this->response; + } + + public function action_put_index() { + $firstName = $this->request->query('firstName'); + + return '{ what: put index, id: '.$firstName.' }'; + } + + public function action_get_list_by_name() { + return '{ what: nothing }'; + } +} diff --git a/~dev_rating/application/classes/Controller/Api/V0/Subject.php b/~dev_rating/application/classes/Controller/Api/V0/Subject.php new file mode 100644 index 0000000000000000000000000000000000000000..7aeb6fcb0ed313348e4141e49c8c9f4ebcfb4b0d --- /dev/null +++ b/~dev_rating/application/classes/Controller/Api/V0/Subject.php @@ -0,0 +1,20 @@ +<?php + +class Controller_Api_V0_Subject extends Controller_Handler_Api +{ + public function action_get_index() { + return '{ name: "Русский язык", + grade: 1, + group: 2 }'; + } + + public function action_put_index() { + $firstName = $this->request->query('firstName'); + + return '{ what: put index, id: '.$firstName.' }'; + } + + public function action_get_list_by_name() { + return '{ what: nothing }'; + } +} diff --git a/~dev_rating/application/classes/Controller/Api/V0/Teacher.php b/~dev_rating/application/classes/Controller/Api/V0/Teacher.php new file mode 100644 index 0000000000000000000000000000000000000000..be9ee50334984f0b76604355c703d4075ec28d42 --- /dev/null +++ b/~dev_rating/application/classes/Controller/Api/V0/Teacher.php @@ -0,0 +1,67 @@ +<?php + +class Controller_Api_V0_Teacher extends Controller_Handler_Api +{ + // ToDo: The functions is copy-paste from departments API. Should be extracted. + private function getDepIDByName($name) { + try { + $id = Model_Faculties::getDepartmentIdByName($name); + } + catch (InvalidArgumentException $e) { + return NULL; + } + return $id; + } + + private function createTeacher($data) { + $teacher = Model_Teacher::make() + ->jobPosition($data->jobPositionID) + ->department($data->departmentID) + ->firstName($data->firstName) + ->secondName($data->secondName) + ->lastName($data->lastName) + ->create(); + return ['ID' => $teacher->ID, 'Code' => $teacher->ActivationCode]; + } + + private function normolizeTeacherData($data) { + if ( $data->departmentID === NULL && $data->departmentName !== NULL) + $data->departmentID = $this->getDepIDByName($data->departmentName); + + if ( $data->jobPositionID === NULL && $data->jobPositionName !== NULL ) + $data->jobPositionID = Model_Faculties::getJobPositionIdByName($data->jobPositionName); + + return $data; + } + + public function action_put_index() { + try { + if ( $this->request->query('batch') !== NULL ) { + $data = json_decode($this->request->body()); + + $res = []; + foreach ($data as $item) { + $data = $this->normolizeTeacherData($item); + $res[] = $this->createTeacher($data); + } + } else { + $data = [ 'firstName' => $this->request->query('firstName') + , 'secondName' => $this->request->query('secondName') + , 'lastName' => $this->request->query('lastName') + , 'departmentName' => $this->request->query('departmentName') + , 'departmentID' => $this->request->query('departmentID') + , 'jobPositionName' => $this->request->query('jobPositionName') + , 'jobPositionID' => $this->request->query('jobPositionID') + , 'status' => $this->request->query('status')]; + + $data = $this->normolizeTeacherData((object)$data); + $res[] = $this->createTeacher($data); + } + } catch (Exception $e) { + $this->badRequestError($e->getMessage()); + } + + return $res; + } + +} diff --git a/~dev_rating/application/classes/Controller/Handler/Api.php b/~dev_rating/application/classes/Controller/Handler/Api.php index b03aa2cda41ec66161a4ac8f5c2a51070c43399e..c0e8781c95df03abc1ca2a4c5816198761f95996 100644 --- a/~dev_rating/application/classes/Controller/Handler/Api.php +++ b/~dev_rating/application/classes/Controller/Handler/Api.php @@ -1,9 +1,5 @@ <?php defined('SYSPATH') OR die('No direct script access.'); -/** - * Class Controller_Handler_Api - * Not stable, use it only if you are Igor. - */ abstract class Controller_Handler_Api extends Controller { /** @var array */ @@ -15,13 +11,26 @@ abstract class Controller_Handler_Api extends Controller /** @var User */ protected $user; + /** @var Token */ + protected $token; + public function before() { // todo: var $user should be defined here // either by GET param (token), // or on the session variables. + $this->token = $this->request->query('token'); + if ( $this->token != '' ) + { + $ok = User::instance()->signInByToken($this->token); + if (!$ok) $this->fail(); + } + $this->user = User::instance(); + if (!$this->user->isAuthorized()) + $this->fail(); + $this->get =& $_GET; $this->post =& $_POST; } @@ -35,7 +44,7 @@ abstract class Controller_Handler_Api extends Controller // If the action doesn't exist, it's a 404 if (!method_exists($this, $action)) { - throw HTTP_Exception::factory(404, + throw HTTP_API_Exception::factory(404, 'The requested URL :uri was not found on this server.', [':uri' => $this->request->uri()] )->request($this->request); @@ -46,6 +55,8 @@ abstract class Controller_Handler_Api extends Controller $data = $this->{$action}(); $answer = ['response' => $data ?: '']; $json_answer = json_encode($answer, JSON_UNESCAPED_UNICODE); + } catch (HTTP_API_Exception $e) { // Let HTTP errors go throw away + throw $e; } catch (Exception $e) { // todo: improve error capturing while ($e->getPrevious()) @@ -126,4 +137,25 @@ abstract class Controller_Handler_Api extends Controller return $result; } + + private function fail() { + throw HTTP_API_Exception::factory(403, + 'Token is broken.', + [':uri' => $this->request->uri()] + )->request($this->request); + } + + protected function notFoundError($message) { + throw HTTP_API_Exception::factory(404, + $message, + [':uri' => $this->request->uri()] + )->request($this->request); + } + + protected function badRequestError($message) { + throw HTTP_API_Exception::factory(400, + $message, + [':uri' => $this->request->uri()] + )->request($this->request); + } } \ No newline at end of file diff --git a/~dev_rating/application/classes/Error.php b/~dev_rating/application/classes/Error.php index 42f14b6c2977e912b89ae96d0088ed0c2b73b99c..c9202c8d11ee64848c86a3f0a05dd315cf0e1363 100644 --- a/~dev_rating/application/classes/Error.php +++ b/~dev_rating/application/classes/Error.php @@ -6,4 +6,5 @@ class Error { const DISCIPLINE_IS_LOCKED = 'Discipline is locked'; const DISCIPLINE_NOT_FOUND = 'Discipline does not exist'; const INVALID_PARAMETERS = 'Invalid parameters'; + const DEPARTMENT_NOT_FOUND = 'Department does not exist'; } diff --git a/~dev_rating/application/classes/Model/Faculties.php b/~dev_rating/application/classes/Model/Faculties.php index 00bf19d90dd4d1fd24726ecad5da1800a5fc6024..9f6898ec47206421dd0b44da6459ad1fc31266d4 100644 --- a/~dev_rating/application/classes/Model/Faculties.php +++ b/~dev_rating/application/classes/Model/Faculties.php @@ -25,4 +25,28 @@ class Model_Faculties extends Model return $list; } + + public static function getDepartmentIdByName($departmentName) { + $sql = 'CALL `GetDepartmentIdByName`(:name)'; + $id = DB::query(Database::SELECT, $sql) + ->param(':name', $departmentName) + ->execute(); + + if ($id->count() == 0) + throw new InvalidArgumentException(Error::DEPARTMENT_NOT_FOUND); + + return $id->get('ID'); + } + + public static function getJobPositionIdByName($jobPositionName) { + $sql = 'CALL `GetJobPositionIdByName`(:name)'; + $id = DB::query(Database::SELECT, $sql) + ->param(':name', $jobPositionName) + ->execute(); + + if ($id->count() == 0) + return NULL; + + return $id->get('ID'); + } } diff --git a/~dev_rating/application/classes/User.php b/~dev_rating/application/classes/User.php index 67cf33c39a15f76fcded1d23af4c64bf8c940d40..f649f47c840ee025e90bba5cd33113a2572d3123 100644 --- a/~dev_rating/application/classes/User.php +++ b/~dev_rating/application/classes/User.php @@ -158,6 +158,11 @@ class User implements ArrayAccess return $this->initSession($id, $this->hash($password)); } + public function signInByToken($token) { + $id = (int) Model_Account::checkAuthToken($token); + return $this->initSession($id, $this->hash($token)); + } + protected function initSession($id, $passHash) { if ($id <= 0) return false; diff --git a/~dev_rating/application/routes/api/v0.php b/~dev_rating/application/routes/api/v0.php new file mode 100644 index 0000000000000000000000000000000000000000..285d27c6ddf0f70096de52e9567641259e2abefd --- /dev/null +++ b/~dev_rating/application/routes/api/v0.php @@ -0,0 +1,92 @@ +<?php +Route::set('apiv0:teacher', 'api/v0/teacher') + ->filter(function($route, $params, $request) + { + // Prefix the method to the action name + $params['action'] = strtolower($request->method()).'_'.$params['action']; + return $params; // Returning an array will replace the parameters + }) + ->defaults([ + 'action' => 'index', + 'directory' => 'Api/V0', + 'controller' => 'Teacher', + ]); + +Route::set('apiv0:department', 'api/v0/department') + ->filter(function($route, $params, $request) + { + // Prefix the method to the action name + $params['action'] = strtolower($request->method()).'_'.$params['action']; + return $params; // Returning an array will replace the parameters + }) + ->defaults([ + 'action' => 'index', + 'directory' => 'Api/V0', + 'controller' => 'Department', + ]); + +Route::set('apiv0:department:another', 'api/v0/department(/<action>(/<id>))', ['id' => '\d+']) + ->filter(function($route, $params, $request) + { + // Prefix the method to the action name + $params['action'] = strtolower($request->method()).'_'.$params['action']; + return $params; // Returning an array will replace the parameters + }) + ->defaults([ + 'action' => 'index', + 'directory' => 'Api/V0', + 'controller' => 'Department', + ]); + +Route::set('apiv0:student', 'api/v0/student') + ->filter(function($route, $params, $request) + { + // Prefix the method to the action name + $params['action'] = strtolower($request->method()).'_'.$params['action']; + return $params; // Returning an array will replace the parameters + }) + ->defaults([ + 'action' => 'index', + 'directory' => 'Api/V0', + 'controller' => 'Student', + ]); + +Route::set('apiv0:student:get', 'api/v0/student(/<id>)', ['id' => '\d+']) + ->filter(function($route, $params, $request) + { + // Prefix the method to the action name + $params['action'] = strtolower($request->method()).'_'.$params['action']; + return $params; // Returning an array will replace the parameters + }) + ->defaults([ + 'action' => 'index', + 'directory' => 'Api/V0', + 'controller' => 'Student', + ]); + +Route::set('apiv0:student:another', 'api/v0/student(/<action>(/<id>))', ['id' => '\d+']) + ->filter(function($route, $params, $request) + { + // Prefix the method to the action name + $params['action'] = strtolower($request->method()).'_'.$params['action']; + return $params; // Returning an array will replace the parameters + }) + ->defaults([ + 'action' => 'index', + 'directory' => 'Api/V0', + 'controller' => 'Student', + ]); + + +Route::set('apiv0:subject', 'api/v0/subject') + ->filter(function($route, $params, $request) + { + // Prefix the method to the action name + $params['action'] = strtolower($request->method()).'_'.$params['action']; + return $params; // Returning an array will replace the parameters + }) + ->defaults([ + 'action' => 'index', + 'directory' => 'Api/V0', + 'controller' => 'Subject', + ]); diff --git a/~dev_rating/system/classes/HTTP/API/Exception/403.php b/~dev_rating/system/classes/HTTP/API/Exception/403.php new file mode 100644 index 0000000000000000000000000000000000000000..93bd98d722bb52b4758def6d903e43dd1104f06f --- /dev/null +++ b/~dev_rating/system/classes/HTTP/API/Exception/403.php @@ -0,0 +1,5 @@ +<?php defined('SYSPATH') OR die('No direct script access.'); + +class HTTP_API_Exception_403 extends HTTP_API_Exception { + protected $_code = 403; +} diff --git a/~dev_rating/system/classes/HTTP/API/Exception/404.php b/~dev_rating/system/classes/HTTP/API/Exception/404.php new file mode 100644 index 0000000000000000000000000000000000000000..2cd10fe14dd1749a551f399dd4154b816c644d7a --- /dev/null +++ b/~dev_rating/system/classes/HTTP/API/Exception/404.php @@ -0,0 +1,5 @@ +<?php defined('SYSPATH') OR die('No direct script access.'); + +class HTTP_API_Exception_404 extends HTTP_API_Exception { + protected $_code = 404; +}