Merge branch 'feature/create-new-user' into 'master'
Allow to register new user accounts Closes #17 See merge request pleroma/admin-fe!20
This commit is contained in:
commit
46958a3b3c
9 changed files with 448 additions and 91 deletions
|
@ -1,4 +1,4 @@
|
|||
export const users = [
|
||||
export let users = [
|
||||
{ active: true, deactivated: false, id: '2', nickname: 'allis', local: true, external: false, roles: { admin: true, moderator: false }, tags: [] },
|
||||
{ active: true, deactivated: false, id: '10', nickname: 'bob', local: false, external: true, roles: { admin: false, moderator: false }, tags: ['sandbox'] },
|
||||
{ active: false, deactivated: true, id: 'abc', nickname: 'john', local: true, external: false, roles: { admin: false, moderator: false }, tags: ['strip_media'] }
|
||||
|
@ -69,3 +69,9 @@ export async function tagUser(nickname, tag, authHost, token) {
|
|||
export async function untagUser(nickname, tag, authHost, token) {
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
export async function createNewAccount(nickname, email, password, authHost, token) {
|
||||
const newUser = { active: true, deactivated: false, id: '15', nickname, local: true, external: false, roles: { admin: false, moderator: false }, tags: [] }
|
||||
users = [...users, newUser]
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
|
|
@ -2,33 +2,6 @@ import request from '@/utils/request'
|
|||
import { getToken } from '@/utils/auth'
|
||||
import { baseName } from './utils'
|
||||
|
||||
export async function fetchUsers(filters, authHost, token, page = 1) {
|
||||
return await request({
|
||||
baseURL: baseName(authHost),
|
||||
url: `/api/pleroma/admin/users?page=${page}&filters=${filters}`,
|
||||
method: 'get',
|
||||
headers: authHeaders(token)
|
||||
})
|
||||
}
|
||||
|
||||
export async function toggleUserActivation(nickname, authHost, token) {
|
||||
return await request({
|
||||
baseURL: baseName(authHost),
|
||||
url: `/api/pleroma/admin/users/${nickname}/toggle_activation`,
|
||||
method: 'patch',
|
||||
headers: authHeaders(token)
|
||||
})
|
||||
}
|
||||
|
||||
export async function searchUsers(query, filters, authHost, token, page = 1) {
|
||||
return await request({
|
||||
baseURL: baseName(authHost),
|
||||
url: `/api/pleroma/admin/users?query=${query}&page=${page}&filters=${filters}`,
|
||||
method: 'get',
|
||||
headers: authHeaders(token)
|
||||
})
|
||||
}
|
||||
|
||||
export async function addRight(nickname, right, authHost, token) {
|
||||
return await request({
|
||||
baseURL: baseName(authHost),
|
||||
|
@ -38,6 +11,16 @@ export async function addRight(nickname, right, authHost, token) {
|
|||
})
|
||||
}
|
||||
|
||||
export async function createNewAccount(nickname, email, password, authHost, token) {
|
||||
return await request({
|
||||
baseURL: baseName(authHost),
|
||||
url: '/api/pleroma/admin/users',
|
||||
method: 'post',
|
||||
headers: authHeaders(token),
|
||||
data: { nickname, email, password }
|
||||
})
|
||||
}
|
||||
|
||||
export async function deleteRight(nickname, right, authHost, token) {
|
||||
return await request({
|
||||
baseURL: baseName(authHost),
|
||||
|
@ -56,6 +39,24 @@ export async function deleteUser(nickname, authHost, token) {
|
|||
})
|
||||
}
|
||||
|
||||
export async function fetchUsers(filters, authHost, token, page = 1) {
|
||||
return await request({
|
||||
baseURL: baseName(authHost),
|
||||
url: `/api/pleroma/admin/users?page=${page}&filters=${filters}`,
|
||||
method: 'get',
|
||||
headers: authHeaders(token)
|
||||
})
|
||||
}
|
||||
|
||||
export async function searchUsers(query, filters, authHost, token, page = 1) {
|
||||
return await request({
|
||||
baseURL: baseName(authHost),
|
||||
url: `/api/pleroma/admin/users?query=${query}&page=${page}&filters=${filters}`,
|
||||
method: 'get',
|
||||
headers: authHeaders(token)
|
||||
})
|
||||
}
|
||||
|
||||
export async function tagUser(nicknames, tags, authHost, token) {
|
||||
return await request({
|
||||
baseURL: baseName(authHost),
|
||||
|
@ -66,6 +67,15 @@ export async function tagUser(nicknames, tags, authHost, token) {
|
|||
})
|
||||
}
|
||||
|
||||
export async function toggleUserActivation(nickname, authHost, token) {
|
||||
return await request({
|
||||
baseURL: baseName(authHost),
|
||||
url: `/api/pleroma/admin/users/${nickname}/toggle_activation`,
|
||||
method: 'patch',
|
||||
headers: authHeaders(token)
|
||||
})
|
||||
}
|
||||
|
||||
export async function untagUser(nicknames, tags, authHost, token) {
|
||||
return await request({
|
||||
baseURL: baseName(authHost),
|
||||
|
|
|
@ -182,16 +182,46 @@ export default {
|
|||
revokeModerator: 'Revoke Moderator',
|
||||
grantModerator: 'Grant Moderator',
|
||||
activateAccount: 'Activate Account',
|
||||
activateAccounts: 'Activate Accounts',
|
||||
deactivateAccount: 'Deactivate Account',
|
||||
deactivateAccounts: 'Deactivate Accounts',
|
||||
deleteAccount: 'Delete Account',
|
||||
deleteAccounts: 'Delete Accounts',
|
||||
forceNsfw: 'Force posts to be NSFW',
|
||||
stripMedia: 'Force posts not to have media',
|
||||
forceUnlisted: 'Force posts to be unlisted',
|
||||
sandbox: 'Force posts to be followers-only',
|
||||
disableRemoteSubscription: 'Disallow following user from remote instances',
|
||||
disableRemoteSubscriptionForMultiple: 'Disallow following users from remote instances',
|
||||
disableAnySubscription: 'Disallow following user at all',
|
||||
disableAnySubscriptionForMultiple: 'Disallow following users at all',
|
||||
selectUsers: 'Select users to apply actions to multiple users',
|
||||
moderateUsers: 'Moderate multiple users'
|
||||
moderateUsers: 'Moderate multiple users',
|
||||
createAccount: 'Create new user account',
|
||||
apply: 'apply',
|
||||
remove: 'remove',
|
||||
grantRightConfirmation: 'Are you sure you want to grant {right} rights to all selected users?',
|
||||
revokeRightConfirmation: 'Are you sure you want to revoke {right} rights from all selected users?',
|
||||
activateMultipleUsersConfirmation: 'Are you sure you want to activate accounts of all selected users?',
|
||||
deactivateMultipleUsersConfirmation: 'Are you sure you want to deactivate accounts of all selected users?',
|
||||
deleteMultipleUsersConfirmation: 'Are you sure you want to delete accounts of all selected users?',
|
||||
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?',
|
||||
ok: 'Okay',
|
||||
completed: 'Completed',
|
||||
cancel: 'Cancel',
|
||||
canceled: 'Canceled',
|
||||
username: 'Username',
|
||||
email: 'E-mail',
|
||||
password: 'Password',
|
||||
create: 'Create',
|
||||
submitFormError: 'There are errors on the form. Please fix them before continuing.',
|
||||
emptyEmailError: 'Please input the e-mail',
|
||||
invalidEmailError: 'Please input valid e-mail',
|
||||
emptyPasswordError: 'Please input the password',
|
||||
emptyNicknameError: 'Please input the username',
|
||||
invalidNicknameError: 'Username can include "a-z", "A-Z" and "0-9" characters'
|
||||
|
||||
},
|
||||
usersFilter: {
|
||||
inputPlaceholder: 'Select filter',
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { addRight, fetchUsers, deleteRight, deleteUser, searchUsers, tagUser, toggleUserActivation, untagUser } from '@/api/users'
|
||||
import { addRight, createNewAccount, fetchUsers, deleteRight, deleteUser, searchUsers, tagUser, toggleUserActivation, untagUser } from '@/api/users'
|
||||
|
||||
const users = {
|
||||
state: {
|
||||
|
@ -61,6 +61,10 @@ const users = {
|
|||
commit('CLEAR_USERS_FILTERS')
|
||||
dispatch('SearchUsers', { query: state.searchQuery, page: 1 })
|
||||
},
|
||||
async CreateNewAccount({ dispatch, getters, state }, { nickname, email, password }) {
|
||||
await createNewAccount(nickname, email, password, getters.authHost, getters.token)
|
||||
dispatch('FetchUsers', { page: state.currentPage })
|
||||
},
|
||||
async DeleteUser({ commit, getters }, user) {
|
||||
await deleteUser(user.nickname, getters.authHost, getters.token)
|
||||
const updatedUser = { ...user, deactivated: true }
|
||||
|
@ -83,7 +87,7 @@ const users = {
|
|||
async SearchUsers({ commit, dispatch, state, getters }, { query, page }) {
|
||||
if (query.length === 0) {
|
||||
commit('SET_SEARCH_QUERY', query)
|
||||
dispatch('FetchUsers', page)
|
||||
dispatch('FetchUsers', { page })
|
||||
} else {
|
||||
commit('SET_LOADING', true)
|
||||
commit('SET_SEARCH_QUERY', query)
|
||||
|
|
|
@ -29,22 +29,26 @@
|
|||
<el-dropdown-item
|
||||
divided
|
||||
@click.native="activateMultipleUsers">
|
||||
{{ $t('users.activateAccount') }}
|
||||
{{ $t('users.activateAccounts') }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
@click.native="deactivateMultipleUsers">
|
||||
{{ $t('users.deactivateAccount') }}
|
||||
{{ $t('users.deactivateAccounts') }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
@click.native="deleteMultipleUsers">
|
||||
{{ $t('users.deleteAccount') }}
|
||||
{{ $t('users.deleteAccounts') }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item divided class="no-hover">
|
||||
<div class="tag-container">
|
||||
<span class="tag-text">{{ $t('users.forceNsfw') }}</span>
|
||||
<el-button-group class="tag-button-group">
|
||||
<el-button size="mini" @click.native="addTagForMultipleUsers('force_nsfw')">apply</el-button>
|
||||
<el-button size="mini" @click.native="removeTagFromMultipleUsers('force_nsfw')">remove</el-button>
|
||||
<el-button size="mini" @click.native="addTagForMultipleUsers('force_nsfw')">
|
||||
{{ $t('users.apply') }}
|
||||
</el-button>
|
||||
<el-button size="mini" @click.native="removeTagFromMultipleUsers('force_nsfw')">
|
||||
{{ $t('users.remove') }}
|
||||
</el-button>
|
||||
</el-button-group>
|
||||
</div>
|
||||
</el-dropdown-item>
|
||||
|
@ -52,8 +56,12 @@
|
|||
<div class="tag-container">
|
||||
<span class="tag-text">{{ $t('users.stripMedia') }}</span>
|
||||
<el-button-group class="tag-button-group">
|
||||
<el-button size="mini" @click.native="addTagForMultipleUsers('strip_media')">apply</el-button>
|
||||
<el-button size="mini" @click.native="removeTagFromMultipleUsers('strip_media')">remove</el-button>
|
||||
<el-button size="mini" @click.native="addTagForMultipleUsers('strip_media')">
|
||||
{{ $t('users.apply') }}
|
||||
</el-button>
|
||||
<el-button size="mini" @click.native="removeTagFromMultipleUsers('strip_media')">
|
||||
{{ $t('users.remove') }}
|
||||
</el-button>
|
||||
</el-button-group>
|
||||
</div>
|
||||
</el-dropdown-item>
|
||||
|
@ -61,8 +69,12 @@
|
|||
<div class="tag-container">
|
||||
<span class="tag-text">{{ $t('users.forceUnlisted') }}</span>
|
||||
<el-button-group class="tag-button-group">
|
||||
<el-button size="mini" @click.native="addTagForMultipleUsers('force_unlisted')">apply</el-button>
|
||||
<el-button size="mini" @click.native="removeTagFromMultipleUsers('force_unlisted')">remove</el-button>
|
||||
<el-button size="mini" @click.native="addTagForMultipleUsers('force_unlisted')">
|
||||
{{ $t('users.apply') }}
|
||||
</el-button>
|
||||
<el-button size="mini" @click.native="removeTagFromMultipleUsers('force_unlisted')">
|
||||
{{ $t('users.remove') }}
|
||||
</el-button>
|
||||
</el-button-group>
|
||||
</div>
|
||||
</el-dropdown-item>
|
||||
|
@ -70,26 +82,38 @@
|
|||
<div class="tag-container">
|
||||
<span class="tag-text">{{ $t('users.sandbox') }}</span>
|
||||
<el-button-group class="tag-button-group">
|
||||
<el-button size="mini" @click.native="addTagForMultipleUsers('sandbox')">apply</el-button>
|
||||
<el-button size="mini" @click.native="removeTagFromMultipleUsers('sandbox')">remove</el-button>
|
||||
<el-button size="mini" @click.native="addTagForMultipleUsers('sandbox')">
|
||||
{{ $t('users.apply') }}
|
||||
</el-button>
|
||||
<el-button size="mini" @click.native="removeTagFromMultipleUsers('sandbox')">
|
||||
{{ $t('users.remove') }}
|
||||
</el-button>
|
||||
</el-button-group>
|
||||
</div>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item class="no-hover">
|
||||
<div class="tag-container">
|
||||
<span class="tag-text">{{ $t('users.disableRemoteSubscription') }}</span>
|
||||
<span class="tag-text">{{ $t('users.disableRemoteSubscriptionForMultiple') }}</span>
|
||||
<el-button-group class="tag-button-group">
|
||||
<el-button size="mini" @click.native="addTagForMultipleUsers('disable_remote_subscription')">apply</el-button>
|
||||
<el-button size="mini" @click.native="removeTagFromMultipleUsers('disable_remote_subscription')">remove</el-button>
|
||||
<el-button size="mini" @click.native="addTagForMultipleUsers('disable_remote_subscription')">
|
||||
{{ $t('users.apply') }}
|
||||
</el-button>
|
||||
<el-button size="mini" @click.native="removeTagFromMultipleUsers('disable_remote_subscription')">
|
||||
{{ $t('users.remove') }}
|
||||
</el-button>
|
||||
</el-button-group>
|
||||
</div>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item class="no-hover">
|
||||
<div class="tag-container">
|
||||
<span class="tag-text">{{ $t('users.disableAnySubscription') }}</span>
|
||||
<span class="tag-text">{{ $t('users.disableAnySubscriptionForMultiple') }}</span>
|
||||
<el-button-group class="tag-button-group">
|
||||
<el-button size="mini" @click.native="addTagForMultipleUsers('disable_any_subscription')">apply</el-button>
|
||||
<el-button size="mini" @click.native="removeTagFromMultipleUsers('disable_any_subscription')">remove</el-button>
|
||||
<el-button size="mini" @click.native="addTagForMultipleUsers('disable_any_subscription')">
|
||||
{{ $t('users.apply') }}
|
||||
</el-button>
|
||||
<el-button size="mini" @click.native="removeTagFromMultipleUsers('disable_any_subscription')">
|
||||
{{ $t('users.remove') }}
|
||||
</el-button>
|
||||
</el-button-group>
|
||||
</div>
|
||||
</el-dropdown-item>
|
||||
|
@ -157,68 +181,68 @@ export default {
|
|||
grantRightToMultipleUsers(right) {
|
||||
const { grantRight } = this.mappers()
|
||||
this.confirmMessage(
|
||||
`Are you sure you want to grant ${right} rights to all selected users?`,
|
||||
this.$t('users.grantRightConfirmation', { right }),
|
||||
grantRight(right)
|
||||
)
|
||||
},
|
||||
revokeRightFromMultipleUsers(right) {
|
||||
const { revokeRight } = this.mappers()
|
||||
this.confirmMessage(
|
||||
`Are you sure you want to revoke ${right} rights from all selected users?`,
|
||||
this.$t('users.revokeRightConfirmation', { right }),
|
||||
revokeRight(right)
|
||||
)
|
||||
},
|
||||
activateMultipleUsers() {
|
||||
const { activate } = this.mappers()
|
||||
this.confirmMessage(
|
||||
'Are you sure you want to activate accounts of all selected users?',
|
||||
this.$t('users.activateMultipleUsersConfirmation'),
|
||||
activate
|
||||
)
|
||||
},
|
||||
deactivateMultipleUsers() {
|
||||
const { deactivate } = this.mappers()
|
||||
this.confirmMessage(
|
||||
'Are you sure you want to deactivate accounts of all selected users?',
|
||||
this.$t('users.deactivateMultipleUsersConfirmation'),
|
||||
deactivate
|
||||
)
|
||||
},
|
||||
deleteMultipleUsers() {
|
||||
const { remove } = this.mappers()
|
||||
this.confirmMessage(
|
||||
'Are you sure you want to delete accounts of all selected users?',
|
||||
this.$t('users.deleteMultipleUsersConfirmation'),
|
||||
remove
|
||||
)
|
||||
},
|
||||
addTagForMultipleUsers(tag) {
|
||||
const { addTag } = this.mappers()
|
||||
this.confirmMessage(
|
||||
'Are you sure you want to apply tag to all selected users?',
|
||||
this.$t('users.addTagForMultipleUsersConfirmation'),
|
||||
addTag(tag)
|
||||
)
|
||||
},
|
||||
removeTagFromMultipleUsers(tag) {
|
||||
const { removeTag } = this.mappers()
|
||||
this.confirmMessage(
|
||||
'Are you sure you want to remove tag from all selected users?',
|
||||
this.$t('users.removeTagFromMultipleUsersConfirmation'),
|
||||
removeTag(tag)
|
||||
)
|
||||
},
|
||||
confirmMessage(message, applyAction) {
|
||||
this.$confirm(message, {
|
||||
confirmButtonText: 'OK',
|
||||
cancelButtonText: 'Cancel',
|
||||
confirmButtonText: this.$t('users.ok'),
|
||||
cancelButtonText: this.$t('users.cancel'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
applyAction()
|
||||
this.$emit('apply-action')
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: 'Completed'
|
||||
message: this.$t('users.completed')
|
||||
})
|
||||
}).catch(() => {
|
||||
this.$message({
|
||||
type: 'info',
|
||||
message: 'Canceled'
|
||||
message: this.$t('users.canceled')
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -229,9 +253,8 @@ export default {
|
|||
<style rel='stylesheet/scss' lang='scss' scoped>
|
||||
.actions-button {
|
||||
text-align: left;
|
||||
margin: 0 15px 10px 0;
|
||||
width: 350px;
|
||||
padding: 10px 15px;
|
||||
padding: 10px;
|
||||
}
|
||||
.actions-button-container {
|
||||
display: flex;
|
||||
|
@ -240,8 +263,8 @@ export default {
|
|||
.el-dropdown {
|
||||
float: right;
|
||||
}
|
||||
.el-dropdown-menu {
|
||||
margin-right: 15px;
|
||||
.el-icon-edit {
|
||||
margin-right: 5px;
|
||||
}
|
||||
.tag-container {
|
||||
display: flex;
|
151
src/views/users/components/NewAccountDialog.vue
Normal file
151
src/views/users/components/NewAccountDialog.vue
Normal file
|
@ -0,0 +1,151 @@
|
|||
<template>
|
||||
<el-dialog
|
||||
:visible.sync="isVisible"
|
||||
:show-close="false"
|
||||
:title="$t('users.createAccount')"
|
||||
custom-class="create-user-dialog"
|
||||
@open="resetForm">
|
||||
<el-form ref="form" :model="form" :rules="rules" :label-width="getLabelWidth" status-icon>
|
||||
<el-form-item :label="$t('users.username')" prop="nickname" class="create-account-form-item">
|
||||
<el-input v-model="form.nickname" name="nickname" autofocus/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('users.email')" prop="email" class="create-account-form-item">
|
||||
<el-input v-model="form.email" name="email" type="email"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('users.password')" prop="password" class="create-account-form-item">
|
||||
<el-input v-model="form.password" type="password" name="password" autocomplete="off"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer">
|
||||
<el-button @click="closeDialogWindow">{{ $t('users.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="submitForm('form')">{{ $t('users.create') }}</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'NewAccountDialog',
|
||||
props: {
|
||||
dialogFormVisible: {
|
||||
type: Boolean,
|
||||
default: function() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
nickname: '',
|
||||
email: '',
|
||||
password: ''
|
||||
},
|
||||
rules: {
|
||||
nickname: [
|
||||
{ validator: this.validateUsername, trigger: 'blur' }
|
||||
],
|
||||
email: [
|
||||
{ validator: this.validateEmail, trigger: 'blur' }
|
||||
],
|
||||
password: [
|
||||
{ validator: this.validatePassword, trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isDesktop() {
|
||||
return this.$store.state.app.device === 'desktop'
|
||||
},
|
||||
isVisible: {
|
||||
get() {
|
||||
return this.$props.dialogFormVisible
|
||||
},
|
||||
set() {
|
||||
this.closeDialogWindow()
|
||||
}
|
||||
},
|
||||
getLabelWidth() {
|
||||
return this.isDesktop ? '120px' : '80px'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
closeDialogWindow() {
|
||||
this.$emit('closeWindow')
|
||||
},
|
||||
resetForm() {
|
||||
this.$nextTick(() => {
|
||||
this.$refs['form'].resetFields()
|
||||
})
|
||||
},
|
||||
submitForm(formName) {
|
||||
this.$refs[formName].validate((valid) => {
|
||||
if (valid) {
|
||||
this.$emit('createNewAccount', this.$data.form)
|
||||
this.closeDialogWindow()
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: this.$t('users.completed')
|
||||
})
|
||||
} else {
|
||||
this.$message({
|
||||
type: 'error',
|
||||
message: this.$t('users.submitFormError')
|
||||
})
|
||||
return false
|
||||
}
|
||||
})
|
||||
},
|
||||
validateEmail(rule, value, callback) {
|
||||
if (value === '') {
|
||||
return callback(new Error(this.$t('users.emptyEmailError')))
|
||||
} else if (!this.validEmail(value)) {
|
||||
return callback(new Error(this.$t('users.invalidEmailError')))
|
||||
} else {
|
||||
return callback()
|
||||
}
|
||||
},
|
||||
validatePassword(rule, value, callback) {
|
||||
if (value === '') {
|
||||
return callback(new Error(this.$t('users.emptyPasswordError')))
|
||||
} else {
|
||||
return callback()
|
||||
}
|
||||
},
|
||||
validateUsername(rule, value, callback) {
|
||||
if (value === '') {
|
||||
return callback(new Error(this.$t('users.emptyNicknameError')))
|
||||
} else if (!this.validNickname(value)) {
|
||||
return callback(new Error(this.$t('users.invalidNicknameError')))
|
||||
} else {
|
||||
return callback()
|
||||
}
|
||||
},
|
||||
validEmail(email) {
|
||||
var re = /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/
|
||||
return re.test(email)
|
||||
},
|
||||
validNickname(nickname) {
|
||||
var re = /^[a-zA-Z\d]+$/
|
||||
return re.test(nickname)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style rel='stylesheet/scss' lang='scss'>
|
||||
@media
|
||||
only screen and (max-width: 760px),
|
||||
(min-device-width: 768px) and (max-device-width: 1024px) {
|
||||
.create-user-dialog {
|
||||
width: 80%
|
||||
}
|
||||
.create-account-form-item {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.el-dialog__body {
|
||||
padding: 20px 20px 0 20px
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -4,13 +4,25 @@
|
|||
{{ $t('users.users') }}
|
||||
<span class="user-count">({{ normalizedUsersCount }})</span>
|
||||
</h1>
|
||||
<div class="search-container">
|
||||
<div class="filter-container">
|
||||
<users-filter/>
|
||||
<el-input :placeholder="$t('users.search')" v-model="search" class="search" @input="handleDebounceSearchInput"/>
|
||||
</div>
|
||||
<dropdown-actions-menu
|
||||
:selected-users="selectedUsers"
|
||||
@apply-action="clearSelection"/>
|
||||
<div class="actions-container">
|
||||
<el-button class="actions-button create-account" @click="dialogFormVisible = true">
|
||||
<span>
|
||||
<i class="el-icon-plus" />
|
||||
{{ $t('users.createAccount') }}
|
||||
</span>
|
||||
</el-button>
|
||||
<multiple-users-menu
|
||||
:selected-users="selectedUsers"
|
||||
@apply-action="clearSelection"/>
|
||||
</div>
|
||||
<new-account-dialog
|
||||
:dialog-form-visible="dialogFormVisible"
|
||||
@createNewAccount="createNewAccount"
|
||||
@closeWindow="dialogFormVisible = false"/>
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
ref="usersTable"
|
||||
|
@ -140,22 +152,21 @@
|
|||
import debounce from 'lodash.debounce'
|
||||
import numeral from 'numeral'
|
||||
import UsersFilter from './components/UsersFilter'
|
||||
import DropdownActionsMenu from './components/DropdownActionsMenu'
|
||||
import MultipleUsersMenu from './components/MultipleUsersMenu'
|
||||
import NewAccountDialog from './components/NewAccountDialog'
|
||||
|
||||
export default {
|
||||
name: 'Users',
|
||||
components: {
|
||||
UsersFilter,
|
||||
DropdownActionsMenu
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
selectedUsers: []
|
||||
}
|
||||
MultipleUsersMenu,
|
||||
NewAccountDialog
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
search: ''
|
||||
search: '',
|
||||
selectedUsers: [],
|
||||
dialogFormVisible: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
@ -207,6 +218,9 @@ export default {
|
|||
clearSelection() {
|
||||
this.$refs.usersTable.clearSelection()
|
||||
},
|
||||
createNewAccount(accountData) {
|
||||
this.$store.dispatch('CreateNewAccount', accountData)
|
||||
},
|
||||
getFirstLetter(str) {
|
||||
return str.charAt(0).toUpperCase()
|
||||
},
|
||||
|
@ -246,6 +260,18 @@ export default {
|
|||
</script>
|
||||
|
||||
<style rel='stylesheet/scss' lang='scss' scoped>
|
||||
.actions-button {
|
||||
text-align: left;
|
||||
width: 350px;
|
||||
padding: 10px;
|
||||
}
|
||||
.actions-container {
|
||||
display: flex;
|
||||
height: 36px;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin: 0 15px 10px 15px;
|
||||
}
|
||||
.active-tag {
|
||||
color: #409EFF;
|
||||
font-weight: 700;
|
||||
|
@ -256,9 +282,12 @@ export default {
|
|||
}
|
||||
}
|
||||
.el-dropdown-link:hover {
|
||||
cursor: pointer;
|
||||
color: #409EFF;
|
||||
}
|
||||
cursor: pointer;
|
||||
color: #409EFF;
|
||||
}
|
||||
.el-icon-plus {
|
||||
margin-right: 5px;
|
||||
}
|
||||
.users-container {
|
||||
h1 {
|
||||
margin: 22px 0 0 15px;
|
||||
|
@ -273,7 +302,7 @@ export default {
|
|||
width: 350px;
|
||||
float: right;
|
||||
}
|
||||
.search-container {
|
||||
.filter-container {
|
||||
display: flex;
|
||||
height: 36px;
|
||||
justify-content: space-between;
|
||||
|
@ -292,17 +321,25 @@ only screen and (max-width: 760px),
|
|||
h1 {
|
||||
margin: 7px 10px 7px 10px;
|
||||
}
|
||||
.actions-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0 10px 7px 10px
|
||||
}
|
||||
.create-account {
|
||||
width: 100%;
|
||||
}
|
||||
.el-icon-arrow-down {
|
||||
font-size: 12px;
|
||||
}
|
||||
.search {
|
||||
width: 100%;
|
||||
}
|
||||
.search-container {
|
||||
.filter-container {
|
||||
display: flex;
|
||||
height: 82px;
|
||||
flex-direction: column;
|
||||
margin: 0 10px 7px 10px
|
||||
margin: 0 10px
|
||||
}
|
||||
.el-tag {
|
||||
width: 30px;
|
||||
|
|
|
@ -3,6 +3,7 @@ import { mount, createLocalVue, config } from '@vue/test-utils'
|
|||
import flushPromises from 'flush-promises'
|
||||
import Element from 'element-ui'
|
||||
import Users from '@/views/users/index'
|
||||
import NewAccountDialog from '@/views/users/components/NewAccountDialog'
|
||||
import storeConfig from './store.conf'
|
||||
import { cloneDeep } from 'lodash'
|
||||
|
||||
|
@ -232,3 +233,98 @@ describe('Users actions', () => {
|
|||
done()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Creates new account', () => {
|
||||
let store
|
||||
|
||||
const nicknameInput = 'input[name="nickname"]'
|
||||
const emailInput = 'input[name="email"]'
|
||||
const passwordInput = 'input[name="password"]'
|
||||
|
||||
beforeEach(async() => {
|
||||
store = new Vuex.Store(cloneDeep(storeConfig))
|
||||
})
|
||||
|
||||
it('opens and closes dialog window', async (done) => {
|
||||
const wrapper = mount(Users, {
|
||||
store,
|
||||
localVue,
|
||||
sync: false
|
||||
})
|
||||
await flushPromises()
|
||||
|
||||
const dialog = wrapper.find('div.el-dialog__wrapper')
|
||||
expect(dialog.isVisible()).toBe(false)
|
||||
|
||||
const openDialogButton = wrapper.find('button.actions-button')
|
||||
const closeDialogButton = wrapper.find('div.el-dialog__footer button')
|
||||
|
||||
openDialogButton.trigger('click')
|
||||
await flushPromises()
|
||||
expect(dialog.isVisible()).toBe(true)
|
||||
|
||||
closeDialogButton.trigger('click')
|
||||
await flushPromises()
|
||||
expect(dialog.isVisible()).toBe(false)
|
||||
done()
|
||||
})
|
||||
|
||||
it('creates new account', async (done) => {
|
||||
const wrapper = mount(Users, {
|
||||
store,
|
||||
localVue,
|
||||
sync: false
|
||||
})
|
||||
await flushPromises()
|
||||
expect(wrapper.vm.usersCount).toEqual(3)
|
||||
|
||||
const openDialogButton = wrapper.find('button.actions-button')
|
||||
openDialogButton.trigger('click')
|
||||
await flushPromises()
|
||||
|
||||
const nickname = wrapper.find(nicknameInput)
|
||||
nickname.element.value = 'marshall'
|
||||
nickname.trigger('input')
|
||||
|
||||
const email = wrapper.find(emailInput)
|
||||
email.element.value = 'marshall@marshall.com'
|
||||
email.trigger('input')
|
||||
|
||||
const password = wrapper.find(passwordInput)
|
||||
password.element.value = '1234'
|
||||
password.trigger('input')
|
||||
|
||||
const createButton = wrapper.find('button.el-button--primary')
|
||||
createButton.trigger('click')
|
||||
await flushPromises()
|
||||
|
||||
expect(wrapper.vm.usersCount).toEqual(4)
|
||||
done()
|
||||
})
|
||||
|
||||
it('validates data', () => {
|
||||
const wrapper = mount(NewAccountDialog, {
|
||||
store,
|
||||
localVue,
|
||||
sync: false
|
||||
})
|
||||
|
||||
const validateEmailRule = { validator: wrapper.vm.validateEmail, field: 'email', fullField: 'email', type: 'string' }
|
||||
const validatePasswordRule = { validator: wrapper.vm.validatePassword, field: 'password', fullField: 'password', type: 'string' }
|
||||
const validateUsernameRule = { validator: wrapper.vm.validateUsername, field: 'nickname', fullField: 'nickname', type: 'string' }
|
||||
const identity = val => val
|
||||
|
||||
expect(wrapper.vm.validateUsername(validateUsernameRule, '', identity).message).toBe('Please input the username')
|
||||
expect(wrapper.vm.validateUsername(validateUsernameRule, 'marshall%$', identity).message).toBe('Username can include "a-z", "A-Z" and "0-9" characters')
|
||||
expect(wrapper.vm.validateUsername(validateUsernameRule, 'Marshall66', identity)).toBeUndefined()
|
||||
|
||||
expect(wrapper.vm.validateEmail(validateEmailRule, '', identity).message).toBe('Please input the e-mail')
|
||||
expect(wrapper.vm.validateEmail(validateEmailRule, 'test', identity).message).toBe('Please input valid e-mail')
|
||||
expect(wrapper.vm.validateEmail(validateEmailRule, 'test@test.com', identity)).toBeUndefined()
|
||||
|
||||
expect(wrapper.vm.validatePassword(validatePasswordRule, '', identity).message).toBe('Please input the password')
|
||||
expect(wrapper.vm.validatePassword(validatePasswordRule, '1234', identity)).toBeUndefined()
|
||||
|
||||
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import Vuex from 'vuex'
|
||||
import { mount, createLocalVue, config } from '@vue/test-utils'
|
||||
import Element from 'element-ui'
|
||||
import DropdownMenu from '@/views/users/components/DropdownMenu'
|
||||
import MultipleUsersMenu from '@/views/users/components/MultipleUsersMenu'
|
||||
import storeConfig from './store.conf'
|
||||
import { cloneDeep } from 'lodash'
|
||||
import flushPromises from 'flush-promises'
|
||||
|
@ -25,7 +25,7 @@ describe('Apply users actions to multiple users', () => {
|
|||
})
|
||||
|
||||
it('grants admin rights to multiple users', async (done) => {
|
||||
const wrapper = mount(DropdownMenu, {
|
||||
const wrapper = mount(MultipleUsersMenu, {
|
||||
store,
|
||||
localVue,
|
||||
sync: false,
|
||||
|
@ -62,7 +62,7 @@ describe('Apply users actions to multiple users', () => {
|
|||
})
|
||||
|
||||
it('grants moderator rights to multiple users', async (done) => {
|
||||
const wrapper = mount(DropdownMenu, {
|
||||
const wrapper = mount(MultipleUsersMenu, {
|
||||
store,
|
||||
localVue,
|
||||
sync: false,
|
||||
|
@ -99,7 +99,7 @@ describe('Apply users actions to multiple users', () => {
|
|||
})
|
||||
|
||||
it('revokes admin rights from multiple users', async (done) => {
|
||||
const wrapper = mount(DropdownMenu, {
|
||||
const wrapper = mount(MultipleUsersMenu, {
|
||||
store,
|
||||
localVue,
|
||||
sync: false,
|
||||
|
@ -132,7 +132,7 @@ describe('Apply users actions to multiple users', () => {
|
|||
})
|
||||
|
||||
it('calls a function that revokes moderator rights from multiple users', async (done) => {
|
||||
const wrapper = mount(DropdownMenu, {
|
||||
const wrapper = mount(MultipleUsersMenu, {
|
||||
store,
|
||||
localVue,
|
||||
sync: false,
|
||||
|
@ -152,7 +152,7 @@ describe('Apply users actions to multiple users', () => {
|
|||
})
|
||||
|
||||
it('activates multiple accounts', async (done) => {
|
||||
const wrapper = mount(DropdownMenu, {
|
||||
const wrapper = mount(MultipleUsersMenu, {
|
||||
store,
|
||||
localVue,
|
||||
sync: false,
|
||||
|
@ -180,7 +180,7 @@ describe('Apply users actions to multiple users', () => {
|
|||
})
|
||||
|
||||
it('deactivates multiple accounts', async (done) => {
|
||||
const wrapper = mount(DropdownMenu, {
|
||||
const wrapper = mount(MultipleUsersMenu, {
|
||||
store,
|
||||
localVue,
|
||||
sync: false,
|
||||
|
@ -212,7 +212,7 @@ describe('Apply users actions to multiple users', () => {
|
|||
})
|
||||
|
||||
it('deletes multiple accounts', async (done) => {
|
||||
const wrapper = mount(DropdownMenu, {
|
||||
const wrapper = mount(MultipleUsersMenu, {
|
||||
store,
|
||||
localVue,
|
||||
sync: false,
|
||||
|
@ -248,7 +248,7 @@ describe('Apply users actions to multiple users', () => {
|
|||
})
|
||||
|
||||
it('applies tags for multiple accounts', async (done) => {
|
||||
const wrapper = mount(DropdownMenu, {
|
||||
const wrapper = mount(MultipleUsersMenu, {
|
||||
store,
|
||||
localVue,
|
||||
sync: false,
|
||||
|
@ -289,7 +289,7 @@ describe('Apply users actions to multiple users', () => {
|
|||
})
|
||||
|
||||
it('removes tags from multiple accounts', async (done) => {
|
||||
const wrapper = mount(DropdownMenu, {
|
||||
const wrapper = mount(MultipleUsersMenu, {
|
||||
store,
|
||||
localVue,
|
||||
sync: false,
|
Loading…
Reference in a new issue