Skip to content

Commit

Permalink
Merge pull request #13821 from nextcloud/backport/13812/stable30
Browse files Browse the repository at this point in the history
[stable30] fix: e-mail guests parsing in chat messages
  • Loading branch information
nickvergessen authored Nov 20, 2024
2 parents f8ccd18 + 6e3de52 commit 8545f00
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 22 deletions.
26 changes: 16 additions & 10 deletions lib/Chat/AutoComplete/SearchPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public function search($search, $limit, $offset, ISearchResult $searchResult): b
$groupIds = [];
/** @var array<string, string> $cloudIds */
$cloudIds = [];
/** @var array<string, string> $emailAttendees */
/** @var array<string, Attendee> $emailAttendees */
$emailAttendees = [];
/** @var list<Attendee> $guestAttendees */
$guestAttendees = [];
Expand All @@ -85,7 +85,7 @@ public function search($search, $limit, $offset, ISearchResult $searchResult): b
if ($attendee->getActorType() === Attendee::ACTOR_GUESTS) {
$guestAttendees[] = $attendee;
} elseif ($attendee->getActorType() === Attendee::ACTOR_EMAILS) {
$emailAttendees[$attendee->getActorId()] = $attendee->getDisplayName();
$emailAttendees[$attendee->getActorId()] = $attendee;
} elseif ($attendee->getActorType() === Attendee::ACTOR_USERS) {
$userIds[$attendee->getActorId()] = $attendee->getDisplayName();
} elseif ($attendee->getActorType() === Attendee::ACTOR_FEDERATED_USERS) {
Expand Down Expand Up @@ -307,7 +307,7 @@ protected function searchGuests(string $search, array $attendees, ISearchResult

/**
* @param string $search
* @param array<string, string> $attendees
* @param array<string, Attendee> $attendees
* @param ISearchResult $searchResult
*/
protected function searchEmails(string $search, array $attendees, ISearchResult $searchResult): void {
Expand All @@ -325,25 +325,25 @@ protected function searchEmails(string $search, array $attendees, ISearchResult
}

$matches = $exactMatches = [];
foreach ($attendees as $actorId => $displayName) {
foreach ($attendees as $actorId => $attendee) {
if ($currentSessionHash === $actorId) {
// Do not suggest the current guest
continue;
}

$displayName = $displayName ?: $this->l->t('Guest');
$displayName = $attendee->getDisplayName() ?: $this->l->t('Guest');
if ($search === '') {
$matches[] = $this->createEmailResult($actorId, $displayName);
$matches[] = $this->createEmailResult($actorId, $displayName, $attendee->getInvitedCloudId());
continue;
}

if (strtolower($displayName) === $search) {
$exactMatches[] = $this->createEmailResult($actorId, $displayName);
$exactMatches[] = $this->createEmailResult($actorId, $displayName, $attendee->getInvitedCloudId());
continue;
}

if (stripos($displayName, $search) !== false) {
$matches[] = $this->createEmailResult($actorId, $displayName);
$matches[] = $this->createEmailResult($actorId, $displayName, $attendee->getInvitedCloudId());
continue;
}
}
Expand Down Expand Up @@ -386,13 +386,19 @@ protected function createGuestResult(string $actorId, string $name): array {
];
}

protected function createEmailResult(string $actorId, string $name): array {
return [
protected function createEmailResult(string $actorId, string $name, ?string $email): array {
$data = [
'label' => $name,
'value' => [
'shareType' => 'email',
'shareWith' => 'email/' . $actorId,
],
];

if ($email) {
$data['details'] = ['email' => $email];
}

return $data;
}
}
4 changes: 4 additions & 0 deletions lib/Controller/ChatController.php
Original file line number Diff line number Diff line change
Expand Up @@ -1495,6 +1495,10 @@ protected function prepareResultArray(array $results, array $statuses): array {
$data['statusClearAt'] = $statuses[$data['id']]->getClearAt()?->getTimestamp();
}

if ($type === Attendee::ACTOR_EMAILS && isset($result['details']) && $this->participant->hasModeratorPermissions()) {
$data['details'] = $result['details']['email'];
}

$output[] = $data;
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/components/MessagesList/MessagesGroup/Message/Message.vue
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ import MessageBody from './MessagePart/MessageBody.vue'
import Poll from './MessagePart/Poll.vue'
import Reactions from './MessagePart/Reactions.vue'

import { CONVERSATION, PARTICIPANT } from '../../../../constants.js'
import { CONVERSATION, MENTION, PARTICIPANT } from '../../../../constants.js'
import { getTalkConfig } from '../../../../services/CapabilitiesManager.ts'
import { EventBus } from '../../../../services/EventBus.ts'
import { useChatExtrasStore } from '../../../../stores/chatExtras.js'
Expand Down Expand Up @@ -262,7 +262,7 @@ export default {
messageParameters: this.message.messageParameters,
messageType: this.message.messageType
})
if (type === 'user' || type === 'call' || type === 'guest' || type === 'user-group' || type === 'group') {
if (Object.values(MENTION.TYPE).includes(type)) {
richParameters[p] = {
component: Mention,
props: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { loadState } from '@nextcloud/initial-state'
import NcUserBubble from '@nextcloud/vue/dist/Components/NcUserBubble.js'
import { useIsDarkTheme } from '@nextcloud/vue/dist/Composables/useIsDarkTheme.js'

import { MENTION } from '../../../../../constants.js'
import { getConversationAvatarOcsUrl, getUserProxyAvatarOcsUrl } from '../../../../../services/avatarService.ts'

export default {
Expand Down Expand Up @@ -69,25 +70,27 @@ export default {

computed: {
isMentionToAll() {
return this.type === 'call'
return this.type === MENTION.TYPE.CALL
},
isGroupMention() {
return this.type === 'user-group' || this.type === 'group'
return [MENTION.TYPE.USERGROUP, MENTION.TYPE.GROUP].includes(this.type)
},
isMentionToGuest() {
return this.type === 'guest'
return this.type === MENTION.TYPE.GUEST || this.type === MENTION.TYPE.EMAIL
},
isRemoteUser() {
return this.type === 'user' && this.server !== ''
return [MENTION.TYPE.USER, MENTION.TYPE.FEDERATED_USER].includes(this.type) && this.server !== ''
},
isCurrentGuest() {
// On mention bubbles the id is actually "guest/ACTOR_ID" for guests
// This is to make sure guests can never collide with users,
// while storing them as "… @id …" in chat messages.
// So when comparing a guest we have to prefix "guest/"
// when comparing the id
// However we do not prefix email accounts, so simply compare id
return this.$store.getters.isActorGuest()
&& this.id === ('guest/' + this.$store.getters.getActorId())
&& (this.id === ('guest/' + this.$store.getters.getActorId())
|| this.id === this.$store.getters.getActorId())
},
isCurrentUser() {
if (this.isRemoteUser) {
Expand Down
3 changes: 3 additions & 0 deletions src/composables/useChatMentions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ function useChatMentionsComposable(token: Ref<string>): ReturnType {
} else if (possibleMention.source === ATTENDEE.ACTOR_TYPE.GUESTS) {
chatMention.icon = 'icon-user-forced-white'
chatMention.subline = t('spreed', 'Guest')
} else if (possibleMention.source === ATTENDEE.ACTOR_TYPE.EMAILS) {
chatMention.icon = 'icon-user-forced-white'
chatMention.subline = possibleMention?.details ?? t('spreed', 'Guest')
} else if (possibleMention.source === ATTENDEE.ACTOR_TYPE.FEDERATED_USERS) {
chatMention.icon = 'icon-user-forced-white'
chatMention.iconUrl = getUserProxyAvatarOcsUrl(token, possibleMention.id, isDarkTheme, 64)
Expand Down
13 changes: 13 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -306,3 +306,16 @@ export const FEDERATION = {
ACCEPTED: 1,
},
}

export const MENTION = {
TYPE: {
CALL: 'call',
USER: 'user',
GUEST: 'guest',
EMAIL: 'email',
USERGROUP: 'user-group',
// Parsed to another types
FEDERATED_USER: 'federated_user',
GROUP: 'group',
},
}
17 changes: 12 additions & 5 deletions src/utils/textParse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import { getBaseUrl } from '@nextcloud/router'

import { MENTION } from '../constants.js'
import type { ChatMessage, Mention } from '../types/index.ts'

/**
Expand All @@ -18,14 +19,20 @@ function parseMentions(text: string, parameters: ChatMessage['messageParameters'
const value: Mention = parameters[key] as Mention
let mention = ''

if (key.startsWith('mention-call') && value.type === 'call') {
if (key.startsWith('mention-call') && value.type === MENTION.TYPE.CALL) {
mention = '@all'
} else if (key.startsWith('mention-federated-user') && value.type === 'user') {
const server = value?.server ?? getBaseUrl().replace('https://', '')
} else if (key.startsWith('mention-federated-user')
&& [MENTION.TYPE.USER, MENTION.TYPE.FEDERATED_USER].includes(value.type)) {
const server = (value?.server ?? getBaseUrl()).replace('https://', '')
mention = `@"federated_user/${value.id}@${server}"`
} else if (key.startsWith('mention-group') && value.type === 'user-group') {
} else if (key.startsWith('mention-group')
&& [MENTION.TYPE.USERGROUP, MENTION.TYPE.GROUP].includes(value.type)) {
mention = `@"group/${value.id}"`
} else if (key.startsWith('mention-user') && value.type === 'user') {
} else if (key.startsWith('mention-guest') && value.type === MENTION.TYPE.GUEST) {
mention = `@"${value.id}"`
} else if (key.startsWith('mention-email') && value.type === MENTION.TYPE.EMAIL) {
mention = `@"email/${value.id}"`
} else if (key.startsWith('mention-user') && value.type === MENTION.TYPE.USER) {
mention = value.id.includes(' ') ? `@"${value.id}"` : `@${value.id}`
}

Expand Down

0 comments on commit 8545f00

Please sign in to comment.