build / build (push) Failing after 1m32s
Nextcloud keys dashboard widgets and reference providers globally, not per app, so the rebrand had to cover them too and did not. This fork shipped with upstream's IDs -- mastodon_notifications, mastodon_home_timeline and mastodon-multi -- and enabling it alongside integration_mastodon clobbered that app's registry entries. The dashboard then resolved those IDs to classes in the wrong app and logged: Could not register lazy dashboard widget: OCA\Mastodon\Dashboard\MastodonWidget Found on a live instance running both apps side by side. No data was affected; disabling this app restored the other immediately. The JS registrations in dashboard.js/dashboardHome.js are renamed to match, since OCA.Dashboard.register() must agree with the widget's getId(). 'connected-accounts' is deliberately left shared -- it is a core Nextcloud settings section, not an app-owned identifier. 'mastodonToken' is likewise left alone: it is a query parameter passed between this app's own controller and its own settings page. Assisted-by: Claude Code:claude-opus-5
214 lines
6.7 KiB
PHP
214 lines
6.7 KiB
PHP
<?php
|
|
|
|
/**
|
|
* @copyright Copyright (c) 2023 Julien Veyssier <julien-nc@posteo.net>
|
|
*
|
|
* @author Julien Veyssier <julien-nc@posteo.net>
|
|
*
|
|
* @license GNU AGPL version 3 or any later version
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
namespace OCA\GoToSocial\Reference;
|
|
|
|
use OCA\GoToSocial\AppInfo\Application;
|
|
use OCP\AppFramework\Services\IAppConfig;
|
|
use OCP\Collaboration\Reference\ADiscoverableReferenceProvider;
|
|
use OCP\Collaboration\Reference\IReference;
|
|
use OCP\Collaboration\Reference\IReferenceManager;
|
|
use OCP\Collaboration\Reference\ISearchableReferenceProvider;
|
|
use OCP\Collaboration\Reference\LinkReferenceProvider;
|
|
use OCP\IConfig;
|
|
use OCP\IL10N;
|
|
use OCP\IURLGenerator;
|
|
|
|
class GoToSocialReferenceProvider extends ADiscoverableReferenceProvider implements ISearchableReferenceProvider {
|
|
|
|
public function __construct(
|
|
private IAppConfig $appConfig,
|
|
private IConfig $config,
|
|
private IL10N $l10n,
|
|
private IURLGenerator $urlGenerator,
|
|
private IReferenceManager $referenceManager,
|
|
private LinkReferenceProvider $linkReferenceProvider,
|
|
private ?string $userId,
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* @inheritDoc
|
|
*/
|
|
public function getId(): string {
|
|
return 'gotosocial-multi';
|
|
}
|
|
|
|
/**
|
|
* @inheritDoc
|
|
*/
|
|
public function getTitle(): string {
|
|
if ($this->userId !== null) {
|
|
$searchStatusesEnabled = $this->config->getUserValue($this->userId, Application::APP_ID, 'search_statuses_enabled', '1') === '1';
|
|
$searchAccountsEnabled = $this->config->getUserValue($this->userId, Application::APP_ID, 'search_accounts_enabled', '1') === '1';
|
|
$searchTagsEnabled = $this->config->getUserValue($this->userId, Application::APP_ID, 'search_hashtags_enabled', '1') === '1';
|
|
if ($searchStatusesEnabled && $searchAccountsEnabled && $searchTagsEnabled) {
|
|
return $this->l10n->t('GoToSocial people, posts and hashtags');
|
|
} elseif ($searchStatusesEnabled && $searchAccountsEnabled) {
|
|
return $this->l10n->t('GoToSocial people and posts');
|
|
} elseif ($searchStatusesEnabled && $searchTagsEnabled) {
|
|
return $this->l10n->t('GoToSocial posts and hashtags');
|
|
} elseif ($searchTagsEnabled && $searchAccountsEnabled) {
|
|
return $this->l10n->t('GoToSocial people and hashtags');
|
|
} elseif ($searchTagsEnabled) {
|
|
return $this->l10n->t('GoToSocial hashtags');
|
|
} elseif ($searchAccountsEnabled) {
|
|
return $this->l10n->t('GoToSocial people');
|
|
} elseif ($searchStatusesEnabled) {
|
|
return $this->l10n->t('GoToSocial posts');
|
|
}
|
|
return $this->l10n->t('GoToSocial');
|
|
}
|
|
return $this->l10n->t('GoToSocial people, posts and hashtags');
|
|
}
|
|
|
|
/**
|
|
* @inheritDoc
|
|
*/
|
|
public function getOrder(): int {
|
|
return 10;
|
|
}
|
|
|
|
/**
|
|
* @inheritDoc
|
|
*/
|
|
public function getIconUrl(): string {
|
|
return $this->urlGenerator->getAbsoluteURL(
|
|
$this->urlGenerator->imagePath(Application::APP_ID, 'app-dark.svg')
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @inheritDoc
|
|
*/
|
|
public function getSupportedSearchProviderIds(): array {
|
|
if ($this->userId !== null) {
|
|
$searchProviderIds = [];
|
|
$searchStatusesEnabled = $this->config->getUserValue($this->userId, Application::APP_ID, 'search_statuses_enabled', '1') === '1';
|
|
if ($searchStatusesEnabled) {
|
|
$searchProviderIds[] = 'gotosocial-search-statuses';
|
|
}
|
|
$searchAccountsEnabled = $this->config->getUserValue($this->userId, Application::APP_ID, 'search_accounts_enabled', '1') === '1';
|
|
if ($searchAccountsEnabled) {
|
|
$searchProviderIds[] = 'gotosocial-search-accounts';
|
|
}
|
|
$searchTagsEnabled = $this->config->getUserValue($this->userId, Application::APP_ID, 'search_hashtags_enabled', '1') === '1';
|
|
if ($searchTagsEnabled) {
|
|
$searchProviderIds[] = 'gotosocial-search-hashtags';
|
|
}
|
|
return $searchProviderIds;
|
|
}
|
|
return [
|
|
'gotosocial-search-statuses',
|
|
'gotosocial-search-accounts',
|
|
'gotosocial-search-hashtags',
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @inheritDoc
|
|
*/
|
|
public function matchReference(string $referenceText): bool {
|
|
$adminLinkPreviewEnabled = $this->appConfig->getAppValueString('link_preview_enabled', '1', lazy: true) === '1';
|
|
$userLinkPreviewEnabled = $this->config->getUserValue($this->userId, Application::APP_ID, 'link_preview_enabled', '1') === '1';
|
|
if (!$adminLinkPreviewEnabled || !$userLinkPreviewEnabled) {
|
|
return false;
|
|
}
|
|
|
|
// never resolve mastodon
|
|
// leave it to the linkReferenceProvider which does it pretty well
|
|
return false;
|
|
// link examples:
|
|
// https://instance.org/@user/123456
|
|
// https://instance.org/@user@instance.net/987654
|
|
return preg_match('/^(?:https?:\/\/)?(?:www\.)?[^\/]+\/@[^\/@]+\/\d+/i', $referenceText) === 1
|
|
|| preg_match('/^(?:https?:\/\/)?(?:www\.)?[^\/]+\/@[^\/@]+@[^\/@]+\/\d+/i', $referenceText) === 1;
|
|
}
|
|
|
|
/**
|
|
* @inheritDoc
|
|
*/
|
|
public function resolveReference(string $referenceText): ?IReference {
|
|
if ($this->matchReference($referenceText)) {
|
|
$urlInfo = $this->getUrlInfo($referenceText);
|
|
if ($urlInfo !== null) {
|
|
}
|
|
// fallback to opengraph
|
|
return $this->linkReferenceProvider->resolveReference($referenceText);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* @param string $url
|
|
* @return array|null
|
|
*/
|
|
private function getUrlInfo(string $url): ?array {
|
|
preg_match('/^(?:https?:\/\/)?(?:www\.)?([^\/]+)\/@([^\/@]+)@([^\/@]+)\/(\d+)/i', $url, $matches);
|
|
if (count($matches) > 4) {
|
|
return [
|
|
'instance' => $matches[1],
|
|
'username' => $matches[2],
|
|
'id' => (int)$matches[4],
|
|
];
|
|
}
|
|
|
|
preg_match('/^(?:https?:\/\/)?(?:www\.)?([^\/]+)\/@([^\/@]+)\/(\d+)/i', $url, $matches);
|
|
if (count($matches) > 3) {
|
|
return [
|
|
'instance' => $matches[1],
|
|
'username' => $matches[2],
|
|
'id' => (int)$matches[4],
|
|
];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* We use the userId here because when connecting/disconnecting from the GitHub account,
|
|
* we want to invalidate all the user cache and this is only possible with the cache prefix
|
|
* @inheritDoc
|
|
*/
|
|
public function getCachePrefix(string $referenceId): string {
|
|
return $this->userId ?? '';
|
|
}
|
|
|
|
/**
|
|
* We don't use the userId here but rather a reference unique id
|
|
* @inheritDoc
|
|
*/
|
|
public function getCacheKey(string $referenceId): ?string {
|
|
return $referenceId;
|
|
}
|
|
|
|
/**
|
|
* @param string $userId
|
|
* @return void
|
|
*/
|
|
public function invalidateUserCache(string $userId): void {
|
|
$this->referenceManager->invalidateCache($userId);
|
|
}
|
|
}
|