Revert "Merge branch 'feature/edit-tags-manually' into 'develop'"

This reverts commit fd9f0542ce17e26fa7459ad816b7b20c003786ef, reversing
changes made to acfe0dd6a3e600eaf0bb2000ccca6202542c9144.
This commit is contained in:
Angelina Filippova 2020-11-13 02:11:52 +03:00
parent 0fda46954e
commit f5b4845aa2
11 changed files with 290 additions and 348 deletions

View file

@ -20,7 +20,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Hide Tag actions on Users tab if MRF TagPolicy is disabled. Add ability to enable TagPolicy from Moderation menu - Hide Tag actions on Users tab if MRF TagPolicy is disabled. Add ability to enable TagPolicy from Moderation menu
- Move `:restrict_unauthenticated` settings from Authentication tab to Instance tab - Move `:restrict_unauthenticated` settings from Authentication tab to Instance tab
- Replace regular inputs with textareas for setting welcome messages in the Settings section - Replace regular inputs with textareas for setting welcome messages in the Settings section
- Move tag moderation from Moderation menu to separate column in the Users table, add ability to add custom tags
### Fixed ### Fixed

View file

@ -121,10 +121,6 @@ export async function deleteUsers(nicknames, authHost, token) {
}) })
} }
export async function listAllTags(authHost, token) {
return Promise.resolve({ data: ['verify', 'mrf_tag:media-force-nsfw'] })
}
export async function tagUser(nickname, tag, authHost, token) { export async function tagUser(nickname, tag, authHost, token) {
return Promise.resolve() return Promise.resolve()
} }

View file

