cleaned up, refactored and implemented new <ModerationTools>
This commit is contained in:
parent
3443ddddbb
commit
e56ea2dbeb
23 changed files with 1124 additions and 975 deletions
|
|
@ -4,6 +4,7 @@ export default {
|
||||||
validInnerComponents: ['Text', 'Icon', 'Link', 'Border', 'ButtonUnstyled'],
|
validInnerComponents: ['Text', 'Icon', 'Link', 'Border', 'ButtonUnstyled'],
|
||||||
variants: {
|
variants: {
|
||||||
normal: '.neutral',
|
normal: '.neutral',
|
||||||
|
info: '.info',
|
||||||
error: '.error',
|
error: '.error',
|
||||||
warning: '.warning',
|
warning: '.warning',
|
||||||
success: '.success',
|
success: '.success',
|
||||||
|
|
@ -47,5 +48,11 @@ export default {
|
||||||
background: '--cGreen',
|
background: '--cGreen',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
variant: 'info',
|
||||||
|
directives: {
|
||||||
|
background: '--cBlue',
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,9 +31,7 @@ const Announcement = {
|
||||||
canEditAnnouncement() {
|
canEditAnnouncement() {
|
||||||
return (
|
return (
|
||||||
this.currentUser &&
|
this.currentUser &&
|
||||||
this.currentUser.privileges.includes(
|
this.currentUser.privileges.has('announcements_manage_announcements')
|
||||||
'announcements_manage_announcements',
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
content() {
|
content() {
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ const Interactions = {
|
||||||
allowFollowingMove:
|
allowFollowingMove:
|
||||||
this.$store.state.users.currentUser.allow_following_move,
|
this.$store.state.users.currentUser.allow_following_move,
|
||||||
filterMode: tabModeDict.mentions,
|
filterMode: tabModeDict.mentions,
|
||||||
canSeeReports: this.$store.state.users.currentUser.privileges.includes(
|
canSeeReports: this.$store.state.users.currentUser.has.has(
|
||||||
'reports_manage_reports',
|
'reports_manage_reports',
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ const List = {
|
||||||
},
|
},
|
||||||
getKey: {
|
getKey: {
|
||||||
type: Function,
|
type: Function,
|
||||||
default: (item) => item,
|
default: (item) => item.id,
|
||||||
},
|
},
|
||||||
getClass: {
|
getClass: {
|
||||||
type: Function,
|
type: Function,
|
||||||
|
|
@ -37,7 +37,7 @@ const List = {
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
emits: ['fetchRequested'],
|
emits: ['fetchRequested', 'select'],
|
||||||
components: {
|
components: {
|
||||||
Checkbox,
|
Checkbox,
|
||||||
},
|
},
|
||||||
|
|
@ -56,11 +56,14 @@ const List = {
|
||||||
allKeys() {
|
allKeys() {
|
||||||
return new Set(this.finalItems.map(this.getKey))
|
return new Set(this.finalItems.map(this.getKey))
|
||||||
},
|
},
|
||||||
filteredSelected() {
|
selectedItems() {
|
||||||
return [...this.allKeys.values().filter((key) => this.selected.has(key))]
|
return this.items.filter((item) => this.selected.has(this.getKey(item)))
|
||||||
},
|
},
|
||||||
allSelected() {
|
allSelected() {
|
||||||
return this.selected.size === this.finalItems.length
|
return (
|
||||||
|
this.selected.size !== 0 &&
|
||||||
|
this.selected.size === this.finalItems.length
|
||||||
|
)
|
||||||
},
|
},
|
||||||
noneSelected() {
|
noneSelected() {
|
||||||
return this.selected.size === 0
|
return this.selected.size === 0
|
||||||
|
|
@ -101,6 +104,7 @@ const List = {
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.loading = false
|
this.loading = false
|
||||||
this.error = error
|
this.error = error
|
||||||
|
console.error('Error loading list data:', error)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
reset() {
|
reset() {
|
||||||
|
|
@ -124,19 +128,17 @@ const List = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
isSelected(item) {
|
isSelected(item) {
|
||||||
return this.filteredSelected.indexOf(this.getKey(item)) !== -1
|
return this.selected.has(this.getKey(item))
|
||||||
},
|
},
|
||||||
toggle(checked, item) {
|
toggle(checked, item) {
|
||||||
const key = this.getKey(item)
|
const key = this.getKey(item)
|
||||||
const oldChecked = this.isSelected(key)
|
if (checked) {
|
||||||
if (checked !== oldChecked) {
|
this.selected.add(key)
|
||||||
if (checked) {
|
} else {
|
||||||
this.selected.add(key)
|
this.selected.delete(key)
|
||||||
} else {
|
|
||||||
this.selected.delete(key)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this.$emit('selected', this.selected)
|
|
||||||
|
this.$emit('select', this.selected)
|
||||||
},
|
},
|
||||||
toggleAll(value) {
|
toggleAll(value) {
|
||||||
if (value) {
|
if (value) {
|
||||||
|
|
@ -144,7 +146,7 @@ const List = {
|
||||||
} else {
|
} else {
|
||||||
this.selected = new Set([])
|
this.selected = new Set([])
|
||||||
}
|
}
|
||||||
this.$emit('selected', this.selected)
|
this.$emit('select', this.selected)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<slot
|
<slot
|
||||||
name="header"
|
name="header"
|
||||||
:selected="filteredSelected"
|
:selected="selectedItems"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
import DialogModal from 'src/components/dialog_modal/dialog_modal.vue'
|
import { last } from 'lodash'
|
||||||
|
|
||||||
|
import ConfirmModal from 'src/components/confirm_modal/confirm_modal.vue'
|
||||||
import Popover from 'src/components/popover/popover.vue'
|
import Popover from 'src/components/popover/popover.vue'
|
||||||
|
|
||||||
|
import { useAdminSettingsStore } from 'src/stores/admin_settings.js'
|
||||||
import { useInstanceStore } from 'src/stores/instance.js'
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
||||||
|
|
||||||
|
|
@ -16,41 +19,372 @@ const DISABLE_REMOTE_SUBSCRIPTION = 'mrf_tag:disable-remote-subscription'
|
||||||
const DISABLE_ANY_SUBSCRIPTION = 'mrf_tag:disable-any-subscription'
|
const DISABLE_ANY_SUBSCRIPTION = 'mrf_tag:disable-any-subscription'
|
||||||
const SANDBOX = 'mrf_tag:sandbox'
|
const SANDBOX = 'mrf_tag:sandbox'
|
||||||
const QUARANTINE = 'mrf_tag:quarantine'
|
const QUARANTINE = 'mrf_tag:quarantine'
|
||||||
|
const TAGS = new Set([
|
||||||
|
FORCE_NSFW,
|
||||||
|
STRIP_MEDIA,
|
||||||
|
FORCE_UNLISTED,
|
||||||
|
DISABLE_REMOTE_SUBSCRIPTION,
|
||||||
|
DISABLE_ANY_SUBSCRIPTION,
|
||||||
|
SANDBOX,
|
||||||
|
QUARANTINE,
|
||||||
|
])
|
||||||
|
|
||||||
|
const ENTRIES = [
|
||||||
|
{
|
||||||
|
check: '!state:activated',
|
||||||
|
label: 'user_card.admin_menu.activate_account',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
check: 'state:activated',
|
||||||
|
label: 'user_card.admin_menu.deactivate_account',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
separator: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
check: '!state:confirmed',
|
||||||
|
label: 'user_card.admin_menu.confirm_account',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
check: 'action:resend_confirmation',
|
||||||
|
conditions: ['!state:confirmed'],
|
||||||
|
label: 'user_card.admin_menu.resend_confirmation',
|
||||||
|
},
|
||||||
|
// No API for revocation
|
||||||
|
// {
|
||||||
|
// check: 'state:confirmed',
|
||||||
|
// label: 'user_card.admin_menu.unconfirm_account',
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
check: '!state:approved',
|
||||||
|
conditions: ['property:local'],
|
||||||
|
label: 'user_card.admin_menu.approve_account',
|
||||||
|
},
|
||||||
|
// No API for revocation
|
||||||
|
// {
|
||||||
|
// check: 'state:approved',
|
||||||
|
// label: 'user_card.admin_menu.unapprove_account',
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
check: '!state:suggested',
|
||||||
|
// conditions: ['property:local'], // TODO Should we allow non-local users in suggested?
|
||||||
|
label: 'user_card.admin_menu.suggest_account',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
check: 'state:suggested',
|
||||||
|
label: 'user_card.admin_menu.remove_suggested_account',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
separator: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
check: '!state:disable_mfa',
|
||||||
|
label: 'user_card.admin_menu.disable_mfa',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
check: '!state:require_password_change',
|
||||||
|
label: 'user_card.admin_menu.require_password_change',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
separator: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
check: '!rights:moderator',
|
||||||
|
label: 'user_card.admin_menu.grant_moderator',
|
||||||
|
conditions: ['property:local', 'state:activated'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
check: 'rights:moderator',
|
||||||
|
label: 'user_card.admin_menu.revoke_moderator',
|
||||||
|
conditions: ['property:local', 'state:activated'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
check: '!rights:admin',
|
||||||
|
label: 'user_card.admin_menu.grant_admin',
|
||||||
|
conditions: ['property:local', 'state:activated'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
check: 'rights:admin',
|
||||||
|
label: 'user_card.admin_menu.revoke_admin',
|
||||||
|
conditions: ['property:local', 'state:activated'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
separator: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
check: FORCE_NSFW,
|
||||||
|
label: 'user_card.admin_menu.force_nsfw',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
check: STRIP_MEDIA,
|
||||||
|
label: 'user_card.admin_menu.strip_media',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
check: FORCE_UNLISTED,
|
||||||
|
label: 'user_card.admin_menu.force_unlisted',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
check: SANDBOX,
|
||||||
|
label: 'user_card.admin_menu.sandbox',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
check: DISABLE_ANY_SUBSCRIPTION,
|
||||||
|
conditions: ['property:local'],
|
||||||
|
label: 'user_card.admin_menu.disable_any_subscription',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
check: DISABLE_REMOTE_SUBSCRIPTION,
|
||||||
|
conditions: ['property:local'],
|
||||||
|
label: 'user_card.admin_menu.disable_remote_subscription',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
check: QUARANTINE,
|
||||||
|
conditions: ['property:local'],
|
||||||
|
label: 'user_card.admin_menu.quarantine',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
separator: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
check: 'action:delete',
|
||||||
|
label: 'user_card.admin_menu.delete_account',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
const ModerationTools = {
|
const ModerationTools = {
|
||||||
props: ['user'],
|
props: {
|
||||||
|
users: {
|
||||||
|
type: Array,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
if (this.users.length !== 1) return
|
||||||
|
useAdminSettingsStore().getUserData({ user: this.users[0] })
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
tags: {
|
open: false,
|
||||||
FORCE_NSFW,
|
confirmDialogShow: false,
|
||||||
STRIP_MEDIA,
|
confirmDialogTitle: null,
|
||||||
FORCE_UNLISTED,
|
confirmDialogContent: null,
|
||||||
DISABLE_REMOTE_SUBSCRIPTION,
|
confirmDialogConfirm: null,
|
||||||
DISABLE_ANY_SUBSCRIPTION,
|
confirmDialogAction: null,
|
||||||
SANDBOX,
|
confirmDialogGroup: null,
|
||||||
QUARANTINE,
|
confirmDialogName: null,
|
||||||
},
|
|
||||||
showDeleteUserDialog: false,
|
|
||||||
toggled: false,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
DialogModal,
|
ConfirmModal,
|
||||||
Popover,
|
Popover,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
ready() {
|
||||||
|
return this.users.every((u) => u.adminData)
|
||||||
|
},
|
||||||
|
entries() {
|
||||||
|
return ENTRIES.map(({ check, label, separator, conditions }) => {
|
||||||
|
if (separator) return 'separator'
|
||||||
|
const [, negateToken, group, name] = /^([!~]?)([a-z-_]+):([a-z-_]+)$/.exec(
|
||||||
|
check,
|
||||||
|
)
|
||||||
|
|
||||||
|
const hasTag = this.tagsSet.has(`${group}:${name}`)
|
||||||
|
const noTag = this.tagsSet.has(`!${group}:${name}`)
|
||||||
|
const maybeTag = this.tagsSet.has(`~${group}:${name}`)
|
||||||
|
|
||||||
|
// We are checking for condition to show element, i.e. only show "activate" if user is "deactivated"
|
||||||
|
const checkNegated = (negateToken === '!' || negateToken === '~')
|
||||||
|
|
||||||
|
// Naturally, new value should also be the same
|
||||||
|
const value = checkNegated
|
||||||
|
|
||||||
|
const action = (() => {
|
||||||
|
switch (group) {
|
||||||
|
case 'rights':
|
||||||
|
return () => this.setRight(name, value)
|
||||||
|
case 'state':
|
||||||
|
return () => this.setStatus(name, value)
|
||||||
|
case 'mrf_tag':
|
||||||
|
return () => this.setTag(`${group}:${name}`, noTag)
|
||||||
|
case 'action': {
|
||||||
|
switch (name) {
|
||||||
|
case 'delete': {
|
||||||
|
return () => this.deleteUsers()
|
||||||
|
}
|
||||||
|
case 'resend_confirmation': {
|
||||||
|
return () => this.resendConfirmationEmail()
|
||||||
|
}
|
||||||
|
case 'disable_mfa': {
|
||||||
|
return () => this.disableMFA()
|
||||||
|
}
|
||||||
|
case 'require_password_change': {
|
||||||
|
return () => this.requirePasswordChange()
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new Error(`Unknown action group: ${name}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new Error(`Unknown moderation group: ${group}`)
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
|
||||||
|
let checkboxClass = ''
|
||||||
|
if (maybeTag) {
|
||||||
|
checkboxClass = 'menu-checkbox-indeterminate'
|
||||||
|
} else if (hasTag) {
|
||||||
|
checkboxClass = 'menu-checkbox-checked'
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
check,
|
||||||
|
negateToken,
|
||||||
|
checkbox: group === 'mrf_tag',
|
||||||
|
checkboxClass,
|
||||||
|
conditions,
|
||||||
|
group,
|
||||||
|
name,
|
||||||
|
action,
|
||||||
|
label,
|
||||||
|
value,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter((entry) => {
|
||||||
|
if (entry === 'separator') return true
|
||||||
|
const { group, name, value, conditions } = entry
|
||||||
|
|
||||||
|
if (conditions) {
|
||||||
|
// Checking that all items match positive criteria
|
||||||
|
const positive = conditions.every((condition) =>
|
||||||
|
this.totalSet.has(condition),
|
||||||
|
)
|
||||||
|
// Checking that there are no items that don't match criteria
|
||||||
|
const negative = conditions.some((condition) =>
|
||||||
|
this.totalSet.has('!' + condition),
|
||||||
|
)
|
||||||
|
if (!(positive && !negative)) return false
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (group) {
|
||||||
|
case 'action': {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case 'rights': {
|
||||||
|
return this.canGrantRole(name, value)
|
||||||
|
}
|
||||||
|
case 'state': {
|
||||||
|
return this.canChangeState(name, value)
|
||||||
|
}
|
||||||
|
case 'mrf_tag': {
|
||||||
|
return this.canUseTagPolicy
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
throw new Error(`Unknown moderation group: ${group}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.reduce((acc, entry, index) => {
|
||||||
|
if (entry === 'separator') {
|
||||||
|
if (
|
||||||
|
acc.length === 0 ||
|
||||||
|
last(acc) === 'separator' ||
|
||||||
|
index === ENTRIES.length - 1
|
||||||
|
) {
|
||||||
|
return acc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [...acc, entry]
|
||||||
|
}, [])
|
||||||
|
},
|
||||||
|
rightsSet() {
|
||||||
|
return this.users.reduce((acc, user) => {
|
||||||
|
if (user.rights.admin) {
|
||||||
|
acc.add('rights:admin')
|
||||||
|
} else {
|
||||||
|
acc.add('!rights:admin')
|
||||||
|
}
|
||||||
|
if (user.rights.moderator) {
|
||||||
|
acc.add('rights:moderator')
|
||||||
|
} else {
|
||||||
|
acc.add('!rights:moderator')
|
||||||
|
}
|
||||||
|
return acc
|
||||||
|
}, new Set())
|
||||||
|
},
|
||||||
|
stateSet() {
|
||||||
|
return this.users.reduce((acc, user) => {
|
||||||
|
if (!user.deactivated) {
|
||||||
|
acc.add('state:activated')
|
||||||
|
} else {
|
||||||
|
acc.add('!state:activated')
|
||||||
|
}
|
||||||
|
if (user.adminData?.is_confirmed) {
|
||||||
|
acc.add('state:confirmed')
|
||||||
|
} else {
|
||||||
|
acc.add('!state:confirmed')
|
||||||
|
}
|
||||||
|
if (user.adminData?.is_approved) {
|
||||||
|
acc.add('state:approved')
|
||||||
|
} else {
|
||||||
|
acc.add('!state:approved')
|
||||||
|
}
|
||||||
|
if (user.adminData?.is_suggested) {
|
||||||
|
acc.add('state:suggested')
|
||||||
|
} else {
|
||||||
|
acc.add('!state:suggested')
|
||||||
|
}
|
||||||
|
return acc
|
||||||
|
}, new Set())
|
||||||
|
},
|
||||||
tagsSet() {
|
tagsSet() {
|
||||||
return new Set(this.user.tags)
|
const present = new Set()
|
||||||
|
const missing = new Set()
|
||||||
|
|
||||||
|
this.users.forEach((user) => {
|
||||||
|
TAGS.forEach((tag) => {
|
||||||
|
if (user.tags.has(tag)) {
|
||||||
|
present.add(tag)
|
||||||
|
} else {
|
||||||
|
missing.add(tag)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const result = new Set()
|
||||||
|
|
||||||
|
TAGS.forEach((tag) => {
|
||||||
|
if (present.has(tag) && missing.has(tag)) {
|
||||||
|
result.add(`~${tag}`)
|
||||||
|
} else if (missing.has(tag)) {
|
||||||
|
result.add(`!${tag}`)
|
||||||
|
} else {
|
||||||
|
result.add(tag)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return result
|
||||||
},
|
},
|
||||||
canGrantRole() {
|
propertySet() {
|
||||||
return (
|
return this.users.reduce((acc, user) => {
|
||||||
this.user.is_local &&
|
if (user.is_local) {
|
||||||
!this.user.deactivated &&
|
acc.add('property:local')
|
||||||
this.$store.state.users.currentUser.role === 'admin'
|
} else {
|
||||||
)
|
acc.add('!property:local')
|
||||||
|
}
|
||||||
|
return acc
|
||||||
|
}, new Set())
|
||||||
},
|
},
|
||||||
canChangeActivationState() {
|
disabled() {
|
||||||
return this.privileged('users_manage_activation_state')
|
return !this.ready || this.users.length === 0
|
||||||
|
},
|
||||||
|
totalSet() {
|
||||||
|
return new Set([
|
||||||
|
...this.rightsSet,
|
||||||
|
...this.stateSet,
|
||||||
|
...this.tagsSet,
|
||||||
|
...this.propertySet,
|
||||||
|
])
|
||||||
},
|
},
|
||||||
canDeleteAccount() {
|
canDeleteAccount() {
|
||||||
return this.privileged('users_delete')
|
return this.privileged('users_delete')
|
||||||
|
|
@ -63,87 +397,221 @@ const ModerationTools = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
hasTag(tagName) {
|
canGrantRole(name, value) {
|
||||||
return this.tagsSet.has(tagName)
|
const setEntry = `${value ? '!' : ''}rights:${name}`
|
||||||
|
|
||||||
|
return (
|
||||||
|
this.$store.state.users.currentUser.role === 'admin' &&
|
||||||
|
this.totalSet.has(setEntry)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
canChangeState(name, value) {
|
||||||
|
let privilege
|
||||||
|
|
||||||
|
switch (name) {
|
||||||
|
// TODO detailed privileges
|
||||||
|
default: {
|
||||||
|
privilege = 'users_manage_activation_state'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const setEntry = `${value ? '!' : ''}state:${name}`
|
||||||
|
|
||||||
|
return this.privileged(privilege) && this.totalSet.has(setEntry)
|
||||||
|
},
|
||||||
|
doConfirmDialogAction() {
|
||||||
|
if (typeof this.confirmDialogAction !== 'function') {
|
||||||
|
console.error('Confirm Dialog action is not a function!!')
|
||||||
|
}
|
||||||
|
|
||||||
|
this.confirmDialogAction()
|
||||||
|
this.clearConfirmDialog()
|
||||||
|
},
|
||||||
|
clearConfirmDialog() {
|
||||||
|
this.confirmDialogShow = false
|
||||||
|
this.confirmDialogTitle = null
|
||||||
|
this.confirmDialogContent = null
|
||||||
|
this.confirmDialogContent2 = null
|
||||||
|
this.confirmDialogDanger = false
|
||||||
|
this.confirmDialogConfirm = null
|
||||||
|
this.confirmDialogAction = null
|
||||||
|
this.confirmDialogGroup = null
|
||||||
|
this.confirmDialogName = null
|
||||||
},
|
},
|
||||||
privileged(privilege) {
|
privileged(privilege) {
|
||||||
return this.$store.state.users.currentUser.privileges.includes(privilege)
|
return this.$store.state.users.currentUser.privileges.has(privilege)
|
||||||
},
|
},
|
||||||
toggleTag(tag) {
|
setTag(tag, value) {
|
||||||
const store = this.$store
|
useAdminSettingsStore().setUsersTags({ users: this.users, value, tags: [tag] })
|
||||||
if (this.tagsSet.has(tag)) {
|
|
||||||
store.state.api.backendInteractor
|
|
||||||
.untagUser({ user: this.user, tag })
|
|
||||||
.then((response) => {
|
|
||||||
if (!response.ok) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
store.commit('untagUser', { user: this.user, tag })
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
store.state.api.backendInteractor
|
|
||||||
.tagUser({ user: this.user, tag })
|
|
||||||
.then((response) => {
|
|
||||||
if (!response.ok) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
store.commit('tagUser', { user: this.user, tag })
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
toggleRight(right) {
|
setRight(right, value) {
|
||||||
const store = this.$store
|
useAdminSettingsStore().setUsersRight({ users: this.users, value, right })
|
||||||
if (this.user.rights[right]) {
|
|
||||||
store.state.api.backendInteractor
|
|
||||||
.deleteRight({ user: this.user, right })
|
|
||||||
.then((response) => {
|
|
||||||
if (!response.ok) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
store.commit('updateRight', {
|
|
||||||
user: this.user,
|
|
||||||
right,
|
|
||||||
value: false,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
store.state.api.backendInteractor
|
|
||||||
.addRight({ user: this.user, right })
|
|
||||||
.then((response) => {
|
|
||||||
if (!response.ok) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
store.commit('updateRight', { user: this.user, right, value: true })
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
toggleActivationStatus() {
|
setStatus(name, value) {
|
||||||
this.$store.dispatch('toggleActivationStatus', { user: this.user })
|
const noun = (() => {
|
||||||
},
|
switch (name) {
|
||||||
deleteUserDialog(show) {
|
case 'activated':
|
||||||
this.showDeleteUserDialog = show
|
return 'Activation'
|
||||||
},
|
case 'confirmed':
|
||||||
deleteUser() {
|
return 'Confirmation'
|
||||||
const store = this.$store
|
case 'approved':
|
||||||
const user = this.user
|
return 'Approval'
|
||||||
const { id, name } = user
|
case 'suggested':
|
||||||
store.state.api.backendInteractor.deleteUser({ user }).then(() => {
|
return 'Suggestion'
|
||||||
this.$store.dispatch(
|
|
||||||
'markStatusesAsDeleted',
|
|
||||||
(status) => user.id === status.user.id,
|
|
||||||
)
|
|
||||||
const isProfile =
|
|
||||||
this.$route.name === 'external-user-profile' ||
|
|
||||||
this.$route.name === 'user-profile'
|
|
||||||
const isTargetUser =
|
|
||||||
this.$route.params.name === name || this.$route.params.id === id
|
|
||||||
if (isProfile && isTargetUser) {
|
|
||||||
window.history.back()
|
|
||||||
}
|
}
|
||||||
|
})()
|
||||||
|
|
||||||
|
useAdminSettingsStore()[`setUsers${noun}Status`]({
|
||||||
|
users: this.users,
|
||||||
|
value,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
setToggled(value) {
|
resendConfirmationEmail() {
|
||||||
this.toggled = value
|
useAdminSettingsStore().resendConfirmationEmail({ users: this.users })
|
||||||
|
},
|
||||||
|
requirePasswordChange() {
|
||||||
|
useAdminSettingsStore().requirePasswordChange({ users: this.users })
|
||||||
|
},
|
||||||
|
disableMFA() {
|
||||||
|
this.users.forEach((user) => {
|
||||||
|
useAdminSettingsStore().disableMFA({ user })
|
||||||
|
})
|
||||||
|
},
|
||||||
|
deleteUsers() {
|
||||||
|
const { id, name } = this.users[0]
|
||||||
|
|
||||||
|
useAdminSettingsStore()
|
||||||
|
.deleteUsers({ users: this.users })
|
||||||
|
.then((userIds) => {
|
||||||
|
if (userIds.length > 1) return
|
||||||
|
|
||||||
|
const isProfile =
|
||||||
|
this.$route.name === 'external-user-profile' ||
|
||||||
|
this.$route.name === 'user-profile'
|
||||||
|
const isTargetUser =
|
||||||
|
this.$route.params.name === name || this.$route.params.id === id
|
||||||
|
|
||||||
|
if (isProfile && isTargetUser) {
|
||||||
|
window.history.back()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
setOpen(value) {
|
||||||
|
this.open = value
|
||||||
|
},
|
||||||
|
maybeShowConfirm(close, { group, name, action, value }) {
|
||||||
|
close()
|
||||||
|
this.confirmDialogName = name
|
||||||
|
this.confirmDialogGroup = group
|
||||||
|
this.confirmDialogAction = () => action()
|
||||||
|
|
||||||
|
switch (group) {
|
||||||
|
case 'action': {
|
||||||
|
if (name === 'delete') {
|
||||||
|
this.confirmDialogShow = true
|
||||||
|
this.confirmDialogTitle = this.$t(
|
||||||
|
'user_card.admin_menu.confirm_modal.delete_title',
|
||||||
|
)
|
||||||
|
this.confirmDialogDanger = true
|
||||||
|
this.confirmDialogContent =
|
||||||
|
'user_card.admin_menu.confirm_modal.delete_content'
|
||||||
|
this.confirmDialogContent2 =
|
||||||
|
'user_card.admin_menu.confirm_modal.delete_content_2'
|
||||||
|
this.confirmDialogConfirm = this.$t(
|
||||||
|
'user_card.admin_menu.confirm_modal.delete',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'state': {
|
||||||
|
switch (name) {
|
||||||
|
case 'activated': {
|
||||||
|
this.confirmDialogShow = true
|
||||||
|
|
||||||
|
this.confirmDialogTitle = this.$t(
|
||||||
|
'user_card.admin_menu.confirm_modal.activate_title',
|
||||||
|
)
|
||||||
|
this.confirmDialogContent = value
|
||||||
|
? 'user_card.admin_menu.confirm_modal.activate_content'
|
||||||
|
: 'user_card.admin_menu.confirm_modal.deactivate_content'
|
||||||
|
this.confirmDialogConfirm = value
|
||||||
|
? this.$t('user_card.admin_menu.confirm_modal.activate')
|
||||||
|
: this.$t('user_card.admin_menu.confirm_modal.deactivate')
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// Confirmation and Approval statuses cannot be revokedn(no API)
|
||||||
|
case 'confirmed': {
|
||||||
|
this.confirmDialogTitle = this.$t(
|
||||||
|
'user_card.admin_menu.confirm_modal.confirm_title',
|
||||||
|
)
|
||||||
|
this.confirmDialogContent = //value
|
||||||
|
/*?*/ 'user_card.admin_menu.confirm_modal.confirm_content'
|
||||||
|
//: 'user_card.admin_menu.confirm_modal.confirm_revoke_content'
|
||||||
|
this.confirmDialogConfirm = value
|
||||||
|
/*?*/ this.$t('user_card.admin_menu.confirm_modal.confirm')
|
||||||
|
//: this.$t('user_card.admin_menu.confirm_modal.revoke')
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'approved': {
|
||||||
|
this.confirmDialogTitle = this.$t(
|
||||||
|
'user_card.admin_menu.confirm_modal.approval_title',
|
||||||
|
)
|
||||||
|
this.confirmDialogContent = //value
|
||||||
|
/*?*/ 'user_card.admin_menu.confirm_modal.approval_content'
|
||||||
|
//: 'user_card.admin_menu.confirm_modal.approval_revoke_content'
|
||||||
|
this.confirmDialogConfirm = value
|
||||||
|
/*?*/ this.$t('user_card.admin_menu.confirm_modal.approve')
|
||||||
|
//: this.$t('user_card.admin_menu.confirm_modal.revoke')
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'suggest': {
|
||||||
|
this.confirmDialogTitle = this.$t(
|
||||||
|
'user_card.admin_menu.confirm_modal.suggest_title',
|
||||||
|
)
|
||||||
|
this.confirmDialogContent = value
|
||||||
|
? 'user_card.admin_menu.confirm_modal.add_suggest_content'
|
||||||
|
: 'user_card.admin_menu.confirm_modal.remove_suggest_content'
|
||||||
|
this.confirmDialogConfirm = value
|
||||||
|
? this.$t('user_card.admin_menu.confirm_modal.add')
|
||||||
|
: this.$t('user_card.admin_menu.confirm_modal.remove')
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'rights': {
|
||||||
|
this.confirmDialogTitle = this.$t(
|
||||||
|
'user_card.admin_menu.confirm_modal.user_rights_title',
|
||||||
|
)
|
||||||
|
this.confirmDialogContent = value
|
||||||
|
? 'user_card.admin_menu.confirm_modal.grant_role_content'
|
||||||
|
: 'user_card.admin_menu.confirm_modal.revoke_role_content'
|
||||||
|
this.confirmDialogConfirm = value
|
||||||
|
? this.$t('user_card.admin_menu.confirm_modal.grant')
|
||||||
|
: this.$t('user_card.admin_menu.confirm_modal.revoke')
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'mrf_tag': {
|
||||||
|
this.confirmDialogTitle = this.$t(
|
||||||
|
'user_card.admin_menu.user_tag_title',
|
||||||
|
)
|
||||||
|
this.confirmDialogContent = value
|
||||||
|
? 'user_card.admin_menu.confirm_modal.assign_tag_content'
|
||||||
|
: 'user_card.admin_menu.confirm_modal.unassign_tag_content'
|
||||||
|
this.confirmDialogConfirm = value
|
||||||
|
? this.$t('user_card.admin_menu.confirm_modal.assign')
|
||||||
|
: this.$t('user_card.admin_menu.confirm_modal.unassign')
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.users.length > 1) {
|
||||||
|
this.confirmDialogShow = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.confirmDialogShow) {
|
||||||
|
this.doConfirmDialogAction()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,154 +3,37 @@
|
||||||
<Popover
|
<Popover
|
||||||
trigger="click"
|
trigger="click"
|
||||||
class="moderation-tools-popover"
|
class="moderation-tools-popover"
|
||||||
|
:disabled="disabled"
|
||||||
placement="bottom"
|
placement="bottom"
|
||||||
:offset="{ y: 5 }"
|
:offset="{ y: 5 }"
|
||||||
@show="setToggled(true)"
|
@show="setOpen(true)"
|
||||||
@close="setToggled(false)"
|
@close="setOpen(false)"
|
||||||
>
|
>
|
||||||
<template #content>
|
<template #content="{close}">
|
||||||
<div class="dropdown-menu">
|
<div class="dropdown-menu">
|
||||||
<template v-if="canGrantRole">
|
<template v-for="(entry, index) in entries">
|
||||||
<div class="menu-item dropdown-item -icon-space">
|
|
||||||
<button
|
|
||||||
class="main-button"
|
|
||||||
@click="toggleRight("admin")"
|
|
||||||
>
|
|
||||||
{{ $t(!!user.rights.admin ? 'user_card.admin_menu.revoke_admin' : 'user_card.admin_menu.grant_admin') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="menu-item dropdown-item -icon-space">
|
|
||||||
<button
|
|
||||||
class="main-button"
|
|
||||||
@click="toggleRight("moderator")"
|
|
||||||
>
|
|
||||||
{{ $t(!!user.rights.moderator ? 'user_card.admin_menu.revoke_moderator' : 'user_card.admin_menu.grant_moderator') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div
|
<div
|
||||||
v-if="canChangeActivationState || canDeleteAccount"
|
v-if="entry === 'separator'"
|
||||||
|
:key="index"
|
||||||
role="separator"
|
role="separator"
|
||||||
class="dropdown-divider"
|
class="dropdown-divider"
|
||||||
/>
|
/>
|
||||||
</template>
|
|
||||||
<div
|
|
||||||
v-if="canChangeActivationState"
|
|
||||||
class="menu-item dropdown-item -icon-space"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="main-button"
|
|
||||||
@click="toggleActivationStatus()"
|
|
||||||
>
|
|
||||||
{{ $t(!!user.deactivated ? 'user_card.admin_menu.activate_account' : 'user_card.admin_menu.deactivate_account') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-if="canDeleteAccount"
|
|
||||||
class="menu-item dropdown-item -icon-space"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="main-button"
|
|
||||||
@click="deleteUserDialog(true)"
|
|
||||||
>
|
|
||||||
{{ $t('user_card.admin_menu.delete_account') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<template v-if="canUseTagPolicy">
|
|
||||||
<div
|
<div
|
||||||
role="separator"
|
v-else
|
||||||
class="dropdown-divider"
|
:key="entry.label"
|
||||||
/>
|
class="menu-item dropdown-item"
|
||||||
<div class="menu-item dropdown-item -icon">
|
:class="entry.checkbox ? '-icon' : '-icon-space'"
|
||||||
<button
|
|
||||||
class="main-button"
|
|
||||||
@click="toggleTag(tags.FORCE_NSFW)"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
class="input menu-checkbox"
|
|
||||||
:class="{ 'menu-checkbox-checked': hasTag(tags.FORCE_NSFW) }"
|
|
||||||
/>
|
|
||||||
{{ $t('user_card.admin_menu.force_nsfw') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="menu-item dropdown-item -icon">
|
|
||||||
<button
|
|
||||||
class="main-button"
|
|
||||||
@click="toggleTag(tags.STRIP_MEDIA)"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
class="input menu-checkbox"
|
|
||||||
:class="{ 'menu-checkbox-checked': hasTag(tags.STRIP_MEDIA) }"
|
|
||||||
/>
|
|
||||||
{{ $t('user_card.admin_menu.strip_media') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="menu-item dropdown-item -icon">
|
|
||||||
<button
|
|
||||||
class="main-button"
|
|
||||||
@click="toggleTag(tags.FORCE_UNLISTED)"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
class="input menu-checkbox"
|
|
||||||
:class="{ 'menu-checkbox-checked': hasTag(tags.FORCE_UNLISTED) }"
|
|
||||||
/>
|
|
||||||
{{ $t('user_card.admin_menu.force_unlisted') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="menu-item dropdown-item -icon">
|
|
||||||
<button
|
|
||||||
class="main-button"
|
|
||||||
@click="toggleTag(tags.SANDBOX)"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
class="input menu-checkbox"
|
|
||||||
:class="{ 'menu-checkbox-checked': hasTag(tags.SANDBOX) }"
|
|
||||||
/>
|
|
||||||
{{ $t('user_card.admin_menu.sandbox') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-if="user.is_local"
|
|
||||||
class="menu-item dropdown-item -icon"
|
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="main-button"
|
class="main-button"
|
||||||
@click="toggleTag(tags.DISABLE_REMOTE_SUBSCRIPTION)"
|
@click="() => maybeShowConfirm(close, entry)"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
|
v-if="entry.checkbox"
|
||||||
class="input menu-checkbox"
|
class="input menu-checkbox"
|
||||||
:class="{ 'menu-checkbox-checked': hasTag(tags.DISABLE_REMOTE_SUBSCRIPTION) }"
|
:class="entry.checkboxClass"
|
||||||
/>
|
/>
|
||||||
{{ $t('user_card.admin_menu.disable_remote_subscription') }}
|
{{ $t(entry.label) }}
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-if="user.is_local"
|
|
||||||
class="menu-item dropdown-item -icon"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="main-button"
|
|
||||||
@click="toggleTag(tags.DISABLE_ANY_SUBSCRIPTION)"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
class="input menu-checkbox"
|
|
||||||
:class="{ 'menu-checkbox-checked': hasTag(tags.DISABLE_ANY_SUBSCRIPTION) }"
|
|
||||||
/>
|
|
||||||
{{ $t('user_card.admin_menu.disable_any_subscription') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-if="user.is_local"
|
|
||||||
class="menu-item dropdown-item -icon"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="main-button"
|
|
||||||
@click="toggleTag(tags.QUARANTINE)"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
class="input menu-checkbox"
|
|
||||||
:class="{ 'menu-checkbox-checked': hasTag(tags.QUARANTINE) }"
|
|
||||||
/>
|
|
||||||
{{ $t('user_card.admin_menu.quarantine') }}
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -159,37 +42,60 @@
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<button
|
<button
|
||||||
class="btn button-default btn-block moderation-tools-button"
|
class="btn button-default btn-block moderation-tools-button"
|
||||||
:class="{ toggled }"
|
:class="{ toggled: open, disabled }"
|
||||||
|
:disabled="disabled"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.admin_menu.moderation') }}
|
{{ $t('user_card.admin_menu.moderation') }}
|
||||||
<FAIcon icon="chevron-down" />
|
<FAIcon v-if="ready" icon="chevron-down" />
|
||||||
|
<span v-else class="loading-spinner">
|
||||||
|
<FAIcon
|
||||||
|
class="fa-old-padding"
|
||||||
|
spin
|
||||||
|
icon="circle-notch"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
</Popover>
|
</Popover>
|
||||||
<teleport to="#modal">
|
<teleport to="#modal">
|
||||||
<DialogModal
|
<ConfirmModal
|
||||||
v-if="showDeleteUserDialog"
|
v-if="confirmDialogShow"
|
||||||
:on-cancel="deleteUserDialog.bind(this, false)"
|
:title="$t(confirmDialogTitle)"
|
||||||
|
:confirm-text="confirmDialogConfirm"
|
||||||
|
:confirm-danger="confirmDialogDanger"
|
||||||
|
:cancel-text="$t('general.cancel')"
|
||||||
|
@accepted="doConfirmDialogAction"
|
||||||
|
@cancelled="clearConfirmDialog"
|
||||||
>
|
>
|
||||||
<template #header>
|
<i18n-t
|
||||||
{{ $t('user_card.admin_menu.delete_user') }}
|
:plural="users.length"
|
||||||
</template>
|
scope="global"
|
||||||
<p>{{ $t('user_card.admin_menu.delete_user_confirmation') }}</p>
|
:keypath="confirmDialogContent"
|
||||||
<template #footer>
|
tag="p"
|
||||||
<button
|
>
|
||||||
class="btn button-default"
|
<template #user>
|
||||||
@click="deleteUserDialog(false)"
|
<span
|
||||||
>
|
v-text="users[0].screen_name_ui"
|
||||||
{{ $t('general.cancel') }}
|
/>
|
||||||
</button>
|
</template>
|
||||||
<button
|
<template #count>
|
||||||
class="btn button-default danger"
|
{{ users.length }}
|
||||||
@click="deleteUser()"
|
</template>
|
||||||
>
|
<template #name>
|
||||||
{{ $t('user_card.admin_menu.delete_user') }}
|
<code>
|
||||||
</button>
|
{{ confirmDialogName }}
|
||||||
</template>
|
</code>
|
||||||
</DialogModal>
|
</template>
|
||||||
|
</i18n-t>
|
||||||
|
<p v-if="confirmDialogContent2">
|
||||||
|
{{ $t(confirmDialogContent2) }}
|
||||||
|
</p>
|
||||||
|
<ul v-if="users.length > 1">
|
||||||
|
<li v-for="user in users">
|
||||||
|
{{ user.screen_name }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</ConfirmModal>
|
||||||
</teleport>
|
</teleport>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,11 @@
|
||||||
content: "✓";
|
content: "✓";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.menu-checkbox-indeterminate::after {
|
||||||
|
font-size: 1.25em;
|
||||||
|
content: "–";
|
||||||
|
}
|
||||||
|
|
||||||
&.-radio {
|
&.-radio {
|
||||||
border-radius: 9999px;
|
border-radius: 9999px;
|
||||||
|
|
||||||
|
|
@ -103,6 +108,11 @@
|
||||||
font-size: 2em;
|
font-size: 2em;
|
||||||
content: "•";
|
content: "•";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.menu-checkbox-indeterminate::after {
|
||||||
|
font-size: 2em;
|
||||||
|
content: "–";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
import { defineAsyncComponent } from 'vue'
|
import { defineAsyncComponent } from 'vue'
|
||||||
|
|
||||||
import BasicUserCard from 'src/components/basic_user_card/basic_user_card.vue'
|
import BasicUserCard from 'src/components/basic_user_card/basic_user_card.vue'
|
||||||
|
import ModerationTools from 'src/components/moderation_tools/moderation_tools.vue'
|
||||||
import { useAdminUsersStore } from 'src/stores/adminUsers.js'
|
|
||||||
|
|
||||||
const AdminCard = {
|
const AdminCard = {
|
||||||
props: {
|
props: {
|
||||||
|
|
@ -12,23 +11,15 @@ const AdminCard = {
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
BasicUserCard,
|
BasicUserCard,
|
||||||
ModerationTools: defineAsyncComponent(
|
ModerationTools,
|
||||||
() => import('src/components/moderation_tools/moderation_tools.vue'),
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
user() {
|
user() {
|
||||||
return this.$store.getters.findUser(this.userId)
|
return this.$store.getters.findUser(this.userId)
|
||||||
},
|
},
|
||||||
userAdminData() {
|
|
||||||
return useAdminUsersStore().getUser(this.userId)
|
|
||||||
},
|
|
||||||
relationship() {
|
relationship() {
|
||||||
return this.$store.getters.relationship(this.userId)
|
return this.$store.getters.relationship(this.userId)
|
||||||
},
|
},
|
||||||
isLocal() {
|
|
||||||
return this.user.is_local
|
|
||||||
},
|
|
||||||
isAdmin() {
|
isAdmin() {
|
||||||
return this.user.rights.admin
|
return this.user.rights.admin
|
||||||
},
|
},
|
||||||
|
|
@ -38,12 +29,6 @@ const AdminCard = {
|
||||||
isActivated() {
|
isActivated() {
|
||||||
return !this.user.deactivated
|
return !this.user.deactivated
|
||||||
},
|
},
|
||||||
isApproved() {
|
|
||||||
return this.userAdminData.is_approved
|
|
||||||
},
|
|
||||||
isConfirmed() {
|
|
||||||
return this.userAdminData.is_confirmed
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
</label>
|
</label>
|
||||||
<label
|
<label
|
||||||
v-if="isActivated"
|
v-if="isActivated"
|
||||||
class="alert info user-role"
|
class="alert success user-role"
|
||||||
>
|
>
|
||||||
{{ $t('admin_dash.users.indicator.active') }}
|
{{ $t('admin_dash.users.indicator.active') }}
|
||||||
</label>
|
</label>
|
||||||
|
|
@ -37,14 +37,32 @@
|
||||||
{{ $t('admin_dash.users.indicator.deactivated') }}
|
{{ $t('admin_dash.users.indicator.deactivated') }}
|
||||||
</label>
|
</label>
|
||||||
<label
|
<label
|
||||||
v-if="isConfirmed"
|
v-if="user.adminData.is_confirmed"
|
||||||
class="alert neutral user-role"
|
class="alert success user-role"
|
||||||
>
|
>
|
||||||
{{ $t('admin_dash.users.indicator.confirmed') }}
|
{{ $t('admin_dash.users.indicator.confirmed') }}
|
||||||
</label>
|
</label>
|
||||||
|
<label
|
||||||
|
v-if="!user.adminData.is_confirmed"
|
||||||
|
class="alert warning user-role"
|
||||||
|
>
|
||||||
|
{{ $t('admin_dash.users.indicator.unconfirmed') }}
|
||||||
|
</label>
|
||||||
|
<label
|
||||||
|
v-if="user.adminData.is_approved"
|
||||||
|
class="alert success user-role"
|
||||||
|
>
|
||||||
|
{{ $t('admin_dash.users.indicator.approved') }}
|
||||||
|
</label>
|
||||||
|
<label
|
||||||
|
v-if="!user.adminData.is_approved"
|
||||||
|
class="alert warning user-role"
|
||||||
|
>
|
||||||
|
{{ $t('admin_dash.users.indicator.unapproved') }}
|
||||||
|
</label>
|
||||||
<ModerationTools
|
<ModerationTools
|
||||||
class="moderation-menu"
|
class="moderation-menu"
|
||||||
:user="user"
|
:users="[user]"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</BasicUserCard>
|
</BasicUserCard>
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ const FrontendsTab = {
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
if (this.user.rights.admin) {
|
if (this.user.rights.admin) {
|
||||||
this.$store.dispatch('loadFrontendsStuff')
|
useAdminSettingsStore().loadFrontendsStuff()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
@ -77,7 +77,7 @@ const FrontendsTab = {
|
||||||
this.working = false
|
this.working = false
|
||||||
})
|
})
|
||||||
.then(async (response) => {
|
.then(async (response) => {
|
||||||
this.$store.dispatch('loadFrontendsStuff')
|
useAdminSettingsStore().loadFrontendsStuff()
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
const reason = await response.error.json()
|
const reason = await response.error.json()
|
||||||
useInterfaceStore().pushGlobalNotice({
|
useInterfaceStore().pushGlobalNotice({
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,26 @@ import BasicUserCard from 'src/components/basic_user_card/basic_user_card.vue'
|
||||||
import Checkbox from 'src/components/checkbox/checkbox.vue'
|
import Checkbox from 'src/components/checkbox/checkbox.vue'
|
||||||
import GenericConfirm from 'src/components/confirm_modal/generic_confirm.vue'
|
import GenericConfirm from 'src/components/confirm_modal/generic_confirm.vue'
|
||||||
import List from 'src/components/list/list.vue'
|
import List from 'src/components/list/list.vue'
|
||||||
import Popover from 'src/components/popover/popover.vue'
|
import ModerationTools from 'src/components/moderation_tools/moderation_tools.vue'
|
||||||
import ProgressButton from 'src/components/progress_button/progress_button.vue'
|
import ProgressButton from 'src/components/progress_button/progress_button.vue'
|
||||||
import Select from 'src/components/select/select.vue'
|
import Select from 'src/components/select/select.vue'
|
||||||
import AdminCard from 'src/components/settings_modal/admin_tabs/admin_card.vue'
|
import AdminCard from 'src/components/settings_modal/admin_tabs/admin_card.vue'
|
||||||
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
|
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
|
||||||
|
|
||||||
import { useAdminUsersStore } from 'src/stores/adminUsers.js'
|
import { useAdminSettingsStore } from 'src/stores/admin_settings.js'
|
||||||
|
|
||||||
const UsersTab = {
|
const UsersTab = {
|
||||||
|
components: {
|
||||||
|
Checkbox,
|
||||||
|
Select,
|
||||||
|
BasicUserCard,
|
||||||
|
List,
|
||||||
|
ProgressButton,
|
||||||
|
AdminCard,
|
||||||
|
TabSwitcher,
|
||||||
|
ModerationTools,
|
||||||
|
GenericConfirm,
|
||||||
|
},
|
||||||
provide() {
|
provide() {
|
||||||
return {
|
return {
|
||||||
defaultDraftMode: true,
|
defaultDraftMode: true,
|
||||||
|
|
@ -90,7 +101,7 @@ const UsersTab = {
|
||||||
local: this.filtersLocal,
|
local: this.filtersLocal,
|
||||||
external: this.filtersExternal,
|
external: this.filtersExternal,
|
||||||
needApproval: this.filtersNeedApproval,
|
needApproval: this.filtersNeedApproval,
|
||||||
unconfirmed: this.filtersUnconfirmeUnconfirmed,
|
unconfirmed: this.filtersUnconfirmed,
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
@ -102,51 +113,15 @@ const UsersTab = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
components: {
|
|
||||||
Checkbox,
|
|
||||||
Select,
|
|
||||||
BasicUserCard,
|
|
||||||
List,
|
|
||||||
ProgressButton,
|
|
||||||
AdminCard,
|
|
||||||
TabSwitcher,
|
|
||||||
Popover,
|
|
||||||
GenericConfirm,
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
fetchUsers(page) {
|
fetchUsers(page) {
|
||||||
return useAdminUsersStore()
|
return useAdminSettingsStore()
|
||||||
.fetchAdminUsers({
|
.fetchAdminUsers({
|
||||||
...this.fetchOptions,
|
...this.fetchOptions,
|
||||||
page,
|
page,
|
||||||
})
|
})
|
||||||
.then(({ count, users }) => ({ count, items: users }))
|
.then(({ count, users }) => ({ count, items: users }))
|
||||||
},
|
},
|
||||||
/**
|
|
||||||
* show the confirmation box for bulk actions.
|
|
||||||
* @param {string} box ref name specified for the confirm component
|
|
||||||
*/
|
|
||||||
confirmSelection(box) {
|
|
||||||
this.$refs[box].show()
|
|
||||||
this.$refs.dropdown.hidePopover()
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* called when a bulk action was confirmed
|
|
||||||
* @param {string} action
|
|
||||||
*/
|
|
||||||
selectionConfirmed(action) {
|
|
||||||
const restricted = []
|
|
||||||
const s = this.$refs.userList.getSelected()
|
|
||||||
s.forEach((u) => {
|
|
||||||
if (
|
|
||||||
restricted.includes(action) !== false ||
|
|
||||||
u.id !== this.$store.state.users.currentUser.id
|
|
||||||
) {
|
|
||||||
const uf = this.$store.getters.findUser(u.id)
|
|
||||||
this.$store.dispatch(action, this.$store.getters.findUser(u.id))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
fetchOptions() {
|
fetchOptions() {
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,7 @@
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
</div>
|
</div>
|
||||||
<div class="filter">
|
<div class="filter">
|
||||||
<Checkbox v-model="filtersUncomfirmed">
|
<Checkbox v-model="filtersUnconfirmed">
|
||||||
{{ $t('admin_dash.users.options.only_unconfirmed') }}
|
{{ $t('admin_dash.users.options.only_unconfirmed') }}
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -123,130 +123,15 @@
|
||||||
<List
|
<List
|
||||||
ref="usersList"
|
ref="usersList"
|
||||||
:fetch-function="fetchUsers"
|
:fetch-function="fetchUsers"
|
||||||
|
@select="onSelect"
|
||||||
selectable
|
selectable
|
||||||
scrollable
|
scrollable
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header="{selected}">
|
||||||
<Popover
|
<ModerationTools :users="selected" />
|
||||||
ref="dropdown"
|
|
||||||
trigger="click"
|
|
||||||
placement="bottom"
|
|
||||||
>
|
|
||||||
<template #trigger>
|
|
||||||
<button
|
|
||||||
class="button button-default btn"
|
|
||||||
>
|
|
||||||
{{ $t('admin_dash.users.actions.title') }}
|
|
||||||
</button>
|
|
||||||
</template>
|
|
||||||
<template #content>
|
|
||||||
<div class="dropdown-menu">
|
|
||||||
<div class="menu-item dropdown-item">
|
|
||||||
<button
|
|
||||||
class="main-button"
|
|
||||||
@click="confirmSelection('confirmActivate')"
|
|
||||||
>
|
|
||||||
{{ $t('admin_dash.users.actions.activate') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="menu-item dropdown-item">
|
|
||||||
<button
|
|
||||||
class="main-button"
|
|
||||||
@click="confirmSelection('confirmDeactivate')"
|
|
||||||
>
|
|
||||||
{{ $t('admin_dash.users.actions.deactivate') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="menu-item dropdown-item">
|
|
||||||
<button
|
|
||||||
class="main-button"
|
|
||||||
@click="confirmSelection('confirmDelete')"
|
|
||||||
>
|
|
||||||
{{ $t('admin_dash.users.actions.delete_user') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="menu-item dropdown-item">
|
|
||||||
<button
|
|
||||||
class="main-button"
|
|
||||||
@click="confirmSelection('confirmGrantAdmin')"
|
|
||||||
>
|
|
||||||
{{ $t('admin_dash.users.actions.grant_admin') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="menu-item dropdown-item">
|
|
||||||
<button
|
|
||||||
class="main-button"
|
|
||||||
@click="confirmSelection('confirmRevokeAdmin')"
|
|
||||||
>
|
|
||||||
{{ $t('admin_dash.users.actions.revoke_admin') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="menu-item dropdown-item">
|
|
||||||
<button
|
|
||||||
class="main-button"
|
|
||||||
@click="confirmSelection('confirmGrantModerator')"
|
|
||||||
>
|
|
||||||
{{ $t('admin_dash.users.actions.grant_moderator') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="menu-item dropdown-item">
|
|
||||||
<button
|
|
||||||
class="main-button"
|
|
||||||
@click="confirmSelection('confirmRevokeModerator')"
|
|
||||||
>
|
|
||||||
{{ $t('admin_dash.users.actions.revoke_moderator') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="menu-item dropdown-item">
|
|
||||||
<button
|
|
||||||
class="main-button"
|
|
||||||
@click="confirmSelection('confirmApprove')"
|
|
||||||
>
|
|
||||||
{{ $t('admin_dash.users.actions.approve') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="menu-item dropdown-item">
|
|
||||||
<button
|
|
||||||
class="main-button"
|
|
||||||
@click="confirmSelection('confirmConfirm')"
|
|
||||||
>
|
|
||||||
{{ $t('admin_dash.users.actions.confirm') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="menu-item dropdown-item">
|
|
||||||
<button
|
|
||||||
class="main-button"
|
|
||||||
@click="confirmSelection('confirmResendEmail')"
|
|
||||||
>
|
|
||||||
{{ $t('admin_dash.users.actions.resend_confirmation_email') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="menu-item dropdown-item">
|
|
||||||
<button
|
|
||||||
class="main-button"
|
|
||||||
@click="confirmSelection('confirmRequirePasswordChange')"
|
|
||||||
>
|
|
||||||
{{ $t('admin_dash.users.actions.require_password_change') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="menu-item dropdown-item">
|
|
||||||
<button
|
|
||||||
class="main-button"
|
|
||||||
@click="confirmSelection('confirmDisableMFA')"
|
|
||||||
>
|
|
||||||
{{ $t('admin_dash.users.actions.disable_mfa') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</Popover>
|
|
||||||
</template>
|
</template>
|
||||||
<template #item="{item}">
|
<template #item="{item}">
|
||||||
<AdminCard
|
<AdminCard :user-id="item.id" />
|
||||||
:user-id="item.id"
|
|
||||||
:confirmed="item.is_confirmed"
|
|
||||||
:suggested="item.is_suggested"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
<template #load>
|
<template #load>
|
||||||
<span> loading </span>
|
<span> loading </span>
|
||||||
|
|
@ -255,102 +140,6 @@
|
||||||
<span> no users </span>
|
<span> no users </span>
|
||||||
</template>
|
</template>
|
||||||
</List>
|
</List>
|
||||||
<GenericConfirm
|
|
||||||
ref="confirmActivate"
|
|
||||||
:title="$t('admin_dash.users.actions.confirm_multi.title')"
|
|
||||||
:message="$t('admin_dash.users.actions.confirm_multi.activate')"
|
|
||||||
:cancel-text="$t('admin_dash.users.actions.no')"
|
|
||||||
:confirm-text="$t('admin_dash.users.actions.yes')"
|
|
||||||
@action="selectionConfirmed('adminActivateUser')"
|
|
||||||
/>
|
|
||||||
<GenericConfirm
|
|
||||||
ref="confirmDeactivate"
|
|
||||||
:title="$t('admin_dash.users.actions.confirm_multi.title')"
|
|
||||||
:message="$t('admin_dash.users.actions.confirm_multi.deactivate')"
|
|
||||||
:cancel-text="$t('admin_dash.users.actions.no')"
|
|
||||||
:confirm-text="$t('admin_dash.users.actions.yes')"
|
|
||||||
@action="selectionConfirmed('adminDeactivateUser')"
|
|
||||||
/>
|
|
||||||
<GenericConfirm
|
|
||||||
ref="confirmDelete"
|
|
||||||
:title="$t('admin_dash.users.actions.confirm_multi.title')"
|
|
||||||
:message="$t('admin_dash.users.actions.confirm_multi.delete_user')"
|
|
||||||
:cancel-text="$t('admin_dash.users.actions.no')"
|
|
||||||
:confirm-text="$t('admin_dash.users.actions.yes')"
|
|
||||||
@action="selectionConfirmed('adminDeleteUser')"
|
|
||||||
/>
|
|
||||||
<GenericConfirm
|
|
||||||
ref="confirmGrantAdmin"
|
|
||||||
:title="$t('admin_dash.users.actions.confirm_multi.title')"
|
|
||||||
:message="$t('admin_dash.users.actions.confirm_multi.grant_admin')"
|
|
||||||
:cancel-text="$t('admin_dash.users.actions.no')"
|
|
||||||
:confirm-text="$t('admin_dash.users.actions.yes')"
|
|
||||||
@action="selectionConfirmed('adminAddUserToAdminGroup')"
|
|
||||||
/>
|
|
||||||
<GenericConfirm
|
|
||||||
ref="confirmRevokeAdmin"
|
|
||||||
:title="$t('admin_dash.users.actions.confirm_multi.title')"
|
|
||||||
:message="$t('admin_dash.users.actions.confirm_multi.revoke_admin')"
|
|
||||||
:cancel-text="$t('admin_dash.users.actions.no')"
|
|
||||||
:confirm-text="$t('admin_dash.users.actions.yes')"
|
|
||||||
@action="selectionConfirmed('adminRemoveUserFromAdminGroup')"
|
|
||||||
/>
|
|
||||||
<GenericConfirm
|
|
||||||
ref="confirmGrantModerator"
|
|
||||||
:title="$t('admin_dash.users.actions.confirm_multi.title')"
|
|
||||||
:message="$t('admin_dash.users.actions.confirm_multi.grant_moderator')"
|
|
||||||
:cancel-text="$t('admin_dash.users.actions.no')"
|
|
||||||
:confirm-text="$t('admin_dash.users.actions.yes')"
|
|
||||||
@action="selectionConfirmed('adminAddUserToModeratorGroup')"
|
|
||||||
/>
|
|
||||||
<GenericConfirm
|
|
||||||
ref="confirmRevokeModerator"
|
|
||||||
:title="$t('admin_dash.users.actions.confirm_multi.title')"
|
|
||||||
:message="$t('admin_dash.users.actions.confirm_multi.revoke_moderator')"
|
|
||||||
:cancel-text="$t('admin_dash.users.actions.no')"
|
|
||||||
:confirm-text="$t('admin_dash.users.actions.yes')"
|
|
||||||
@action="selectionConfirmed('adminRemoveUserFromModeratorGroup')"
|
|
||||||
/>
|
|
||||||
<GenericConfirm
|
|
||||||
ref="confirmApprove"
|
|
||||||
:title="$t('admin_dash.users.actions.confirm_multi.title')"
|
|
||||||
:message="$t('admin_dash.users.actions.confirm_multi.approve')"
|
|
||||||
:cancel-text="$t('admin_dash.users.actions.no')"
|
|
||||||
:confirm-text="$t('admin_dash.users.actions.yes')"
|
|
||||||
@action="selectionConfirmed('adminApproveUser')"
|
|
||||||
/>
|
|
||||||
<GenericConfirm
|
|
||||||
ref="confirmConfirm"
|
|
||||||
:title="$t('admin_dash.users.actions.confirm_multi.title')"
|
|
||||||
:message="$t('admin_dash.users.actions.confirm_multi.confirm')"
|
|
||||||
:cancel-text="$t('admin_dash.users.actions.no')"
|
|
||||||
:confirm-text="$t('admin_dash.users.actions.yes')"
|
|
||||||
@action="selectionConfirmed('adminConfirmUser')"
|
|
||||||
/>
|
|
||||||
<GenericConfirm
|
|
||||||
ref="confirmResendEmail"
|
|
||||||
:title="$t('admin_dash.users.actions.confirm_multi.title')"
|
|
||||||
:message="$t('admin_dash.users.actions.confirm_multi.resend_confirmation_email')"
|
|
||||||
:cancel-text="$t('admin_dash.users.actions.no')"
|
|
||||||
:confirm-text="$t('admin_dash.users.actions.yes')"
|
|
||||||
@action="selectionConfirmed('adminResendConfirmationEmail')"
|
|
||||||
/>
|
|
||||||
<GenericConfirm
|
|
||||||
ref="confirmRequirePasswordChange"
|
|
||||||
:title="$t('admin_dash.users.actions.confirm_multi.title')"
|
|
||||||
:message="$t('admin_dash.users.actions.confirm_multi.require_password_change')"
|
|
||||||
:cancel-text="$t('admin_dash.users.actions.no')"
|
|
||||||
:confirm-text="$t('admin_dash.users.actions.yes')"
|
|
||||||
@action="selectionConfirmed('adminRequirePasswordChange')"
|
|
||||||
/>
|
|
||||||
<GenericConfirm
|
|
||||||
ref="confirmDisableMFA"
|
|
||||||
:title="$t('admin_dash.users.actions.confirm_multi.title')"
|
|
||||||
:message="$t('admin_dash.users.actions.confirm_multi.disable_mfa')"
|
|
||||||
:cancel-text="$t('admin_dash.users.actions.no')"
|
|
||||||
:confirm-text="$t('admin_dash.users.actions.yes')"
|
|
||||||
@action="selectionConfirmed('adminDisableMFA')"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script src="./users_tab.js"></script>
|
<script src="./users_tab.js"></script>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { mapState as mapPiniaState } from 'pinia'
|
import { mapState as mapPiniaState } from 'pinia'
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from 'vuex'
|
||||||
|
|
||||||
|
import { useAdminSettingsStore } from 'src/stores/admin_settings.js'
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
|
|
||||||
const SharedComputedObject = () => ({
|
const SharedComputedObject = () => ({
|
||||||
|
|
@ -8,9 +9,11 @@ const SharedComputedObject = () => ({
|
||||||
...mapPiniaState(useMergedConfigStore, {
|
...mapPiniaState(useMergedConfigStore, {
|
||||||
expertLevel: (store) => store.mergedConfig.expertLevel,
|
expertLevel: (store) => store.mergedConfig.expertLevel,
|
||||||
}),
|
}),
|
||||||
|
...mapPiniaState(useAdminSettingsStore, {
|
||||||
|
adminConfig: (store) => store.config,
|
||||||
|
adminDraft: (store) => store.draft,
|
||||||
|
}),
|
||||||
...mapState({
|
...mapState({
|
||||||
adminConfig: (state) => state.adminSettings.config,
|
|
||||||
adminDraft: (state) => state.adminSettings.draft,
|
|
||||||
user: (state) => state.users.currentUser,
|
user: (state) => state.users.currentUser,
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -229,7 +229,7 @@ export const BUTTONS = [
|
||||||
return (
|
return (
|
||||||
loggedIn &&
|
loggedIn &&
|
||||||
(status.user.id === currentUser.id ||
|
(status.user.id === currentUser.id ||
|
||||||
currentUser.privileges.includes('messages_delete'))
|
currentUser.privileges.has('messages_delete'))
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
confirm: ({ getters }) => useMergedConfigStore().mergedConfig.modalOnDelete,
|
confirm: ({ getters }) => useMergedConfigStore().mergedConfig.modalOnDelete,
|
||||||
|
|
|
||||||
|
|
@ -280,7 +280,7 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
visibleRole() {
|
visibleRole() {
|
||||||
if (!this.newShowRole) {
|
if (!this.user.show_role && !this.user.adminData) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const rights = this.user.rights
|
const rights = this.user.rights
|
||||||
|
|
|
||||||
|
|
@ -291,8 +291,7 @@
|
||||||
</button>
|
</button>
|
||||||
<ModerationTools
|
<ModerationTools
|
||||||
v-if="showModerationMenu"
|
v-if="showModerationMenu"
|
||||||
class="moderation-menu"
|
:users="[user]"
|
||||||
:user="user"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
|
|
||||||
122
src/i18n/en.json
122
src/i18n/en.json
|
|
@ -1331,79 +1331,10 @@
|
||||||
"moderator": "Moderator",
|
"moderator": "Moderator",
|
||||||
"active": "Active",
|
"active": "Active",
|
||||||
"deactivated": "Deactivated",
|
"deactivated": "Deactivated",
|
||||||
"confirmed": "Confirmed"
|
"confirmed": "Confirmed",
|
||||||
},
|
"unconfirmed": "Pending confirmation",
|
||||||
"actions": {
|
"approved": "Approved",
|
||||||
"title": "Actions",
|
"unapproved": "Pending approval"
|
||||||
"yes": "Confirm",
|
|
||||||
"no": "Abort",
|
|
||||||
"activate": "Activate",
|
|
||||||
"deactivate": "Deactivate",
|
|
||||||
"delete_user": "Delete",
|
|
||||||
"delete_status": "Delete",
|
|
||||||
"grant_admin": "Grant Admin",
|
|
||||||
"revoke_admin": "Revoke Admin",
|
|
||||||
"grant_moderator": "Grant Moderator",
|
|
||||||
"revoke_moderator": "Revoke Moderator",
|
|
||||||
"approve": "Approve",
|
|
||||||
"confirm": "Confirm",
|
|
||||||
"require_password_change": "Require Password Change",
|
|
||||||
"resend_confirmation_email": "Resend Confirmation Email",
|
|
||||||
"disable_mfa": "Disable MFA",
|
|
||||||
"confirm_single": {
|
|
||||||
"title": "Confirm",
|
|
||||||
"activate": "Activate User?",
|
|
||||||
"deactivate": "Deactivate User?",
|
|
||||||
"delete_user": "Delete User?",
|
|
||||||
"delete_status": "Delete Status?",
|
|
||||||
"grant_admin": "Grant Admin Privileges?",
|
|
||||||
"revoke_admin": "Revoke Admin Privileges?",
|
|
||||||
"grant_moderator": "Grant Moderator Privileges?",
|
|
||||||
"revoke_moderator": "Revoke Moderator Privileges?",
|
|
||||||
"approve": "Approve User?",
|
|
||||||
"confirm": "Confirm User?",
|
|
||||||
"require_password_change": "Require Password Change?",
|
|
||||||
"resend_confirmation_email": "Resend Confirmation Email?",
|
|
||||||
"disable_mfa": "Disable MFA?"
|
|
||||||
},
|
|
||||||
"confirm_multi": {
|
|
||||||
"title": "Confirm For Selection",
|
|
||||||
"activate": "Activate Selected Users?",
|
|
||||||
"deactivate": "Deactivate Selected Users?",
|
|
||||||
"delete_user": "Delete Selected Users?",
|
|
||||||
"delete_status": "Delete Selected Statuses?",
|
|
||||||
"grant_admin": "Grant Admin Privileges For Selected Users?",
|
|
||||||
"revoke_admin": "Revoke Admin Privileges For Selected Users?",
|
|
||||||
"grant_moderator": "Grant Moderator Privileges For Selected Users?",
|
|
||||||
"revoke_moderator": "Revoke Moderator Privileges For Selected Users?",
|
|
||||||
"approve": "Approve Selected Users?",
|
|
||||||
"confirm": "Confirm Selected Users?",
|
|
||||||
"require_password_change": "Require Password Change For Selected Users?",
|
|
||||||
"resend_confirmation_email": "Resend Confirmation Email For Selected Users?",
|
|
||||||
"disable_mfa": "Disable MFA For Selected Users?"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"details": {
|
|
||||||
"title": "User Details",
|
|
||||||
"overview": "Overview",
|
|
||||||
"button": "Details",
|
|
||||||
"id": "ID",
|
|
||||||
"actor_type": "Actor Type",
|
|
||||||
"actor_types": {
|
|
||||||
"person": "Person",
|
|
||||||
"service": "Service",
|
|
||||||
"application": "Application"
|
|
||||||
},
|
|
||||||
"admin": "Admin",
|
|
||||||
"moderator": "Moderator",
|
|
||||||
"local": "Local",
|
|
||||||
"active": "Active",
|
|
||||||
"inactive": "Inactive",
|
|
||||||
"tags": "Tags",
|
|
||||||
"roles": "Roles",
|
|
||||||
"status": "Status",
|
|
||||||
"remote": "Remote",
|
|
||||||
"account_type": "Account Type"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"limits": {
|
"limits": {
|
||||||
|
|
@ -1845,8 +1776,15 @@
|
||||||
"grant_moderator": "Grant Moderator",
|
"grant_moderator": "Grant Moderator",
|
||||||
"revoke_moderator": "Revoke Moderator",
|
"revoke_moderator": "Revoke Moderator",
|
||||||
"activate_account": "Activate account",
|
"activate_account": "Activate account",
|
||||||
"deactivate_account": "Deactivate account",
|
"deactivate_account": "Deactivate",
|
||||||
"delete_account": "Delete account",
|
"delete_account": "Delete",
|
||||||
|
"suggest_account": "Add to suggested",
|
||||||
|
"remove_suggested_account": "Remove from suggested",
|
||||||
|
"approve_account": "Approve",
|
||||||
|
"confirm_account": "Confirm",
|
||||||
|
|
||||||
|
"disable_mfa": "Disable MFA",
|
||||||
|
|
||||||
"force_nsfw": "Mark all posts as NSFW",
|
"force_nsfw": "Mark all posts as NSFW",
|
||||||
"strip_media": "Remove media from posts",
|
"strip_media": "Remove media from posts",
|
||||||
"force_unlisted": "Force posts to be unlisted",
|
"force_unlisted": "Force posts to be unlisted",
|
||||||
|
|
@ -1854,8 +1792,38 @@
|
||||||
"disable_remote_subscription": "Disallow following user from remote instances",
|
"disable_remote_subscription": "Disallow following user from remote instances",
|
||||||
"disable_any_subscription": "Disallow following user at all",
|
"disable_any_subscription": "Disallow following user at all",
|
||||||
"quarantine": "Disallow user posts from federating",
|
"quarantine": "Disallow user posts from federating",
|
||||||
"delete_user": "Delete user",
|
|
||||||
"delete_user_data_and_deactivate_confirmation": "This will permanently delete the data from this account and deactivate it. Are you absolutely sure?"
|
"require_password_change": "Require Password Change",
|
||||||
|
"resend_confirmation": "Resend Confirmation Email",
|
||||||
|
"confirm_modal": {
|
||||||
|
"delete_title": "User deletion",
|
||||||
|
"delete_content": "Delete user {user}? | Delete {count} users?",
|
||||||
|
"delete_content_2": "This will permanently delete the data from this accounts and deactivate it. Are you absolutely sure?",
|
||||||
|
"activate_title": "User activation",
|
||||||
|
"activate_content": "Activate user {user}? | Activate {count} users?",
|
||||||
|
"deactivate_content": "Dectivate user {user}? | Dectivate {count} users?",
|
||||||
|
"approval_title": "Approve users",
|
||||||
|
"approval_content": "Approve user {user}? | Approve {count} users?",
|
||||||
|
"confirm_title": "Confirm users",
|
||||||
|
"confirm_content": "Approve user {user}? | Approve {count} users?",
|
||||||
|
"suggest_title": "Suggest users",
|
||||||
|
"add_suggest_content": "Add user {user} to suggested list? | Add {count} users to suggested list?",
|
||||||
|
"rights_title": "Promote users",
|
||||||
|
"grant_rights_content": "Grant user {user} {name} role? | Grant {count} users {name} role?",
|
||||||
|
"revoke_rights_content": "Revoke {name} role from user {user}? | Revoke {name} from {count} users?",
|
||||||
|
"tag_title": "Assign user policy",
|
||||||
|
"assign_tag_content": "Assign {user} a {name} policy? | Assign {name} policy to {count} users?",
|
||||||
|
"unassign_tag_content": "Unassign policy {name} from {user}? | Unassign policy {name} from {count} users?",
|
||||||
|
"delete": "Delete",
|
||||||
|
"activate": "Activate",
|
||||||
|
"deactivate": "Deactivate",
|
||||||
|
"grant": "Grant",
|
||||||
|
"revoke": "Revoke",
|
||||||
|
"approve": "Approve",
|
||||||
|
"confirm": "Confirm",
|
||||||
|
"assign": "Assign",
|
||||||
|
"unassign": "Unassign"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"highlight_new": {
|
"highlight_new": {
|
||||||
"disabled": "Don't highlight",
|
"disabled": "Don't highlight",
|
||||||
|
|
|
||||||
|
|
@ -170,15 +170,11 @@ const unmuteDomain = (store, domain) => {
|
||||||
export const mutations = {
|
export const mutations = {
|
||||||
tagUser(state, { user: { id }, tag }) {
|
tagUser(state, { user: { id }, tag }) {
|
||||||
const user = state.usersObject[id]
|
const user = state.usersObject[id]
|
||||||
const tags = user.tags || []
|
user.tags.add(tag)
|
||||||
const newTags = tags.concat([tag])
|
|
||||||
user.tags = newTags
|
|
||||||
},
|
},
|
||||||
untagUser(state, { user: { id }, tag }) {
|
untagUser(state, { user: { id }, tag }) {
|
||||||
const user = state.usersObject[id]
|
const user = state.usersObject[id]
|
||||||
const tags = user.tags || []
|
user.tags.delete(tag)
|
||||||
const newTags = tags.filter((t) => t !== tag)
|
|
||||||
user.tags = newTags
|
|
||||||
},
|
},
|
||||||
updateRight(state, { user: { id }, right, value }) {
|
updateRight(state, { user: { id }, right, value }) {
|
||||||
const user = state.usersObject[id]
|
const user = state.usersObject[id]
|
||||||
|
|
@ -186,9 +182,12 @@ export const mutations = {
|
||||||
newRights[right] = value
|
newRights[right] = value
|
||||||
user.rights = newRights
|
user.rights = newRights
|
||||||
},
|
},
|
||||||
updateActivationStatus(state, { user: { id }, deactivated }) {
|
updateUserAdminData(state, { user }) {
|
||||||
const user = state.usersObject[id]
|
const { id } = user
|
||||||
user.deactivated = deactivated
|
const localUser = state.usersObject[id]
|
||||||
|
localUser.adminData = user
|
||||||
|
localUser.deactivated = !user.is_active
|
||||||
|
localUser.tags = new Set(user.tags)
|
||||||
},
|
},
|
||||||
setCurrentUser(state, user) {
|
setCurrentUser(state, user) {
|
||||||
state.lastLoginName = user.screen_name
|
state.lastLoginName = user.screen_name
|
||||||
|
|
@ -369,10 +368,22 @@ const users = {
|
||||||
getters,
|
getters,
|
||||||
actions: {
|
actions: {
|
||||||
fetchUserIfMissing(store, id) {
|
fetchUserIfMissing(store, id) {
|
||||||
if (!store.getters.findUser(id)) {
|
const user = store.getters.findUser(id)
|
||||||
store.dispatch('fetchUser', id)
|
if (!user) {
|
||||||
|
return store.dispatch('fetchUser', id)
|
||||||
|
} else {
|
||||||
|
return Promise.resolve(user)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
updateUserAdminData(store, { userAdminData }) {
|
||||||
|
return store
|
||||||
|
.dispatch('fetchUserIfMissing', userAdminData.id)
|
||||||
|
.then((user) => {
|
||||||
|
user.adminData = userAdminData
|
||||||
|
store.commit('addNewUsers', [user])
|
||||||
|
return user
|
||||||
|
})
|
||||||
|
},
|
||||||
fetchUser(store, id) {
|
fetchUser(store, id) {
|
||||||
return store.rootState.api.backendInteractor
|
return store.rootState.api.backendInteractor
|
||||||
.fetchUser({ id })
|
.fetchUser({ id })
|
||||||
|
|
@ -541,15 +552,6 @@ const users = {
|
||||||
commit('updateUserRelationship', [relationship]),
|
commit('updateUserRelationship', [relationship]),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
toggleActivationStatus({ rootState, commit }, { user }) {
|
|
||||||
const api = user.deactivated
|
|
||||||
? rootState.api.backendInteractor.activateUser
|
|
||||||
: rootState.api.backendInteractor.deactivateUser
|
|
||||||
api({ user }).then((user) => {
|
|
||||||
const deactivated = !user.is_active
|
|
||||||
commit('updateActivationStatus', { user, deactivated })
|
|
||||||
})
|
|
||||||
},
|
|
||||||
registerPushNotifications(store) {
|
registerPushNotifications(store) {
|
||||||
const token = store.state.currentUser.credentials
|
const token = store.state.currentUser.credentials
|
||||||
const vapidPublicKey = useInstanceStore().vapidPublicKey
|
const vapidPublicKey = useInstanceStore().vapidPublicKey
|
||||||
|
|
|
||||||
|
|
@ -20,12 +20,6 @@ const CHANGE_EMAIL_URL = '/api/pleroma/change_email'
|
||||||
const CHANGE_PASSWORD_URL = '/api/pleroma/change_password'
|
const CHANGE_PASSWORD_URL = '/api/pleroma/change_password'
|
||||||
const MOVE_ACCOUNT_URL = '/api/pleroma/move_account'
|
const MOVE_ACCOUNT_URL = '/api/pleroma/move_account'
|
||||||
const ALIASES_URL = '/api/pleroma/aliases'
|
const ALIASES_URL = '/api/pleroma/aliases'
|
||||||
const TAG_USER_URL = '/api/pleroma/admin/users/tag'
|
|
||||||
const PERMISSION_GROUP_URL = (screenName, right) =>
|
|
||||||
`/api/pleroma/admin/users/${screenName}/permission_group/${right}`
|
|
||||||
const ACTIVATE_USER_URL = '/api/pleroma/admin/users/activate'
|
|
||||||
const DEACTIVATE_USER_URL = '/api/pleroma/admin/users/deactivate'
|
|
||||||
const ADMIN_USERS_URL = '/api/v1/pleroma/admin/users'
|
|
||||||
const SUGGESTIONS_URL = '/api/v1/suggestions'
|
const SUGGESTIONS_URL = '/api/v1/suggestions'
|
||||||
const NOTIFICATION_SETTINGS_URL = '/api/pleroma/notification_settings'
|
const NOTIFICATION_SETTINGS_URL = '/api/pleroma/notification_settings'
|
||||||
const NOTIFICATION_READ_URL = '/api/v1/pleroma/notifications/read'
|
const NOTIFICATION_READ_URL = '/api/v1/pleroma/notifications/read'
|
||||||
|
|
@ -121,7 +115,6 @@ const PLEROMA_CHAT_MESSAGES_URL = (id) => `/api/v1/pleroma/chats/${id}/messages`
|
||||||
const PLEROMA_CHAT_READ_URL = (id) => `/api/v1/pleroma/chats/${id}/read`
|
const PLEROMA_CHAT_READ_URL = (id) => `/api/v1/pleroma/chats/${id}/read`
|
||||||
const PLEROMA_DELETE_CHAT_MESSAGE_URL = (chatId, messageId) =>
|
const PLEROMA_DELETE_CHAT_MESSAGE_URL = (chatId, messageId) =>
|
||||||
`/api/v1/pleroma/chats/${chatId}/messages/${messageId}`
|
`/api/v1/pleroma/chats/${chatId}/messages/${messageId}`
|
||||||
const PLEROMA_ADMIN_REPORTS = '/api/v1/pleroma/admin/reports'
|
|
||||||
const PLEROMA_BACKUP_URL = '/api/v1/pleroma/backups'
|
const PLEROMA_BACKUP_URL = '/api/v1/pleroma/backups'
|
||||||
const PLEROMA_ANNOUNCEMENTS_URL = '/api/v1/pleroma/admin/announcements'
|
const PLEROMA_ANNOUNCEMENTS_URL = '/api/v1/pleroma/admin/announcements'
|
||||||
const PLEROMA_POST_ANNOUNCEMENT_URL = '/api/v1/pleroma/admin/announcements'
|
const PLEROMA_POST_ANNOUNCEMENT_URL = '/api/v1/pleroma/admin/announcements'
|
||||||
|
|
@ -138,6 +131,7 @@ const PLEROMA_BOOKMARK_FOLDERS_URL = '/api/v1/pleroma/bookmark_folders'
|
||||||
const PLEROMA_BOOKMARK_FOLDER_URL = (id) =>
|
const PLEROMA_BOOKMARK_FOLDER_URL = (id) =>
|
||||||
`/api/v1/pleroma/bookmark_folders/${id}`
|
`/api/v1/pleroma/bookmark_folders/${id}`
|
||||||
|
|
||||||
|
const PLEROMA_ADMIN_REPORTS = '/api/v1/pleroma/admin/reports'
|
||||||
const PLEROMA_ADMIN_CONFIG_URL = '/api/v1/pleroma/admin/config'
|
const PLEROMA_ADMIN_CONFIG_URL = '/api/v1/pleroma/admin/config'
|
||||||
const PLEROMA_ADMIN_DESCRIPTIONS_URL =
|
const PLEROMA_ADMIN_DESCRIPTIONS_URL =
|
||||||
'/api/v1/pleroma/admin/config/descriptions'
|
'/api/v1/pleroma/admin/config/descriptions'
|
||||||
|
|
@ -145,7 +139,10 @@ const PLEROMA_ADMIN_FRONTENDS_URL = '/api/v1/pleroma/admin/frontends'
|
||||||
const PLEROMA_ADMIN_FRONTENDS_INSTALL_URL =
|
const PLEROMA_ADMIN_FRONTENDS_INSTALL_URL =
|
||||||
'/api/v1/pleroma/admin/frontends/install'
|
'/api/v1/pleroma/admin/frontends/install'
|
||||||
|
|
||||||
const PLEROMA_ADMIN_USERS_URL = ({
|
const PLEROMA_ADMIN_USERS_URL = '/api/v1/pleroma/admin/users'
|
||||||
|
const PLEROMA_ADMIN_USERS_URL_SHOW = (nickname) =>
|
||||||
|
`/api/v1/pleroma/admin/users/${nickname}`
|
||||||
|
const PLEROMA_ADMIN_USERS_URL_LIST = ({
|
||||||
page,
|
page,
|
||||||
pageSize,
|
pageSize,
|
||||||
filters = {},
|
filters = {},
|
||||||
|
|
@ -177,13 +174,18 @@ const PLEROMA_ADMIN_USERS_URL = ({
|
||||||
.join(',')
|
.join(',')
|
||||||
return `/api/v1/pleroma/admin/users?page=${page}&page_size=${pageSize}&filters=${filters_str}&query=${query}&name=${name}&email=${email}`
|
return `/api/v1/pleroma/admin/users?page=${page}&page_size=${pageSize}&filters=${filters_str}&query=${query}&name=${name}&email=${email}`
|
||||||
}
|
}
|
||||||
const PLEROMA_ADMIN_MODIFY_GROUP_URL = (nickname, group) =>
|
const PLEROMA_ADMIN_TAG_USER_URL = '/api/pleroma/admin/users/tag'
|
||||||
`/api/v1/pleroma/admin/users/${nickname}/permission_group/${group}`
|
const PLEROMA_ADMIN_PERMISSION_GROUP_URL = (right) =>
|
||||||
const PLEROMA_ADMIN_CONFIRM_USER_URL =
|
`/api/pleroma/admin/users/permission_group/${right}`
|
||||||
|
const PLEROMA_ADMIN_ACTIVATE_USERS_URL = '/api/pleroma/admin/users/activate'
|
||||||
|
const PLEROMA_ADMIN_DEACTIVATE_USERS_URL = '/api/pleroma/admin/users/deactivate'
|
||||||
|
const PLEROMA_ADMIN_SUGGEST_USERS_URL = '/api/pleroma/admin/users/suggest'
|
||||||
|
const PLEROMA_ADMIN_UNSUGGEST_USERS_URL = '/api/pleroma/admin/users/unsuggest'
|
||||||
|
const PLEROMA_ADMIN_APPROVE_USERS_URL = '/api/v1/pleroma/admin/users/approve'
|
||||||
|
const PLEROMA_ADMIN_CONFIRM_USERS_URL =
|
||||||
'/api/v1/pleroma/admin/users/confirm_email'
|
'/api/v1/pleroma/admin/users/confirm_email'
|
||||||
const PLEROMA_ADMIN_RESEND_CONFIRMATION_EMAIL_URL =
|
const PLEROMA_ADMIN_RESEND_CONFIRMATION_EMAIL_URL =
|
||||||
'/api/v1/pleroma/admin/users/resend_confirmation_email'
|
'/api/v1/pleroma/admin/users/resend_confirmation_email'
|
||||||
const PLEROMA_ADMIN_APPROVE_URL = '/api/v1/pleroma/admin/users/approve'
|
|
||||||
const PLEROMA_ADMIN_LIST_STATUSES_URL = (id, pageSize, godmode, withReblogs) =>
|
const PLEROMA_ADMIN_LIST_STATUSES_URL = (id, pageSize, godmode, withReblogs) =>
|
||||||
`/api/v1/pleroma/admin/users/${id}/statuses?page_size=${pageSize}&godmode=${godmode}&with_reblogs=${withReblogs}`
|
`/api/v1/pleroma/admin/users/${id}/statuses?page_size=${pageSize}&godmode=${godmode}&with_reblogs=${withReblogs}`
|
||||||
const PLEROMA_ADMIN_CHANGE_STATUS_SCOPE_URL = (id) =>
|
const PLEROMA_ADMIN_CHANGE_STATUS_SCOPE_URL = (id) =>
|
||||||
|
|
@ -251,8 +253,11 @@ const promisedRequest = ({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fetch(url, options).then((response) => {
|
return fetch(url, options).then((response) => {
|
||||||
return new Promise((resolve, reject) =>
|
return new Promise((resolve, reject) => {
|
||||||
response
|
// 204 is "No content", which fails to parse json (as you'd might think)
|
||||||
|
if (response.ok && response.status === 204) resolve()
|
||||||
|
|
||||||
|
return response
|
||||||
.json()
|
.json()
|
||||||
.then((json) => {
|
.then((json) => {
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
|
|
@ -276,8 +281,8 @@ const promisedRequest = ({
|
||||||
response,
|
response,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}),
|
})
|
||||||
)
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -769,92 +774,118 @@ const fetchStatusHistory = ({ status, credentials }) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const tagUser = ({ tag, credentials, user }) => {
|
const adminSetUsersTags = ({
|
||||||
const screenName = user.screen_name
|
tags,
|
||||||
const form = {
|
credentials,
|
||||||
nicknames: [screenName],
|
value,
|
||||||
tags: [tag],
|
screen_names: nicknames,
|
||||||
}
|
}) => {
|
||||||
|
|
||||||
const headers = authHeaders(credentials)
|
|
||||||
headers['Content-Type'] = 'application/json'
|
|
||||||
|
|
||||||
return fetch(TAG_USER_URL, {
|
|
||||||
method: 'PUT',
|
|
||||||
headers,
|
|
||||||
body: JSON.stringify(form),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const untagUser = ({ tag, credentials, user }) => {
|
|
||||||
const screenName = user.screen_name
|
|
||||||
const body = {
|
|
||||||
nicknames: [screenName],
|
|
||||||
tags: [tag],
|
|
||||||
}
|
|
||||||
|
|
||||||
const headers = authHeaders(credentials)
|
|
||||||
headers['Content-Type'] = 'application/json'
|
|
||||||
|
|
||||||
return fetch(TAG_USER_URL, {
|
|
||||||
method: 'DELETE',
|
|
||||||
headers,
|
|
||||||
body: JSON.stringify(body),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const addRight = ({ right, credentials, user }) => {
|
|
||||||
const screenName = user.screen_name
|
|
||||||
|
|
||||||
return fetch(PERMISSION_GROUP_URL(screenName, right), {
|
|
||||||
method: 'POST',
|
|
||||||
headers: authHeaders(credentials),
|
|
||||||
body: {},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const deleteRight = ({ right, credentials, user }) => {
|
|
||||||
const screenName = user.screen_name
|
|
||||||
|
|
||||||
return fetch(PERMISSION_GROUP_URL(screenName, right), {
|
|
||||||
method: 'DELETE',
|
|
||||||
headers: authHeaders(credentials),
|
|
||||||
body: {},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const activateUser = ({ credentials, user: { screen_name: nickname } }) => {
|
|
||||||
return promisedRequest({
|
return promisedRequest({
|
||||||
url: ACTIVATE_USER_URL,
|
url: PLEROMA_ADMIN_TAG_USER_URL,
|
||||||
|
method: value ? 'PUT' : 'DELETE',
|
||||||
|
credentials,
|
||||||
|
payload: {
|
||||||
|
nicknames,
|
||||||
|
tags,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const adminSetUsersRight = ({
|
||||||
|
right,
|
||||||
|
credentials,
|
||||||
|
value,
|
||||||
|
screen_names: nicknames,
|
||||||
|
}) => {
|
||||||
|
return promisedRequest({
|
||||||
|
url: PLEROMA_ADMIN_PERMISSION_GROUP_URL(right),
|
||||||
|
method: value ? 'POST' : 'DELETE',
|
||||||
|
credentials,
|
||||||
|
payload: {
|
||||||
|
nicknames,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const adminSetUsersActivationStatus = ({
|
||||||
|
credentials,
|
||||||
|
screen_names: nicknames,
|
||||||
|
value,
|
||||||
|
}) => {
|
||||||
|
return promisedRequest({
|
||||||
|
url: value
|
||||||
|
? PLEROMA_ADMIN_ACTIVATE_USERS_URL
|
||||||
|
: PLEROMA_ADMIN_DEACTIVATE_USERS_URL,
|
||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
credentials,
|
credentials,
|
||||||
payload: {
|
payload: {
|
||||||
nicknames: [nickname],
|
nicknames,
|
||||||
},
|
},
|
||||||
}).then((response) => response.users[0])
|
}).then((response) => response.users)
|
||||||
}
|
}
|
||||||
|
|
||||||
const deactivateUser = ({ credentials, user: { screen_name: nickname } }) => {
|
const adminSetUsersApprovalStatus = ({
|
||||||
|
credentials,
|
||||||
|
screen_names: nicknames,
|
||||||
|
}) => {
|
||||||
return promisedRequest({
|
return promisedRequest({
|
||||||
url: DEACTIVATE_USER_URL,
|
url: PLEROMA_ADMIN_APPROVE_USERS_URL,
|
||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
credentials,
|
credentials,
|
||||||
payload: {
|
payload: {
|
||||||
nicknames: [nickname],
|
nicknames,
|
||||||
},
|
},
|
||||||
}).then((response) => response.users[0])
|
}).then((response) => response.users)
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleteUser = ({ credentials, user: { screen_name: nickname } }) => {
|
const adminSetUsersConfirmationStatus = ({
|
||||||
const r = promisedRequest({
|
credentials,
|
||||||
url: ADMIN_USERS_URL,
|
screen_names: nicknames,
|
||||||
|
}) => {
|
||||||
|
return promisedRequest({
|
||||||
|
url: PLEROMA_ADMIN_CONFIRM_USERS_URL,
|
||||||
|
method: 'PATCH',
|
||||||
|
credentials,
|
||||||
|
payload: {
|
||||||
|
nicknames,
|
||||||
|
},
|
||||||
|
}).then((response) => response.users)
|
||||||
|
}
|
||||||
|
|
||||||
|
const adminSetUsersSuggestionStatus = ({
|
||||||
|
credentials,
|
||||||
|
screen_names: nicknames,
|
||||||
|
value,
|
||||||
|
}) => {
|
||||||
|
return promisedRequest({
|
||||||
|
url: value
|
||||||
|
? PLEROMA_ADMIN_SUGGEST_USERS_URL
|
||||||
|
: PLEROMA_ADMIN_UNSUGGEST_USERS_URL,
|
||||||
|
method: 'PATCH',
|
||||||
|
credentials,
|
||||||
|
payload: {
|
||||||
|
nicknames,
|
||||||
|
},
|
||||||
|
}).then((response) => response.users)
|
||||||
|
}
|
||||||
|
|
||||||
|
const adminGetUserData = ({ credentials, screen_name: nickname }) => {
|
||||||
|
return promisedRequest({
|
||||||
|
url: PLEROMA_ADMIN_USERS_URL_SHOW(nickname),
|
||||||
|
method: 'GET',
|
||||||
|
credentials,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const adminDeleteAccounts = ({ credentials, screen_names: nicknames }) => {
|
||||||
|
return promisedRequest({
|
||||||
|
url: PLEROMA_ADMIN_USERS_URL,
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
credentials,
|
credentials,
|
||||||
payload: {
|
payload: {
|
||||||
nicknames: [nickname],
|
nicknames,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
return r.then((response) => response.users[0])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const fetchTimeline = ({
|
const fetchTimeline = ({
|
||||||
|
|
@ -1668,75 +1699,57 @@ const dismissAnnouncement = ({ id, credentials }) => {
|
||||||
const adminListUsers = ({ opts, credentials }) => {
|
const adminListUsers = ({ opts, credentials }) => {
|
||||||
// the reported list is hardly useful because standards are for dating i guess,
|
// the reported list is hardly useful because standards are for dating i guess,
|
||||||
// so make sure to fetchIfMissing right afterward using this call
|
// so make sure to fetchIfMissing right afterward using this call
|
||||||
const url = PLEROMA_ADMIN_USERS_URL(opts)
|
const url = PLEROMA_ADMIN_USERS_URL_LIST(opts)
|
||||||
return promisedRequest({
|
return promisedRequest({
|
||||||
url: url,
|
url: url,
|
||||||
credentials,
|
credentials,
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
}).then((data) => ({
|
}).then((data) => ({
|
||||||
...data,
|
...data,
|
||||||
users: data.users.map(parseUser),
|
users: data.users,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
const adminAddUserToAdminGroup = ({ user, credentials }) => {
|
|
||||||
const url = PLEROMA_ADMIN_MODIFY_GROUP_URL(user.name_html, 'admin')
|
|
||||||
return promisedRequest({ url: url, credentials, method: 'POST' })
|
|
||||||
}
|
|
||||||
|
|
||||||
const adminRemoveUserFromAdminGroup = ({ user, credentials }) => {
|
|
||||||
const url = PLEROMA_ADMIN_MODIFY_GROUP_URL(user.name_html, 'admin')
|
|
||||||
return promisedRequest({ url: url, credentials, method: 'DELETE' })
|
|
||||||
}
|
|
||||||
|
|
||||||
const adminAddUserToModeratorGroup = ({ user, credentials }) => {
|
|
||||||
const url = PLEROMA_ADMIN_MODIFY_GROUP_URL(user.name_html, 'moderator')
|
|
||||||
return promisedRequest({ url: url, credentials, method: 'POST' })
|
|
||||||
}
|
|
||||||
|
|
||||||
const adminRemoveUserFromModeratorGroup = ({ user, credentials }) => {
|
|
||||||
const url = PLEROMA_ADMIN_MODIFY_GROUP_URL(user.name_html, 'moderator')
|
|
||||||
return promisedRequest({ url: url, credentials, method: 'DELETE' })
|
|
||||||
}
|
|
||||||
|
|
||||||
const adminConfirmUser = ({ user: { screen_name: nickname }, credentials }) => {
|
|
||||||
const url = PLEROMA_ADMIN_CONFIRM_USER_URL
|
|
||||||
return promisedRequest({
|
|
||||||
url: url,
|
|
||||||
credentials,
|
|
||||||
method: 'PATCH',
|
|
||||||
payload: {
|
|
||||||
nicknames: [nickname],
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const adminResendConfirmationEmail = ({
|
const adminResendConfirmationEmail = ({
|
||||||
user: { screen_name: nickname },
|
screen_names: nicknames,
|
||||||
credentials,
|
credentials,
|
||||||
}) => {
|
}) => {
|
||||||
const url = PLEROMA_ADMIN_RESEND_CONFIRMATION_EMAIL_URL
|
const url = PLEROMA_ADMIN_RESEND_CONFIRMATION_EMAIL_URL
|
||||||
return promisedRequest({
|
return promisedRequest({
|
||||||
url: url,
|
url,
|
||||||
credentials,
|
credentials,
|
||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
payload: {
|
payload: {
|
||||||
nicknames: [nickname],
|
nicknames,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const adminApproveUser = ({ user: { screen_name: nickname }, credentials }) => {
|
const adminRequirePasswordChange = ({
|
||||||
const url = PLEROMA_ADMIN_APPROVE_URL
|
user: { screen_names: nicknames },
|
||||||
const r = promisedRequest({
|
credentials,
|
||||||
url: url,
|
}) => {
|
||||||
|
const url = PLEROMA_ADMIN_REQUIRE_PASSWORD_CHANGE_URL
|
||||||
|
return promisedRequest({
|
||||||
|
url,
|
||||||
credentials,
|
credentials,
|
||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
payload: {
|
payload: {
|
||||||
nicknames: [nickname],
|
nicknames,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const adminDisableMFA = ({ user: { screen_name: nickname }, credentials }) => {
|
||||||
|
const url = PLEROMA_ADMIN_DISABLE_MFA_URL
|
||||||
|
return promisedRequest({
|
||||||
|
url,
|
||||||
|
credentials,
|
||||||
|
method: 'PUT',
|
||||||
|
payload: {
|
||||||
|
nickname,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
return r
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const adminListStatuses = ({
|
const adminListStatuses = ({
|
||||||
|
|
@ -1775,33 +1788,6 @@ const adminChangeStatusScope = ({
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const adminRequirePasswordChange = ({
|
|
||||||
user: { screen_name: nickname },
|
|
||||||
credentials,
|
|
||||||
}) => {
|
|
||||||
const url = PLEROMA_ADMIN_REQUIRE_PASSWORD_CHANGE_URL
|
|
||||||
return promisedRequest({
|
|
||||||
url,
|
|
||||||
credentials,
|
|
||||||
method: 'PATCH',
|
|
||||||
payload: {
|
|
||||||
nicknames: [nickname],
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const adminDisableMFA = ({ user: { screen_name: nickname }, credentials }) => {
|
|
||||||
const url = PLEROMA_ADMIN_DISABLE_MFA_URL
|
|
||||||
return promisedRequest({
|
|
||||||
url,
|
|
||||||
credentials,
|
|
||||||
method: 'PUT',
|
|
||||||
payload: {
|
|
||||||
nickname,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const announcementToPayload = ({ content, startsAt, endsAt, allDay }) => {
|
const announcementToPayload = ({ content, startsAt, endsAt, allDay }) => {
|
||||||
const payload = { content }
|
const payload = { content }
|
||||||
|
|
||||||
|
|
@ -2438,13 +2424,6 @@ const apiService = {
|
||||||
fetchBlocks,
|
fetchBlocks,
|
||||||
fetchOAuthTokens,
|
fetchOAuthTokens,
|
||||||
revokeOAuthToken,
|
revokeOAuthToken,
|
||||||
tagUser,
|
|
||||||
untagUser,
|
|
||||||
deleteUser,
|
|
||||||
addRight,
|
|
||||||
deleteRight,
|
|
||||||
activateUser,
|
|
||||||
deactivateUser,
|
|
||||||
register,
|
register,
|
||||||
getCaptcha,
|
getCaptcha,
|
||||||
updateProfileImages,
|
updateProfileImages,
|
||||||
|
|
@ -2533,13 +2512,15 @@ const apiService = {
|
||||||
updateBookmarkFolder,
|
updateBookmarkFolder,
|
||||||
deleteBookmarkFolder,
|
deleteBookmarkFolder,
|
||||||
adminListUsers,
|
adminListUsers,
|
||||||
adminAddUserToAdminGroup,
|
adminGetUserData,
|
||||||
adminRemoveUserFromAdminGroup,
|
|
||||||
adminAddUserToModeratorGroup,
|
|
||||||
adminRemoveUserFromModeratorGroup,
|
|
||||||
adminConfirmUser,
|
|
||||||
adminResendConfirmationEmail,
|
adminResendConfirmationEmail,
|
||||||
adminApproveUser,
|
adminDeleteAccounts,
|
||||||
|
adminSetUsersRight,
|
||||||
|
adminSetUsersTags,
|
||||||
|
adminSetUsersApprovalStatus,
|
||||||
|
adminSetUsersConfirmationStatus,
|
||||||
|
adminSetUsersActivationStatus,
|
||||||
|
adminSetUsersSuggestionStatus,
|
||||||
adminListStatuses,
|
adminListStatuses,
|
||||||
adminChangeStatusScope,
|
adminChangeStatusScope,
|
||||||
adminRequirePasswordChange,
|
adminRequirePasswordChange,
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,13 @@ import { isStatusNotification } from '../notification_utils/notification_utils.j
|
||||||
|
|
||||||
export const parseUser = (data) => {
|
export const parseUser = (data) => {
|
||||||
const output = {}
|
const output = {}
|
||||||
|
output._original = data // used for server-side settings
|
||||||
|
|
||||||
// case for users in "mentions" property for statuses in MastoAPI
|
// case for users in "mentions" property for statuses in MastoAPI
|
||||||
const mastoShort = !Object.hasOwn(data, 'avatar')
|
const mastoShort = !Object.hasOwn(data, 'avatar')
|
||||||
|
|
||||||
output.inLists = null
|
output.inLists = null
|
||||||
output.id = String(data.id)
|
output.id = String(data.id)
|
||||||
output._original = data // used for server-side settings
|
|
||||||
|
|
||||||
output.screen_name = data.acct
|
output.screen_name = data.acct
|
||||||
output.fqn = data.fqn
|
output.fqn = data.fqn
|
||||||
|
|
@ -118,9 +119,9 @@ export const parseUser = (data) => {
|
||||||
output.birthday = data.pleroma.birthday
|
output.birthday = data.pleroma.birthday
|
||||||
|
|
||||||
if (data.pleroma.privileges) {
|
if (data.pleroma.privileges) {
|
||||||
output.privileges = data.pleroma.privileges
|
output.privileges = new Set(data.pleroma.privileges)
|
||||||
} else if (data.pleroma.is_admin) {
|
} else if (data.pleroma.is_admin) {
|
||||||
output.privileges = [
|
output.privileges = new Set([
|
||||||
'users_read',
|
'users_read',
|
||||||
'users_manage_invites',
|
'users_manage_invites',
|
||||||
'users_manage_activation_state',
|
'users_manage_activation_state',
|
||||||
|
|
@ -135,11 +136,11 @@ export const parseUser = (data) => {
|
||||||
'announcements_manage_announcements',
|
'announcements_manage_announcements',
|
||||||
'emoji_manage_emoji',
|
'emoji_manage_emoji',
|
||||||
'statistics_read',
|
'statistics_read',
|
||||||
]
|
])
|
||||||
} else if (data.pleroma.is_moderator) {
|
} else if (data.pleroma.is_moderator) {
|
||||||
output.privileges = ['messages_delete', 'reports_manage_reports']
|
output.privileges = new Set(['messages_delete', 'reports_manage_reports'])
|
||||||
} else {
|
} else {
|
||||||
output.privileges = []
|
output.privileges = new Set()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -149,7 +150,7 @@ export const parseUser = (data) => {
|
||||||
output.fields = data.source.fields
|
output.fields = data.source.fields
|
||||||
if (data.source.pleroma) {
|
if (data.source.pleroma) {
|
||||||
output.no_rich_text = data.source.pleroma.no_rich_text
|
output.no_rich_text = data.source.pleroma.no_rich_text
|
||||||
output.show_role = data.source.pleroma.show_role
|
output.show_role = typeof data.source.pleroma.show_role === 'boolean' ? data.source.pleroma.show_role : true
|
||||||
output.discoverable = data.source.pleroma.discoverable
|
output.discoverable = data.source.pleroma.discoverable
|
||||||
output.show_birthday = data.pleroma.show_birthday
|
output.show_birthday = data.pleroma.show_birthday
|
||||||
output.actor_type = data.source.pleroma.actor_type
|
output.actor_type = data.source.pleroma.actor_type
|
||||||
|
|
@ -168,7 +169,7 @@ export const parseUser = (data) => {
|
||||||
if (data.pleroma) {
|
if (data.pleroma) {
|
||||||
output.follow_request_count = data.pleroma.follow_request_count
|
output.follow_request_count = data.pleroma.follow_request_count
|
||||||
|
|
||||||
output.tags = data.pleroma.tags
|
output.tags = new Set(data.pleroma.tags)
|
||||||
|
|
||||||
// deactivated was changed to is_active in Pleroma 2.3.0
|
// deactivated was changed to is_active in Pleroma 2.3.0
|
||||||
// so check if is_active is present
|
// so check if is_active is present
|
||||||
|
|
@ -181,7 +182,7 @@ export const parseUser = (data) => {
|
||||||
output.unread_chat_count = data.pleroma.unread_chat_count
|
output.unread_chat_count = data.pleroma.unread_chat_count
|
||||||
}
|
}
|
||||||
|
|
||||||
output.tags = output.tags || []
|
output.tags = output.tags || new Set()
|
||||||
output.rights = output.rights || {}
|
output.rights = output.rights || {}
|
||||||
output.notification_settings = output.notification_settings || {}
|
output.notification_settings = output.notification_settings || {}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,23 +19,14 @@ export const newUserFlags = {
|
||||||
export const useAdminSettingsStore = defineStore('adminSettings', {
|
export const useAdminSettingsStore = defineStore('adminSettings', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
...cloneDeep(defaultState),
|
...cloneDeep(defaultState),
|
||||||
|
backendInteractor: window.vuex.state.api.backendInteractor,
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
|
// Configuration Stuff
|
||||||
setInstanceAdminNoDbConfig() {
|
setInstanceAdminNoDbConfig() {
|
||||||
this.loaded = false
|
this.loaded = false
|
||||||
this.dbConfigEnabled = false
|
this.dbConfigEnabled = false
|
||||||
},
|
},
|
||||||
setAvailableFrontends({ frontends }) {
|
|
||||||
this.frontends = frontends.map((f) => {
|
|
||||||
f.installedRefs = f.installed_refs
|
|
||||||
if (f.name === 'pleroma-fe') {
|
|
||||||
f.refs = ['master', 'develop']
|
|
||||||
} else {
|
|
||||||
f.refs = [f.ref]
|
|
||||||
}
|
|
||||||
return f
|
|
||||||
})
|
|
||||||
},
|
|
||||||
updateAdminSettings({ config, modifiedPaths }) {
|
updateAdminSettings({ config, modifiedPaths }) {
|
||||||
this.loaded = true
|
this.loaded = true
|
||||||
this.dbConfigEnabled = true
|
this.dbConfigEnabled = true
|
||||||
|
|
@ -59,144 +50,23 @@ export const useAdminSettingsStore = defineStore('adminSettings', {
|
||||||
resetAdminDraft() {
|
resetAdminDraft() {
|
||||||
this.draft = cloneDeep(this.config)
|
this.draft = cloneDeep(this.config)
|
||||||
},
|
},
|
||||||
async fetchAdminUsers(opts) {
|
|
||||||
const data = await window.vuex.state.api.backendInteractor.adminListUsers(
|
|
||||||
{
|
|
||||||
opts,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
data.users.forEach((user) =>
|
|
||||||
window.vuex.dispatch('fetchUserIfMissing', user.id),
|
|
||||||
)
|
|
||||||
|
|
||||||
return data
|
|
||||||
},
|
|
||||||
adminAddUserToAdminGroup(user) {
|
|
||||||
window.vuex.state.api.backendInteractor
|
|
||||||
.adminAddUserToAdminGroup({ user })
|
|
||||||
.then((res) =>
|
|
||||||
window.vuex.commit('updateRight', {
|
|
||||||
user,
|
|
||||||
right: 'admin',
|
|
||||||
value: res.is_admin,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
adminRemoveUserFromAdminGroup(user) {
|
|
||||||
// prevent revokation of own rights
|
|
||||||
if (user.id !== window.vuex.state.users.currentUser.id) {
|
|
||||||
return window.vuex.state.api.backendInteractor
|
|
||||||
.adminRemoveUserFromAdminGroup({ user })
|
|
||||||
.then((res) =>
|
|
||||||
window.vuex.commit('updateRight', {
|
|
||||||
user,
|
|
||||||
right: 'admin',
|
|
||||||
value: res.is_admin,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
adminAddUserToModeratorGroup(user) {
|
|
||||||
return window.vuex.state.api.backendInteractor
|
|
||||||
.adminAddUserToModeratorGroup({ user })
|
|
||||||
.then((res) =>
|
|
||||||
window.vuex.commit('updateRight', {
|
|
||||||
user,
|
|
||||||
right: 'moderator',
|
|
||||||
value: res.is_moderator,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
adminRemoveUserFromModeratorGroup(user) {
|
|
||||||
// prevent revokation of own rights
|
|
||||||
if (user.id !== window.vuex.state.users.currentUser.id) {
|
|
||||||
return window.vuex.state.api.backendInteractor
|
|
||||||
.adminRemoveUserFromModeratorGroup({ user })
|
|
||||||
.then((res) =>
|
|
||||||
window.vuex.commit('updateRight', {
|
|
||||||
user,
|
|
||||||
right: 'moderator',
|
|
||||||
value: res.is_moderator,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
adminActivateUser(user) {
|
|
||||||
return window.vuex.state.api.backendInteractor
|
|
||||||
.activateUser({ user })
|
|
||||||
.then((res) => {
|
|
||||||
const deactivated = !res.is_active
|
|
||||||
window.vuex.commit('updateActivationStatus', { user, deactivated })
|
|
||||||
})
|
|
||||||
},
|
|
||||||
adminDeactivateUser(user) {
|
|
||||||
return window.vuex.state.api.backendInteractor
|
|
||||||
.deactivateUser({ user })
|
|
||||||
.then((res) => {
|
|
||||||
const deactivated = !res.is_active
|
|
||||||
window.vuex.commit('updateActivationStatus', { user, deactivated })
|
|
||||||
})
|
|
||||||
},
|
|
||||||
adminDeleteUser(user) {
|
|
||||||
return window.vuex.state.api.backendInteractor.deleteUser({ user })
|
|
||||||
},
|
|
||||||
adminConfirmUser(user) {
|
|
||||||
return window.vuex.state.api.backendInteractor
|
|
||||||
.adminConfirmUser({ user })
|
|
||||||
.then(() => window.vuex.dispatch('fetchUser', user.id))
|
|
||||||
},
|
|
||||||
adminResendConfirmationEmail(user) {
|
|
||||||
return window.vuex.state.api.backendInteractor.adminResendConfirmationEmail(
|
|
||||||
{ user },
|
|
||||||
)
|
|
||||||
},
|
|
||||||
adminApproveUser(user) {
|
|
||||||
return window.vuex.state.api.backendInteractor.adminApproveUser({ user })
|
|
||||||
},
|
|
||||||
adminListStatuses({ userId, opts }) {
|
|
||||||
return window.vuex.state.api.backendInteractor.adminListStatuses({
|
|
||||||
userId,
|
|
||||||
opts,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
adminChangeStatusScope({ opts }) {
|
|
||||||
return window.vuex.state.api.backendInteractor.adminChangeStatusScope({
|
|
||||||
opts,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
adminDisableMFA(user) {
|
|
||||||
return window.vuex.state.api.backendInteractor.adminDisableMFA({ user })
|
|
||||||
},
|
|
||||||
adminTagUser({ user, tag }) {
|
|
||||||
return window.vuex.state.api.backendInteractor.tagUser({ user, tag })
|
|
||||||
},
|
|
||||||
adminUntagUser({ user, tag }) {
|
|
||||||
return window.vuex.state.api.backendInteractor.untagUser({ user, tag })
|
|
||||||
},
|
|
||||||
loadFrontendsStuff() {
|
|
||||||
window.vuex.state.api.backendInteractor
|
|
||||||
.fetchAvailableFrontends()
|
|
||||||
.then((frontends) => this.setAvailableFrontends({ frontends }))
|
|
||||||
},
|
|
||||||
loadAdminStuff() {
|
loadAdminStuff() {
|
||||||
window.vuex.state.api.backendInteractor
|
this.backendInteractor.fetchInstanceDBConfig().then((backendDbConfig) => {
|
||||||
.fetchInstanceDBConfig()
|
if (backendDbConfig.error) {
|
||||||
.then((backendDbConfig) => {
|
if (backendDbConfig.error.status === 400) {
|
||||||
if (backendDbConfig.error) {
|
backendDbConfig.error.json().then((errorJson) => {
|
||||||
if (backendDbConfig.error.status === 400) {
|
if (/configurable_from_database/.test(errorJson.error)) {
|
||||||
backendDbConfig.error.json().then((errorJson) => {
|
this.setInstanceAdminNoDbConfig()
|
||||||
if (/configurable_from_database/.test(errorJson.error)) {
|
}
|
||||||
this.setInstanceAdminNoDbConfig()
|
})
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.setInstanceAdminSettings({ backendDbConfig })
|
|
||||||
}
|
}
|
||||||
})
|
} else {
|
||||||
|
this.setInstanceAdminSettings({ backendDbConfig })
|
||||||
|
}
|
||||||
|
})
|
||||||
if (this.descriptions === null) {
|
if (this.descriptions === null) {
|
||||||
window.vuex.state.api.backendInteractor
|
this.backendInteractor
|
||||||
.fetchInstanceConfigDescriptions()
|
.fetchInstanceConfigDescriptions()
|
||||||
.then((backendDescriptions) =>
|
.then((backendDescriptions) =>
|
||||||
this.setInstanceAdminDescriptions({ backendDescriptions }),
|
this.setInstanceAdminDescriptions({ backendDescriptions }),
|
||||||
|
|
@ -408,5 +278,172 @@ export const useAdminSettingsStore = defineStore('adminSettings', {
|
||||||
this.setInstanceAdminSettings({ backendDbConfig }),
|
this.setInstanceAdminSettings({ backendDbConfig }),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Frontends Stuff
|
||||||
|
loadFrontendsStuff() {
|
||||||
|
this.backendInteractor
|
||||||
|
.fetchAvailableFrontends()
|
||||||
|
.then((frontends) => this.setAvailableFrontends({ frontends }))
|
||||||
|
},
|
||||||
|
|
||||||
|
setAvailableFrontends({ frontends }) {
|
||||||
|
this.frontends = frontends.map((f) => {
|
||||||
|
f.installedRefs = f.installed_refs
|
||||||
|
if (f.name === 'pleroma-fe') {
|
||||||
|
f.refs = ['master', 'develop']
|
||||||
|
} else {
|
||||||
|
f.refs = [f.ref]
|
||||||
|
}
|
||||||
|
return f
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// Statuses stuff
|
||||||
|
listStatuses({ userId, opts }) {
|
||||||
|
return this.backendInteractor.adminListStatuses({
|
||||||
|
userId,
|
||||||
|
opts,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
changeStatusScope({ opts }) {
|
||||||
|
return this.backendInteractor.adminChangeStatusScope({
|
||||||
|
opts,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// Users stuff
|
||||||
|
async fetchAdminUsers(opts) {
|
||||||
|
const adminData = await this.backendInteractor.adminListUsers({
|
||||||
|
opts,
|
||||||
|
})
|
||||||
|
|
||||||
|
adminData.users = await Promise.all(
|
||||||
|
adminData.users.map(
|
||||||
|
async (userAdminData) =>
|
||||||
|
await window.vuex.dispatch('updateUserAdminData', {
|
||||||
|
userAdminData,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
return adminData
|
||||||
|
},
|
||||||
|
async getUserData({ user }) {
|
||||||
|
const api = this.backendInteractor.adminGetUserData
|
||||||
|
const { screen_name } = user
|
||||||
|
|
||||||
|
const result = await api({ screen_name })
|
||||||
|
window.vuex.commit('updateUserAdminData', { user: result })
|
||||||
|
},
|
||||||
|
async deleteUsers({ users }) {
|
||||||
|
const screen_names = users.map((u) => u.screen_name)
|
||||||
|
const api = this.backendInteractor.adminDeleteAccounts
|
||||||
|
|
||||||
|
const resultUserIds = await api({ screen_names })
|
||||||
|
|
||||||
|
resultUserIds.forEach((userId) => {
|
||||||
|
window.vuex.dispatch(
|
||||||
|
'markStatusesAsDeleted',
|
||||||
|
(status) => userId === status.user.id,
|
||||||
|
)
|
||||||
|
// TODO when migrated to pinia, also remove user
|
||||||
|
})
|
||||||
|
|
||||||
|
return resultUserIds
|
||||||
|
},
|
||||||
|
resendConfirmationEmail({ users }) {
|
||||||
|
const screen_names = users.map((u) => u.screen_name)
|
||||||
|
|
||||||
|
return this.backendInteractor.adminResendConfirmationEmail({
|
||||||
|
screen_names,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
requirePasswordChange({ users }) {
|
||||||
|
const screen_names = users.map((u) => u.screen_name)
|
||||||
|
|
||||||
|
return this.backendInteractor.adminRequirePasswordChange({
|
||||||
|
screen_names,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// Singular only!
|
||||||
|
disableMFA({ user }) {
|
||||||
|
return this.backendInteractor.adminDisableMFA(user)
|
||||||
|
},
|
||||||
|
async setUsersTags({ users, tags, value }) {
|
||||||
|
const screen_names = users.map((u) => u.screen_name)
|
||||||
|
const api = this.backendInteractor.adminSetUsersTags
|
||||||
|
|
||||||
|
await api({
|
||||||
|
screen_names,
|
||||||
|
tags,
|
||||||
|
value,
|
||||||
|
})
|
||||||
|
|
||||||
|
users.forEach((user) => {
|
||||||
|
this.getUserData({ user })
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async setUsersRight({ users, right, value }) {
|
||||||
|
const screen_names = users.map((u) => u.screen_name)
|
||||||
|
const api = this.backendInteractor.adminSetUsersRight
|
||||||
|
|
||||||
|
await api({
|
||||||
|
screen_names,
|
||||||
|
right,
|
||||||
|
value,
|
||||||
|
})
|
||||||
|
|
||||||
|
users.forEach((user) => {
|
||||||
|
window.vuex.commit('updateRight', { user, right, value })
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async setUsersActivationStatus({ users, value }) {
|
||||||
|
const screen_names = users.map((u) => u.screen_name)
|
||||||
|
const api = this.backendInteractor.adminSetUsersActivationStatus
|
||||||
|
|
||||||
|
const resultUsers = await api({
|
||||||
|
screen_names,
|
||||||
|
value,
|
||||||
|
})
|
||||||
|
|
||||||
|
resultUsers.forEach((user) => {
|
||||||
|
window.vuex.commit('updateUserAdminData', { user })
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async setUsersSuggestionStatus({ users, value }) {
|
||||||
|
const screen_names = users.map((u) => u.screen_name)
|
||||||
|
const api = this.backendInteractor.adminSetUsersSuggestionStatus
|
||||||
|
|
||||||
|
const resultUsers = await api({
|
||||||
|
screen_names,
|
||||||
|
value,
|
||||||
|
})
|
||||||
|
|
||||||
|
resultUsers.forEach((user) => {
|
||||||
|
window.vuex.commit('updateUserAdminData', { user })
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async setUsersConfirmationStatus({ users }) {
|
||||||
|
const screen_names = users.map((u) => u.screen_name)
|
||||||
|
const api = this.backendInteractor.adminSetUsersConfirmationStatus
|
||||||
|
|
||||||
|
await api({ screen_names })
|
||||||
|
|
||||||
|
users.forEach((user) => {
|
||||||
|
this.getUserData({ user })
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async setUsersApprovalStatus({ users }) {
|
||||||
|
const screen_names = users.map((u) => u.screen_name)
|
||||||
|
const api = this.backendInteractor.adminSetUsersApprovalStatus
|
||||||
|
|
||||||
|
const resultUsers = await api({
|
||||||
|
screen_names,
|
||||||
|
})
|
||||||
|
|
||||||
|
resultUsers.forEach((user) => {
|
||||||
|
window.vuex.commit('updateUserAdminData', { user })
|
||||||
|
})
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ export const useAnnouncementsStore = defineStore('announcements', {
|
||||||
const currentUser = window.vuex.state.users.currentUser
|
const currentUser = window.vuex.state.users.currentUser
|
||||||
const isAdmin =
|
const isAdmin =
|
||||||
currentUser &&
|
currentUser &&
|
||||||
currentUser.privileges.includes('announcements_manage_announcements')
|
currentUser.privileges.has('announcements_manage_announcements')
|
||||||
|
|
||||||
const getAnnouncements = async () => {
|
const getAnnouncements = async () => {
|
||||||
if (!isAdmin) {
|
if (!isAdmin) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue