diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..b91932b --- /dev/null +++ b/.htaccess @@ -0,0 +1,5 @@ +# Rewrite for Nextcloud Notes API + + RewriteEngine on + RewriteRule index.php/apps/notes/api/v0.2 lib/nextcloudnotes.php [PT] + \ No newline at end of file diff --git a/action.php b/action.php index f5d196e..e983f9f 100644 --- a/action.php +++ b/action.php @@ -35,13 +35,13 @@ switch ($VARS['action']) { header('Location: index.php'); die("Logged out."); case "savenote": - if (empty($VARS['content']) || empty($VARS['noteid'])) { - die($Strings->get("invalid parameters")); + if (!isset($VARS['content']) || empty($VARS['noteid'])) { + die($Strings->get("invalid parameters", false)); } http_response_code(204); $note = Note::loadNote($VARS['noteid']); - if ($note->getOwnerID() != $_SESSION['uid']) { - die($Strings->get("invalid parameters")); + if (!$note->hasWriteAccess(new User($_SESSION['uid']))) { + die($Strings->get("invalid parameters", false)); } $note->setText($VARS['content']); $note->setColor($VARS['color']); @@ -52,7 +52,7 @@ switch ($VARS['action']) { die($Strings->get("invalid parameters")); } $note = Note::loadNote($VARS['noteid']); - if ($note->getOwnerID() != $_SESSION['uid']) { + if (!$note->hasWriteAccess(new User($_SESSION['uid']))) { die($Strings->get("invalid parameters")); } $note->deleteNote(); diff --git a/database.mwb b/database.mwb index 62603e0..63826da 100644 Binary files a/database.mwb and b/database.mwb differ diff --git a/lib/Note.lib.php b/lib/Note.lib.php index 410e6d2..71887c9 100644 --- a/lib/Note.lib.php +++ b/lib/Note.lib.php @@ -11,6 +11,8 @@ class Note { private $noteid; private $ownerid; private $content = ""; + private $title = ""; + private $modified = ""; private $color = "FFFFFF"; /** @@ -40,9 +42,13 @@ class Note { throw new NoSuchNoteException(); } - $notedata = $database->get('notes', ['noteid', 'ownerid', 'color', 'content'], ['noteid' => $noteid]); + $notedata = $database->get('notes', ['noteid', 'ownerid', 'color', 'content', 'title', 'modified'], ['noteid' => $noteid]); - return new Note($notedata['content'], $notedata['color'], $notedata['ownerid'], $notedata['noteid']); + $note = new Note($notedata['content'], $notedata['color'], $notedata['ownerid'], $notedata['noteid']); + $note->setTitle(is_null($notedata['title']) ? "" : $notedata['title']); + $note->setModified(is_null($notedata['modified']) ? date("Y-m-d H:i:s") : $notedata['modified']); + + return $note; } /** @@ -57,9 +63,11 @@ class Note { global $database; $data = [ - 'ownerid' => $this->ownerid, - 'color' => $this->color, - 'content' => $this->content + 'ownerid' => $this->getOwnerID(), + 'color' => $this->getColor(), + 'content' => $this->getText(), + 'title' => $this->getTitle(), + 'modified' => $this->getModified() ]; // We can't UPDATE the database, so use save as for INSERT @@ -142,6 +150,34 @@ class Note { return new User($this->ownerid); } + /** + * Get the note title + * @return string + */ + public function getTitle(): string { + global $Strings; + $title = $this->title; + if (empty($title)) { + if (empty($this->getText())) { + $title = $Strings->get("New note", false); + } else { + $title = explode("\n", $this->getText())[0]; + } + } + return $title; + } + + /** + * Get the last modified date/time as "Y-m-d H:i:s" + * @return string + */ + public function getModified(): string { + if (empty($this->modified)) { + return date("Y-m-d H:i:s"); + } + return date("Y-m-d H:i:s", strtotime($this->modified)); + } + /** * Set the note content * @param string $markdown @@ -174,6 +210,22 @@ class Note { $this->ownerid = $owner->getUID(); } + /** + * Set the note title + * @param string $title + */ + public function setTitle(string $title) { + $this->title = $title; + } + + /** + * Set the last modified date/time + * @param string $datetime + */ + public function setModified(string $datetime) { + $this->modified = date("Y-m-d H:i:s", strtotime($datetime)); + } + /** * Get this note as an array. * @return string @@ -181,9 +233,11 @@ class Note { public function toArray(): array { $owner = new User($this->ownerid); $arr = [ - 'noteid' => $this->noteid, - 'color' => $this->color, - 'content' => $this->content, + 'noteid' => $this->getID(), + 'color' => $this->getColor(), + 'content' => $this->getText(), + 'title' => $this->getTitle(), + 'modified' => $this->getModified(), 'owner' => [ 'uid' => $owner->getUID(), 'username' => $owner->getUsername(), @@ -194,13 +248,54 @@ class Note { return $arr; } + /** + * Get an array suitable for returning via the Nextcloud Notes API + * https://github.com/nextcloud/notes/wiki/Notes-0.2#get-a-note + * @return array + */ + public function toNextcloud(): array { + return [ + "id" => $this->getID(), + "modified" => strtotime($this->getModified()), + "title" => $this->getTitle(), + "category" => null, + "content" => $this->getText(), + "favorite" => false + ]; + } + + /** + * Check whether the given User has read access to this note. + * @param User $user + */ + public function hasReadAccess(User $user): bool { + if ($this->getOwnerID() == $user->getUID()) { + return true; + } + return false; + } + + /** + * Check whether the given User has write access to this note. + * @param User $user + */ + public function hasWriteAccess(User $user): bool { + if ($this->getOwnerID() == $user->getUID()) { + return true; + } + return false; + } + /** * Read an array with the structure from toArray(). * @param array $arr * @return \Note A Note constructed from the array data. */ public static function fromArray(array $arr): Note { - return new Note($arr['content'], $arr['color'], $arr['owner']['uid'], $arr['noteid']); + $note = new Note($arr['content'], $arr['color'], $arr['owner']['uid'], $arr['noteid']); + $note->setTitle($arr['title']); + $note->setModified($arr['modified']); + return $note; } } diff --git a/lib/nextcloudnotes.php b/lib/nextcloudnotes.php new file mode 100644 index 0000000..abe047c --- /dev/null +++ b/lib/nextcloudnotes.php @@ -0,0 +1,112 @@ +checkPassword($_SERVER['PHP_AUTH_PW'])) { + header('HTTP/1.0 401 Unauthorized'); + die($Strings->get("login incorrect")); + } +} + +header("Content-Type: application/json"); + +$requestdata = $_GET; +$requestbody = file_get_contents('php://input'); +$requestjson = json_decode($requestbody, TRUE); +if (json_last_error() == JSON_ERROR_NONE) { + $requestdata = array_merge($requestdata, $requestjson); +} + +switch ($_SERVER['REQUEST_METHOD']) { + case "GET": + if (count($route) == 1) { + $noteids = $database->select('notes', 'noteid', ['ownerid' => $user->getUID()]); + $notes = []; + foreach ($noteids as $n) { + $notes[] = Note::loadNote($n)->toNextcloud(); + } + exit(json_encode($notes)); + } else if (count($route) == 2 && is_numeric($route[1])) { + try { + $note = Note::loadNote($route[1]); + if ($note->getOwner()->getUID() == $user->getUID()) { + exit(json_encode($note->toNextcloud())); + } else { + http_response_code(401); + } + } catch (NoSuchNoteException $ex) { + http_response_code(404); + } + } + break; + case "POST": + $note = new Note($requestdata['content']); + + if (empty($requestdata['modified']) || !is_numeric($requestdata['modified'])) { + $note->setModified(date("Y-m-d H:i:s")); + } else { + $note->setModified($requestdata['modified']); + } + + $note->setOwner($user); + + $note->saveNote(); + + exit(json_encode($note->toNextcloud())); + break; + case "PUT": + if (count($route) == 2 && is_numeric($route[1])) { + try { + $note = Note::loadNote($route[1]); + if ($note->hasWriteAccess($user)) { + $note->setText($requestdata['content']); + if (empty($requestdata['modified']) || !is_numeric($requestdata['modified'])) { + $note->setModified(date("Y-m-d H:i:s")); + } else { + $note->setModified($requestdata['modified']); + } + $note->saveNote(); + exit(json_encode($note->toNextcloud())); + } else { + http_response_code(401); + } + } catch (NoSuchNoteException $ex) { + http_response_code(404); + } + } + break; + case "DELETE": + if (count($route) == 2 && is_numeric($route[1])) { + try { + $note = Note::loadNote($route[1]); + if ($note->hasWriteAccess($user)) { + $note->deleteNote(); + exit; + } else { + http_response_code(401); + } + } catch (NoSuchNoteException $ex) { + http_response_code(404); + } + } + break; +} \ No newline at end of file