-
-
Notifications
You must be signed in to change notification settings - Fork 4.7k
fix(contactsMenu): Attach user cloud to each contact entry #44954
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -31,6 +31,7 @@ | |
|
|
||
| namespace OC\Contacts\ContactsMenu; | ||
|
|
||
| use OC\Federation\CloudId; | ||
| use OC\KnownUser\KnownUserService; | ||
| use OC\Profile\ProfileManager; | ||
| use OCA\UserStatus\Db\UserStatus; | ||
|
|
@@ -44,6 +45,7 @@ | |
| use OCP\IUser; | ||
| use OCP\IUserManager; | ||
| use OCP\L10N\IFactory as IL10NFactory; | ||
| use Psr\Log\LoggerInterface; | ||
| use function array_column; | ||
| use function array_fill_keys; | ||
| use function array_filter; | ||
|
|
@@ -62,6 +64,7 @@ public function __construct( | |
| private IGroupManager $groupManager, | ||
| private KnownUserService $knownUserService, | ||
| private IL10NFactory $l10nFactory, | ||
| private LoggerInterface $logger, | ||
| ) { | ||
| } | ||
|
|
||
|
|
@@ -351,19 +354,35 @@ public function findOne(IUser $user, int $shareType, string $shareWith): ?IEntry | |
|
|
||
| private function contactArrayToEntry(array $contact): Entry { | ||
| $entry = new Entry(); | ||
|
|
||
| if (!empty($contact['UID'])) { | ||
| $uid = $contact['UID']; | ||
| $entry->setId($uid); | ||
| $entry->setProperty('isUser', false); | ||
| $username = ''; | ||
| $remoteServer = ''; | ||
|
|
||
| if (isset($contact['CLOUD']) && is_array($contact['CLOUD']) && isset($contact['CLOUD'][0])) { | ||
| preg_match('/^(.*?)@(https?:\/\/.*?)$/', $contact['CLOUD'][0], $matches); | ||
| if (count($matches) === 3) { | ||
| $username = $matches[1]; | ||
| $remoteServer = $matches[2]; | ||
| $cloud = new CloudId($entry->getId(), $username, $remoteServer); | ||
| $entry->setCloudId($cloud); | ||
| $this->logger->warning('Set address cloud: ' . json_encode(['username' => $username, 'server' => $remoteServer])); | ||
| } else { | ||
| $this->logger->warning('Unable to process contact remote server: ' . $contact['CLOUD'][0]); | ||
| } | ||
| } else { | ||
| $this->logger->warning('Invalid remote server data'); | ||
| } | ||
| // overloaded usage so leaving as-is for now | ||
| if (isset($contact['isLocalSystemBook'])) { | ||
| $avatar = $this->urlGenerator->linkToRouteAbsolute('core.avatar.getAvatar', ['userId' => $uid, 'size' => 64]); | ||
| $entry->setProperty('isUser', true); | ||
| } elseif (!empty($contact['FN'])) { | ||
| $avatar = $this->urlGenerator->linkToRouteAbsolute('core.GuestAvatar.getAvatar', ['guestName' => str_replace('/', ' ', $contact['FN']), 'size' => 64]); | ||
| } elseif ($username != '') { | ||
| $avatar = $this->urlGenerator->linkToRemoteRouteAbsolute($remoteServer, 'core.avatar.getAvatar', ['userId' => str_replace('/', ' ', $username), 'size' => 64]); | ||
Check failureCode scanning / Psalm UndefinedInterfaceMethod
Method OCP\IURLGenerator::linkToRemoteRouteAbsolute does not exist
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This assumes every cloud ID is a nextcloud? 🫣 |
||
| } else { | ||
| $avatar = $this->urlGenerator->linkToRouteAbsolute('core.GuestAvatar.getAvatar', ['guestName' => str_replace('/', ' ', $uid), 'size' => 64]); | ||
| $avatar = $this->urlGenerator->linkToRemoteRouteAbsolute($remoteServer, 'core.avatar.getAvatar', ['userId' => str_replace('/', ' ', $uid), 'size' => 64]); | ||
Check failureCode scanning / Psalm UndefinedInterfaceMethod
Method OCP\IURLGenerator::linkToRemoteRouteAbsolute does not exist
|
||
| } | ||
| $entry->setAvatar($avatar); | ||
| } | ||
|
|
@@ -374,7 +393,7 @@ private function contactArrayToEntry(array $contact): Entry { | |
|
|
||
| $avatarPrefix = "VALUE=uri:"; | ||
| if (!empty($contact['PHOTO']) && str_starts_with($contact['PHOTO'], $avatarPrefix)) { | ||
| $entry->setAvatar(substr($contact['PHOTO'], strlen($avatarPrefix))); | ||
| //$entry->setAvatar(substr($contact['PHOTO'], strlen($avatarPrefix))); | ||
| } | ||
|
|
||
| if (!empty($contact['EMAIL'])) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,41 +27,40 @@ | |
|
|
||
| namespace OC\Contacts\ContactsMenu; | ||
|
|
||
| use OC\Federation\CloudId; | ||
| use OCP\Contacts\ContactsMenu\IAction; | ||
| use OCP\Contacts\ContactsMenu\IEntry; | ||
| use function array_merge; | ||
|
|
||
| class Entry implements IEntry { | ||
| public const PROPERTY_STATUS_MESSAGE_TIMESTAMP = 'statusMessageTimestamp'; | ||
|
|
||
| /** @var string|int|null */ | ||
| private $id = null; | ||
|
|
||
| private string $fullName = ''; | ||
|
|
||
| /** @var string[] */ | ||
| private array $emailAddresses = []; | ||
|
|
||
| private ?string $avatar = null; | ||
|
|
||
| private ?string $profileTitle = null; | ||
|
|
||
| private ?string $profileUrl = null; | ||
|
|
||
| /** @var IAction[] */ | ||
| private array $actions = []; | ||
|
|
||
| private array $properties = []; | ||
| public function __construct( | ||
| private ?string $id = null, | ||
| private string $fullName = '', | ||
| private array $emailAddresses = [], | ||
| private ?string $avatar = null, | ||
| private ?string $profileTitle = null, | ||
| private ?string $profileUrl = null, | ||
| private array $actions = [], | ||
| private array $properties = [], | ||
| private ?string $status = null, | ||
| private ?string $statusMessage = null, | ||
| private ?int $statusMessageTimestamp = null, | ||
| private ?string $statusIcon = null, | ||
| private ?CloudId $cloud = null | ||
| ) { | ||
| } | ||
|
|
||
| private ?string $status = null; | ||
| private ?string $statusMessage = null; | ||
| private ?int $statusMessageTimestamp = null; | ||
| private ?string $statusIcon = null; | ||
|
|
||
| public function setId(string $id): void { | ||
| $this->id = $id; | ||
| } | ||
|
|
||
| public function getId(): string { | ||
Check failureCode scanning / Psalm InvalidNullableReturnType
The declared return type 'string' for OC\Contacts\ContactsMenu\Entry::getId is not nullable, but 'null|string' contains null
|
||
| return $this->id; | ||
Check failureCode scanning / Psalm NullableReturnStatement
The declared return type 'string' for OC\Contacts\ContactsMenu\Entry::getId is not nullable, but the function returns 'null|string'
|
||
| } | ||
|
|
||
| public function setFullName(string $displayName): void { | ||
| $this->fullName = $displayName; | ||
| } | ||
|
|
@@ -163,8 +162,25 @@ public function getProperty(string $key): mixed { | |
| return $this->properties[$key]; | ||
| } | ||
|
|
||
|
|
||
| public function getStatusMessage(): ?string { | ||
| return $this->statusMessage; | ||
| } | ||
|
|
||
| public function getStatusMessageTimestamp(): ?int { | ||
| return $this->statusMessageTimestamp; | ||
| } | ||
|
|
||
| public function setCloudId(CloudId $cloudId) { | ||
| $this->cloud = $cloudId; | ||
| } | ||
|
|
||
| public function getCloud(): CloudId { | ||
Check failureCode scanning / Psalm InvalidNullableReturnType
The declared return type 'OC\Federation\CloudId' for OC\Contacts\ContactsMenu\Entry::getCloud is not nullable, but 'OC\Federation\CloudId|null' contains null
|
||
| return $this->cloud; | ||
Check failureCode scanning / Psalm NullableReturnStatement
The declared return type 'OC\Federation\CloudId' for OC\Contacts\ContactsMenu\Entry::getCloud is not nullable, but the function returns 'OC\Federation\CloudId|null'
|
||
| } | ||
|
|
||
| /** | ||
| * @return array{id: int|string|null, fullName: string, avatar: string|null, topAction: mixed, actions: array, lastMessage: '', emailAddresses: string[], profileTitle: string|null, profileUrl: string|null, status: string|null, statusMessage: null|string, statusMessageTimestamp: null|int, statusIcon: null|string, isUser: bool, uid: mixed} | ||
| * @return array{id: int|string|null, fullName: string, avatar: string|null, topAction: mixed, actions: array, lastMessage: '', emailAddresses: string[], profileTitle: string|null, profileUrl: string|null, status: string|null, statusMessage: null|string, statusMessageTimestamp: null|int, statusIcon: null|string, isUser: bool, uid: mixed, cloud: mixed} | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. cloud should be called cloudId to be more clear and the type should be the array you define in the other file |
||
| */ | ||
| public function jsonSerialize(): array { | ||
| $topAction = !empty($this->actions) ? $this->actions[0]->jsonSerialize() : null; | ||
|
|
@@ -188,14 +204,7 @@ public function jsonSerialize(): array { | |
| 'statusIcon' => $this->statusIcon, | ||
| 'isUser' => $this->getProperty('isUser') === true, | ||
| 'uid' => $this->getProperty('UID'), | ||
| 'cloud' => $this->cloud, | ||
| ]; | ||
| } | ||
|
|
||
| public function getStatusMessage(): ?string { | ||
| return $this->statusMessage; | ||
| } | ||
|
|
||
| public function getStatusMessageTimestamp(): ?int { | ||
| return $this->statusMessageTimestamp; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -88,4 +88,16 @@ public function getUser(): string { | |
| public function getRemote(): string { | ||
| return $this->remote; | ||
| } | ||
|
|
||
| /** | ||
| * @return array{id: string, user: string, remote: string, displayName: string|null} | ||
| */ | ||
| public function jsonSerialize(): array { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should implement the interface JsonSerializable?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That being said, should be on the public interface? |
||
| return [ | ||
| 'id' => $this->id, | ||
| 'user' => $this->user, | ||
| 'remote' => $this->remote, | ||
| 'displayName' => $this->displayName, | ||
| ]; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -115,6 +115,19 @@ public function linkToRouteAbsolute(string $routeName, array $arguments = []): s | |
| return $this->getAbsoluteURL($this->linkToRoute($routeName, $arguments)); | ||
| } | ||
|
|
||
|
|
||
| public function linkToRemoteRouteAbsolute(string $remote, $routeName, array $arguments = []): string { | ||
Check failureCode scanning / Psalm InvalidNullableReturnType
The declared return type 'string' for OC\URLGenerator::linkToRemoteRouteAbsolute is not nullable, but 'null|string' contains null
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should not be here or on the public interface |
||
| return $this->formatAsUrl($remote, $this->linkToRoute($routeName, $arguments)); | ||
Check failureCode scanning / Psalm NullableReturnStatement
The declared return type 'string' for OC\URLGenerator::linkToRemoteRouteAbsolute is not nullable, but the function returns 'null|string'
|
||
| } | ||
|
|
||
| private function formatAsUrl(string $baseUrl, string $restUrl): ?string { | ||
| $baseUrl = trim($baseUrl); | ||
| if (empty($baseUrl) || !filter_var(preg_match("~^(?:f|ht)tps?://~i", $baseUrl) ? $baseUrl : "http://$baseUrl", FILTER_VALIDATE_URL)) { | ||
| return null; | ||
| } | ||
| return filter_var($baseUrl . $restUrl, FILTER_VALIDATE_URL) ? $baseUrl . $restUrl : null; | ||
| } | ||
|
|
||
| public function linkToOCSRouteAbsolute(string $routeName, array $arguments = []): string { | ||
| // Returns `/subfolder/index.php/ocsapp/…` with `'htaccess.IgnoreFrontController' => false` in config.php | ||
| // And `/subfolder/ocsapp/…` with `'htaccess.IgnoreFrontController' => true` in config.php | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use the
ICloudManager::resolve()method instead?