NotesService::getNote()   A
last analyzed

Complexity

Conditions 5
Paths 3

Size

Total Lines 12
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 10
c 2
b 0
f 0
dl 0
loc 12
rs 9.6111
cc 5
nc 3
nop 4
1
<?php
2
3
namespace OCA\Notes\Service;
4
5
use OCP\Encryption\Exceptions\GenericEncryptionException;
6
use OCP\Files\File;
7
use OCP\Files\Folder;
8
use OCP\Files\IRootFolder;
9
use OCP\IConfig;
10
use OCP\IL10N;
11
use OCP\ILogger;
12
use OCP\ITagManager;
13
14
use OCA\Notes\Db\Note;
15
use OCA\Notes\Service\SettingsService;
16
17
/**
18
 * Class NotesService
19
 *
20
 * @package OCA\Notes\Service
21
 */
22
class NotesService {
23
24
	private $l10n;
25
	private $root;
26
	private $logger;
27
	private $config;
28
	private $tags;
29
	private $settings;
30
	private $noteUtil;
31
	private $appName;
32
33
	/**
34
	 * @param IRootFolder $root
35
	 * @param IL10N $l10n
36
	 * @param ILogger $logger
37
	 * @param IConfig $config
38
	 * @param ITagManager $tagManager
39
	 * @param SettingsService $settings
40
	 * @param NoteUtil $noteUtil
41
	 * @param String $appName
42
	 */
43
	public function __construct(
44
		IRootFolder $root,
45
		IL10N $l10n,
46
		ILogger $logger,
47
		IConfig $config,
48
		ITagManager $tagManager,
49
		SettingsService $settings,
50
		NoteUtil $noteUtil,
51
		$appName
52
	) {
53
		$this->root = $root;
54
		$this->l10n = $l10n;
55
		$this->logger = $logger;
56
		$this->config = $config;
57
		$this->tags = $tagManager->load('files');
58
		$this->settings = $settings;
59
		$this->noteUtil = $noteUtil;
60
		$this->appName = $appName;
61
	}
62
63
64
	/**
65
	 * @param string $userId
66
	 * @return array with all notes in the current directory
67
	 */
68
	public function getAll($userId, $onlyMeta = false) {
69
		$notesFolder = $this->getFolderForUser($userId);
70
		$notes = $this->noteUtil->gatherNoteFiles($notesFolder);
71
		$filesById = [];
72
		foreach ($notes as $note) {
73
			$filesById[$note->getId()] = $note;
74
		}
75
		$tags = $this->tags->getTagsForObjects(array_keys($filesById));
76
77
		$notes = [];
78
		foreach ($filesById as $id => $file) {
79
			$noteTags = is_array($tags) && array_key_exists($id, $tags) ? $tags[$id] : [];
80
			$notes[] = $this->getNote($file, $notesFolder, $noteTags, $onlyMeta);
81
		}
82
83
		return $notes;
84
	}
85
86
87
	/**
88
	 * Used to get a single note by id
89
	 * @param int $id the id of the note to get
90
	 * @param string $userId
91
	 * @throws NoteDoesNotExistException if note does not exist
92
	 * @return Note
93
	 */
94
	public function get($id, $userId, $onlyMeta = false) : Note {
95
		$folder = $this->getFolderForUser($userId);
96
		return $this->getNote($this->getFileById($folder, $id), $folder, $this->getTags($id), $onlyMeta);
97
	}
98
99
	private function getTags($id) {
100
		$tags = $this->tags->getTagsForObjects([$id]);
101
		return is_array($tags) && array_key_exists($id, $tags) ? $tags[$id] : [];
102
	}
103
104
	private function getNote(File $file, Folder $notesFolder, $tags = [], $onlyMeta = false) : Note {
105
		$id = $file->getId();
106
		try {
107
			$note = Note::fromFile($file, $notesFolder, $tags, $onlyMeta);
108
		} catch (GenericEncryptionException $e) {
109
			$message = $this->l10n->t('Encryption Error').': ('.$file->getName().') '.$e->getMessage();
110
			$note = Note::fromException($message, $file, $notesFolder, array_key_exists($id, $tags) ? $tags[$id] : []);
111
		} catch (\Exception $e) {
112
			$message = $this->l10n->t('Error').': ('.$file->getName().') '.$e->getMessage();
113
			$note = Note::fromException($message, $file, $notesFolder, array_key_exists($id, $tags) ? $tags[$id] : []);
114
		}
115
		return $note;
116
	}
117
118
119
	/**
120
	 * Creates a note and returns the empty note
121
	 * @param string $userId
122
	 * @see update for setting note content
123
	 * @return Note the newly created note
124
	 */
125
	public function create($userId) : Note {
126
		$title = $this->l10n->t('New note');
127
		$folder = $this->getFolderForUser($userId);
128
		$this->noteUtil->ensureSufficientStorage($folder, 1);
129
130
		// check new note exists already and we need to number it
131
		// pass -1 because no file has id -1 and that will ensure
132
		// to only return filenames that dont yet exist
133
		$path = $this->noteUtil->generateFileName($folder, $title, $this->settings->get($userId, 'fileSuffix'), -1);
134
		$file = $folder->newFile($path);
135
136
		// try to write some content
137
		try {
138
			// If server-side encryption is activated, the server creates an empty file without signature
139
			// which leads to an GenericEncryptionException('Missing Signature') afterwards.
140
			// Saving a space-char (and removing it later) is a working work-around.
141
			$file->putContent(' ');
142
		} catch (\Throwable $e) {
143
			// if writing the content fails, we have to roll back the note creation
144
			$this->delete($file->getId(), $userId);
145
			throw $e;
146
		}
147
148
		return $this->getNote($file, $folder);
149
	}
150
151
152
	/**
153
	 * Updates a note. Be sure to check the returned note since the title is
154
	 * dynamically generated and filename conflicts are resolved
155
	 * @param int $id the id of the note used to update
156
	 * @param string|null $content the content which will be written into the note
157
	 * the title is generated from the first line of the content
158
	 * @param string|null $category the category in which the note should be saved
159
	 * @param int $mtime time of the note modification (optional)
160
	 * @throws NoteDoesNotExistException if note does not exist
161
	 * @return \OCA\Notes\Db\Note the updated note
162
	 */
163
	public function update($id, $content, $userId, $category = null, $mtime = 0) : Note {
164
		$notesFolder = $this->getFolderForUser($userId);
165
		$file = $this->getFileById($notesFolder, $id);
166
		$title = $this->noteUtil->getSafeTitleFromContent($content===null ? $file->getContent() : $content);
167
168
		// rename/move file with respect to title/category
169
		// this can fail if access rights are not sufficient or category name is illegal
170
		try {
171
			$this->noteUtil->moveNote($notesFolder, $file, $category, $title);
172
		} catch (\OCP\Files\NotPermittedException $e) {
173
			$err = 'Moving note '.$id.' ('.$title.') to the desired target is not allowed.'
174
				.' Please check the note\'s target category ('.$category.').';
175
			$this->logger->error($err, ['app' => $this->appName]);
176
		} catch (\Exception $e) {
177
			$err = 'Moving note '.$id.' ('.$title.') to the desired target has failed '
178
				.'with a '.get_class($e).': '.$e->getMessage();
179
			$this->logger->error($err, ['app' => $this->appName]);
180
		}
181
182
		if ($content !== null) {
183
			$this->noteUtil->ensureSufficientStorage($file->getParent(), strlen($content));
184
			$file->putContent($content);
185
		}
186
187
		if ($mtime) {
188
			$file->touch($mtime);
189
		}
190
191
		return $this->getNote($file, $notesFolder, $this->getTags($id));
192
	}
193
194
	/**
195
	 * Set or unset a note as favorite.
196
	 * @param int $id the id of the note used to update
197
	 * @param boolean $favorite whether the note should be a favorite or not
198
	 * @throws NoteDoesNotExistException if note does not exist
199
	 * @return boolean the new favorite state of the note
200
	 */
201
	public function favorite($id, $favorite, $userId) {
202
		$note = $this->get($id, $userId, true);
203
		if ($favorite !== $note->getFavorite()) {
204
			if ($favorite) {
205
				$this->tags->addToFavorites($id);
206
			} else {
207
				$this->tags->removeFromFavorites($id);
208
			}
209
			$note = $this->get($id, $userId, true);
210
		}
211
		return $note->getFavorite();
212
	}
213
214
215
	/**
216
	 * Deletes a note
217
	 * @param int $id the id of the note which should be deleted
218
	 * @param string $userId
219
	 * @throws NoteDoesNotExistException if note does not
220
	 * exist
221
	 */
222
	public function delete($id, $userId) {
223
		$notesFolder = $this->getFolderForUser($userId);
224
		$file = $this->getFileById($notesFolder, $id);
225
		$parent = $file->getParent();
226
		$file->delete();
227
		$this->noteUtil->deleteEmptyFolder($notesFolder, $parent);
228
	}
229
230
	/**
231
	 * @param Folder $folder
232
	 * @param int $id
233
	 * @throws NoteDoesNotExistException
234
	 * @return \OCP\Files\File
235
	 */
236
	private function getFileById(Folder $folder, $id) : File {
237
		$file = $folder->getById($id);
238
239
		if (count($file) <= 0 || !($file[0] instanceof File) || !$this->noteUtil->isNote($file[0])) {
240
			throw new NoteDoesNotExistException();
241
		}
242
		return $file[0];
243
	}
244
245
	/**
246
	 * @param string $userId the user id
247
	 * @return Folder
248
	 */
249
	private function getFolderForUser($userId) : Folder {
250
		// TODO use IRootFolder->getUserFolder()  ?
251
		$path = '/' . $userId . '/files/' . $this->settings->get($userId, 'notesPath');
252
		try {
253
			$folder = $this->noteUtil->getOrCreateFolder($path);
254
		} catch (\Exception $e) {
255
			throw new NotesFolderException($path);
256
		}
257
		return $folder;
258
	}
259
}
260