diff --git a/RestapiModule.php b/RestapiModule.php index 8102e45..b51d425 100644 --- a/RestapiModule.php +++ b/RestapiModule.php @@ -59,6 +59,9 @@ public function getCheckAttributeAccessControl($model) { } protected function init() { + Yii::import($this->getId().".components.*"); + Yii::import($this->getId().".models.*"); + if (empty($this->modelMap)) { Yii::log("Model Map is not set. No Model will rest.", CLogger::LEVEL_ERROR, "restapi"); } diff --git a/components/RestApiAccessControl.php b/components/RestApiAccessControl.php index 3712f4f..f76fb97 100644 --- a/components/RestApiAccessControl.php +++ b/components/RestApiAccessControl.php @@ -1,6 +1,4 @@ user) return $this->user->username; else return ''; } -} +} \ No newline at end of file diff --git a/controllers/ApiController.php b/controllers/ApiController.php index 6ea87d0..2614c95 100644 --- a/controllers/ApiController.php +++ b/controllers/ApiController.php @@ -1,281 +1,279 @@ -layout = false; - Yii::app()->getErrorHandler()->errorAction = 'restapi/api/error'; - if (isset($_GET['model'])) { - if (!$this->getModule()->checkModel($_GET['model'])) { - throw new CHttpException(501, $_GET['model'].' is not implemented'); - } else { - $_GET['model'] = $this->getModule()->includeModel($_GET['model']); - } - } else { - if (in_array($action->getId(), array('list', 'view', 'update', 'delete', 'create'))) { - throw new CHttpException(501, 'Model is not specify'); - } - } - return parent::beforeAction($action); - } - - public function actionError() { - $error = Yii::app()->getErrorHandler()->getError(); - Yii::log($error['trace'], CLogger::LEVEL_ERROR, "restapi"); - $this->renderText($error['message']); - Yii::app()->end(1); - } - - /** - * Get Token for API Access. - */ - public function actionGetToken($api, $secret) { - $identity = new RestApiUserIdentity(); - $identity->setKeySecret($api, $secret); - if ($identity->authenticate()) { - $apiuser = $identity->getApiUser(); - if ($apiuser->tokenExpired()) { - $apiuser->generateNewToken(); - if ($apiuser->save()) { - $result = array('success'=>true, 'token'=>$apiuser->token, 'expiry'=>strtotime($apiuser->token_expire)); - } else { - $result = array('success'=>false, 'message'=>"Can not save the generated token"); - } - } else { - $result = array('success'=>true, 'token'=>$apiuser->token, 'expiry'=>strtotime($apiuser->token_expire)); - } - } else { - $result = array('success'=>false, 'message'=>"Access Denied"); - } - echo json_encode($result); - Yii::app()->end(); - } - - /** - * This method is invoked right after an action is executed. - * You may override this method to do some postprocessing for the action. - * @param CAction $action the action just executed. - */ - protected function afterAction($action) { - if (empty($this->result) && !is_array($this->result)) throw new CHttpException(404, "Not found with ID:".$_GET['id']); - $list = CommonRest::buildModelJsonReply($this->result, $_GET['model']); - header('content-type: application/json'); - $this->renderText(CJSON::encode(array("root"=>$list, "success"=>true))); - } - - public function actionList($model) { - if ($this->getModule()->accessControl) { - /** @var CWebUser $user */ - $user = Yii::app()->user; - if (!$user->checkAccess("list/$model", array(), true)) { - throw new CHttpException(403, "Read access on $model denied."); - } - } - $modelInstance = new $model(); - $limit = isset($_GET['limit'])?$_GET['limit']:50; - $start = isset($_GET['start'])?$_GET['start']:0; - if (isset($_GET['page'])) { - $start += (($_GET['page']-1) * $limit); - } - if ($modelInstance instanceof CActiveRecord) { - $c = new CDbCriteria($this->getModule()->getDefaultCriteria($model)); - $c->offset = $start; - $c->limit = $limit; - if (isset($_GET['filter'])) { - $filter = CJSON::decode($_GET['filter']); - foreach ($filter as $field=>$condition) { - if (is_array($condition)) { - if (is_int($field)) { - $c->addCondition($condition['property'] . " = " . $condition["value"]); - } else $c->addCondition("$field $condition[0] $condition[1]"); - } else $c->addCondition("$field = $condition"); - } - } - if (isset($_GET['sort'])) { - $sort = CJSON::decode($_GET['sort']); - if (is_array($sort)) { - foreach ($sort as $s) { - $c->order .= $s['property'] . ' ' . $s['direction'] . ','; - } - $c->order = substr($c->order, 0, -1); - } else { - $c->order = $_GET['sort']; - } - } - if (isset($_GET['group'])) { - $group = CJSON::decode($_GET['group']); - if (is_array($group)) { - foreach ($group as $s) { - $c->group .= $s['property'] . ','; - } - $c->group = substr($c->group, 0, -1); - } else { - $c->group = $_GET['group']; - } - } - $this->result = CActiveRecord::model($model)->findAll($c); - } else if (@class_exists('EActiveResource') && $modelInstance instanceof EActiveResource) { - /** @var $list EActiveResource[] */ - $this->result = EActiveResource::model($model)->findAll(); - } else if (@class_exists('EMongoDocument') && $modelInstance instanceof EMongoDocument) { - $mc = new EMongoCriteria(); - $mc->setLimit($limit); - $mc->setOffset($start); - if (isset($_GET['filter'])) { - $filter = CJSON::decode($_GET['filter']); - foreach ($filter as $field=>$condition) { - if (is_array($condition)) { - if (is_int($field)) { - $field = $condition['property']; - $mc->$field = $condition["value"]; - } else $mc->$field($condition[0], $condition[1]); - } else $mc->$field = $condition; - } - } - if (isset($_GET['sort'])) $mc->setSort($_GET['sort']); - $this->result = EMongoDocument::model($model)->findAll($mc); - } - if ($this->getModule()->accessControl) { - /** @var CWebUser $user */ - $user = Yii::app()->user; - foreach ($this->result as $key=>$item) { - if (!$user->checkAccess("read/$model", array('model'=>$item), true)) { - Yii::log("DENIED: Try to list model $model ID: ".$item->getPrimaryKey(), CLogger::LEVEL_INFO, "restapi"); - unset($this->result[$key]); - } - } - $this->result = array_values($this->result); - } - } - - public function actionView($model, $id) { - $modelInstance = new $model(); - if ($modelInstance instanceof CActiveRecord) { - $this->result = CActiveRecord::model($model)->findByPk($id); - } else if (@class_exists('EMongoDocument') && $modelInstance instanceof EMongoDocument) { - $this->result = EMongoDocument::model($model)->findByPk(new MongoId($id)); - } else if ($modelInstance instanceof EActiveResource) { - $this->result = EActiveResource::model($model)->findById($id); - } - if ($this->getModule()->accessControl) { - /** @var CWebUser $user */ - $user = Yii::app()->user; - if (!$user->checkAccess("view/$model", array('model'=>$this->result), true)) { - throw new CHttpException(403, "Read access on $model denied."); - } - } - } - - public function actionUpdate($model, $id, $type = 'update') { - $this->actionView($model, $id); - if (is_null($this->result)) { - throw new CHttpException(400, "Did not find any model with ID: " . $id); - } - $modelInstance = $this->result; - $modelInstance->setScenario("update"); - if ($this->getModule()->accessControl) { - $modelInstance->setScenario($type); - /** @var CWebUser $user */ - $user = Yii::app()->user; - if ($type !== "update") $type = "update.".$type; - if (!$user->checkAccess("$type/$model", array('model'=>$modelInstance, 'scenario'=>$type), true)) { - throw new CHttpException(403, "Write access on $model denied."); - } - } - $vars = CJSON::decode(file_get_contents('php://input')); - if (!is_array($vars)) { - Yii::log("Input need to be Json: ".var_export($vars, true), CLogger::LEVEL_ERROR, "restapi"); - throw new CHttpException(500, "Input need to be JSON"); - } - if ($this->getModule()->getCheckAttributeAccessControl($_GET['model'])) { - /** @var CWebUser $user */ - $user = Yii::app()->user; - foreach ($vars as $field=>$value) { - if (!$user->checkAccess("update/".$_GET['model']."/".$field, array('model'=>$modelInstance), true)) { - unset($vars[$field]); - Yii::log("DENIED: Try to set attribute: $field with $value", CLogger::LEVEL_INFO, "restapi"); - } - } - } - $modelInstance->setAttributes($vars); - if ($modelInstance->save()) { - $modelInstance->refresh(); - } else { - Yii::log(implode("\n", $modelInstance->getErrors()), CLogger::LEVEL_ERROR, "restapi"); - throw new CHttpException(500, "Can not save model ID: " . $id); - } - } - - public function actionDelete($model, $id) { - $this->actionView($model, $id); - if (is_null($this->result)) { - throw new CHttpException(400, "Did not find any model with ID: " . $id); - } - $modelInstance = $this->result; - if ($this->getModule()->accessControl) { - /** @var CWebUser $user */ - $user = Yii::app()->user; - if (!$user->checkAccess("delete/$model", array('model'=>$modelInstance), true)) { - throw new CHttpException(403, "Write access on $model denied."); - } - } - if (!$modelInstance->delete()) { - Yii::log(implode("\n", $modelInstance->getErrors()), CLogger::LEVEL_ERROR, "restapi"); - throw new CHttpException(500, "Can not delete model ID: " . $id); - } else { - Yii::app()->end(); - } - } - - public function actionCreate($model) { - $modelInstance = new $model(); - $vars = CJSON::decode(file_get_contents('php://input')); - if (!is_array($vars)) { - Yii::log("Input need to be Json: ".var_export($vars, true), CLogger::LEVEL_ERROR, "restapi"); - throw new CHttpException(500, "Input need to be JSON"); - } - if ($this->getModule()->accessControl) { - /** @var CWebUser $user */ - $user = Yii::app()->user; - if (!$user->checkAccess("create/$model", array('model'=>$modelInstance), true)) { - throw new CHttpException(403, "Write access on $model denied."); - } - } - if ($this->getModule()->getCheckAttributeAccessControl($_GET['model'])) { - /** @var CWebUser $user */ - $user = Yii::app()->user; - foreach ($vars as $field=>$value) { - if (!$user->checkAccess("update/".$_GET['model']."/".$field, array('model'=>$modelInstance), true)) { - unset($vars[$field]); - Yii::log("DENIED: Try to set attribute: $field with $value", CLogger::LEVEL_INFO, "restapi"); - } - } - } - $modelInstance->setAttributes($vars); - if ($modelInstance->save()) { - $modelInstance->refresh(); - $this->result = $modelInstance; - } else { - Yii::log(implode("\n", $modelInstance->getErrors()), CLogger::LEVEL_ERROR, "restapi"); - throw new CHttpException(500, "Can not save model: " . $model); - } - } -} +layout = false; + Yii::app()->getErrorHandler()->errorAction = 'restapi/api/error'; + if (isset($_GET['model'])) { + if (!$this->getModule()->checkModel($_GET['model'])) { + throw new CHttpException(501, $_GET['model'].' is not implemented'); + } else { + $_GET['model'] = $this->getModule()->includeModel($_GET['model']); + } + } else { + if (in_array($action->getId(), array('list', 'view', 'update', 'delete', 'create'))) { + throw new CHttpException(501, 'Model is not specify'); + } + } + return parent::beforeAction($action); + } + + public function actionError() { + $error = Yii::app()->getErrorHandler()->getError(); + Yii::log($error['trace'], CLogger::LEVEL_ERROR, "restapi"); + $this->renderText($error['message']); + Yii::app()->end(1); + } + + /** + * Get Token for API Access. + */ + public function actionGetToken($api, $secret) { + $identity = new RestApiUserIdentity(); + $identity->setKeySecret($api, $secret); + if ($identity->authenticate()) { + $apiuser = $identity->getApiUser(); + if ($apiuser->tokenExpired()) { + $apiuser->generateNewToken(); + if ($apiuser->save()) { + $result = array('success'=>true, 'token'=>$apiuser->token, 'expiry'=>strtotime($apiuser->token_expire)); + } else { + $result = array('success'=>false, 'message'=>"Can not save the generated token"); + } + } else { + $result = array('success'=>true, 'token'=>$apiuser->token, 'expiry'=>strtotime($apiuser->token_expire)); + } + } else { + $result = array('success'=>false, 'message'=>"Access Denied"); + } + echo json_encode($result); + Yii::app()->end(); + } + + /** + * This method is invoked right after an action is executed. + * You may override this method to do some postprocessing for the action. + * @param CAction $action the action just executed. + */ + protected function afterAction($action) { + if (empty($this->result) && !is_array($this->result)) throw new CHttpException(404, "Not found with ID:".$_GET['id']); + $list = CommonRest::buildModelJsonReply($this->result, $_GET['model']); + header('content-type: application/json'); + $this->renderText(CJSON::encode(array("root"=>$list, "success"=>true))); + } + + public function actionList($model) { + if ($this->getModule()->accessControl) { + /** @var CWebUser $user */ + $user = Yii::app()->user; + if (!$user->checkAccess("list/$model", array(), true)) { + throw new CHttpException(403, "Read access on $model denied."); + } + } + $modelInstance = new $model(); + $limit = isset($_GET['limit'])?$_GET['limit']:50; + $start = isset($_GET['start'])?$_GET['start']:0; + if (isset($_GET['page'])) { + $start += (($_GET['page']-1) * $limit); + } + if ($modelInstance instanceof CActiveRecord) { + $c = new CDbCriteria($this->getModule()->getDefaultCriteria($model)); + $c->offset = $start; + $c->limit = $limit; + if (isset($_GET['filter'])) { + $filter = CJSON::decode($_GET['filter']); + foreach ($filter as $field=>$condition) { + if (is_array($condition)) { + if (is_int($field)) { + $c->addCondition($condition['property'] . " = " . $condition["value"]); + } else $c->addCondition("$field $condition[0] $condition[1]"); + } else $c->addCondition("$field = $condition"); + } + } + if (isset($_GET['sort'])) { + $sort = CJSON::decode($_GET['sort']); + if (is_array($sort)) { + foreach ($sort as $s) { + $c->order .= $s['property'] . ' ' . $s['direction'] . ','; + } + $c->order = substr($c->order, 0, -1); + } else { + $c->order = $_GET['sort']; + } + } + if (isset($_GET['group'])) { + $group = CJSON::decode($_GET['group']); + if (is_array($group)) { + foreach ($group as $s) { + $c->group .= $s['property'] . ','; + } + $c->group = substr($c->group, 0, -1); + } else { + $c->group = $_GET['group']; + } + } + $this->result = CActiveRecord::model($model)->findAll($c); + } else if (@class_exists('EActiveResource') && $modelInstance instanceof EActiveResource) { + /** @var $list EActiveResource[] */ + $this->result = EActiveResource::model($model)->findAll(); + } else if (@class_exists('EMongoDocument') && $modelInstance instanceof EMongoDocument) { + $mc = new EMongoCriteria(); + $mc->setLimit($limit); + $mc->setOffset($start); + if (isset($_GET['filter'])) { + $filter = CJSON::decode($_GET['filter']); + foreach ($filter as $field=>$condition) { + if (is_array($condition)) { + if (is_int($field)) { + $field = $condition['property']; + $mc->$field = $condition["value"]; + } else $mc->$field($condition[0], $condition[1]); + } else $mc->$field = $condition; + } + } + if (isset($_GET['sort'])) $mc->setSort($_GET['sort']); + $this->result = EMongoDocument::model($model)->findAll($mc); + } + if ($this->getModule()->accessControl) { + /** @var CWebUser $user */ + $user = Yii::app()->user; + foreach ($this->result as $key=>$item) { + if (!$user->checkAccess("read/$model", array('model'=>$item), true)) { + Yii::log("DENIED: Try to list model $model ID: ".$item->getPrimaryKey(), CLogger::LEVEL_INFO, "restapi"); + unset($this->result[$key]); + } + } + $this->result = array_values($this->result); + } + } + + public function actionView($model, $id) { + $modelInstance = new $model(); + if ($modelInstance instanceof CActiveRecord) { + $this->result = CActiveRecord::model($model)->findByPk($id); + } else if (@class_exists('EMongoDocument') && $modelInstance instanceof EMongoDocument) { + $this->result = EMongoDocument::model($model)->findByPk(new MongoId($id)); + } else if ($modelInstance instanceof EActiveResource) { + $this->result = EActiveResource::model($model)->findById($id); + } + if ($this->getModule()->accessControl) { + /** @var CWebUser $user */ + $user = Yii::app()->user; + if (!$user->checkAccess("view/$model", array('model'=>$this->result), true)) { + throw new CHttpException(403, "Read access on $model denied."); + } + } + } + + public function actionUpdate($model, $id, $type = 'update') { + $this->actionView($model, $id); + if (is_null($this->result)) { + throw new CHttpException(400, "Did not find any model with ID: " . $id); + } + $modelInstance = $this->result; + $modelInstance->setScenario("update"); + if ($this->getModule()->accessControl) { + $modelInstance->setScenario($type); + /** @var CWebUser $user */ + $user = Yii::app()->user; + if ($type !== "update") $type = "update.".$type; + if (!$user->checkAccess("$type/$model", array('model'=>$modelInstance, 'scenario'=>$type), true)) { + throw new CHttpException(403, "Write access on $model denied."); + } + } + $vars = CJSON::decode(file_get_contents('php://input')); + if (!is_array($vars)) { + Yii::log("Input need to be Json: ".var_export($vars, true), CLogger::LEVEL_ERROR, "restapi"); + throw new CHttpException(500, "Input need to be JSON"); + } + if ($this->getModule()->getCheckAttributeAccessControl($_GET['model'])) { + /** @var CWebUser $user */ + $user = Yii::app()->user; + foreach ($vars as $field=>$value) { + if (!$user->checkAccess("update/".$_GET['model']."/".$field, array('model'=>$modelInstance), true)) { + unset($vars[$field]); + Yii::log("DENIED: Try to set attribute: $field with $value", CLogger::LEVEL_INFO, "restapi"); + } + } + } + $modelInstance->setAttributes($vars); + if ($modelInstance->save()) { + $modelInstance->refresh(); + } else { + Yii::log(implode("\n", $modelInstance->getErrors()), CLogger::LEVEL_ERROR, "restapi"); + throw new CHttpException(500, "Can not save model ID: " . $id); + } + } + + public function actionDelete($model, $id) { + $this->actionView($model, $id); + if (is_null($this->result)) { + throw new CHttpException(400, "Did not find any model with ID: " . $id); + } + $modelInstance = $this->result; + if ($this->getModule()->accessControl) { + /** @var CWebUser $user */ + $user = Yii::app()->user; + if (!$user->checkAccess("delete/$model", array('model'=>$modelInstance), true)) { + throw new CHttpException(403, "Write access on $model denied."); + } + } + if (!$modelInstance->delete()) { + Yii::log(implode("\n", $modelInstance->getErrors()), CLogger::LEVEL_ERROR, "restapi"); + throw new CHttpException(500, "Can not delete model ID: " . $id); + } else { + Yii::app()->end(); + } + } + + public function actionCreate($model) { + $modelInstance = new $model(); + $vars = CJSON::decode(file_get_contents('php://input')); + if (!is_array($vars)) { + Yii::log("Input need to be Json: ".var_export($vars, true), CLogger::LEVEL_ERROR, "restapi"); + throw new CHttpException(500, "Input need to be JSON"); + } + if ($this->getModule()->accessControl) { + /** @var CWebUser $user */ + $user = Yii::app()->user; + if (!$user->checkAccess("create/$model", array('model'=>$modelInstance), true)) { + throw new CHttpException(403, "Write access on $model denied."); + } + } + if ($this->getModule()->getCheckAttributeAccessControl($_GET['model'])) { + /** @var CWebUser $user */ + $user = Yii::app()->user; + foreach ($vars as $field=>$value) { + if (!$user->checkAccess("update/".$_GET['model']."/".$field, array('model'=>$modelInstance), true)) { + unset($vars[$field]); + Yii::log("DENIED: Try to set attribute: $field with $value", CLogger::LEVEL_INFO, "restapi"); + } + } + } + $modelInstance->setAttributes($vars); + if ($modelInstance->save()) { + $modelInstance->refresh(); + $this->result = $modelInstance; + } else { + Yii::log(implode("\n", $modelInstance->getErrors()), CLogger::LEVEL_ERROR, "restapi"); + throw new CHttpException(500, "Can not save model: " . $model); + } + } +}