Merge pull request #2838 from nextcloud/bugfix/722/update-guestnames

Update guest names on chat messages and in the call
This commit is contained in:
Joas Schilling 2020-01-27 09:23:49 +01:00 коммит произвёл GitHub
Родитель 7dda57d056 e69740b372
Коммит ce7a4c932b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
11 изменённых файлов: 164 добавлений и 20 удалений

Просмотреть файл

@ -91,7 +91,7 @@ class GuestManager {
$dispatchEvent = true;
try {
$oldName = $this->getNameBySessionHash($sessionHash);
$oldName = $this->getNameBySessionHash($sessionHash, true);
if ($oldName !== $displayName) {
$query = $this->connection->getQueryBuilder();
@ -117,10 +117,11 @@ class GuestManager {
/**
* @param string $sessionHash
* @param bool $allowEmpty
* @return string
* @throws ParticipantNotFoundException
*/
public function getNameBySessionHash(string $sessionHash): string {
public function getNameBySessionHash(string $sessionHash, bool $allowEmpty = false): string {
$query = $this->connection->getQueryBuilder();
$query->select('display_name')
->from('talk_guests')
@ -130,7 +131,7 @@ class GuestManager {
$row = $result->fetch();
$result->closeCursor();
if (isset($row['display_name']) && $row['display_name'] !== '') {
if (isset($row['display_name']) && ($allowEmpty || $row['display_name'] !== '')) {
return $row['display_name'];
}

Просмотреть файл

@ -46,6 +46,8 @@
import attachMediaStream from 'attachmediastream'
import Avatar from '@nextcloud/vue/dist/Components/Avatar'
import LocalMediaControls from './LocalMediaControls'
import Hex from 'crypto-js/enc-hex'
import SHA1 from 'crypto-js/sha1'
export default {
@ -81,12 +83,20 @@ export default {
return this.$store.getters.getDisplayName()
},
guestName() {
return this.localCallParticipantModel.attributes.guestName || localStorage.getItem('nick') || '?'
firstLetterOfGuestName() {
const customName = this.guestName !== t('spreed', 'Guest') ? this.guestName : '?'
return customName.charAt(0)
},
firstLetterOfGuestName() {
return this.guestName.substring(0, 1)
sessionHash() {
return Hex.stringify(SHA1(this.localCallParticipantModel.attributes.peerId))
},
guestName() {
return this.$store.getters.getGuestName(
this.$store.getters.getToken(),
this.sessionHash,
) || localStorage.getItem('nick') || t('spreed', 'Guest')
},
avatarSize() {

Просмотреть файл

@ -70,6 +70,8 @@ import attachMediaStream from 'attachmediastream'
import Avatar from '@nextcloud/vue/dist/Components/Avatar'
import Tooltip from '@nextcloud/vue/dist/Directives/Tooltip'
import { ConnectionState } from '../../utils/webrtc/models/CallParticipantModel'
import SHA1 from 'crypto-js/sha1'
import Hex from 'crypto-js/enc-hex'
export default {
@ -126,18 +128,23 @@ export default {
'icon-loading': this.model.attributes.connectionState !== ConnectionState.CONNECTED && this.model.attributes.connectionState !== ConnectionState.COMPLETED && this.model.attributes.connectionState !== ConnectionState.FAILED_NO_RESTART,
}
},
firstLetterOfGuestName() {
return (this.model.attributes.name || '?').substring(0, 1)
const customName = this.participantName !== t('spreed', 'Guest') ? this.participantName : '?'
return customName.charAt(0)
},
sessionHash() {
return Hex.stringify(SHA1(this.model.attributes.peerId))
},
participantName() {
let participantName = this.model.attributes.name
// "Guest" placeholder is not shown until the initial connection for
// consistency with regular users.
if (!this.model.attributes.userId && this.model.attributes.connectionState !== ConnectionState.NEW) {
participantName = participantName || t('spreed', 'Guest')
if (!this.model.attributes.userId) {
participantName = this.$store.getters.getGuestName(
this.$store.getters.getToken(),
this.sessionHash,
)
}
return participantName

Просмотреть файл

@ -113,8 +113,8 @@ export default {
actorDisplayName() {
const displayName = this.messages[0].actorDisplayName.trim()
if (displayName === '' && this.actorType === 'guests') {
return t('spreed', 'Guest')
if (this.actorType === 'guests') {
return this.$store.getters.getGuestName(this.token, this.actorId)
}
if (displayName === '') {

Просмотреть файл

@ -252,7 +252,6 @@ export default {
&& (message1.systemMessage.length === 0) === (message2.systemMessage.length === 0) // Only group system messages with each others
&& message1.actorType === message2.actorType // To have the same author, the type
&& message1.actorId === message2.actorId // and the id of the author must be the same
&& message1.actorDisplayName === message2.actorDisplayName // FIXME: this is in case a guest user changes its username
&& !this.messagesHaveDifferentDate(message1, message2) // Posted on the same day
},
@ -371,6 +370,9 @@ export default {
const messages = await request({ token: this.token, lastKnownMessageId, includeLastKnown })
// Process each messages and adds it to the store
messages.data.ocs.data.forEach(message => {
if (message.actorType === 'guests') {
this.$store.dispatch('setGuestNameIfEmpty', message)
}
this.$store.dispatch('processMessage', message)
})
} catch (exception) {
@ -397,6 +399,9 @@ export default {
const messages = await request({ token: this.token, lastKnownMessageId })
// Process each messages and adds it to the store
messages.data.ocs.data.forEach(message => {
if (message.actorType === 'guests') {
this.$store.dispatch('forceGuestName', message)
}
this.$store.dispatch('processMessage', message)
})
// Scroll to the last message if sticky

Просмотреть файл

@ -162,6 +162,12 @@ export default {
token: this.token,
isReplyable: false,
})
if (this.$store.getters.getActorType() === 'guests') {
// Strip off "guests/" from the sessionHash
message.actorId = this.$store.getters.getActorId().substring(6)
}
/**
* If the current message is a quote-reply messag, add the parent key to the
* temporary message object.

Просмотреть файл

@ -81,7 +81,7 @@ import ParticipantsList from './ParticipantsList/ParticipantsList'
import SearchBox from '../../LeftSidebar/SearchBox/SearchBox'
import debounce from 'debounce'
import { EventBus } from '../../../services/EventBus'
import { CONVERSATION, WEBINAR } from '../../../constants'
import { CONVERSATION, PARTICIPANT, WEBINAR } from '../../../constants'
import { searchPossibleConversations } from '../../../services/conversationsService'
import {
addParticipant,
@ -89,6 +89,8 @@ import {
} from '../../../services/participantsService'
import isInLobby from '../../../mixins/isInLobby'
import { loadState } from '@nextcloud/initial-state'
import SHA1 from 'crypto-js/sha1'
import Hex from 'crypto-js/enc-hex'
export default {
name: 'ParticipantsTab',
@ -315,6 +317,14 @@ export default {
token: token,
participant,
})
if (participant.participantType === PARTICIPANT.TYPE.GUEST
|| participant.participantType === PARTICIPANT.TYPE.GUEST_MODERATOR) {
this.$store.dispatch('forceGuestName', {
token: token,
actorId: Hex.stringify(SHA1(participant.sessionId)),
actorDisplayName: participant.displayName,
})
}
})
this.participantsInitialised = true
} catch (exception) {

Просмотреть файл

@ -394,11 +394,23 @@ export default {
this.isEditingPassword = false
},
async handleChooseUserName() {
const previousName = this.$store.getters.getDisplayName()
try {
await setGuestUserName(this.token, this.guestUserName)
this.$store.dispatch('setDisplayName', this.guestUserName)
this.$store.dispatch('forceGuestName', {
token: this.token,
actorId: this.$store.getters.getActorId().substring(6),
actorDisplayName: this.guestUserName,
})
await setGuestUserName(this.token, this.guestUserName)
this.isEditingUsername = false
} catch (exception) {
this.$store.dispatch('setDisplayName', previousName)
this.$store.dispatch('forceGuestName', {
token: this.token,
actorId: this.$store.getters.getActorId().substring(6),
actorDisplayName: previousName,
})
console.debug(exception)
}
},

Просмотреть файл

@ -56,8 +56,8 @@ const lookForNewMessages = async({ token, lastKnownMessageId }, options) => {
* @param {string} message The message object;
* @param {Number} parent The id of the message to be replied to.
*/
const postNewMessage = async function({ token, message, parent }) {
const response = await axios.post(generateOcsUrl('apps/spreed/api/v1/chat', 2) + token, { message, actorDisplayName: '', replyTo: parent })
const postNewMessage = async function({ token, message, actorDisplayName, parent }) {
const response = await axios.post(generateOcsUrl('apps/spreed/api/v1/chat', 2) + token, { message, actorDisplayName, replyTo: parent })
return response
}

Просмотреть файл

@ -0,0 +1,91 @@
/**
* @copyright Copyright (c) 2019 Joas Schilling <coding@schilljs.com>
*
* @author Joas Schilling <coding@schilljs.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/>.
*
*/
import Vue from 'vue'
const state = {
guestNames: {
},
}
const getters = {
/**
* Gets the participants array
* @param {object} state the state object.
* @returns {array} the participants array (if there are participants in the store)
*/
getGuestName: (state) => (token, actorId) => {
if (state.guestNames[token] && state.guestNames[token][actorId]) {
return state.guestNames[token][actorId]
}
return t('spreed', 'Guest')
},
}
const mutations = {
/**
* Adds a guest name to the store
* @param {object} state current store state
* @param {boolean} noUpdate Only set the guest name if it was not set before
* @param {string} token the token of the conversation
* @param {string} actorId the guest
* @param {string} actorDisplayName the display name to set
*/
addGuestName(state, { noUpdate, token, actorId, actorDisplayName }) {
if (!state.guestNames[token]) {
Vue.set(state.guestNames, token, [])
}
if (!state.guestNames[token][actorId]) {
Vue.set(state.guestNames[token], actorId, t('spreed', 'Guest'))
} else if (noUpdate) {
return
}
state.guestNames[token][actorId] = actorDisplayName
},
}
const actions = {
/**
* Add guest name of a chat message to the store
*
* @param {object} context default store context
* @param {string} token the token of the conversation
* @param {string} actorId the guest
* @param {string} actorDisplayName the display name to set
*/
setGuestNameIfEmpty(context, { token, actorId, actorDisplayName }) {
context.commit('addGuestName', { noUpdate: true, token, actorId, actorDisplayName })
},
/**
* Add guest name of a chat message to the store
*
* @param {object} context default store context
* @param {string} token the token of the conversation
* @param {string} actorId the guest
* @param {string} actorDisplayName the display name to set
*/
forceGuestName(context, { token, actorId, actorDisplayName }) {
context.commit('addGuestName', { noUpdate: false, token, actorId, actorDisplayName })
},
}
export default { state, mutations, getters, actions }

Просмотреть файл

@ -24,6 +24,7 @@ import Vue from 'vue'
import Vuex, { Store } from 'vuex'
import actorStore from './actorStore'
import conversationsStore from './conversationsStore'
import guestNameStore from './guestNameStore'
import messagesStore from './messagesStore'
import participantsStore from './participantsStore'
import quoteReplyStore from './quoteReplyStore'
@ -39,6 +40,7 @@ export default new Store({
modules: {
actorStore,
conversationsStore,
guestNameStore,
messagesStore,
participantsStore,
quoteReplyStore,