aboutsummaryrefslogtreecommitdiffstats
path: root/lib/private
diff options
context:
space:
mode:
authorChristopher Ng <chrng8@gmail.com>2021-10-14 08:19:40 +0000
committerChristopher Ng <chrng8@gmail.com>2021-10-19 04:59:35 +0000
commit309354852f12ae88d5eef05d311d6ebcba8ee762 (patch)
tree640c4e2394ba2a868d8d1cb6b5271fd1271bbdab /lib/private
parent7215148a242815a5064ce5d00a387c634dc936f3 (diff)
downloadnextcloud-server-309354852f12ae88d5eef05d311d6ebcba8ee762.tar.gz
nextcloud-server-309354852f12ae88d5eef05d311d6ebcba8ee762.zip
Profile backend
Signed-off-by: Christopher Ng <chrng8@gmail.com>
Diffstat (limited to 'lib/private')
-rw-r--r--lib/private/AppFramework/Bootstrap/Coordinator.php21
-rw-r--r--lib/private/AppFramework/Bootstrap/RegistrationContext.php28
-rw-r--r--lib/private/Contacts/ContactsMenu/ActionProviderStore.php6
-rw-r--r--lib/private/Contacts/ContactsMenu/ContactsStore.php54
-rw-r--r--lib/private/Contacts/ContactsMenu/Entry.php37
-rw-r--r--lib/private/Contacts/ContactsMenu/Providers/ProfileProvider.php93
-rw-r--r--lib/private/Profile/Actions/EmailAction.php94
-rw-r--r--lib/private/Profile/Actions/PhoneAction.php94
-rw-r--r--lib/private/Profile/Actions/TwitterAction.php97
-rw-r--r--lib/private/Profile/Actions/WebsiteAction.php94
-rw-r--r--lib/private/Profile/ProfileManager.php333
-rw-r--r--lib/private/Profile/TProfileHelper.php46
-rw-r--r--lib/private/Setup.php3
-rw-r--r--lib/private/Template/SCSSCacher.php9
14 files changed, 986 insertions, 23 deletions
diff --git a/lib/private/AppFramework/Bootstrap/Coordinator.php b/lib/private/AppFramework/Bootstrap/Coordinator.php
index 8ffe54a2575..6e05b7fdc88 100644
--- a/lib/private/AppFramework/Bootstrap/Coordinator.php
+++ b/lib/private/AppFramework/Bootstrap/Coordinator.php
@@ -27,10 +27,14 @@ declare(strict_types=1);
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
+
namespace OC\AppFramework\Bootstrap;
-use OC\Support\CrashReport\Registry;
+use function class_exists;
+use function class_implements;
+use function in_array;
use OC_App;
+use OC\Support\CrashReport\Registry;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootstrap;
use OCP\AppFramework\QueryException;
@@ -39,9 +43,6 @@ use OCP\EventDispatcher\IEventDispatcher;
use OCP\IServerContainer;
use Psr\Log\LoggerInterface;
use Throwable;
-use function class_exists;
-use function class_implements;
-use function in_array;
class Coordinator {
@@ -66,11 +67,13 @@ class Coordinator {
/** @var string[] */
private $bootedApps = [];
- public function __construct(IServerContainer $container,
- Registry $registry,
- IManager $dashboardManager,
- IEventDispatcher $eventListener,
- LoggerInterface $logger) {
+ public function __construct(
+ IServerContainer $container,
+ Registry $registry,
+ IManager $dashboardManager,
+ IEventDispatcher $eventListener,
+ LoggerInterface $logger
+ ) {
$this->serverContainer = $container;
$this->registry = $registry;
$this->dashboardManager = $dashboardManager;
diff --git a/lib/private/AppFramework/Bootstrap/RegistrationContext.php b/lib/private/AppFramework/Bootstrap/RegistrationContext.php
index 8eed6a5bde4..c638af94c84 100644
--- a/lib/private/AppFramework/Bootstrap/RegistrationContext.php
+++ b/lib/private/AppFramework/Bootstrap/RegistrationContext.php
@@ -26,9 +26,11 @@ declare(strict_types=1);
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
+
namespace OC\AppFramework\Bootstrap;
use Closure;
+use function array_shift;
use OC\Support\CrashReport\Registry;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
@@ -43,11 +45,11 @@ use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\Template\ICustomTemplateProvider;
use OCP\Http\WellKnown\IHandler;
use OCP\Notification\INotifier;
+use OCP\Profile\ILinkAction;
use OCP\Search\IProvider;
use OCP\Support\CrashReport\IReporter;
use Psr\Log\LoggerInterface;
use Throwable;
-use function array_shift;
class RegistrationContext {
@@ -60,6 +62,9 @@ class RegistrationContext {
/** @var ServiceRegistration<IWidget>[] */
private $dashboardPanels = [];
+ /** @var ServiceRegistration<ILinkAction>[] */
+ private $profileActions = [];
+
/** @var ServiceFactoryRegistration[] */
private $services = [];
@@ -236,6 +241,13 @@ class RegistrationContext {
$class
);
}
+
+ public function registerProfileAction(string $actionClass): void {
+ $this->context->registerProfileAction(
+ $this->appId,
+ $actionClass
+ );
+ }
};
}
@@ -316,6 +328,13 @@ class RegistrationContext {
}
/**
+ * @psalm-param class-string<ILinkAction> $capability
+ */
+ public function registerProfileAction(string $appId, string $actionClass): void {
+ $this->profileActions[] = new ServiceRegistration($appId, $actionClass);
+ }
+
+ /**
* @param App[] $apps
*/
public function delegateCapabilityRegistrations(array $apps): void {
@@ -552,4 +571,11 @@ class RegistrationContext {
public function getCalendarProviders(): array {
return $this->calendarProviders;
}
+
+ /**
+ * @return ServiceRegistration<ILinkAction>[]
+ */
+ public function getProfileActions(): array {
+ return $this->profileActions;
+ }
}
diff --git a/lib/private/Contacts/ContactsMenu/ActionProviderStore.php b/lib/private/Contacts/ContactsMenu/ActionProviderStore.php
index a984f9d6dfb..1db99497a21 100644
--- a/lib/private/Contacts/ContactsMenu/ActionProviderStore.php
+++ b/lib/private/Contacts/ContactsMenu/ActionProviderStore.php
@@ -24,11 +24,13 @@ declare(strict_types=1);
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
+
namespace OC\Contacts\ContactsMenu;
use Exception;
use OC\App\AppManager;
use OC\Contacts\ContactsMenu\Providers\EMailProvider;
+use OC\Contacts\ContactsMenu\Providers\ProfileProvider;
use OCP\AppFramework\QueryException;
use OCP\Contacts\ContactsMenu\IProvider;
use OCP\IServerContainer;
@@ -67,7 +69,8 @@ class ActionProviderStore {
try {
$providers[] = $this->serverContainer->query($class);
} catch (QueryException $ex) {
- $this->logger->error('Could not load contacts menu action provider ' . $class,
+ $this->logger->error(
+ 'Could not load contacts menu action provider ' . $class,
[
'app' => 'core',
'exception' => $ex,
@@ -85,6 +88,7 @@ class ActionProviderStore {
*/
private function getServerProviderClasses(): array {
return [
+ ProfileProvider::class,
EMailProvider::class,
];
}
diff --git a/lib/private/Contacts/ContactsMenu/ContactsStore.php b/lib/private/Contacts/ContactsMenu/ContactsStore.php
index 31e13bbe8f2..a4a53bf8774 100644
--- a/lib/private/Contacts/ContactsMenu/ContactsStore.php
+++ b/lib/private/Contacts/ContactsMenu/ContactsStore.php
@@ -1,4 +1,5 @@
<?php
+
/**
* @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at>
* @copyright 2017 Lukas Reschke <lukas@statuscode.ch>
@@ -27,18 +28,26 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
+
namespace OC\Contacts\ContactsMenu;
use OC\KnownUser\KnownUserService;
+use OCP\Accounts\IAccountManager;
use OCP\Contacts\ContactsMenu\IContactsStore;
use OCP\Contacts\ContactsMenu\IEntry;
use OCP\Contacts\IManager;
use OCP\IConfig;
use OCP\IGroupManager;
+use OCP\IURLGenerator;
use OCP\IUser;
use OCP\IUserManager;
+use OCP\L10N\IFactory as IL10NFactory;
class ContactsStore implements IContactsStore {
+ use \OC\Profile\TProfileHelper;
+
+ /** @var IAccountManager */
+ private $accountManager;
/** @var IManager */
private $contactsManager;
@@ -49,22 +58,36 @@ class ContactsStore implements IContactsStore {
/** @var IUserManager */
private $userManager;
+ /** @var IURLGenerator */
+ private $urlGenerator;
+
/** @var IGroupManager */
private $groupManager;
/** @var KnownUserService */
private $knownUserService;
- public function __construct(IManager $contactsManager,
- IConfig $config,
- IUserManager $userManager,
- IGroupManager $groupManager,
- KnownUserService $knownUserService) {
+ /** @var IL10NFactory */
+ private $l10nFactory;
+
+ public function __construct(
+ IAccountManager $accountManager,
+ IManager $contactsManager,
+ IConfig $config,
+ IUserManager $userManager,
+ IURLGenerator $urlGenerator,
+ IGroupManager $groupManager,
+ KnownUserService $knownUserService,
+ IL10NFactory $l10nFactory
+ ) {
+ $this->accountManager = $accountManager;
$this->contactsManager = $contactsManager;
$this->config = $config;
$this->userManager = $userManager;
+ $this->urlGenerator = $urlGenerator;
$this->groupManager = $groupManager;
$this->knownUserService = $knownUserService;
+ $this->l10nFactory = $l10nFactory;
}
/**
@@ -116,9 +139,11 @@ class ContactsStore implements IContactsStore {
* @param string $filter
* @return Entry[] the filtered contacts
*/
- private function filterContacts(IUser $self,
- array $entries,
- $filter) {
+ private function filterContacts(
+ IUser $self,
+ array $entries,
+ $filter
+ ) {
$disallowEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') !== 'yes';
$restrictEnumerationGroup = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes';
$restrictEnumerationPhone = $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_phone', 'no') === 'yes';
@@ -302,6 +327,19 @@ class ContactsStore implements IContactsStore {
}
}
+ // Provide profile parameters for core/src/OC/contactsmenu/contact.handlebars template
+ if (isset($contact['UID']) && isset($contact['FN'])) {
+ $targetUserId = $contact['UID'];
+ $user = $this->userManager->get($targetUserId);
+ if (!empty($user)) {
+ $account = $this->accountManager->getAccount($user);
+ if ($this->isProfileEnabled($account)) {
+ $entry->setProfileTitle($this->l10nFactory->get('core')->t('View profile'));
+ $entry->setProfileUrl($this->urlGenerator->linkToRouteAbsolute('core.ProfilePage.index', ['targetUserId' => $targetUserId]));
+ }
+ }
+ }
+
// Attach all other properties to the entry too because some
// providers might make use of it.
$entry->setProperties($contact);
diff --git a/lib/private/Contacts/ContactsMenu/Entry.php b/lib/private/Contacts/ContactsMenu/Entry.php
index aea71df2968..915a0434cc8 100644
--- a/lib/private/Contacts/ContactsMenu/Entry.php
+++ b/lib/private/Contacts/ContactsMenu/Entry.php
@@ -24,6 +24,7 @@ declare(strict_types=1);
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
+
namespace OC\Contacts\ContactsMenu;
use OCP\Contacts\ContactsMenu\IAction;
@@ -43,6 +44,12 @@ class Entry implements IEntry {
/** @var string|null */
private $avatar;
+ /** @var string|null */
+ private $profileTitle;
+
+ /** @var string|null */
+ private $profileUrl;
+
/** @var IAction[] */
private $actions = [];
@@ -99,6 +106,34 @@ class Entry implements IEntry {
}
/**
+ * @param string $profileTitle
+ */
+ public function setProfileTitle(string $profileTitle): void {
+ $this->profileTitle = $profileTitle;
+ }
+
+ /**
+ * @return string
+ */
+ public function getProfileTitle(): ?string {
+ return $this->profileTitle;
+ }
+
+ /**
+ * @param string $profileUrl
+ */
+ public function setProfileUrl(string $profileUrl): void {
+ $this->profileUrl = $profileUrl;
+ }
+
+ /**
+ * @return string
+ */
+ public function getProfileUrl(): ?string {
+ return $this->profileUrl;
+ }
+
+ /**
* @param IAction $action
*/
public function addAction(IAction $action): void {
@@ -166,6 +201,8 @@ class Entry implements IEntry {
'actions' => $otherActions,
'lastMessage' => '',
'emailAddresses' => $this->getEMailAddresses(),
+ 'profileTitle' => $this->profileTitle,
+ 'profileUrl' => $this->profileUrl,
];
}
}
diff --git a/lib/private/Contacts/ContactsMenu/Providers/ProfileProvider.php b/lib/private/Contacts/ContactsMenu/Providers/ProfileProvider.php
new file mode 100644
index 00000000000..4882c0ac883
--- /dev/null
+++ b/lib/private/Contacts/ContactsMenu/Providers/ProfileProvider.php
@@ -0,0 +1,93 @@
+<?php
+
+/**
+ * @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @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 OC\Contacts\ContactsMenu\Providers;
+
+use OCP\Accounts\IAccountManager;
+use OCP\Contacts\ContactsMenu\IActionFactory;
+use OCP\Contacts\ContactsMenu\IEntry;
+use OCP\Contacts\ContactsMenu\IProvider;
+use OCP\IURLGenerator;
+use OCP\IUserManager;
+use OCP\L10N\IFactory as IL10NFactory;
+
+class ProfileProvider implements IProvider {
+ use \OC\Profile\TProfileHelper;
+
+ /** @var IAccountManager */
+ private $accountManager;
+
+ /** @var IActionFactory */
+ private $actionFactory;
+
+ /** @var IL10NFactory */
+ private $l10nFactory;
+
+ /** @var IURLGenerator */
+ private $urlGenerator;
+
+ /** @var IUserManager */
+ private $userManager;
+
+ /**
+ * @param IAccountManager $accountManager
+ * @param IActionFactory $actionFactory
+ * @param IL10NFactory $l10nFactory
+ * @param IURLGenerator $urlGenerator
+ * @param IUserManager $userManager
+ */
+ public function __construct(
+ IAccountManager $accountManager,
+ IActionFactory $actionFactory,
+ IL10NFactory $l10nFactory,
+ IURLGenerator $urlGenerator,
+ IUserManager $userManager
+ ) {
+ $this->accountManager = $accountManager;
+ $this->actionFactory = $actionFactory;
+ $this->l10nFactory = $l10nFactory;
+ $this->urlGenerator = $urlGenerator;
+ $this->userManager = $userManager;
+ }
+
+ /**
+ * @param IEntry $entry
+ */
+ public function process(IEntry $entry) {
+ $targetUserId = $entry->getProperty('UID');
+ $targetUser = $this->userManager->get($targetUserId);
+ if (!empty($targetUser)) {
+ $account = $this->accountManager->getAccount($targetUser);
+ if ($this->isProfileEnabled($account)) {
+ $iconUrl = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'actions/profile.svg'));
+ $profileActionText = $this->l10nFactory->get('core')->t('View profile');
+ $profileUrl = $this->urlGenerator->linkToRouteAbsolute('core.ProfilePage.index', ['targetUserId' => $targetUserId]);
+ $action = $this->actionFactory->newLinkAction($iconUrl, $profileActionText, $profileUrl);
+ // Set highest priority (by descending order), other actions have the default priority 10 as defined in lib/private/Contacts/ContactsMenu/Actions/LinkAction.php
+ $action->setPriority(20);
+ $entry->addAction($action);
+ }
+ }
+ }
+}
diff --git a/lib/private/Profile/Actions/EmailAction.php b/lib/private/Profile/Actions/EmailAction.php
new file mode 100644
index 00000000000..1eef1236630
--- /dev/null
+++ b/lib/private/Profile/Actions/EmailAction.php
@@ -0,0 +1,94 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright 2021 Christopher Ng <chrng8@gmail.com>
+ *
+ * @author Christopher Ng <chrng8@gmail.com>
+ *
+ * @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 OC\Profile\Actions;
+
+use OCP\Accounts\IAccountManager;
+use OCP\IURLGenerator;
+use OCP\IUser;
+use OCP\L10N\IFactory;
+use OCP\Profile\ILinkAction;
+
+class EmailAction implements ILinkAction {
+
+ /** @var string */
+ private $value;
+
+ /** @var IAccountManager */
+ private $accountManager;
+
+ /** @var IFactory */
+ private $l10nFactory;
+
+ /** @var IUrlGenerator */
+ private $urlGenerator;
+
+ public function __construct(
+ IAccountManager $accountManager,
+ IFactory $l10nFactory,
+ IURLGenerator $urlGenerator
+ ) {
+ $this->accountManager = $accountManager;
+ $this->l10nFactory = $l10nFactory;
+ $this->urlGenerator = $urlGenerator;
+ }
+
+ public function preload(IUser $targetUser): void {
+ $account = $this->accountManager->getAccount($targetUser);
+ $this->value = $account->getProperty(IAccountManager::PROPERTY_EMAIL)->getValue();
+ }
+
+ public function getAppId(): string {
+ return 'core';
+ }
+
+ public function getId(): string {
+ return IAccountManager::PROPERTY_EMAIL;
+ }
+
+ public function getDisplayId(): string {
+ return $this->l10nFactory->get('core')->t('Email');
+ }
+
+ public function getTitle(): string {
+ return $this->l10nFactory->get('core')->t('Mail %s', [$this->value]);
+ }
+
+ public function getPriority(): int {
+ return 20;
+ }
+
+ public function getIcon(): string {
+ return $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'actions/mail.svg'));
+ }
+
+ public function getTarget(): ?string {
+ if (empty($this->value)) {
+ return null;
+ }
+ return 'mailto:' . $this->value;
+ }
+}
diff --git a/lib/private/Profile/Actions/PhoneAction.php b/lib/private/Profile/Actions/PhoneAction.php
new file mode 100644
index 00000000000..df0e30cd277
--- /dev/null
+++ b/lib/private/Profile/Actions/PhoneAction.php
@@ -0,0 +1,94 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright 2021 Christopher Ng <chrng8@gmail.com>
+ *
+ * @author Christopher Ng <chrng8@gmail.com>
+ *
+ * @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 OC\Profile\Actions;
+
+use OCP\Accounts\IAccountManager;
+use OCP\IURLGenerator;
+use OCP\IUser;
+use OCP\L10N\IFactory;
+use OCP\Profile\ILinkAction;
+
+class PhoneAction implements ILinkAction {
+
+ /** @var string */
+ private $value;
+
+ /** @var IAccountManager */
+ private $accountManager;
+
+ /** @var IFactory */
+ private $l10nFactory;
+
+ /** @var IUrlGenerator */
+ private $urlGenerator;
+
+ public function __construct(
+ IAccountManager $accountManager,
+ IFactory $l10nFactory,
+ IURLGenerator $urlGenerator
+ ) {
+ $this->accountManager = $accountManager;
+ $this->l10nFactory = $l10nFactory;
+ $this->urlGenerator = $urlGenerator;
+ }
+
+ public function preload(IUser $targetUser): void {
+ $account = $this->accountManager->getAccount($targetUser);
+ $this->value = $account->getProperty(IAccountManager::PROPERTY_PHONE)->getValue();
+ }
+
+ public function getAppId(): string {
+ return 'core';
+ }
+
+ public function getId(): string {
+ return IAccountManager::PROPERTY_PHONE;
+ }
+
+ public function getDisplayId(): string {
+ return $this->l10nFactory->get('core')->t('Phone');
+ }
+
+ public function getTitle(): string {
+ return $this->l10nFactory->get('core')->t('Call %s', [$this->value]);
+ }
+
+ public function getPriority(): int {
+ return 30;
+ }
+
+ public function getIcon(): string {
+ return $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'actions/phone.svg'));
+ }
+
+ public function getTarget(): ?string {
+ if (empty($this->value)) {
+ return null;
+ }
+ return 'tel:' . $this->value;
+ }
+}
diff --git a/lib/private/Profile/Actions/TwitterAction.php b/lib/private/Profile/Actions/TwitterAction.php
new file mode 100644
index 00000000000..3dcfa8aaf12
--- /dev/null
+++ b/lib/private/Profile/Actions/TwitterAction.php
@@ -0,0 +1,97 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright 2021 Christopher Ng <chrng8@gmail.com>
+ *
+ * @author Christopher Ng <chrng8@gmail.com>
+ *
+ * @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 OC\Profile\Actions;
+
+use function Safe\substr;
+use OCP\Accounts\IAccountManager;
+use OCP\IURLGenerator;
+use OCP\IUser;
+use OCP\L10N\IFactory;
+use OCP\Profile\ILinkAction;
+
+class TwitterAction implements ILinkAction {
+
+ /** @var string */
+ private $value;
+
+ /** @var IAccountManager */
+ private $accountManager;
+
+ /** @var IFactory */
+ private $l10nFactory;
+
+ /** @var IUrlGenerator */
+ private $urlGenerator;
+
+ public function __construct(
+ IAccountManager $accountManager,
+ IFactory $l10nFactory,
+ IURLGenerator $urlGenerator
+ ) {
+ $this->accountManager = $accountManager;
+ $this->l10nFactory = $l10nFactory;
+ $this->urlGenerator = $urlGenerator;
+ }
+
+ public function preload(IUser $targetUser): void {
+ $account = $this->accountManager->getAccount($targetUser);
+ $this->value = $account->getProperty(IAccountManager::PROPERTY_TWITTER)->getValue();
+ }
+
+ public function getAppId(): string {
+ return 'core';
+ }
+
+ public function getId(): string {
+ return IAccountManager::PROPERTY_TWITTER;
+ }
+
+ public function getDisplayId(): string {
+ return $this->l10nFactory->get('core')->t('Twitter');
+ }
+
+ public function getTitle(): string {
+ $displayUsername = $this->value[0] === '@' ? $this->value : '@' . $this->value;
+ return $this->l10nFactory->get('core')->t('View %s on Twitter', [$displayUsername]);
+ }
+
+ public function getPriority(): int {
+ return 50;
+ }
+
+ public function getIcon(): string {
+ return $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'actions/twitter.svg'));
+ }
+
+ public function getTarget(): ?string {
+ if (empty($this->value)) {
+ return null;
+ }
+ $username = $this->value[0] === '@' ? substr($this->value, 1) : $this->value;
+ return 'https://twitter.com/' . $username;
+ }
+}
diff --git a/lib/private/Profile/Actions/WebsiteAction.php b/lib/private/Profile/Actions/WebsiteAction.php
new file mode 100644
index 00000000000..ea1daeee20e
--- /dev/null
+++ b/lib/private/Profile/Actions/WebsiteAction.php
@@ -0,0 +1,94 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright 2021 Christopher Ng <chrng8@gmail.com>
+ *
+ * @author Christopher Ng <chrng8@gmail.com>
+ *
+ * @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 OC\Profile\Actions;
+
+use OCP\Accounts\IAccountManager;
+use OCP\IURLGenerator;
+use OCP\IUser;
+use OCP\L10N\IFactory;
+use OCP\Profile\ILinkAction;
+
+class WebsiteAction implements ILinkAction {
+
+ /** @var string */
+ private $value;
+
+ /** @var IAccountManager */
+ private $accountManager;
+
+ /** @var IFactory */
+ private $l10nFactory;
+
+ /** @var IUrlGenerator */
+ private $urlGenerator;
+
+ public function __construct(
+ IAccountManager $accountManager,
+ IFactory $l10nFactory,
+ IURLGenerator $urlGenerator
+ ) {
+ $this->accountManager = $accountManager;
+ $this->l10nFactory = $l10nFactory;
+ $this->urlGenerator = $urlGenerator;
+ }
+
+ public function preload(IUser $targetUser): void {
+ $account = $this->accountManager->getAccount($targetUser);
+ $this->value = $account->getProperty(IAccountManager::PROPERTY_WEBSITE)->getValue();
+ }
+
+ public function getAppId(): string {
+ return 'core';
+ }
+
+ public function getId(): string {
+ return IAccountManager::PROPERTY_WEBSITE;
+ }
+
+ public function getDisplayId(): string {
+ return $this->l10nFactory->get('core')->t('Website');
+ }
+
+ public function getTitle(): string {
+ return $this->l10nFactory->get('core')->t('Visit %s', [$this->value]);
+ }
+
+ public function getPriority(): int {
+ return 40;
+ }
+
+ public function getIcon(): string {
+ return $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'actions/timezone.svg'));
+ }
+
+ public function getTarget(): ?string {
+ if (empty($this->value)) {
+ return null;
+ }
+ return $this->value;
+ }
+}
diff --git a/lib/private/Profile/ProfileManager.php b/lib/private/Profile/ProfileManager.php
new file mode 100644
index 00000000000..6a38f4ae16d
--- /dev/null
+++ b/lib/private/Profile/ProfileManager.php
@@ -0,0 +1,333 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright 2021 Christopher Ng <chrng8@gmail.com>
+ *
+ * @author Christopher Ng <chrng8@gmail.com>
+ *
+ * @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 OC\Profile;
+
+use function Safe\usort;
+
+use OC\AppFramework\Bootstrap\Coordinator;
+use OC\Core\Db\ProfileConfig;
+use OC\Core\Db\ProfileConfigMapper;
+use OC\KnownUser\KnownUserService;
+use OC\Profile\Actions\EmailAction;
+use OC\Profile\Actions\PhoneAction;
+use OC\Profile\Actions\TwitterAction;
+use OC\Profile\Actions\WebsiteAction;
+use OCP\Accounts\IAccountManager;
+use OCP\Accounts\PropertyDoesNotExistException;
+use OCP\App\IAppManager;
+use OCP\AppFramework\Db\DoesNotExistException;
+use OCP\IUser;
+use OCP\L10N\IFactory;
+use OCP\Profile\ILinkAction;
+use Psr\Container\ContainerInterface;
+use Psr\Log\LoggerInterface;
+
+/**
+ * @inheritDoc
+ */
+class ProfileManager {
+
+ /** @var IAccountManager */
+ private $accountManager;
+
+ /** @var IAppManager */
+ private $appManager;
+
+ /** @var ProfileConfigMapper */
+ private $configMapper;
+
+ /** @var ContainerInterface */
+ private $container;
+
+ /** @var KnownUserService */
+ private $knownUserService;
+
+ /** @var IFactory */
+ private $l10nFactory;
+
+ /** @var LoggerInterface */
+ private $logger;
+
+ /** @var Coordinator */
+ private $coordinator;
+
+ /** @var ILinkAction[] */
+ private $actions = [];
+
+ private const ACCOUNT_PROPERTY_ACTIONS = [
+ EmailAction::class,
+ PhoneAction::class,
+ WebsiteAction::class,
+ TwitterAction::class,
+ ];
+
+ /**
+ * Array of account properties displayed on the profile
+ */
+ private const PROFILE_PROPERTIES = [
+ IAccountManager::PROPERTY_ADDRESS,
+ IAccountManager::PROPERTY_BIOGRAPHY,
+ IAccountManager::PROPERTY_DISPLAYNAME,
+ IAccountManager::PROPERTY_HEADLINE,
+ IAccountManager::PROPERTY_ORGANISATION,
+ IAccountManager::PROPERTY_ROLE,
+ ];
+
+ public function __construct(
+ IAccountManager $accountManager,
+ IAppManager $appManager,
+ ProfileConfigMapper $configMapper,
+ ContainerInterface $container,
+ KnownUserService $knownUserService,
+ IFactory $l10nFactory,
+ LoggerInterface $logger,
+ Coordinator $coordinator
+ ) {
+ $this->accountManager = $accountManager;
+ $this->appManager = $appManager;
+ $this->configMapper = $configMapper;
+ $this->container = $container;
+ $this->knownUserService = $knownUserService;
+ $this->l10nFactory = $l10nFactory;
+ $this->logger = $logger;
+ $this->coordinator = $coordinator;
+ }
+
+ /**
+ * Register an action for the user
+ */
+ private function registerAction(IUser $targetUser, ?IUser $visitingUser, ILinkAction $action): void {
+ $action->preload($targetUser);
+
+ if ($action->getTarget() === null) {
+ // Actions without a target are not registered
+ return;
+ }
+
+ if (isset($this->actions[$action->getId()])) {
+ $this->logger->error('Cannot register duplicate action: ' . $action->getId());
+ return;
+ }
+
+ if ($action->getAppId() !== 'core') {
+ if (!$this->appManager->isEnabledForUser($action->getAppId(), $targetUser)) {
+ $this->logger->notice('App: ' . $action->getAppId() . ' cannot register actions as it is not enabled for the user: ' . $targetUser->getUID());
+ return;
+ }
+ if ($visitingUser === null) {
+ $this->logger->notice('App: ' . $action->getAppId() . ' cannot register actions as it is not available to non logged in users');
+ return;
+ }
+ if (!$this->appManager->isEnabledForUser($action->getAppId(), $visitingUser)) {
+ $this->logger->notice('App: ' . $action->getAppId() . ' cannot register actions as it is not enabled for the visiting user: ' . $visitingUser->getUID());
+ return;
+ }
+ }
+
+ // Add action to associative array of actions
+ $this->actions[$action->getId()] = $action;
+ }
+
+ /**
+ * Return an array of registered profile actions for the user
+ *
+ * @return ILinkAction[]
+ */
+ private function getActions(IUser $targetUser, ?IUser $visitingUser): array {
+ $context = $this->coordinator->getRegistrationContext();
+ if ($context === null) {
+ return [];
+ }
+
+ foreach (self::ACCOUNT_PROPERTY_ACTIONS as $actionClass) {
+ /** @var ILinkAction $provider */
+ $provider = $this->container->get($actionClass);
+ $this->registerAction($targetUser, $visitingUser, $provider);
+ }
+
+ foreach ($context->getProfileActions() as $registration) {
+ /** @var ILinkAction $provider */
+ $provider = $this->container->get($registration->getService());
+ $this->registerAction($targetUser, $visitingUser, $provider);
+ }
+
+ $actionsClone = $this->actions;
+ // Sort associative array into indexed array in ascending order of priority
+ usort($actionsClone, function (ILinkAction $a, ILinkAction $b) {
+ return $a->getPriority() === $b->getPriority() ? 0 : ($a->getPriority() < $b->getPriority() ? -1 : 1);
+ });
+ return $actionsClone;
+ }
+
+ /**
+ * Return whether the profile parameter is visible to the visiting user
+ */
+ private function isParameterVisible(IUser $targetUser, ?IUser $visitingUser, string $paramId): bool {
+ try {
+ $account = $this->accountManager->getAccount($targetUser);
+ $scope = $account->getProperty($paramId)->getScope();
+ } catch (PropertyDoesNotExistException $e) {
+ // Allow the exception as not all profile parameters are account properties
+ }
+
+ $visibility = $this->getProfileConfig($targetUser, $visitingUser)[$paramId]['visibility'];
+ // Handle profile visibility and account property scope
+ switch ($visibility) {
+ case ProfileConfig::VISIBILITY_HIDE:
+ return false;
+ case ProfileConfig::VISIBILITY_SHOW_USERS_ONLY:
+ if (!empty($scope)) {
+ switch ($scope) {
+ case IAccountManager::SCOPE_PRIVATE:
+ return $visitingUser !== null && $this->knownUserService->isKnownToUser($targetUser->getUID(), $visitingUser->getUID());
+ case IAccountManager::SCOPE_LOCAL:
+ case IAccountManager::SCOPE_FEDERATED:
+ case IAccountManager::SCOPE_PUBLISHED:
+ return $visitingUser !== null;
+ default:
+ return false;
+ }
+ }
+ return $visitingUser !== null;
+ case ProfileConfig::VISIBILITY_SHOW:
+ if (!empty($scope)) {
+ switch ($scope) {
+ case IAccountManager::SCOPE_PRIVATE:
+ return $visitingUser !== null && $this->knownUserService->isKnownToUser($targetUser->getUID(), $visitingUser->getUID());
+ case IAccountManager::SCOPE_LOCAL:
+ case IAccountManager::SCOPE_FEDERATED:
+ case IAccountManager::SCOPE_PUBLISHED:
+ return true;
+ default:
+ return false;
+ }
+ }
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getProfileParams(IUser $targetUser, ?IUser $visitingUser): array {
+ $account = $this->accountManager->getAccount($targetUser);
+ // Initialize associative array of profile parameters
+ $profileParameters = [
+ 'userId' => $account->getUser()->getUID(),
+ ];
+
+ // Add account properties
+ foreach (self::PROFILE_PROPERTIES as $property) {
+ $profileParameters[$property] =
+ $this->isParameterVisible($targetUser, $visitingUser, $property)
+ // Explicitly set to null when value is empty string
+ ? ($account->getProperty($property)->getValue() ?: null)
+ : null;
+ }
+
+ // Add avatar visibility
+ $profileParameters['isUserAvatarVisible'] = $this->isParameterVisible($targetUser, $visitingUser, IAccountManager::PROPERTY_AVATAR);
+
+ // Add actions
+ $profileParameters['actions'] = array_map(
+ function (ILinkAction $action) {
+ return [
+ 'id' => $action->getId(),
+ 'icon' => $action->getIcon(),
+ 'title' => $action->getTitle(),
+ 'target' => $action->getTarget(),
+ ];
+ },
+ // This is needed to reindex the array after filtering
+ array_values(
+ array_filter(
+ $this->getActions($targetUser, $visitingUser),
+ function (ILinkAction $action) use ($targetUser, $visitingUser) {
+ return $this->isParameterVisible($targetUser, $visitingUser, $action->getId());
+ }
+ ),
+ )
+ );
+
+ return $profileParameters;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getProfileConfig(IUser $targetUser, ?IUser $visitingUser): array {
+ try {
+ $configArray = $this->configMapper->getArray($targetUser->getUID());
+ } catch (DoesNotExistException $e) {
+ $config = new ProfileConfig();
+ $config->setUserId($targetUser->getUID());
+
+ // Map of account properties to display IDs
+ $propertyDisplayMap = [
+ IAccountManager::PROPERTY_ADDRESS => $this->l10nFactory->get('core')->t('Address'),
+ IAccountManager::PROPERTY_AVATAR => $this->l10nFactory->get('core')->t('Avatar'),
+ IAccountManager::PROPERTY_BIOGRAPHY => $this->l10nFactory->get('core')->t('About'),
+ IAccountManager::PROPERTY_DISPLAYNAME => $this->l10nFactory->get('core')->t('Full name'),
+ IAccountManager::PROPERTY_HEADLINE => $this->l10nFactory->get('core')->t('Headline'),
+ IAccountManager::PROPERTY_ORGANISATION => $this->l10nFactory->get('core')->t('Organisation'),
+ IAccountManager::PROPERTY_ROLE => $this->l10nFactory->get('core')->t('Role'),
+ IAccountManager::PROPERTY_EMAIL => $this->l10nFactory->get('core')->t('Email'),
+ IAccountManager::PROPERTY_PHONE => $this->l10nFactory->get('core')->t('Phone'),
+ IAccountManager::PROPERTY_TWITTER => $this->l10nFactory->get('core')->t('Twitter'),
+ IAccountManager::PROPERTY_WEBSITE => $this->l10nFactory->get('core')->t('Website'),
+ ];
+
+ // Contruct the default config for account properties
+ $propertiesConfig = [];
+ foreach ($propertyDisplayMap as $property => $displayId) {
+ $propertiesConfig[$property] = [
+ 'displayId' => $displayId,
+ 'visibility' => ProfileConfig::DEFAULT_PROPERTY_VISIBILITY[$property] ?: ProfileConfig::DEFAULT_VISIBILITY,
+ ];
+ }
+
+ // Contruct the default config for actions
+ $actionsConfig = [];
+ /** @var ILinkAction $action */
+ foreach ($this->getActions($targetUser, $visitingUser) as $action) {
+ $actionsConfig[$action->getId()] = [
+ 'displayId' => $action->getDisplayId(),
+ 'visibility' => ProfileConfig::DEFAULT_VISIBILITY,
+ ];
+ }
+
+ // Set the default config
+ $config->setConfigArray(array_merge($propertiesConfig, $actionsConfig));
+ $this->configMapper->insert($config);
+ $configArray = $config->getConfigArray();
+ }
+
+ return $configArray;
+ }
+}
diff --git a/lib/private/Profile/TProfileHelper.php b/lib/private/Profile/TProfileHelper.php
new file mode 100644
index 00000000000..0d4b5c6286e
--- /dev/null
+++ b/lib/private/Profile/TProfileHelper.php
@@ -0,0 +1,46 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright 2021 Christopher Ng <chrng8@gmail.com>
+ *
+ * @author Christopher Ng <chrng8@gmail.com>
+ *
+ * @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 OC\Profile;
+
+use OCP\Accounts\IAccount;
+use OCP\Accounts\IAccountManager;
+
+trait TProfileHelper {
+
+ /**
+ * Returns whether the profile is enabled for the account
+ *
+ * @since 23.0.0
+ */
+ protected function isProfileEnabled(IAccount $account): ?bool {
+ return filter_var(
+ $account->getProperty(IAccountManager::PROPERTY_PROFILE_ENABLED)->getValue(),
+ FILTER_VALIDATE_BOOLEAN,
+ FILTER_NULL_ON_FAILURE,
+ );
+ }
+}
diff --git a/lib/private/Setup.php b/lib/private/Setup.php
index c24d417f8cf..a7f0f190fa2 100644
--- a/lib/private/Setup.php
+++ b/lib/private/Setup.php
@@ -425,6 +425,9 @@ class Setup {
//and we are done
$config->setSystemValue('installed', true);
+ $bootstrapCoordinator = \OC::$server->query(\OC\AppFramework\Bootstrap\Coordinator::class);
+ $bootstrapCoordinator->runInitialRegistration();
+
// Create a session token for the newly created user
// The token provider requires a working db, so it's not injected on setup
/* @var $userSession User\Session */
diff --git a/lib/private/Template/SCSSCacher.php b/lib/private/Template/SCSSCacher.php
index 0543427f997..c1bd556de60 100644
--- a/lib/private/Template/SCSSCacher.php
+++ b/lib/private/Template/SCSSCacher.php
@@ -32,6 +32,7 @@ namespace OC\Template;
use OC\AppConfig;
use OC\Files\AppData\Factory;
use OC\Memcache\NullCache;
+use OCA\Theming\ThemingDefaults;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\Files\IAppData;
use OCP\Files\NotFoundException;
@@ -62,7 +63,7 @@ class SCSSCacher {
/** @var IConfig */
protected $config;
- /** @var \OC_Defaults */
+ /** @var ThemingDefaults */
private $defaults;
/** @var string */
@@ -96,7 +97,7 @@ class SCSSCacher {
* @param Factory $appDataFactory
* @param IURLGenerator $urlGenerator
* @param IConfig $config
- * @param \OC_Defaults $defaults
+ * @param ThemingDefaults $defaults
* @param string $serverRoot
* @param ICacheFactory $cacheFactory
* @param IconsCacher $iconsCacher
@@ -106,7 +107,7 @@ class SCSSCacher {
Factory $appDataFactory,
IURLGenerator $urlGenerator,
IConfig $config,
- \OC_Defaults $defaults,
+ ThemingDefaults $defaults,
$serverRoot,
ICacheFactory $cacheFactory,
IconsCacher $iconsCacher,
@@ -406,7 +407,7 @@ class SCSSCacher {
}
/**
- * @return string SCSS code for variables from OC_Defaults
+ * @return string SCSS code for variables from ThemingDefaults
*/
private function getInjectedVariables(string $cache = ''): string {
if ($this->injectedVariables !== null) {