nextcloud-notes/lib/Service/NotesService.php

170 lines
5.0 KiB
PHP

<?php
declare(strict_types=1);
namespace OCA\Notes\Service;
use OCP\Files\File;
use OCP\Files\FileInfo;
use OCP\Files\Folder;
class NotesService {
private $metaService;
private $settings;
private $noteUtil;
public function __construct(
MetaService $metaService,
SettingsService $settings,
NoteUtil $noteUtil
) {
$this->metaService = $metaService;
$this->settings = $settings;
$this->noteUtil = $noteUtil;
}
public function getAll(string $userId) : array {
$notesFolder = $this->getNotesFolder($userId);
$data = $this->gatherNoteFiles($notesFolder);
$fileIds = array_map(function (File $file) : int {
return $file->getId();
}, $data['files']);
// 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);
}, $data['files']);
return [ 'notes' => $notes, 'categories' => $data['categories'] ];
}
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);
}
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;
}
/**
* @throws \OCP\Files\NotPermittedException
*/
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);
$this->noteUtil->ensureSufficientStorage($folder, 1);
// get file name
$fileSuffix = $this->settings->get($userId, 'fileSuffix');
$filename = $this->noteUtil->generateFileName($folder, $title, $fileSuffix, -1);
// create file
$file = $folder->newFile($filename);
// 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
$this->delete($userId, $file->getId());
throw $e;
}
return new Note($file, $notesFolder, $this->noteUtil);
}
/**
* @throws NoteDoesNotExistException if note does not exist
*/
public function delete(string $userId, int $id) {
$notesFolder = $this->getNotesFolder($userId);
$file = $this->getFileById($notesFolder, $id);
$parent = $file->getParent();
$file->delete();
$this->noteUtil->deleteEmptyFolder($parent, $notesFolder);
}
public function getTitleFromContent(string $content) : string {
$content = $this->noteUtil->stripMarkdown($content);
return $this->noteUtil->getSafeTitle($content);
}
/**
* @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');
$folder = $this->noteUtil->getOrCreateFolder($path);
return $folder;
}
/**
* gather note files in given directory and all subdirectories
*/
private static function gatherNoteFiles(Folder $folder, string $categoryPrefix = '') : array {
$data = [
'files' => [],
'categories' => [],
];
$nodes = $folder->getDirectoryListing();
foreach ($nodes as $node) {
if ($node->getType() === FileInfo::TYPE_FOLDER && $node instanceof Folder) {
$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;
}
}
return $data;
}
/**
* test if file is a note
*/
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);
}
/**
* @throws NoteDoesNotExistException
*/
private static function getFileById(Folder $folder, int $id) : File {
$file = $folder->getById($id);
if (count($file) <= 0 || !($file[0] instanceof File) || !self::isNote($file[0])) {
throw new NoteDoesNotExistException();
}
return $file[0];
}
}