@ -22,35 +22,6 @@ export async function addRight(nicknames, right, authHost, token) {
}) })
} }
export async function fetchUserChats(id, authHost, token) {
return await request({
baseURL: baseName(authHost),
url: `/api/pleroma/admin/users/${id}/chats`,
method: 'get',
headers: authHeaders(token)
})
}
export async function approveUserAccount(nicknames, authHost, token) {
return await request({
baseURL: baseName(authHost),
url: '/api/pleroma/admin/users/approve',
method: 'patch',
headers: authHeaders(token),
data: { nicknames }
})
}
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 createNewAccount(nickname, email, password, authHost, token) { export async function createNewAccount(nickname, email, password, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
@ -110,6 +81,25 @@ export async function fetchUser(id, authHost, token) {
}) })
} }
export async function fetchUserCredentials(nickname, authHost, token) {
return await request({
baseURL: baseName(authHost),
url: `/api/pleroma/admin/users/${nickname}/credentials`,
method: 'get',
headers: authHeaders(token)
})
}
export async function updateUserCredentials(nickname, credentials, authHost, token) {
return await request({
baseURL: baseName(authHost),
url: `/api/pleroma/admin/users/${nickname}/credentials`,
method: 'patch',
headers: authHeaders(token),
data: credentials
})
}
export async function fetchUsers(filters, actorTypeFilters, authHost, token, page = 1) { export async function fetchUsers(filters, actorTypeFilters, authHost, token, page = 1) {
const url = actorTypeFilters.length === 0 const url = actorTypeFilters.length === 0
? `/api/pleroma/admin/users?page=${page}&filters=${filters}` ? `/api/pleroma/admin/users?page=${page}&filters=${filters}`
@ -126,34 +116,6 @@ export async function fetchUsers(filters, actorTypeFilters, authHost, token, pag
}) })
} }
export async function fetchUserCredentials(nickname, authHost, token) {
return await request({
baseURL: baseName(authHost),
url: `/api/pleroma/admin/users/${nickname}/credentials`,
method: 'get',
headers: authHeaders(token)
})
}
export async function fetchUserStatuses(id, authHost, godmode, token) {
return await request({
baseURL: baseName(authHost),
url: `/api/pleroma/admin/users/${id}/statuses?godmode=${godmode}`,
method: 'get',
headers: authHeaders(token)
})
}
export async function forcePasswordReset(nicknames, authHost, token) {
return await request({
baseURL: baseName(authHost),
url: `/api/pleroma/admin/users/force_password_reset`,
method: 'patch',
headers: authHeaders(token),
data: { nicknames }
})
}
export async function getPasswordResetToken(nickname, authHost, token) { export async function getPasswordResetToken(nickname, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
@ -163,19 +125,10 @@ export async function getPasswordResetToken(nickname, authHost, token) {
}) })
} }
export async function listAllTags(authHost, token) { export async function forcePasswordReset(nicknames, authHost, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/users/tag`, url: `/api/pleroma/admin/users/force_password_reset`,
method: 'get',
headers: authHeaders(token)
})
}
export async function resendConfirmationEmail(nicknames, authHost, token) {
return await request({
baseURL: baseName(authHost),
url: '/api/pleroma/admin/users/resend_confirmation_email',
method: 'patch', method: 'patch',
headers: authHeaders(token), headers: authHeaders(token),
data: { nicknames } data: { nicknames }
@ -218,13 +171,51 @@ export async function untagUser(nicknames, tags, authHost, token) {
}) })
} }
export async function updateUserCredentials(nickname, credentials, authHost, token) { export async function fetchUserStatuses(id, authHost, godmode, token) {
return await request({ return await request({
baseURL: baseName(authHost), baseURL: baseName(authHost),
url: `/api/pleroma/admin/users/${nickname}/credentials`, url: `/api/pleroma/admin/users/${id}/statuses?godmode=${godmode}`,
method: 'get',
headers: authHeaders(token)
})
}
export async function fetchUserChats(id, authHost, token) {
return await request({
baseURL: baseName(authHost),
url: `/api/pleroma/admin/users/${id}/chats`,
method: 'get',
headers: authHeaders(token)
})
}
export async function approveUserAccount(nicknames, authHost, token) {
return await request({
baseURL: baseName(authHost),
url: '/api/pleroma/admin/users/approve',
method: 'patch', method: 'patch',
headers: authHeaders(token), headers: authHeaders(token),
data: credentials data: { nicknames }
})
}
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 }
}) })
} }

View file

@ -192,7 +192,6 @@ export default {
search: 'Search', search: 'Search',
id: 'ID', id: 'ID',
name: 'Name', name: 'Name',
label: 'Label',
status: 'Status', status: 'Status',
local: 'Local', local: 'Local',
external: 'External', external: 'External',
@ -280,12 +279,9 @@ export default {
registrationReason: 'Registration Reason', registrationReason: 'Registration Reason',
service: 'Service', service: 'Service',
person: 'Person', person: 'Person',
enableTagPolicy: 'Enable MRF TagPolicy to manage tags', enableTagPolicy: 'Enable MRF TagPolicy to manage user tags',
confirmEnablingTagPolicy: 'Are you sure you want to add TagPolicy to the list of enabled MRF policies?', confirmEnablingTagPolicy: 'Are you sure you want to add TagPolicy to the list of enabled MRF policies?',
enableTagPolicySuccessMessage: 'MRF TagPolicy was enabled', enableTagPolicySuccessMessage: 'MRF TagPolicy was enabled'
customTags: 'Custom Tags',
defaultTags: 'Default Tags',
tags: 'Tags'
}, },
statuses: { statuses: {
statuses: 'Statuses', statuses: 'Statuses',

View file

@ -3,21 +3,20 @@ import i18n from '@/lang'
import { import {
activateUsers, activateUsers,
addRight, addRight,
approveUserAccount,
confirmUserEmail,
createNewAccount, createNewAccount,
deactivateUsers, deactivateUsers,
deleteRight, deleteRight,
deleteUsers, deleteUsers,
disableMfa, disableMfa,
fetchUsers, fetchUsers,
forcePasswordReset,
getPasswordResetToken, getPasswordResetToken,
listAllTags,
resendConfirmationEmail,
searchUsers, searchUsers,
tagUser, tagUser,
untagUser, untagUser,
forcePasswordReset,
approveUserAccount,
confirmUserEmail,
resendConfirmationEmail,
updateUserCredentials updateUserCredentials
} from '@/api/users' } from '@/api/users'
import { fetchSettings, updateSettings } from '@/api/settings' import { fetchSettings, updateSettings } from '@/api/settings'
@ -36,8 +35,7 @@ const users = {
passwordResetToken: { passwordResetToken: {
token: '', token: '',
link: '' link: ''
}, }
tags: []
}, },
mutations: { mutations: {
SET_ACTOR_TYPE_FILTERS: (state, actorTypeFilters) => { SET_ACTOR_TYPE_FILTERS: (state, actorTypeFilters) => {
@ -83,9 +81,6 @@ const users = {
SET_TAG_POLICY: (state, mrfPolicies) => { SET_TAG_POLICY: (state, mrfPolicies) => {
state.mrfPolicies = mrfPolicies state.mrfPolicies = mrfPolicies
}, },
SET_TAGS: (state, tags) => {
state.tags = tags
},
SET_USERS_FILTERS: (state, filters) => { SET_USERS_FILTERS: (state, filters) => {
state.filters = filters state.filters = filters
} }
@ -249,10 +244,6 @@ const users = {
RemovePasswordToken({ commit }) { RemovePasswordToken({ commit }) {
commit('SET_PASSWORD_RESET_TOKEN', { link: '', token: '' }) commit('SET_PASSWORD_RESET_TOKEN', { link: '', token: '' })
}, },
async ListTags({ commit, getters }) {
const { data } = await listAllTags(getters.authHost, getters.token)
commit('SET_TAGS', data)
},
async RemoveTag({ dispatch, getters }, { users, tag, _userId, _statusId }) { async RemoveTag({ dispatch, getters }, { users, tag, _userId, _statusId }) {
const updatedUsers = users.map(user => { const updatedUsers = users.map(user => {
return { ...user, tags: user.tags.filter(userTag => userTag !== tag) } return { ...user, tags: user.tags.filter(userTag => userTag !== tag) }

View file

@ -15,17 +15,49 @@
@click.native="handleDeletion(account)"> @click.native="handleDeletion(account)">
{{ $t('users.deleteAccount') }} {{ $t('users.deleteAccount') }}
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item divided/> <el-dropdown-item
<div v-if="tagPolicyEnabled"> v-if="tagPolicyEnabled"
<el-dropdown-item :divided="true"
v-for="option in tags" :class="{ 'active-tag': tags.includes('mrf_tag:media-force-nsfw') }"
:key="option.tag" @click.native="toggleTag(account, 'mrf_tag:media-force-nsfw')">
:class="{ 'active-tag': account.tags.includes(option.tag) }" {{ $t('users.forceNsfw') }}
@click.native="toggleTag(account, option.tag)"> <i v-if="tags.includes('mrf_tag:media-force-nsfw')" class="el-icon-check"/>
{{ option.label }} </el-dropdown-item>
<i v-if="account.tags.includes(option.tag)" class="el-icon-check"/> <el-dropdown-item
</el-dropdown-item> v-if="tagPolicyEnabled"
</div> :class="{ 'active-tag': tags.includes('mrf_tag:media-strip') }"
@click.native="toggleTag(account, 'mrf_tag:media-strip')">
{{ $t('users.stripMedia') }}
<i v-if="tags.includes('mrf_tag:media-strip')" class="el-icon-check"/>
</el-dropdown-item>
<el-dropdown-item
v-if="tagPolicyEnabled"
:class="{ 'active-tag': tags.includes('mrf_tag:force-unlisted') }"
@click.native="toggleTag(account, 'mrf_tag:force-unlisted')">
{{ $t('users.forceUnlisted') }}
<i v-if="tags.includes('mrf_tag:force-unlisted')" class="el-icon-check"/>
</el-dropdown-item>
<el-dropdown-item
v-if="tagPolicyEnabled"
:class="{ 'active-tag': tags.includes('mrf_tag:sandbox') }"
@click.native="toggleTag(account, 'mrf_tag:sandbox')">
{{ $t('users.sandbox') }}
<i v-if="tags.includes('mrf_tag:sandbox')" class="el-icon-check"/>
</el-dropdown-item>
<el-dropdown-item
v-if="tagPolicyEnabled && account.local"
:class="{ 'active-tag': tags.includes('mrf_tag:disable-remote-subscription') }"
@click.native="toggleTag(account, 'mrf_tag:disable-remote-subscription')">
{{ $t('users.disableRemoteSubscription') }}
<i v-if="tags.includes('mrf_tag:disable-remote-subscription')" class="el-icon-check"/>
</el-dropdown-item>
<el-dropdown-item
v-if="tagPolicyEnabled && account.local"
:class="{ 'active-tag': tags.includes('mrf_tag:disable-any-subscription') }"
@click.native="toggleTag(account, 'mrf_tag:disable-any-subscription')">
{{ $t('users.disableAnySubscription') }}
<i v-if="tags.includes('mrf_tag:disable-any-subscription')" class="el-icon-check"/>
</el-dropdown-item>
<el-dropdown-item <el-dropdown-item
v-if="!tagPolicyEnabled" v-if="!tagPolicyEnabled"
divided divided
@ -55,28 +87,11 @@ export default {
} }
}, },
computed: { computed: {
mapTags() {
return {
'mrf_tag:media-force-nsfw': 'Force posts to be NSFW',
'mrf_tag:media-strip': 'Force posts to not have media',
'mrf_tag:force-unlisted': 'Force posts to be unlisted',
'mrf_tag:sandbox': 'Force posts to be followers-only',
'mrf_tag:verified': 'Verified',
'mrf_tag:disable-remote-subscription': 'Disallow following user from remote instances',
'mrf_tag:disable-any-subscription': 'Disallow following user at all'
}
},
tagPolicyEnabled() { tagPolicyEnabled() {
return this.$store.state.users.mrfPolicies.includes('Pleroma.Web.ActivityPub.MRF.TagPolicy') return this.$store.state.users.mrfPolicies.includes('Pleroma.Web.ActivityPub.MRF.TagPolicy')
}, },
tags() { tags() {
return this.$store.state.users.tags.map(tag => { return this.account.tags || []
if (this.mapTags[tag]) {
return { tag, label: this.mapTags[tag] }
} else {
return { tag, label: tag.charAt(0).toUpperCase() + tag.slice(1) }
}
}, {})
} }
}, },
methods: { methods: {

View file

@ -43,7 +43,6 @@ export default {
this.$store.dispatch('NeedReboot') this.$store.dispatch('NeedReboot')
this.$store.dispatch('FetchTagPolicySetting') this.$store.dispatch('FetchTagPolicySetting')
this.$store.dispatch('FetchReports', 1) this.$store.dispatch('FetchReports', 1)
this.$store.dispatch('ListTags')
} }
} }
</script> </script>

View file

@ -67,6 +67,56 @@
@click.native="handleConfirmationResend(user)"> @click.native="handleConfirmationResend(user)">
{{ $t('users.resendConfirmation') }} {{ $t('users.resendConfirmation') }}
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item
v-if="tagPolicyEnabled"
:divided="showAdminAction(user)"
:class="{ 'active-tag': user.tags.includes('mrf_tag:media-force-nsfw') }"
@click.native="toggleTag(user, 'mrf_tag:media-force-nsfw')">
{{ $t('users.forceNsfw') }}
<i v-if="user.tags.includes('mrf_tag:media-force-nsfw')" class="el-icon-check"/>
</el-dropdown-item>
<el-dropdown-item
v-if="tagPolicyEnabled"
:class="{ 'active-tag': user.tags.includes('mrf_tag:media-strip') }"
@click.native="toggleTag(user, 'mrf_tag:media-strip')">
{{ $t('users.stripMedia') }}
<i v-if="user.tags.includes('mrf_tag:media-strip')" class="el-icon-check"/>
</el-dropdown-item>
<el-dropdown-item
v-if="tagPolicyEnabled"
:class="{ 'active-tag': user.tags.includes('mrf_tag:force-unlisted') }"
@click.native="toggleTag(user, 'mrf_tag:force-unlisted')">
{{ $t('users.forceUnlisted') }}
<i v-if="user.tags.includes('mrf_tag:force-unlisted')" class="el-icon-check"/>
</el-dropdown-item>
<el-dropdown-item
v-if="tagPolicyEnabled"
:class="{ 'active-tag': user.tags.includes('mrf_tag:sandbox') }"
@click.native="toggleTag(user, 'mrf_tag:sandbox')">
{{ $t('users.sandbox') }}
<i v-if="user.tags.includes('mrf_tag:sandbox')" class="el-icon-check"/>
</el-dropdown-item>
<el-dropdown-item
v-if="user.local && tagPolicyEnabled"
:class="{ 'active-tag': user.tags.includes('mrf_tag:disable-remote-subscription') }"
@click.native="toggleTag(user, 'mrf_tag:disable-remote-subscription')">
{{ $t('users.disableRemoteSubscription') }}
<i v-if="user.tags.includes('mrf_tag:disable-remote-subscription')" class="el-icon-check"/>
</el-dropdown-item>
<el-dropdown-item
v-if="user.local && tagPolicyEnabled"
:class="{ 'active-tag': user.tags.includes('mrf_tag:disable-any-subscription') }"
@click.native="toggleTag(user, 'mrf_tag:disable-any-subscription')">
{{ $t('users.disableAnySubscription') }}
<i v-if="user.tags.includes('mrf_tag:disable-any-subscription')" class="el-icon-check"/>
</el-dropdown-item>
<el-dropdown-item
v-if="!tagPolicyEnabled"
divided
class="no-hover"
@click.native="enableTagPolicy">
{{ $t('users.enableTagPolicy') }}
</el-dropdown-item>
<el-dropdown-item <el-dropdown-item
v-if="user.local" v-if="user.local"
divided divided
@ -122,12 +172,35 @@ export default {
}, },
isDesktop() { isDesktop() {
return this.$store.state.app.device === 'desktop' return this.$store.state.app.device === 'desktop'
},
tagPolicyEnabled() {
return this.$store.state.users.mrfPolicies.includes('Pleroma.Web.ActivityPub.MRF.TagPolicy')
} }
}, },
methods: { methods: {
disableMfa(nickname) { disableMfa(nickname) {
this.$store.dispatch('DisableMfa', nickname) this.$store.dispatch('DisableMfa', nickname)
}, },
enableTagPolicy() {
this.$confirm(
this.$t('users.confirmEnablingTagPolicy'),
{
confirmButtonText: 'Yes',
cancelButtonText: 'Cancel',
type: 'warning'
}).then(() => {
this.$message({
type: 'success',
message: this.$t('users.enableTagPolicySuccessMessage')
})
this.$store.dispatch('EnableTagPolicy')
}).catch(() => {
this.$message({
type: 'info',
message: 'Canceled'
})
})
},
getPasswordResetToken(nickname) { getPasswordResetToken(nickname) {
this.$emit('open-reset-token-dialog') this.$emit('open-reset-token-dialog')
this.$store.dispatch('GetPasswordResetToken', nickname) this.$store.dispatch('GetPasswordResetToken', nickname)
@ -192,6 +265,11 @@ export default {
? this.$store.dispatch('ActivateUsers', { users: [user], _userId: user.id }) ? this.$store.dispatch('ActivateUsers', { users: [user], _userId: user.id })
: this.$store.dispatch('DeactivateUsers', { users: [user], _userId: user.id }) : this.$store.dispatch('DeactivateUsers', { users: [user], _userId: user.id })
}, },
toggleTag(user, tag) {
user.tags.includes(tag)
? this.$store.dispatch('RemoveTag', { users: [user], tag, _userId: user.id, _statusId: this.statusId })
: this.$store.dispatch('AddTag', { users: [user], tag, _userId: user.id, _statusId: this.statusId })
},
toggleUserRight(user, right) { toggleUserRight(user, right) {
user.roles[right] user.roles[right]
? this.$store.dispatch('DeleteRight', { users: [user], right, _userId: user.id, _statusId: this.statusId }) ? this.$store.dispatch('DeleteRight', { users: [user], right, _userId: user.id, _statusId: this.statusId })
@ -233,14 +311,8 @@ export default {
} }
} }
.actor-type-select .el-input.is-focus .el-input__inner { .actor-type-select .el-input.is-focus .el-input__inner {
border-color: transparent; border-color: transparent;
} }
.custom-tags-titile {
padding-left: 20px;
font-size: 12px;
color: #909399;
line-height: 30px;
}
.moderate-user-button { .moderate-user-button {
text-align: left; text-align: left;
width: 350px; width: 350px;
@ -252,9 +324,6 @@ export default {
} }
.moderation-dropdown-menu { .moderation-dropdown-menu {
width: 350px; width: 350px;
.el-dropdown-menu--small .el-dropdown-menu__item.el-dropdown-menu__item--divided {
margin-top: 0;
}
} }
@media only screen and (max-width:480px) { @media only screen and (max-width:480px) {
.moderate-user-button { .moderate-user-button {

View file

@ -61,27 +61,83 @@
@click.native="requirePasswordReset"> @click.native="requirePasswordReset">
{{ $t('users.requirePasswordReset') }} {{ $t('users.requirePasswordReset') }}
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item v-if="tagPolicyEnabled" divided> <el-dropdown-item v-if="tagPolicyEnabled" divided class="no-hover">
<el-dropdown class="multiple-tags-moderation"> <div class="tag-container">
<div> <span class="tag-text">{{ $t('users.forceNsfw') }}</span>
{{ $t('users.tags') }}<i class="el-icon-arrow-down el-icon--right" /> <el-button-group class="tag-button-group">
</div> <el-button size="mini" @click.native="addTagForMultipleUsers('mrf_tag:media-force-nsfw')">
<el-dropdown-menu slot="dropdown"> {{ $t('users.apply') }}
<el-dropdown-item v-for="option in tags" :key="option.tag" class="no-hover"> </el-button>
<div class="tag-container"> <el-button size="mini" @click.native="removeTagFromMultipleUsers('mrf_tag:media-force-nsfw')">
<span class="tag-text">{{ option.label }}</span> {{ $t('users.remove') }}
<el-button-group class="tag-button-group"> </el-button>
<el-button size="mini" @click.native="addTagForMultipleUsers(option.tag)"> </el-button-group>
{{ $t('users.apply') }} </div>
</el-button> </el-dropdown-item>
<el-button size="mini" @click.native="removeTagFromMultipleUsers(option.tag)"> <el-dropdown-item v-if="tagPolicyEnabled" class="no-hover">
{{ $t('users.remove') }} <div class="tag-container">
</el-button> <span class="tag-text">{{ $t('users.stripMedia') }}</span>
</el-button-group> <el-button-group class="tag-button-group">
</div> <el-button size="mini" @click.native="addTagForMultipleUsers('mrf_tag:media-strip')">
</el-dropdown-item> {{ $t('users.apply') }}
</el-dropdown-menu> </el-button>
</el-dropdown> <el-button size="mini" @click.native="removeTagFromMultipleUsers('mrf_tag:media-strip')">
{{ $t('users.remove') }}
</el-button>
</el-button-group>
</div>
</el-dropdown-item>
<el-dropdown-item v-if="tagPolicyEnabled" class="no-hover">
<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('mrf_tag:force-unlisted')">
{{ $t('users.apply') }}
</el-button>
<el-button size="mini" @click.native="removeTagFromMultipleUsers('mrf_tag:force-unlisted')">
{{ $t('users.remove') }}
</el-button>
</el-button-group>
</div>
</el-dropdown-item>
<el-dropdown-item v-if="tagPolicyEnabled" class="no-hover">
<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('mrf_tag:sandbox')">
{{ $t('users.apply') }}
</el-button>
<el-button size="mini" @click.native="removeTagFromMultipleUsers('mrf_tag:sandbox')">
{{ $t('users.remove') }}
</el-button>
</el-button-group>
</div>
</el-dropdown-item>
<el-dropdown-item v-if="tagPolicyEnabled" class="no-hover">
<div class="tag-container">
<span class="tag-text">{{ $t('users.disableRemoteSubscriptionForMultiple') }}</span>
<el-button-group class="tag-button-group">
<el-button size="mini" @click.native="addTagForMultipleUsers('mrf_tag:disable-remote-subscription')">
{{ $t('users.apply') }}
</el-button>
<el-button size="mini" @click.native="removeTagFromMultipleUsers('mrf_tag:disable-remote-subscription')">
{{ $t('users.remove') }}
</el-button>
</el-button-group>
</div>
</el-dropdown-item>
<el-dropdown-item v-if="tagPolicyEnabled" class="no-hover">
<div class="tag-container">
<span class="tag-text">{{ $t('users.disableAnySubscriptionForMultiple') }}</span>
<el-button-group class="tag-button-group">
<el-button size="mini" @click.native="addTagForMultipleUsers('mrf_tag:disable-any-subscription')">
{{ $t('users.apply') }}
</el-button>
<el-button size="mini" @click.native="removeTagFromMultipleUsers('mrf_tag:disable-any-subscription')">
{{ $t('users.remove') }}
</el-button>
</el-button-group>
</div>
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item <el-dropdown-item
v-if="!tagPolicyEnabled" v-if="!tagPolicyEnabled"
@ -112,31 +168,11 @@ export default {
isDesktop() { isDesktop() {
return this.$store.state.app.device === 'desktop' return this.$store.state.app.device === 'desktop'
}, },
mapTags() {
return {
'mrf_tag:media-force-nsfw': 'NSFW',
'mrf_tag:media-strip': 'Strip Media',
'mrf_tag:force-unlisted': 'Unlisted',
'mrf_tag:sandbox': 'Sandbox',
'mrf_tag:verified': 'Verified',
'mrf_tag:disable-remote-subscription': 'Disable remote subscription',
'mrf_tag:disable-any-subscription': 'Disable any subscription'
}
},
showDropdownForMultipleUsers() { showDropdownForMultipleUsers() {
return this.$props.selectedUsers.length > 0 return this.$props.selectedUsers.length > 0
}, },
tagPolicyEnabled() { tagPolicyEnabled() {
return this.$store.state.users.mrfPolicies.includes('Pleroma.Web.ActivityPub.MRF.TagPolicy') return this.$store.state.users.mrfPolicies.includes('Pleroma.Web.ActivityPub.MRF.TagPolicy')
},
tags() {
return this.$store.state.users.tags.map(tag => {
if (this.mapTags[tag]) {
return { tag, label: this.mapTags[tag] }
} else {
return { tag, label: tag.charAt(0).toUpperCase() + tag.slice(1) }
}
}, {})
} }
}, },
methods: { methods: {
@ -370,14 +406,6 @@ export default {
.el-icon-edit { .el-icon-edit {
margin-right: 5px; margin-right: 5px;
} }
.multiple-tags-moderation {
width: 100%;
}
.no-hover:hover {
color: #606266;
background-color: white;
cursor: auto;
}
.tag-container { .tag-container {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
@ -386,4 +414,9 @@ export default {
.tag-text { .tag-text {
padding-right: 20px; padding-right: 20px;
} }
.no-hover:hover {
color: #606266;
background-color: white;
cursor: auto;
}
</style> </style>

View file

@ -54,7 +54,7 @@
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :min-width="width" :label="$t('users.status')" width="200px"> <el-table-column :min-width="width" :label="$t('users.status')">
<template slot-scope="scope"> <template slot-scope="scope">
<el-tag v-if="!scope.row.deactivated & !scope.row.approval_pending" type="success"> <el-tag v-if="!scope.row.deactivated & !scope.row.approval_pending" type="success">
<span v-if="isDesktop">{{ $t('users.active') }}</span> <span v-if="isDesktop">{{ $t('users.active') }}</span>
@ -83,45 +83,6 @@
</el-tooltip> </el-tooltip>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :min-width="width" :label="$t('users.tags')">
<template slot-scope="scope">
<el-select
v-if="tagPolicyEnabled"
:value="scope.row.tags"
multiple
filterable
allow-create
placeholder="Add Tags"
size="small"
class="select-tags"
@change="toggleTag($event, scope.row)">
<el-option-group :label="$t('users.defaultTags')">
<el-option
v-for="option in defaultTags(scope.row.local)"
:value="option.tag"
:key="option.tag"
:label="option.label"
:class="{ 'active-tag': scope.row.tags.includes(option.tag) }">
{{ option.label }}
</el-option>
</el-option-group>
<el-option-group :label="$t('users.customTags')">
<el-option
v-for="option in customTags()"
:value="option.tag"
:key="option.tag"
:label="option.label"
:class="{ 'active-tag': scope.row.tags.includes(option.tag) }"
class="capitalize">
{{ option.label }}
</el-option>
</el-option-group>
</el-select>
<el-button v-if="!tagPolicyEnabled" type="text" @click.native.stop="enableTagPolicy">
{{ $t('users.enableTagPolicy') }}
</el-button>
</template>
</el-table-column>
<el-table-column v-if="pendingView && isDesktop" :label="$t('users.registrationReason')"> <el-table-column v-if="pendingView && isDesktop" :label="$t('users.registrationReason')">
<template slot-scope="scope"> <template slot-scope="scope">
<el-tooltip <el-tooltip
@ -199,6 +160,15 @@ export default {
} }
}, },
computed: { computed: {
loading() {
return this.$store.state.users.loading
},
normalizedUsersCount() {
return numeral(this.$store.state.users.totalUsersCount).format('0a')
},
pageSize() {
return this.$store.state.users.pageSize
},
currentPage() { currentPage() {
return this.$store.state.users.currentPage return this.$store.state.users.currentPage
}, },
@ -208,41 +178,6 @@ export default {
isMobile() { isMobile() {
return this.$store.state.app.device === 'mobile' return this.$store.state.app.device === 'mobile'
}, },
loading() {
return this.$store.state.users.loading
},
mapRemoteTags() {
return {
'mrf_tag:media-force-nsfw': 'NSFW',
'mrf_tag:media-strip': 'Strip Media',
'mrf_tag:force-unlisted': 'Unlisted',
'mrf_tag:sandbox': 'Sandbox',
'mrf_tag:verified': 'Verified'
}
},
mapTags() {
return {
'mrf_tag:media-force-nsfw': 'NSFW',
'mrf_tag:media-strip': 'Strip Media',
'mrf_tag:force-unlisted': 'Unlisted',
'mrf_tag:sandbox': 'Sandbox',
'mrf_tag:verified': 'Verified',
'mrf_tag:disable-remote-subscription': 'Disable remote subscription',
'mrf_tag:disable-any-subscription': 'Disable any subscription'
}
},
normalizedUsersCount() {
return numeral(this.$store.state.users.totalUsersCount).format('0a')
},
pageSize() {
return this.$store.state.users.pageSize
},
pendingView() {
return this.$store.state.users.filters['need_approval']
},
tagPolicyEnabled() {
return this.$store.state.users.mrfPolicies.includes('Pleroma.Web.ActivityPub.MRF.TagPolicy')
},
users() { users() {
return this.$store.state.users.fetchedUsers return this.$store.state.users.fetchedUsers
}, },
@ -265,7 +200,6 @@ export default {
this.$store.dispatch('NeedReboot') this.$store.dispatch('NeedReboot')
this.$store.dispatch('FetchTagPolicySetting') this.$store.dispatch('FetchTagPolicySetting')
this.$store.dispatch('FetchUsers', { page: 1 }) this.$store.dispatch('FetchUsers', { page: 1 })
this.$store.dispatch('ListTags')
}, },
destroyed() { destroyed() {
this.$store.dispatch('ClearUsersState') this.$store.dispatch('ClearUsersState')
@ -282,44 +216,6 @@ export default {
await this.$store.dispatch('CreateNewAccount', accountData) await this.$store.dispatch('CreateNewAccount', accountData)
this.createAccountDialogOpen = false this.createAccountDialogOpen = false
}, },
customTags() {
return this.$store.state.users.tags
.filter(tag => !Object.keys(this.mapTags).includes(tag))
.map(tag => {
return { tag, label: tag.charAt(0).toUpperCase() + tag.slice(1) }
})
},
defaultTags(userLocal) {
const tagsByType = userLocal ? Object.keys(this.mapTags) : Object.keys(this.mapRemoteTags)
return tagsByType.filter(tag => this.$store.state.users.tags.includes(tag))
.map(tag => {
if (userLocal) {
return { tag, label: this.mapTags[tag] }
} else {
return { tag, label: this.mapRemoteTags[tag] }
}
}, {})
},
enableTagPolicy() {
this.$confirm(
this.$t('users.confirmEnablingTagPolicy'),
{
confirmButtonText: 'Yes',
cancelButtonText: 'Cancel',
type: 'warning'
}).then(() => {
this.$message({
type: 'success',
message: this.$t('users.enableTagPolicySuccessMessage')
})
this.$store.dispatch('EnableTagPolicy')
}).catch(() => {
this.$message({
type: 'info',
message: 'Canceled'
})
})
},
getFirstLetter(str) { getFirstLetter(str) {
return str.charAt(0).toUpperCase() return str.charAt(0).toUpperCase()
}, },
@ -350,11 +246,6 @@ export default {
}, },
showDeactivatedButton(id) { showDeactivatedButton(id) {
return this.$store.state.user.id !== id return this.$store.state.user.id !== id
},
toggleTag(tags, user) {
tags.length > user.tags.length
? this.$store.dispatch('AddTag', { users: [user], tag: tags.filter(tag => !user.tags.includes(tag))[0] })
: this.$store.dispatch('RemoveTag', { users: [user], tag: user.tags.filter(tag => !tags.includes(tag))[0] })
} }
} }
} }
@ -390,9 +281,6 @@ export default {
color: #bbb; color: #bbb;
} }
} }
.capitalize {
text-transform: capitalize;
}
.el-dropdown-link:hover { .el-dropdown-link:hover {
cursor: pointer; cursor: pointer;
color: #409EFF; color: #409EFF;
@ -442,10 +330,6 @@ export default {
float: right; float: right;
margin-left: 10px; margin-left: 10px;
} }
.select-tags {
padding-right: 10px;
width: 100%;
}
.filter-container { .filter-container {
display: flex; display: flex;
height: 36px; height: 36px;

View file

@ -138,7 +138,7 @@ describe('Users actions', () => {
const dropdownMenuItems = wrapper.findAll( const dropdownMenuItems = wrapper.findAll(
`.el-table__fixed-body-wrapper table tr:nth-child(3) ul.el-dropdown-menu > li` `.el-table__fixed-body-wrapper table tr:nth-child(3) ul.el-dropdown-menu > li`
) )
expect(dropdownMenuItems.length).toBe(3) expect(dropdownMenuItems.length).toBe(7)
done() done()
}) })
@ -198,28 +198,8 @@ describe('Users actions', () => {
expect(user1.tags.length).toBe(0) expect(user1.tags.length).toBe(0)
expect(user2.tags.length).toBe(1) expect(user2.tags.length).toBe(1)
wrapper.vm.toggleTag(['test-tag'], wrapper.find(htmlElement(1, 6)).trigger('click')
{ active: true, wrapper.find(htmlElement(2, 6)).trigger('click')
approval_pending: false,
deactivated: false, id: '2',
nickname: 'allis',
local: true,
external: false,
roles: { admin: true, moderator: false },
tags: [],
actor_type: 'Person' })
wrapper.vm.toggleTag(['test-tag', 'mrf_tag:sandbox'],
{ active: true,
approval_pending: false,
deactivated: false,
id: '10',
nickname: 'bob',
local: true,
external: false,
roles: { admin: false, moderator: false },
tags: ['mrf_tag:sandbox'],
actor_type: 'Person' })
const updatedUser1 = store.state.users.fetchedUsers[0] const updatedUser1 = store.state.users.fetchedUsers[0]
const updatedUser2 = store.state.users.fetchedUsers[1] const updatedUser2 = store.state.users.fetchedUsers[1]
@ -241,18 +221,7 @@ describe('Users actions', () => {
const user = store.state.users.fetchedUsers[1] const user = store.state.users.fetchedUsers[1]
expect(user.tags.length).toBe(1) expect(user.tags.length).toBe(1)
wrapper.find(htmlElement(2, 9)).trigger('click')
wrapper.vm.toggleTag([],
{ active: true,
approval_pending: false,
deactivated: false,
id: '10',
nickname: 'bob',
local: true,
external: false,
roles: { admin: false, moderator: false },
tags: ['mrf_tag:sandbox'],
actor_type: 'Person' })
const updatedUser = store.state.users.fetchedUsers[1] const updatedUser = store.state.users.fetchedUsers[1]
expect(updatedUser.tags.length).toBe(0) expect(updatedUser.tags.length).toBe(0)
@ -302,7 +271,7 @@ describe('Users actions', () => {
expect(wrapper.vm.resetPasswordDialogOpen).toBe(false) expect(wrapper.vm.resetPasswordDialogOpen).toBe(false)
expect(store.state.users.passwordResetToken.token).toBe('') expect(store.state.users.passwordResetToken.token).toBe('')
wrapper.find(htmlElement(1, 6)).trigger('click') wrapper.find(htmlElement(1, 12)).trigger('click')
await flushPromises() await flushPromises()
expect(wrapper.vm.resetPasswordDialogOpen).toBe(true) expect(wrapper.vm.resetPasswordDialogOpen).toBe(true)