diff --git a/src/components/dialog_modal/dialog_modal.vue b/src/components/dialog_modal/dialog_modal.vue
index 0feef27b..0042d057 100644
--- a/src/components/dialog_modal/dialog_modal.vue
+++ b/src/components/dialog_modal/dialog_modal.vue
@@ -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 {
diff --git a/src/components/mod_modal/tabs/users_tab/users_tab.js b/src/components/mod_modal/tabs/users_tab/users_tab.js
index fd3ab389..ca7dd924 100644
--- a/src/components/mod_modal/tabs/users_tab/users_tab.js
+++ b/src/components/mod_modal/tabs/users_tab/users_tab.js
@@ -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
}
},
diff --git a/src/components/mod_modal/tabs/users_tab/users_tab.vue b/src/components/mod_modal/tabs/users_tab/users_tab.vue
index a13b2396..36cc67fd 100644
--- a/src/components/mod_modal/tabs/users_tab/users_tab.vue
+++ b/src/components/mod_modal/tabs/users_tab/users_tab.vue
@@ -151,10 +151,6 @@
:class="{ 'menu-checkbox-checked': all(actorType) }"
/>{{ $t('moderation.users.filter.all') }}
-
@@ -170,7 +166,11 @@
class="user"
>
-
+
diff --git a/src/components/moderation_tools/moderation_tools.js b/src/components/moderation_tools/moderation_tools.js
index 2469327a..c2da3a69 100644
--- a/src/components/moderation_tools/moderation_tools.js
+++ b/src/components/moderation_tools/moderation_tools.js
@@ -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
}
diff --git a/src/components/moderation_tools/moderation_tools.vue b/src/components/moderation_tools/moderation_tools.vue
index 75ea08cc..f93f4847 100644
--- a/src/components/moderation_tools/moderation_tools.vue
+++ b/src/components/moderation_tools/moderation_tools.vue
@@ -120,6 +120,37 @@
{{ $t('user_card.admin_menu.quarantine') }}
+
+
+
+
+
+
+
@@ -156,6 +187,26 @@
+
+
+ {{ $t('user_card.admin_menu.password_reset_token') }}
+
+
+ {{ $t('user_card.admin_menu.password_reset_token_content', { token: passwordResetToken.token }) }}
+ {{ passwordResetToken.link }}
+
+
+
+
+
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 21fb6f99..e91be01d 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -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",
diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js
index da4cc238..126bfc8a 100644
--- a/src/services/api/api.service.js
+++ b/src/services/api/api.service.js
@@ -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,
diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js
index 04a474a8..14f76cc9 100644
--- a/src/services/entity_normalizer/entity_normalizer.service.js
+++ b/src/services/entity_normalizer/entity_normalizer.service.js
@@ -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