Skip to content
Snippets Groups Projects
Commit 342e9f7c authored by Artem Konenko's avatar Artem Konenko Committed by Роман Штейнберг
Browse files

#119 Add teacher insertion to API

* Add getDepartmentIdByName API (with auxiliary procedure)
* Add teacher insertion (only one at the time)
* Add token checking to user authorization in API handler
* Add throwing away HTTP exceptions in API handler
* Add functions for throwing HTTP exceptions (403, 404)
* Add singing in by tokens in User
* Add autocompleting department's ID by name
* Add error handling (show 400 bad request, if any require data missed)
* Add batch processing
* Add autocompleting job position ID by name
parent 04565842
Branches
Tags
No related merge requests found
Showing
with 321 additions and 5 deletions
......@@ -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
......
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 ;
......@@ -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';
......
<?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;
}
}
<?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 }';
}
}
<?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 }';
}
}
<?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;
}
}
<?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
......@@ -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';
}
......@@ -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');
}
}
......@@ -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;
......
<?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',
]);
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_API_Exception_403 extends HTTP_API_Exception {
protected $_code = 403;
}
<?php defined('SYSPATH') OR die('No direct script access.');
class HTTP_API_Exception_404 extends HTTP_API_Exception {
protected $_code = 404;
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment