code style and lint errors
This commit is contained in:
parent
682dc48055
commit
16de16937e
|
@ -1,10 +1,12 @@
|
||||||
node_modules/
|
node_modules/
|
||||||
|
vendor/
|
||||||
*.log
|
*.log
|
||||||
build/
|
build/
|
||||||
js/
|
js/
|
||||||
.rvm
|
.rvm
|
||||||
report
|
report
|
||||||
clover.xml
|
clover.xml
|
||||||
|
composer.lock
|
||||||
|
|
||||||
# just sane ignores
|
# just sane ignores
|
||||||
.*.sw[po]
|
.*.sw[po]
|
||||||
|
|
|
@ -11,6 +11,7 @@ build:
|
||||||
tests:
|
tests:
|
||||||
override:
|
override:
|
||||||
- php-scrutinizer-run
|
- php-scrutinizer-run
|
||||||
|
- phpcs-run --standard=phpcs.xml appinfo/ lib/
|
||||||
- eslint-run --ext .js,.vue src
|
- eslint-run --ext .js,.vue src
|
||||||
|
|
||||||
tools:
|
tools:
|
||||||
|
|
|
@ -49,8 +49,7 @@ script:
|
||||||
# - phpunit -c phpunit.integration.xml
|
# - phpunit -c phpunit.integration.xml
|
||||||
|
|
||||||
# build js
|
# build js
|
||||||
- make npm-init
|
- make init
|
||||||
- make lint
|
- make lint
|
||||||
- make stylelint
|
|
||||||
- make build-js-production
|
- make build-js-production
|
||||||
|
|
||||||
|
|
64
Makefile
64
Makefile
|
@ -9,32 +9,32 @@ appstore_dir=$(build_dir)/appstore
|
||||||
package_name=$(app_name)
|
package_name=$(app_name)
|
||||||
cert_dir=$(HOME)/.nextcloud/certificates
|
cert_dir=$(HOME)/.nextcloud/certificates
|
||||||
|
|
||||||
appstore: clean
|
appstore: clean lint build-js-production
|
||||||
mkdir -p $(sign_dir)
|
mkdir -p $(sign_dir)
|
||||||
rsync -a \
|
rsync -a \
|
||||||
--exclude=.git \
|
--exclude=.babelrc.js \
|
||||||
--exclude=build \
|
--exclude=build \
|
||||||
--exclude=.gitignore \
|
|
||||||
--exclude=.travis.yml \
|
|
||||||
--exclude=.scrutinizer.yml \
|
|
||||||
--exclude=CONTRIBUTING.md \
|
|
||||||
--exclude=composer.json \
|
--exclude=composer.json \
|
||||||
--exclude=composer.lock \
|
--exclude=composer.lock \
|
||||||
--exclude=composer.phar \
|
--exclude=composer.phar \
|
||||||
--exclude=.tx \
|
--exclude=CONTRIBUTING.md \
|
||||||
|
--exclude=.editorconfig \
|
||||||
|
--exclude=.eslintrc.js \
|
||||||
|
--exclude=.git \
|
||||||
|
--exclude=.github \
|
||||||
|
--exclude=.gitignore \
|
||||||
--exclude=l10n/no-php \
|
--exclude=l10n/no-php \
|
||||||
--exclude=Makefile \
|
--exclude=Makefile \
|
||||||
--exclude=nbproject \
|
--exclude=package*.json \
|
||||||
--exclude=screenshots \
|
--exclude=phpcs.xml \
|
||||||
--exclude=phpunit*xml \
|
--exclude=phpunit*xml \
|
||||||
|
--exclude=.scrutinizer.yml \
|
||||||
|
--exclude=src \
|
||||||
|
--exclude=.stylelintrc.js \
|
||||||
--exclude=tests \
|
--exclude=tests \
|
||||||
--exclude=vendor/bin \
|
--exclude=.travis.yml \
|
||||||
--exclude=js/node_modules \
|
--exclude=.tx \
|
||||||
--exclude=js/tests \
|
--exclude=vendor \
|
||||||
--exclude=js/karma.conf.js \
|
|
||||||
--exclude=js/gulpfile.js \
|
|
||||||
--exclude=js/bower.json \
|
|
||||||
--exclude=js/package.json \
|
|
||||||
$(project_dir) $(sign_dir)
|
$(project_dir) $(sign_dir)
|
||||||
@echo "Signing…"
|
@echo "Signing…"
|
||||||
php ../server/occ integrity:sign-app \
|
php ../server/occ integrity:sign-app \
|
||||||
|
@ -51,7 +51,12 @@ appstore: clean
|
||||||
all: dev-setup lint build-js-production test
|
all: dev-setup lint build-js-production test
|
||||||
|
|
||||||
# Dev env management
|
# Dev env management
|
||||||
dev-setup: clean clean-dev npm-init
|
dev-setup: clean clean-dev init
|
||||||
|
|
||||||
|
init: composer-init npm-init
|
||||||
|
|
||||||
|
composer-init:
|
||||||
|
composer install
|
||||||
|
|
||||||
npm-init:
|
npm-init:
|
||||||
npm install
|
npm install
|
||||||
|
@ -84,17 +89,27 @@ test-coverage:
|
||||||
npm run test:coverage
|
npm run test:coverage
|
||||||
|
|
||||||
# Linting
|
# Linting
|
||||||
lint:
|
lint: lint-php lint-js lint-css
|
||||||
|
|
||||||
|
lint-php:
|
||||||
|
vendor/bin/phpcs --standard=phpcs.xml --runtime-set ignore_warnings_on_exit 1 appinfo/ lib/
|
||||||
|
|
||||||
|
lint-js:
|
||||||
npm run lint
|
npm run lint
|
||||||
|
|
||||||
lint-fix:
|
lint-css:
|
||||||
npm run lint:fix
|
|
||||||
|
|
||||||
# Style linting
|
|
||||||
stylelint:
|
|
||||||
npm run stylelint
|
npm run stylelint
|
||||||
|
|
||||||
stylelint-fix:
|
# Fix lint
|
||||||
|
lint-fix: lint-php-fix lint-js-fix lint-css-fix
|
||||||
|
|
||||||
|
lint-php-fix:
|
||||||
|
vendor/bin/phpcbf --standard=phpcs.xml appinfo/ lib/
|
||||||
|
|
||||||
|
lint-js-fix:
|
||||||
|
npm run lint:fix
|
||||||
|
|
||||||
|
lint-css-fix:
|
||||||
npm run stylelint:fix
|
npm run stylelint:fix
|
||||||
|
|
||||||
# Cleaning
|
# Cleaning
|
||||||
|
@ -104,4 +119,5 @@ clean:
|
||||||
|
|
||||||
clean-dev:
|
clean-dev:
|
||||||
rm -rf node_modules
|
rm -rf node_modules
|
||||||
|
rm -rf vendor
|
||||||
|
|
||||||
|
|
|
@ -17,14 +17,13 @@ $app = new App('notes');
|
||||||
$container = $app->getContainer();
|
$container = $app->getContainer();
|
||||||
|
|
||||||
$container->query('OCP\INavigationManager')->add(function () use ($container) {
|
$container->query('OCP\INavigationManager')->add(function () use ($container) {
|
||||||
$urlGenerator = $container->query('OCP\IURLGenerator');
|
$urlGenerator = $container->query('OCP\IURLGenerator');
|
||||||
$l10n = $container->query('OCP\IL10N');
|
$l10n = $container->query('OCP\IL10N');
|
||||||
return [
|
return [
|
||||||
'id' => 'notes',
|
'id' => 'notes',
|
||||||
'order' => 10,
|
'order' => 10,
|
||||||
'href' => $urlGenerator->linkToRoute('notes.page.index'),
|
'href' => $urlGenerator->linkToRoute('notes.page.index'),
|
||||||
'icon' => $urlGenerator->imagePath('notes', 'notes.svg'),
|
'icon' => $urlGenerator->imagePath('notes', 'notes.svg'),
|
||||||
'name' => $l10n->t('Notes')
|
'name' => $l10n->t('Notes')
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"christophwurst/nextcloud": "^15.0"
|
"christophwurst/nextcloud": "^15.0",
|
||||||
|
"squizlabs/php_codesniffer": "3.*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,4 @@
|
||||||
<?php
|
<?php
|
||||||
/**
|
|
||||||
* Nextcloud - Notes
|
|
||||||
*
|
|
||||||
* This file is licensed under the Affero General Public License version 3 or
|
|
||||||
* later. See the COPYING file.
|
|
||||||
*
|
|
||||||
* @author Bernhard Posselt <dev@bernhard-posselt.com>
|
|
||||||
* @copyright Bernhard Posselt 2012, 2014
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace OCA\Notes\Controller;
|
namespace OCA\Notes\Controller;
|
||||||
|
|
||||||
|
@ -22,15 +13,15 @@ use OCA\Notes\Service\NoteDoesNotExistException;
|
||||||
* @package OCA\Notes\Controller
|
* @package OCA\Notes\Controller
|
||||||
*/
|
*/
|
||||||
trait Errors {
|
trait Errors {
|
||||||
/**
|
/**
|
||||||
* @param $callback
|
* @param $callback
|
||||||
* @return DataResponse
|
* @return DataResponse
|
||||||
*/
|
*/
|
||||||
protected function respond ($callback) {
|
protected function respond($callback) {
|
||||||
try {
|
try {
|
||||||
return new DataResponse($callback());
|
return new DataResponse($callback());
|
||||||
} catch(NoteDoesNotExistException $ex) {
|
} catch (NoteDoesNotExistException $ex) {
|
||||||
return new DataResponse([], Http::STATUS_NOT_FOUND);
|
return new DataResponse([], Http::STATUS_NOT_FOUND);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,4 @@
|
||||||
<?php
|
<?php
|
||||||
/**
|
|
||||||
* Nextcloud - Notes
|
|
||||||
*
|
|
||||||
* This file is licensed under the Affero General Public License version 3 or
|
|
||||||
* later. See the COPYING file.
|
|
||||||
*
|
|
||||||
* @author Bernhard Posselt <dev@bernhard-posselt.com>
|
|
||||||
* @copyright Bernhard Posselt 2012, 2014
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace OCA\Notes\Controller;
|
namespace OCA\Notes\Controller;
|
||||||
|
|
||||||
|
@ -28,173 +19,171 @@ use OCA\Notes\Db\Note;
|
||||||
*/
|
*/
|
||||||
class NotesApiController extends ApiController {
|
class NotesApiController extends ApiController {
|
||||||
|
|
||||||
use Errors;
|
use Errors;
|
||||||
|
|
||||||
/** @var NotesService */
|
/** @var NotesService */
|
||||||
private $service;
|
private $service;
|
||||||
/** @var MetaService */
|
/** @var MetaService */
|
||||||
private $metaService;
|
private $metaService;
|
||||||
/** @var IUserSession */
|
/** @var IUserSession */
|
||||||
private $userSession;
|
private $userSession;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $AppName
|
* @param string $AppName
|
||||||
* @param IRequest $request
|
* @param IRequest $request
|
||||||
* @param NotesService $service
|
* @param NotesService $service
|
||||||
* @param IUserSession $userSession
|
* @param IUserSession $userSession
|
||||||
*/
|
*/
|
||||||
public function __construct($AppName, IRequest $request, NotesService $service, MetaService $metaService, IUserSession $userSession) {
|
public function __construct($AppName, IRequest $request, NotesService $service, MetaService $metaService, IUserSession $userSession) {
|
||||||
parent::__construct($AppName, $request);
|
parent::__construct($AppName, $request);
|
||||||
$this->service = $service;
|
$this->service = $service;
|
||||||
$this->metaService = $metaService;
|
$this->metaService = $metaService;
|
||||||
$this->userSession = $userSession;
|
$this->userSession = $userSession;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getUID() {
|
private function getUID() {
|
||||||
return $this->userSession->getUser()->getUID();
|
return $this->userSession->getUser()->getUID();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Note $note
|
* @param Note $note
|
||||||
* @param string[] $exclude the fields that should be removed from the
|
* @param string[] $exclude the fields that should be removed from the
|
||||||
* notes
|
* notes
|
||||||
* @return Note
|
* @return Note
|
||||||
*/
|
*/
|
||||||
private function excludeFields(Note &$note, array $exclude) {
|
private function excludeFields(Note &$note, array $exclude) {
|
||||||
if(count($exclude) > 0) {
|
if (count($exclude) > 0) {
|
||||||
foreach ($exclude as $field) {
|
foreach ($exclude as $field) {
|
||||||
if(property_exists($note, $field)) {
|
if (property_exists($note, $field)) {
|
||||||
unset($note->$field);
|
unset($note->$field);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $note;
|
return $note;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @NoAdminRequired
|
* @NoAdminRequired
|
||||||
* @CORS
|
* @CORS
|
||||||
* @NoCSRFRequired
|
* @NoCSRFRequired
|
||||||
*
|
*
|
||||||
* @param string $exclude
|
* @param string $exclude
|
||||||
* @return DataResponse
|
* @return DataResponse
|
||||||
*/
|
*/
|
||||||
public function index($exclude='', $pruneBefore=0) {
|
public function index($exclude = '', $pruneBefore = 0) {
|
||||||
$exclude = explode(',', $exclude);
|
$exclude = explode(',', $exclude);
|
||||||
$now = new \DateTime(); // this must be before loading notes if there are concurrent changes possible
|
$now = new \DateTime(); // this must be before loading notes if there are concurrent changes possible
|
||||||
$notes = $this->service->getAll($this->getUID());
|
$notes = $this->service->getAll($this->getUID());
|
||||||
$metas = $this->metaService->updateAll($this->getUID(), $notes);
|
$metas = $this->metaService->updateAll($this->getUID(), $notes);
|
||||||
foreach ($notes as $note) {
|
foreach ($notes as $note) {
|
||||||
$lastUpdate = $metas[$note->getId()]->getLastUpdate();
|
$lastUpdate = $metas[$note->getId()]->getLastUpdate();
|
||||||
if($pruneBefore && $lastUpdate<$pruneBefore) {
|
if ($pruneBefore && $lastUpdate<$pruneBefore) {
|
||||||
$vars = get_object_vars($note);
|
$vars = get_object_vars($note);
|
||||||
unset($vars['id']);
|
unset($vars['id']);
|
||||||
$this->excludeFields($note, array_keys($vars));
|
$this->excludeFields($note, array_keys($vars));
|
||||||
} else {
|
} else {
|
||||||
$this->excludeFields($note, $exclude);
|
$this->excludeFields($note, $exclude);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$etag = md5(json_encode($notes));
|
$etag = md5(json_encode($notes));
|
||||||
if ($this->request->getHeader('If-None-Match') === '"'.$etag.'"') {
|
if ($this->request->getHeader('If-None-Match') === '"'.$etag.'"') {
|
||||||
return new DataResponse([], Http::STATUS_NOT_MODIFIED);
|
return new DataResponse([], Http::STATUS_NOT_MODIFIED);
|
||||||
}
|
}
|
||||||
return (new DataResponse($notes))
|
return (new DataResponse($notes))
|
||||||
->setLastModified($now)
|
->setLastModified($now)
|
||||||
->setETag($etag);
|
->setETag($etag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @NoAdminRequired
|
* @NoAdminRequired
|
||||||
* @CORS
|
* @CORS
|
||||||
* @NoCSRFRequired
|
* @NoCSRFRequired
|
||||||
*
|
*
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @param string $exclude
|
* @param string $exclude
|
||||||
* @return DataResponse
|
* @return DataResponse
|
||||||
*/
|
*/
|
||||||
public function get($id, $exclude='') {
|
public function get($id, $exclude = '') {
|
||||||
$exclude = explode(',', $exclude);
|
$exclude = explode(',', $exclude);
|
||||||
|
|
||||||
return $this->respond(function () use ($id, $exclude) {
|
return $this->respond(function () use ($id, $exclude) {
|
||||||
$note = $this->service->get($id, $this->getUID());
|
$note = $this->service->get($id, $this->getUID());
|
||||||
$note = $this->excludeFields($note, $exclude);
|
$note = $this->excludeFields($note, $exclude);
|
||||||
return $note;
|
return $note;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @NoAdminRequired
|
* @NoAdminRequired
|
||||||
* @CORS
|
* @CORS
|
||||||
* @NoCSRFRequired
|
* @NoCSRFRequired
|
||||||
*
|
*
|
||||||
* @param string $content
|
* @param string $content
|
||||||
* @param string $category
|
* @param string $category
|
||||||
* @param int $modified
|
* @param int $modified
|
||||||
* @param boolean $favorite
|
* @param boolean $favorite
|
||||||
* @return DataResponse
|
* @return DataResponse
|
||||||
*/
|
*/
|
||||||
public function create($content, $category=null, $modified=0, $favorite=null) {
|
public function create($content, $category = null, $modified = 0, $favorite = null) {
|
||||||
return $this->respond(function () use ($content, $category, $modified, $favorite) {
|
return $this->respond(function () use ($content, $category, $modified, $favorite) {
|
||||||
$note = $this->service->create($this->getUID());
|
$note = $this->service->create($this->getUID());
|
||||||
return $this->updateData($note->getId(), $content, $category, $modified, $favorite);
|
return $this->updateData($note->getId(), $content, $category, $modified, $favorite);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @NoAdminRequired
|
* @NoAdminRequired
|
||||||
* @CORS
|
* @CORS
|
||||||
* @NoCSRFRequired
|
* @NoCSRFRequired
|
||||||
*
|
*
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @param string $content
|
* @param string $content
|
||||||
* @param string $category
|
* @param string $category
|
||||||
* @param int $modified
|
* @param int $modified
|
||||||
* @param boolean $favorite
|
* @param boolean $favorite
|
||||||
* @return DataResponse
|
* @return DataResponse
|
||||||
*/
|
*/
|
||||||
public function update($id, $content=null, $category=null, $modified=0, $favorite=null) {
|
public function update($id, $content = null, $category = null, $modified = 0, $favorite = null) {
|
||||||
return $this->respond(function () use ($id, $content, $category, $modified, $favorite) {
|
return $this->respond(function () use ($id, $content, $category, $modified, $favorite) {
|
||||||
return $this->updateData($id, $content, $category, $modified, $favorite);
|
return $this->updateData($id, $content, $category, $modified, $favorite);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates a note, used by create and update
|
|
||||||
* @param int $id
|
|
||||||
* @param string $content
|
|
||||||
* @param int $modified
|
|
||||||
* @param boolean $favorite
|
|
||||||
* @return Note
|
|
||||||
*/
|
|
||||||
private function updateData($id, $content, $category, $modified, $favorite) {
|
|
||||||
if($favorite!==null) {
|
|
||||||
$this->service->favorite($id, $favorite, $this->getUID());
|
|
||||||
}
|
|
||||||
if($content===null) {
|
|
||||||
return $this->service->get($id, $this->getUID());
|
|
||||||
} else {
|
|
||||||
return $this->service->update($id, $content, $this->getUID(), $category, $modified);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @NoAdminRequired
|
|
||||||
* @CORS
|
|
||||||
* @NoCSRFRequired
|
|
||||||
*
|
|
||||||
* @param int $id
|
|
||||||
* @return DataResponse
|
|
||||||
*/
|
|
||||||
public function destroy($id) {
|
|
||||||
return $this->respond(function () use ($id) {
|
|
||||||
$this->service->delete($id, $this->getUID());
|
|
||||||
return [];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a note, used by create and update
|
||||||
|
* @param int $id
|
||||||
|
* @param string|null $content
|
||||||
|
* @param int $modified
|
||||||
|
* @param boolean|null $favorite
|
||||||
|
* @return Note
|
||||||
|
*/
|
||||||
|
private function updateData($id, $content, $category, $modified, $favorite) {
|
||||||
|
if ($favorite!==null) {
|
||||||
|
$this->service->favorite($id, $favorite, $this->getUID());
|
||||||
|
}
|
||||||
|
if ($content===null) {
|
||||||
|
return $this->service->get($id, $this->getUID());
|
||||||
|
} else {
|
||||||
|
return $this->service->update($id, $content, $this->getUID(), $category, $modified);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @NoAdminRequired
|
||||||
|
* @CORS
|
||||||
|
* @NoCSRFRequired
|
||||||
|
*
|
||||||
|
* @param int $id
|
||||||
|
* @return DataResponse
|
||||||
|
*/
|
||||||
|
public function destroy($id) {
|
||||||
|
return $this->respond(function () use ($id) {
|
||||||
|
$this->service->delete($id, $this->getUID());
|
||||||
|
return [];
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,4 @@
|
||||||
<?php
|
<?php
|
||||||
/**
|
|
||||||
* Nextcloud - Notes
|
|
||||||
*
|
|
||||||
* This file is licensed under the Affero General Public License version 3 or
|
|
||||||
* later. See the COPYING file.
|
|
||||||
*
|
|
||||||
* @author Bernhard Posselt <dev@bernhard-posselt.com>
|
|
||||||
* @copyright Bernhard Posselt 2012, 2014
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace OCA\Notes\Controller;
|
namespace OCA\Notes\Controller;
|
||||||
|
|
||||||
|
@ -27,167 +18,177 @@ use OCA\Notes\Service\SettingsService;
|
||||||
*/
|
*/
|
||||||
class NotesController extends Controller {
|
class NotesController extends Controller {
|
||||||
|
|
||||||
use Errors;
|
use Errors;
|
||||||
|
|
||||||
/** @var NotesService */
|
/** @var NotesService */
|
||||||
private $notesService;
|
private $notesService;
|
||||||
/** @var SettingsService */
|
/** @var SettingsService */
|
||||||
private $settingsService;
|
private $settingsService;
|
||||||
/** @var IConfig */
|
/** @var IConfig */
|
||||||
private $settings;
|
private $settings;
|
||||||
/** @var string */
|
/** @var string */
|
||||||
private $userId;
|
private $userId;
|
||||||
/** @var IL10N */
|
/** @var IL10N */
|
||||||
private $l10n;
|
private $l10n;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $AppName
|
* @param string $AppName
|
||||||
* @param IRequest $request
|
* @param IRequest $request
|
||||||
* @param NotesService $notesService
|
* @param NotesService $notesService
|
||||||
* @param SettingsService $settingsService
|
* @param SettingsService $settingsService
|
||||||
* @param IConfig $settings
|
* @param IConfig $settings
|
||||||
* @param IL10N $l10n
|
* @param IL10N $l10n
|
||||||
* @param string $UserId
|
* @param string $UserId
|
||||||
*/
|
*/
|
||||||
public function __construct($AppName,
|
public function __construct(
|
||||||
IRequest $request,
|
$AppName,
|
||||||
NotesService $notesService,
|
IRequest $request,
|
||||||
SettingsService $settingsService,
|
NotesService $notesService,
|
||||||
IConfig $settings,
|
SettingsService $settingsService,
|
||||||
IL10N $l10n,
|
IConfig $settings,
|
||||||
$UserId) {
|
IL10N $l10n,
|
||||||
parent::__construct($AppName, $request);
|
$UserId
|
||||||
$this->notesService = $notesService;
|
) {
|
||||||
$this->settingsService = $settingsService;
|
parent::__construct($AppName, $request);
|
||||||
$this->settings = $settings;
|
$this->notesService = $notesService;
|
||||||
$this->userId = $UserId;
|
$this->settingsService = $settingsService;
|
||||||
$this->l10n = $l10n;
|
$this->settings = $settings;
|
||||||
}
|
$this->userId = $UserId;
|
||||||
|
$this->l10n = $l10n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @NoAdminRequired
|
* @NoAdminRequired
|
||||||
*/
|
*/
|
||||||
public function index() {
|
public function index() {
|
||||||
$notes = $this->notesService->getAll($this->userId, true);
|
$notes = $this->notesService->getAll($this->userId, true);
|
||||||
$settings = $this->settingsService->getAll($this->userId);
|
$settings = $this->settingsService->getAll($this->userId);
|
||||||
|
|
||||||
$errorMessage = null;
|
$errorMessage = null;
|
||||||
$lastViewedNote = (int) $this->settings->getUserValue($this->userId,
|
$lastViewedNote = (int) $this->settings->getUserValue(
|
||||||
$this->appName, 'notesLastViewedNote');
|
$this->userId,
|
||||||
// check if notes folder is accessible
|
$this->appName,
|
||||||
try {
|
'notesLastViewedNote'
|
||||||
$this->notesService->checkNotesFolder($this->userId);
|
);
|
||||||
if($lastViewedNote) {
|
// check if notes folder is accessible
|
||||||
// check if note exists
|
try {
|
||||||
try {
|
$this->notesService->checkNotesFolder($this->userId);
|
||||||
$this->notesService->get($lastViewedNote, $this->userId);
|
if ($lastViewedNote) {
|
||||||
} catch(\Exception $ex) {
|
// check if note exists
|
||||||
$this->settings->deleteUserValue($this->userId, $this->appName, 'notesLastViewedNote');
|
try {
|
||||||
$lastViewedNote = 0;
|
$this->notesService->get($lastViewedNote, $this->userId);
|
||||||
$errorMessage = $this->l10n->t('The last viewed note cannot be accessed. ').$ex->getMessage();
|
} catch (\Exception $ex) {
|
||||||
}
|
$this->settings->deleteUserValue($this->userId, $this->appName, 'notesLastViewedNote');
|
||||||
}
|
$lastViewedNote = 0;
|
||||||
} catch(\Exception $e) {
|
$errorMessage = $this->l10n->t('The last viewed note cannot be accessed. ').$ex->getMessage();
|
||||||
$errorMessage = $this->l10n->t('The notes folder is not accessible: %s', $e->getMessage());
|
}
|
||||||
}
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$errorMessage = $this->l10n->t('The notes folder is not accessible: %s', $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
return new DataResponse([
|
return new DataResponse([
|
||||||
'notes' => $notes,
|
'notes' => $notes,
|
||||||
'settings' => $settings,
|
'settings' => $settings,
|
||||||
'lastViewedNote' => $lastViewedNote,
|
'lastViewedNote' => $lastViewedNote,
|
||||||
'errorMessage' => $errorMessage,
|
'errorMessage' => $errorMessage,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @NoAdminRequired
|
* @NoAdminRequired
|
||||||
*
|
*
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return DataResponse
|
* @return DataResponse
|
||||||
*/
|
*/
|
||||||
public function get($id) {
|
public function get($id) {
|
||||||
// save the last viewed note
|
// save the last viewed note
|
||||||
$this->settings->setUserValue(
|
$this->settings->setUserValue(
|
||||||
$this->userId, $this->appName, 'notesLastViewedNote', $id
|
$this->userId,
|
||||||
);
|
$this->appName,
|
||||||
|
'notesLastViewedNote',
|
||||||
|
$id
|
||||||
|
);
|
||||||
|
|
||||||
return $this->respond(function () use ($id) {
|
return $this->respond(function () use ($id) {
|
||||||
return $this->notesService->get($id, $this->userId);
|
return $this->notesService->get($id, $this->userId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @NoAdminRequired
|
* @NoAdminRequired
|
||||||
*
|
*
|
||||||
* @param string $content
|
* @param string $content
|
||||||
*/
|
*/
|
||||||
public function create($content='', $category=null) {
|
public function create($content = '', $category = null) {
|
||||||
$note = $this->notesService->create($this->userId);
|
$note = $this->notesService->create($this->userId);
|
||||||
$note = $this->notesService->update(
|
$note = $this->notesService->update(
|
||||||
$note->getId(), $content, $this->userId, $category
|
$note->getId(),
|
||||||
);
|
$content,
|
||||||
return new DataResponse($note);
|
$this->userId,
|
||||||
}
|
$category
|
||||||
|
);
|
||||||
|
return new DataResponse($note);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @NoAdminRequired
|
* @NoAdminRequired
|
||||||
*
|
*
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @param string $content
|
* @param string $content
|
||||||
* @return DataResponse
|
* @return DataResponse
|
||||||
*/
|
*/
|
||||||
public function update($id, $content) {
|
public function update($id, $content) {
|
||||||
return $this->respond(function () use ($id, $content) {
|
return $this->respond(function () use ($id, $content) {
|
||||||
return $this->notesService->update($id, $content, $this->userId);
|
return $this->notesService->update($id, $content, $this->userId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @NoAdminRequired
|
* @NoAdminRequired
|
||||||
*
|
*
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @param string $category
|
* @param string $category
|
||||||
* @return DataResponse
|
* @return DataResponse
|
||||||
*/
|
*/
|
||||||
public function category($id, $category) {
|
public function category($id, $category) {
|
||||||
return $this->respond(function () use ($id, $category) {
|
return $this->respond(function () use ($id, $category) {
|
||||||
$note = $this->notesService->update($id, null, $this->userId, $category);
|
$note = $this->notesService->update($id, null, $this->userId, $category);
|
||||||
return $note->category;
|
return $note->category;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @NoAdminRequired
|
* @NoAdminRequired
|
||||||
*
|
*
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @param boolean $favorite
|
* @param boolean $favorite
|
||||||
* @return DataResponse
|
* @return DataResponse
|
||||||
*/
|
*/
|
||||||
public function favorite($id, $favorite) {
|
public function favorite($id, $favorite) {
|
||||||
return $this->respond(function () use ($id, $favorite) {
|
return $this->respond(function () use ($id, $favorite) {
|
||||||
return $this->notesService->favorite($id, $favorite, $this->userId);
|
return $this->notesService->favorite($id, $favorite, $this->userId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @NoAdminRequired
|
* @NoAdminRequired
|
||||||
*
|
*
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @return DataResponse
|
* @return DataResponse
|
||||||
*/
|
*/
|
||||||
public function destroy($id) {
|
public function destroy($id) {
|
||||||
return $this->respond(function () use ($id) {
|
return $this->respond(function () use ($id) {
|
||||||
$this->notesService->delete($id, $this->userId);
|
$this->notesService->delete($id, $this->userId);
|
||||||
return [];
|
return [];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,4 @@
|
||||||
<?php
|
<?php
|
||||||
/**
|
|
||||||
* Nextcloud - Notes
|
|
||||||
*
|
|
||||||
* This file is licensed under the Affero General Public License version 3 or
|
|
||||||
* later. See the COPYING file.
|
|
||||||
*
|
|
||||||
* @author Bernhard Posselt <dev@bernhard-posselt.com>
|
|
||||||
* @copyright Bernhard Posselt 2012, 2014
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace OCA\Notes\Controller;
|
namespace OCA\Notes\Controller;
|
||||||
|
|
||||||
|
@ -23,33 +14,32 @@ use OCP\IRequest;
|
||||||
*/
|
*/
|
||||||
class PageController extends Controller {
|
class PageController extends Controller {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $AppName
|
* @param string $AppName
|
||||||
* @param IRequest $request
|
* @param IRequest $request
|
||||||
*/
|
*/
|
||||||
public function __construct($AppName, IRequest $request) {
|
public function __construct($AppName, IRequest $request) {
|
||||||
parent::__construct($AppName, $request);
|
parent::__construct($AppName, $request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @NoAdminRequired
|
* @NoAdminRequired
|
||||||
* @NoCSRFRequired
|
* @NoCSRFRequired
|
||||||
*
|
*
|
||||||
* @return TemplateResponse
|
* @return TemplateResponse
|
||||||
*/
|
*/
|
||||||
public function index() {
|
public function index() {
|
||||||
$response = new TemplateResponse(
|
$response = new TemplateResponse(
|
||||||
$this->appName,
|
$this->appName,
|
||||||
'main',
|
'main',
|
||||||
[ ]
|
[ ]
|
||||||
);
|
);
|
||||||
|
|
||||||
$csp = new ContentSecurityPolicy();
|
$csp = new ContentSecurityPolicy();
|
||||||
$csp->addAllowedImageDomain('*');
|
$csp->addAllowedImageDomain('*');
|
||||||
$response->setContentSecurityPolicy($csp);
|
$response->setContentSecurityPolicy($csp);
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
namespace OCA\Notes\Controller;
|
namespace OCA\Notes\Controller;
|
||||||
|
|
||||||
use OCP\AppFramework\Controller;
|
use OCP\AppFramework\Controller;
|
||||||
|
|
||||||
use OCP\IConfig;
|
use OCP\IConfig;
|
||||||
|
@ -10,8 +11,8 @@ use OCP\Files\IRootFolder;
|
||||||
use OCP\AppFramework\Http\JSONResponse;
|
use OCP\AppFramework\Http\JSONResponse;
|
||||||
use OCA\Notes\Service\SettingsService;
|
use OCA\Notes\Service\SettingsService;
|
||||||
|
|
||||||
class SettingsController extends Controller
|
class SettingsController extends Controller {
|
||||||
{
|
|
||||||
private $service;
|
private $service;
|
||||||
private $userSession;
|
private $userSession;
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,21 @@
|
||||||
<?php
|
<?php
|
||||||
/**
|
|
||||||
* Nextcloud - Notes
|
|
||||||
*
|
|
||||||
* This file is licensed under the Affero General Public License version 3 or
|
|
||||||
* later. See the COPYING file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace OCA\Notes\Db;
|
namespace OCA\Notes\Db;
|
||||||
|
|
||||||
use OCP\AppFramework\Db\Entity;
|
use OCP\AppFramework\Db\Entity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Meta
|
||||||
|
* @method string getUserId()
|
||||||
|
* @method void setUserId(string $value)
|
||||||
|
* @method integer getFileId()
|
||||||
|
* @method void setFileId(integer $value)
|
||||||
|
* @method integer getLastUpdate()
|
||||||
|
* @method void setLastUpdate(integer $value)
|
||||||
|
* @method string getEtag()
|
||||||
|
* @method void setEtag(string $value)
|
||||||
|
* @package OCA\Notes\Db
|
||||||
|
*/
|
||||||
class Meta extends Entity {
|
class Meta extends Entity {
|
||||||
|
|
||||||
public $userId;
|
public $userId;
|
||||||
|
|
|
@ -1,29 +1,24 @@
|
||||||
<?php
|
<?php
|
||||||
/**
|
|
||||||
* Nextcloud - Notes
|
|
||||||
*
|
|
||||||
* This file is licensed under the Affero General Public License version 3 or
|
|
||||||
* later. See the COPYING file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace OCA\Notes\Db;
|
namespace OCA\Notes\Db;
|
||||||
|
|
||||||
use OCP\IDBConnection;
|
use OCP\IDBConnection;
|
||||||
use OCP\AppFramework\Db\Mapper;
|
use OCP\AppFramework\Db\QBMapper;
|
||||||
|
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||||
|
|
||||||
class MetaMapper extends Mapper {
|
class MetaMapper extends QBMapper {
|
||||||
|
|
||||||
public function __construct(IDBConnection $db) {
|
public function __construct(IDBConnection $db) {
|
||||||
parent::__construct($db, 'notes_meta');
|
parent::__construct($db, 'notes_meta');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAll($userId) {
|
public function getAll($userId) {
|
||||||
$sql = 'SELECT * FROM `*PREFIX*notes_meta` WHERE user_id=?';
|
$qb = $this->db->getQueryBuilder();
|
||||||
return $this->findEntities($sql, [$userId]);
|
$qb->select('*')
|
||||||
}
|
->from('*PREFIX*notes_meta')
|
||||||
|
->where(
|
||||||
public function get($userId, $fileId) {
|
$qb->expr()->eq('user_id', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR))
|
||||||
$sql = 'SELECT * FROM `*PREFIX*notes_meta` WHERE user_id=? AND file_id=?';
|
);
|
||||||
return $this->findEntity($sql, [$userId, $fileId]);
|
return $this->findEntities($qb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
170
lib/Db/Note.php
170
lib/Db/Note.php
|
@ -1,20 +1,11 @@
|
||||||
<?php
|
<?php
|
||||||
/**
|
|
||||||
* Nextcloud - Notes
|
|
||||||
*
|
|
||||||
* This file is licensed under the Affero General Public License version 3 or
|
|
||||||
* later. See the COPYING file.
|
|
||||||
*
|
|
||||||
* @author Bernhard Posselt <dev@bernhard-posselt.com>
|
|
||||||
* @copyright Bernhard Posselt 2012, 2014
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace OCA\Notes\Db;
|
namespace OCA\Notes\Db;
|
||||||
|
|
||||||
use OCP\Files\File;
|
use OCP\Files\File;
|
||||||
use OCP\Files\Folder;
|
use OCP\Files\Folder;
|
||||||
use OCP\AppFramework\Db\Entity;
|
use OCP\AppFramework\Db\Entity;
|
||||||
use League\Flysystem\FileNotFoundException;
|
|
||||||
/**
|
/**
|
||||||
* Class Note
|
* Class Note
|
||||||
* @method integer getId()
|
* @method integer getId()
|
||||||
|
@ -38,87 +29,88 @@ use League\Flysystem\FileNotFoundException;
|
||||||
* @package OCA\Notes\Db
|
* @package OCA\Notes\Db
|
||||||
*/
|
*/
|
||||||
class Note extends Entity {
|
class Note extends Entity {
|
||||||
public $etag;
|
public $etag;
|
||||||
public $modified;
|
public $modified;
|
||||||
public $title;
|
public $title;
|
||||||
public $category;
|
public $category;
|
||||||
public $content = null;
|
public $content = null;
|
||||||
public $favorite = false;
|
public $favorite = false;
|
||||||
public $error = false;
|
public $error = false;
|
||||||
public $errorMessage='';
|
public $errorMessage='';
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
$this->addType('modified', 'integer');
|
$this->addType('modified', 'integer');
|
||||||
$this->addType('favorite', 'boolean');
|
$this->addType('favorite', 'boolean');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param File $file
|
* @param File $file
|
||||||
* @return static
|
* @return static
|
||||||
*/
|
*/
|
||||||
public static function fromFile(File $file, Folder $notesFolder, $tags=[], $onlyMeta=false) {
|
public static function fromFile(File $file, Folder $notesFolder, $tags = [], $onlyMeta = false) {
|
||||||
$note = new static();
|
$note = new static();
|
||||||
$note->setId($file->getId());
|
$note->setId($file->getId());
|
||||||
if(!$onlyMeta) {
|
if (!$onlyMeta) {
|
||||||
$fileContent=$file->getContent();
|
$fileContent=$file->getContent();
|
||||||
if($fileContent===false){
|
if ($fileContent===false) {
|
||||||
throw new FileNotFoundException("File not found");
|
throw new \Exception("File not found");
|
||||||
}
|
}
|
||||||
$note->setContent(self::convertEncoding($fileContent));
|
$note->setContent(self::convertEncoding($fileContent));
|
||||||
}
|
}
|
||||||
$note->setModified($file->getMTime());
|
$note->setModified($file->getMTime());
|
||||||
$note->setTitle(pathinfo($file->getName(),PATHINFO_FILENAME)); // remove extension
|
$note->setTitle(pathinfo($file->getName(), PATHINFO_FILENAME)); // remove extension
|
||||||
$subdir = substr(dirname($file->getPath()), strlen($notesFolder->getPath())+1);
|
$subdir = substr(dirname($file->getPath()), strlen($notesFolder->getPath())+1);
|
||||||
$note->setCategory($subdir ? $subdir : '');
|
$note->setCategory($subdir ? $subdir : '');
|
||||||
if(is_array($tags) && in_array(\OC\Tags::TAG_FAVORITE, $tags)) {
|
if (is_array($tags) && in_array(\OC\Tags::TAG_FAVORITE, $tags)) {
|
||||||
$note->setFavorite(true);
|
$note->setFavorite(true);
|
||||||
//unset($tags[array_search(\OC\Tags::TAG_FAVORITE, $tags)]);
|
//unset($tags[array_search(\OC\Tags::TAG_FAVORITE, $tags)]);
|
||||||
}
|
}
|
||||||
if(!$onlyMeta) {
|
if (!$onlyMeta) {
|
||||||
$note->updateETag();
|
$note->updateETag();
|
||||||
}
|
}
|
||||||
$note->resetUpdatedFields();
|
$note->resetUpdatedFields();
|
||||||
return $note;
|
return $note;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* @param File $file
|
|
||||||
* @return static
|
|
||||||
*/
|
|
||||||
public static function fromException($message,File $file,Folder $notesFolder,$tags=[]){
|
|
||||||
$note = new static();
|
|
||||||
$note->setId($file->getId());
|
|
||||||
$note->setErrorMessage($message);
|
|
||||||
$note->setError(true);
|
|
||||||
$note->setContent($message);
|
|
||||||
$note->setModified(null);
|
|
||||||
$note->setTitle(pathinfo($file->getName(),PATHINFO_FILENAME)); // remove extension
|
|
||||||
$subdir = substr(dirname($file->getPath()), strlen($notesFolder->getPath())+1);
|
|
||||||
$note->setCategory($subdir ? $subdir : null);
|
|
||||||
if(is_array($tags) && in_array(\OC\Tags::TAG_FAVORITE, $tags)) {
|
|
||||||
$note->setFavorite(true);
|
|
||||||
//unset($tags[array_search(\OC\Tags::TAG_FAVORITE, $tags)]);
|
|
||||||
}
|
|
||||||
$note->updateETag();
|
|
||||||
$note->resetUpdatedFields();
|
|
||||||
return $note;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function convertEncoding($str) {
|
/**
|
||||||
if(!mb_check_encoding($str, 'UTF-8')) {
|
* @param File $file
|
||||||
$str = mb_convert_encoding($str, 'UTF-8');
|
* @return static
|
||||||
}
|
*/
|
||||||
return $str;
|
public static function fromException($message, File $file, Folder $notesFolder, $tags = []) {
|
||||||
}
|
$note = new static();
|
||||||
|
$note->setId($file->getId());
|
||||||
|
$note->setErrorMessage($message);
|
||||||
|
$note->setError(true);
|
||||||
|
$note->setContent($message);
|
||||||
|
$note->setModified(null);
|
||||||
|
$note->setTitle(pathinfo($file->getName(), PATHINFO_FILENAME)); // remove extension
|
||||||
|
$subdir = substr(dirname($file->getPath()), strlen($notesFolder->getPath())+1);
|
||||||
|
$note->setCategory($subdir ? $subdir : null);
|
||||||
|
if (is_array($tags) && in_array(\OC\Tags::TAG_FAVORITE, $tags)) {
|
||||||
|
$note->setFavorite(true);
|
||||||
|
//unset($tags[array_search(\OC\Tags::TAG_FAVORITE, $tags)]);
|
||||||
|
}
|
||||||
|
$note->updateETag();
|
||||||
|
$note->resetUpdatedFields();
|
||||||
|
return $note;
|
||||||
|
}
|
||||||
|
|
||||||
private function updateETag() {
|
private static function convertEncoding($str) {
|
||||||
// collect all relevant attributes
|
if (!mb_check_encoding($str, 'UTF-8')) {
|
||||||
$data = '';
|
$str = mb_convert_encoding($str, 'UTF-8');
|
||||||
foreach(get_object_vars($this) as $key => $val) {
|
}
|
||||||
if($key!=='etag') {
|
return $str;
|
||||||
$data .= $val;
|
}
|
||||||
}
|
|
||||||
}
|
private function updateETag() {
|
||||||
$etag = md5($data);
|
// collect all relevant attributes
|
||||||
$this->setEtag($etag);
|
$data = '';
|
||||||
}
|
foreach (get_object_vars($this) as $key => $val) {
|
||||||
|
if ($key!=='etag') {
|
||||||
|
$data .= $val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$etag = md5($data);
|
||||||
|
$this->setEtag($etag);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,4 @@
|
||||||
<?php
|
<?php
|
||||||
/**
|
|
||||||
* Nextcloud - Notes
|
|
||||||
*
|
|
||||||
* This file is licensed under the Affero General Public License version 3 or
|
|
||||||
* later. See the COPYING file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace OCA\Notes\Service;
|
namespace OCA\Notes\Service;
|
||||||
|
|
||||||
|
@ -29,18 +23,18 @@ class MetaService {
|
||||||
$metas = $this->metaMapper->getAll($userId);
|
$metas = $this->metaMapper->getAll($userId);
|
||||||
$metas = $this->getIndexedArray($metas, 'fileId');
|
$metas = $this->getIndexedArray($metas, 'fileId');
|
||||||
$notes = $this->getIndexedArray($notes, 'id');
|
$notes = $this->getIndexedArray($notes, 'id');
|
||||||
foreach($metas as $id=>$meta) {
|
foreach ($metas as $id => $meta) {
|
||||||
if(!array_key_exists($id, $notes)) {
|
if (!array_key_exists($id, $notes)) {
|
||||||
// DELETE obsolete notes
|
// DELETE obsolete notes
|
||||||
$this->metaMapper->delete($meta);
|
$this->metaMapper->delete($meta);
|
||||||
unset($metas[$id]);
|
unset($metas[$id]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach($notes as $id=>$note) {
|
foreach ($notes as $id => $note) {
|
||||||
if(!array_key_exists($id, $metas)) {
|
if (!array_key_exists($id, $metas)) {
|
||||||
// INSERT new notes
|
// INSERT new notes
|
||||||
$metas[$note->getId()] = $this->create($userId, $note);
|
$metas[$note->getId()] = $this->create($userId, $note);
|
||||||
} elseif($note->getEtag()!==$metas[$id]->getEtag()) {
|
} elseif ($note->getEtag()!==$metas[$id]->getEtag()) {
|
||||||
// UPDATE changed notes
|
// UPDATE changed notes
|
||||||
$meta = $metas[$id];
|
$meta = $metas[$id];
|
||||||
$this->updateIfNeeded($meta, $note);
|
$this->updateIfNeeded($meta, $note);
|
||||||
|
@ -53,7 +47,7 @@ class MetaService {
|
||||||
$property = ucfirst($property);
|
$property = ucfirst($property);
|
||||||
$getter = 'get'.$property;
|
$getter = 'get'.$property;
|
||||||
$result = array();
|
$result = array();
|
||||||
foreach($data as $entity) {
|
foreach ($data as $entity) {
|
||||||
$result[$entity->$getter()] = $entity;
|
$result[$entity->$getter()] = $entity;
|
||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
|
@ -66,7 +60,7 @@ class MetaService {
|
||||||
}
|
}
|
||||||
|
|
||||||
private function updateIfNeeded(&$meta, $note) {
|
private function updateIfNeeded(&$meta, $note) {
|
||||||
if($note->getEtag()!==$meta->getEtag()) {
|
if ($note->getEtag()!==$meta->getEtag()) {
|
||||||
$meta->setEtag($note->getEtag());
|
$meta->setEtag($note->getEtag());
|
||||||
$meta->setLastUpdate(time());
|
$meta->setLastUpdate(time());
|
||||||
$this->metaMapper->update($meta);
|
$this->metaMapper->update($meta);
|
||||||
|
|
|
@ -1,13 +1,4 @@
|
||||||
<?php
|
<?php
|
||||||
/**
|
|
||||||
* Nextcloud - Notes
|
|
||||||
*
|
|
||||||
* This file is licensed under the Affero General Public License version 3 or
|
|
||||||
* later. See the COPYING file.
|
|
||||||
*
|
|
||||||
* @author Bernhard Posselt <dev@bernhard-posselt.com>
|
|
||||||
* @copyright Bernhard Posselt 2012, 2014
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace OCA\Notes\Service;
|
namespace OCA\Notes\Service;
|
||||||
|
|
||||||
|
@ -18,4 +9,5 @@ use Exception;
|
||||||
*
|
*
|
||||||
* @package OCA\Notes\Service
|
* @package OCA\Notes\Service
|
||||||
*/
|
*/
|
||||||
class NoteDoesNotExistException extends Exception {}
|
class NoteDoesNotExistException extends Exception {
|
||||||
|
}
|
||||||
|
|
|
@ -1,11 +1,4 @@
|
||||||
<?php
|
<?php
|
||||||
/**
|
|
||||||
* Nextcloud - Notes
|
|
||||||
*
|
|
||||||
* This file is licensed under the Affero General Public License version 3 or
|
|
||||||
* later. See the COPYING file.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace OCA\Notes\Service;
|
namespace OCA\Notes\Service;
|
||||||
|
|
||||||
|
@ -16,4 +9,5 @@ use Exception;
|
||||||
*
|
*
|
||||||
* @package OCA\Notes\Service
|
* @package OCA\Notes\Service
|
||||||
*/
|
*/
|
||||||
class NotesFolderException extends Exception {}
|
class NotesFolderException extends Exception {
|
||||||
|
}
|
||||||
|
|
|
@ -1,13 +1,4 @@
|
||||||
<?php
|
<?php
|
||||||
/**
|
|
||||||
* Nextcloud - Notes
|
|
||||||
*
|
|
||||||
* This file is licensed under the Affero General Public License version 3 or
|
|
||||||
* later. See the COPYING file.
|
|
||||||
*
|
|
||||||
* @author Bernhard Posselt <dev@bernhard-posselt.com>
|
|
||||||
* @copyright Bernhard Posselt 2012, 2014
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace OCA\Notes\Service;
|
namespace OCA\Notes\Service;
|
||||||
|
|
||||||
|
@ -17,13 +8,11 @@ use OCP\Files\IRootFolder;
|
||||||
use OCP\Files\Folder;
|
use OCP\Files\Folder;
|
||||||
use OCP\ILogger;
|
use OCP\ILogger;
|
||||||
use OCP\Encryption\Exceptions\GenericEncryptionException;
|
use OCP\Encryption\Exceptions\GenericEncryptionException;
|
||||||
use League\Flysystem\FileNotFoundException;
|
|
||||||
use OCA\Notes\Db\Note;
|
use OCA\Notes\Db\Note;
|
||||||
use OCA\Notes\Service\SettingsService;
|
use OCA\Notes\Service\SettingsService;
|
||||||
use OCP\IConfig;
|
use OCP\IConfig;
|
||||||
use OCP\IUserSession;
|
use OCP\IUserSession;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class NotesService
|
* Class NotesService
|
||||||
*
|
*
|
||||||
|
@ -31,12 +20,12 @@ use OCP\IUserSession;
|
||||||
*/
|
*/
|
||||||
class NotesService {
|
class NotesService {
|
||||||
|
|
||||||
private $l10n;
|
private $l10n;
|
||||||
private $root;
|
private $root;
|
||||||
private $logger;
|
private $logger;
|
||||||
private $config;
|
private $config;
|
||||||
private $settings;
|
private $settings;
|
||||||
private $appName;
|
private $appName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param IRootFolder $root
|
* @param IRootFolder $root
|
||||||
|
@ -46,374 +35,379 @@ class NotesService {
|
||||||
* @param \OCA\Notes\Service\SettingsService $settings
|
* @param \OCA\Notes\Service\SettingsService $settings
|
||||||
* @param String $appName
|
* @param String $appName
|
||||||
*/
|
*/
|
||||||
public function __construct (IRootFolder $root, IL10N $l10n, ILogger $logger, IConfig $config, SettingsService $settings, $appName) {
|
public function __construct(IRootFolder $root, IL10N $l10n, ILogger $logger, IConfig $config, SettingsService $settings, $appName) {
|
||||||
$this->root = $root;
|
$this->root = $root;
|
||||||
$this->l10n = $l10n;
|
$this->l10n = $l10n;
|
||||||
$this->logger = $logger;
|
$this->logger = $logger;
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
$this->settings = $settings;
|
$this->settings = $settings;
|
||||||
$this->appName = $appName;
|
$this->appName = $appName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $userId
|
* @param string $userId
|
||||||
* @return array with all notes in the current directory
|
* @return array with all notes in the current directory
|
||||||
*/
|
*/
|
||||||
public function getAll ($userId, $onlyMeta=false) {
|
public function getAll($userId, $onlyMeta = false) {
|
||||||
$notesFolder = $this->getFolderForUser($userId);
|
$notesFolder = $this->getFolderForUser($userId);
|
||||||
$notes = $this->gatherNoteFiles($notesFolder);
|
$notes = $this->gatherNoteFiles($notesFolder);
|
||||||
$filesById = [];
|
$filesById = [];
|
||||||
foreach($notes as $note) {
|
foreach ($notes as $note) {
|
||||||
$filesById[$note->getId()] = $note;
|
$filesById[$note->getId()] = $note;
|
||||||
}
|
}
|
||||||
$tagger = \OC::$server->getTagManager()->load('files');
|
$tagger = \OC::$server->getTagManager()->load('files');
|
||||||
if($tagger===null) {
|
if ($tagger===null) {
|
||||||
$tags = [];
|
$tags = [];
|
||||||
} else {
|
} else {
|
||||||
$tags = $tagger->getTagsForObjects(array_keys($filesById));
|
$tags = $tagger->getTagsForObjects(array_keys($filesById));
|
||||||
}
|
}
|
||||||
|
|
||||||
$notes = [];
|
$notes = [];
|
||||||
foreach($filesById as $id=>$file) {
|
foreach ($filesById as $id => $file) {
|
||||||
$notes[] = $this->getNote($file, $notesFolder, array_key_exists($id, $tags) ? $tags[$id] : [], $onlyMeta);
|
$notes[] = $this->getNote($file, $notesFolder, array_key_exists($id, $tags) ? $tags[$id] : [], $onlyMeta);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $notes;
|
return $notes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to get a single note by id
|
* Used to get a single note by id
|
||||||
* @param int $id the id of the note to get
|
* @param int $id the id of the note to get
|
||||||
* @param string $userId
|
* @param string $userId
|
||||||
* @throws NoteDoesNotExistException if note does not exist
|
* @throws NoteDoesNotExistException if note does not exist
|
||||||
* @return Note
|
* @return Note
|
||||||
*/
|
*/
|
||||||
public function get ($id, $userId) {
|
public function get($id, $userId) {
|
||||||
$folder = $this->getFolderForUser($userId);
|
$folder = $this->getFolderForUser($userId);
|
||||||
return $this->getNote($this->getFileById($folder, $id), $folder, $this->getTags($id));
|
return $this->getNote($this->getFileById($folder, $id), $folder, $this->getTags($id));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getTags ($id) {
|
private function getTags($id) {
|
||||||
$tagger = \OC::$server->getTagManager()->load('files');
|
$tagger = \OC::$server->getTagManager()->load('files');
|
||||||
if($tagger===null) {
|
if ($tagger===null) {
|
||||||
$tags = [];
|
$tags = [];
|
||||||
} else {
|
} else {
|
||||||
$tags = $tagger->getTagsForObjects([$id]);
|
$tags = $tagger->getTagsForObjects([$id]);
|
||||||
}
|
}
|
||||||
return array_key_exists($id, $tags) ? $tags[$id] : [];
|
return array_key_exists($id, $tags) ? $tags[$id] : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getNote($file, $notesFolder, $tags=[], $onlyMeta=false) {
|
private function getNote($file, $notesFolder, $tags = [], $onlyMeta = false) {
|
||||||
$id = $file->getId();
|
$id = $file->getId();
|
||||||
try {
|
try {
|
||||||
$note = Note::fromFile($file, $notesFolder, $tags, $onlyMeta);
|
$note = Note::fromFile($file, $notesFolder, $tags, $onlyMeta);
|
||||||
} catch(FileNotFoundException $e){
|
} catch (GenericEncryptionException $e) {
|
||||||
$note = Note::fromException($this->l10n->t('File error').': ('.$file->getName().') '.$e->getMessage(), $file, $notesFolder, array_key_exists($id, $tags) ? $tags[$id] : []);
|
$note = Note::fromException($this->l10n->t('Encryption Error').': ('.$file->getName().') '.$e->getMessage(), $file, $notesFolder, array_key_exists($id, $tags) ? $tags[$id] : []);
|
||||||
} catch(GenericEncryptionException $e) {
|
} catch (\Exception $e) {
|
||||||
$note = Note::fromException($this->l10n->t('Encryption Error').': ('.$file->getName().') '.$e->getMessage(), $file, $notesFolder, array_key_exists($id, $tags) ? $tags[$id] : []);
|
$note = Note::fromException($this->l10n->t('Error').': ('.$file->getName().') '.$e->getMessage(), $file, $notesFolder, array_key_exists($id, $tags) ? $tags[$id] : []);
|
||||||
} catch(\Exception $e) {
|
}
|
||||||
$note = Note::fromException($this->l10n->t('Error').': ('.$file->getName().') '.$e->getMessage(), $file, $notesFolder, array_key_exists($id, $tags) ? $tags[$id] : []);
|
return $note;
|
||||||
}
|
}
|
||||||
return $note;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a note and returns the empty note
|
* Creates a note and returns the empty note
|
||||||
* @param string $userId
|
* @param string $userId
|
||||||
* @see update for setting note content
|
* @see update for setting note content
|
||||||
* @return Note the newly created note
|
* @return Note the newly created note
|
||||||
*/
|
*/
|
||||||
public function create ($userId) {
|
public function create($userId) {
|
||||||
$title = $this->l10n->t('New note');
|
$title = $this->l10n->t('New note');
|
||||||
$folder = $this->getFolderForUser($userId);
|
$folder = $this->getFolderForUser($userId);
|
||||||
|
|
||||||
// check new note exists already and we need to number it
|
// check new note exists already and we need to number it
|
||||||
// pass -1 because no file has id -1 and that will ensure
|
// pass -1 because no file has id -1 and that will ensure
|
||||||
// to only return filenames that dont yet exist
|
// to only return filenames that dont yet exist
|
||||||
$path = $this->generateFileName($folder, $title, $this->settings->get($userId, 'fileSuffix'), -1);
|
$path = $this->generateFileName($folder, $title, $this->settings->get($userId, 'fileSuffix'), -1);
|
||||||
$file = $folder->newFile($path);
|
$file = $folder->newFile($path);
|
||||||
|
|
||||||
// If server-side encryption is activated, the server creates an empty file without signature
|
// If server-side encryption is activated, the server creates an empty file without signature
|
||||||
// which leads to an GenericEncryptionException('Missing Signature') afterwards.
|
// which leads to an GenericEncryptionException('Missing Signature') afterwards.
|
||||||
// Saving a space-char (and removing it later) is a working work-around.
|
// Saving a space-char (and removing it later) is a working work-around.
|
||||||
$file->putContent(' ');
|
$file->putContent(' ');
|
||||||
|
|
||||||
return $this->getNote($file, $folder);
|
return $this->getNote($file, $folder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates a note. Be sure to check the returned note since the title is
|
* Updates a note. Be sure to check the returned note since the title is
|
||||||
* dynamically generated and filename conflicts are resolved
|
* dynamically generated and filename conflicts are resolved
|
||||||
* @param int $id the id of the note used to update
|
* @param int $id the id of the note used to update
|
||||||
* @param string $content the content which will be written into the note
|
* @param string|null $content the content which will be written into the note
|
||||||
* the title is generated from the first line of the content
|
* the title is generated from the first line of the content
|
||||||
* @param int $mtime time of the note modification (optional)
|
* @param string|null $category the category in which the note should be saved
|
||||||
* @throws NoteDoesNotExistException if note does not exist
|
* @param int $mtime time of the note modification (optional)
|
||||||
* @return \OCA\Notes\Db\Note the updated note
|
* @throws NoteDoesNotExistException if note does not exist
|
||||||
*/
|
* @return \OCA\Notes\Db\Note the updated note
|
||||||
public function update ($id, $content, $userId, $category=null, $mtime=0) {
|
*/
|
||||||
$notesFolder = $this->getFolderForUser($userId);
|
public function update($id, $content, $userId, $category = null, $mtime = 0) {
|
||||||
$file = $this->getFileById($notesFolder, $id);
|
$notesFolder = $this->getFolderForUser($userId);
|
||||||
$title = $this->getSafeTitleFromContent( $content===null ? $file->getContent() : $content );
|
$file = $this->getFileById($notesFolder, $id);
|
||||||
|
$title = $this->getSafeTitleFromContent($content===null ? $file->getContent() : $content);
|
||||||
|
|
||||||
|
|
||||||
// rename/move file with respect to title/category
|
// rename/move file with respect to title/category
|
||||||
// this can fail if access rights are not sufficient or category name is illegal
|
// this can fail if access rights are not sufficient or category name is illegal
|
||||||
try {
|
try {
|
||||||
$currentFilePath = $this->root->getFullPath($file->getPath());
|
$currentFilePath = $this->root->getFullPath($file->getPath());
|
||||||
$currentBasePath = pathinfo($currentFilePath, PATHINFO_DIRNAME);
|
$currentBasePath = pathinfo($currentFilePath, PATHINFO_DIRNAME);
|
||||||
$fileSuffix = '.' . pathinfo($file->getName(), PATHINFO_EXTENSION);
|
$fileSuffix = '.' . pathinfo($file->getName(), PATHINFO_EXTENSION);
|
||||||
|
|
||||||
// detect (new) folder path based on category name
|
// detect (new) folder path based on category name
|
||||||
if($category===null) {
|
if ($category===null) {
|
||||||
$basePath = $currentBasePath;
|
$basePath = $currentBasePath;
|
||||||
} else {
|
} else {
|
||||||
$basePath = $notesFolder->getPath();
|
$basePath = $notesFolder->getPath();
|
||||||
if(!empty($category)) {
|
if (!empty($category)) {
|
||||||
// sanitise path
|
// sanitise path
|
||||||
$cats = explode('/', $category);
|
$cats = explode('/', $category);
|
||||||
$cats = array_map([$this, 'sanitisePath'], $cats);
|
$cats = array_map([$this, 'sanitisePath'], $cats);
|
||||||
$cats = array_filter($cats, function($str) { return !empty($str); });
|
$cats = array_filter($cats, function ($str) {
|
||||||
$basePath .= '/'.implode('/', $cats);
|
return !empty($str);
|
||||||
}
|
});
|
||||||
}
|
$basePath .= '/'.implode('/', $cats);
|
||||||
$folder = $this->getOrCreateFolder($basePath);
|
}
|
||||||
|
}
|
||||||
|
$folder = $this->getOrCreateFolder($basePath);
|
||||||
|
|
||||||
// assemble new file path
|
// assemble new file path
|
||||||
$newFilePath = $basePath . '/' . $this->generateFileName($folder, $title, $fileSuffix, $id);
|
$newFilePath = $basePath . '/' . $this->generateFileName($folder, $title, $fileSuffix, $id);
|
||||||
|
|
||||||
// if the current path is not the new path, the file has to be renamed
|
// if the current path is not the new path, the file has to be renamed
|
||||||
if($currentFilePath !== $newFilePath) {
|
if ($currentFilePath !== $newFilePath) {
|
||||||
$file->move($newFilePath);
|
$file->move($newFilePath);
|
||||||
}
|
}
|
||||||
if($currentBasePath !== $basePath) {
|
if ($currentBasePath !== $basePath) {
|
||||||
$this->deleteEmptyFolder($notesFolder, $this->root->get($currentBasePath));
|
$this->deleteEmptyFolder($notesFolder, $this->root->get($currentBasePath));
|
||||||
}
|
}
|
||||||
} catch(\OCP\Files\NotPermittedException $e) {
|
} catch (\OCP\Files\NotPermittedException $e) {
|
||||||
$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]);
|
$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]);
|
||||||
} catch(\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$this->logger->error('Moving note '.$id.' ('.$title.') to the desired target has failed with a '.get_class($e).': '.$e->getMessage(), ['app' => $this->appName]);
|
$this->logger->error('Moving note '.$id.' ('.$title.') to the desired target has failed with a '.get_class($e).': '.$e->getMessage(), ['app' => $this->appName]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if($content !== null) {
|
if ($content !== null) {
|
||||||
$file->putContent($content);
|
$file->putContent($content);
|
||||||
}
|
}
|
||||||
|
|
||||||
if($mtime) {
|
if ($mtime) {
|
||||||
$file->touch($mtime);
|
$file->touch($mtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->getNote($file, $notesFolder, $this->getTags($id));
|
return $this->getNote($file, $notesFolder, $this->getTags($id));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set or unset a note as favorite.
|
* Set or unset a note as favorite.
|
||||||
* @param int $id the id of the note used to update
|
* @param int $id the id of the note used to update
|
||||||
* @param boolean $favorite whether the note should be a favorite or not
|
* @param boolean $favorite whether the note should be a favorite or not
|
||||||
* @throws NoteDoesNotExistException if note does not exist
|
* @throws NoteDoesNotExistException if note does not exist
|
||||||
* @return boolean the new favorite state of the note
|
* @return boolean the new favorite state of the note
|
||||||
*/
|
*/
|
||||||
public function favorite ($id, $favorite, $userId){
|
public function favorite($id, $favorite, $userId) {
|
||||||
$folder = $this->getFolderForUser($userId);
|
$folder = $this->getFolderForUser($userId);
|
||||||
$file = $this->getFileById($folder, $id);
|
$file = $this->getFileById($folder, $id);
|
||||||
if(!$this->isNote($file)) {
|
if (!$this->isNote($file)) {
|
||||||
throw new NoteDoesNotExistException();
|
throw new NoteDoesNotExistException();
|
||||||
}
|
}
|
||||||
$tagger = \OC::$server->getTagManager()->load('files');
|
$tagger = \OC::$server->getTagManager()->load('files');
|
||||||
if($favorite)
|
if ($favorite) {
|
||||||
$tagger->addToFavorites($id);
|
$tagger->addToFavorites($id);
|
||||||
else
|
} else {
|
||||||
$tagger->removeFromFavorites($id);
|
$tagger->removeFromFavorites($id);
|
||||||
|
}
|
||||||
|
|
||||||
$tags = $tagger->getTagsForObjects([$id]);
|
$tags = $tagger->getTagsForObjects([$id]);
|
||||||
return array_key_exists($id, $tags) && in_array(\OC\Tags::TAG_FAVORITE, $tags[$id]);
|
return array_key_exists($id, $tags) && in_array(\OC\Tags::TAG_FAVORITE, $tags[$id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a note
|
* Deletes a note
|
||||||
* @param int $id the id of the note which should be deleted
|
* @param int $id the id of the note which should be deleted
|
||||||
* @param string $userId
|
* @param string $userId
|
||||||
* @throws NoteDoesNotExistException if note does not
|
* @throws NoteDoesNotExistException if note does not
|
||||||
* exist
|
* exist
|
||||||
*/
|
*/
|
||||||
public function delete ($id, $userId) {
|
public function delete($id, $userId) {
|
||||||
$notesFolder = $this->getFolderForUser($userId);
|
$notesFolder = $this->getFolderForUser($userId);
|
||||||
$file = $this->getFileById($notesFolder, $id);
|
$file = $this->getFileById($notesFolder, $id);
|
||||||
$parent = $file->getParent();
|
$parent = $file->getParent();
|
||||||
$file->delete();
|
$file->delete();
|
||||||
$this->deleteEmptyFolder($notesFolder, $parent);
|
$this->deleteEmptyFolder($notesFolder, $parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// removes characters that are illegal in a file or folder name on some operating systems
|
// removes characters that are illegal in a file or folder name on some operating systems
|
||||||
private function sanitisePath($str) {
|
private function sanitisePath($str) {
|
||||||
// remove characters which are illegal on Windows (includes illegal characters on Unix/Linux)
|
// remove characters which are illegal on Windows (includes illegal characters on Unix/Linux)
|
||||||
// prevents also directory traversal by eliminiating slashes
|
// prevents also directory traversal by eliminiating slashes
|
||||||
// see also \OC\Files\Storage\Common::verifyPosixPath(...)
|
// see also \OC\Files\Storage\Common::verifyPosixPath(...)
|
||||||
$str = str_replace(['*', '|', '/', '\\', ':', '"', '<', '>', '?'], '', $str);
|
$str = str_replace(['*', '|', '/', '\\', ':', '"', '<', '>', '?'], '', $str);
|
||||||
|
|
||||||
// if mysql doesn't support 4byte UTF-8, then remove those characters
|
// if mysql doesn't support 4byte UTF-8, then remove those characters
|
||||||
// see \OC\Files\Storage\Common::verifyPath(...)
|
// see \OC\Files\Storage\Common::verifyPath(...)
|
||||||
if (!\OC::$server->getDatabaseConnection()->supports4ByteText()) {
|
if (!\OC::$server->getDatabaseConnection()->supports4ByteText()) {
|
||||||
$str = preg_replace('%(?:
|
$str = preg_replace('%(?:
|
||||||
\xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
|
\xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
|
||||||
| [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
|
| [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
|
||||||
| \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
|
| \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
|
||||||
)%xs', '', $str);
|
)%xs', '', $str);
|
||||||
}
|
}
|
||||||
|
|
||||||
// prevent file to be hidden
|
// prevent file to be hidden
|
||||||
$str = preg_replace("/^[\. ]+/mu", "", $str);
|
$str = preg_replace("/^[\. ]+/mu", "", $str);
|
||||||
return trim($str);
|
return trim($str);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getSafeTitleFromContent($content) {
|
private function getSafeTitleFromContent($content) {
|
||||||
// prepare content: remove markdown characters and empty spaces
|
// prepare content: remove markdown characters and empty spaces
|
||||||
$content = preg_replace("/^\s*[*+-]\s+/mu", "", $content); // list item
|
$content = preg_replace("/^\s*[*+-]\s+/mu", "", $content); // list item
|
||||||
$content = preg_replace("/^#+\s+(.*?)\s*#*$/mu", "$1", $content); // headline
|
$content = preg_replace("/^#+\s+(.*?)\s*#*$/mu", "$1", $content); // headline
|
||||||
$content = preg_replace("/^(=+|-+)$/mu", "", $content); // separate line for headline
|
$content = preg_replace("/^(=+|-+)$/mu", "", $content); // separate line for headline
|
||||||
$content = preg_replace("/(\*+|_+)(.*?)\\1/mu", "$2", $content); // emphasis
|
$content = preg_replace("/(\*+|_+)(.*?)\\1/mu", "$2", $content); // emphasis
|
||||||
|
|
||||||
// sanitize: prevent directory traversal, illegal characters and unintended file names
|
// sanitize: prevent directory traversal, illegal characters and unintended file names
|
||||||
$content = $this->sanitisePath($content);
|
$content = $this->sanitisePath($content);
|
||||||
|
|
||||||
// generate title from the first line of the content
|
// generate title from the first line of the content
|
||||||
$splitContent = preg_split("/\R/u", $content, 2);
|
$splitContent = preg_split("/\R/u", $content, 2);
|
||||||
$title = trim($splitContent[0]);
|
$title = trim($splitContent[0]);
|
||||||
|
|
||||||
// ensure that title is not empty
|
// ensure that title is not empty
|
||||||
if(empty($title)) {
|
if (empty($title)) {
|
||||||
$title = $this->l10n->t('New note');
|
$title = $this->l10n->t('New note');
|
||||||
}
|
}
|
||||||
|
|
||||||
// using a maximum of 100 chars should be enough
|
// using a maximum of 100 chars should be enough
|
||||||
$title = mb_substr($title, 0, 100, "UTF-8");
|
$title = mb_substr($title, 0, 100, "UTF-8");
|
||||||
|
|
||||||
return $title;
|
return $title;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Folder $folder
|
* @param Folder $folder
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @throws NoteDoesNotExistException
|
* @throws NoteDoesNotExistException
|
||||||
* @return \OCP\Files\File
|
* @return \OCP\Files\File
|
||||||
*/
|
*/
|
||||||
private function getFileById ($folder, $id) {
|
private function getFileById($folder, $id) {
|
||||||
$file = $folder->getById($id);
|
$file = $folder->getById($id);
|
||||||
|
|
||||||
if(count($file) <= 0 || !$this->isNote($file[0])) {
|
if (count($file) <= 0 || !$this->isNote($file[0])) {
|
||||||
throw new NoteDoesNotExistException();
|
throw new NoteDoesNotExistException();
|
||||||
}
|
}
|
||||||
return $file[0];
|
return $file[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $userId the user id
|
* @param string $userId the user id
|
||||||
* @return boolean true if folder is accessible, or Exception otherwise
|
* @return boolean true if folder is accessible, or Exception otherwise
|
||||||
*/
|
*/
|
||||||
public function checkNotesFolder($userId) {
|
public function checkNotesFolder($userId) {
|
||||||
$folder = $this->getFolderForUser($userId);
|
$this->getFolderForUser($userId);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $userId the user id
|
* @param string $userId the user id
|
||||||
* @return Folder
|
* @return Folder
|
||||||
*/
|
*/
|
||||||
private function getFolderForUser ($userId) {
|
private function getFolderForUser($userId) {
|
||||||
$path = '/' . $userId . '/files/' . $this->settings->get($userId, 'notesPath');
|
$path = '/' . $userId . '/files/' . $this->settings->get($userId, 'notesPath');
|
||||||
try {
|
try {
|
||||||
$folder = $this->getOrCreateFolder($path);
|
$folder = $this->getOrCreateFolder($path);
|
||||||
} catch(\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
throw new NotesFolderException($path);
|
throw new NotesFolderException($path);
|
||||||
}
|
}
|
||||||
return $folder;
|
return $folder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds a folder and creates it if non-existent
|
* Finds a folder and creates it if non-existent
|
||||||
* @param string $path path to the folder
|
* @param string $path path to the folder
|
||||||
* @return Folder
|
* @return Folder
|
||||||
*/
|
*/
|
||||||
private function getOrCreateFolder($path) {
|
private function getOrCreateFolder($path) {
|
||||||
if ($this->root->nodeExists($path)) {
|
if ($this->root->nodeExists($path)) {
|
||||||
$folder = $this->root->get($path);
|
$folder = $this->root->get($path);
|
||||||
} else {
|
} else {
|
||||||
$folder = $this->root->newFolder($path);
|
$folder = $this->root->newFolder($path);
|
||||||
}
|
}
|
||||||
return $folder;
|
return $folder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Delete a folder and it's parent(s) if it's/they're empty
|
* Delete a folder and it's parent(s) if it's/they're empty
|
||||||
* @param Folder root folder for notes
|
* @param Folder root folder for notes
|
||||||
* @param Folder folder to delete
|
* @param Folder folder to delete
|
||||||
*/
|
*/
|
||||||
private function deleteEmptyFolder(Folder $notesFolder, Folder $folder) {
|
private function deleteEmptyFolder(Folder $notesFolder, Folder $folder) {
|
||||||
$content = $folder->getDirectoryListing();
|
$content = $folder->getDirectoryListing();
|
||||||
$isEmpty = !count($content);
|
$isEmpty = !count($content);
|
||||||
$isNotesFolder = $folder->getPath()===$notesFolder->getPath();
|
$isNotesFolder = $folder->getPath()===$notesFolder->getPath();
|
||||||
if($isEmpty && !$isNotesFolder) {
|
if ($isEmpty && !$isNotesFolder) {
|
||||||
$this->logger->info('Deleting empty category folder '.$folder->getPath(), ['app' => $this->appName]);
|
$this->logger->info('Deleting empty category folder '.$folder->getPath(), ['app' => $this->appName]);
|
||||||
$parent = $folder->getParent();
|
$parent = $folder->getParent();
|
||||||
$folder->delete();
|
$folder->delete();
|
||||||
$this->deleteEmptyFolder($notesFolder, $parent);
|
$this->deleteEmptyFolder($notesFolder, $parent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get path of file and the title.txt and check if they are the same
|
* get path of file and the title.txt and check if they are the same
|
||||||
* file. If not the title needs to be renamed
|
* file. If not the title needs to be renamed
|
||||||
*
|
*
|
||||||
* @param Folder $folder a folder to the notes directory
|
* @param Folder $folder a folder to the notes directory
|
||||||
* @param string $title the filename which should be used
|
* @param string $title the filename which should be used
|
||||||
* @param string $suffix the suffix (incl. dot) which should be used
|
* @param string $suffix the suffix (incl. dot) which should be used
|
||||||
* @param int $id the id of the note for which the title should be generated
|
* @param int $id the id of the note for which the title should be generated
|
||||||
* used to see if the file itself has the title and not a different file for
|
* used to see if the file itself has the title and not a different file for
|
||||||
* checking for filename collisions
|
* checking for filename collisions
|
||||||
* @return string the resolved filename to prevent overwriting different
|
* @return string the resolved filename to prevent overwriting different
|
||||||
* files with the same title
|
* files with the same title
|
||||||
*/
|
*/
|
||||||
private function generateFileName (Folder $folder, $title, $suffix, $id) {
|
private function generateFileName(Folder $folder, $title, $suffix, $id) {
|
||||||
$path = $title . $suffix;
|
$path = $title . $suffix;
|
||||||
|
|
||||||
// if file does not exist, that name has not been taken. Similar we don't
|
// if file does not exist, that name has not been taken. Similar we don't
|
||||||
// need to handle file collisions if it is the filename did not change
|
// need to handle file collisions if it is the filename did not change
|
||||||
if (!$folder->nodeExists($path) || $folder->get($path)->getId() === $id) {
|
if (!$folder->nodeExists($path) || $folder->get($path)->getId() === $id) {
|
||||||
return $path;
|
return $path;
|
||||||
} else {
|
} else {
|
||||||
// increments name (2) to name (3)
|
// increments name (2) to name (3)
|
||||||
$match = preg_match('/\((?P<id>\d+)\)$/u', $title, $matches);
|
$match = preg_match('/\((?P<id>\d+)\)$/u', $title, $matches);
|
||||||
if($match) {
|
if ($match) {
|
||||||
$newId = ((int) $matches['id']) + 1;
|
$newId = ((int) $matches['id']) + 1;
|
||||||
$newTitle = preg_replace('/(.*)\s\((\d+)\)$/u',
|
$newTitle = preg_replace(
|
||||||
'$1 (' . $newId . ')', $title);
|
'/(.*)\s\((\d+)\)$/u',
|
||||||
} else {
|
'$1 (' . $newId . ')',
|
||||||
$newTitle = $title . ' (2)';
|
$title
|
||||||
}
|
);
|
||||||
return $this->generateFileName($folder, $newTitle, $suffix, $id);
|
} else {
|
||||||
}
|
$newTitle = $title . ' (2)';
|
||||||
}
|
}
|
||||||
|
return $this->generateFileName($folder, $newTitle, $suffix, $id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gather note files in given directory and all subdirectories
|
* gather note files in given directory and all subdirectories
|
||||||
* @param Folder $folder
|
* @param Folder $folder
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
private function gatherNoteFiles ($folder) {
|
private function gatherNoteFiles($folder) {
|
||||||
$notes = [];
|
$notes = [];
|
||||||
$nodes = $folder->getDirectoryListing();
|
$nodes = $folder->getDirectoryListing();
|
||||||
foreach($nodes as $node) {
|
foreach ($nodes as $node) {
|
||||||
if($node->getType() === FileInfo::TYPE_FOLDER) {
|
if ($node->getType() === FileInfo::TYPE_FOLDER) {
|
||||||
$notes = array_merge($notes, $this->gatherNoteFiles($node));
|
$notes = array_merge($notes, $this->gatherNoteFiles($node));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if($this->isNote($node)) {
|
if ($this->isNote($node)) {
|
||||||
$notes[] = $node;
|
$notes[] = $node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -421,23 +415,24 @@ class NotesService {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* test if file is a note
|
* test if file is a note
|
||||||
*
|
*
|
||||||
* @param \OCP\Files\File $file
|
* @param \OCP\Files\File $file
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
private function isNote($file) {
|
private function isNote($file) {
|
||||||
$allowedExtensions = ['txt', 'org', 'markdown', 'md', 'note'];
|
$allowedExtensions = ['txt', 'org', 'markdown', 'md', 'note'];
|
||||||
|
|
||||||
if($file->getType() !== 'file') return false;
|
if ($file->getType() !== 'file') {
|
||||||
|
return false;
|
||||||
$ext = pathinfo($file->getName(), PATHINFO_EXTENSION);
|
}
|
||||||
$iext = strtolower($ext);
|
|
||||||
if(!in_array($iext, $allowedExtensions)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
$ext = pathinfo($file->getName(), PATHINFO_EXTENSION);
|
||||||
|
$iext = strtolower($ext);
|
||||||
|
if (!in_array($iext, $allowedExtensions)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace OCA\Notes\Service;
|
namespace OCA\Notes\Service;
|
||||||
|
|
||||||
use OCP\AppFramework\Controller;
|
use OCP\AppFramework\Controller;
|
||||||
|
|
||||||
use OCP\IConfig;
|
use OCP\IConfig;
|
||||||
|
@ -10,15 +11,15 @@ use OCP\IUserSession;
|
||||||
use OCP\Files\IRootFolder;
|
use OCP\Files\IRootFolder;
|
||||||
use OCP\AppFramework\Http\JSONResponse;
|
use OCP\AppFramework\Http\JSONResponse;
|
||||||
|
|
||||||
class SettingsService
|
class SettingsService {
|
||||||
{
|
|
||||||
private $config;
|
private $config;
|
||||||
private $root;
|
private $root;
|
||||||
|
|
||||||
/* Default values */
|
/* Default values */
|
||||||
private $defaults = [
|
private $defaults = [
|
||||||
"notesPath" => "Notes",
|
'notesPath' => 'Notes',
|
||||||
"fileSuffix" => ".txt",
|
'fileSuffix' => '.txt',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
@ -32,8 +33,8 @@ class SettingsService
|
||||||
*/
|
*/
|
||||||
public function set($uid, $settings) {
|
public function set($uid, $settings) {
|
||||||
// remove illegal, empty and default settings
|
// remove illegal, empty and default settings
|
||||||
foreach($settings as $name => $value) {
|
foreach ($settings as $name => $value) {
|
||||||
if(!array_key_exists($name, $this->defaults)
|
if (!array_key_exists($name, $this->defaults)
|
||||||
|| empty($value)
|
|| empty($value)
|
||||||
|| $value === $this->defaults[$name]
|
|| $value === $this->defaults[$name]
|
||||||
) {
|
) {
|
||||||
|
@ -45,10 +46,10 @@ class SettingsService
|
||||||
|
|
||||||
public function getAll($uid) {
|
public function getAll($uid) {
|
||||||
$settings = json_decode($this->config->getUserValue($uid, 'notes', 'settings'));
|
$settings = json_decode($this->config->getUserValue($uid, 'notes', 'settings'));
|
||||||
if(is_object($settings)) {
|
if (is_object($settings)) {
|
||||||
// use default for empty settings
|
// use default for empty settings
|
||||||
foreach($this->defaults as $name => $defaultValue) {
|
foreach ($this->defaults as $name => $defaultValue) {
|
||||||
if(!property_exists($settings, $name) || empty($settings->{$name})) {
|
if (!property_exists($settings, $name) || empty($settings->{$name})) {
|
||||||
$settings->{$name} = $defaultValue;
|
$settings->{$name} = $defaultValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,7 +64,7 @@ class SettingsService
|
||||||
*/
|
*/
|
||||||
public function get($uid, $name) {
|
public function get($uid, $name) {
|
||||||
$settings = $this->getAll($uid);
|
$settings = $this->getAll($uid);
|
||||||
if(property_exists($settings, $name)) {
|
if (property_exists($settings, $name)) {
|
||||||
return $settings->{$name};
|
return $settings->{$name};
|
||||||
} else {
|
} else {
|
||||||
throw new \OCP\PreConditionNotMetException('Setting '.$name.' not found for user '.$uid.'.');
|
throw new \OCP\PreConditionNotMetException('Setting '.$name.' not found for user '.$uid.'.');
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<ruleset name="MyStandard">
|
||||||
|
<description>
|
||||||
|
PSR2 with changes:
|
||||||
|
* tabs instead of spaces (https://gist.github.com/gsherwood/9d22f634c57f990a7c64)
|
||||||
|
* bracers on end of line instead new line
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<!-- tabs -->
|
||||||
|
<arg name="tab-width" value="4"/>
|
||||||
|
<rule ref="PSR2">
|
||||||
|
<!-- bracers -->
|
||||||
|
<exclude name="Squiz.Functions.MultiLineFunctionDeclaration.BraceOnSameLine" />
|
||||||
|
<exclude name="PSR2.Classes.ClassDeclaration.OpenBraceNewLine" />
|
||||||
|
|
||||||
|
<!-- tabs -->
|
||||||
|
<exclude name="Generic.WhiteSpace.DisallowTabIndent"/>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<!-- tabs -->
|
||||||
|
<rule ref="Generic.WhiteSpace.DisallowSpaceIndent"/>
|
||||||
|
<rule ref="Generic.WhiteSpace.ScopeIndent">
|
||||||
|
<properties>
|
||||||
|
<property name="indent" value="4"/>
|
||||||
|
<property name="tabIndent" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<!-- bracers -->
|
||||||
|
<rule ref="Generic.Functions.OpeningFunctionBraceKernighanRitchie" />
|
||||||
|
<rule ref="Generic.Classes.OpeningBraceSameLine"/>
|
||||||
|
</ruleset>
|
Loading…
Reference in New Issue