From f77b0cde907561ecea8835d4f51e01bce87437e7 Mon Sep 17 00:00:00 2001 From: Maxim Filippov <colixer@gmail.com> Date: Tue, 19 Nov 2019 20:15:15 +0900 Subject: [PATCH] Confirm user account, resend confirmation email --- src/api/users.js | 20 +++++++++++ src/lang/en.js | 9 ++++- src/store/modules/users.js | 29 ++++++++++++++- .../users/components/MultipleUsersMenu.vue | 35 +++++++++++++++++++ src/views/users/index.vue | 22 ++++++++++++ 5 files changed, 113 insertions(+), 2 deletions(-) diff --git a/src/api/users.js b/src/api/users.js index fb168d6c..3755ee7c 100644 --- a/src/api/users.js +++ b/src/api/users.js @@ -136,4 +136,24 @@ export async function fetchUserStatuses(id, authHost, godmode, token) { }) } +export async function confirmUserEmail(nicknames, authHost, token) { + return await request({ + baseURL: baseName(authHost), + url: '/api/pleroma/admin/users/confirm_email', + method: 'patch', + headers: authHeaders(token), + data: { nicknames } + }) +} + +export async function resendConfirmationEmail(nicknames, authHost, token) { + return await request({ + baseURL: baseName(authHost), + url: '/api/pleroma/admin/users/resend_confirmation_email', + method: 'patch', + headers: authHeaders(token), + data: { nicknames } + }) +} + const authHeaders = (token) => token ? { 'Authorization': `Bearer ${getToken()}` } : {} diff --git a/src/lang/en.js b/src/lang/en.js index 29ba5eb3..dd3326e5 100644 --- a/src/lang/en.js +++ b/src/lang/en.js @@ -175,6 +175,7 @@ export default { external: 'external', deactivated: 'deactivated', active: 'active', + unconfirmed: 'unconfirmed', actions: 'Actions', activate: 'Activate', deactivate: 'Deactivate', @@ -213,6 +214,8 @@ export default { addTagForMultipleUsersConfirmation: 'Are you sure you want to apply tag to all selected users?', removeTagFromMultipleUsersConfirmation: 'Are you sure you want to remove tag from all selected users?', requirePasswordResetConfirmation: 'Are you sure you want to require password reset for all selected users?', + confirmAccountsConfirmation: 'Are you sure you want to confirm emails for all selected users?', + resendEmailConfirmation: 'Are you sure you want to resend confirmation email for all selected users?', mailerMustBeEnabled: 'To require user\'s password reset you must enable mailer.', ok: 'Okay', completed: 'Completed', @@ -230,7 +233,11 @@ export default { invalidNicknameError: 'Username can include "a-z", "A-Z" and "0-9" characters', getPasswordResetToken: 'Get password reset token', passwordResetTokenCreated: 'Password reset token was created', - accountCreated: 'New account was created!' + accountCreated: 'New account was created!', + unconfirmedEmail: 'User didn\'t confirm the email', + confirmAccount: 'Confirm account', + confirmAccounts: 'Confirm accounts', + resendConfirmation: 'Resend confirmation email' }, statuses: { statuses: 'Statuses', diff --git a/src/store/modules/users.js b/src/store/modules/users.js index 0290b888..160b4ff2 100644 --- a/src/store/modules/users.js +++ b/src/store/modules/users.js @@ -12,7 +12,9 @@ import { searchUsers, tagUser, untagUser, - requirePasswordReset + requirePasswordReset, + confirmUserEmail, + resendConfirmationEmail } from '@/api/users' const users = { @@ -151,6 +153,31 @@ const users = { } dispatch('SuccessMessage') }, + async ConfirmUsersEmail({ commit, dispatch, getters, state }, users) { + const updatedUsers = users.map(user => { + return { ...user, confirmation_pending: false } + }) + commit('SWAP_USERS', updatedUsers) + + const usersNicknames = users.map(user => user.nickname) + try { + await confirmUserEmail(usersNicknames, getters.authHost, getters.token) + } catch (_e) { + return + } finally { + dispatch('SearchUsers', { query: state.searchQuery, page: state.currentPage }) + } + dispatch('SuccessMessage') + }, + async ResendConfirmationEmail({ dispatch, getters }, users) { + const usersNicknames = users.map(user => user.nickname) + try { + await resendConfirmationEmail(usersNicknames, getters.authHost, getters.token) + } catch (_e) { + return + } + dispatch('SuccessMessage') + }, async DeleteRight({ commit, dispatch, getters, state }, { users, right }) { const updatedUsers = users.map(user => { return user.local ? { ...user, roles: { ...user.roles, [right]: false }} : user diff --git a/src/views/users/components/MultipleUsersMenu.vue b/src/views/users/components/MultipleUsersMenu.vue index f3be52cf..1fdc029b 100644 --- a/src/views/users/components/MultipleUsersMenu.vue +++ b/src/views/users/components/MultipleUsersMenu.vue @@ -26,6 +26,15 @@ @click.native="revokeRightFromMultipleUsers('moderator')"> {{ $t('users.revokeModerator') }} </el-dropdown-item> + <el-dropdown-item + divided + @click.native="confirmAccountsForMultipleUsers"> + {{ $t('users.confirmAccounts') }} + </el-dropdown-item> + <el-dropdown-item + @click.native="resendConfirmationForMultipleUsers"> + {{ $t('users.resendConfirmation') }} + </el-dropdown-item> <el-dropdown-item divided @click.native="activateMultipleUsers"> @@ -209,6 +218,18 @@ export default { const filtered = this.selectedUsers.filter(user => user.local) filtered.map(user => this.$store.dispatch('RequirePasswordReset', user)) this.$emit('apply-action') + }, + confirmAccounts: () => { + const filtered = this.selectedUsers.filter(user => user.local && user.confirmation_pending) + const confirmAccountFn = async(users) => await this.$store.dispatch('ConfirmUsersEmail', users) + + applyAction(filtered, confirmAccountFn) + }, + resendConfirmation: () => { + const filtered = this.selectedUsers.filter(user => user.local && user.confirmation_pending) + const resendConfirmationFn = async(users) => await this.$store.dispatch('ResendConfirmationEmail', users) + + applyAction(filtered, resendConfirmationFn) } } }, @@ -276,6 +297,20 @@ export default { removeTag(tag) ) }, + confirmAccountsForMultipleUsers() { + const { confirmAccounts } = this.mappers() + this.confirmMessage( + this.$t('users.confirmAccountsConfirmation'), + confirmAccounts + ) + }, + resendConfirmationForMultipleUsers() { + const { resendConfirmation } = this.mappers() + this.confirmMessage( + this.$t('users.resendEmailConfirmation'), + resendConfirmation + ) + }, confirmMessage(message, applyAction) { this.$confirm(message, { confirmButtonText: this.$t('users.ok'), diff --git a/src/views/users/index.vue b/src/views/users/index.vue index f9b5e10f..93b6a7f1 100644 --- a/src/views/users/index.vue +++ b/src/views/users/index.vue @@ -57,6 +57,11 @@ <el-tag v-if="scope.row.roles.moderator"> <span>{{ isDesktop ? $t('users.moderator') : getFirstLetter($t('users.moderator')) }}</span> </el-tag> + <el-tooltip :content="$t('users.unconfirmedEmail')" effect="dark"> + <el-tag v-if="scope.row.confirmation_pending" type="info"> + {{ isDesktop ? $t('users.unconfirmed') : getFirstLetter($t('users.unconfirmed')) }} + </el-tag> + </el-tooltip> </template> </el-table-column> <el-table-column :label="$t('users.actions')" fixed="right"> @@ -88,6 +93,17 @@ @click.native="handleDeletion(scope.row)"> {{ $t('users.deleteAccount') }} </el-dropdown-item> + <el-dropdown-item + v-if="scope.row.local && scope.row.confirmation_pending" + divided + @click.native="handleEmailConfirmation(scope.row)"> + {{ $t('users.confirmAccount') }} + </el-dropdown-item> + <el-dropdown-item + v-if="scope.row.local && scope.row.confirmation_pending" + @click.native="handleConfirmationResend(scope.row)"> + {{ $t('users.resendConfirmation') }} + </el-dropdown-item> <el-dropdown-item :divided="showAdminAction(scope.row)" :class="{ 'active-tag': scope.row.tags.includes('force_nsfw') }" @@ -301,6 +317,12 @@ export default { user.roles[right] ? this.$store.dispatch('DeleteRight', { users: [user], right }) : this.$store.dispatch('AddRight', { users: [user], right }) + }, + handleEmailConfirmation(user) { + this.$store.dispatch('ConfirmUsersEmail', [user]) + }, + handleConfirmationResend(user) { + this.$store.dispatch('ResendConfirmationEmail', [user]) } } } -- GitLab