|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* Nextcloud - Notes |
|
4
|
|
|
* |
|
5
|
|
|
* This file is licensed under the Affero General Public License version 3 or |
|
6
|
|
|
* later. See the COPYING file. |
|
7
|
|
|
* |
|
8
|
|
|
* @author Bernhard Posselt <[email protected]> |
|
9
|
|
|
* @copyright Bernhard Posselt 2012, 2014 |
|
10
|
|
|
*/ |
|
11
|
|
|
|
|
12
|
|
|
namespace OCA\Notes\Service; |
|
13
|
|
|
|
|
14
|
|
|
use OCP\Files\FileInfo; |
|
15
|
|
|
use OCP\IL10N; |
|
16
|
|
|
use OCP\Files\IRootFolder; |
|
17
|
|
|
use OCP\Files\Folder; |
|
18
|
|
|
use OCP\ILogger; |
|
19
|
|
|
use OCP\Encryption\Exceptions\GenericEncryptionException; |
|
20
|
|
|
use League\Flysystem\FileNotFoundException; |
|
21
|
|
|
use OCA\Notes\Db\Note; |
|
22
|
|
|
use OCA\Notes\Service\SettingsService; |
|
23
|
|
|
use OCP\IConfig; |
|
24
|
|
|
use OCP\IUserSession; |
|
25
|
|
|
|
|
26
|
|
|
|
|
27
|
|
|
/** |
|
28
|
|
|
* Class NotesService |
|
29
|
|
|
* |
|
30
|
|
|
* @package OCA\Notes\Service |
|
31
|
|
|
*/ |
|
32
|
|
|
class NotesService { |
|
33
|
|
|
|
|
34
|
|
|
private $l10n; |
|
35
|
|
|
private $root; |
|
36
|
|
|
private $logger; |
|
37
|
|
|
private $config; |
|
38
|
|
|
private $settings; |
|
39
|
|
|
private $appName; |
|
40
|
|
|
|
|
41
|
|
|
/** |
|
42
|
|
|
* @param IRootFolder $root |
|
43
|
|
|
* @param IL10N $l10n |
|
44
|
|
|
* @param ILogger $logger |
|
45
|
|
|
* @param IConfig $config |
|
46
|
|
|
* @param \OCA\Notes\Service\SettingsService $settings |
|
47
|
|
|
* @param String $appName |
|
48
|
|
|
*/ |
|
49
|
|
|
public function __construct (IRootFolder $root, IL10N $l10n, ILogger $logger, IConfig $config, SettingsService $settings, $appName) { |
|
50
|
|
|
$this->root = $root; |
|
51
|
|
|
$this->l10n = $l10n; |
|
52
|
|
|
$this->logger = $logger; |
|
53
|
|
|
$this->config = $config; |
|
54
|
|
|
$this->settings = $settings; |
|
55
|
|
|
$this->appName = $appName; |
|
56
|
|
|
} |
|
57
|
|
|
|
|
58
|
|
|
|
|
59
|
|
|
/** |
|
60
|
|
|
* @param string $userId |
|
61
|
|
|
* @return array with all notes in the current directory |
|
62
|
|
|
*/ |
|
63
|
|
|
public function getAll ($userId, $onlyMeta=false) { |
|
64
|
|
|
$notesFolder = $this->getFolderForUser($userId); |
|
65
|
|
|
$notes = $this->gatherNoteFiles($notesFolder); |
|
66
|
|
|
$filesById = []; |
|
67
|
|
|
foreach($notes as $note) { |
|
68
|
|
|
$filesById[$note->getId()] = $note; |
|
69
|
|
|
} |
|
70
|
|
|
$tagger = \OC::$server->getTagManager()->load('files'); |
|
71
|
|
|
if($tagger===null) { |
|
72
|
|
|
$tags = []; |
|
73
|
|
|
} else { |
|
74
|
|
|
$tags = $tagger->getTagsForObjects(array_keys($filesById)); |
|
75
|
|
|
} |
|
76
|
|
|
|
|
77
|
|
|
$notes = []; |
|
78
|
|
|
foreach($filesById as $id=>$file) { |
|
79
|
|
|
$notes[] = $this->getNote($file, $notesFolder, array_key_exists($id, $tags) ? $tags[$id] : [], $onlyMeta); |
|
80
|
|
|
} |
|
81
|
|
|
|
|
82
|
|
|
return $notes; |
|
83
|
|
|
} |
|
84
|
|
|
|
|
85
|
|
|
|
|
86
|
|
|
/** |
|
87
|
|
|
* Used to get a single note by id |
|
88
|
|
|
* @param int $id the id of the note to get |
|
89
|
|
|
* @param string $userId |
|
90
|
|
|
* @throws NoteDoesNotExistException if note does not exist |
|
91
|
|
|
* @return Note |
|
92
|
|
|
*/ |
|
93
|
|
|
public function get ($id, $userId) { |
|
94
|
|
|
$folder = $this->getFolderForUser($userId); |
|
95
|
|
|
return $this->getNote($this->getFileById($folder, $id), $folder, $this->getTags($id)); |
|
96
|
|
|
} |
|
97
|
|
|
|
|
98
|
|
|
private function getTags ($id) { |
|
99
|
|
|
$tagger = \OC::$server->getTagManager()->load('files'); |
|
100
|
|
|
if($tagger===null) { |
|
101
|
|
|
$tags = []; |
|
102
|
|
|
} else { |
|
103
|
|
|
$tags = $tagger->getTagsForObjects([$id]); |
|
104
|
|
|
} |
|
105
|
|
|
return array_key_exists($id, $tags) ? $tags[$id] : []; |
|
106
|
|
|
} |
|
107
|
|
|
|
|
108
|
|
|
private function getNote($file, $notesFolder, $tags=[], $onlyMeta=false) { |
|
109
|
|
|
$id = $file->getId(); |
|
110
|
|
|
try { |
|
111
|
|
|
$note = Note::fromFile($file, $notesFolder, $tags, $onlyMeta); |
|
112
|
|
|
} catch(FileNotFoundException $e){ |
|
|
|
|
|
|
113
|
|
|
$note = Note::fromException($this->l10n->t('File error').': ('.$file->getName().') '.$e->getMessage(), $file, $notesFolder, array_key_exists($id, $tags) ? $tags[$id] : []); |
|
114
|
|
|
} catch(GenericEncryptionException $e) { |
|
|
|
|
|
|
115
|
|
|
$note = Note::fromException($this->l10n->t('Encryption Error').': ('.$file->getName().') '.$e->getMessage(), $file, $notesFolder, array_key_exists($id, $tags) ? $tags[$id] : []); |
|
116
|
|
|
} catch(\Exception $e) { |
|
117
|
|
|
$note = Note::fromException($this->l10n->t('Error').': ('.$file->getName().') '.$e->getMessage(), $file, $notesFolder, array_key_exists($id, $tags) ? $tags[$id] : []); |
|
118
|
|
|
} |
|
119
|
|
|
return $note; |
|
120
|
|
|
} |
|
121
|
|
|
|
|
122
|
|
|
|
|
123
|
|
|
/** |
|
124
|
|
|
* Creates a note and returns the empty note |
|
125
|
|
|
* @param string $userId |
|
126
|
|
|
* @see update for setting note content |
|
127
|
|
|
* @return Note the newly created note |
|
128
|
|
|
*/ |
|
129
|
|
|
public function create ($userId) { |
|
130
|
|
|
$title = $this->l10n->t('New note'); |
|
131
|
|
|
$folder = $this->getFolderForUser($userId); |
|
132
|
|
|
|
|
133
|
|
|
// check new note exists already and we need to number it |
|
134
|
|
|
// pass -1 because no file has id -1 and that will ensure |
|
135
|
|
|
// to only return filenames that dont yet exist |
|
136
|
|
|
$path = $this->generateFileName($folder, $title, $this->settings->get($userId, 'fileSuffix'), -1); |
|
137
|
|
|
$file = $folder->newFile($path); |
|
138
|
|
|
|
|
139
|
|
|
// If server-side encryption is activated, the server creates an empty file without signature |
|
140
|
|
|
// which leads to an GenericEncryptionException('Missing Signature') afterwards. |
|
141
|
|
|
// Saving a space-char (and removing it later) is a working work-around. |
|
142
|
|
|
$file->putContent(' '); |
|
143
|
|
|
|
|
144
|
|
|
return $this->getNote($file, $folder); |
|
145
|
|
|
} |
|
146
|
|
|
|
|
147
|
|
|
|
|
148
|
|
|
/** |
|
149
|
|
|
* Updates a note. Be sure to check the returned note since the title is |
|
150
|
|
|
* dynamically generated and filename conflicts are resolved |
|
151
|
|
|
* @param int $id the id of the note used to update |
|
152
|
|
|
* @param string $content the content which will be written into the note |
|
153
|
|
|
* the title is generated from the first line of the content |
|
154
|
|
|
* @param int $mtime time of the note modification (optional) |
|
155
|
|
|
* @throws NoteDoesNotExistException if note does not exist |
|
156
|
|
|
* @return \OCA\Notes\Db\Note the updated note |
|
157
|
|
|
*/ |
|
158
|
|
|
public function update ($id, $content, $userId, $category=null, $mtime=0) { |
|
159
|
|
|
$notesFolder = $this->getFolderForUser($userId); |
|
160
|
|
|
$file = $this->getFileById($notesFolder, $id); |
|
161
|
|
|
$title = $this->getSafeTitleFromContent( $content===null ? $file->getContent() : $content ); |
|
162
|
|
|
|
|
163
|
|
|
|
|
164
|
|
|
// rename/move file with respect to title/category |
|
165
|
|
|
// this can fail if access rights are not sufficient or category name is illegal |
|
166
|
|
|
try { |
|
167
|
|
|
$currentFilePath = $this->root->getFullPath($file->getPath()); |
|
168
|
|
|
$currentBasePath = pathinfo($currentFilePath, PATHINFO_DIRNAME); |
|
169
|
|
|
$fileSuffix = '.' . pathinfo($file->getName(), PATHINFO_EXTENSION); |
|
170
|
|
|
|
|
171
|
|
|
// detect (new) folder path based on category name |
|
172
|
|
|
if($category===null) { |
|
173
|
|
|
$basePath = $currentBasePath; |
|
174
|
|
|
} else { |
|
175
|
|
|
$basePath = $notesFolder->getPath(); |
|
176
|
|
|
if(!empty($category)) { |
|
177
|
|
|
// sanitise path |
|
178
|
|
|
$cats = explode('/', $category); |
|
179
|
|
|
$cats = array_map([$this, 'sanitisePath'], $cats); |
|
180
|
|
|
$cats = array_filter($cats, function($str) { return !empty($str); }); |
|
181
|
|
|
$basePath .= '/'.implode('/', $cats); |
|
182
|
|
|
} |
|
183
|
|
|
} |
|
184
|
|
|
$folder = $this->getOrCreateFolder($basePath); |
|
185
|
|
|
|
|
186
|
|
|
// assemble new file path |
|
187
|
|
|
$newFilePath = $basePath . '/' . $this->generateFileName($folder, $title, $fileSuffix, $id); |
|
188
|
|
|
|
|
189
|
|
|
// if the current path is not the new path, the file has to be renamed |
|
190
|
|
|
if($currentFilePath !== $newFilePath) { |
|
191
|
|
|
$file->move($newFilePath); |
|
192
|
|
|
} |
|
193
|
|
|
if($currentBasePath !== $basePath) { |
|
194
|
|
|
$this->deleteEmptyFolder($notesFolder, $this->root->get($currentBasePath)); |
|
195
|
|
|
} |
|
196
|
|
|
} catch(\OCP\Files\NotPermittedException $e) { |
|
|
|
|
|
|
197
|
|
|
$this->logger->error('Moving note '.$id.' ('.$title.') to the desired target is not allowed. Please check the note\'s target category ('.$category.').', ['app' => $this->appName]); |
|
198
|
|
|
} catch(\Exception $e) { |
|
199
|
|
|
$this->logger->error('Moving note '.$id.' ('.$title.') to the desired target has failed with a '.get_class($e).': '.$e->getMessage(), ['app' => $this->appName]); |
|
200
|
|
|
} |
|
201
|
|
|
|
|
202
|
|
|
if($content !== null) { |
|
203
|
|
|
$file->putContent($content); |
|
204
|
|
|
} |
|
205
|
|
|
|
|
206
|
|
|
if($mtime) { |
|
207
|
|
|
$file->touch($mtime); |
|
208
|
|
|
} |
|
209
|
|
|
|
|
210
|
|
|
return $this->getNote($file, $notesFolder, $this->getTags($id)); |
|
211
|
|
|
} |
|
212
|
|
|
|
|
213
|
|
|
/** |
|
214
|
|
|
* Set or unset a note as favorite. |
|
215
|
|
|
* @param int $id the id of the note used to update |
|
216
|
|
|
* @param boolean $favorite whether the note should be a favorite or not |
|
217
|
|
|
* @throws NoteDoesNotExistException if note does not exist |
|
218
|
|
|
* @return boolean the new favorite state of the note |
|
219
|
|
|
*/ |
|
220
|
|
|
public function favorite ($id, $favorite, $userId){ |
|
221
|
|
|
$folder = $this->getFolderForUser($userId); |
|
222
|
|
|
$file = $this->getFileById($folder, $id); |
|
223
|
|
|
if(!$this->isNote($file)) { |
|
224
|
|
|
throw new NoteDoesNotExistException(); |
|
225
|
|
|
} |
|
226
|
|
|
$tagger = \OC::$server->getTagManager()->load('files'); |
|
227
|
|
|
if($favorite) |
|
228
|
|
|
$tagger->addToFavorites($id); |
|
229
|
|
|
else |
|
230
|
|
|
$tagger->removeFromFavorites($id); |
|
231
|
|
|
|
|
232
|
|
|
$tags = $tagger->getTagsForObjects([$id]); |
|
233
|
|
|
return array_key_exists($id, $tags) && in_array(\OC\Tags::TAG_FAVORITE, $tags[$id]); |
|
234
|
|
|
} |
|
235
|
|
|
|
|
236
|
|
|
|
|
237
|
|
|
/** |
|
238
|
|
|
* Deletes a note |
|
239
|
|
|
* @param int $id the id of the note which should be deleted |
|
240
|
|
|
* @param string $userId |
|
241
|
|
|
* @throws NoteDoesNotExistException if note does not |
|
242
|
|
|
* exist |
|
243
|
|
|
*/ |
|
244
|
|
|
public function delete ($id, $userId) { |
|
245
|
|
|
$notesFolder = $this->getFolderForUser($userId); |
|
246
|
|
|
$file = $this->getFileById($notesFolder, $id); |
|
247
|
|
|
$parent = $file->getParent(); |
|
248
|
|
|
$file->delete(); |
|
249
|
|
|
$this->deleteEmptyFolder($notesFolder, $parent); |
|
250
|
|
|
} |
|
251
|
|
|
|
|
252
|
|
|
// removes characters that are illegal in a file or folder name on some operating systems |
|
253
|
|
|
private function sanitisePath($str) { |
|
254
|
|
|
// remove characters which are illegal on Windows (includes illegal characters on Unix/Linux) |
|
255
|
|
|
// prevents also directory traversal by eliminiating slashes |
|
256
|
|
|
// see also \OC\Files\Storage\Common::verifyPosixPath(...) |
|
257
|
|
|
$str = str_replace(['*', '|', '/', '\\', ':', '"', '<', '>', '?'], '', $str); |
|
258
|
|
|
|
|
259
|
|
|
// if mysql doesn't support 4byte UTF-8, then remove those characters |
|
260
|
|
|
// see \OC\Files\Storage\Common::verifyPath(...) |
|
261
|
|
|
if (!\OC::$server->getDatabaseConnection()->supports4ByteText()) { |
|
262
|
|
|
$str = preg_replace('%(?: |
|
263
|
|
|
\xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 |
|
264
|
|
|
| [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15 |
|
265
|
|
|
| \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 |
|
266
|
|
|
)%xs', '', $str); |
|
267
|
|
|
} |
|
268
|
|
|
|
|
269
|
|
|
// prevent file to be hidden |
|
270
|
|
|
$str = preg_replace("/^[\. ]+/mu", "", $str); |
|
271
|
|
|
return trim($str); |
|
272
|
|
|
} |
|
273
|
|
|
|
|
274
|
|
|
private function getSafeTitleFromContent($content) { |
|
275
|
|
|
// prepare content: remove markdown characters and empty spaces |
|
276
|
|
|
$content = preg_replace("/^\s*[*+-]\s+/mu", "", $content); // list item |
|
277
|
|
|
$content = preg_replace("/^#+\s+(.*?)\s*#*$/mu", "$1", $content); // headline |
|
278
|
|
|
$content = preg_replace("/^(=+|-+)$/mu", "", $content); // separate line for headline |
|
279
|
|
|
$content = preg_replace("/(\*+|_+)(.*?)\\1/mu", "$2", $content); // emphasis |
|
280
|
|
|
|
|
281
|
|
|
// sanitize: prevent directory traversal, illegal characters and unintended file names |
|
282
|
|
|
$content = $this->sanitisePath($content); |
|
283
|
|
|
|
|
284
|
|
|
// generate title from the first line of the content |
|
285
|
|
|
$splitContent = preg_split("/\R/u", $content, 2); |
|
286
|
|
|
$title = trim($splitContent[0]); |
|
287
|
|
|
|
|
288
|
|
|
// ensure that title is not empty |
|
289
|
|
|
if(empty($title)) { |
|
290
|
|
|
$title = $this->l10n->t('New note'); |
|
291
|
|
|
} |
|
292
|
|
|
|
|
293
|
|
|
// using a maximum of 100 chars should be enough |
|
294
|
|
|
$title = mb_substr($title, 0, 100, "UTF-8"); |
|
295
|
|
|
|
|
296
|
|
|
return $title; |
|
297
|
|
|
} |
|
298
|
|
|
|
|
299
|
|
|
/** |
|
300
|
|
|
* @param Folder $folder |
|
301
|
|
|
* @param int $id |
|
302
|
|
|
* @throws NoteDoesNotExistException |
|
303
|
|
|
* @return \OCP\Files\File |
|
304
|
|
|
*/ |
|
305
|
|
|
private function getFileById ($folder, $id) { |
|
306
|
|
|
$file = $folder->getById($id); |
|
307
|
|
|
|
|
308
|
|
|
if(count($file) <= 0 || !$this->isNote($file[0])) { |
|
309
|
|
|
throw new NoteDoesNotExistException(); |
|
310
|
|
|
} |
|
311
|
|
|
return $file[0]; |
|
312
|
|
|
} |
|
313
|
|
|
|
|
314
|
|
|
/** |
|
315
|
|
|
* @param string $userId the user id |
|
316
|
|
|
* @return boolean true if folder is accessible, or Exception otherwise |
|
317
|
|
|
*/ |
|
318
|
|
|
public function checkNotesFolder($userId) { |
|
319
|
|
|
$folder = $this->getFolderForUser($userId); |
|
|
|
|
|
|
320
|
|
|
return true; |
|
321
|
|
|
} |
|
322
|
|
|
|
|
323
|
|
|
/** |
|
324
|
|
|
* @param string $userId the user id |
|
325
|
|
|
* @return Folder |
|
326
|
|
|
*/ |
|
327
|
|
|
private function getFolderForUser ($userId) { |
|
328
|
|
|
$path = '/' . $userId . '/files/' . $this->settings->get($userId, 'notesPath'); |
|
329
|
|
|
try { |
|
330
|
|
|
$folder = $this->getOrCreateFolder($path); |
|
331
|
|
|
} catch(\Exception $e) { |
|
332
|
|
|
throw new NotesFolderException($path); |
|
333
|
|
|
} |
|
334
|
|
|
return $folder; |
|
335
|
|
|
} |
|
336
|
|
|
|
|
337
|
|
|
|
|
338
|
|
|
/** |
|
339
|
|
|
* Finds a folder and creates it if non-existent |
|
340
|
|
|
* @param string $path path to the folder |
|
341
|
|
|
* @return Folder |
|
342
|
|
|
*/ |
|
343
|
|
|
private function getOrCreateFolder($path) { |
|
344
|
|
|
if ($this->root->nodeExists($path)) { |
|
345
|
|
|
$folder = $this->root->get($path); |
|
346
|
|
|
} else { |
|
347
|
|
|
$folder = $this->root->newFolder($path); |
|
348
|
|
|
} |
|
349
|
|
|
return $folder; |
|
350
|
|
|
} |
|
351
|
|
|
|
|
352
|
|
|
/* |
|
353
|
|
|
* Delete a folder and it's parent(s) if it's/they're empty |
|
354
|
|
|
* @param Folder root folder for notes |
|
355
|
|
|
* @param Folder folder to delete |
|
356
|
|
|
*/ |
|
357
|
|
|
private function deleteEmptyFolder(Folder $notesFolder, Folder $folder) { |
|
358
|
|
|
$content = $folder->getDirectoryListing(); |
|
359
|
|
|
$isEmpty = !count($content); |
|
360
|
|
|
$isNotesFolder = $folder->getPath()===$notesFolder->getPath(); |
|
361
|
|
|
if($isEmpty && !$isNotesFolder) { |
|
362
|
|
|
$this->logger->info('Deleting empty category folder '.$folder->getPath(), ['app' => $this->appName]); |
|
363
|
|
|
$parent = $folder->getParent(); |
|
364
|
|
|
$folder->delete(); |
|
365
|
|
|
$this->deleteEmptyFolder($notesFolder, $parent); |
|
366
|
|
|
} |
|
367
|
|
|
} |
|
368
|
|
|
|
|
369
|
|
|
/** |
|
370
|
|
|
* get path of file and the title.txt and check if they are the same |
|
371
|
|
|
* file. If not the title needs to be renamed |
|
372
|
|
|
* |
|
373
|
|
|
* @param Folder $folder a folder to the notes directory |
|
374
|
|
|
* @param string $title the filename which should be used |
|
375
|
|
|
* @param string $suffix the suffix (incl. dot) which should be used |
|
376
|
|
|
* @param int $id the id of the note for which the title should be generated |
|
377
|
|
|
* used to see if the file itself has the title and not a different file for |
|
378
|
|
|
* checking for filename collisions |
|
379
|
|
|
* @return string the resolved filename to prevent overwriting different |
|
380
|
|
|
* files with the same title |
|
381
|
|
|
*/ |
|
382
|
|
|
private function generateFileName (Folder $folder, $title, $suffix, $id) { |
|
383
|
|
|
$path = $title . $suffix; |
|
384
|
|
|
|
|
385
|
|
|
// if file does not exist, that name has not been taken. Similar we don't |
|
386
|
|
|
// need to handle file collisions if it is the filename did not change |
|
387
|
|
|
if (!$folder->nodeExists($path) || $folder->get($path)->getId() === $id) { |
|
388
|
|
|
return $path; |
|
389
|
|
|
} else { |
|
390
|
|
|
// increments name (2) to name (3) |
|
391
|
|
|
$match = preg_match('/\((?P<id>\d+)\)$/u', $title, $matches); |
|
392
|
|
|
if($match) { |
|
393
|
|
|
$newId = ((int) $matches['id']) + 1; |
|
394
|
|
|
$newTitle = preg_replace('/(.*)\s\((\d+)\)$/u', |
|
395
|
|
|
'$1 (' . $newId . ')', $title); |
|
396
|
|
|
} else { |
|
397
|
|
|
$newTitle = $title . ' (2)'; |
|
398
|
|
|
} |
|
399
|
|
|
return $this->generateFileName($folder, $newTitle, $suffix, $id); |
|
400
|
|
|
} |
|
401
|
|
|
} |
|
402
|
|
|
|
|
403
|
|
|
/** |
|
404
|
|
|
* gather note files in given directory and all subdirectories |
|
405
|
|
|
* @param Folder $folder |
|
406
|
|
|
* @return array |
|
407
|
|
|
*/ |
|
408
|
|
|
private function gatherNoteFiles ($folder) { |
|
409
|
|
|
$notes = []; |
|
410
|
|
|
$nodes = $folder->getDirectoryListing(); |
|
411
|
|
|
foreach($nodes as $node) { |
|
412
|
|
|
if($node->getType() === FileInfo::TYPE_FOLDER) { |
|
413
|
|
|
$notes = array_merge($notes, $this->gatherNoteFiles($node)); |
|
414
|
|
|
continue; |
|
415
|
|
|
} |
|
416
|
|
|
if($this->isNote($node)) { |
|
417
|
|
|
$notes[] = $node; |
|
418
|
|
|
} |
|
419
|
|
|
} |
|
420
|
|
|
return $notes; |
|
421
|
|
|
} |
|
422
|
|
|
|
|
423
|
|
|
|
|
424
|
|
|
/** |
|
425
|
|
|
* test if file is a note |
|
426
|
|
|
* |
|
427
|
|
|
* @param \OCP\Files\File $file |
|
428
|
|
|
* @return bool |
|
429
|
|
|
*/ |
|
430
|
|
|
private function isNote($file) { |
|
431
|
|
|
$allowedExtensions = ['txt', 'org', 'markdown', 'md', 'note']; |
|
432
|
|
|
|
|
433
|
|
|
if($file->getType() !== 'file') return false; |
|
434
|
|
|
|
|
435
|
|
|
$ext = pathinfo($file->getName(), PATHINFO_EXTENSION); |
|
436
|
|
|
$iext = strtolower($ext); |
|
437
|
|
|
if(!in_array($iext, $allowedExtensions)) { |
|
438
|
|
|
return false; |
|
439
|
|
|
} |
|
440
|
|
|
return true; |
|
441
|
|
|
} |
|
442
|
|
|
|
|
443
|
|
|
} |
|
444
|
|
|
|
Scrutinizer analyzes your
composer.json/composer.lockfile if available to determine the classes, and functions that are defined by your dependencies.It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.