Skip to content

Commit 91d6363

Browse files
committed
Create photos sidebar tab
Signed-off-by: Louis Chemineau <[email protected]>
1 parent b7f478a commit 91d6363

9 files changed

Lines changed: 660 additions & 11 deletions

File tree

lib/AppInfo/Application.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
use OCA\DAV\Connector\Sabre\Principal;
2929
use OCA\DAV\Events\SabrePluginAuthInitEvent;
30+
use OCA\Files\Event\LoadSidebar;
3031
use OCA\Photos\Listener\AlbumsManagementEventListener;
3132
use OCA\Photos\Listener\SabrePluginAuthInitListener;
3233
use OCA\Photos\Listener\TagListener;
@@ -43,6 +44,7 @@
4344
use OCP\FilesMetadata\Event\MetadataLiveEvent;
4445
use OCP\Group\Events\GroupDeletedEvent;
4546
use OCP\Group\Events\UserRemovedEvent;
47+
use OCP\Security\CSP\AddContentSecurityPolicyEvent;
4648
use OCP\Share\Events\ShareDeletedEvent;
4749
use OCP\SystemTag\MapperEvent;
4850
use OCP\User\Events\UserDeletedEvent;
@@ -79,6 +81,10 @@ public function register(IRegistrationContext $context): void {
7981
/** Register $principalBackend for the DAV collection */
8082
$context->registerServiceAlias('principalBackend', Principal::class);
8183

84+
$context->registerEventListener(LoadSidebar::class, LoadSidebarScripts::class);
85+
86+
$context->registerEventListener(AddContentSecurityPolicyEvent::class, CSPListener::class);
87+
8288
// Metadata
8389
$context->registerEventListener(MetadataLiveEvent::class, ExifMetadataProvider::class);
8490
$context->registerEventListener(MetadataLiveEvent::class, SizeMetadataProvider::class);

lib/Listener/CSPListener.php

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* @copyright Copyright (c) 2023, Louis Chmn <[email protected]>
6+
*
7+
* @author Louis Chmn <[email protected]>
8+
*
9+
* @license GNU AGPL version 3 or any later version
10+
*
11+
* This program is free software: you can redistribute it and/or modify
12+
* it under the terms of the GNU Affero General Public License as
13+
* published by the Free Software Foundation, either version 3 of the
14+
* License, or (at your option) any later version.
15+
*
16+
* This program is distributed in the hope that it will be useful,
17+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
18+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19+
* GNU Affero General Public License for more details.
20+
*
21+
* You should have received a copy of the GNU Affero General Public License
22+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
23+
*
24+
*/
25+
26+
namespace OCA\Photos\Listener;
27+
28+
use OCP\AppFramework\Http\ContentSecurityPolicy;
29+
use OCP\EventDispatcher\Event;
30+
use OCP\EventDispatcher\IEventListener;
31+
use OCP\Security\CSP\AddContentSecurityPolicyEvent;
32+
33+
/**
34+
* @template-implements IEventListener<Event>
35+
*/
36+
class CSPListener implements IEventListener {
37+
38+
public function __construct(
39+
) {
40+
}
41+
42+
public function handle(Event $event): void {
43+
if (!($event instanceof AddContentSecurityPolicyEvent)) {
44+
return;
45+
}
46+
47+
$csp = new ContentSecurityPolicy();
48+
$csp->addAllowedImageDomain('https://*.tile.openstreetmap.org');
49+
$event->addPolicy($csp);
50+
}
51+
}

lib/Listener/ExifMetadataProvider.php

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
*
2121
*/
2222

23-
namespace OCA\Photos\Listener;
23+
namespace OCA\Photos\MetadataProvider;
2424

2525
use OCA\Photos\AppInfo\Application;
2626
use OCP\EventDispatcher\Event;
@@ -33,7 +33,7 @@
3333
* Extract EXIF, IFD0, and GPS data from a picture file.
3434
* EXIF data reference: https://web.archive.org/web/20220428165430/exif.org/Exif2-2.PDF
3535
*
36-
* @template-implements IEventListener<Event>
36+
* @template-implements IEventListener<OCP\FilesMetadata\Event\MetadataLiveEvent>
3737
*/
3838
class ExifMetadataProvider implements IEventListener {
3939
public function __construct(
@@ -80,11 +80,11 @@ public function handle(Event $event): void {
8080
}
8181

8282
if ($rawExifData && array_key_exists('EXIF', $rawExifData)) {
83-
$event->getMetadata()->setArray('photos-exif', $this->base64Encode($rawExifData['EXIF']));
83+
$event->getMetadata()->setArray('photos-exif', $this->sanitizeEntries($rawExifData['EXIF']));
8484
}
8585

8686
if ($rawExifData && array_key_exists('IFD0', $rawExifData)) {
87-
$event->getMetadata()->setArray('photos-ifd0', $this->base64Encode($rawExifData['IFD0']));
87+
$event->getMetadata()->setArray('photos-ifd0', $this->sanitizeEntries($rawExifData['IFD0']));
8888
}
8989

9090
if (
@@ -142,14 +142,26 @@ private function parseGPSData(string $rawData): float {
142142
/**
143143
* Exif data can contain anything.
144144
* This method will base 64 encode any non UTF-8 string in an array.
145+
* This will also remove control characters from UTF-8 strings.
145146
*/
146-
private function base64Encode(array $data): array {
147+
private function sanitizeEntries(array $data): array {
148+
$cleanData = [];
149+
147150
foreach ($data as $key => $value) {
148151
if (is_string($value) && !mb_check_encoding($value, 'UTF-8')) {
149-
$data[$key] = 'base64:'.base64_encode($value);
152+
$value = 'base64:'.base64_encode($value);
153+
} elseif (is_string($value)) {
154+
// TODO: Can be remove when the Sidebar use the @nextcloud/files to fetch and parse the DAV response.
155+
$value = preg_replace('/[[:cntrl:]]/u', '', $value);
156+
}
157+
158+
if (preg_match('/[^a-zA-Z]/', $key) !== 0) {
159+
$key = preg_replace('/[^a-zA-Z]/', '_', $key);
150160
}
161+
162+
$cleanData[$key] = $value;
151163
}
152164

153-
return $data;
165+
return $cleanData;
154166
}
155167
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* @copyright Copyright (c) 2023, Louis Chmn <[email protected]>
6+
*
7+
* @author Louis Chmn <[email protected]>
8+
*
9+
* @license GNU AGPL version 3 or any later version
10+
*
11+
* This program is free software: you can redistribute it and/or modify
12+
* it under the terms of the GNU Affero General Public License as
13+
* published by the Free Software Foundation, either version 3 of the
14+
* License, or (at your option) any later version.
15+
*
16+
* This program is distributed in the hope that it will be useful,
17+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
18+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19+
* GNU Affero General Public License for more details.
20+
*
21+
* You should have received a copy of the GNU Affero General Public License
22+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
23+
*
24+
*/
25+
26+
namespace OCA\Photos\Listener;
27+
28+
use OCA\Files\Event\LoadSidebar;
29+
use OCA\Photos\AppInfo\Application;
30+
use OCP\EventDispatcher\Event;
31+
use OCP\EventDispatcher\IEventListener;
32+
use OCP\IRequest;
33+
use OCP\Util;
34+
35+
/**
36+
* @template-implements IEventListener<Event>
37+
*/
38+
class LoadSidebarScripts implements IEventListener {
39+
40+
public function __construct(
41+
private IRequest $request,
42+
) {
43+
}
44+
45+
public function handle(Event $event): void {
46+
if (!($event instanceof LoadSidebar)) {
47+
return;
48+
}
49+
50+
// Only load sidebar tab in the photos app.
51+
if (!preg_match('/^photos\.page\..+/', $this->request->getParams()['_route'])) {
52+
return;
53+
}
54+
55+
Util::addScript(Application::APP_ID, 'photos-sidebar');
56+
}
57+
}

package-lock.json

Lines changed: 42 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
},
4040
"dependencies": {
4141
"@essentials/request-timeout": "^1.3.0",
42-
"@mdi/svg": "^7.1.96",
42+
"@mdi/svg": "^7.3.67",
4343
"@nextcloud/auth": "^2.1.0",
4444
"@nextcloud/axios": "^2.1.0",
4545
"@nextcloud/dialogs": "^4.1.0",
@@ -57,6 +57,7 @@
5757
"camelcase": "^7.0.0",
5858
"debounce": "^1.2.1",
5959
"he": "^1.2.0",
60+
"leaflet-defaulticon-compatibility": "^0.1.2",
6061
"path-posix": "^1.0.0",
6162
"qs": "^6.11.2",
6263
"url-parse": "^1.5.10",
@@ -65,6 +66,7 @@
6566
"vue-router": "^3.6.5",
6667
"vue-template-compiler": "^2.7.14",
6768
"vue-virtual-grid": "^2.5.0",
69+
"vue2-leaflet": "^2.7.1",
6870
"vuex": "^3.6.2",
6971
"vuex-router-sync": "^5.0.0",
7072
"webdav": "^4.11.0"

0 commit comments

Comments
 (0)