content = $content; $this->color = $color; $this->ownerid = $ownerid; $this->noteid = $noteid; } /** * Load a note from the database and return it. * @global type $database * @param int $noteid * @return \Note * @throws NoSuchNoteException When the note ID isn't found. */ public static function loadNote(int $noteid): Note { global $database; if (!$database->has('notes', ['noteid' => $noteid])) { throw new NoSuchNoteException(); } $notedata = $database->get('notes', ['noteid', 'ownerid', 'color', 'content', 'title', 'modified', 'favorite'], ['noteid' => $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']); $note->setFavorite($notedata['favorite'] == true); return $note; } /** * Save the note to the database. * @global type $database * @param bool $saveas If true, save the note under a new ID. Forced to * true if the current note ID is missing or invalid. * @return int The database ID of the saved note * @throws Exception If there is no note owner set. */ public function saveNote(bool $saveas = false): int { global $database; $data = [ 'ownerid' => $this->getOwnerID(), 'color' => $this->getColor(), 'content' => $this->getText(), 'title' => $this->getTitle(), 'modified' => $this->getModified(), 'favorite' => $this->getFavorite() ? 1 : 0 ]; // We can't UPDATE the database, so use save as for INSERT if (empty($this->noteid) || !$database->has('notes', ['noteid' => $this->noteid])) { $saveas = true; } if (empty($this->ownerid)) { throw new Exception("No owner set."); } if ($saveas) { $database->insert('notes', $data); $this->noteid = $database->id(); } else { $database->update('notes', $data, ['noteid' => $this->noteid]); } return $this->noteid; } /** * Delete this note from the database. * @global type $database */ public function deleteNote() { global $database; $database->delete('notes', ['noteid' => $this->noteid]); } /** * Get the Markdown content of the note. * @return string */ public function getText(): string { return $this->content; } /** * Get the HTML render of the note. * @param bool $fragment Get just the HTML content, instead of a whole HTML5 file * @return string */ public function getHTML(bool $fragment = true): string { $parsedown = new ParsedownCheckbox(); $html = $parsedown->text($this->content); $safehtml = Htmlawed::filter($html, ['safe' => 1]); if ($fragment) { return $safehtml; } $document = "\n" . "\n" . "\n" . "" . $this->getCleanTitle() . " (" . $note->getModified() . ")\n" . "\n" . $safehtml; return $document; } /** * Get the note ID. * @return int */ public function getID(): int { return $this->noteid; } /** * Get the note color as RRGGBB hex. * @return string */ public function getColor(): string { $this->setColor($this->color); return $this->color; } /** * Get the owner UID * @return int */ public function getOwnerID(): int { return $this->ownerid; } /** * Get the owner as a User object * @return \User */ public function getOwner(): User { 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 note title stripped of Markdown and trimmed * @return string */ public function getCleanTitle(): string { $title = $this->getTitle(); $title = str_replace("*", "", $title); $title = str_replace("#", "", $title); $title = str_replace("_", "", $title); $title = str_replace("`", "", $title); return trim($title); } /** * Get the last modified date/time as "Y-m-d H:i:s" * @return string */ public function getModified(): string { if (empty($this->modified) || strtotime($this->modified) == 0) { return date("Y-m-d H:i:s"); } return date("Y-m-d H:i:s", strtotime($this->modified)); } /** * Get if the note is favorited (starred). * @return bool */ public function getFavorite(): bool { return $this->favorite; } /** * Get the text color for this note, based on the background color. * Thanks to https://stackoverflow.com/a/8468448 * @return string */ public function getTextColor(): string { $bg = $this->getColor(); $r = hexdec(substr($bg, 0, 2)); $g = hexdec(substr($bg, 2, 2)); $b = hexdec(substr($bg, 4, 2)); $contrast = sqrt( $r * $r * .241 + $g * $g * .691 + $b * $b * .068 ); if ($contrast > 130) { return '000000'; } else { return 'FFFFFF'; } } /** * Set the note content * @param string $markdown */ public function setText(string $markdown) { $this->content = $markdown; } /** * Set the note color to a hex string * @param string $color "RRGGBB" */ public function setColor(string $color) { $color = strtoupper($color); $color = str_replace("#", "", $color); // Make sure we have a valid RRGGBB hex if (!preg_match("/[A-F0-9]{6}/", $color)) { $color = "FFFFFF"; } $this->color = $color; } /** * Set the owner by UID * @param int $uid */ public function setOwnerID(int $uid) { $this->ownerid = $uid; } /** * Set the owner * @param User $user */ public function setOwner(User $owner) { $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) { if (is_numeric($datetime)) { $this->modified = date("Y-m-d H:i:s", $datetime); return; } $this->modified = date("Y-m-d H:i:s", strtotime($datetime)); } /** * Set the note as favorite or not * @param bool $favorite */ public function setFavorite(bool $favorite) { $this->favorite = $favorite; } /** * Convert normal lines of text to checklist items. */ public function toChecklist() { $text = explode("\n", $this->getText()); for ($i = 0; $i < count($text); $i++) { if (preg_match("/^[^\s\=\#\-<](.+)/", $text[$i])) { if (count($text) > $i && preg_match("/^[\=-](.+)/", $text[$i + 1])) { // Don't do it if the next line makes this one a heading continue; } $text[$i] = "- [ ] " . $text[$i]; } } $this->setText(implode("\n", $text)); } /** * Toggle the checked status of a checklist item. * @param string $item The text of the item to toggle. */ public function toggleChecklistItem(string $item) { $text = explode("\n", $this->getText()); $item = trim(str_replace("\n", "", $item)); for ($i = 0; $i < count($text); $i++) { if (!preg_match("/^- \[[Xx ]\] .*/", $text[$i])) { continue; } $linecleaned = trim(preg_replace("/^- \[[Xx ]\] /", "", $text[$i])); if ($item != $linecleaned) { continue; } if (preg_match("/^- \[[Xx]\] .*/", $text[$i])) { $text[$i] = preg_replace("/^- \[[Xx]\] /", "- [ ] ", $text[$i]); } else if (preg_match("/^- \[ \] .*/", $text[$i])) { $text[$i] = preg_replace("/^- \[ \] /", "- [x] ", $text[$i]); } } $this->setText(implode("\n", $text)); } /** * Get this note as an array. * @return string */ public function toArray(): array { $owner = new User($this->ownerid); $arr = [ 'noteid' => $this->getID(), 'color' => $this->getColor(), 'content' => $this->getText(), 'html' => $this->getHTML(true), 'title' => $this->getTitle(), 'modified' => $this->getModified(), 'favorite' => $this->getFavorite(), 'owner' => [ 'uid' => $owner->getUID(), 'username' => $owner->getUsername(), 'name' => $owner->getName() ] ]; 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" => $this->getFavorite() ]; } /** * 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 { $note = new Note($arr['content'], $arr['color'], $arr['owner']['uid'], $arr['noteid']); $note->setTitle($arr['title']); $note->setModified($arr['modified']); $note->setFavorite($arr['favorite']); return $note; } }