Add extended moderation options

This commit is contained in:
Sol Fisher Romanoff 2022-11-14 23:11:28 +02:00
parent 86f0d09276
commit c966e10ed4
Signed by: nbsp
GPG Key ID: 9D3F2B64F2341B62
8 changed files with 127 additions and 9 deletions

View File

@ -69,7 +69,7 @@
padding: 1rem 1rem;
background-color: $fallback--bg;
background-color: var(--bg, $fallback--bg);
white-space: normal;
white-space: pre-wrap;
}
.dialog-modal-footer {

View File

@ -49,7 +49,6 @@ const UsersTab = {
users () { return this.$store.state.users.adminUsers },
isActive () {
const tabSwitcher = this.$parent
console.log(this.users)
return tabSwitcher ? tabSwitcher.isActive('users') : false
}
},

View File

@ -151,10 +151,6 @@
:class="{ 'menu-checkbox-checked': all(actorType) }"
/>{{ $t('moderation.users.filter.all') }}
</button>
<div
role="separator"
class="dropdown-divider"
/>
</div>
</template>
</Popover>
@ -170,7 +166,11 @@
class="user"
>
<BasicUserCard :user="user" />
<ModerationTools :user="user" class="user-moderation" />
<ModerationTools
:user="user"
class="user-moderation"
extended="true"
/>
</div>
</div>
</div>

View File

@ -16,7 +16,8 @@ const QUARANTINE = 'mrf_tag:quarantine'
const ModerationTools = {
props: [
'user'
'user',
'extended'
],
data () {
return {
@ -30,7 +31,10 @@ const ModerationTools = {
QUARANTINE
},
showDeleteUserDialog: false,
toggled: false
showPasswordTokenDialog: false,
toggled: false,
passwordResetToken: {},
bot: this.user.bot
}
},
components: {
@ -83,6 +87,9 @@ const ModerationTools = {
deleteUserDialog (show) {
this.showDeleteUserDialog = show
},
passwordTokenDialog (show) {
this.showPasswordTokenDialog = show
},
deleteUser () {
const store = this.$store
const user = this.user
@ -97,6 +104,29 @@ const ModerationTools = {
}
})
},
getPasswordResetToken () {
this.$store.state.api.backendInteractor.getPasswordResetToken({ nickname: this.user.screen_name })
.then(data => {
this.passwordResetToken = data
this.passwordTokenDialog(true)
})
},
forcePasswordReset () {
this.$store.state.api.backendInteractor.forcePasswordReset({ nickname: this.user.screen_name })
},
forceDisableMFA () {
this.$store.state.api.backendInteractor.forceDisableMFA({ nickname: this.user.screen_name })
},
toggleBot () {
const params = { bot: !this.bot }
this.$store.state.api.backendInteractor
.updateProfile({ params })
.then((user) => {
this.$store.commit('addNewUsers', [user])
this.bot = !this.bot
})
},
setToggled (value) {
this.toggled = value
}

View File

@ -120,6 +120,37 @@
{{ $t('user_card.admin_menu.quarantine') }}
</button>
</span>
<div
v-if="extended && user.is_local"
role="separator"
class="dropdown-divider"
/>
<span v-if="extended && user.is_local">
<button
class="button-default dropdown-item"
@click="getPasswordResetToken"
>
{{ $t('user_card.admin_menu.get_password_reset_token') }}
</button>
<button
class="button-default dropdown-item"
@click="forcePasswordReset"
>
{{ $t('user_card.admin_menu.force_password_reset') }}
</button>
<button
class="button-default dropdown-item"
@click="forceDisableMFA"
>
{{ $t('user_card.admin_menu.disable_mfa') }}
</button>
<button
class="button-default dropdown-item"
@click="toggleBot"
>
{{ $t('user_card.admin_menu.convert_to', { type: !!bot ? 'Person' : 'Service' }) }}
</button>
</span>
</div>
</template>
<template v-slot:trigger>
@ -156,6 +187,26 @@
</button>
</template>
</DialogModal>
<DialogModal
v-if="showPasswordTokenDialog"
:on-cancel="passwordTokenDialog.bind(this, false)"
>
<template v-slot:header>
{{ $t('user_card.admin_menu.password_reset_token') }}
</template>
<p>
{{ $t('user_card.admin_menu.password_reset_token_content', { token: passwordResetToken.token }) }}
<a :href="passwordResetToken.link">{{ passwordResetToken.link }}</a>
</p>
<template v-slot:footer>
<button
class="btn button-default"
@click="passwordTokenDialog(false)"
>
{{ $t('general.close') }}
</button>
</template>
</DialogModal>
</teleport>
</div>
</template>

View File

@ -1109,17 +1109,23 @@
"user_card": {
"admin_menu": {
"activate_account": "Activate account",
"convert_to": "Convert to { type }",
"deactivate_account": "Deactivate account",
"delete_account": "Delete account",
"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?",
"disable_any_subscription": "Disallow following user at all",
"disable_mfa": "Disable multi-factor authentication",
"disable_remote_subscription": "Disallow following user from remote instances",
"force_nsfw": "Mark all posts as NSFW",
"force_password_reset": "Require password reset on next login",
"force_unlisted": "Force posts to be unlisted",
"get_password_reset_token": "Get password reset token",
"grant_admin": "Grant Admin",
"grant_moderator": "Grant Moderator",
"moderation": "Moderation",
"password_reset_token": "Password reset token",
"password_reset_token_content": "Password reset token has been generated: { token }\nYou can also use this link to reset the password: ",
"quarantine": "Disallow user posts from federating",
"revoke_admin": "Revoke Admin",
"revoke_moderator": "Revoke Moderator",

View File

@ -23,6 +23,9 @@ const NOTIFICATION_READ_URL = '/api/v1/pleroma/notifications/read'
const ADMIN_REPORTS_URL = '/api/v1/pleroma/admin/reports'
const ADMIN_REPORT_NOTES_URL = id => `/api/v1/pleroma/admin/reports/${id}/notes`
const ADMIN_REPORT_NOTE_URL = (report, note) => `/api/v1/pleroma/admin/reports/${report}/notes/${note}`
const ADMIN_PASSWORD_RESET_TOKEN_URL = nickname => `/api/v1/pleroma/admin/users/${nickname}/password_reset`
const ADMIN_FORCE_PASSWORD_RESET_URL = '/api/v1/pleroma/admin/users/force_password_reset'
const ADMIN_DISABLE_MFA_URL = '/api/v1/pleroma/admin/users/disable_mfa'
const MFA_SETTINGS_URL = '/api/pleroma/accounts/mfa'
const MFA_BACKUP_CODES_URL = '/api/pleroma/accounts/mfa/backup_codes'
@ -717,6 +720,31 @@ const deleteNoteFromReport = ({ report, note, credentials }) => {
})
}
const getPasswordResetToken = ({ nickname, credentials }) => {
const url = ADMIN_PASSWORD_RESET_TOKEN_URL(nickname)
return fetch(url, { headers: authHeaders(credentials) })
.then(data => data.json())
}
const forcePasswordReset = ({ nickname, credentials }) => {
return promisedRequest({
url: ADMIN_FORCE_PASSWORD_RESET_URL,
method: 'PATCH',
payload: { nicknames: [nickname] },
credentials
})
}
const forceDisableMFA = ({ nickname, credentials }) => {
return promisedRequest({
url: ADMIN_DISABLE_MFA_URL,
method: 'PUT',
payload: { nickname },
credentials
})
}
const fetchTimeline = ({
timeline,
credentials,
@ -1793,6 +1821,9 @@ const apiService = {
deleteRight,
activateUser,
deactivateUser,
getPasswordResetToken,
forcePasswordReset,
forceDisableMFA,
register,
getCaptcha,
updateProfileImages,

View File

@ -143,6 +143,7 @@ export const parseUser = (data) => {
// TODO: handle is_local
output.is_local = !output.screen_name.includes('@')
} else if (admin) {
output.bot = data.actor_type === 'Service'
output.screen_name = data.nickname
output.name = data.display_name
output.profile_image_url = data.avatar