Commit 46958a3b authored by feld's avatar feld

Merge branch 'feature/create-new-user' into 'master'

Allow to register new user accounts

Closes #17

See merge request pleroma/admin-fe!20
parents 3a8a032e 6cca2938
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: '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: 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'] } { 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) { ...@@ -69,3 +69,9 @@ export async function tagUser(nickname, tag, authHost, token) {
export async function untagUser(nickname, tag, authHost, token) { export async function untagUser(nickname, tag, authHost, token) {
return Promise.resolve() 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,56 +2,57 @@ import request from '@/utils/request' ...@@ -2,56 +2,57 @@ import request from '@/utils/request'
import { getToken } from '@/utils/auth' import { getToken } from '@/utils/auth'
import { baseName } from './utils' import { baseName } from './utils'
export async function fetchUsers(filters, authHost, token, page = 1) { export async function addRight(nickname, right, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/users?page=${page}&filters=${filters}`, url: `/api/pleroma/admin/users/${nickname}/permission_group/${right}`,
method: 'get', method: 'post',
headers: authHeaders(token) headers: authHeaders(token)
}) })
} }
export async function toggleUserActivation(nickname, authHost, token) { export async function createNewAccount(nickname, email, password, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/users/${nickname}/toggle_activation`, url: '/api/pleroma/admin/users',
method: 'patch', method: 'post',
headers: authHeaders(token) headers: authHeaders(token),
data: { nickname, email, password }
}) })
} }
export async function searchUsers(query, filters, authHost, token, page = 1) { export async function deleteRight(nickname, right, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/users?query=${query}&page=${page}&filters=${filters}`, url: `/api/pleroma/admin/users/${nickname}/permission_group/${right}`,
method: 'get', method: 'delete',
headers: authHeaders(token) headers: authHeaders(token)
}) })
} }
export async function addRight(nickname, right, authHost, token) { export async function deleteUser(nickname, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/users/${nickname}/permission_group/${right}`, url: `/api/pleroma/admin/users?nickname=${nickname}`,
method: 'post', method: 'delete',
headers: authHeaders(token) headers: authHeaders(token)
}) })
} }
export async function deleteRight(nickname, right, authHost, token) { export async function fetchUsers(filters, authHost, token, page = 1) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/users/${nickname}/permission_group/${right}`, url: `/api/pleroma/admin/users?page=${page}&filters=${filters}`,
method: 'delete', method: 'get',
headers: authHeaders(token) headers: authHeaders(token)
}) })
} }
export async function deleteUser(nickname, authHost, token) { export async function searchUsers(query, filters, authHost, token, page = 1) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/users?nickname=${nickname}`, url: `/api/pleroma/admin/users?query=${query}&page=${page}&filters=${filters}`,
method: 'delete', method: 'get',
headers: authHeaders(token) headers: authHeaders(token)
}) })
} }
...@@ -66,6 +67,15 @@ export async function tagUser(nicknames, tags, authHost, token) { ...@@ -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) { export async function untagUser(nicknames, tags, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
......
...@@ -182,16 +182,46 @@ export default { ...@@ -182,16 +182,46 @@ export default {
revokeModerator: 'Revoke Moderator', revokeModerator: 'Revoke Moderator',
grantModerator: 'Grant Moderator', grantModerator: 'Grant Moderator',
activateAccount: 'Activate Account', activateAccount: 'Activate Account',
activateAccounts: 'Activate Accounts',
deactivateAccount: 'Deactivate Account', deactivateAccount: 'Deactivate Account',
deactivateAccounts: 'Deactivate Accounts',
deleteAccount: 'Delete Account', deleteAccount: 'Delete Account',
deleteAccounts: 'Delete Accounts',
forceNsfw: 'Force posts to be NSFW', forceNsfw: 'Force posts to be NSFW',
stripMedia: 'Force posts not to have media', stripMedia: 'Force posts not to have media',
forceUnlisted: 'Force posts to be unlisted', forceUnlisted: 'Force posts to be unlisted',
sandbox: 'Force posts to be followers-only', sandbox: 'Force posts to be followers-only',
disableRemoteSubscription: 'Disallow following user from remote instances', disableRemoteSubscription: 'Disallow following user from remote instances',
disableRemoteSubscriptionForMultiple: 'Disallow following users from remote instances',
disableAnySubscription: 'Disallow following user at all', disableAnySubscription: 'Disallow following user at all',
disableAnySubscriptionForMultiple: 'Disallow following users at all',
selectUsers: 'Select users to apply actions to multiple users', 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: { usersFilter: {
inputPlaceholder: 'Select filter', inputPlaceholder: 'Select filter',
......
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 = { const users = {
state: { state: {
...@@ -61,6 +61,10 @@ const users = { ...@@ -61,6 +61,10 @@ const users = {
commit('CLEAR_USERS_FILTERS') commit('CLEAR_USERS_FILTERS')
dispatch('SearchUsers', { query: state.searchQuery, page: 1 }) 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) { async DeleteUser({ commit, getters }, user) {
await deleteUser(user.nickname, getters.authHost, getters.token) await deleteUser(user.nickname, getters.authHost, getters.token)
const updatedUser = { ...user, deactivated: true } const updatedUser = { ...user, deactivated: true }
...@@ -83,7 +87,7 @@ const users = { ...@@ -83,7 +87,7 @@ const users = {
async SearchUsers({ commit, dispatch, state, getters }, { query, page }) { async SearchUsers({ commit, dispatch, state, getters }, { query, page }) {
if (query.length === 0) { if (query.length === 0) {
commit('SET_SEARCH_QUERY', query) commit('SET_SEARCH_QUERY', query)
dispatch('FetchUsers', page) dispatch('FetchUsers', { page })
} else { } else {
commit('SET_LOADING', true) commit('SET_LOADING', true)
commit('SET_SEARCH_QUERY', query) commit('SET_SEARCH_QUERY', query)
......
...@@ -29,22 +29,26 @@ ...@@ -29,22 +29,26 @@
<el-dropdown-item <el-dropdown-item
divided divided
@click.native="activateMultipleUsers"> @click.native="activateMultipleUsers">
{{ $t('users.activateAccount') }} {{ $t('users.activateAccounts') }}
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item <el-dropdown-item
@click.native="deactivateMultipleUsers"> @click.native="deactivateMultipleUsers">
{{ $t('users.deactivateAccount') }} {{ $t('users.deactivateAccounts') }}
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item <el-dropdown-item
@click.native="deleteMultipleUsers"> @click.native="deleteMultipleUsers">
{{ $t('users.deleteAccount') }} {{ $t('users.deleteAccounts') }}
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item divided class="no-hover"> <el-dropdown-item divided class="no-hover">
<div class="tag-container"> <div class="tag-container">
<span class="tag-text">{{ $t('users.forceNsfw') }}</span> <span class="tag-text">{{ $t('users.forceNsfw') }}</span>
<el-button-group class="tag-button-group"> <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="addTagForMultipleUsers('force_nsfw')">
<el-button size="mini" @click.native="removeTagFromMultipleUsers('force_nsfw')">remove</el-button> {{ $t('users.apply') }}
</el-button>
<el-button size="mini" @click.native="removeTagFromMultipleUsers('force_nsfw')">
{{ $t('users.remove') }}
</el-button>
</el-button-group> </el-button-group>
</div> </div>
</el-dropdown-item> </el-dropdown-item>
...@@ -52,8 +56,12 @@ ...@@ -52,8 +56,12 @@
<div class="tag-container"> <div class="tag-container">
<span class="tag-text">{{ $t('users.stripMedia') }}</span> <span class="tag-text">{{ $t('users.stripMedia') }}</span>
<el-button-group class="tag-button-group"> <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="addTagForMultipleUsers('strip_media')">
<el-button size="mini" @click.native="removeTagFromMultipleUsers('strip_media')">remove</el-button> {{ $t('users.apply') }}
</el-button>
<el-button size="mini" @click.native="removeTagFromMultipleUsers('strip_media')">
{{ $t('users.remove') }}
</el-button>
</el-button-group> </el-button-group>
</div> </div>
</el-dropdown-item> </el-dropdown-item>
...@@ -61,8 +69,12 @@ ...@@ -61,8 +69,12 @@
<div class="tag-container"> <div class="tag-container">
<span class="tag-text">{{ $t('users.forceUnlisted') }}</span> <span class="tag-text">{{ $t('users.forceUnlisted') }}</span>
<el-button-group class="tag-button-group"> <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="addTagForMultipleUsers('force_unlisted')">
<el-button size="mini" @click.native="removeTagFromMultipleUsers('force_unlisted')">remove</el-button> {{ $t('users.apply') }}
</el-button>
<el-button size="mini" @click.native="removeTagFromMultipleUsers('force_unlisted')">
{{ $t('users.remove') }}
</el-button>
</el-button-group> </el-button-group>
</div> </div>
</el-dropdown-item> </el-dropdown-item>
...@@ -70,26 +82,38 @@ ...@@ -70,26 +82,38 @@
<div class="tag-container"> <div class="tag-container">
<span class="tag-text">{{ $t('users.sandbox') }}</span> <span class="tag-text">{{ $t('users.sandbox') }}</span>
<el-button-group class="tag-button-group"> <el-button-group class="tag-button-group">
<el-button size="mini" @click.native="addTagForMultipleUsers('sandbox')">apply</el-button> <el-button size="mini" @click.native="addTagForMultipleUsers('sandbox')">
<el-button size="mini" @click.native="removeTagFromMultipleUsers('sandbox')">remove</el-button> {{ $t('users.apply') }}
</el-button>
<el-button size="mini" @click.native="removeTagFromMultipleUsers('sandbox')">
{{ $t('users.remove') }}
</el-button>
</el-button-group> </el-button-group>
</div> </div>
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item class="no-hover"> <el-dropdown-item class="no-hover">
<div class="tag-container"> <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-group class="tag-button-group">
<el-button size="mini" @click.native="addTagForMultipleUsers('disable_remote_subscription')">apply</el-button> <el-button size="mini" @click.native="addTagForMultipleUsers('disable_remote_subscription')">
<el-button size="mini" @click.native="removeTagFromMultipleUsers('disable_remote_subscription')">remove</el-button> {{ $t('users.apply') }}
</el-button>
<el-button size="mini" @click.native="removeTagFromMultipleUsers('disable_remote_subscription')">
{{ $t('users.remove') }}
</el-button>
</el-button-group> </el-button-group>
</div> </div>
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item class="no-hover"> <el-dropdown-item class="no-hover">
<div class="tag-container"> <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-group class="tag-button-group">
<el-button size="mini" @click.native="addTagForMultipleUsers('disable_any_subscription')">apply</el-button> <el-button size="mini" @click.native="addTagForMultipleUsers('disable_any_subscription')">
<el-button size="mini" @click.native="removeTagFromMultipleUsers('disable_any_subscription')">remove</el-button> {{ $t('users.apply') }}
</el-button>
<el-button size="mini" @click.native="removeTagFromMultipleUsers('disable_any_subscription')">
{{ $t('users.remove') }}
</el-button>
</el-button-group> </el-button-group>
</div> </div>
</el-dropdown-item> </el-dropdown-item>
...@@ -157,68 +181,68 @@ export default { ...@@ -157,68 +181,68 @@ export default {
grantRightToMultipleUsers(right) { grantRightToMultipleUsers(right) {
const { grantRight } = this.mappers() const { grantRight } = this.mappers()
this.confirmMessage( this.confirmMessage(
`Are you sure you want to grant ${right} rights to all selected users?`, this.$t('users.grantRightConfirmation', { right }),
grantRight(right) grantRight(right)
) )
}, },
revokeRightFromMultipleUsers(right) { revokeRightFromMultipleUsers(right) {
const { revokeRight } = this.mappers() const { revokeRight } = this.mappers()
this.confirmMessage( this.confirmMessage(
`Are you sure you want to revoke ${right} rights from all selected users?`, this.$t('users.revokeRightConfirmation', { right }),
revokeRight(right) revokeRight(right)
) )
}, },
activateMultipleUsers() { activateMultipleUsers() {
const { activate } = this.mappers() const { activate } = this.mappers()
this.confirmMessage( this.confirmMessage(
'Are you sure you want to activate accounts of all selected users?', this.$t('users.activateMultipleUsersConfirmation'),
activate activate
) )
}, },
deactivateMultipleUsers() { deactivateMultipleUsers() {
const { deactivate } = this.mappers() const { deactivate } = this.mappers()
this.confirmMessage( this.confirmMessage(
'Are you sure you want to deactivate accounts of all selected users?', this.$t('users.deactivateMultipleUsersConfirmation'),
deactivate deactivate
) )
}, },
deleteMultipleUsers() { deleteMultipleUsers() {
const { remove } = this.mappers() const { remove } = this.mappers()
this.confirmMessage( this.confirmMessage(
'Are you sure you want to delete accounts of all selected users?', this.$t('users.deleteMultipleUsersConfirmation'),
remove remove
) )
}, },
addTagForMultipleUsers(tag) { addTagForMultipleUsers(tag) {
const { addTag } = this.mappers() const { addTag } = this.mappers()
this.confirmMessage( this.confirmMessage(
'Are you sure you want to apply tag to all selected users?', this.$t('users.addTagForMultipleUsersConfirmation'),
addTag(tag) addTag(tag)
) )
}, },
removeTagFromMultipleUsers(tag) { removeTagFromMultipleUsers(tag) {
const { removeTag } = this.mappers() const { removeTag } = this.mappers()
this.confirmMessage( this.confirmMessage(
'Are you sure you want to remove tag from all selected users?', this.$t('users.removeTagFromMultipleUsersConfirmation'),
removeTag(tag) removeTag(tag)
) )
}, },
confirmMessage(message, applyAction) { confirmMessage(message, applyAction) {
this.$confirm(message, { this.$confirm(message, {
confirmButtonText: 'OK', confirmButtonText: this.$t('users.ok'),
cancelButtonText: 'Cancel', cancelButtonText: this.$t('users.cancel'),
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
applyAction() applyAction()
this.$emit('apply-action') this.$emit('apply-action')
this.$message({ this.$message({
type: 'success', type: 'success',
message: 'Completed' message: this.$t('users.completed')
}) })
}).catch(() => { }).catch(() => {
this.$message({ this.$message({
type: 'info', type: 'info',
message: 'Canceled' message: this.$t('users.canceled')
}) })
}) })
} }
...@@ -229,9 +253,8 @@ export default { ...@@ -229,9 +253,8 @@ export default {
<style rel='stylesheet/scss' lang='scss' scoped> <style rel='stylesheet/scss' lang='scss' scoped>
.actions-button { .actions-button {
text-align: left; text-align: left;
margin: 0 15px 10px 0;
width: 350px; width: 350px;
padding: 10px 15px; padding: 10px;
} }
.actions-button-container { .actions-button-container {
display: flex; display: flex;
...@@ -240,8 +263,8 @@ export default { ...@@ -240,8 +263,8 @@ export default {
.el-dropdown { .el-dropdown {
float: right; float: right;
} }
.el-dropdown-menu { .el-icon-edit {
margin-right: 15px; margin-right: 5px;
} }
.tag-container { .tag-container {
display: flex; display: flex;
......
<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: {