X-Git-Url: https://git.cweiske.de/grauphel.git/blobdiff_plain/3780cf15a59c48b3d71e8ec27e3bdacd8a119460..fdc7b416ddd51376c388d3e99aef8c12b6a17895:/controller/apicontroller.php diff --git a/controller/apicontroller.php b/controller/apicontroller.php index 5e743e0..23a47e7 100644 --- a/controller/apicontroller.php +++ b/controller/apicontroller.php @@ -12,7 +12,16 @@ * @link http://cweiske.de/grauphel.htm */ namespace OCA\Grauphel\Controller; + use \OCP\AppFramework\Controller; +use \OCP\AppFramework\Http\JSONResponse; + +use \OCA\Grauphel\Lib\Client; +use \OCA\Grauphel\Lib\NoteStorage; +use \OCA\Grauphel\Lib\OAuth; +use \OCA\Grauphel\Lib\OAuthException; +use \OCA\Grauphel\Lib\Dependencies; +use \OCA\Grauphel\Lib\Response\ErrorResponse; /** * Tomboy's REST API @@ -27,97 +36,206 @@ use \OCP\AppFramework\Controller; */ class ApiController extends Controller { + /** + * constructor of the controller + * + * @param string $appName Name of the app + * @param IRequest $request Instance of the request + */ + public function __construct($appName, \OCP\IRequest $request, $user) + { + parent::__construct($appName, $request); + $this->user = $user; + $this->deps = Dependencies::get(); + $this->notes = new NoteStorage($this->deps->urlGen); + + //default http header: we assume something is broken + header('HTTP/1.0 500 Internal Server Error'); + } + /** * /api/1.0 + * + * @NoAdminRequired + * @NoCSRFRequired + * @PublicPage */ - public function index() + public function index($route = 'grauphel.api.index') { - var_dump('asd');die(); + $deps = Dependencies::get(); $authenticated = false; $oauth = new OAuth(); - $oauth->setDeps($this->deps); - $urlGen = $this->deps->urlGen; + $oauth->setDeps($deps); + $urlGen = $deps->urlGen; try { - $provider = new \OAuthProvider(); + $provider = OAuth::getProvider(); $oauth->registerHandler($provider) ->registerAccessTokenHandler($provider); - $provider->checkOAuthRequest($urlGen->fullPath()); + $provider->checkOAuthRequest( + $urlGen->getAbsoluteURL( + $urlGen->linkToRoute($route) + ) + ); $authenticated = true; - $token = $this->deps->tokens->load('access', $provider->token); + $token = $deps->tokens->load('access', $provider->token); $username = $token->user; - } catch (OAuth_Exception $e) { - $this->deps->renderer->errorOut($e->getMessage()); + } catch (OAuthException $e) { + return new ErrorResponse($e->getMessage()); } catch (\OAuthException $e) { if ($e->getCode() != OAUTH_PARAMETER_ABSENT) { $oauth->error($e); } + if ($this->user !== null) { + $username = $this->user->getUID(); + $authenticated = true; + } } $data = array( - 'oauth_request_token_url' => $urlGen->oauthRequestToken(), - 'oauth_authorize_url' => $urlGen->oauthAuthorize(), - 'oauth_access_token_url' => $urlGen->oauthAccessToken(), + 'oauth_request_token_url' => $urlGen->getAbsoluteURL( + $urlGen->linkToRoute('grauphel.oauth.requestToken') + ), + 'oauth_authorize_url' => $urlGen->getAbsoluteURL( + $urlGen->linkToRoute('grauphel.oauth.authorize') + ), + 'oauth_access_token_url' => $urlGen->getAbsoluteURL( + $urlGen->linkToRoute('grauphel.oauth.accessToken') + ), 'api-version' => '1.0', ); + $cl = new Client(); + $client = $cl->getClient(); + if ($client !== false) { + $data['oauth_authorize_url'] .= '?client=' . urlencode($client); + } + if ($authenticated) { $data['user-ref'] = array( - 'api-ref' => $urlGen->user($username), - 'href' => $urlGen->userHtml($username), + 'api-ref' => $urlGen->getAbsoluteURL( + $urlGen->linkToRoute( + 'grauphel.api.user', array('username' => $username) + ) + ), + 'href' => null, ); } - $this->deps->renderer->sendJson($data); + return new JSONResponse($data); } /** - * GET /api/1.0/$user/notes/$noteguid + * /api/1.0/ + * + * @NoAdminRequired + * @NoCSRFRequired + * @PublicPage */ - public function note() + public function indexSlash() { - $username = $this->deps->urlGen->loadUsername(); - $guid = $this->deps->urlGen->loadGuid(); - $oauth = new OAuth(); - $oauth->setDeps($this->deps); - $oauth->verifyOAuthUser($username, $this->deps->urlGen->note($username, $guid)); + return $this->index('grauphel.api.indexSlash'); + } - $note = $this->deps->notes->load($username, $guid, false); - if ($note === null) { - header('HTTP/1.0 404 Not Found'); - header('Content-type: text/plain'); - echo "Note does not exist\n"; - exit(1); - } + /** + * GET /api/1.0/$user + * + * @NoAdminRequired + * @NoCSRFRequired + * @PublicPage + */ + public function user($username) + { + $this->verifyUser( + $username, + $this->deps->urlGen->getAbsoluteURL( + $this->deps->urlGen->linkToRoute( + 'grauphel.api.user', array('username' => $username) + ) + ) + ); + $syncdata = $this->notes->loadSyncData(); - $data = array('note' => array($note)); - $this->deps->renderer->sendJson($data); + $data = array( + 'user-name' => $username, + 'first-name' => null, + 'last-name' => null, + 'notes-ref' => array( + 'api-ref' => $this->deps->urlGen->getAbsoluteURL( + $this->deps->urlGen->linkToRoute( + 'grauphel.api.notes', array('username' => $username) + ) + ), + 'href' => $this->deps->urlGen->getAbsoluteURL( + $this->deps->urlGen->linkToRoute('grauphel.gui.index') + ), + ), + 'latest-sync-revision' => $syncdata->latestSyncRevision, + 'current-sync-guid' => $syncdata->currentSyncGuid, + ); + return new JSONResponse($data); } /** - * GET|PUT /api/1.0/$user/notes + * GET /api/1.0/$user/notes + * + * @NoAdminRequired + * @NoCSRFRequired + * @PublicPage */ - public function notes() + public function notes($username) { - $username = $this->deps->urlGen->loadUsername(); - $oauth = new OAuth(); - $oauth->setDeps($this->deps); - $oauth->verifyOAuthUser($username, $this->deps->urlGen->notes($username)); + $this->verifyUser( + $username, + $this->deps->urlGen->getAbsoluteURL( + $this->deps->urlGen->linkToRoute( + 'grauphel.api.notes', array('username' => $username) + ) + ) + ); + $syncdata = $this->notes->loadSyncData(); + return $this->fetchNotes($syncdata); + } - $syncdata = $this->deps->notes->loadSyncData($username); + /** + * PUT /api/1.0/$user/notes + * + * @NoAdminRequired + * @NoCSRFRequired + * @PublicPage + */ + public function notesSave($username) + { + $this->verifyUser( + $username, + $this->deps->urlGen->getAbsoluteURL( + $this->deps->urlGen->linkToRoute( + 'grauphel.api.notesSave', array('username' => $username) + ) + ) + ); + $syncdata = $this->notes->loadSyncData(); - $this->handleNoteSave($username, $syncdata); + $res = $this->handleNoteSave($username, $syncdata); + if ($res instanceof \OCP\AppFramework\Http\Response) { + return $res; + } + + return $this->fetchNotes($syncdata); + } + protected function fetchNotes($syncdata) + { $since = null; if (isset($_GET['since'])) { $since = (int) $_GET['since']; } if (isset($_GET['include_notes']) && $_GET['include_notes']) { - $notes = $this->deps->notes->loadNotesFull($username, $since); + $notes = $this->notes->loadNotesFull($since); } else { - $notes = $this->deps->notes->loadNotesOverview($username, $since); + $notes = $this->notes->loadNotesOverview($since); } //work around bug https://bugzilla.gnome.org/show_bug.cgi?id=734313 @@ -131,7 +249,7 @@ class ApiController extends Controller 'latest-sync-revision' => $syncdata->latestSyncRevision, 'notes' => $notes, ); - $this->deps->renderer->sendJson($data); + return new JSONResponse($data); } protected function handleNoteSave($username, $syncdata) @@ -140,74 +258,112 @@ class ApiController extends Controller return; } - $data = file_get_contents('php://input'); - $putObj = json_decode($data); - if ($putObj === NULL) { - errorOut('Invalid JSON data in PUT request'); - } + //Note that we have more data in $arPut than just our JSON. + // The request object merges it with other data. + $arPut = $this->request->put; //structural validation - if (!isset($putObj->{'latest-sync-revision'})) { - errorOut('Missing "latest-sync-revision"'); + if (!isset($arPut['latest-sync-revision'])) { + return new ErrorResponse('Missing "latest-sync-revision"'); } - if (!isset($putObj->{'note-changes'})) { - errorOut('Missing "note-changes"'); + if (!isset($arPut['note-changes'])) { + return new ErrorResponse('Missing "note-changes"'); } - foreach ($putObj->{'note-changes'} as $note) { + foreach ($arPut['note-changes'] as $note) { + //owncloud converts object to array, so we reverse + $note = (object) $note; if (!isset($note->guid) || $note->guid == '') { - errorOut('Missing "guid" on note'); + return new ErrorResponse('Missing "guid" on note'); } } //content validation - if ($putObj->{'latest-sync-revision'} != $syncdata->latestSyncRevision +1 + if ($arPut['latest-sync-revision'] != $syncdata->latestSyncRevision +1 && $syncdata->latestSyncRevision != -1 ) { - errorOut('Wrong "latest-sync-revision". You are not up to date.'); + return new ErrorResponse( + 'Wrong "latest-sync-revision". You are not up to date.' + ); } //update - ++$syncdata->latestSyncRevision; - foreach ($putObj->{'note-changes'} as $noteUpdate) { - $note = $this->deps->notes->load($username, $noteUpdate->guid); - if (isset($noteUpdate->command) && $noteUpdate->command == 'delete') { - $this->deps->notes->delete($username, $noteUpdate->guid); - } else { - $this->deps->notes->update( - $note, $noteUpdate, $syncdata->latestSyncRevision - ); - $this->deps->notes->save($username, $note); + $db = \OC::$server->getDatabaseConnection(); + $db->beginTransaction(); + try { + ++$syncdata->latestSyncRevision; + foreach ($arPut['note-changes'] as $noteUpdate) { + //owncloud converts object to array, so we reverse + $noteUpdate = (object) $noteUpdate; + + $note = $this->notes->load($noteUpdate->guid); + if (isset($noteUpdate->command) && $noteUpdate->command == 'delete') { + $this->notes->delete($noteUpdate->guid); + } else { + $this->notes->update( + $note, $noteUpdate, $syncdata->latestSyncRevision + ); + $this->notes->save($note); + } } + + $this->notes->saveSyncData($syncdata); + $db->commit(); + } catch (\DatabaseException $e) { + $db->rollBack(); + throw $e; } + } - $this->deps->notes->saveSyncData($username, $syncdata); + /** + * GET /api/1.0/$user/notes/$noteguid + * + * @NoAdminRequired + * @NoCSRFRequired + * @PublicPage + */ + public function note($username, $guid) + { + $this->verifyUser( + $username, + $this->deps->urlGen->getAbsoluteURL( + $this->deps->urlGen->linkToRoute( + 'grauphel.api.note', + array('username' => $username, 'guid' => $guid) + ) + ) + ); + + $note = $this->notes->load($guid, false); + if ($note === null) { + header('HTTP/1.0 404 Not Found'); + header('Content-type: text/plain'); + echo "Note does not exist\n"; + exit(1); + } + + return new JSONResponse($note); } /** - * GET /api/1.0/$user + * Checks if the given user is authorized (by oauth token or normal login) + * + * @param string $username Username to verify + * + * @return boolean True if all is fine, Response in case of an error */ - public function user() + protected function verifyUser($username, $curUrl) { - $username = $this->deps->urlGen->loadUsername(); + if ($this->user !== null && $this->user->getUid() == $username) { + $this->notes->setUsername($username); + return true; + } $oauth = new OAuth(); $oauth->setDeps($this->deps); - $oauth->verifyOAuthUser($username, $this->deps->urlGen->user($username)); + $oauth->verifyOAuthUser($username, $curUrl); - $syncdata = $this->deps->notes->loadSyncData($username); - - $data = array( - 'user-name' => $username, - 'first-name' => null, - 'last-name' => null, - 'notes-ref' => array( - 'api-ref' => $this->deps->urlGen->notes($username), - 'href' => null, - ), - 'latest-sync-revision' => $syncdata->latestSyncRevision, - 'current-sync-guid' => $syncdata->currentSyncGuid, - ); - $this->deps->renderer->sendJson($data); + $this->notes->setUsername($username); + return true; } } ?>