mirror of
https://github.com/nextcloud/spreed.git
synced 2025-12-18 05:20:50 +01:00
Merge pull request #15307 from nextcloud/chore/noid/migrate-actor-store
chore(pinia): migrate actor store to pinia
This commit is contained in:
commit
2a4341f2b4
71 changed files with 755 additions and 631 deletions
16
src/App.vue
16
src/App.vue
|
|
@ -47,6 +47,7 @@ import Router from './router/router.ts'
|
|||
import BrowserStorage from './services/BrowserStorage.js'
|
||||
import { EventBus } from './services/EventBus.ts'
|
||||
import { leaveConversationSync } from './services/participantsService.js'
|
||||
import { useActorStore } from './stores/actor.ts'
|
||||
import { useCallViewStore } from './stores/callView.ts'
|
||||
import { useFederationStore } from './stores/federation.ts'
|
||||
import { useSidebarStore } from './stores/sidebar.ts'
|
||||
|
|
@ -80,6 +81,7 @@ export default {
|
|||
federationStore: useFederationStore(),
|
||||
callViewStore: useCallViewStore(),
|
||||
sidebarStore: useSidebarStore(),
|
||||
actorStore: useActorStore(),
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -122,7 +124,7 @@ export default {
|
|||
},
|
||||
|
||||
getUserId() {
|
||||
return this.$store.getters.getUserId()
|
||||
return this.actorStore.userId
|
||||
},
|
||||
|
||||
isSendingMessages() {
|
||||
|
|
@ -323,7 +325,7 @@ export default {
|
|||
|
||||
const payload = {
|
||||
token: params.token,
|
||||
participantIdentifier: this.$store.getters.getParticipantIdentifier(),
|
||||
participantIdentifier: this.actorStore.participantIdentifier,
|
||||
flags,
|
||||
silent: true,
|
||||
recordingConsent: this.recordingConsentGiven,
|
||||
|
|
@ -372,7 +374,7 @@ export default {
|
|||
if (!getCurrentUser()) {
|
||||
// Set the current actor/participant for guests
|
||||
const conversation = this.$store.getters.conversation(this.token)
|
||||
this.$store.dispatch('setCurrentParticipant', conversation)
|
||||
this.actorStore.setCurrentParticipant(conversation)
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -440,14 +442,6 @@ export default {
|
|||
})
|
||||
}
|
||||
})
|
||||
|
||||
if (getCurrentUser()) {
|
||||
console.debug('Setting current user')
|
||||
this.$store.dispatch('setCurrentUser', getCurrentUser())
|
||||
this.$store.dispatch('getCurrentUserTeams')
|
||||
} else {
|
||||
console.debug('Can not set current user because it\'s a guest')
|
||||
}
|
||||
},
|
||||
|
||||
async mounted() {
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ import { getFileConversation } from './services/filesIntegrationServices.js'
|
|||
import {
|
||||
leaveConversationSync,
|
||||
} from './services/participantsService.js'
|
||||
import { useActorStore } from './stores/actor.ts'
|
||||
import { checkBrowser } from './utils/browserCheck.ts'
|
||||
import CancelableRequest from './utils/cancelableRequest.js'
|
||||
import { signalingKill } from './utils/webrtc/index.js'
|
||||
|
|
@ -62,6 +63,7 @@ export default {
|
|||
setup() {
|
||||
return {
|
||||
isLeavingAfterSessionIssue: useSessionIssueHandler(),
|
||||
actorStore: useActorStore(),
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -142,7 +144,7 @@ export default {
|
|||
},
|
||||
|
||||
beforeMount() {
|
||||
this.$store.dispatch('setCurrentUser', getCurrentUser())
|
||||
this.actorStore.setCurrentUser(getCurrentUser())
|
||||
|
||||
window.addEventListener('unload', () => {
|
||||
console.info('Navigating away, leaving conversation')
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ import {
|
|||
leaveConversationSync,
|
||||
setGuestUserName,
|
||||
} from './services/participantsService.js'
|
||||
import { useActorStore } from './stores/actor.ts'
|
||||
import { signalingKill } from './utils/webrtc/index.js'
|
||||
|
||||
export default {
|
||||
|
|
@ -65,6 +66,7 @@ export default {
|
|||
|
||||
return {
|
||||
isLeavingAfterSessionIssue: useSessionIssueHandler(),
|
||||
actorStore: useActorStore(),
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -127,9 +129,9 @@ export default {
|
|||
const guestNickname = getGuestNickname()
|
||||
|
||||
if (currentUser) {
|
||||
this.$store.dispatch('setCurrentUser', currentUser)
|
||||
this.actorStore.setCurrentUser(currentUser)
|
||||
} else if (guestNickname) {
|
||||
this.$store.dispatch('setDisplayName', guestNickname)
|
||||
this.actorStore.setDisplayName(guestNickname)
|
||||
} else {
|
||||
subscribe('talk:guest-name:added', this.showGuestMediaSettings)
|
||||
}
|
||||
|
|
@ -183,12 +185,12 @@ export default {
|
|||
// Although the current participant is automatically added to
|
||||
// the participants store it must be explicitly set in the
|
||||
// actors store.
|
||||
if (!this.$store.getters.getUserId()) {
|
||||
if (!this.actorStore.userId) {
|
||||
// Set the current actor/participant for guests
|
||||
const conversation = this.$store.getters.conversation(this.token)
|
||||
|
||||
// Setting a guest only uses "sessionId" and "participantType".
|
||||
this.$store.dispatch('setCurrentParticipant', conversation)
|
||||
this.actorStore.setCurrentParticipant(conversation)
|
||||
}
|
||||
} catch (exception) {
|
||||
window.clearInterval(this.fetchCurrentConversationIntervalId)
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ import { getPublicShareConversationData } from './services/filesIntegrationServi
|
|||
import {
|
||||
leaveConversationSync,
|
||||
} from './services/participantsService.js'
|
||||
import { useActorStore } from './stores/actor.ts'
|
||||
import { checkBrowser } from './utils/browserCheck.ts'
|
||||
import { signalingKill } from './utils/webrtc/index.js'
|
||||
|
||||
|
|
@ -97,6 +98,7 @@ export default {
|
|||
return {
|
||||
isInCall: useIsInCall(),
|
||||
isLeavingAfterSessionIssue: useSessionIssueHandler(),
|
||||
actorStore: useActorStore(),
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -223,7 +225,7 @@ export default {
|
|||
// signaling server will retry the connection again and again,
|
||||
// so at some point the anonymous user will have been overriden
|
||||
// with the current user and the connection will succeed.
|
||||
this.$store.dispatch('setCurrentUser', {
|
||||
this.actorStore.setCurrentUser({
|
||||
uid: data.userId,
|
||||
displayName: data.displayName,
|
||||
})
|
||||
|
|
@ -241,12 +243,12 @@ export default {
|
|||
// Although the current participant is automatically added to
|
||||
// the participants store it must be explicitly set in the
|
||||
// actors store.
|
||||
if (!this.$store.getters.getUserId()) {
|
||||
if (!this.actorStore.userId) {
|
||||
// Set the current actor/participant for guests
|
||||
const conversation = this.$store.getters.conversation(this.token)
|
||||
|
||||
// Setting a guest only uses "sessionId" and "participantType".
|
||||
this.$store.dispatch('setCurrentParticipant', conversation)
|
||||
this.actorStore.setCurrentParticipant(conversation)
|
||||
}
|
||||
} catch (exception) {
|
||||
window.clearInterval(this.fetchCurrentConversationIntervalId)
|
||||
|
|
|
|||
|
|
@ -164,6 +164,7 @@ import LocalVideo from '../shared/LocalVideo.vue'
|
|||
import VideoBottomBar from '../shared/VideoBottomBar.vue'
|
||||
import VideoVue from '../shared/VideoVue.vue'
|
||||
import { ATTENDEE, PARTICIPANT } from '../../../constants.ts'
|
||||
import { useActorStore } from '../../../stores/actor.ts'
|
||||
import { useCallViewStore } from '../../../stores/callView.ts'
|
||||
import { placeholderImage, placeholderModel, placeholderName, placeholderSharedData } from './gridPlaceholders.ts'
|
||||
|
||||
|
|
@ -269,6 +270,7 @@ export default {
|
|||
videosCap,
|
||||
videosCapEnforced,
|
||||
callViewStore: useCallViewStore(),
|
||||
actorStore: useActorStore(),
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -502,7 +504,7 @@ export default {
|
|||
},
|
||||
|
||||
isGuestNonModerator() {
|
||||
return this.$store.getters.getActorType() === ATTENDEE.ACTOR_TYPE.GUESTS
|
||||
return this.actorStore.isActorGuest
|
||||
&& this.$store.getters.conversation(this.token).participantType !== PARTICIPANT.TYPE.GUEST_MODERATOR
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@
|
|||
<AvatarWrapper :id="userId"
|
||||
:token="token"
|
||||
:name="displayName"
|
||||
:source="actorType"
|
||||
:source="actorStore.actorType"
|
||||
:size="avatarSize"
|
||||
:loading="isNotConnected"
|
||||
disable-menu
|
||||
|
|
@ -69,6 +69,7 @@ import AccountOff from 'vue-material-design-icons/AccountOff.vue'
|
|||
import AvatarWrapper from '../../AvatarWrapper/AvatarWrapper.vue'
|
||||
import VideoBackground from './VideoBackground.vue'
|
||||
import { AVATAR } from '../../../constants.ts'
|
||||
import { useActorStore } from '../../../stores/actor.ts'
|
||||
import { useCallViewStore } from '../../../stores/callView.ts'
|
||||
import attachMediaStream from '../../../utils/attachmediastream.js'
|
||||
import { ConnectionState } from '../../../utils/webrtc/models/CallParticipantModel.js'
|
||||
|
|
@ -158,6 +159,7 @@ export default {
|
|||
devMode,
|
||||
screenshotMode,
|
||||
callViewStore: useCallViewStore(),
|
||||
actorStore: useActorStore(),
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -208,15 +210,11 @@ export default {
|
|||
},
|
||||
|
||||
userId() {
|
||||
return this.$store.getters.getUserId()
|
||||
},
|
||||
|
||||
actorType() {
|
||||
return this.$store.getters.getActorType()
|
||||
return this.actorStore.userId
|
||||
},
|
||||
|
||||
displayName() {
|
||||
return this.$store.getters.getDisplayName()
|
||||
return this.actorStore.displayName
|
||||
},
|
||||
|
||||
avatarSize() {
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import usernameToColor from '@nextcloud/vue/functions/usernameToColor'
|
|||
import Hex from 'crypto-js/enc-hex.js'
|
||||
import SHA1 from 'crypto-js/sha1.js'
|
||||
import TransitionWrapper from '../../UIShared/TransitionWrapper.vue'
|
||||
import { useActorStore } from '../../../stores/actor.ts'
|
||||
import { useGuestNameStore } from '../../../stores/guestName.js'
|
||||
|
||||
const reactions = {
|
||||
|
|
@ -86,7 +87,10 @@ export default {
|
|||
|
||||
setup() {
|
||||
const guestNameStore = useGuestNameStore()
|
||||
return { guestNameStore }
|
||||
return {
|
||||
guestNameStore,
|
||||
actorStore: useActorStore(),
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
|
|
@ -159,7 +163,7 @@ export default {
|
|||
reaction,
|
||||
reactionURL: this.getReactionURL(reaction),
|
||||
name: isLocalModel
|
||||
? this.$store.getters.getDisplayName() || t('spreed', 'Guest')
|
||||
? this.actorStore.displayName || t('spreed', 'Guest')
|
||||
: this.getParticipantName(model),
|
||||
seed: Math.random(),
|
||||
})
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import VideoOff from 'vue-material-design-icons/VideoOff.vue'
|
|||
import VideoBottomBar from './VideoBottomBar.vue'
|
||||
import { CONVERSATION, PARTICIPANT } from '../../../constants.ts'
|
||||
import storeConfig from '../../../store/storeConfig.js'
|
||||
import { useActorStore } from '../../../stores/actor.ts'
|
||||
import { useCallViewStore } from '../../../stores/callView.ts'
|
||||
import { findNcButton } from '../../../test-helpers.js'
|
||||
import { ConnectionState } from '../../../utils/webrtc/models/CallParticipantModel.js'
|
||||
|
|
@ -36,6 +37,7 @@ describe('VideoBottomBar.vue', () => {
|
|||
let testStoreConfig
|
||||
let componentProps
|
||||
let conversationProps
|
||||
let actorStore
|
||||
|
||||
const audioIndicatorAriaLabels = [t('spreed', 'Mute'), t('spreed', 'Muted')]
|
||||
const videoIndicatorAriaLabels = [t('spreed', 'Disable video'), t('spreed', 'Enable video')]
|
||||
|
|
@ -47,6 +49,7 @@ describe('VideoBottomBar.vue', () => {
|
|||
localVue.use(Vuex)
|
||||
setActivePinia(createPinia())
|
||||
callViewStore = useCallViewStore()
|
||||
actorStore = useActorStore()
|
||||
|
||||
conversationProps = {
|
||||
token: TOKEN,
|
||||
|
|
@ -83,7 +86,7 @@ describe('VideoBottomBar.vue', () => {
|
|||
|
||||
testStoreConfig = cloneDeep(storeConfig)
|
||||
testStoreConfig.modules.conversationsStore.getters.conversation = jest.fn().mockReturnValue((token) => conversationProps)
|
||||
testStoreConfig.modules.actorStore.getters.getUserId = jest.fn().mockReturnValue(() => USER_ID)
|
||||
actorStore.userId = USER_ID
|
||||
store = new Store(testStoreConfig)
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ import VideoIcon from 'vue-material-design-icons/Video.vue'
|
|||
import VideoOff from 'vue-material-design-icons/VideoOff.vue'
|
||||
import TransitionWrapper from '../../UIShared/TransitionWrapper.vue'
|
||||
import { PARTICIPANT } from '../../../constants.ts'
|
||||
import { useActorStore } from '../../../stores/actor.ts'
|
||||
import { useCallViewStore } from '../../../stores/callView.ts'
|
||||
import { ConnectionState } from '../../../utils/webrtc/models/CallParticipantModel.js'
|
||||
|
||||
|
|
@ -186,6 +187,7 @@ export default {
|
|||
setup() {
|
||||
return {
|
||||
callViewStore: useCallViewStore(),
|
||||
actorStore: useActorStore(),
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -265,7 +267,7 @@ export default {
|
|||
// Moderator rights
|
||||
participantType() {
|
||||
return this.$store.getters.conversation(this.token)?.participantType
|
||||
|| (this.$store.getters.getUserId() !== null
|
||||
|| (this.actorStore.isLoggedIn
|
||||
? PARTICIPANT.TYPE.USER
|
||||
: PARTICIPANT.TYPE.GUEST)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ import TransitionWrapper from './UIShared/TransitionWrapper.vue'
|
|||
import { CONVERSATION, PARTICIPANT } from '../constants.ts'
|
||||
import { getTalkConfig } from '../services/CapabilitiesManager.ts'
|
||||
import { EventBus } from '../services/EventBus.ts'
|
||||
import { useActorStore } from '../stores/actor.ts'
|
||||
import { useChatExtrasStore } from '../stores/chatExtras.js'
|
||||
|
||||
export default {
|
||||
|
|
@ -108,6 +109,7 @@ export default {
|
|||
provide('chatView:isSidebar', props.isSidebar)
|
||||
return {
|
||||
chatExtrasStore: useChatExtrasStore(),
|
||||
actorStore: useActorStore(),
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -120,16 +122,15 @@ export default {
|
|||
|
||||
computed: {
|
||||
isGuest() {
|
||||
return this.$store.getters.isActorGuest()
|
||||
return this.actorStore.isActorGuest
|
||||
},
|
||||
|
||||
isGuestWithoutDisplayName() {
|
||||
const userName = this.$store.getters.getDisplayName()
|
||||
return !userName && this.isGuest
|
||||
return this.isGuest && !this.actorStore.displayName
|
||||
},
|
||||
|
||||
canUploadFiles() {
|
||||
return getTalkConfig(this.token, 'attachments', 'allowed') && this.$store.getters.getUserId()
|
||||
return getTalkConfig(this.token, 'attachments', 'allowed') && this.actorStore.userId
|
||||
&& this.$store.getters.getAttachmentFolderFreeSpace() !== 0
|
||||
&& (this.conversation.permissions & PARTICIPANT.PERMISSIONS.CHAT)
|
||||
&& !this.conversation.remoteServer // no attachments support in federated conversations
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@ import RecordingConsentSettings from './RecordingConsentSettings.vue'
|
|||
import SipSettings from './SipSettings.vue'
|
||||
import { CALL, CONFIG, CONVERSATION, PARTICIPANT } from '../../constants.ts'
|
||||
import { getTalkConfig, hasTalkFeature } from '../../services/CapabilitiesManager.ts'
|
||||
import { useActorStore } from '../../stores/actor.ts'
|
||||
import { useSettingsStore } from '../../stores/settings.js'
|
||||
|
||||
const matterbridgeEnabled = loadState('spreed', 'enable_matterbridge')
|
||||
|
|
@ -174,6 +175,7 @@ export default {
|
|||
settingsStore,
|
||||
token,
|
||||
meetingHeader,
|
||||
actorStore: useActorStore(),
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -195,7 +197,7 @@ export default {
|
|||
},
|
||||
|
||||
isGuest() {
|
||||
return this.$store.getters.isActorGuest()
|
||||
return this.actorStore.isActorGuest
|
||||
},
|
||||
|
||||
showSettings() {
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import { useStore } from '../../composables/useStore.js'
|
|||
import { CONVERSATION } from '../../constants.ts'
|
||||
import { getTalkConfig, hasTalkFeature } from '../../services/CapabilitiesManager.ts'
|
||||
import { EventBus } from '../../services/EventBus.ts'
|
||||
import { useActorStore } from '../../stores/actor.ts'
|
||||
import { useDashboardStore } from '../../stores/dashboard.ts'
|
||||
import { hasUnreadMentions } from '../../utils/conversation.ts'
|
||||
import { copyConversationLinkToClipboard } from '../../utils/handleUrl.ts'
|
||||
|
|
@ -46,6 +47,7 @@ const isDirectionRTL = isRTL()
|
|||
const store = useStore()
|
||||
const router = useRouter()
|
||||
const dashboardStore = useDashboardStore()
|
||||
const actorStore = useActorStore()
|
||||
const forwardScrollable = ref(false)
|
||||
const backwardScrollable = ref(false)
|
||||
const eventCardsWrapper = ref<HTMLDivElement | null>(null)
|
||||
|
|
@ -166,7 +168,7 @@ function scrollEventCards({ direction }: { direction: 'backward' | 'forward' })
|
|||
<template>
|
||||
<div class="talk-dashboard-wrapper">
|
||||
<h2 class="talk-dashboard__header">
|
||||
{{ t('spreed', 'Hello, {displayName}', { displayName: store.getters.getDisplayName() }, { escape: false }) }}
|
||||
{{ t('spreed', 'Hello, {displayName}', { displayName: actorStore.displayName }, { escape: false }) }}
|
||||
</h2>
|
||||
<div class="talk-dashboard__actions">
|
||||
<NcPopover v-if="canStartConversations"
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ import { callSIPDialOut } from '../../../services/callsService.js'
|
|||
import { hasTalkFeature } from '../../../services/CapabilitiesManager.ts'
|
||||
import { createLegacyConversation } from '../../../services/conversationsService.ts'
|
||||
import { addParticipant } from '../../../services/participantsService.js'
|
||||
import { useActorStore } from '../../../stores/actor.ts'
|
||||
|
||||
export default {
|
||||
name: 'CallPhoneDialog',
|
||||
|
|
@ -71,6 +72,12 @@ export default {
|
|||
|
||||
expose: ['showModal'],
|
||||
|
||||
setup() {
|
||||
return {
|
||||
actorStore: useActorStore(),
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
modal: false,
|
||||
|
|
@ -156,7 +163,7 @@ export default {
|
|||
console.info('Joining call')
|
||||
await this.$store.dispatch('joinCall', {
|
||||
token,
|
||||
participantIdentifier: this.$store.getters.getParticipantIdentifier(),
|
||||
participantIdentifier: this.actorStore.participantIdentifier,
|
||||
flags,
|
||||
silent: false,
|
||||
recordingConsent: true,
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import { searchListedConversations } from '../../services/conversationsService.t
|
|||
import { autocompleteQuery } from '../../services/coreService.ts'
|
||||
import { EventBus } from '../../services/EventBus.ts'
|
||||
import storeConfig from '../../store/storeConfig.js'
|
||||
import { useActorStore } from '../../stores/actor.ts'
|
||||
import { findNcActionButton, findNcButton } from '../../test-helpers.js'
|
||||
import { requestTabLeadership } from '../../utils/requestTabLeadership.js'
|
||||
|
||||
|
|
@ -90,6 +91,7 @@ describe('LeftSidebar.vue', () => {
|
|||
localVue.use(Vuex)
|
||||
localVue.use(VueRouter)
|
||||
setActivePinia(createPinia())
|
||||
const actorStore = useActorStore()
|
||||
|
||||
loadStateSettings = {
|
||||
circles_enabled: true,
|
||||
|
|
@ -109,8 +111,7 @@ describe('LeftSidebar.vue', () => {
|
|||
fetchConversationsAction = jest.fn().mockReturnValue({ headers: {} })
|
||||
addConversationAction = jest.fn()
|
||||
createOneToOneConversationAction = jest.fn()
|
||||
const getUserIdMock = jest.fn().mockReturnValue('current-user')
|
||||
testStoreConfig.modules.actorStore.getters.getUserId = () => getUserIdMock
|
||||
actorStore.userId = 'current-user'
|
||||
testStoreConfig.modules.conversationsStore.getters.conversationsList = conversationsListMock
|
||||
testStoreConfig.modules.conversationsStore.actions.fetchConversations = fetchConversationsAction
|
||||
testStoreConfig.modules.conversationsStore.actions.addConversation = addConversationAction
|
||||
|
|
|
|||
|
|
@ -302,6 +302,7 @@ import {
|
|||
import { autocompleteQuery } from '../../services/coreService.ts'
|
||||
import { EventBus } from '../../services/EventBus.ts'
|
||||
import { talkBroadcastChannel } from '../../services/talkBroadcastChannel.js'
|
||||
import { useActorStore } from '../../stores/actor.ts'
|
||||
import { useFederationStore } from '../../stores/federation.ts'
|
||||
import { useSettingsStore } from '../../stores/settings.js'
|
||||
import { useTalkHashStore } from '../../stores/talkHash.js'
|
||||
|
|
@ -393,6 +394,7 @@ export default {
|
|||
showArchived,
|
||||
settingsStore,
|
||||
FILTER_LABELS,
|
||||
actorStore: useActorStore(),
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -680,7 +682,7 @@ export default {
|
|||
acc.push(result.name)
|
||||
}
|
||||
return acc
|
||||
}, [this.$store.getters.getUserId()])
|
||||
}, [this.actorStore.userId])
|
||||
|
||||
this.searchResults = response?.data?.ocs?.data.filter((match) => {
|
||||
return !(match.source === ATTENDEE.ACTOR_TYPE.USERS && oneToOneMap.includes(match.id))
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ import NcRichText from '@nextcloud/vue/components/NcRichText'
|
|||
import RoomService from 'vue-material-design-icons/RoomService.vue'
|
||||
import GuestWelcomeWindow from './GuestWelcomeWindow.vue'
|
||||
import SetGuestUsername from './SetGuestUsername.vue'
|
||||
import { useActorStore } from '../stores/actor.ts'
|
||||
import { futureRelativeTime, ONE_DAY_IN_MS } from '../utils/formattedTime.ts'
|
||||
|
||||
export default {
|
||||
|
|
@ -55,6 +56,12 @@ export default {
|
|||
SetGuestUsername,
|
||||
},
|
||||
|
||||
setup() {
|
||||
return {
|
||||
actorStore: useActorStore(),
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
|
||||
token() {
|
||||
|
|
@ -94,12 +101,11 @@ export default {
|
|||
|
||||
// Determines whether the current user is a guest user
|
||||
currentUserIsGuest() {
|
||||
return !this.$store.getters.getUserId()
|
||||
return !this.actorStore.userId
|
||||
},
|
||||
|
||||
isGuestWithoutDisplayName() {
|
||||
const userName = this.$store.getters.getDisplayName()
|
||||
return !userName && this.currentUserIsGuest
|
||||
return !this.actorStore.displayName && this.currentUserIsGuest
|
||||
},
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
<AvatarWrapper :id="userId"
|
||||
:token="token"
|
||||
:name="displayName"
|
||||
:source="actorType"
|
||||
:source="actorStore.actorType"
|
||||
:size="AVATAR.SIZE.EXTRA_LARGE"
|
||||
disable-menu
|
||||
disable-tooltip />
|
||||
|
|
@ -231,6 +231,7 @@ import { useIsInCall } from '../../composables/useIsInCall.js'
|
|||
import { AVATAR, CALL, CONFIG, PARTICIPANT, VIRTUAL_BACKGROUND } from '../../constants.ts'
|
||||
import BrowserStorage from '../../services/BrowserStorage.js'
|
||||
import { getTalkConfig } from '../../services/CapabilitiesManager.ts'
|
||||
import { useActorStore } from '../../stores/actor.ts'
|
||||
import { useGuestNameStore } from '../../stores/guestName.js'
|
||||
import { useSettingsStore } from '../../stores/settings.js'
|
||||
import { localMediaModel } from '../../utils/webrtc/index.js'
|
||||
|
|
@ -337,6 +338,7 @@ export default {
|
|||
dialogHeaderId,
|
||||
supportStartWithoutMedia,
|
||||
supportDefaultBlurVirtualBackground,
|
||||
actorStore: useActorStore(),
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -361,22 +363,18 @@ export default {
|
|||
|
||||
computed: {
|
||||
displayName() {
|
||||
return this.$store.getters.getDisplayName()
|
||||
return this.actorStore.displayName
|
||||
},
|
||||
|
||||
guestName() {
|
||||
return this.guestNameStore.getGuestName(
|
||||
this.$store.getters.getToken(),
|
||||
this.$store.getters.getActorId(),
|
||||
this.actorStore.actorId,
|
||||
)
|
||||
},
|
||||
|
||||
userId() {
|
||||
return this.$store.getters.getUserId()
|
||||
},
|
||||
|
||||
actorType() {
|
||||
return this.$store.getters.getActorType()
|
||||
return this.actorStore.userId
|
||||
},
|
||||
|
||||
token() {
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ import { VIRTUAL_BACKGROUND } from '../../constants.ts'
|
|||
import BrowserStorage from '../../services/BrowserStorage.js'
|
||||
import { getTalkConfig } from '../../services/CapabilitiesManager.ts'
|
||||
import { getDavClient } from '../../services/DavClient.js'
|
||||
import { useActorStore } from '../../stores/actor.ts'
|
||||
import { useSettingsStore } from '../../stores/settings.js'
|
||||
import { findUniquePath } from '../../utils/fileUpload.js'
|
||||
|
||||
|
|
@ -131,6 +132,7 @@ export default {
|
|||
predefinedBackgrounds: getTalkConfig('local', 'call', 'predefined-backgrounds'),
|
||||
predefinedBackgroundsV2: getTalkConfig('local', 'call', 'predefined-backgrounds-v2'),
|
||||
settingsStore: useSettingsStore(),
|
||||
actorStore: useActorStore(),
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -174,12 +176,12 @@ export default {
|
|||
async mounted() {
|
||||
this.loadBackground()
|
||||
|
||||
if (this.$store.getters.getUserId() === null) {
|
||||
if (this.actorStore.userId === null) {
|
||||
console.debug('Skip Talk backgrounds folder check and setup for participants that are not logged in')
|
||||
return
|
||||
}
|
||||
|
||||
const userRoot = '/files/' + this.$store.getters.getUserId()
|
||||
const userRoot = '/files/' + this.actorStore.userId
|
||||
const absoluteBackgroundsFolderPath = userRoot + this.relativeBackgroundsFolderPath
|
||||
|
||||
try {
|
||||
|
|
@ -216,7 +218,7 @@ export default {
|
|||
event.target.value = ''
|
||||
|
||||
// userRoot path
|
||||
const userRoot = '/files/' + this.$store.getters.getUserId()
|
||||
const userRoot = '/files/' + this.actorStore.userId
|
||||
|
||||
const filePath = this.$store.getters.getAttachmentFolder() + '/Backgrounds/' + file.name
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import * as useIsInCallModule from '../../../../composables/useIsInCall.js'
|
|||
import { ATTENDEE, CONVERSATION, MESSAGE, PARTICIPANT } from '../../../../constants.ts'
|
||||
import { EventBus } from '../../../../services/EventBus.ts'
|
||||
import storeConfig from '../../../../store/storeConfig.js'
|
||||
import { useActorStore } from '../../../../stores/actor.ts'
|
||||
|
||||
// needed because of https://github.com/vuejs/vue-test-utils/issues/1507
|
||||
const RichTextStub = {
|
||||
|
|
@ -45,13 +46,13 @@ describe('Message.vue', () => {
|
|||
let messageProps
|
||||
let conversationProps
|
||||
let injected
|
||||
let getActorTypeMock
|
||||
const getVisualLastReadMessageIdMock = jest.fn()
|
||||
|
||||
beforeEach(() => {
|
||||
localVue = createLocalVue()
|
||||
localVue.use(Vuex)
|
||||
setActivePinia(createPinia())
|
||||
const actorStore = useActorStore()
|
||||
|
||||
conversationProps = {
|
||||
token: TOKEN,
|
||||
|
|
@ -65,17 +66,15 @@ describe('Message.vue', () => {
|
|||
getMessagesListScroller: jest.fn(),
|
||||
}
|
||||
|
||||
actorStore.actorId = 'user-id-1'
|
||||
actorStore.actorType = ATTENDEE.ACTOR_TYPE.USERS
|
||||
testStoreConfig = cloneDeep(storeConfig)
|
||||
testStoreConfig.modules.tokenStore.getters.getToken
|
||||
= jest.fn().mockReturnValue(() => TOKEN)
|
||||
testStoreConfig.modules.conversationsStore.getters.conversation
|
||||
= jest.fn().mockReturnValue((token) => conversationProps)
|
||||
testStoreConfig.modules.actorStore.getters.getActorId
|
||||
= jest.fn().mockReturnValue(() => 'user-id-1')
|
||||
testStoreConfig.modules.messagesStore.getters.getVisualLastReadMessageId
|
||||
= jest.fn().mockReturnValue(getVisualLastReadMessageIdMock)
|
||||
getActorTypeMock = jest.fn().mockReturnValue(() => ATTENDEE.ACTOR_TYPE.USERS)
|
||||
testStoreConfig.modules.actorStore.getters.getActorType = getActorTypeMock
|
||||
|
||||
messageProps = {
|
||||
message: {
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ import Reactions from './MessagePart/Reactions.vue'
|
|||
import { CONVERSATION, MENTION, MESSAGE, PARTICIPANT } from '../../../../constants.ts'
|
||||
import { getTalkConfig, hasTalkFeature } from '../../../../services/CapabilitiesManager.ts'
|
||||
import { EventBus } from '../../../../services/EventBus.ts'
|
||||
import { useActorStore } from '../../../../stores/actor.ts'
|
||||
import { useChatExtrasStore } from '../../../../stores/chatExtras.js'
|
||||
import { getItemTypeFromMessage } from '../../../../utils/getItemTypeFromMessage.ts'
|
||||
|
||||
|
|
@ -204,6 +205,7 @@ export default {
|
|||
return {
|
||||
isTranslationAvailable,
|
||||
chatExtrasStore: useChatExtrasStore(),
|
||||
actorStore: useActorStore(),
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -279,8 +281,7 @@ export default {
|
|||
return !this.isSystemMessage
|
||||
&& !this.isTemporary
|
||||
&& !this.isDeleting
|
||||
&& this.message.actorType === this.$store.getters.getActorType()
|
||||
&& this.message.actorId === this.$store.getters.getActorId()
|
||||
&& this.actorStore.checkIfSelfIsActor(this.message)
|
||||
&& !this.isDeletedMessage
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import MessageButtonsBar from './../MessageButtonsBar/MessageButtonsBar.vue'
|
|||
import * as useMessageInfoModule from '../../../../../composables/useMessageInfo.js'
|
||||
import { ATTENDEE, CONVERSATION, MESSAGE, PARTICIPANT } from '../../../../../constants.ts'
|
||||
import storeConfig from '../../../../../store/storeConfig.js'
|
||||
import { useActorStore } from '../../../../../stores/actor.ts'
|
||||
import { useIntegrationsStore } from '../../../../../stores/integrations.js'
|
||||
import { findNcActionButton, findNcButton } from '../../../../../test-helpers.js'
|
||||
|
||||
|
|
@ -24,14 +25,13 @@ describe('MessageButtonsBar.vue', () => {
|
|||
let messageProps
|
||||
let injected
|
||||
let conversationProps
|
||||
let getActorTypeMock
|
||||
let isActorUserMock
|
||||
let isActorGuestMock
|
||||
let actorStore
|
||||
|
||||
beforeEach(() => {
|
||||
localVue = createLocalVue()
|
||||
localVue.use(Vuex)
|
||||
setActivePinia(createPinia())
|
||||
actorStore = useActorStore()
|
||||
|
||||
conversationProps = {
|
||||
token: TOKEN,
|
||||
|
|
@ -46,14 +46,8 @@ describe('MessageButtonsBar.vue', () => {
|
|||
= jest.fn().mockReturnValue(() => TOKEN)
|
||||
testStoreConfig.modules.conversationsStore.getters.conversation
|
||||
= jest.fn().mockReturnValue((token) => conversationProps)
|
||||
testStoreConfig.modules.actorStore.getters.getActorId
|
||||
= jest.fn().mockReturnValue(() => 'user-id-1')
|
||||
getActorTypeMock = jest.fn().mockReturnValue(() => ATTENDEE.ACTOR_TYPE.USERS)
|
||||
isActorUserMock = jest.fn().mockReturnValue(() => true)
|
||||
isActorGuestMock = jest.fn().mockReturnValue(() => false)
|
||||
testStoreConfig.modules.actorStore.getters.getActorType = getActorTypeMock
|
||||
testStoreConfig.modules.actorStore.getters.isActorUser = isActorUserMock
|
||||
testStoreConfig.modules.actorStore.getters.isActorGuest = isActorGuestMock
|
||||
actorStore.actorType = ATTENDEE.ACTOR_TYPE.USERS
|
||||
actorStore.actorId = 'user-id-1'
|
||||
|
||||
messageProps = {
|
||||
previousMessageId: 100,
|
||||
|
|
@ -254,9 +248,7 @@ describe('MessageButtonsBar.vue', () => {
|
|||
|
||||
test('hides private reply action when current user is a guest', async () => {
|
||||
messageProps.message.actorId = 'another-user'
|
||||
getActorTypeMock.mockClear().mockReturnValue(() => ATTENDEE.ACTOR_TYPE.GUESTS)
|
||||
isActorUserMock.mockClear().mockReturnValue(() => false)
|
||||
isActorGuestMock.mockClear().mockReturnValue(() => true)
|
||||
actorStore.actorType = ATTENDEE.ACTOR_TYPE.GUESTS
|
||||
testPrivateReplyActionVisible(false)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -302,6 +302,7 @@ import { useMessageInfo } from '../../../../../composables/useMessageInfo.js'
|
|||
import { ATTENDEE, CONVERSATION, MESSAGE, PARTICIPANT } from '../../../../../constants.ts'
|
||||
import { hasTalkFeature } from '../../../../../services/CapabilitiesManager.ts'
|
||||
import { getMessageReminder, removeMessageReminder, setMessageReminder } from '../../../../../services/remindersService.js'
|
||||
import { useActorStore } from '../../../../../stores/actor.ts'
|
||||
import { useIntegrationsStore } from '../../../../../stores/integrations.js'
|
||||
import { useReactionsStore } from '../../../../../stores/reactions.js'
|
||||
import { generatePublicShareDownloadUrl, generateUserFileUrl } from '../../../../../utils/davUtils.ts'
|
||||
|
|
@ -406,6 +407,7 @@ export default {
|
|||
const { message } = toRefs(props)
|
||||
const reactionsStore = useReactionsStore()
|
||||
const { messageActions } = useIntegrationsStore()
|
||||
const actorStore = useActorStore()
|
||||
const {
|
||||
isEditable,
|
||||
isDeleteable,
|
||||
|
|
@ -430,6 +432,7 @@ export default {
|
|||
isDeleteable,
|
||||
isConversationReadOnly,
|
||||
isConversationModifiable,
|
||||
actorStore,
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -457,7 +460,7 @@ export default {
|
|||
|| this.conversation.type === CONVERSATION.TYPE.GROUP)
|
||||
&& !this.isCurrentUserOwnMessage
|
||||
&& this.message.actorType === ATTENDEE.ACTOR_TYPE.USERS
|
||||
&& this.$store.getters.isActorUser()
|
||||
&& !this.isCurrentGuest
|
||||
},
|
||||
|
||||
messageFile() {
|
||||
|
|
@ -472,7 +475,7 @@ export default {
|
|||
},
|
||||
|
||||
isCurrentGuest() {
|
||||
return this.$store.getters.isActorGuest()
|
||||
return this.actorStore.isActorGuest
|
||||
},
|
||||
|
||||
isDeletedMessage() {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import { t } from '@nextcloud/l10n'
|
|||
import { encodePath } from '@nextcloud/paths'
|
||||
import { generateRemoteUrl } from '@nextcloud/router'
|
||||
import { EventBus } from '../../../../../services/EventBus.ts'
|
||||
import { useActorStore } from '../../../../../stores/actor.ts'
|
||||
|
||||
export default {
|
||||
name: 'AudioPlayer',
|
||||
|
|
@ -67,6 +68,12 @@ export default {
|
|||
},
|
||||
},
|
||||
|
||||
setup() {
|
||||
return {
|
||||
actorStore: useActorStore(),
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
internalAbsolutePath() {
|
||||
if (this.path.startsWith('/')) {
|
||||
|
|
@ -79,7 +86,7 @@ export default {
|
|||
if (this.localUrl) {
|
||||
return this.localUrl
|
||||
}
|
||||
const userId = this.$store.getters.getUserId()
|
||||
const userId = this.actorStore.userId
|
||||
if (userId === null) {
|
||||
// guest mode, use public link download URL
|
||||
return this.link + '/download/' + encodePath(this.name)
|
||||
|
|
|
|||
|
|
@ -12,27 +12,29 @@ import NcButton from '@nextcloud/vue/components/NcButton'
|
|||
import PlayCircleOutline from 'vue-material-design-icons/PlayCircleOutline.vue'
|
||||
import FilePreview from './FilePreview.vue'
|
||||
import storeConfig from '../../../../../store/storeConfig.js'
|
||||
import { useActorStore } from '../../../../../stores/actor.ts'
|
||||
|
||||
describe('FilePreview.vue', () => {
|
||||
let store
|
||||
let localVue
|
||||
let testStoreConfig
|
||||
let propsData
|
||||
let getUserIdMock
|
||||
let oldPixelRatio
|
||||
let actorStore
|
||||
|
||||
beforeEach(() => {
|
||||
localVue = createLocalVue()
|
||||
localVue.use(Vuex)
|
||||
setActivePinia(createPinia())
|
||||
actorStore = useActorStore()
|
||||
|
||||
oldPixelRatio = window.devicePixelRatio
|
||||
|
||||
testStoreConfig = cloneDeep(storeConfig)
|
||||
getUserIdMock = jest.fn().mockReturnValue('current-user-id')
|
||||
testStoreConfig.modules.actorStore.getters.getUserId = () => getUserIdMock
|
||||
store = new Vuex.Store(testStoreConfig)
|
||||
|
||||
actorStore.userId = 'current-user-id'
|
||||
|
||||
propsData = {
|
||||
token: 'TOKEN',
|
||||
file: {
|
||||
|
|
@ -83,7 +85,7 @@ describe('FilePreview.vue', () => {
|
|||
|
||||
test('renders file preview for guests', async () => {
|
||||
propsData.file.link = 'https://localhost/nc-webroot/s/xtokenx'
|
||||
getUserIdMock.mockClear().mockReturnValue(null)
|
||||
actorStore.userId = null
|
||||
|
||||
const wrapper = shallowMount(FilePreview, {
|
||||
localVue,
|
||||
|
|
@ -270,7 +272,7 @@ describe('FilePreview.vue', () => {
|
|||
test('directly renders small GIF files for guests', async () => {
|
||||
propsData.file.size = '128'
|
||||
propsData.file.link = 'https://localhost/nc-webroot/s/xtokenx'
|
||||
getUserIdMock.mockClear().mockReturnValue(null)
|
||||
actorStore.userId = null
|
||||
|
||||
const wrapper = shallowMount(FilePreview, {
|
||||
localVue,
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ import AudioPlayer from './AudioPlayer.vue'
|
|||
import { useViewer } from '../../../../../composables/useViewer.js'
|
||||
import { SHARED_ITEM } from '../../../../../constants.ts'
|
||||
import { getTalkConfig } from '../../../../../services/CapabilitiesManager.ts'
|
||||
import { useActorStore } from '../../../../../stores/actor.ts'
|
||||
import { useSharedItemsStore } from '../../../../../stores/sharedItems.js'
|
||||
|
||||
const PREVIEW_TYPE = {
|
||||
|
|
@ -176,6 +177,7 @@ export default {
|
|||
return {
|
||||
openViewer,
|
||||
sharedItemsStore,
|
||||
actorStore: useActorStore(),
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -324,7 +326,7 @@ export default {
|
|||
},
|
||||
|
||||
previewUrl() {
|
||||
const userId = this.$store.getters.getUserId()
|
||||
const userId = this.actorStore.userId
|
||||
|
||||
if (this.previewType === PREVIEW_TYPE.TEMPORARY) {
|
||||
return this.file.localUrl
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import { useIsDarkTheme } from '@nextcloud/vue/composables/useIsDarkTheme'
|
|||
import NcUserBubble from '@nextcloud/vue/components/NcUserBubble'
|
||||
import { MENTION } from '../../../../../constants.ts'
|
||||
import { getConversationAvatarOcsUrl, getUserProxyAvatarOcsUrl } from '../../../../../services/avatarService.ts'
|
||||
import { useActorStore } from '../../../../../stores/actor.ts'
|
||||
|
||||
export default {
|
||||
name: 'Mention',
|
||||
|
|
@ -60,6 +61,7 @@ export default {
|
|||
|
||||
return {
|
||||
isDarkTheme,
|
||||
actorStore: useActorStore(),
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -97,9 +99,9 @@ export default {
|
|||
// 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 === this.$store.getters.getActorId())
|
||||
return this.actorStore.isActorGuest
|
||||
&& (this.id === ('guest/' + this.actorStore.actorId)
|
||||
|| this.id === this.actorStore.actorId)
|
||||
},
|
||||
|
||||
isCurrentUser() {
|
||||
|
|
@ -108,16 +110,16 @@ export default {
|
|||
return false
|
||||
}
|
||||
|
||||
return this.$store.getters.isActorUser()
|
||||
&& this.id === this.$store.getters.getUserId()
|
||||
return this.actorStore.isActorUser
|
||||
&& this.id === this.actorStore.userId
|
||||
},
|
||||
|
||||
isCurrentUserGroup() {
|
||||
return this.isGroupMention && this.$store.getters.isActorMemberOfGroup(this.id)
|
||||
return this.isGroupMention && this.actorStore.isActorMemberOfGroup(this.id)
|
||||
},
|
||||
|
||||
isCurrentUserTeam() {
|
||||
return this.isTeamMention && this.$store.getters.isActorMemberOfTeam(this.id)
|
||||
return this.isTeamMention && this.actorStore.isActorMemberOfTeam(this.id)
|
||||
},
|
||||
|
||||
primary() {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import {
|
|||
} from '../../../../../services/reactionsService.ts'
|
||||
import vuexStore from '../../../../../store/index.js'
|
||||
import storeConfig from '../../../../../store/storeConfig.js'
|
||||
import { useActorStore } from '../../../../../stores/actor.ts'
|
||||
import { useReactionsStore } from '../../../../../stores/reactions.js'
|
||||
import { generateOCSResponse } from '../../../../../test-helpers.js'
|
||||
|
||||
|
|
@ -41,8 +42,6 @@ describe('Reactions.vue', () => {
|
|||
let store
|
||||
let localVue
|
||||
let messageMock
|
||||
let getActorTypeMock
|
||||
let getActorIdMock
|
||||
let reactionsStored
|
||||
let message
|
||||
|
||||
|
|
@ -51,6 +50,7 @@ describe('Reactions.vue', () => {
|
|||
reactionsStore = useReactionsStore()
|
||||
localVue = createLocalVue()
|
||||
localVue.use(Vuex)
|
||||
const actorStore = useActorStore()
|
||||
|
||||
testStoreConfig = cloneDeep(storeConfig)
|
||||
token = 'token1'
|
||||
|
|
@ -69,11 +69,8 @@ describe('Reactions.vue', () => {
|
|||
messageMock = jest.fn().mockReturnValue(message)
|
||||
testStoreConfig.modules.messagesStore.getters.message = () => messageMock
|
||||
|
||||
getActorTypeMock = jest.fn().mockReturnValue(() => ATTENDEE.ACTOR_TYPE.USERS)
|
||||
testStoreConfig.modules.actorStore.getters.getActorType = getActorTypeMock
|
||||
|
||||
getActorIdMock = jest.fn().mockReturnValue('admin')
|
||||
testStoreConfig.modules.actorStore.getters.getActorId = () => getActorIdMock
|
||||
actorStore.actorId = 'admin'
|
||||
actorStore.actorType = ATTENDEE.ACTOR_TYPE.USERS
|
||||
|
||||
store = new Vuex.Store(testStoreConfig)
|
||||
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ import EmoticonPlusOutline from 'vue-material-design-icons/EmoticonPlusOutline.v
|
|||
import HeartOutlineIcon from 'vue-material-design-icons/HeartOutline.vue'
|
||||
import ReactionsList from './ReactionsList.vue'
|
||||
import { ATTENDEE } from '../../../../../constants.ts'
|
||||
import { useActorStore } from '../../../../../stores/actor.ts'
|
||||
import { useGuestNameStore } from '../../../../../stores/guestName.js'
|
||||
import { useReactionsStore } from '../../../../../stores/reactions.js'
|
||||
import { getDisplayNameWithFallback } from '../../../../../utils/getDisplayName.ts'
|
||||
|
|
@ -134,11 +135,10 @@ export default {
|
|||
emits: ['emoji-picker-toggled'],
|
||||
|
||||
setup() {
|
||||
const guestNameStore = useGuestNameStore()
|
||||
const reactionsStore = useReactionsStore()
|
||||
return {
|
||||
guestNameStore,
|
||||
reactionsStore,
|
||||
guestNameStore: useGuestNameStore(),
|
||||
reactionsStore: useReactionsStore(),
|
||||
actorStore: useActorStore(),
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -249,8 +249,7 @@ export default {
|
|||
const summary = []
|
||||
|
||||
for (const item in list) {
|
||||
if (list[item].actorType === this.$store.getters.getActorType()
|
||||
&& list[item].actorId === this.$store.getters.getActorId()) {
|
||||
if (this.actorStore.checkIfSelfIsActor(list[item])) {
|
||||
summary.unshift(t('spreed', 'You'))
|
||||
} else {
|
||||
summary.push(this.getDisplayNameForReaction(list[item]))
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import Vuex from 'vuex'
|
|||
import MessagesGroup from './MessagesGroup.vue'
|
||||
import { ATTENDEE, MESSAGE } from '../../../constants.ts'
|
||||
import storeConfig from '../../../store/storeConfig.js'
|
||||
import { useActorStore } from '../../../stores/actor.ts'
|
||||
import { useGuestNameStore } from '../../../stores/guestName.js'
|
||||
|
||||
describe('MessagesGroup.vue', () => {
|
||||
|
|
@ -23,11 +24,12 @@ describe('MessagesGroup.vue', () => {
|
|||
localVue.use(Vuex)
|
||||
setActivePinia(createPinia())
|
||||
guestNameStore = useGuestNameStore()
|
||||
const actorStore = useActorStore()
|
||||
|
||||
testStoreConfig = cloneDeep(storeConfig)
|
||||
testStoreConfig.modules.conversationsStore.getters.conversation = () => () => ({})
|
||||
testStoreConfig.modules.actorStore.getters.getActorId = () => () => 'actor-1'
|
||||
testStoreConfig.modules.actorStore.getters.getActorType = () => () => ATTENDEE.ACTOR_TYPE.USERS
|
||||
actorStore.actorId = 'actor-1'
|
||||
actorStore.actorType = ATTENDEE.ACTOR_TYPE.USERS
|
||||
store = new Vuex.Store(testStoreConfig)
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import AvatarWrapper from '../../AvatarWrapper/AvatarWrapper.vue'
|
|||
import Message from './Message/Message.vue'
|
||||
import { useMessageInfo } from '../../../composables/useMessageInfo.js'
|
||||
import { ATTENDEE, AVATAR } from '../../../constants.ts'
|
||||
import { useActorStore } from '../../../stores/actor.ts'
|
||||
import { useGuestNameStore } from '../../../stores/guestName.js'
|
||||
|
||||
export default {
|
||||
|
|
@ -92,6 +93,7 @@ export default {
|
|||
return {
|
||||
AVATAR,
|
||||
guestNameStore: useGuestNameStore(),
|
||||
actorStore: useActorStore(),
|
||||
actorDisplayName,
|
||||
actorInfo,
|
||||
}
|
||||
|
|
@ -109,7 +111,7 @@ export default {
|
|||
disableMenu() {
|
||||
// disable the menu if accessing the conversation as guest
|
||||
// or the message sender is a bridged user
|
||||
return this.$store.getters.isActorGuest() || this.actorType === ATTENDEE.ACTOR_TYPE.BRIDGED
|
||||
return this.actorStore.isActorGuest || this.actorType === ATTENDEE.ACTOR_TYPE.BRIDGED
|
||||
},
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -200,6 +200,7 @@ import BrowserStorage from '../../services/BrowserStorage.js'
|
|||
import { getTalkConfig, hasTalkFeature } from '../../services/CapabilitiesManager.ts'
|
||||
import { EventBus } from '../../services/EventBus.ts'
|
||||
import { shareFile } from '../../services/filesSharingServices.ts'
|
||||
import { useActorStore } from '../../stores/actor.ts'
|
||||
import { useChatExtrasStore } from '../../stores/chatExtras.js'
|
||||
import { useGroupwareStore } from '../../stores/groupware.ts'
|
||||
import { useSettingsStore } from '../../stores/settings.js'
|
||||
|
|
@ -295,6 +296,7 @@ export default {
|
|||
const { autoComplete, userData } = useChatMentions(token)
|
||||
const { createTemporaryMessage } = useTemporaryMessage()
|
||||
return {
|
||||
actorStore: useActorStore(),
|
||||
chatExtrasStore: useChatExtrasStore(),
|
||||
groupwareStore: useGroupwareStore(),
|
||||
settingsStore: useSettingsStore(),
|
||||
|
|
@ -377,12 +379,8 @@ export default {
|
|||
return messageToEditId && this.$store.getters.message(this.token, messageToEditId)
|
||||
},
|
||||
|
||||
currentUserIsGuest() {
|
||||
return this.$store.getters.getUserId() === null
|
||||
},
|
||||
|
||||
canShareFiles() {
|
||||
return !this.currentUserIsGuest
|
||||
return !this.actorStore.isActorGuest
|
||||
&& !this.conversation.remoteServer // no attachments support in federated conversations
|
||||
},
|
||||
|
||||
|
|
@ -893,8 +891,7 @@ export default {
|
|||
|
||||
// last message within 24 hours
|
||||
const lastMessageByCurrentUser = this.$store.getters.messagesList(this.token).findLast((message) => {
|
||||
return message.actorId === this.$store.getters.getUserId()
|
||||
&& message.actorType === this.$store.getters.getActorType()
|
||||
return this.actorStore.checkIfSelfIsActor(message)
|
||||
&& !message.isTemporary && !message.systemMessage
|
||||
&& (Date.now() - message.timestamp * 1000 < ONE_DAY_IN_MS)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import { n, t } from '@nextcloud/l10n'
|
|||
import escapeHtml from 'escape-html'
|
||||
import AvatarWrapper from '../AvatarWrapper/AvatarWrapper.vue'
|
||||
import { AVATAR } from '../../constants.ts'
|
||||
import { useActorStore } from '../../stores/actor.ts'
|
||||
import { useGuestNameStore } from '../../stores/guestName.js'
|
||||
|
||||
export default {
|
||||
|
|
@ -48,12 +49,16 @@ export default {
|
|||
|
||||
setup() {
|
||||
const guestNameStore = useGuestNameStore()
|
||||
return { AVATAR, guestNameStore }
|
||||
return {
|
||||
AVATAR,
|
||||
guestNameStore,
|
||||
actorStore: useActorStore(),
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
isGuest() {
|
||||
return this.$store.getters.isActorGuest()
|
||||
return this.actorStore.isActorGuest
|
||||
},
|
||||
|
||||
externalTypingSignals() {
|
||||
|
|
|
|||
|
|
@ -137,6 +137,7 @@ import { useIsInCall } from '../../composables/useIsInCall.js'
|
|||
import { POLL } from '../../constants.ts'
|
||||
import { hasTalkFeature } from '../../services/CapabilitiesManager.ts'
|
||||
import { EventBus } from '../../services/EventBus.ts'
|
||||
import { useActorStore } from '../../stores/actor.ts'
|
||||
import { usePollsStore } from '../../stores/polls.ts'
|
||||
import { calculateVotePercentage } from '../../utils/calculateVotePercentage.ts'
|
||||
import { convertToJSONDataURI } from '../../utils/fileDownload.ts'
|
||||
|
|
@ -187,6 +188,7 @@ export default {
|
|||
|
||||
return {
|
||||
isInCall: useIsInCall(),
|
||||
actorStore: useActorStore(),
|
||||
pollsStore,
|
||||
voteToSubmit,
|
||||
modalPage,
|
||||
|
|
@ -243,8 +245,7 @@ export default {
|
|||
|
||||
selfIsOwnerOrModerator() {
|
||||
return this.isModerator
|
||||
|| (this.poll?.actorType === this.$store.getters.getActorType()
|
||||
&& this.poll?.actorId === this.$store.getters.getActorId())
|
||||
|| (this.poll && this.actorStore.checkIfSelfIsActor(this.poll))
|
||||
},
|
||||
|
||||
pollSummaryText() {
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ import FilePreview from './MessagesList/MessagesGroup/Message/MessagePart/FilePr
|
|||
import { useMessageInfo } from '../composables/useMessageInfo.js'
|
||||
import { ATTENDEE, AVATAR } from '../constants.ts'
|
||||
import { EventBus } from '../services/EventBus.ts'
|
||||
import { useActorStore } from '../stores/actor.ts'
|
||||
import { useChatExtrasStore } from '../stores/chatExtras.js'
|
||||
|
||||
export default {
|
||||
|
|
@ -125,6 +126,7 @@ export default {
|
|||
isFileShareWithoutCaption,
|
||||
actorDisplayName,
|
||||
actorInfo,
|
||||
actorStore: useActorStore(),
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -136,8 +138,7 @@ export default {
|
|||
},
|
||||
|
||||
isOwnMessageQuoted() {
|
||||
return this.message.actorId === this.$store.getters.getActorId()
|
||||
&& this.message.actorType === this.$store.getters.getActorType()
|
||||
return this.actorStore.checkIfSelfIsActor(this.message)
|
||||
},
|
||||
|
||||
richParameters() {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import AvatarWrapper from '../../AvatarWrapper/AvatarWrapper.vue'
|
|||
import Participant from './Participant.vue'
|
||||
import { ATTENDEE, PARTICIPANT, WEBINAR } from '../../../constants.ts'
|
||||
import storeConfig from '../../../store/storeConfig.js'
|
||||
import { useActorStore } from '../../../stores/actor.ts'
|
||||
import { findNcActionButton, findNcButton } from '../../../test-helpers.js'
|
||||
|
||||
describe('Participant.vue', () => {
|
||||
|
|
@ -36,6 +37,7 @@ describe('Participant.vue', () => {
|
|||
localVue = createLocalVue()
|
||||
localVue.use(Vuex)
|
||||
setActivePinia(createPinia())
|
||||
const actorStore = useActorStore()
|
||||
|
||||
participant = {
|
||||
displayName: 'Alice',
|
||||
|
|
@ -61,13 +63,12 @@ describe('Participant.vue', () => {
|
|||
lobbyState: WEBINAR.LOBBY.NONE,
|
||||
}
|
||||
|
||||
actorStore.actorId = 'user-actor-id'
|
||||
actorStore.actorType = ATTENDEE.ACTOR_TYPE.USERS
|
||||
|
||||
const conversationGetterMock = jest.fn().mockReturnValue(conversation)
|
||||
const actorIdMock = jest.fn().mockReturnValue('user-actor-id')
|
||||
const actorTypeMock = jest.fn().mockReturnValue(ATTENDEE.ACTOR_TYPE.USERS)
|
||||
|
||||
testStoreConfig = cloneDeep(storeConfig)
|
||||
testStoreConfig.modules.actorStore.getters.getActorId = () => () => actorIdMock()
|
||||
testStoreConfig.modules.actorStore.getters.getActorType = () => () => actorTypeMock()
|
||||
testStoreConfig.modules.tokenStore.getters.getToken = () => () => 'current-token'
|
||||
testStoreConfig.modules.conversationsStore.getters.conversation = () => conversationGetterMock
|
||||
store = new Vuex.Store(testStoreConfig)
|
||||
|
|
|
|||
|
|
@ -354,6 +354,7 @@ import {
|
|||
callSIPUnmutePhone,
|
||||
} from '../../../services/callsService.js'
|
||||
import { hasTalkFeature } from '../../../services/CapabilitiesManager.ts'
|
||||
import { useActorStore } from '../../../stores/actor.ts'
|
||||
import { formattedTime } from '../../../utils/formattedTime.ts'
|
||||
import { getDisplayNameWithFallback } from '../../../utils/getDisplayName.ts'
|
||||
import { readableNumber } from '../../../utils/readableNumber.ts'
|
||||
|
|
@ -417,6 +418,7 @@ export default {
|
|||
setup() {
|
||||
return {
|
||||
isInCall: useIsInCall(),
|
||||
actorStore: useActorStore(),
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -609,7 +611,7 @@ export default {
|
|||
return this.$store.getters.conversation(this.token) || {
|
||||
sessionId: '0',
|
||||
participantFlags: 0,
|
||||
participantType: this.$store.getters.getUserId() !== null ? PARTICIPANT.TYPE.USER : PARTICIPANT.TYPE.GUEST,
|
||||
participantType: this.actorStore.isLoggedIn ? PARTICIPANT.TYPE.USER : PARTICIPANT.TYPE.GUEST,
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -625,7 +627,7 @@ export default {
|
|||
},
|
||||
|
||||
isSelf() {
|
||||
return this.participant.actorType === this.$store.getters.getActorType() && this.participant.actorId === this.$store.getters.getActorId()
|
||||
return this.actorStore.checkIfSelfIsActor(this.participant)
|
||||
},
|
||||
|
||||
selfIsModerator() {
|
||||
|
|
@ -904,7 +906,7 @@ export default {
|
|||
console.info('Joining call')
|
||||
await this.$store.dispatch('joinCall', {
|
||||
token: this.token,
|
||||
participantIdentifier: this.$store.getters.getParticipantIdentifier(),
|
||||
participantIdentifier: this.actorStore.participantIdentifier,
|
||||
flags,
|
||||
silent: false,
|
||||
recordingConsent: true,
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ import { getTalkConfig, hasTalkFeature } from '../../../services/CapabilitiesMan
|
|||
import { autocompleteQuery } from '../../../services/coreService.ts'
|
||||
import { EventBus } from '../../../services/EventBus.ts'
|
||||
import { addParticipant } from '../../../services/participantsService.js'
|
||||
import { useActorStore } from '../../../stores/actor.ts'
|
||||
import { useSidebarStore } from '../../../stores/sidebar.ts'
|
||||
import CancelableRequest from '../../../utils/cancelableRequest.js'
|
||||
|
||||
|
|
@ -155,6 +156,7 @@ export default {
|
|||
isInCall,
|
||||
cancelableGetParticipants,
|
||||
sidebarStore: useSidebarStore(),
|
||||
actorStore: useActorStore(),
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -220,7 +222,7 @@ export default {
|
|||
},
|
||||
|
||||
userId() {
|
||||
return this.$store.getters.getUserId()
|
||||
return this.actorStore.userId
|
||||
},
|
||||
|
||||
canAddPhones() {
|
||||
|
|
|
|||
|
|
@ -142,6 +142,7 @@ import SharedItemsTab from './SharedItems/SharedItemsTab.vue'
|
|||
import SipSettings from './SipSettings.vue'
|
||||
import { CONVERSATION, PARTICIPANT, WEBINAR } from '../../constants.ts'
|
||||
import { getTalkConfig, hasTalkFeature } from '../../services/CapabilitiesManager.ts'
|
||||
import { useActorStore } from '../../stores/actor.ts'
|
||||
import { useSidebarStore } from '../../stores/sidebar.ts'
|
||||
|
||||
const canStartConversations = getTalkConfig('local', 'conversations', 'can-create')
|
||||
|
|
@ -234,6 +235,7 @@ export default {
|
|||
sidebar,
|
||||
sidebarContent,
|
||||
sidebarStore: useSidebarStore(),
|
||||
actorStore: useActorStore(),
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -279,7 +281,7 @@ export default {
|
|||
},
|
||||
|
||||
getUserId() {
|
||||
return this.$store.getters.getUserId()
|
||||
return this.actorStore.userId
|
||||
},
|
||||
|
||||
canAddParticipants() {
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ import SharedItemsBrowser from './SharedItemsBrowser.vue'
|
|||
import { CONVERSATION } from '../../../constants.ts'
|
||||
import { hasTalkFeature } from '../../../services/CapabilitiesManager.ts'
|
||||
import { EventBus } from '../../../services/EventBus.ts'
|
||||
import { useActorStore } from '../../../stores/actor.ts'
|
||||
import { useSharedItemsStore } from '../../../stores/sharedItems.js'
|
||||
import { useSidebarStore } from '../../../stores/sidebar.ts'
|
||||
import {
|
||||
|
|
@ -126,6 +127,7 @@ export default {
|
|||
|
||||
setup() {
|
||||
return {
|
||||
actorStore: useActorStore(),
|
||||
sharedItemsStore: useSharedItemsStore(),
|
||||
sidebarStore: useSidebarStore(),
|
||||
sharedItemButtonTitle,
|
||||
|
|
@ -146,7 +148,7 @@ export default {
|
|||
|
||||
computed: {
|
||||
getUserId() {
|
||||
return this.$store.getters.getUserId()
|
||||
return this.actorStore.userId
|
||||
},
|
||||
|
||||
token() {
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ import escapeHtml from 'escape-html'
|
|||
import NcButton from '@nextcloud/vue/components/NcButton'
|
||||
import NcTextField from '@nextcloud/vue/components/NcTextField'
|
||||
import Pencil from 'vue-material-design-icons/Pencil.vue'
|
||||
import { useActorStore } from '../stores/actor.ts'
|
||||
import { useGuestNameStore } from '../stores/guestName.js'
|
||||
|
||||
export default {
|
||||
|
|
@ -59,7 +60,10 @@ export default {
|
|||
|
||||
setup() {
|
||||
const guestNameStore = useGuestNameStore()
|
||||
return { guestNameStore }
|
||||
return {
|
||||
guestNameStore,
|
||||
actorStore: useActorStore(),
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
|
|
@ -72,7 +76,7 @@ export default {
|
|||
|
||||
computed: {
|
||||
actorDisplayName() {
|
||||
return this.$store.getters.getDisplayName() || t('spreed', 'Guest')
|
||||
return this.actorStore.displayName || t('spreed', 'Guest')
|
||||
},
|
||||
|
||||
displayNameLabel() {
|
||||
|
|
@ -82,7 +86,7 @@ export default {
|
|||
},
|
||||
|
||||
actorId() {
|
||||
return this.$store.getters.getActorId()
|
||||
return this.actorStore.actorId
|
||||
},
|
||||
|
||||
token() {
|
||||
|
|
|
|||
|
|
@ -232,6 +232,7 @@ import BrowserStorage from '../../services/BrowserStorage.js'
|
|||
import { getTalkConfig } from '../../services/CapabilitiesManager.ts'
|
||||
import { useCustomSettings } from '../../services/SettingsAPI.ts'
|
||||
import { setUserConfig } from '../../services/settingsService.ts'
|
||||
import { useActorStore } from '../../stores/actor.ts'
|
||||
import { useSettingsStore } from '../../stores/settings.js'
|
||||
import { useSoundsStore } from '../../stores/sounds.js'
|
||||
import { isMac } from '../../utils/browserCheck.ts'
|
||||
|
|
@ -276,6 +277,7 @@ export default {
|
|||
customSettingsSections,
|
||||
supportStartWithoutMedia,
|
||||
supportConversationsListStyle,
|
||||
actorStore: useActorStore(),
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -305,7 +307,7 @@ export default {
|
|||
},
|
||||
|
||||
isGuest() {
|
||||
return !this.$store.getters.getUserId()
|
||||
return !this.actorStore.userId
|
||||
},
|
||||
|
||||
readStatusPrivacyIsPublic() {
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ import { ATTENDEE, CALL, CONVERSATION, PARTICIPANT } from '../../constants.ts'
|
|||
import { callSIPDialOut } from '../../services/callsService.js'
|
||||
import { hasTalkFeature } from '../../services/CapabilitiesManager.ts'
|
||||
import { EventBus } from '../../services/EventBus.ts'
|
||||
import { useActorStore } from '../../stores/actor.ts'
|
||||
import { useBreakoutRoomsStore } from '../../stores/breakoutRooms.ts'
|
||||
import { useCallViewStore } from '../../stores/callView.ts'
|
||||
import { useSettingsStore } from '../../stores/settings.js'
|
||||
|
|
@ -189,6 +190,7 @@ export default {
|
|||
|
||||
setup() {
|
||||
return {
|
||||
actorStore: useActorStore(),
|
||||
isInCall: useIsInCall(),
|
||||
breakoutRoomsStore: useBreakoutRoomsStore(),
|
||||
callViewStore: useCallViewStore(),
|
||||
|
|
@ -384,7 +386,7 @@ export default {
|
|||
})
|
||||
await this.$store.dispatch('joinCall', {
|
||||
token: this.token,
|
||||
participantIdentifier: this.$store.getters.getParticipantIdentifier(),
|
||||
participantIdentifier: this.actorStore.participantIdentifier,
|
||||
flags,
|
||||
silent: this.hasCall ? true : this.silentCall,
|
||||
recordingConsent: this.recordingConsentGiven,
|
||||
|
|
@ -425,7 +427,7 @@ export default {
|
|||
})
|
||||
await this.$store.dispatch('leaveCall', {
|
||||
token: this.token,
|
||||
participantIdentifier: this.$store.getters.getParticipantIdentifier(),
|
||||
participantIdentifier: this.actorStore.participantIdentifier,
|
||||
all: endMeetingForAll,
|
||||
})
|
||||
this.loading = false
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@ import TopBarMenu from './TopBarMenu.vue'
|
|||
import { useGetParticipants } from '../../composables/useGetParticipants.js'
|
||||
import { AVATAR, CONVERSATION } from '../../constants.ts'
|
||||
import { getTalkConfig, hasTalkFeature } from '../../services/CapabilitiesManager.ts'
|
||||
import { useActorStore } from '../../stores/actor.ts'
|
||||
import { useGroupwareStore } from '../../stores/groupware.ts'
|
||||
import { useSidebarStore } from '../../stores/sidebar.ts'
|
||||
import { getStatusMessage } from '../../utils/userStatus.ts'
|
||||
|
|
@ -187,6 +188,7 @@ export default {
|
|||
localMediaModel,
|
||||
groupwareStore: useGroupwareStore(),
|
||||
sidebarStore: useSidebarStore(),
|
||||
actorStore: useActorStore(),
|
||||
CONVERSATION,
|
||||
}
|
||||
},
|
||||
|
|
@ -229,13 +231,6 @@ export default {
|
|||
return getStatusMessage(this.conversation)
|
||||
},
|
||||
|
||||
/**
|
||||
* Current actor id
|
||||
*/
|
||||
actorId() {
|
||||
return this.$store.getters.getActorId()
|
||||
},
|
||||
|
||||
/**
|
||||
* Online status of the peer in one to one conversation.
|
||||
*/
|
||||
|
|
@ -249,7 +244,7 @@ export default {
|
|||
let peer
|
||||
const participants = this.$store.getters.participantsList(this.token)
|
||||
for (const participant of participants) {
|
||||
if (participant.actorId !== this.actorId) {
|
||||
if (participant.actorId !== this.actorStore.actorId) {
|
||||
peer = participant
|
||||
}
|
||||
}
|
||||
|
|
@ -287,7 +282,7 @@ export default {
|
|||
},
|
||||
|
||||
getUserId() {
|
||||
return this.$store.getters.getUserId()
|
||||
return this.actorStore.userId
|
||||
},
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -184,6 +184,7 @@ import {
|
|||
import { useIsInCall } from '../../composables/useIsInCall.js'
|
||||
import { CALL, CONVERSATION, PARTICIPANT } from '../../constants.ts'
|
||||
import { getTalkConfig, hasTalkFeature } from '../../services/CapabilitiesManager.ts'
|
||||
import { useActorStore } from '../../stores/actor.ts'
|
||||
import { useBreakoutRoomsStore } from '../../stores/breakoutRooms.ts'
|
||||
import { useCallViewStore } from '../../stores/callView.ts'
|
||||
import { generateAbsoluteUrl } from '../../utils/handleUrl.ts'
|
||||
|
|
@ -259,6 +260,7 @@ export default {
|
|||
isFullscreen: useDocumentFullscreen(),
|
||||
breakoutRoomsStore: useBreakoutRoomsStore(),
|
||||
callViewStore: useCallViewStore(),
|
||||
actorStore: useActorStore(),
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -472,7 +474,7 @@ export default {
|
|||
this.$store.dispatch(
|
||||
'setParticipantHandRaised',
|
||||
{
|
||||
sessionId: this.$store.getters.getSessionId(),
|
||||
sessionId: this.actorStore.sessionId,
|
||||
raisedHand: this.model.attributes.raisedHand,
|
||||
},
|
||||
)
|
||||
|
|
@ -480,7 +482,7 @@ export default {
|
|||
// also send request for assistance to the moderators.
|
||||
if (this.userIsInBreakoutRoomAndInCall && !this.canModerate) {
|
||||
const hasRaisedHands = Object.keys(this.$store.getters.participantRaisedHandList)
|
||||
.filter((sessionId) => sessionId !== this.$store.getters.getSessionId())
|
||||
.filter((sessionId) => sessionId !== this.actorStore.sessionId)
|
||||
.length !== 0
|
||||
if (hasRaisedHands) {
|
||||
return // Assistance is already requested by someone in the room
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { computed, ref } from 'vue'
|
||||
import { ATTENDEE, CONVERSATION, MESSAGE } from '../../constants.ts'
|
||||
import { useActorStore } from '../../stores/actor.ts'
|
||||
import { useGuestNameStore } from '../../stores/guestName.js'
|
||||
import { useConversationInfo } from '../useConversationInfo.ts'
|
||||
import { useMessageInfo } from '../useMessageInfo.js'
|
||||
|
|
@ -26,12 +27,17 @@ describe('message actions', () => {
|
|||
let message
|
||||
let conversationProps
|
||||
let mockConversationInfo
|
||||
let actorStore
|
||||
const TOKEN = 'XXTOKENXX'
|
||||
|
||||
jest.useFakeTimers().setSystemTime(new Date('2024-05-01 17:00:00'))
|
||||
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
actorStore = useActorStore()
|
||||
|
||||
actorStore.actorId = 'user-id-1'
|
||||
actorStore.actorType = ATTENDEE.ACTOR_TYPE.USERS
|
||||
|
||||
message = ref({
|
||||
message: 'test message',
|
||||
|
|
@ -55,8 +61,6 @@ describe('message actions', () => {
|
|||
useStore.mockReturnValue({
|
||||
getters: {
|
||||
conversation: () => conversationProps,
|
||||
getActorId: () => 'user-id-1',
|
||||
getActorType: () => ATTENDEE.ACTOR_TYPE.USERS,
|
||||
isModerator: false,
|
||||
},
|
||||
})
|
||||
|
|
@ -123,11 +127,10 @@ describe('message actions', () => {
|
|||
useStore.mockReturnValue({
|
||||
getters: {
|
||||
conversation: () => conversationProps,
|
||||
getActorId: () => 'user-id-1',
|
||||
getActorType: () => ATTENDEE.ACTOR_TYPE.MODERATOR,
|
||||
isModerator: true,
|
||||
},
|
||||
})
|
||||
actorStore.actorType = ATTENDEE.ACTOR_TYPE.MODERATOR
|
||||
// Act
|
||||
const result = useMessageInfo(message)
|
||||
// Assert
|
||||
|
|
@ -142,8 +145,6 @@ describe('message actions', () => {
|
|||
useStore.mockReturnValue({
|
||||
getters: {
|
||||
conversation: () => conversationProps,
|
||||
getActorId: () => 'user-id-1',
|
||||
getActorType: () => ATTENDEE.ACTOR_TYPE.USER,
|
||||
isModerator: false,
|
||||
},
|
||||
})
|
||||
|
|
@ -186,11 +187,10 @@ describe('message actions', () => {
|
|||
useStore.mockReturnValue({
|
||||
getters: {
|
||||
conversation: () => conversationProps,
|
||||
getActorId: () => 'user-id-1',
|
||||
getActorType: () => ATTENDEE.ACTOR_TYPE.MODERATOR,
|
||||
isModerator: true,
|
||||
},
|
||||
})
|
||||
actorStore.actorType = ATTENDEE.ACTOR_TYPE.MODERATOR
|
||||
// Act
|
||||
const result = useMessageInfo(message)
|
||||
// Assert
|
||||
|
|
@ -205,8 +205,6 @@ describe('message actions', () => {
|
|||
useStore.mockReturnValue({
|
||||
getters: {
|
||||
conversation: () => conversationProps,
|
||||
getActorId: () => 'user-id-1',
|
||||
getActorType: () => ATTENDEE.ACTOR_TYPE.USERS,
|
||||
isModerator: false,
|
||||
},
|
||||
})
|
||||
|
|
@ -273,8 +271,6 @@ describe('message actions', () => {
|
|||
useStore.mockReturnValue({
|
||||
getters: {
|
||||
conversation: () => null,
|
||||
getActorId: () => 'user-id-1',
|
||||
getActorType: () => ATTENDEE.ACTOR_TYPE.USERS,
|
||||
},
|
||||
})
|
||||
// Act
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
import { n, t } from '@nextcloud/l10n'
|
||||
import cloneDeep from 'lodash/cloneDeep.js'
|
||||
import { useActorStore } from '../stores/actor.ts'
|
||||
import { useStore } from './useStore.js'
|
||||
|
||||
/**
|
||||
|
|
@ -13,16 +14,7 @@ import { useStore } from './useStore.js'
|
|||
*/
|
||||
export function useCombinedSystemMessage() {
|
||||
const store = useStore()
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {object} message message to check for
|
||||
* @return {boolean}
|
||||
*/
|
||||
function checkIfSelfIsActor(message) {
|
||||
return message.actorId === store.getters.getActorId()
|
||||
&& message.actorType === store.getters.getActorType()
|
||||
}
|
||||
const actorStore = useActorStore()
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -30,8 +22,8 @@ export function useCombinedSystemMessage() {
|
|||
* @return {boolean}
|
||||
*/
|
||||
function checkIfSelfIsOneOfActors(message) {
|
||||
return message.messageParameters.actor.id === store.getters.getActorId()
|
||||
&& message.messageParameters.actor.type + 's' === store.getters.getActorType()
|
||||
return message.messageParameters.actor.id === actorStore.actorId
|
||||
&& message.messageParameters.actor.type + 's' === actorStore.actorType
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -40,8 +32,8 @@ export function useCombinedSystemMessage() {
|
|||
* @return {boolean}
|
||||
*/
|
||||
function checkIfSelfIsOneOfUsers(message) {
|
||||
return message.messageParameters.user.id === store.getters.getActorId()
|
||||
&& message.messageParameters.user.type + 's' === store.getters.getActorType()
|
||||
return message.messageParameters.user.id === actorStore.actorId
|
||||
&& message.messageParameters.user.type + 's' === actorStore.actorType
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -90,7 +82,7 @@ export function useCombinedSystemMessage() {
|
|||
usersCounter++
|
||||
})
|
||||
|
||||
if (checkIfSelfIsActor(combinedMessage)) {
|
||||
if (actorStore.checkIfSelfIsActor(combinedMessage)) {
|
||||
if (usersCounter === 2) {
|
||||
combinedMessage.message = t('spreed', 'You added {user0} and {user1}')
|
||||
} else {
|
||||
|
|
@ -156,7 +148,7 @@ export function useCombinedSystemMessage() {
|
|||
usersCounter++
|
||||
})
|
||||
|
||||
if (checkIfSelfIsActor(combinedMessage)) {
|
||||
if (actorStore.checkIfSelfIsActor(combinedMessage)) {
|
||||
if (usersCounter === 2) {
|
||||
combinedMessage.message = t('spreed', 'You removed {user0} and {user1}')
|
||||
} else {
|
||||
|
|
@ -299,7 +291,7 @@ export function useCombinedSystemMessage() {
|
|||
usersCounter++
|
||||
})
|
||||
|
||||
if (checkIfSelfIsActor(combinedMessage)) {
|
||||
if (actorStore.checkIfSelfIsActor(combinedMessage)) {
|
||||
if (usersCounter === 2) {
|
||||
combinedMessage.message = t('spreed', 'You promoted {user0} and {user1} to moderators')
|
||||
} else {
|
||||
|
|
@ -365,7 +357,7 @@ export function useCombinedSystemMessage() {
|
|||
usersCounter++
|
||||
})
|
||||
|
||||
if (checkIfSelfIsActor(combinedMessage)) {
|
||||
if (actorStore.checkIfSelfIsActor(combinedMessage)) {
|
||||
if (usersCounter === 2) {
|
||||
combinedMessage.message = t('spreed', 'You demoted {user0} and {user1} from moderators')
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import { t } from '@nextcloud/l10n'
|
|||
import { computed, ref, watch } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router/composables'
|
||||
import { EventBus } from '../services/EventBus.ts'
|
||||
import { useActorStore } from '../stores/actor.ts'
|
||||
import { hasCall, hasUnreadMentions } from '../utils/conversation.ts'
|
||||
import { useDocumentVisibility } from './useDocumentVisibility.ts'
|
||||
import { useStore } from './useStore.js'
|
||||
|
|
@ -35,8 +36,9 @@ export function useDocumentTitle() {
|
|||
const savedLastMessageMap = ref<LastMessageMap>({})
|
||||
|
||||
const conversationList = computed(() => store.getters.conversationsList)
|
||||
const actorId = computed(() => store.getters.getActorId())
|
||||
const actorType = computed(() => store.getters.getActorType())
|
||||
const actorStore = useActorStore()
|
||||
const actorId = computed(() => actorStore.actorId)
|
||||
const actorType = computed(() => actorStore.actorType)
|
||||
|
||||
watch(conversationList, (newValue) => {
|
||||
if (isDocumentVisible.value || document.title.startsWith('* ')
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { t } from '@nextcloud/l10n'
|
|||
import { computed, ref } from 'vue'
|
||||
import { ATTENDEE, CONVERSATION, MESSAGE } from '../constants.ts'
|
||||
import { hasTalkFeature } from '../services/CapabilitiesManager.ts'
|
||||
import { useActorStore } from '../stores/actor.ts'
|
||||
import { useGuestNameStore } from '../stores/guestName.js'
|
||||
import { ONE_DAY_IN_MS, ONE_HOUR_IN_MS } from '../utils/formattedTime.ts'
|
||||
import { getDisplayNameWithFallback } from '../utils/getDisplayName.ts'
|
||||
|
|
@ -22,9 +23,10 @@ import { useStore } from './useStore.js'
|
|||
export function useMessageInfo(message = ref({})) {
|
||||
// Get the conversation
|
||||
const store = useStore()
|
||||
const actorStore = useActorStore()
|
||||
const conversation = computed(() => store.getters.conversation(message.value.token))
|
||||
const currentActorId = store.getters.getActorId()
|
||||
const currentActorType = store.getters.getActorType()
|
||||
const currentActorId = actorStore.actorId
|
||||
const currentActorType = actorStore.actorType
|
||||
// If the conversation or message is not available, return false
|
||||
if (!conversation.value || !message.value.id) {
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
import type { PrepareTemporaryMessagePayload } from '../utils/prepareTemporaryMessage.ts'
|
||||
|
||||
import { useActorStore } from '../stores/actor.ts'
|
||||
import { useChatExtrasStore } from '../stores/chatExtras.js'
|
||||
import { prepareTemporaryMessage } from '../utils/prepareTemporaryMessage.ts'
|
||||
import { useStore } from './useStore.js'
|
||||
|
|
@ -16,6 +17,7 @@ import { useStore } from './useStore.js'
|
|||
export function useTemporaryMessage(context: unknown) {
|
||||
const store = context ?? useStore()
|
||||
const chatExtrasStore = useChatExtrasStore()
|
||||
const actorStore = useActorStore()
|
||||
|
||||
/**
|
||||
* @param payload payload for generating a temporary message
|
||||
|
|
@ -25,9 +27,9 @@ export function useTemporaryMessage(context: unknown) {
|
|||
|
||||
return prepareTemporaryMessage({
|
||||
...payload,
|
||||
actorId: store.getters.getActorId(),
|
||||
actorType: store.getters.getActorType(),
|
||||
actorDisplayName: store.getters.getDisplayName(),
|
||||
actorId: actorStore.actorId ?? '',
|
||||
actorType: actorStore.actorType ?? '',
|
||||
actorDisplayName: actorStore.displayName,
|
||||
parent: parentId && store.getters.message(payload.token, parentId),
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,204 +0,0 @@
|
|||
/**
|
||||
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
/**
|
||||
* This store helps to identify a the current actor in all cases.
|
||||
* In Talk not every user is a local nextcloud user, so identifying
|
||||
* solely by userId is not enough.
|
||||
* If an as no userId, they are a guest and identified by actorType + sessionId.
|
||||
*/
|
||||
|
||||
import { loadState } from '@nextcloud/initial-state'
|
||||
import { ATTENDEE, PARTICIPANT } from '../constants.ts'
|
||||
import { getTeams } from '../services/teamsService.ts'
|
||||
|
||||
const state = {
|
||||
userId: null,
|
||||
sessionId: null,
|
||||
attendeeId: null,
|
||||
actorId: null,
|
||||
actorType: null,
|
||||
displayName: '',
|
||||
actorGroups: loadState('spreed', 'user_group_ids', []),
|
||||
actorTeams: [],
|
||||
}
|
||||
|
||||
const getters = {
|
||||
getUserId: (state) => () => {
|
||||
return state.userId
|
||||
},
|
||||
getSessionId: (state) => () => {
|
||||
return state.sessionId
|
||||
},
|
||||
getAttendeeId: (state) => () => {
|
||||
return state.attendeeId
|
||||
},
|
||||
getActorId: (state) => () => {
|
||||
return state.actorId
|
||||
},
|
||||
getActorType: (state) => () => {
|
||||
return state.actorType
|
||||
},
|
||||
isActorUser: (state) => () => {
|
||||
return state.actorType === ATTENDEE.ACTOR_TYPE.USERS
|
||||
},
|
||||
isActorGuest: (state) => () => {
|
||||
return state.actorType === ATTENDEE.ACTOR_TYPE.GUESTS
|
||||
},
|
||||
isActorMemberOfGroup: (state) => (groupId) => {
|
||||
return state.actorGroups.includes(groupId)
|
||||
},
|
||||
isActorMemberOfTeam: (state) => (teamId) => {
|
||||
return state.actorTeams.includes(teamId)
|
||||
},
|
||||
getDisplayName: (state) => () => {
|
||||
return state.displayName
|
||||
},
|
||||
getParticipantIdentifier: (state) => () => {
|
||||
return {
|
||||
attendeeId: state.attendeeId,
|
||||
actorType: state.actorType,
|
||||
actorId: state.actorId,
|
||||
sessionId: state.sessionId,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
/**
|
||||
* Set the userId
|
||||
*
|
||||
* @param {object} state current store state;
|
||||
* @param {string} userId The user id
|
||||
*/
|
||||
setUserId(state, userId) {
|
||||
state.userId = userId
|
||||
state.actorId = userId
|
||||
},
|
||||
/**
|
||||
* Set the attendeeId
|
||||
*
|
||||
* @param {object} state current store state;
|
||||
* @param {string} attendeeId The actors attendee id
|
||||
*/
|
||||
setAttendeeId(state, attendeeId) {
|
||||
state.attendeeId = attendeeId
|
||||
},
|
||||
/**
|
||||
* Set the sessionId
|
||||
*
|
||||
* @param {object} state current store state;
|
||||
* @param {string} sessionId The actors session id
|
||||
*/
|
||||
setSessionId(state, sessionId) {
|
||||
state.sessionId = sessionId
|
||||
},
|
||||
/**
|
||||
* Set the actorId
|
||||
*
|
||||
* @param {object} state current store state;
|
||||
* @param {string} actorId The actor id
|
||||
*/
|
||||
setActorId(state, actorId) {
|
||||
state.actorId = actorId
|
||||
},
|
||||
/**
|
||||
* Set the userId
|
||||
*
|
||||
* @param {object} state current store state;
|
||||
* @param {string} displayName The name
|
||||
*/
|
||||
setDisplayName(state, displayName) {
|
||||
state.displayName = displayName
|
||||
},
|
||||
/**
|
||||
* Set the userId
|
||||
*
|
||||
* @param {object} state current store state;
|
||||
* @param {actorType} actorType The actor type of the user
|
||||
*/
|
||||
setActorType(state, actorType) {
|
||||
state.actorType = actorType
|
||||
},
|
||||
/**
|
||||
* Set the user teams ids
|
||||
*
|
||||
* @param {object} state current store state;
|
||||
* @param {Array} teams Teams ids of the current user
|
||||
*/
|
||||
setCurrentUserTeams(state, teams) {
|
||||
state.actorTeams = teams
|
||||
},
|
||||
}
|
||||
|
||||
const actions = {
|
||||
|
||||
/**
|
||||
* Set the actor from the current user
|
||||
*
|
||||
* @param {object} context default store context;
|
||||
* @param {object} user A NextcloudUser object as returned by @nextcloud/auth
|
||||
* @param {string} user.uid The user id of the user
|
||||
* @param {string|null} user.displayName The display name of the user
|
||||
*/
|
||||
setCurrentUser(context, user) {
|
||||
context.commit('setUserId', user.uid)
|
||||
context.commit('setDisplayName', user.displayName || user.uid)
|
||||
context.commit('setActorType', ATTENDEE.ACTOR_TYPE.USERS)
|
||||
context.commit('setActorId', user.uid)
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the actor from the current participant
|
||||
*
|
||||
* @param {object} context default store context;
|
||||
* @param {object} participant The participant data
|
||||
* @param {number} participant.attendeeId The attendee id of the participant
|
||||
* @param {number} participant.participantType The type of the participant
|
||||
* @param {string} participant.sessionId The session id of the participant
|
||||
* @param {string} participant.actorId The actor id of the participant
|
||||
*/
|
||||
setCurrentParticipant(context, participant) {
|
||||
context.commit('setSessionId', participant.sessionId)
|
||||
context.commit('setAttendeeId', participant.attendeeId)
|
||||
|
||||
if (participant.participantType === PARTICIPANT.TYPE.GUEST
|
||||
|| participant.participantType === PARTICIPANT.TYPE.GUEST_MODERATOR) {
|
||||
context.commit('setUserId', null)
|
||||
context.commit('setActorType', ATTENDEE.ACTOR_TYPE.GUESTS)
|
||||
context.commit('setActorId', participant.actorId)
|
||||
// FIXME context.commit('setDisplayName', '')
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Sets displayName only, we currently use this for guests user names.
|
||||
*
|
||||
* @param {object} context default store context;
|
||||
* @param {string} displayName the display name to be set;
|
||||
*/
|
||||
setDisplayName(context, displayName) {
|
||||
context.commit('setDisplayName', displayName)
|
||||
},
|
||||
/**
|
||||
* Sets current user teams, if circles app enabled
|
||||
*
|
||||
* @param {object} context default store context;
|
||||
*/
|
||||
async getCurrentUserTeams(context) {
|
||||
if (!loadState('spreed', 'circles_enabled', false)) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await getTeams()
|
||||
const teams = response.data.ocs.data.map((team) => team.id)
|
||||
context.commit('setCurrentUserTeams', teams)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default { state, mutations, getters, actions }
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
/**
|
||||
* SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
import { createLocalVue } from '@vue/test-utils'
|
||||
import { cloneDeep } from 'lodash'
|
||||
import Vuex from 'vuex'
|
||||
import { PARTICIPANT } from '../constants.ts'
|
||||
import actorStore from './actorStore.js'
|
||||
|
||||
describe('actorStore', () => {
|
||||
let localVue = null
|
||||
let store = null
|
||||
|
||||
beforeEach(() => {
|
||||
localVue = createLocalVue()
|
||||
localVue.use(Vuex)
|
||||
store = new Vuex.Store(cloneDeep(actorStore))
|
||||
})
|
||||
|
||||
test('setCurrentUser updates all relevant attributes', () => {
|
||||
store.dispatch('setCurrentUser', {
|
||||
uid: 'userId',
|
||||
displayName: 'display-name',
|
||||
})
|
||||
|
||||
expect(store.getters.getUserId()).toBe('userId')
|
||||
expect(store.getters.getDisplayName()).toBe('display-name')
|
||||
expect(store.getters.getActorId()).toBe('userId')
|
||||
expect(store.getters.getActorType()).toBe('users')
|
||||
})
|
||||
|
||||
test('setDisplayName updates all relevant attributes', () => {
|
||||
store.dispatch('setCurrentUser', {
|
||||
uid: 'userId',
|
||||
displayName: 'display-name',
|
||||
})
|
||||
|
||||
store.dispatch('setDisplayName', 'new-display-name')
|
||||
|
||||
expect(store.getters.getUserId()).toBe('userId')
|
||||
expect(store.getters.getDisplayName()).toBe('new-display-name')
|
||||
})
|
||||
|
||||
describe('setCurrentParticipant', () => {
|
||||
test('setCurrentParticipant with type GUEST clears user id and updates all relevant attributes', () => {
|
||||
store.dispatch('setCurrentParticipant', {
|
||||
actorId: 'guestActorId',
|
||||
sessionId: 'XXSESSIONIDXX',
|
||||
participantType: PARTICIPANT.TYPE.GUEST,
|
||||
})
|
||||
|
||||
expect(store.getters.getSessionId()).toBe('XXSESSIONIDXX')
|
||||
expect(store.getters.getUserId()).toBe(null)
|
||||
expect(store.getters.getDisplayName()).toBe('')
|
||||
expect(store.getters.getActorId()).toBe('guestActorId')
|
||||
expect(store.getters.getActorType()).toBe('guests')
|
||||
})
|
||||
|
||||
test('setCurrentParticipant with type GUEST_MODERATOR clears user id and updates all relevant attributes', () => {
|
||||
store.dispatch('setCurrentParticipant', {
|
||||
actorId: 'guestActorId',
|
||||
sessionId: 'XXSESSIONIDXX',
|
||||
participantType: PARTICIPANT.TYPE.GUEST_MODERATOR,
|
||||
})
|
||||
|
||||
expect(store.getters.getSessionId()).toBe('XXSESSIONIDXX')
|
||||
expect(store.getters.getUserId()).toBe(null)
|
||||
expect(store.getters.getDisplayName()).toBe('')
|
||||
expect(store.getters.getActorId()).toBe('guestActorId')
|
||||
expect(store.getters.getActorType()).toBe('guests')
|
||||
})
|
||||
|
||||
test('setCurrentParticipant with type USER keeps user id and updates all relevant attributes', () => {
|
||||
store.dispatch('setCurrentUser', {
|
||||
uid: 'userId',
|
||||
displayName: 'display-name',
|
||||
})
|
||||
|
||||
store.dispatch('setCurrentParticipant', {
|
||||
actorId: 'userActorId',
|
||||
sessionId: 'XXSESSIONIDXX',
|
||||
participantType: PARTICIPANT.TYPE.USER,
|
||||
})
|
||||
|
||||
expect(store.getters.getSessionId()).toBe('XXSESSIONIDXX')
|
||||
|
||||
// user values unchanged
|
||||
expect(store.getters.getUserId()).toBe('userId')
|
||||
expect(store.getters.getDisplayName()).toBe('display-name')
|
||||
expect(store.getters.getActorId()).toBe('userId')
|
||||
expect(store.getters.getActorType()).toBe('users')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -64,6 +64,7 @@ import {
|
|||
stopCallRecording,
|
||||
} from '../services/recordingService.js'
|
||||
import { talkBroadcastChannel } from '../services/talkBroadcastChannel.js'
|
||||
import { useActorStore } from '../stores/actor.ts'
|
||||
import { useBreakoutRoomsStore } from '../stores/breakoutRooms.ts'
|
||||
import { useChatExtrasStore } from '../stores/chatExtras.js'
|
||||
import { useFederationStore } from '../stores/federation.ts'
|
||||
|
|
@ -299,10 +300,11 @@ const actions = {
|
|||
return
|
||||
}
|
||||
|
||||
const actorStore = useActorStore()
|
||||
// Add current user to a new conversation participants
|
||||
let currentUser = {
|
||||
uid: context.getters.getUserId(),
|
||||
displayName: context.getters.getDisplayName(),
|
||||
uid: actorStore.userId,
|
||||
displayName: actorStore.displayName,
|
||||
}
|
||||
|
||||
// Fallback to getCurrentUser() only if it has not been set yet (as
|
||||
|
|
@ -1059,8 +1061,9 @@ const actions = {
|
|||
*/
|
||||
async extendOneToOneConversation(context, { token, newParticipants }) {
|
||||
const conversation = context.getters.conversation(token)
|
||||
const actorStore = useActorStore()
|
||||
const participants = [
|
||||
{ id: conversation.actorId, source: conversation.actorType, label: context.rootGetters.getDisplayName() },
|
||||
{ id: conversation.actorId, source: conversation.actorType, label: actorStore.displayName },
|
||||
...newParticipants,
|
||||
]
|
||||
const roomName = getDisplayNamesList(participants.map((participant) => participant.label), CONVERSATION.MAX_NAME_LENGTH)
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import {
|
|||
setSIPEnabled,
|
||||
} from '../services/conversationsService.ts'
|
||||
import { setConversationUnread, updateLastReadMessage } from '../services/messagesService.ts'
|
||||
import { useActorStore } from '../stores/actor.ts'
|
||||
import { useTalkHashStore } from '../stores/talkHash.js'
|
||||
import { generateOCSErrorResponse, generateOCSResponse } from '../test-helpers.js'
|
||||
import storeConfig from './storeConfig.js'
|
||||
|
|
@ -87,12 +88,14 @@ describe('conversationsStore', () => {
|
|||
let localVue = null
|
||||
let store = null
|
||||
let addParticipantOnceAction = null
|
||||
let actorStore
|
||||
const permissions = PARTICIPANT.PERMISSIONS.MAX_CUSTOM
|
||||
|
||||
beforeEach(() => {
|
||||
localVue = createLocalVue()
|
||||
localVue.use(Vuex)
|
||||
setActivePinia(createPinia())
|
||||
actorStore = useActorStore()
|
||||
|
||||
testConversation = {
|
||||
token: testToken,
|
||||
|
|
@ -139,7 +142,7 @@ describe('conversationsStore', () => {
|
|||
})
|
||||
|
||||
test('adds conversation to the store, with current user as participant', () => {
|
||||
store.dispatch('setCurrentUser', {
|
||||
actorStore.setCurrentUser({
|
||||
uid: 'current-user',
|
||||
displayName: 'display-name',
|
||||
})
|
||||
|
|
@ -169,7 +172,7 @@ describe('conversationsStore', () => {
|
|||
})
|
||||
|
||||
test('adds conversation to the store, with empty user id for guests', () => {
|
||||
store.dispatch('setCurrentParticipant', {
|
||||
actorStore.setCurrentParticipant({
|
||||
actorId: 'guestActorId',
|
||||
sessionId: 'XXSESSIONIDXX',
|
||||
participantType: PARTICIPANT.TYPE.GUEST,
|
||||
|
|
@ -201,7 +204,7 @@ describe('conversationsStore', () => {
|
|||
})
|
||||
|
||||
test('deletes messages with conversation', () => {
|
||||
store.dispatch('setCurrentUser', {
|
||||
actorStore.setCurrentUser({
|
||||
uid: 'current-user',
|
||||
displayName: 'display-name',
|
||||
})
|
||||
|
|
@ -910,7 +913,7 @@ describe('conversationsStore', () => {
|
|||
describe('read marker', () => {
|
||||
beforeEach(() => {
|
||||
store = new Vuex.Store(testStoreConfig)
|
||||
store.commit('setUserId', 'current-user')
|
||||
actorStore.userId = 'current-user'
|
||||
})
|
||||
|
||||
test('marks conversation as read by clearing unread counters', async () => {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import {
|
|||
shareFile,
|
||||
} from '../services/filesSharingServices.ts'
|
||||
import { setAttachmentFolder } from '../services/settingsService.ts'
|
||||
import { useActorStore } from '../stores/actor.ts'
|
||||
import { useChatExtrasStore } from '../stores/chatExtras.js'
|
||||
import {
|
||||
findUniquePath,
|
||||
|
|
@ -335,7 +336,8 @@ const actions = {
|
|||
*/
|
||||
async prepareUploadPaths(context, { token, uploadId }) {
|
||||
const client = getDavClient()
|
||||
const userRoot = '/files/' + context.getters.getUserId()
|
||||
const actorStore = useActorStore()
|
||||
const userRoot = '/files/' + actorStore.userId
|
||||
|
||||
// Store propfind attempts within one action to reduce amount of requests for duplicates
|
||||
const knownPaths = {}
|
||||
|
|
@ -584,7 +586,8 @@ const actions = {
|
|||
return
|
||||
}
|
||||
|
||||
if (getters.getUserId() === null) {
|
||||
const actorStore = useActorStore()
|
||||
if (actorStore.userId === null) {
|
||||
console.debug('Skip file templates setup for participants that are not logged in')
|
||||
commit('markFileTemplatesInitialised')
|
||||
return
|
||||
|
|
|
|||
|
|
@ -12,9 +12,9 @@ import Vuex from 'vuex'
|
|||
import { getDavClient } from '../services/DavClient.js'
|
||||
import { shareFile } from '../services/filesSharingServices.ts'
|
||||
import { setAttachmentFolder } from '../services/settingsService.ts'
|
||||
import { useActorStore } from '../stores/actor.ts'
|
||||
import { findUniquePath } from '../utils/fileUpload.js'
|
||||
import fileUploadStore from './fileUploadStore.js'
|
||||
import storeConfig from './storeConfig.js'
|
||||
|
||||
jest.mock('../services/DavClient', () => ({
|
||||
getDavClient: jest.fn(),
|
||||
|
|
@ -38,11 +38,13 @@ describe('fileUploadStore', () => {
|
|||
let storeConfig = null
|
||||
let store = null
|
||||
let mockedActions = null
|
||||
let actorStore
|
||||
|
||||
beforeEach(() => {
|
||||
localVue = createLocalVue()
|
||||
localVue.use(Vuex)
|
||||
setActivePinia(createPinia())
|
||||
actorStore = useActorStore()
|
||||
|
||||
mockedActions = {
|
||||
addTemporaryMessage: jest.fn(),
|
||||
|
|
@ -53,10 +55,10 @@ describe('fileUploadStore', () => {
|
|||
|
||||
storeConfig = cloneDeep(fileUploadStore)
|
||||
storeConfig.actions = Object.assign(storeConfig.actions, mockedActions)
|
||||
storeConfig.getters.getUserId = jest.fn().mockReturnValue(() => 'current-user')
|
||||
storeConfig.getters.getActorId = jest.fn().mockReturnValue(() => 'current-user')
|
||||
storeConfig.getters.getActorType = jest.fn().mockReturnValue(() => 'users')
|
||||
storeConfig.getters.getDisplayName = jest.fn().mockReturnValue(() => 'Current User')
|
||||
actorStore.userId = 'current-user'
|
||||
actorStore.actorId = 'current-user'
|
||||
actorStore.actorType = 'users'
|
||||
actorStore.displayName = 'Current User'
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import {
|
|||
postRichObjectToConversation,
|
||||
updateLastReadMessage,
|
||||
} from '../services/messagesService.ts'
|
||||
import { useActorStore } from '../stores/actor.ts'
|
||||
import { useCallViewStore } from '../stores/callView.ts'
|
||||
import { useGuestNameStore } from '../stores/guestName.js'
|
||||
import { usePollsStore } from '../stores/polls.ts'
|
||||
|
|
@ -44,6 +45,7 @@ import { convertToUnix } from '../utils/formattedTime.ts'
|
|||
* false otherwise
|
||||
*/
|
||||
function hasMentionToSelf(context, message) {
|
||||
const actorStore = useActorStore()
|
||||
if (!message.messageParameters) {
|
||||
return false
|
||||
}
|
||||
|
|
@ -55,14 +57,14 @@ function hasMentionToSelf(context, message) {
|
|||
return true
|
||||
}
|
||||
if (param.type === 'guest'
|
||||
&& context.getters.isActorGuest()
|
||||
&& param.id === ('guest/' + context.getters.getActorId())
|
||||
&& actorStore.isActorGuest
|
||||
&& param.id === ('guest/' + actorStore.actorId)
|
||||
) {
|
||||
return true
|
||||
}
|
||||
if (param.type === 'user'
|
||||
&& context.getters.isActorUser()
|
||||
&& param.id === context.getters.getUserId()
|
||||
&& actorStore.isActorUser
|
||||
&& param.id === actorStore.userId
|
||||
) {
|
||||
return true
|
||||
}
|
||||
|
|
@ -542,6 +544,7 @@ const actions = {
|
|||
*/
|
||||
processMessage(context, { token, message }) {
|
||||
const sharedItemsStore = useSharedItemsStore()
|
||||
const actorStore = useActorStore()
|
||||
|
||||
if (message.systemMessage === 'message_deleted'
|
||||
|| message.systemMessage === 'reaction'
|
||||
|
|
@ -588,8 +591,7 @@ const actions = {
|
|||
if (tempMessages.length > 0) {
|
||||
// Replacing temporary placeholder message with server response (text message / file share)
|
||||
const conversation = context.getters.conversation(token)
|
||||
const isOwnMessage = message.actorId === context.getters.getActorId()
|
||||
&& message.actorType === context.getters.getActorType()
|
||||
const isOwnMessage = actorStore.checkIfSelfIsActor(message)
|
||||
|
||||
// update lastMessage and lastReadMessage (no await to make it async)
|
||||
// do it conditionally because there could have been more messages appearing concurrently
|
||||
|
|
@ -856,7 +858,8 @@ const actions = {
|
|||
context.commit('setVisualLastReadMessageId', { token, id: visualIdToUpdate })
|
||||
}
|
||||
|
||||
if (context.getters.getUserId()) {
|
||||
const actorStore = useActorStore()
|
||||
if (actorStore.userId) {
|
||||
// only update on server side if there's an actual user, not guest
|
||||
const response = await updateLastReadMessage(token, id)
|
||||
context.dispatch('addConversation', response.data.ocs.data)
|
||||
|
|
@ -1107,6 +1110,7 @@ const actions = {
|
|||
* @param {number} data.lastKnownMessageId The id of the last message in the store.
|
||||
*/
|
||||
async pollNewMessages(context, { token, lastKnownMessageId, requestId, requestOptions }) {
|
||||
const actorStore = useActorStore()
|
||||
context.dispatch('cancelPollNewMessages', { requestId })
|
||||
|
||||
if (!lastKnownMessageId) {
|
||||
|
|
@ -1137,8 +1141,8 @@ const actions = {
|
|||
}
|
||||
|
||||
const conversation = context.getters.conversation(token)
|
||||
const actorId = context.getters.getActorId()
|
||||
const actorType = context.getters.getActorType()
|
||||
const actorId = actorStore.actorId
|
||||
const actorType = actorStore.actorType
|
||||
let countNewMessages = 0
|
||||
let hasNewMention = conversation.unreadMention
|
||||
let lastMessage = null
|
||||
|
|
@ -1179,14 +1183,13 @@ const actions = {
|
|||
}
|
||||
if (message.systemMessage === 'call_ended_everyone'
|
||||
&& conversation.type !== CONVERSATION.TYPE.ONE_TO_ONE
|
||||
&& !(message.actorId === context.getters.getActorId()
|
||||
&& message.actorType === context.getters.getActorType())) {
|
||||
&& !actorStore.checkIfSelfIsActor(message)) {
|
||||
const callViewStore = useCallViewStore()
|
||||
callViewStore.setCallHasJustEnded(message.timestamp)
|
||||
|
||||
context.dispatch('leaveCall', {
|
||||
token,
|
||||
participantIdentifier: context.getters.getParticipantIdentifier(),
|
||||
participantIdentifier: actorStore.participantIdentifier,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import {
|
|||
postRichObjectToConversation,
|
||||
updateLastReadMessage,
|
||||
} from '../services/messagesService.ts'
|
||||
import { useActorStore } from '../stores/actor.ts'
|
||||
import { useGuestNameStore } from '../stores/guestName.js'
|
||||
import { useReactionsStore } from '../stores/reactions.js'
|
||||
import { generateOCSErrorResponse, generateOCSResponse } from '../test-helpers.js'
|
||||
|
|
@ -76,37 +77,32 @@ describe('messagesStore', () => {
|
|||
let localVue = null
|
||||
let testStoreConfig
|
||||
let store = null
|
||||
let getActorIdMock
|
||||
let getUserIdMock
|
||||
let getActorTypeMock
|
||||
let getDisplayNameMock
|
||||
let conversationMock
|
||||
let updateConversationLastMessageMock
|
||||
let updateConversationLastReadMessageMock
|
||||
let updateConversationLastActiveAction
|
||||
let reactionsStore
|
||||
let actorStore
|
||||
|
||||
beforeEach(() => {
|
||||
localVue = createLocalVue()
|
||||
localVue.use(Vuex)
|
||||
setActivePinia(createPinia())
|
||||
reactionsStore = useReactionsStore()
|
||||
actorStore = useActorStore()
|
||||
|
||||
testStoreConfig = cloneDeep(storeConfig)
|
||||
|
||||
getActorIdMock = jest.fn().mockReturnValue(() => 'actor-id-1')
|
||||
getUserIdMock = jest.fn().mockReturnValue(() => 'actor-id-1')
|
||||
getActorTypeMock = jest.fn().mockReturnValue(() => ATTENDEE.ACTOR_TYPE.USERS)
|
||||
getDisplayNameMock = jest.fn().mockReturnValue(() => 'actor-display-name-1')
|
||||
actorStore.actorId = 'actor-id-1'
|
||||
actorStore.userId = 'actor-id-1'
|
||||
actorStore.actorType = ATTENDEE.ACTOR_TYPE.USERS
|
||||
actorStore.displayName = 'actor-display-name-1'
|
||||
|
||||
conversationMock = jest.fn().mockReturnValue(conversation)
|
||||
updateConversationLastMessageMock = jest.fn()
|
||||
updateConversationLastReadMessageMock = jest.fn()
|
||||
updateConversationLastActiveAction = jest.fn()
|
||||
|
||||
testStoreConfig.modules.actorStore.getters.getActorId = getActorIdMock
|
||||
testStoreConfig.modules.actorStore.getters.getUserId = getUserIdMock
|
||||
testStoreConfig.modules.actorStore.getters.getActorType = getActorTypeMock
|
||||
testStoreConfig.modules.actorStore.getters.getDisplayName = getDisplayNameMock
|
||||
testStoreConfig.modules.conversationsStore.getters.conversation = jest.fn().mockReturnValue(conversationMock)
|
||||
testStoreConfig.modules.conversationsStore.actions.updateConversationLastMessage = updateConversationLastMessageMock
|
||||
testStoreConfig.modules.conversationsStore.actions.updateConversationLastReadMessage = updateConversationLastReadMessageMock
|
||||
|
|
@ -689,6 +685,8 @@ describe('messagesStore', () => {
|
|||
describe('last read message markers', () => {
|
||||
beforeEach(() => {
|
||||
const response = generateOCSResponse({ payload: conversation })
|
||||
actorStore.userId = 'user-1'
|
||||
actorStore.actorType = ATTENDEE.ACTOR_TYPE.USERS
|
||||
updateLastReadMessage.mockResolvedValue(response)
|
||||
})
|
||||
|
||||
|
|
@ -701,7 +699,7 @@ describe('messagesStore', () => {
|
|||
})
|
||||
|
||||
test('clears last read message', async () => {
|
||||
getUserIdMock.mockReturnValue(() => 'user-1')
|
||||
actorStore.userId = 'user-1'
|
||||
|
||||
store.dispatch('setVisualLastReadMessageId', { token: TOKEN, id: 100 })
|
||||
await store.dispatch('clearLastReadMessage', {
|
||||
|
|
@ -710,7 +708,6 @@ describe('messagesStore', () => {
|
|||
})
|
||||
|
||||
expect(conversationMock).toHaveBeenCalled()
|
||||
expect(getUserIdMock).toHaveBeenCalled()
|
||||
expect(updateConversationLastReadMessageMock).toHaveBeenCalledWith(expect.anything(), {
|
||||
token: TOKEN,
|
||||
lastReadMessage: 123,
|
||||
|
|
@ -721,7 +718,6 @@ describe('messagesStore', () => {
|
|||
})
|
||||
|
||||
test('clears last read message for federated conversation', async () => {
|
||||
getUserIdMock.mockReturnValue(() => 'federated-user-1')
|
||||
conversationMock.mockReturnValue({
|
||||
lastMessage: {},
|
||||
remoteServer: 'nextcloud.com',
|
||||
|
|
@ -735,7 +731,6 @@ describe('messagesStore', () => {
|
|||
})
|
||||
|
||||
expect(conversationMock).toHaveBeenCalled()
|
||||
expect(getUserIdMock).toHaveBeenCalled()
|
||||
expect(updateConversationLastReadMessageMock).not.toHaveBeenCalled()
|
||||
|
||||
expect(updateLastReadMessage).toHaveBeenCalledWith(TOKEN, null)
|
||||
|
|
@ -743,8 +738,6 @@ describe('messagesStore', () => {
|
|||
})
|
||||
|
||||
test('clears last read message and update visually', async () => {
|
||||
getUserIdMock.mockReturnValue(() => 'user-1')
|
||||
|
||||
store.dispatch('setVisualLastReadMessageId', { token: TOKEN, id: 100 })
|
||||
await store.dispatch('clearLastReadMessage', {
|
||||
token: TOKEN,
|
||||
|
|
@ -752,7 +745,6 @@ describe('messagesStore', () => {
|
|||
})
|
||||
|
||||
expect(conversationMock).toHaveBeenCalled()
|
||||
expect(getUserIdMock).toHaveBeenCalled()
|
||||
expect(updateConversationLastReadMessageMock).toHaveBeenCalledWith(expect.anything(), {
|
||||
token: TOKEN,
|
||||
lastReadMessage: 123,
|
||||
|
|
@ -763,7 +755,8 @@ describe('messagesStore', () => {
|
|||
})
|
||||
|
||||
test('clears last read message for guests', async () => {
|
||||
getUserIdMock.mockReturnValue(() => null)
|
||||
actorStore.userId = null
|
||||
actorStore.actorType = ATTENDEE.ACTOR_TYPE.GUESTS
|
||||
|
||||
store.dispatch('setVisualLastReadMessageId', { token: TOKEN, id: 100 })
|
||||
await store.dispatch('clearLastReadMessage', {
|
||||
|
|
@ -772,7 +765,7 @@ describe('messagesStore', () => {
|
|||
})
|
||||
|
||||
expect(conversationMock).toHaveBeenCalled()
|
||||
expect(getUserIdMock).toHaveBeenCalled()
|
||||
expect(actorStore.isActorGuest).toBe(true)
|
||||
expect(updateConversationLastReadMessageMock).toHaveBeenCalledWith(expect.anything(), {
|
||||
token: TOKEN,
|
||||
lastReadMessage: 123,
|
||||
|
|
@ -783,7 +776,6 @@ describe('messagesStore', () => {
|
|||
})
|
||||
|
||||
test('updates last read message', async () => {
|
||||
getUserIdMock.mockReturnValue(() => 'user-1')
|
||||
const response = generateOCSResponse({
|
||||
payload: {
|
||||
unreadMessages: 0,
|
||||
|
|
@ -800,7 +792,6 @@ describe('messagesStore', () => {
|
|||
})
|
||||
|
||||
expect(conversationMock).toHaveBeenCalled()
|
||||
expect(getUserIdMock).toHaveBeenCalled()
|
||||
expect(updateConversationLastReadMessageMock).toHaveBeenCalledWith(expect.anything(), {
|
||||
token: TOKEN,
|
||||
lastReadMessage: 200,
|
||||
|
|
@ -811,7 +802,6 @@ describe('messagesStore', () => {
|
|||
})
|
||||
|
||||
test('updates last read message and update visually', async () => {
|
||||
getUserIdMock.mockReturnValue(() => 'user-1')
|
||||
const response = generateOCSResponse({
|
||||
payload: {
|
||||
unreadMessages: 0,
|
||||
|
|
@ -828,7 +818,6 @@ describe('messagesStore', () => {
|
|||
})
|
||||
|
||||
expect(conversationMock).toHaveBeenCalled()
|
||||
expect(getUserIdMock).toHaveBeenCalled()
|
||||
expect(updateConversationLastReadMessageMock).toHaveBeenCalledWith(expect.anything(), {
|
||||
token: TOKEN,
|
||||
lastReadMessage: 200,
|
||||
|
|
@ -839,7 +828,8 @@ describe('messagesStore', () => {
|
|||
})
|
||||
|
||||
test('updates last read message for guests', async () => {
|
||||
getUserIdMock.mockReturnValue(() => null)
|
||||
actorStore.userId = null
|
||||
actorStore.actorType = ATTENDEE.ACTOR_TYPE.GUESTS
|
||||
|
||||
store.dispatch('setVisualLastReadMessageId', { token: TOKEN, id: 100 })
|
||||
await store.dispatch('updateLastReadMessage', {
|
||||
|
|
@ -849,7 +839,7 @@ describe('messagesStore', () => {
|
|||
})
|
||||
|
||||
expect(conversationMock).toHaveBeenCalled()
|
||||
expect(getUserIdMock).toHaveBeenCalled()
|
||||
expect(actorStore.isActorGuest).toBe(true)
|
||||
expect(updateConversationLastReadMessageMock).toHaveBeenCalledWith(expect.anything(), {
|
||||
token: TOKEN,
|
||||
lastReadMessage: 200,
|
||||
|
|
@ -1155,28 +1145,13 @@ describe('messagesStore', () => {
|
|||
let addGuestNameAction
|
||||
let cancelFunctionMocks
|
||||
let conversationMock
|
||||
let getActorIdMock
|
||||
let getActorTypeMock
|
||||
let isActorUserMock
|
||||
let isActorGuestMock
|
||||
let getUserIdMock
|
||||
|
||||
beforeEach(() => {
|
||||
testStoreConfig = cloneDeep(messagesStore)
|
||||
const guestNameStore = useGuestNameStore()
|
||||
|
||||
conversationMock = jest.fn()
|
||||
getActorIdMock = jest.fn()
|
||||
getActorTypeMock = jest.fn()
|
||||
isActorUserMock = jest.fn()
|
||||
isActorGuestMock = jest.fn()
|
||||
getUserIdMock = jest.fn()
|
||||
testStoreConfig.getters.conversation = jest.fn().mockReturnValue(conversationMock)
|
||||
testStoreConfig.getters.getActorId = jest.fn().mockReturnValue(getActorIdMock)
|
||||
testStoreConfig.getters.getActorType = jest.fn().mockReturnValue(getActorTypeMock)
|
||||
testStoreConfig.getters.isActorUser = jest.fn().mockReturnValue(isActorUserMock)
|
||||
testStoreConfig.getters.isActorGuest = jest.fn().mockReturnValue(isActorGuestMock)
|
||||
testStoreConfig.getters.getUserId = jest.fn().mockReturnValue(getUserIdMock)
|
||||
|
||||
updateConversationLastMessageAction = jest.fn()
|
||||
updateLastCommonReadMessageAction = jest.fn()
|
||||
|
|
@ -1527,10 +1502,8 @@ describe('messagesStore', () => {
|
|||
})
|
||||
|
||||
test('updates unread mention flag for guest mention', async () => {
|
||||
getActorIdMock.mockReturnValue('me_as_guest')
|
||||
getActorTypeMock.mockReturnValue(ATTENDEE.ACTOR_TYPE.GUESTS)
|
||||
isActorUserMock.mockReturnValue(false)
|
||||
isActorGuestMock.mockReturnValue(true)
|
||||
actorStore.actorId = 'me_as_guest'
|
||||
actorStore.actorType = ATTENDEE.ACTOR_TYPE.GUESTS
|
||||
await testMentionFlag({
|
||||
'mention-0': {
|
||||
type: 'user',
|
||||
|
|
@ -1544,8 +1517,8 @@ describe('messagesStore', () => {
|
|||
})
|
||||
|
||||
test('does not update unread mention flag for a different guest mention', async () => {
|
||||
getActorIdMock.mockReturnValue('me_as_guest')
|
||||
getActorTypeMock.mockReturnValue(ATTENDEE.ACTOR_TYPE.GUESTS)
|
||||
actorStore.actorId = 'me_as_guest'
|
||||
actorStore.actorType = ATTENDEE.ACTOR_TYPE.GUESTS
|
||||
await testMentionFlag({
|
||||
'mention-1': {
|
||||
type: 'guest',
|
||||
|
|
@ -1555,11 +1528,9 @@ describe('messagesStore', () => {
|
|||
})
|
||||
|
||||
test('updates unread mention flag for user mention', async () => {
|
||||
getUserIdMock.mockReturnValue('me_as_user')
|
||||
getActorIdMock.mockReturnValue('me_as_user')
|
||||
getActorTypeMock.mockReturnValue(ATTENDEE.ACTOR_TYPE.USERS)
|
||||
isActorUserMock.mockReturnValue(true)
|
||||
isActorGuestMock.mockReturnValue(false)
|
||||
actorStore.actorId = 'me_as_user'
|
||||
actorStore.userId = 'me_as_user'
|
||||
actorStore.actorType = ATTENDEE.ACTOR_TYPE.USERS
|
||||
await testMentionFlag({
|
||||
'mention-0': {
|
||||
type: 'user',
|
||||
|
|
@ -1573,8 +1544,9 @@ describe('messagesStore', () => {
|
|||
})
|
||||
|
||||
test('does not update unread mention flag for another user mention', async () => {
|
||||
getActorIdMock.mockReturnValue('me_as_user')
|
||||
getActorTypeMock.mockReturnValue(ATTENDEE.ACTOR_TYPE.USERS)
|
||||
actorStore.actorId = 'me_as_user'
|
||||
actorStore.userId = 'me_as_user'
|
||||
actorStore.actorType = ATTENDEE.ACTOR_TYPE.USERS
|
||||
await testMentionFlag({
|
||||
'mention-1': {
|
||||
type: 'user',
|
||||
|
|
@ -1636,9 +1608,6 @@ describe('messagesStore', () => {
|
|||
describe('posting new message', () => {
|
||||
let message1
|
||||
let conversationMock
|
||||
let getUserIdMock
|
||||
let getActorIdMock
|
||||
let getActorTypeMock
|
||||
let updateLastCommonReadMessageAction
|
||||
let updateConversationLastMessageAction
|
||||
let cancelFunctionMocks
|
||||
|
|
@ -1651,15 +1620,11 @@ describe('messagesStore', () => {
|
|||
console.error = jest.fn()
|
||||
|
||||
conversationMock = jest.fn()
|
||||
getUserIdMock = jest.fn()
|
||||
getActorIdMock = jest.fn().mockReturnValue(() => 'actor-id-1')
|
||||
getActorTypeMock = jest.fn().mockReturnValue(() => ATTENDEE.ACTOR_TYPE.USERS)
|
||||
actorStore.actorId = 'actor-id-1'
|
||||
actorStore.actorType = ATTENDEE.ACTOR_TYPE.USERS
|
||||
updateConversationLastMessageAction = jest.fn()
|
||||
updateLastCommonReadMessageAction = jest.fn()
|
||||
testStoreConfig.getters.conversation = jest.fn().mockReturnValue(conversationMock)
|
||||
testStoreConfig.getters.getUserId = jest.fn().mockReturnValue(getUserIdMock)
|
||||
testStoreConfig.getters.getActorId = getActorIdMock
|
||||
testStoreConfig.getters.getActorType = getActorTypeMock
|
||||
testStoreConfig.actions.updateConversationLastMessage = updateConversationLastMessageAction
|
||||
testStoreConfig.actions.updateLastCommonReadMessage = updateLastCommonReadMessageAction
|
||||
// mock this complex local action as we already tested it elsewhere
|
||||
|
|
@ -1697,7 +1662,7 @@ describe('messagesStore', () => {
|
|||
lastMessage: { id: 100 },
|
||||
lastReadMessage: 50,
|
||||
})
|
||||
getUserIdMock.mockReturnValue(() => 'current-user')
|
||||
actorStore.userId = 'current-user'
|
||||
|
||||
const baseMessage = {
|
||||
actorId: 'actor-id-1',
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import {
|
|||
} from '../services/participantsService.js'
|
||||
import SessionStorage from '../services/SessionStorage.js'
|
||||
import { talkBroadcastChannel } from '../services/talkBroadcastChannel.js'
|
||||
import { useActorStore } from '../stores/actor.ts'
|
||||
import { useCallViewStore } from '../stores/callView.ts'
|
||||
import { useGuestNameStore } from '../stores/guestName.js'
|
||||
import { useSessionStore } from '../stores/session.ts'
|
||||
|
|
@ -123,17 +124,14 @@ const getters = {
|
|||
* Gets the array of external session ids.
|
||||
*
|
||||
* @param {object} state - the state object.
|
||||
* @param {object} getters - the getters object.
|
||||
* @param {object} rootState - the rootState object.
|
||||
* @param {object} rootGetters - the rootGetters object.
|
||||
* @return {Array} the typing session IDs array.
|
||||
*/
|
||||
externalTypingSignals: (state, getters, rootState, rootGetters) => (token) => {
|
||||
externalTypingSignals: (state) => (token) => {
|
||||
if (!state.typing[token]) {
|
||||
return []
|
||||
}
|
||||
|
||||
return Object.keys(state.typing[token]).filter((sessionId) => rootGetters.getSessionId() !== sessionId)
|
||||
const actorStore = useActorStore()
|
||||
return Object.keys(state.typing[token]).filter((sessionId) => actorStore.sessionId !== sessionId)
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -149,8 +147,8 @@ const getters = {
|
|||
if (!state.typing[rootGetters.getToken()]) {
|
||||
return false
|
||||
}
|
||||
|
||||
return Object.keys(state.typing[rootGetters.getToken()]).some((sessionId) => rootGetters.getSessionId() === sessionId)
|
||||
const actorStore = useActorStore()
|
||||
return Object.keys(state.typing[rootGetters.getToken()]).some((sessionId) => actorStore.sessionId === sessionId)
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -159,20 +157,19 @@ const getters = {
|
|||
*
|
||||
* @param {object} state - the state object.
|
||||
* @param {object} getters - the getters object.
|
||||
* @param {object} rootState - the rootState object.
|
||||
* @param {object} rootGetters - the rootGetters object.
|
||||
* @return {Array} the participants array (for registered users only).
|
||||
*/
|
||||
participantsListTyping: (state, getters, rootState, rootGetters) => (token) => {
|
||||
participantsListTyping: (state, getters) => (token) => {
|
||||
if (!getters.externalTypingSignals(token).length) {
|
||||
return []
|
||||
}
|
||||
|
||||
const actorStore = useActorStore()
|
||||
return getters.participantsList(token).filter((attendee) => {
|
||||
// Check if participant's sessionId matches with any of sessionIds from signaling...
|
||||
return getters.externalTypingSignals(token).some((sessionId) => attendee.sessionIds.includes(sessionId))
|
||||
// ... and it's not the participant with same actorType and actorId as yourself
|
||||
&& (attendee.actorType !== rootGetters.getActorType() || attendee.actorId !== rootGetters.getActorId())
|
||||
&& !actorStore.checkIfSelfIsActor(attendee)
|
||||
})
|
||||
},
|
||||
|
||||
|
|
@ -1030,16 +1027,17 @@ const actions = {
|
|||
*/
|
||||
async joinConversation(context, { token }) {
|
||||
const forceJoin = SessionStorage.getItem('joined_conversation') === token
|
||||
const actorStore = useActorStore()
|
||||
|
||||
try {
|
||||
const response = await joinConversation({ token, forceJoin })
|
||||
|
||||
// Update the participant and actor session after a force join
|
||||
context.dispatch('setCurrentParticipant', response.data.ocs.data)
|
||||
actorStore.setCurrentParticipant(response.data.ocs.data)
|
||||
context.dispatch('addConversation', response.data.ocs.data)
|
||||
context.dispatch('updateSessionId', {
|
||||
token,
|
||||
participantIdentifier: context.getters.getParticipantIdentifier(),
|
||||
participantIdentifier: actorStore.participantIdentifier,
|
||||
sessionId: response.data.ocs.data.sessionId,
|
||||
})
|
||||
|
||||
|
|
@ -1087,10 +1085,11 @@ const actions = {
|
|||
* @param {string} data.token - conversation token.
|
||||
*/
|
||||
async leaveConversation(context, { token }) {
|
||||
const actorStore = useActorStore()
|
||||
if (context.getters.isInCall(token)) {
|
||||
await context.dispatch('leaveCall', {
|
||||
token,
|
||||
participantIdentifier: context.getters.getParticipantIdentifier(),
|
||||
participantIdentifier: actorStore.participantIdentifier,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import {
|
|||
removeCurrentUserFromConversation,
|
||||
resendInvitations,
|
||||
} from '../services/participantsService.js'
|
||||
import { useActorStore } from '../stores/actor.ts'
|
||||
import { useGuestNameStore } from '../stores/guestName.js'
|
||||
import { useSessionStore } from '../stores/session.ts'
|
||||
import { generateOCSErrorResponse, generateOCSResponse } from '../test-helpers.js'
|
||||
|
|
@ -73,12 +74,14 @@ describe('participantsStore', () => {
|
|||
let localVue = null
|
||||
let store = null
|
||||
let guestNameStore = null
|
||||
let actorStore
|
||||
|
||||
beforeEach(() => {
|
||||
localVue = createLocalVue()
|
||||
localVue.use(Vuex)
|
||||
setActivePinia(createPinia())
|
||||
guestNameStore = useGuestNameStore()
|
||||
actorStore = useActorStore()
|
||||
|
||||
testStoreConfig = cloneDeep(participantsStore)
|
||||
store = new Vuex.Store(testStoreConfig)
|
||||
|
|
@ -795,7 +798,6 @@ describe('participantsStore', () => {
|
|||
|
||||
describe('joining conversation', () => {
|
||||
let getTokenMock
|
||||
let getParticipantIdentifierMock
|
||||
let participantData
|
||||
let joinedConversationEventMock
|
||||
|
||||
|
|
@ -804,9 +806,6 @@ describe('participantsStore', () => {
|
|||
EventBus.once('joined-conversation', joinedConversationEventMock)
|
||||
|
||||
getTokenMock = jest.fn().mockReturnValue(TOKEN)
|
||||
getParticipantIdentifierMock = jest.fn().mockReturnValue({
|
||||
attendeeId: 1,
|
||||
})
|
||||
participantData = {
|
||||
actorId: 'actor-id',
|
||||
sessionId: 'session-id-1',
|
||||
|
|
@ -815,9 +814,11 @@ describe('participantsStore', () => {
|
|||
inCall: PARTICIPANT.CALL_FLAG.DISCONNECTED,
|
||||
}
|
||||
|
||||
actorStore.setCurrentParticipant(Object.assign({}, participantData, {
|
||||
attendeeId: 1,
|
||||
}))
|
||||
|
||||
testStoreConfig.getters.getToken = () => getTokenMock
|
||||
testStoreConfig.getters.getParticipantIdentifier = () => getParticipantIdentifierMock
|
||||
testStoreConfig.actions.setCurrentParticipant = jest.fn()
|
||||
testStoreConfig.actions.addConversation = jest.fn().mockImplementation((context) => {
|
||||
// needed for the updateSessionId call which requires this
|
||||
context.dispatch('addParticipantOnce', {
|
||||
|
|
@ -836,10 +837,9 @@ describe('participantsStore', () => {
|
|||
expect(joinConversation).toHaveBeenCalledWith({ token: TOKEN, forceJoin: false })
|
||||
expect(returnedResponse).toBe(response)
|
||||
|
||||
expect(testStoreConfig.actions.setCurrentParticipant).toHaveBeenCalledWith(expect.anything(), participantData)
|
||||
expect(testStoreConfig.actions.addConversation).toHaveBeenCalledWith(expect.anything(), participantData)
|
||||
|
||||
expect(getParticipantIdentifierMock).toHaveBeenCalled()
|
||||
expect(actorStore.participantIdentifier.sessionId).toBe('session-id-1')
|
||||
|
||||
expect(store.getters.participantsList(TOKEN)[0])
|
||||
.toStrictEqual(participantData)
|
||||
|
|
@ -863,10 +863,9 @@ describe('participantsStore', () => {
|
|||
|
||||
expect(joinConversation).toHaveBeenCalledWith({ token: TOKEN, forceJoin: true })
|
||||
|
||||
expect(testStoreConfig.actions.setCurrentParticipant).toHaveBeenCalledWith(expect.anything(), updatedParticipantData)
|
||||
expect(testStoreConfig.actions.addConversation).toHaveBeenCalledWith(expect.anything(), updatedParticipantData)
|
||||
|
||||
expect(getParticipantIdentifierMock).toHaveBeenCalled()
|
||||
expect(actorStore.participantIdentifier.sessionId).toBe('another-session-id')
|
||||
|
||||
expect(store.getters.participantsList(TOKEN)[0])
|
||||
.toStrictEqual(updatedParticipantData)
|
||||
|
|
@ -881,9 +880,6 @@ describe('participantsStore', () => {
|
|||
})
|
||||
afterEach(() => {
|
||||
jest.useRealTimers()
|
||||
|
||||
expect(testStoreConfig.actions.setCurrentParticipant).not.toHaveBeenCalled()
|
||||
expect(testStoreConfig.actions.addConversation).not.toHaveBeenCalled()
|
||||
expect(sessionStorage.setItem).not.toHaveBeenCalled()
|
||||
expect(joinedConversationEventMock).not.toHaveBeenCalled()
|
||||
|
||||
|
|
@ -970,7 +966,7 @@ describe('participantsStore', () => {
|
|||
})
|
||||
|
||||
test('leaves conversation while in call', async () => {
|
||||
testStoreConfig.getters.getParticipantIdentifier = () => jest.fn().mockReturnValue({
|
||||
actorStore.setCurrentParticipant({
|
||||
attendeeId: 1,
|
||||
sessionId: 'session-id-1',
|
||||
})
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import actorStore from './actorStore.js'
|
||||
import conversationsStore from './conversationsStore.js'
|
||||
import fileUploadStore from './fileUploadStore.js'
|
||||
import messagesStore from './messagesStore.js'
|
||||
|
|
@ -12,7 +11,6 @@ import tokenStore from './tokenStore.js'
|
|||
|
||||
export default {
|
||||
modules: {
|
||||
actorStore,
|
||||
conversationsStore,
|
||||
fileUploadStore,
|
||||
messagesStore,
|
||||
|
|
|
|||
199
src/stores/__tests__/actor.spec.js
Normal file
199
src/stores/__tests__/actor.spec.js
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
/**
|
||||
* SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { getCurrentUser } from '@nextcloud/auth'
|
||||
import { loadState } from '@nextcloud/initial-state'
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { ATTENDEE, PARTICIPANT } from '../../constants.ts'
|
||||
import { getTeams } from '../../services/teamsService.ts'
|
||||
import { generateOCSResponse } from '../../test-helpers.js'
|
||||
import { useActorStore } from '../actor.ts'
|
||||
|
||||
jest.mock('@nextcloud/initial-state', () => ({
|
||||
loadState: jest.fn(() => false),
|
||||
}))
|
||||
jest.mock('../../services/teamsService.ts', () => ({
|
||||
getTeams: jest.fn(() => Promise.resolve({
|
||||
data: {
|
||||
ocs: {
|
||||
data: [],
|
||||
},
|
||||
},
|
||||
})),
|
||||
}))
|
||||
|
||||
jest.mock('@nextcloud/auth', () => ({
|
||||
getCurrentUser: jest.fn(),
|
||||
}))
|
||||
|
||||
describe('actorStore', () => {
|
||||
let actorStore
|
||||
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
actorStore = useActorStore()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks()
|
||||
actorStore.userId = null
|
||||
actorStore.sessionId = null
|
||||
actorStore.attendeeId = null
|
||||
actorStore.actorId = null
|
||||
actorStore.actorType = null
|
||||
actorStore.displayName = ''
|
||||
actorStore.actorGroups = []
|
||||
actorStore.actorTeams = []
|
||||
})
|
||||
|
||||
describe('initialize', () => {
|
||||
test('initialize the store', () => {
|
||||
const user = { uid: 'userId', displayName: 'display-name' }
|
||||
getCurrentUser.mockReturnValue(user)
|
||||
expect(actorStore.actorId).toBeNull()
|
||||
expect(actorStore.displayName).toBe('')
|
||||
|
||||
actorStore.initialize()
|
||||
|
||||
expect(actorStore.actorId).toBe('userId')
|
||||
expect(actorStore.displayName).toBe('display-name')
|
||||
})
|
||||
})
|
||||
|
||||
test('setCurrentUser updates all relevant attributes', () => {
|
||||
actorStore.setCurrentUser({
|
||||
uid: 'userId',
|
||||
displayName: 'display-name',
|
||||
})
|
||||
|
||||
expect(actorStore.userId).toBe('userId')
|
||||
expect(actorStore.displayName).toBe('display-name')
|
||||
expect(actorStore.actorId).toBe('userId')
|
||||
expect(actorStore.actorType).toBe('users')
|
||||
})
|
||||
|
||||
test('setDisplayName updates all relevant attributes', () => {
|
||||
actorStore.setCurrentUser({
|
||||
uid: 'userId',
|
||||
displayName: 'display-name',
|
||||
})
|
||||
actorStore.setDisplayName('new-display-name')
|
||||
|
||||
expect(actorStore.userId).toBe('userId')
|
||||
expect(actorStore.displayName).toBe('new-display-name')
|
||||
})
|
||||
|
||||
test('check if the message actor is the current one', () => {
|
||||
actorStore.setCurrentParticipant({
|
||||
actorId: 'guestId',
|
||||
attendeeId: 1,
|
||||
displayName: 'display-name',
|
||||
participantType: PARTICIPANT.TYPE.GUEST,
|
||||
})
|
||||
|
||||
const message = {
|
||||
actorId: 'guestId',
|
||||
actorType: ATTENDEE.ACTOR_TYPE.GUESTS,
|
||||
message: 'Hello',
|
||||
}
|
||||
|
||||
expect(actorStore.checkIfSelfIsActor(message)).toBe(true)
|
||||
})
|
||||
|
||||
describe('setCurrentParticipant', () => {
|
||||
test('setCurrentParticipant with type GUEST clears user id and updates all relevant attributes', () => {
|
||||
actorStore.setCurrentParticipant({
|
||||
actorId: 'guestActorId',
|
||||
sessionId: 'XXSESSIONIDXX',
|
||||
participantType: PARTICIPANT.TYPE.GUEST,
|
||||
})
|
||||
|
||||
expect(actorStore.userId).toBe(null)
|
||||
expect(actorStore.actorId).toBe('guestActorId')
|
||||
expect(actorStore.actorType).toBe('guests')
|
||||
expect(actorStore.sessionId).toBe('XXSESSIONIDXX')
|
||||
})
|
||||
|
||||
test('setCurrentParticipant with type GUEST_MODERATOR clears user id and updates all relevant attributes', () => {
|
||||
actorStore.setCurrentParticipant({
|
||||
actorId: 'guestActorId',
|
||||
sessionId: 'XXSESSIONIDXX',
|
||||
participantType: PARTICIPANT.TYPE.GUEST_MODERATOR,
|
||||
})
|
||||
|
||||
expect(actorStore.userId).toBe(null)
|
||||
expect(actorStore.actorId).toBe('guestActorId')
|
||||
expect(actorStore.actorType).toBe('guests')
|
||||
expect(actorStore.sessionId).toBe('XXSESSIONIDXX')
|
||||
})
|
||||
|
||||
test('setCurrentParticipant with type USER keeps user id and updates all relevant attributes', () => {
|
||||
actorStore.setCurrentUser({
|
||||
uid: 'userId',
|
||||
displayName: 'display-name',
|
||||
})
|
||||
|
||||
actorStore.setCurrentParticipant({
|
||||
actorId: 'userActorId',
|
||||
sessionId: 'XXSESSIONIDXX',
|
||||
participantType: PARTICIPANT.TYPE.USER,
|
||||
})
|
||||
|
||||
expect(actorStore.sessionId).toBe('XXSESSIONIDXX')
|
||||
|
||||
// user values unchanged
|
||||
expect(actorStore.userId).toBe('userId')
|
||||
expect(actorStore.displayName).toBe('display-name')
|
||||
expect(actorStore.actorId).toBe('userId')
|
||||
expect(actorStore.actorType).toBe('users')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Groups and Teams', () => {
|
||||
test('isActorMemberOfGroup returns true for group member', () => {
|
||||
actorStore.actorGroups = ['group1', 'group2']
|
||||
expect(actorStore.isActorMemberOfGroup('group1')).toBe(true)
|
||||
expect(actorStore.isActorMemberOfGroup('group3')).toBe(false)
|
||||
})
|
||||
|
||||
test('isActorMemberOfTeam returns true for team member', () => {
|
||||
actorStore.actorTeams = ['team1', 'team2']
|
||||
expect(actorStore.isActorMemberOfTeam('team1')).toBe(true)
|
||||
expect(actorStore.isActorMemberOfTeam('team3')).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getCurrentUserTeams', () => {
|
||||
test('does nothing if circles are not enabled', async () => {
|
||||
loadState.mockReturnValue(false)
|
||||
await actorStore.getCurrentUserTeams()
|
||||
expect(getTeams).not.toHaveBeenCalled()
|
||||
expect(actorStore.actorTeams).toEqual([])
|
||||
})
|
||||
|
||||
test('sets actorTeams from API response', async () => {
|
||||
loadState.mockReturnValue(true)
|
||||
getTeams.mockResolvedValue(generateOCSResponse({
|
||||
payload: [
|
||||
{ id: 'team1' },
|
||||
{ id: 'team2' },
|
||||
],
|
||||
}))
|
||||
await actorStore.getCurrentUserTeams()
|
||||
expect(getTeams).toHaveBeenCalled()
|
||||
expect(actorStore.actorTeams).toEqual(['team1', 'team2'])
|
||||
})
|
||||
|
||||
test('logs error if getTeams throws', async () => {
|
||||
loadState.mockReturnValue(true)
|
||||
const error = new Error('fail')
|
||||
getTeams.mockRejectedValue(error)
|
||||
const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {})
|
||||
await actorStore.getCurrentUserTeams()
|
||||
expect(consoleSpy).toHaveBeenCalledWith(error)
|
||||
consoleSpy.mockRestore()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -6,8 +6,8 @@ import { t } from '@nextcloud/l10n'
|
|||
*/
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { setGuestUserName } from '../../services/participantsService.js'
|
||||
import vuexStore from '../../store/index.js'
|
||||
import { generateOCSErrorResponse } from '../../test-helpers.js'
|
||||
import { useActorStore } from '../actor.ts'
|
||||
import { useGuestNameStore } from '../guestName.js'
|
||||
|
||||
jest.mock('../../services/participantsService', () => ({
|
||||
|
|
@ -20,10 +20,12 @@ jest.mock('@nextcloud/auth', () => ({
|
|||
|
||||
describe('guestNameStore', () => {
|
||||
let store
|
||||
let actorStore
|
||||
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
store = useGuestNameStore()
|
||||
actorStore = useActorStore()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
|
|
@ -151,7 +153,7 @@ describe('guestNameStore', () => {
|
|||
actorDisplayName: t('spreed', 'Guest'),
|
||||
}
|
||||
|
||||
vuexStore.dispatch('setCurrentUser', { uid: 'actor-id1' })
|
||||
actorStore.setCurrentUser({ uid: 'actor-id1' })
|
||||
|
||||
const newName = 'actor 1'
|
||||
|
||||
|
|
@ -165,7 +167,7 @@ describe('guestNameStore', () => {
|
|||
expect(setGuestUserName).toHaveBeenCalledWith(actor1.token, newName)
|
||||
expect(setGuestNickname).toHaveBeenCalledWith(newName)
|
||||
expect(store.getGuestName('token-1', 'actor-id1')).toBe('actor 1')
|
||||
expect(vuexStore.getters.getDisplayName()).toBe('actor 1')
|
||||
expect(actorStore.displayName).toBe('actor 1')
|
||||
})
|
||||
|
||||
test('removes display name from local storage when user sumbits an empty new name', async () => {
|
||||
|
|
@ -177,7 +179,7 @@ describe('guestNameStore', () => {
|
|||
}
|
||||
const newName = ''
|
||||
|
||||
vuexStore.dispatch('setCurrentUser', { uid: 'actor-id1' })
|
||||
actorStore.setCurrentUser({ uid: 'actor-id1' })
|
||||
|
||||
// Mock implementation of setGuestUserName
|
||||
setGuestUserName.mockResolvedValue()
|
||||
|
|
@ -199,7 +201,7 @@ describe('guestNameStore', () => {
|
|||
}
|
||||
console.error = jest.fn()
|
||||
|
||||
vuexStore.dispatch('setCurrentUser', { uid: 'actor-id1' })
|
||||
actorStore.setCurrentUser({ uid: 'actor-id1' })
|
||||
store.addGuestName(actor1, { noUpdate: false })
|
||||
|
||||
const newName = 'actor 1'
|
||||
|
|
@ -213,6 +215,6 @@ describe('guestNameStore', () => {
|
|||
|
||||
// Assert
|
||||
expect(setGuestUserName).toHaveBeenCalledWith(actor1.token, newName)
|
||||
expect(vuexStore.getters.getDisplayName()).toBe(actor1.actorDisplayName)
|
||||
expect(actorStore.displayName).toBe(actor1.actorDisplayName)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
177
src/stores/actor.ts
Normal file
177
src/stores/actor.ts
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
/**
|
||||
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
/**
|
||||
* This store helps to identify a current actor in all cases.
|
||||
* In Talk not every user is a local nextcloud user, so identifying
|
||||
* solely by userId is not enough.
|
||||
* If an as no userId, they are a guest and identified by actorType + sessionId.
|
||||
*/
|
||||
|
||||
import type { NextcloudUser } from '@nextcloud/auth'
|
||||
import type { Participant } from '../types/index.ts'
|
||||
|
||||
import { getCurrentUser } from '@nextcloud/auth'
|
||||
import { loadState } from '@nextcloud/initial-state'
|
||||
import { defineStore } from 'pinia'
|
||||
import { computed, ref } from 'vue'
|
||||
import { ATTENDEE, PARTICIPANT } from '../constants.ts'
|
||||
import { getTeams } from '../services/teamsService.ts'
|
||||
|
||||
export const useActorStore = defineStore('actor', () => {
|
||||
const userId = ref<string | null>(null)
|
||||
const sessionId = ref<string | null>(null)
|
||||
const attendeeId = ref<number | null>(null)
|
||||
const actorId = ref<string | null>(null)
|
||||
const actorType = ref<string | null>(null)
|
||||
const displayName = ref<string>('')
|
||||
const actorGroups = ref<string[]>(loadState('spreed', 'user_group_ids', []))
|
||||
const actorTeams = ref<string[]>([])
|
||||
|
||||
const isLoggedIn = computed(() => userId.value !== null)
|
||||
// TODO check usage for computed below, migrate to isLoggedIn where appropriate
|
||||
const isActorUser = computed(() => actorType.value === ATTENDEE.ACTOR_TYPE.USERS)
|
||||
const isActorGuest = computed(() => actorType.value === ATTENDEE.ACTOR_TYPE.GUESTS)
|
||||
const participantIdentifier = computed(() => ({
|
||||
attendeeId: attendeeId.value,
|
||||
actorType: actorType.value,
|
||||
actorId: actorId.value,
|
||||
sessionId: sessionId.value,
|
||||
}))
|
||||
|
||||
// Initialize the store
|
||||
initialize()
|
||||
|
||||
/**
|
||||
* Initialize the actor store.
|
||||
*/
|
||||
function initialize() {
|
||||
if (getCurrentUser()) {
|
||||
console.debug('Setting current user')
|
||||
setCurrentUser(getCurrentUser())
|
||||
getCurrentUserTeams()
|
||||
} else {
|
||||
console.debug('Can not set current user because it\'s a guest')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the actor is a member of a group
|
||||
*
|
||||
* @param groupId The group id
|
||||
*/
|
||||
function isActorMemberOfGroup(groupId: string) {
|
||||
return actorGroups.value.includes(groupId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the actor is a member of a team
|
||||
*
|
||||
* @param teamId The team id
|
||||
*/
|
||||
function isActorMemberOfTeam(teamId: string) {
|
||||
return actorTeams.value.includes(teamId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the message is from the current actor
|
||||
*
|
||||
* @param payload object to check for
|
||||
*/
|
||||
function checkIfSelfIsActor(payload: { actorId?: string, actorType?: string }) {
|
||||
return payload.actorId === actorId.value
|
||||
&& payload.actorType === actorType.value
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the display name of the actor
|
||||
*
|
||||
* @param newDisplayName The name to set
|
||||
*/
|
||||
function setDisplayName(newDisplayName: string) {
|
||||
displayName.value = newDisplayName
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the actor from the current user
|
||||
*
|
||||
* @param user A NextcloudUser object as returned by @nextcloud/auth
|
||||
* @param user.uid The user id of the user
|
||||
* @param user.displayName The display name of the user
|
||||
*/
|
||||
function setCurrentUser(user: NextcloudUser | null) {
|
||||
if (!user) {
|
||||
return
|
||||
}
|
||||
userId.value = user.uid
|
||||
displayName.value = user.displayName || user.uid
|
||||
actorType.value = ATTENDEE.ACTOR_TYPE.USERS
|
||||
actorId.value = user.uid
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the actor from the current participant
|
||||
*
|
||||
* @param participant The participant data
|
||||
* @param participant.attendeeId The attendee id of the participant
|
||||
* @param participant.participantType The type of the participant
|
||||
* @param participant.sessionId The session id of the participant
|
||||
* @param participant.actorId The actor id of the participant
|
||||
*/
|
||||
function setCurrentParticipant(participant: Participant & { sessionId: string }) {
|
||||
sessionId.value = participant.sessionId
|
||||
attendeeId.value = participant.attendeeId
|
||||
// FIXME other actor types like EMAILS
|
||||
if (participant.participantType === PARTICIPANT.TYPE.GUEST
|
||||
|| participant.participantType === PARTICIPANT.TYPE.GUEST_MODERATOR) {
|
||||
// FIXME displayName.value = ''
|
||||
userId.value = null
|
||||
actorType.value = ATTENDEE.ACTOR_TYPE.GUESTS
|
||||
actorId.value = participant.actorId
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Sets current user teams, if circles app enabled
|
||||
*
|
||||
*/
|
||||
async function getCurrentUserTeams() {
|
||||
if (!loadState('spreed', 'circles_enabled', false)) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await getTeams()
|
||||
const teams = response.data.ocs.data.map((team) => team.id)
|
||||
actorTeams.value = teams
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
userId,
|
||||
sessionId,
|
||||
attendeeId,
|
||||
actorId,
|
||||
actorType,
|
||||
displayName,
|
||||
actorGroups,
|
||||
actorTeams,
|
||||
isLoggedIn,
|
||||
isActorUser,
|
||||
isActorGuest,
|
||||
participantIdentifier,
|
||||
|
||||
isActorMemberOfGroup,
|
||||
isActorMemberOfTeam,
|
||||
checkIfSelfIsActor,
|
||||
|
||||
initialize,
|
||||
setDisplayName,
|
||||
setCurrentUser,
|
||||
setCurrentParticipant,
|
||||
getCurrentUserTeams,
|
||||
}
|
||||
})
|
||||
|
|
@ -8,7 +8,7 @@ import { t } from '@nextcloud/l10n'
|
|||
import { defineStore } from 'pinia'
|
||||
import Vue from 'vue'
|
||||
import { setGuestUserName } from '../services/participantsService.js'
|
||||
import store from '../store/index.js'
|
||||
import { useActorStore } from './actor.ts'
|
||||
|
||||
export const useGuestNameStore = defineStore('guestName', {
|
||||
state: () => ({
|
||||
|
|
@ -77,11 +77,12 @@ export const useGuestNameStore = defineStore('guestName', {
|
|||
* @param {string} name the new guest name
|
||||
*/
|
||||
async submitGuestUsername(token, name) {
|
||||
const actorId = store.getters.getActorId()
|
||||
const actorStore = useActorStore()
|
||||
const actorId = actorStore.actorId
|
||||
const previousName = this.getGuestName(token, actorId)
|
||||
|
||||
try {
|
||||
store.dispatch('setDisplayName', name)
|
||||
actorStore.setDisplayName(name)
|
||||
this.addGuestName({
|
||||
token,
|
||||
actorId,
|
||||
|
|
@ -93,7 +94,7 @@ export const useGuestNameStore = defineStore('guestName', {
|
|||
setGuestNickname(name || t('spreed', 'Guest'))
|
||||
emit('talk:guest-name:added')
|
||||
} catch (error) {
|
||||
store.dispatch('setDisplayName', previousName)
|
||||
actorStore.setDisplayName(previousName)
|
||||
this.addGuestName({
|
||||
token,
|
||||
actorId,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { useActorStore } from '../stores/actor.ts'
|
||||
import pinia from '../stores/pinia.ts'
|
||||
import SignalingParticipantList from './SignalingParticipantList.js'
|
||||
|
||||
/**
|
||||
|
|
@ -17,6 +19,7 @@ import SignalingParticipantList from './SignalingParticipantList.js'
|
|||
*/
|
||||
export default function SignalingTypingHandler(store) {
|
||||
this._store = store
|
||||
this._actorStore = useActorStore(pinia)
|
||||
|
||||
this._signaling = null
|
||||
this._signalingParticipantList = new SignalingParticipantList()
|
||||
|
|
@ -74,7 +77,7 @@ SignalingTypingHandler.prototype = {
|
|||
return
|
||||
}
|
||||
|
||||
const currentNextcloudSessionId = this._store.getters.getSessionId()
|
||||
const currentNextcloudSessionId = this._actorStore.sessionId
|
||||
|
||||
for (const participant of this._signalingParticipantList.getParticipants()) {
|
||||
if (participant.nextcloudSessionId === currentNextcloudSessionId) {
|
||||
|
|
@ -89,7 +92,7 @@ SignalingTypingHandler.prototype = {
|
|||
|
||||
this._store.dispatch('setTyping', {
|
||||
token: this._store.getters.getToken(),
|
||||
sessionId: this._store.getters.getSessionId(),
|
||||
sessionId: this._actorStore.sessionId,
|
||||
typing,
|
||||
})
|
||||
},
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
import { cloneDeep } from 'lodash'
|
||||
import Vuex from 'vuex'
|
||||
import storeConfig from '../store/storeConfig.js'
|
||||
import { useActorStore } from '../stores/actor.ts'
|
||||
import SignalingTypingHandler from './SignalingTypingHandler.js'
|
||||
|
||||
describe('SignalingTypingHandler', () => {
|
||||
|
|
@ -74,6 +75,7 @@ describe('SignalingTypingHandler', () => {
|
|||
beforeEach(() => {
|
||||
const testStoreConfig = cloneDeep(storeConfig)
|
||||
store = new Vuex.Store(testStoreConfig)
|
||||
const actorStore = useActorStore()
|
||||
|
||||
signaling = new function() {
|
||||
this._handlers = {}
|
||||
|
|
@ -115,7 +117,7 @@ describe('SignalingTypingHandler', () => {
|
|||
signalingTypingHandler = new SignalingTypingHandler(store)
|
||||
signalingTypingHandler._signalingParticipantList.getParticipants = jest.fn()
|
||||
|
||||
store.dispatch('setCurrentParticipant', {
|
||||
actorStore.setCurrentParticipant({
|
||||
sessionId: 'localNextcloudSessionId',
|
||||
attendeeId: 'localAttendeeId',
|
||||
})
|
||||
|
|
|
|||
|
|
@ -19,11 +19,15 @@ import { EventBus } from '../services/EventBus.ts'
|
|||
import { rejoinConversation } from '../services/participantsService.js'
|
||||
import { pullSignalingMessages } from '../services/signalingService.js'
|
||||
import store from '../store/index.js'
|
||||
import { useActorStore } from '../stores/actor.ts'
|
||||
import pinia from '../stores/pinia.ts'
|
||||
import CancelableRequest from './cancelableRequest.js'
|
||||
import Encryption from './e2ee/encryption.js'
|
||||
import { convertToUnix } from './formattedTime.ts'
|
||||
import { messagePleaseTryToReload } from './talkDesktopUtils.ts'
|
||||
|
||||
const actorStore = useActorStore(pinia)
|
||||
|
||||
const Signaling = {
|
||||
Base: {},
|
||||
Internal: {},
|
||||
|
|
@ -898,7 +902,7 @@ Signaling.Standalone.prototype.forceReconnect = function(newSession, flags) {
|
|||
|
||||
this.nextcloudSessionId = response.data.ocs.data.sessionId
|
||||
|
||||
store.dispatch('setCurrentParticipant', response.data.ocs.data)
|
||||
actorStore.setCurrentParticipant(response.data.ocs.data)
|
||||
store.commit('setInCall', {
|
||||
token: this.currentRoomToken,
|
||||
sessionId: this.nextcloudSessionId,
|
||||
|
|
|
|||
|
|
@ -10,9 +10,13 @@
|
|||
* It is expected that the speaking status of participant will be
|
||||
* modified only when the current conversation is joined and call is started.
|
||||
*/
|
||||
|
||||
import { useActorStore } from '../../stores/actor.ts'
|
||||
import pinia from '../../stores/pinia.ts'
|
||||
export default class SpeakingStatusHandler {
|
||||
// Constants, properties
|
||||
#store
|
||||
#actorStore
|
||||
#localMediaModel
|
||||
#localCallParticipantModel
|
||||
#callParticipantCollection
|
||||
|
|
@ -26,6 +30,7 @@ export default class SpeakingStatusHandler {
|
|||
|
||||
constructor(store, localMediaModel, localCallParticipantModel, callParticipantCollection) {
|
||||
this.#store = store
|
||||
this.#actorStore = useActorStore(pinia)
|
||||
this.#localMediaModel = localMediaModel
|
||||
this.#localCallParticipantModel = localCallParticipantModel
|
||||
this.#callParticipantCollection = callParticipantCollection
|
||||
|
|
@ -95,7 +100,7 @@ export default class SpeakingStatusHandler {
|
|||
*/
|
||||
#handleLocalSpeaking(localMediaModel, speaking) {
|
||||
this.#store.dispatch('setSpeaking', {
|
||||
attendeeId: this.#store.getters.getAttendeeId(),
|
||||
attendeeId: this.#actorStore.attendeeId,
|
||||
speaking,
|
||||
})
|
||||
}
|
||||
|
|
@ -106,7 +111,7 @@ export default class SpeakingStatusHandler {
|
|||
*/
|
||||
#handleLocalPeerId() {
|
||||
this.#store.dispatch('setSpeaking', {
|
||||
attendeeId: this.#store.getters.getAttendeeId(),
|
||||
attendeeId: this.#actorStore.attendeeId,
|
||||
speaking: this.#localMediaModel.attributes.speaking,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,11 +3,13 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { reactive } from 'vue'
|
||||
import store from '../../../store/index.js'
|
||||
import { reactive, watch } from 'vue'
|
||||
import { useActorStore } from '../../../stores/actor.ts'
|
||||
import pinia from '../../../stores/pinia.ts'
|
||||
import EmitterMixin from '../../EmitterMixin.js'
|
||||
import { ConnectionState } from './CallParticipantModel.js'
|
||||
|
||||
const actorStore = useActorStore(pinia)
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
@ -55,7 +57,10 @@ LocalCallParticipantModel.prototype = {
|
|||
this.set('guestName', null)
|
||||
|
||||
this._webRtc.on('forcedMute', this._handleForcedMuteBound)
|
||||
this._unwatchDisplayNameChange = store.watch((state) => state.actorStore.displayName, this.setGuestName.bind(this))
|
||||
this._unwatchDisplayNameChange = watch(
|
||||
() => actorStore.displayName,
|
||||
this.setGuestName.bind(this),
|
||||
)
|
||||
},
|
||||
|
||||
setPeerId(peerId) {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ import {
|
|||
import { t } from '@nextcloud/l10n'
|
||||
import { PARTICIPANT } from '../../constants.ts'
|
||||
import store from '../../store/index.js'
|
||||
import { useActorStore } from '../../stores/actor.ts'
|
||||
import pinia from '../../stores/pinia.ts'
|
||||
import { Sounds } from '../sounds.js'
|
||||
import SimpleWebRTC from './simplewebrtc/simplewebrtc.js'
|
||||
|
||||
|
|
@ -31,6 +33,7 @@ let callParticipantCollection = null
|
|||
let localCallParticipantModel = null
|
||||
let showedTURNWarning = false
|
||||
let sendCurrentStateWithRepetitionTimeout = null
|
||||
const actorStore = useActorStore(pinia)
|
||||
|
||||
/**
|
||||
* @param {Array} a Source object
|
||||
|
|
@ -198,7 +201,7 @@ function sendCurrentMediaState() {
|
|||
*
|
||||
*/
|
||||
function sendCurrentNick() {
|
||||
webrtc.webrtc.emit('nickChanged', store.getters.getDisplayName())
|
||||
webrtc.webrtc.emit('nickChanged', actorStore.displayName)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -471,10 +474,9 @@ function usersInCallChanged(signaling, users) {
|
|||
&& selfInCall === PARTICIPANT.CALL_FLAG.DISCONNECTED
|
||||
&& localUserInCall) {
|
||||
console.info('Force leaving the call for current participant')
|
||||
|
||||
store.dispatch('leaveCall', {
|
||||
token: store.getters.getToken(),
|
||||
participantIdentifier: store.getters.getParticipantIdentifier(),
|
||||
participantIdentifier: actorStore.participantIdentifier,
|
||||
})
|
||||
|
||||
// Do not return to disconnect already from the other participants
|
||||
|
|
@ -669,7 +671,6 @@ export default function initWebRtc(signaling, _callParticipantCollection, _local
|
|||
message.broadcaster = message.from
|
||||
}
|
||||
})
|
||||
|
||||
webrtc = new SimpleWebRTC({
|
||||
autoRequestMedia: true,
|
||||
debug: false,
|
||||
|
|
@ -678,7 +679,7 @@ export default function initWebRtc(signaling, _callParticipantCollection, _local
|
|||
connection: signaling,
|
||||
enableDataChannels: true,
|
||||
enableSimulcast: signaling.hasFeature('simulcast'),
|
||||
nick: store.getters.getDisplayName(),
|
||||
nick: actorStore.displayName,
|
||||
})
|
||||
|
||||
if (!window.OCA.Talk) {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import PollViewer from '../components/PollViewer/PollViewer.vue'
|
|||
import TopBar from '../components/TopBar/TopBar.vue'
|
||||
import { useIsInCall } from '../composables/useIsInCall.js'
|
||||
import { useStore } from '../composables/useStore.js'
|
||||
import { useActorStore } from '../stores/actor.ts'
|
||||
|
||||
const props = defineProps<{
|
||||
token: string
|
||||
|
|
@ -23,6 +24,7 @@ const store = useStore()
|
|||
const isInCall = useIsInCall()
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const actorStore = useActorStore()
|
||||
|
||||
const isInLobby = computed(() => store.getters.isInLobby)
|
||||
const connectionFailed = computed(() => store.getters.connectionFailed(props.token))
|
||||
|
|
@ -32,7 +34,7 @@ watch(isInLobby, (isInLobby) => {
|
|||
if (isInLobby && isInCall.value) {
|
||||
store.dispatch('leaveCall', {
|
||||
token: props.token,
|
||||
participantIdentifier: store.getters.getParticipantIdentifier(),
|
||||
participantIdentifier: actorStore.participantIdentifier,
|
||||
})
|
||||
}
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue