Skip to content

Commit 998626b

Browse files
Merge pull request #4331 from nextcloud/feature/1647/ui-for-readonly-conversation
Add checkbox for locking conversation
2 parents d9e28ca + 51debd5 commit 998626b

File tree

8 files changed

+93
-8
lines changed

8 files changed

+93
-8
lines changed

src/components/ChatView.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export default {
8484
if (this.isGuest) {
8585
return t('spreed', 'You need to be logged in to upload files')
8686
} else if (this.isReadOnly) {
87-
return t('spreed', 'This conversation is read only')
87+
return t('spreed', 'This conversation is read-only')
8888
} else {
8989
return t('spreed', 'Drop your files to upload')
9090
}

src/components/MessagesList/MessagesGroup/Message/Message.vue

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ import RichText from '@juliushaertl/vue-richtext'
8686
import Quote from '../../../Quote'
8787
import { EventBus } from '../../../../services/EventBus'
8888
import emojiRegex from 'emoji-regex'
89-
import { PARTICIPANT } from '../../../../constants'
89+
import { PARTICIPANT, CONVERSATION } from '../../../../constants'
9090
import moment from '@nextcloud/moment'
9191
9292
export default {
@@ -217,7 +217,12 @@ export default {
217217
218218
computed: {
219219
hasActions() {
220-
return this.isReplyable
220+
return this.isReplyable && !this.isConversationReadOnly
221+
},
222+
223+
isConversationReadOnly() {
224+
const conversation = this.$store.getters.conversation(this.token)
225+
return conversation.readOnly === CONVERSATION.STATE.READ_ONLY
221226
},
222227
223228
isSystemMessage() {

src/components/NewMessageForm/AdvancedInput/AdvancedInput.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ export default {
175175
*/
176176
placeholderText: {
177177
type: String,
178-
default: t('spreed', 'Write message, @ to mention someone …'),
178+
default: '',
179179
},
180180
181181
/**

src/components/NewMessageForm/NewMessageForm.vue

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
</Actions>
5959
</div>
6060
<div
61+
v-if="!isReadOnly"
6162
class="new-message-form__button">
6263
<EmojiPicker @select="addEmoji">
6364
<button
@@ -80,11 +81,14 @@
8081
ref="advancedInput"
8182
v-model="text"
8283
:token="token"
84+
:active-input="!isReadOnly"
85+
:placeholder-text="placeholderText"
8386
@update:contentEditable="contentEditableToParsed"
8487
@submit="handleSubmit"
8588
@files-pasted="handleFiles" />
8689
</div>
8790
<button
91+
:disabled="isReadOnly"
8892
type="submit"
8993
:aria-label="t('spreed', 'Send message')"
9094
class="new-message-form__button submit icon-confirm-fade"
@@ -96,7 +100,7 @@
96100

97101
<script>
98102
import AdvancedInput from './AdvancedInput/AdvancedInput'
99-
import { getFilePickerBuilder } from '@nextcloud/dialogs'
103+
import { getFilePickerBuilder, showError } from '@nextcloud/dialogs'
100104
import { postNewMessage } from '../../services/messagesService'
101105
import Quote from '../Quote'
102106
import Actions from '@nextcloud/vue/dist/Components/Actions'
@@ -149,6 +153,16 @@ export default {
149153
}
150154
},
151155
156+
isReadOnly() {
157+
return this.conversation.readOnly === CONVERSATION.STATE.READ_ONLY
158+
},
159+
160+
placeholderText() {
161+
return this.isReadOnly
162+
? t('spreed', 'This conversation has been locked')
163+
: t('spreed', 'Write message, @ to mention someone …')
164+
},
165+
152166
messageToBeReplied() {
153167
return this.$store.getters.getMessageToBeReplied(this.token)
154168
},
@@ -158,7 +172,7 @@ export default {
158172
},
159173
160174
canShareAndUploadFiles() {
161-
return !this.currentUserIsGuest && this.conversation.readOnly === CONVERSATION.STATE.READ_WRITE
175+
return !this.currentUserIsGuest && !this.isReadOnly
162176
},
163177
164178
attachmentFolder() {
@@ -238,8 +252,8 @@ export default {
238252
* Sends the new message
239253
*/
240254
async handleSubmit() {
241-
242255
if (this.parsedText !== '') {
256+
const oldMessage = this.parsedText
243257
const temporaryMessage = createTemporaryMessage(this.parsedText, this.token)
244258
this.$store.dispatch('addTemporaryMessage', temporaryMessage)
245259
this.text = ''
@@ -270,7 +284,22 @@ export default {
270284
})
271285
}
272286
} catch (error) {
273-
console.debug(`error while submitting message ${error}`)
287+
let statusCode = null
288+
console.debug(`error while submitting message ${error}`, error)
289+
if (error.isAxiosError) {
290+
statusCode = error.response.status
291+
}
292+
// 403 when room is read-only, 412 when switched to lobby mode
293+
if (statusCode === 403 || statusCode === 412) {
294+
showError(t('spreed', 'No permission to post messages in this conversation'))
295+
} else {
296+
showError(t('spreed', 'Could not post message: {errorMessage}', { errorMessage: error.message || error }))
297+
}
298+
299+
// restore message to allow re-sending
300+
this.$store.dispatch('deleteMessage', temporaryMessage)
301+
this.text = oldMessage
302+
this.parsedText = oldMessage
274303
}
275304
}
276305
},

src/components/TopBar/CallButton.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ export default {
117117
return (!this.conversation.canStartCall
118118
&& !this.conversation.hasCall)
119119
|| this.isBlockedByLobby
120+
|| this.conversation.readOnly
120121
|| this.isNextcloudTalkHashDirty
121122
},
122123

src/components/TopBar/TopBar.vue

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,12 @@
118118
{{ t('spreed', 'Enter a password') }}
119119
</ActionInput>
120120
<ActionSeparator />
121+
<ActionCheckbox
122+
:checked="isReadOnly"
123+
:disabled="readOnlyStateLoading"
124+
@change="toggleReadOnly">
125+
{{ t('spreed', 'Lock conversation') }}
126+
</ActionCheckbox>
121127
<ActionCheckbox
122128
:checked="hasLobbyEnabled"
123129
@change="toggleLobby">
@@ -204,6 +210,7 @@ export default {
204210
// Switch for the password-editing operation
205211
isEditingPassword: false,
206212
lobbyTimerLoading: false,
213+
readOnlyStateLoading: false,
207214
}
208215
},
209216
@@ -317,6 +324,9 @@ export default {
317324
hasLobbyEnabled() {
318325
return this.conversation.lobbyState === WEBINAR.LOBBY.NON_MODERATORS
319326
},
327+
isReadOnly() {
328+
return this.conversation.readOnly === CONVERSATION.STATE.READ_ONLY
329+
},
320330
isPasswordProtected() {
321331
return this.conversation.hasPassword
322332
},
@@ -457,6 +467,16 @@ export default {
457467
458468
this.lobbyTimerLoading = false
459469
},
470+
471+
async toggleReadOnly() {
472+
this.readOnlyStateLoading = true
473+
await this.$store.dispatch('setReadOnlyState', {
474+
token: this.token,
475+
readOnly: this.isReadOnly ? CONVERSATION.STATE.READ_WRITE : CONVERSATION.STATE.READ_ONLY,
476+
})
477+
this.readOnlyStateLoading = false
478+
},
479+
460480
async handlePasswordDisable() {
461481
// disable the password protection for the current conversation
462482
if (this.conversation.hasPassword) {

src/services/conversationsService.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,22 @@ const changeLobbyState = async function(token, newState, timestamp) {
297297
}
298298
}
299299

300+
/**
301+
* Change the read-only state
302+
* @param {string} token The token of the conversation to be modified
303+
* @param {int} readOnly The new read-only state to set
304+
*/
305+
const changeReadOnlyState = async function(token, readOnly) {
306+
try {
307+
const response = await axios.put(generateOcsUrl('apps/spreed/api/v2', 2) + `room/${token}/read-only`, {
308+
state: readOnly,
309+
})
310+
return response
311+
} catch (error) {
312+
console.debug('Error while updating read-only state: ', error)
313+
}
314+
}
315+
300316
export {
301317
fetchConversations,
302318
fetchConversation,
@@ -312,6 +328,7 @@ export {
312328
makePublic,
313329
makePrivate,
314330
changeLobbyState,
331+
changeReadOnlyState,
315332
setConversationPassword,
316333
setConversationName,
317334
}

src/store/conversationsStore.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
makePublic,
2525
makePrivate,
2626
changeLobbyState,
27+
changeReadOnlyState,
2728
addToFavorites,
2829
removeFromFavorites,
2930
setConversationName,
@@ -206,6 +207,18 @@ const actions = {
206207
commit('addConversation', conversation)
207208
},
208209

210+
async setReadOnlyState({ commit, getters }, { token, readOnly }) {
211+
const conversation = Object.assign({}, getters.conversations[token])
212+
if (!conversation) {
213+
return
214+
}
215+
216+
await changeReadOnlyState(token, readOnly)
217+
conversation.readOnly = readOnly
218+
219+
commit('addConversation', conversation)
220+
},
221+
209222
async setLobbyTimer({ commit, getters }, { token, timestamp }) {
210223
const conversation = Object.assign({}, getters.conversations[token])
211224
if (!conversation) {

0 commit comments

Comments
 (0)