diff options
7 files changed, 157 insertions, 62 deletions
diff --git a/css/authenticate.css b/css/authenticate.css deleted file mode 100644 index 781d9ea03..000000000 --- a/css/authenticate.css +++ /dev/null @@ -1,53 +0,0 @@ -form fieldset { - display: flex !important; - flex-direction: column; -} - -#password { - margin-right: 0 !important; - height: 45px; - box-sizing: border-box; - flex: 1 1 auto; - width: 100% !important; - min-width: 0; /* FF hack for to override default value */ - - /* The padding needs to be set here instead of for "input[type="password"]" - * elements to prevent being overriden by a more specific rule in the - * server. */ - padding-right: 44px; -} - -input[type="password"]:focus + .icon-confirm:not(:disabled) { - opacity: .6; -} - -input[type="password"] + .icon-confirm { - position: absolute; - right: 15px; - - /* Needed to honour the height set below for "input[type='submit']" by - * overriding a rule set in the server. */ - height: 45px; - - border: none; - /* Needed to override an important rule set in the server. */ - background-color: transparent !important; - - opacity: .3; -} - -input[type="password"] + .icon-confirm:hover:not(:disabled), -input[type="password"] + .icon-confirm:focus:not(:disabled), -input[type="password"] + .icon-confirm:active:not(:disabled) { - opacity: 1; -} - -input[type='submit'] { - width: 45px; - height: 45px; - margin-left: 0 !important; -} - -fieldset > p { - display: inline-flex; -} diff --git a/src/components/LeftSidebar/NewGroupConversation/NewGroupConversation.vue b/src/components/LeftSidebar/NewGroupConversation/NewGroupConversation.vue index 10141074f..99fe8fbda 100644 --- a/src/components/LeftSidebar/NewGroupConversation/NewGroupConversation.vue +++ b/src/components/LeftSidebar/NewGroupConversation/NewGroupConversation.vue @@ -45,6 +45,18 @@ <SetConversationType v-model="isPublic" :conversation-name="conversationName" /> + <template v-if="isPublic"> + <input + id="password-checkbox" + type="checkbox" + class="checkbox" + :checked="passwordProtect" + @input="handleCheckboxInput"> + <label for="password-checkbox">{{ t('spreed', 'Password protect') }}</label> + <PasswordProtect + v-if="passwordProtect" + v-model="password" /> + </template> </template> <template v-if="page === 1"> <SetContacts @@ -108,8 +120,10 @@ import { addParticipant } from '../../../services/participantsService' import { createPublicConversation, createPrivateConversation, + setConversationPassword, } from '../../../services/conversationsService' import { generateUrl } from '@nextcloud/router' +import PasswordProtect from './PasswordProtect/PasswordProtect' export default { @@ -124,6 +138,7 @@ export default { SetConversationType, Confirmation, Popover, + PasswordProtect, }, data() { @@ -137,6 +152,8 @@ export default { selectedParticipants: [], success: false, error: false, + password: '', + passwordProtect: false, } }, @@ -150,7 +167,7 @@ export default { } else return '' }, disabled() { - return this.conversationName === '' + return this.conversationName === '' || (this.passwordProtect && this.password === '') }, }, @@ -169,6 +186,7 @@ export default { this.selectedParticipants = [] this.success = false this.error = false + this.password = '' }, handleSetConversationName(event) { this.page = 1 @@ -199,7 +217,11 @@ export default { if (this.isPublic) { try { await this.createPublicConversation() + if (this.password && this.passwordProtect) { + await setConversationPassword(this.token, this.password) + } } catch (exception) { + console.debug(exception) this.isLoading = false this.error = true // Stop the execution of the method on exceptions. @@ -209,6 +231,7 @@ export default { try { await this.createPrivateConversation() } catch (exception) { + console.debug(exception) this.isLoading = false this.error = true // Stop the execution of the method on exceptions. @@ -252,6 +275,13 @@ export default { this.$router.push({ name: 'conversation', params: { token: this.token } }) .catch(err => console.debug(`Error while pushing the new conversation's route: ${err}`)) }, + handleCheckboxInput(event) { + this.passwordProtect = event.target.checked + // Reinitialise the password value when unchecking the password-protect option. + if (this.passwordProtect === false) { + this.password = '' + } + }, }, } diff --git a/src/components/LeftSidebar/NewGroupConversation/PasswordProtect/PasswordProtect.vue b/src/components/LeftSidebar/NewGroupConversation/PasswordProtect/PasswordProtect.vue new file mode 100644 index 000000000..d6c013341 --- /dev/null +++ b/src/components/LeftSidebar/NewGroupConversation/PasswordProtect/PasswordProtect.vue @@ -0,0 +1,67 @@ +<!-- + - @copyright Copyright (c) 2020 Marco Ambrosini <marcoambrosini@pm.me> + - + - @author Marco Ambrosini <marcoambrosini@pm.me> + - + - @license GNU AGPL version 3 or any later version + - + - This program is free software: you can redistribute it and/or modify + - it under the terms of the GNU Affero General Public License as + - published by the Free Software Foundation, either version 3 of the + - License, or (at your option) any later version. + - + - This program is distributed in the hope that it will be useful, + - but WITHOUT ANY WARRANTY; without even the implied warranty of + - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + - GNU Affero General Public License for more details. + - + - You should have received a copy of the GNU Affero General Public License + - along with this program. If not, see <http://www.gnu.org/licenses/>. +--> + +<template> + <input + ref="password" + v-observe-visibility="visibilityChanged" + type="text" + :value="value" + class="password-protect" + :placeholder="t('spreed', 'Choose a password')" + @input="handleInput"> +</template> + +<script> + +export default { + name: 'PasswordProtect', + + props: { + value: { + type: String, + required: true, + }, + }, + + methods: { + handleInput(event) { + this.$emit('input', event.target.value) + }, + visibilityChanged(isVisible) { + if (isVisible) { + // Focus the input field of the current component. + this.$refs.password.focus() + } + }, + }, + +} + +</script> + +<style lang="scss" scoped> + +.password-protect { + width: calc(100% - 18px); + margin-left: 18px; +} +</style> diff --git a/src/components/LeftSidebar/NewGroupConversation/SetConversationType/SetConversationType.vue b/src/components/LeftSidebar/NewGroupConversation/SetConversationType/SetConversationType.vue index e9cce0cd6..89ee35799 100644 --- a/src/components/LeftSidebar/NewGroupConversation/SetConversationType/SetConversationType.vue +++ b/src/components/LeftSidebar/NewGroupConversation/SetConversationType/SetConversationType.vue @@ -28,9 +28,6 @@ :checked="value" @change="handleInput"> <label for="checkbox" class="conversation-type__label">{{ t('spreed', 'Allow guests to join via link ') }}</label> - <p class="conversation-type__hint"> - {{ t('spreed', `If checked, you will be able to share this conversation with unregistered users once the conversation is created.`) }} - </p> </div> </template> diff --git a/src/components/RightSidebar/RightSidebar.vue b/src/components/RightSidebar/RightSidebar.vue index 10ae4d655..1c329a463 100644 --- a/src/components/RightSidebar/RightSidebar.vue +++ b/src/components/RightSidebar/RightSidebar.vue @@ -39,6 +39,24 @@ @change="toggleGuests"> {{ t('spreed', 'Share link') }} </ActionCheckbox> + <!-- password --> + <ActionCheckbox + class="share-link-password-checkbox" + :checked="isPasswordProtected" + @check="handlePasswordEnable" + @uncheck="handlePasswordDisable"> + {{ t('spreed', 'Password protection') }} + </ActionCheckbox> + <ActionInput + v-show="isEditingPassword" + class="share-link-password" + icon="icon-password" + type="password" + :value.sync="password" + autocomplete="new-password" + @submit="handleSetNewPassword"> + {{ t('spreed', 'Enter a password') }} + </ActionInput> <ActionText v-if="canFullModerate" icon="icon-lobby" @@ -98,6 +116,7 @@ import ParticipantsTab from './Participants/ParticipantsTab' import { addToFavorites, removeFromFavorites, + setConversationPassword, } from '../../services/conversationsService' import isInLobby from '../../mixins/isInLobby' @@ -129,6 +148,10 @@ export default { return { contactsLoading: false, lobbyTimerLoading: false, + // The conversation's password + password: '', + // Switch for the password-editing operation + isEditingPassword: false, } }, @@ -231,6 +254,9 @@ export default { showModerationMenu() { return this.canModerate && (this.canFullModerate || this.isSharedPublicly) }, + isPasswordProtected() { + return this.$store.getters.conversations[this.token].hasPassword + }, }, methods: { @@ -279,6 +305,23 @@ export default { this.lobbyTimerLoading = false }, + async handlePasswordDisable() { + // disable the password protection for the current conversation + if (this.conversation.hasPassword) { + await setConversationPassword(this.token, '') + } + this.password = '' + this.isEditingPassword = false + }, + async handlePasswordEnable() { + this.isEditingPassword = true + }, + + async handleSetNewPassword() { + await setConversationPassword(this.token, this.password) + this.password = '' + this.isEditingPassword = false + }, }, } </script> diff --git a/src/services/conversationsService.js b/src/services/conversationsService.js index c9fa47644..daf3e3ab2 100644 --- a/src/services/conversationsService.js +++ b/src/services/conversationsService.js @@ -129,6 +129,16 @@ const createPublicConversation = async function(conversationName) { } /** + * Set a conversation's password + * @param {string} token the conversation's token + * @param {string} password the password to be set + */ +const setConversationPassword = async function(token, password) { + const response = await axios.put(generateOcsUrl('apps/spreed/api/v1', 2) + `room/${token}/password?password=${password}`) + return response +} + +/** * Delete a conversation. * @param {string} token The token of the conversation to be deleted. */ @@ -240,4 +250,5 @@ export { makePublic, makePrivate, changeLobbyState, + setConversationPassword, } diff --git a/templates/authenticate.php b/templates/authenticate.php index 023e62685..f62042e1b 100644 --- a/templates/authenticate.php +++ b/templates/authenticate.php @@ -1,8 +1,8 @@ <?php - /** @var $_ array */ - /** @var $l \OCP\IL10N */ - style('spreed', 'authenticate'); - script('spreed', 'authenticate'); +/** @var $_ array */ +/** @var $l \OCP\IL10N */ +style('core', 'publicshareauth'); +script('core', 'publicshareauth'); ?> <form method="post"> <fieldset class="warning"> @@ -16,7 +16,7 @@ <input type="hidden" name="requesttoken" value="<?php p($_['requesttoken']) ?>" /> <input type="password" name="password" id="password" placeholder="<?php p($l->t('Password')); ?>" value="" - autocomplete="off" autocapitalize="off" autocorrect="off" + autocomplete="new-password" autocapitalize="off" autocorrect="off" autofocus /> <input type="submit" id="password-submit" class="svg icon-confirm input-button-inline" value="" disabled="disabled" /> |