From e0d919bbfcc3de5839a5134f301b879a949cf6c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Fri, 22 Jul 2016 16:13:26 +0200 Subject: [PATCH] Adding Open Graph Support for public shares http://ogp.me/ In case no preview is available we display the ownCloud logo Fix unit test --- .../files_sharing/lib/AppInfo/Application.php | 8 +++-- .../lib/Controllers/ShareController.php | 31 ++++++++++++++++-- apps/files_sharing/templates/public.php | 2 +- .../tests/Controllers/ShareControllerTest.php | 6 +++- core/img/favicon-fb.png | Bin 0 -> 9786 bytes 5 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 core/img/favicon-fb.png diff --git a/apps/files_sharing/lib/AppInfo/Application.php b/apps/files_sharing/lib/AppInfo/Application.php index 5558ffbdfc4..357860e8fa0 100644 --- a/apps/files_sharing/lib/AppInfo/Application.php +++ b/apps/files_sharing/lib/AppInfo/Application.php @@ -37,12 +37,14 @@ use OCA\Files_Sharing\Controllers\ExternalSharesController; use OCA\Files_Sharing\Controllers\ShareController; use OCA\Files_Sharing\Middleware\SharingCheckMiddleware; use \OCP\IContainer; +use OCP\IServerContainer; class Application extends App { public function __construct(array $urlParams = array()) { parent::__construct('files_sharing', $urlParams); $container = $this->getContainer(); + /** @var IServerContainer $server */ $server = $container->getServer(); /** @@ -63,7 +65,9 @@ class Application extends App { $server->getPreviewManager(), $server->getRootFolder(), $federatedSharingApp->getFederatedShareProvider(), - $server->getEventDispatcher() + $server->getEventDispatcher(), + $server->getL10N($c->query('AppName')), + $server->getThemingDefaults() ); }); $container->registerService('ExternalSharesController', function (SimpleContainer $c) { @@ -133,7 +137,7 @@ class Application extends App { }); // Execute middlewares - $container->registerMiddleware('SharingCheckMiddleware'); + $container->registerMiddleWare('SharingCheckMiddleware'); $container->registerMiddleWare('OCSShareAPIMiddleware'); $container->registerService('MountProvider', function (IContainer $c) { diff --git a/apps/files_sharing/lib/Controllers/ShareController.php b/apps/files_sharing/lib/Controllers/ShareController.php index 5ccaab746fc..8e3405311e9 100644 --- a/apps/files_sharing/lib/Controllers/ShareController.php +++ b/apps/files_sharing/lib/Controllers/ShareController.php @@ -35,6 +35,8 @@ namespace OCA\Files_Sharing\Controllers; use OC_Files; use OC_Util; use OCA\FederatedFileSharing\FederatedShareProvider; +use OCP\Defaults; +use OCP\IL10N; use OCP\Template; use OCP\Share; use OCP\AppFramework\Controller; @@ -84,6 +86,10 @@ class ShareController extends Controller { protected $federatedShareProvider; /** @var EventDispatcherInterface */ protected $eventDispatcher; + /** @var IL10N */ + protected $l10n; + /** @var Defaults */ + protected $defaults; /** * @param string $appName @@ -99,6 +105,8 @@ class ShareController extends Controller { * @param IRootFolder $rootFolder * @param FederatedShareProvider $federatedShareProvider * @param EventDispatcherInterface $eventDispatcher + * @param IL10N $l10n + * @param \OC_Defaults $defaults */ public function __construct($appName, IRequest $request, @@ -112,7 +120,9 @@ class ShareController extends Controller { IPreview $previewManager, IRootFolder $rootFolder, FederatedShareProvider $federatedShareProvider, - EventDispatcherInterface $eventDispatcher) { + EventDispatcherInterface $eventDispatcher, + IL10N $l10n, + \OC_Defaults $defaults) { parent::__construct($appName, $request); $this->config = $config; @@ -126,6 +136,8 @@ class ShareController extends Controller { $this->rootFolder = $rootFolder; $this->federatedShareProvider = $federatedShareProvider; $this->eventDispatcher = $eventDispatcher; + $this->l10n = $l10n; + $this->defaults = $defaults; } /** @@ -352,12 +364,19 @@ class ShareController extends Controller { $shareTmpl['hideFileList'] = $hideFileList; $shareTmpl['shareOwner'] = $this->userManager->get($share->getShareOwner())->getDisplayName(); - $shareTmpl['downloadURL'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.downloadShare', array('token' => $token)); + $shareTmpl['downloadURL'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.downloadShare', ['token' => $token]); + $shareTmpl['shareUrl'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $token]); $shareTmpl['maxSizeAnimateGif'] = $this->config->getSystemValue('max_filesize_animated_gifs_public_sharing', 10); $shareTmpl['previewEnabled'] = $this->config->getSystemValue('enable_previews', true); $shareTmpl['previewMaxX'] = $this->config->getSystemValue('preview_max_x', 1024); $shareTmpl['previewMaxY'] = $this->config->getSystemValue('preview_max_y', 1024); $shareTmpl['disclaimer'] = $this->config->getAppValue('core', 'shareapi_public_link_disclaimertext', null); + if ($shareTmpl['previewSupported']) { + $shareTmpl['previewImage'] = $this->urlGenerator->linkToRouteAbsolute( 'core_ajax_public_preview', + ['x' => 200, 'y' => 200, 'file' => $shareTmpl['directory_path'], 't' => $shareTmpl['dirToken']]); + } else { + $shareTmpl['previewImage'] = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'favicon-fb.png')); + } // Load files we need \OCP\Util::addScript('files', 'file-upload'); @@ -382,6 +401,14 @@ class ShareController extends Controller { \OCP\Util::addScript('files', 'keyboardshortcuts'); } + // OpenGraph Support: http://ogp.me/ + \OCP\Util::addHeader('meta', ['property' => "og:title", 'content' => $this->defaults->getName() . ' - ' . $this->defaults->getSlogan()]); + \OCP\Util::addHeader('meta', ['property' => "og:description", 'content' => $this->l10n->t('%s is publicly shared', [$shareTmpl['filename']])]); + \OCP\Util::addHeader('meta', ['property' => "og:site_name", 'content' => $this->defaults->getName()]); + \OCP\Util::addHeader('meta', ['property' => "og:url", 'content' => $shareTmpl['shareUrl']]); + \OCP\Util::addHeader('meta', ['property' => "og:type", 'content' => "object"]); + \OCP\Util::addHeader('meta', ['property' => "og:image", 'content' => $shareTmpl['previewImage']]); + $this->eventDispatcher->dispatch('OCA\Files_Sharing::loadAdditionalScripts'); $csp = new \OCP\AppFramework\Http\ContentSecurityPolicy(); diff --git a/apps/files_sharing/templates/public.php b/apps/files_sharing/templates/public.php index bdedb04d244..80c7d4d7460 100644 --- a/apps/files_sharing/templates/public.php +++ b/apps/files_sharing/templates/public.php @@ -4,7 +4,7 @@ ?> - +
diff --git a/apps/files_sharing/tests/Controllers/ShareControllerTest.php b/apps/files_sharing/tests/Controllers/ShareControllerTest.php index 1b9fd401f78..cc51d0b1f82 100644 --- a/apps/files_sharing/tests/Controllers/ShareControllerTest.php +++ b/apps/files_sharing/tests/Controllers/ShareControllerTest.php @@ -109,7 +109,9 @@ class ShareControllerTest extends \Test\TestCase { $this->previewManager, $this->getMockBuilder('\OCP\Files\IRootFolder')->getMock(), $this->federatedShareProvider, - $this->eventDispatcher + $this->eventDispatcher, + $this->getMockBuilder('\OCP\IL10N')->getMock(), + $this->getMockBuilder('\OCP\Defaults')->getMock() ); @@ -392,6 +394,8 @@ class ShareControllerTest extends \Test\TestCase { 'hideFileList' => false, 'shareOwner' => 'ownerDisplay', 'disclaimer' => 'My disclaimer text', + 'shareUrl' => null, + 'previewImage' => null ); $csp = new \OCP\AppFramework\Http\ContentSecurityPolicy(); diff --git a/core/img/favicon-fb.png b/core/img/favicon-fb.png new file mode 100644 index 0000000000000000000000000000000000000000..9f0c3f40e08e83caede65d2977f2f0626730badb GIT binary patch literal 9786 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 CWRKkd literal 0 HcmV?d00001