nextcloud-notes/lib/Service/NotesService.php

203 lines
5.8 KiB
PHP
Raw Normal View History

2020-07-13 08:27:52 +02:00
<?php
2013-04-03 17:50:29 +02:00
2020-07-13 08:27:52 +02:00
declare(strict_types=1);
2013-04-03 17:50:29 +02:00
2020-07-13 08:27:52 +02:00
namespace OCA\Notes\Service;
2020-04-12 19:26:57 +02:00
2019-09-20 22:07:56 +02:00
use OCP\Files\File;
2020-04-12 19:26:57 +02:00
use OCP\Files\FileInfo;
2019-09-20 22:07:56 +02:00
use OCP\Files\Folder;
2019-11-16 23:35:37 +01:00
2013-08-12 12:55:10 +02:00
class NotesService {
private $metaService;
2019-05-25 08:15:05 +02:00
private $settings;
2019-09-20 22:07:56 +02:00
private $noteUtil;
2019-09-20 22:07:56 +02:00
public function __construct(
MetaService $metaService,
2019-09-20 22:07:56 +02:00
SettingsService $settings,
2020-04-12 19:26:57 +02:00
NoteUtil $noteUtil
2019-09-20 22:07:56 +02:00
) {
$this->metaService = $metaService;
2019-05-25 08:15:05 +02:00
$this->settings = $settings;
2019-09-20 22:07:56 +02:00
$this->noteUtil = $noteUtil;
2019-05-25 08:15:05 +02:00
}
2020-05-18 19:59:16 +02:00
public function getAll(string $userId) : array {
2020-04-12 19:26:57 +02:00
$notesFolder = $this->getNotesFolder($userId);
2020-05-18 19:59:16 +02:00
$data = $this->gatherNoteFiles($notesFolder);
2020-04-12 19:26:57 +02:00
$fileIds = array_map(function (File $file) : int {
return $file->getId();
2020-05-18 19:59:16 +02:00
}, $data['files']);
2020-04-12 19:26:57 +02:00
// pre-load tags for all notes (performance improvement)
$this->noteUtil->getTagService()->loadTags($fileIds);
$notes = array_map(function (File $file) use ($notesFolder) : Note {
return new Note($file, $notesFolder, $this->noteUtil);
2020-05-18 19:59:16 +02:00
}, $data['files']);
return [ 'notes' => $notes, 'categories' => $data['categories'] ];
2019-05-25 08:15:05 +02:00
}
2020-09-20 14:45:49 +02:00
public function getTopNotes(string $userId, int $count) : array {
$notes = $this->getAll($userId)['notes'];
usort($notes, function (Note $a, Note $b) {
$favA = $a->getFavorite();
$favB = $b->getFavorite();
if ($favA === $favB) {
return $b->getModified() - $a->getModified();
} else {
return $favA > $favB ? -1 : 1;
}
});
return array_slice($notes, 0, $count);
}
2020-04-12 19:26:57 +02:00
public function get(string $userId, int $id) : Note {
$notesFolder = $this->getNotesFolder($userId);
$note = new Note($this->getFileById($notesFolder, $id), $notesFolder, $this->noteUtil);
$this->metaService->update($userId, $note);
return $note;
2019-05-25 08:15:05 +02:00
}
public function search(string $userId, string $search) : array {
$terms = preg_split('/\s+/', $search);
$notes = $this->getAll($userId)['notes'];
return array_values(array_filter(
$notes,
function (Note $note) use ($terms) : bool {
return $this->searchTermsInNote($note, $terms);
}
));
}
private function searchTermsInNote(Note $note, array $terms) : bool {
try {
$d = $note->getData();
$strings = [ $d['title'], $d['category'], $d['content'] ];
foreach ($terms as $term) {
if (!$this->searchTermInData($strings, $term)) {
return false;
}
}
return true;
} catch (\Throwable $e) {
return false;
}
}
private function searchTermInData(array $strings, string $term) : bool {
foreach ($strings as $str) {
if (stripos($str, $term) !== false) {
return true;
}
}
return false;
}
2019-05-25 08:15:05 +02:00
/**
2020-04-12 19:26:57 +02:00
* @throws \OCP\Files\NotPermittedException
2019-05-25 08:15:05 +02:00
*/
2020-04-12 19:26:57 +02:00
public function create(string $userId, string $title, string $category) : Note {
// get folder based on category
$notesFolder = $this->getNotesFolder($userId);
$folder = $this->noteUtil->getCategoryFolder($notesFolder, $category);
2020-02-06 07:02:14 +01:00
$this->noteUtil->ensureSufficientStorage($folder, 1);
2019-05-25 08:15:05 +02:00
2020-04-12 19:26:57 +02:00
// get file name
$fileSuffix = $this->settings->get($userId, 'fileSuffix');
$filename = $this->noteUtil->generateFileName($folder, $title, $fileSuffix, -1);
// create file
$file = $folder->newFile($filename);
2019-05-25 08:15:05 +02:00
2020-02-01 12:08:39 +01:00
// try to write some content
try {
// If server-side encryption is activated, the server creates an empty file without signature
// which leads to an GenericEncryptionException('Missing Signature') afterwards.
// Saving a space-char (and removing it later) is a working work-around.
$file->putContent(' ');
} catch (\Throwable $e) {
// if writing the content fails, we have to roll back the note creation
2020-04-12 19:26:57 +02:00
$this->delete($userId, $file->getId());
2020-02-01 12:08:39 +01:00
throw $e;
}
2019-05-25 08:15:05 +02:00
2020-04-12 19:26:57 +02:00
return new Note($file, $notesFolder, $this->noteUtil);
2019-05-25 08:15:05 +02:00
}
/**
* @throws NoteDoesNotExistException if note does not exist
*/
2020-04-12 19:26:57 +02:00
public function delete(string $userId, int $id) {
$notesFolder = $this->getNotesFolder($userId);
2019-05-25 08:15:05 +02:00
$file = $this->getFileById($notesFolder, $id);
2020-04-12 19:26:57 +02:00
$parent = $file->getParent();
$file->delete();
$this->noteUtil->deleteEmptyFolder($parent, $notesFolder);
}
2019-05-25 08:15:05 +02:00
2020-04-12 19:26:57 +02:00
public function getTitleFromContent(string $content) : string {
2020-09-20 14:45:49 +02:00
$content = $this->noteUtil->stripMarkdown($content);
2020-04-12 19:26:57 +02:00
return $this->noteUtil->getSafeTitle($content);
}
2019-05-25 08:15:05 +02:00
2020-02-03 21:36:41 +01:00
2020-04-12 19:26:57 +02:00
/**
* @param string $userId the user id
* @return Folder
*/
private function getNotesFolder(string $userId) : Folder {
$userPath = $this->noteUtil->getRoot()->getUserFolder($userId)->getPath();
$path = $userPath . '/' . $this->settings->get($userId, 'notesPath');
2020-06-19 12:06:24 +02:00
$folder = $this->noteUtil->getOrCreateFolder($path);
2020-04-12 19:26:57 +02:00
return $folder;
2020-02-03 21:36:41 +01:00
}
2019-05-25 08:15:05 +02:00
/**
2020-04-12 19:26:57 +02:00
* gather note files in given directory and all subdirectories
2019-05-25 08:15:05 +02:00
*/
2020-05-18 19:59:16 +02:00
private static function gatherNoteFiles(Folder $folder, string $categoryPrefix = '') : array {
$data = [
'files' => [],
'categories' => [],
];
2020-04-12 19:26:57 +02:00
$nodes = $folder->getDirectoryListing();
foreach ($nodes as $node) {
if ($node->getType() === FileInfo::TYPE_FOLDER && $node instanceof Folder) {
2020-05-18 19:59:16 +02:00
$subCategory = $categoryPrefix . $node->getName();
$data['categories'][] = $subCategory;
$data_sub = self::gatherNoteFiles($node, $subCategory . '/');
$data['files'] = array_merge($data['files'], $data_sub['files']);
$data['categories'] = array_merge($data['categories'], $data_sub['categories']);
} elseif (self::isNote($node)) {
$data['files'][] = $node;
}
2019-05-25 08:15:05 +02:00
}
2020-05-18 19:59:16 +02:00
return $data;
2019-05-25 08:15:05 +02:00
}
/**
2020-04-12 19:26:57 +02:00
* test if file is a note
2019-05-25 08:15:05 +02:00
*/
2020-04-12 19:26:57 +02:00
private static function isNote(FileInfo $file) : bool {
static $allowedExtensions = ['txt', 'org', 'markdown', 'md', 'note'];
$ext = strtolower(pathinfo($file->getName(), PATHINFO_EXTENSION));
return $file->getType() === 'file' && in_array($ext, $allowedExtensions);
2019-05-25 08:15:05 +02:00
}
/**
* @throws NoteDoesNotExistException
*/
2020-04-12 19:26:57 +02:00
private static function getFileById(Folder $folder, int $id) : File {
2019-05-25 08:15:05 +02:00
$file = $folder->getById($id);
2020-04-12 19:26:57 +02:00
if (count($file) <= 0 || !($file[0] instanceof File) || !self::isNote($file[0])) {
2019-05-25 08:15:05 +02:00
throw new NoteDoesNotExistException();
}
return $file[0];
}
2013-04-03 17:50:29 +02:00
}