diff options
Diffstat (limited to 'src/components/user_settings')
| -rw-r--r-- | src/components/user_settings/confirm.js | 9 | ||||
| -rw-r--r-- | src/components/user_settings/confirm.vue | 22 | ||||
| -rw-r--r-- | src/components/user_settings/mfa.js | 155 | ||||
| -rw-r--r-- | src/components/user_settings/mfa.vue | 173 | ||||
| -rw-r--r-- | src/components/user_settings/mfa_backup_codes.js | 17 | ||||
| -rw-r--r-- | src/components/user_settings/mfa_backup_codes.vue | 33 | ||||
| -rw-r--r-- | src/components/user_settings/mfa_totp.js | 49 | ||||
| -rw-r--r-- | src/components/user_settings/mfa_totp.vue | 43 | ||||
| -rw-r--r-- | src/components/user_settings/user_settings.js | 374 | ||||
| -rw-r--r-- | src/components/user_settings/user_settings.vue | 646 |
10 files changed, 0 insertions, 1521 deletions
diff --git a/src/components/user_settings/confirm.js b/src/components/user_settings/confirm.js deleted file mode 100644 index 0f4ddfc9..00000000 --- a/src/components/user_settings/confirm.js +++ /dev/null @@ -1,9 +0,0 @@ -const Confirm = { - props: ['disabled'], - data: () => ({}), - methods: { - confirm () { this.$emit('confirm') }, - cancel () { this.$emit('cancel') } - } -} -export default Confirm diff --git a/src/components/user_settings/confirm.vue b/src/components/user_settings/confirm.vue deleted file mode 100644 index 69b3811b..00000000 --- a/src/components/user_settings/confirm.vue +++ /dev/null @@ -1,22 +0,0 @@ -<template> - <div> - <slot /> - <button - class="btn btn-default" - :disabled="disabled" - @click="confirm" - > - {{ $t('general.confirm') }} - </button> - <button - class="btn btn-default" - :disabled="disabled" - @click="cancel" - > - {{ $t('general.cancel') }} - </button> - </div> -</template> - -<script src="./confirm.js"> -</script> diff --git a/src/components/user_settings/mfa.js b/src/components/user_settings/mfa.js deleted file mode 100644 index 3090138a..00000000 --- a/src/components/user_settings/mfa.js +++ /dev/null @@ -1,155 +0,0 @@ -import RecoveryCodes from './mfa_backup_codes.vue' -import TOTP from './mfa_totp.vue' -import Confirm from './confirm.vue' -import VueQrcode from '@chenfengyuan/vue-qrcode' -import { mapState } from 'vuex' - -const Mfa = { - data: () => ({ - settings: { // current settings of MFA - available: false, - enabled: false, - totp: false - }, - setupState: { // setup mfa - state: '', // state of setup. '' -> 'getBackupCodes' -> 'setupOTP' -> 'complete' - setupOTPState: '' // state of setup otp. '' -> 'prepare' -> 'confirm' -> 'complete' - }, - backupCodes: { - getNewCodes: false, - inProgress: false, // progress of fetch codes - codes: [] - }, - otpSettings: { // pre-setup setting of OTP. secret key, qrcode url. - provisioning_uri: '', - key: '' - }, - currentPassword: null, - otpConfirmToken: null, - error: null, - readyInit: false - }), - components: { - 'recovery-codes': RecoveryCodes, - 'totp-item': TOTP, - 'qrcode': VueQrcode, - 'confirm': Confirm - }, - computed: { - canSetupOTP () { - return ( - (this.setupInProgress && this.backupCodesPrepared) || - this.settings.enabled - ) && !this.settings.totp && !this.setupOTPInProgress - }, - setupInProgress () { - return this.setupState.state !== '' && this.setupState.state !== 'complete' - }, - setupOTPInProgress () { - return this.setupState.state === 'setupOTP' && !this.completedOTP - }, - prepareOTP () { - return this.setupState.setupOTPState === 'prepare' - }, - confirmOTP () { - return this.setupState.setupOTPState === 'confirm' - }, - completedOTP () { - return this.setupState.setupOTPState === 'completed' - }, - backupCodesPrepared () { - return !this.backupCodes.inProgress && this.backupCodes.codes.length > 0 - }, - confirmNewBackupCodes () { - return this.backupCodes.getNewCodes - }, - ...mapState({ - backendInteractor: (state) => state.api.backendInteractor - }) - }, - - methods: { - activateOTP () { - if (!this.settings.enabled) { - this.setupState.state = 'getBackupcodes' - this.fetchBackupCodes() - } - }, - fetchBackupCodes () { - this.backupCodes.inProgress = true - this.backupCodes.codes = [] - - return this.backendInteractor.generateMfaBackupCodes() - .then((res) => { - this.backupCodes.codes = res.codes - this.backupCodes.inProgress = false - }) - }, - getBackupCodes () { // get a new backup codes - this.backupCodes.getNewCodes = true - }, - confirmBackupCodes () { // confirm getting new backup codes - this.fetchBackupCodes().then((res) => { - this.backupCodes.getNewCodes = false - }) - }, - cancelBackupCodes () { // cancel confirm form of new backup codes - this.backupCodes.getNewCodes = false - }, - - // Setup OTP - setupOTP () { // prepare setup OTP - this.setupState.state = 'setupOTP' - this.setupState.setupOTPState = 'prepare' - this.backendInteractor.mfaSetupOTP() - .then((res) => { - this.otpSettings = res - this.setupState.setupOTPState = 'confirm' - }) - }, - doConfirmOTP () { // handler confirm enable OTP - this.error = null - this.backendInteractor.mfaConfirmOTP({ - token: this.otpConfirmToken, - password: this.currentPassword - }) - .then((res) => { - if (res.error) { - this.error = res.error - return - } - this.completeSetup() - }) - }, - - completeSetup () { - this.setupState.setupOTPState = 'complete' - this.setupState.state = 'complete' - this.currentPassword = null - this.error = null - this.fetchSettings() - }, - cancelSetup () { // cancel setup - this.setupState.setupOTPState = '' - this.setupState.state = '' - this.currentPassword = null - this.error = null - }, - // end Setup OTP - - // fetch settings from server - async fetchSettings () { - let result = await this.backendInteractor.fetchSettingsMFA() - if (result.error) return - this.settings = result.settings - this.settings.available = true - return result - } - }, - mounted () { - this.fetchSettings().then(() => { - this.readyInit = true - }) - } -} -export default Mfa diff --git a/src/components/user_settings/mfa.vue b/src/components/user_settings/mfa.vue deleted file mode 100644 index 14ea10a1..00000000 --- a/src/components/user_settings/mfa.vue +++ /dev/null @@ -1,173 +0,0 @@ -<template> - <div - v-if="readyInit && settings.available" - class="setting-item mfa-settings" - > - <div class="mfa-heading"> - <h2>{{ $t('settings.mfa.title') }}</h2> - </div> - - <div> - <div - v-if="!setupInProgress" - class="setting-item" - > - <!-- Enabled methods --> - <h3>{{ $t('settings.mfa.authentication_methods') }}</h3> - <totp-item - :settings="settings" - @deactivate="fetchSettings" - @activate="activateOTP" - /> - <br> - - <div v-if="settings.enabled"> - <!-- backup codes block--> - <recovery-codes - v-if="!confirmNewBackupCodes" - :backup-codes="backupCodes" - /> - <button - v-if="!confirmNewBackupCodes" - class="btn btn-default" - @click="getBackupCodes" - > - {{ $t('settings.mfa.generate_new_recovery_codes') }} - </button> - - <div v-if="confirmNewBackupCodes"> - <confirm - :disabled="backupCodes.inProgress" - @confirm="confirmBackupCodes" - @cancel="cancelBackupCodes" - > - <p class="warning"> - {{ $t('settings.mfa.warning_of_generate_new_codes') }} - </p> - </confirm> - </div> - </div> - </div> - - <div v-if="setupInProgress"> - <!-- setup block--> - - <h3>{{ $t('settings.mfa.setup_otp') }}</h3> - - <recovery-codes - v-if="!setupOTPInProgress" - :backup-codes="backupCodes" - /> - - <button - v-if="canSetupOTP" - class="btn btn-default" - @click="cancelSetup" - > - {{ $t('general.cancel') }} - </button> - - <button - v-if="canSetupOTP" - class="btn btn-default" - @click="setupOTP" - > - {{ $t('settings.mfa.setup_otp') }} - </button> - - <template v-if="setupOTPInProgress"> - <i v-if="prepareOTP">{{ $t('settings.mfa.wait_pre_setup_otp') }}</i> - - <div v-if="confirmOTP"> - <div class="setup-otp"> - <div class="qr-code"> - <h4>{{ $t('settings.mfa.scan.title') }}</h4> - <p>{{ $t('settings.mfa.scan.desc') }}</p> - <qrcode - :value="otpSettings.provisioning_uri" - :options="{ width: 200 }" - /> - <p> - {{ $t('settings.mfa.scan.secret_code') }}: - {{ otpSettings.key }} - </p> - </div> - - <div class="verify"> - <h4>{{ $t('general.verify') }}</h4> - <p>{{ $t('settings.mfa.verify.desc') }}</p> - <input - v-model="otpConfirmToken" - type="text" - > - - <p>{{ $t('settings.enter_current_password_to_confirm') }}:</p> - <input - v-model="currentPassword" - type="password" - > - <div class="confirm-otp-actions"> - <button - class="btn btn-default" - @click="doConfirmOTP" - > - {{ $t('settings.mfa.confirm_and_enable') }} - </button> - <button - class="btn btn-default" - @click="cancelSetup" - > - {{ $t('general.cancel') }} - </button> - </div> - <div - v-if="error" - class="alert error" - > - {{ error }} - </div> - </div> - </div> - </div> - </template> - </div> - </div> - </div> -</template> - -<script src="./mfa.js"></script> -<style lang="scss"> -@import '../../_variables.scss'; -.warning { - color: $fallback--cOrange; - color: var(--cOrange, $fallback--cOrange); -} -.mfa-settings { - .mfa-heading, .method-item { - overflow: hidden; - display: flex; - flex-wrap: wrap; - justify-content: space-between; - align-items: baseline; - } - - .setup-otp { - display: flex; - justify-content: center; - flex-wrap: wrap; - .qr-code { - flex: 1; - padding-right: 10px; - } - .verify { flex: 1; } - .error { margin: 4px 0 0 0; } - .confirm-otp-actions { - button { - width: 15em; - margin-top: 5px; - } - - } - } -} -</style> diff --git a/src/components/user_settings/mfa_backup_codes.js b/src/components/user_settings/mfa_backup_codes.js deleted file mode 100644 index f0a984ec..00000000 --- a/src/components/user_settings/mfa_backup_codes.js +++ /dev/null @@ -1,17 +0,0 @@ -export default { - props: { - backupCodes: { - type: Object, - default: () => ({ - inProgress: false, - codes: [] - }) - } - }, - data: () => ({}), - computed: { - inProgress () { return this.backupCodes.inProgress }, - ready () { return this.backupCodes.codes.length > 0 }, - displayTitle () { return this.inProgress || this.ready } - } -} diff --git a/src/components/user_settings/mfa_backup_codes.vue b/src/components/user_settings/mfa_backup_codes.vue deleted file mode 100644 index e6c8ede2..00000000 --- a/src/components/user_settings/mfa_backup_codes.vue +++ /dev/null @@ -1,33 +0,0 @@ -<template> - <div> - <h4 v-if="displayTitle"> - {{ $t('settings.mfa.recovery_codes') }} - </h4> - <i v-if="inProgress">{{ $t('settings.mfa.waiting_a_recovery_codes') }}</i> - <template v-if="ready"> - <p class="alert warning"> - {{ $t('settings.mfa.recovery_codes_warning') }} - </p> - <ul class="backup-codes"> - <li - v-for="code in backupCodes.codes" - :key="code" - > - {{ code }} - </li> - </ul> - </template> - </div> -</template> -<script src="./mfa_backup_codes.js"></script> -<style lang="scss"> -@import '../../_variables.scss'; - -.warning { - color: $fallback--cOrange; - color: var(--cOrange, $fallback--cOrange); -} -.backup-codes { - font-family: var(--postCodeFont, monospace); -} -</style> diff --git a/src/components/user_settings/mfa_totp.js b/src/components/user_settings/mfa_totp.js deleted file mode 100644 index 8408d8e9..00000000 --- a/src/components/user_settings/mfa_totp.js +++ /dev/null @@ -1,49 +0,0 @@ -import Confirm from './confirm.vue' -import { mapState } from 'vuex' - -export default { - props: ['settings'], - data: () => ({ - error: false, - currentPassword: '', - deactivate: false, - inProgress: false // progress peform request to disable otp method - }), - components: { - 'confirm': Confirm - }, - computed: { - isActivated () { - return this.settings.totp - }, - ...mapState({ - backendInteractor: (state) => state.api.backendInteractor - }) - }, - methods: { - doActivate () { - this.$emit('activate') - }, - cancelDeactivate () { this.deactivate = false }, - doDeactivate () { - this.error = null - this.deactivate = true - }, - confirmDeactivate () { // confirm deactivate TOTP method - this.error = null - this.inProgress = true - this.backendInteractor.mfaDisableOTP({ - password: this.currentPassword - }) - .then((res) => { - this.inProgress = false - if (res.error) { - this.error = res.error - return - } - this.deactivate = false - this.$emit('deactivate') - }) - } - } -} diff --git a/src/components/user_settings/mfa_totp.vue b/src/components/user_settings/mfa_totp.vue deleted file mode 100644 index c6f2cc7b..00000000 --- a/src/components/user_settings/mfa_totp.vue +++ /dev/null @@ -1,43 +0,0 @@ -<template> - <div> - <div class="method-item"> - <strong>{{ $t('settings.mfa.otp') }}</strong> - <button - v-if="!isActivated" - class="btn btn-default" - @click="doActivate" - > - {{ $t('general.enable') }} - </button> - - <button - v-if="isActivated" - class="btn btn-default" - :disabled="deactivate" - @click="doDeactivate" - > - {{ $t('general.disable') }} - </button> - </div> - - <confirm - v-if="deactivate" - :disabled="inProgress" - @confirm="confirmDeactivate" - @cancel="cancelDeactivate" - > - {{ $t('settings.enter_current_password_to_confirm') }}: - <input - v-model="currentPassword" - type="password" - > - </confirm> - <div - v-if="error" - class="alert error" - > - {{ error }} - </div> - </div> -</template> -<script src="./mfa_totp.js"></script> diff --git a/src/components/user_settings/user_settings.js b/src/components/user_settings/user_settings.js deleted file mode 100644 index 3fdc5340..00000000 --- a/src/components/user_settings/user_settings.js +++ /dev/null @@ -1,374 +0,0 @@ -import unescape from 'lodash/unescape' -import get from 'lodash/get' -import map from 'lodash/map' -import reject from 'lodash/reject' -import TabSwitcher from '../tab_switcher/tab_switcher.js' -import ImageCropper from '../image_cropper/image_cropper.vue' -import StyleSwitcher from '../style_switcher/style_switcher.vue' -import ScopeSelector from '../scope_selector/scope_selector.vue' -import fileSizeFormatService from '../../services/file_size_format/file_size_format.js' -import BlockCard from '../block_card/block_card.vue' -import MuteCard from '../mute_card/mute_card.vue' -import SelectableList from '../selectable_list/selectable_list.vue' -import ProgressButton from '../progress_button/progress_button.vue' -import EmojiInput from '../emoji_input/emoji_input.vue' -import suggestor from '../emoji_input/suggestor.js' -import Autosuggest from '../autosuggest/autosuggest.vue' -import Importer from '../importer/importer.vue' -import Exporter from '../exporter/exporter.vue' -import withSubscription from '../../hocs/with_subscription/with_subscription' -import Checkbox from '../checkbox/checkbox.vue' -import Mfa from './mfa.vue' - -const BlockList = withSubscription({ - fetch: (props, $store) => $store.dispatch('fetchBlocks'), - select: (props, $store) => get($store.state.users.currentUser, 'blockIds', []), - childPropName: 'items' -})(SelectableList) - -const MuteList = withSubscription({ - fetch: (props, $store) => $store.dispatch('fetchMutes'), - select: (props, $store) => get($store.state.users.currentUser, 'muteIds', []), - childPropName: 'items' -})(SelectableList) - -const UserSettings = { - data () { - return { - newEmail: '', - newName: this.$store.state.users.currentUser.name, - newBio: unescape(this.$store.state.users.currentUser.description), - newLocked: this.$store.state.users.currentUser.locked, - newNoRichText: this.$store.state.users.currentUser.no_rich_text, - newDefaultScope: this.$store.state.users.currentUser.default_scope, - hideFollows: this.$store.state.users.currentUser.hide_follows, - hideFollowers: this.$store.state.users.currentUser.hide_followers, - hideFollowsCount: this.$store.state.users.currentUser.hide_follows_count, - hideFollowersCount: this.$store.state.users.currentUser.hide_followers_count, - showRole: this.$store.state.users.currentUser.show_role, - role: this.$store.state.users.currentUser.role, - discoverable: this.$store.state.users.currentUser.discoverable, - pickAvatarBtnVisible: true, - bannerUploading: false, - backgroundUploading: false, - banner: null, - bannerPreview: null, - background: null, - backgroundPreview: null, - bannerUploadError: null, - backgroundUploadError: null, - changeEmailError: false, - changeEmailPassword: '', - changedEmail: false, - deletingAccount: false, - deleteAccountConfirmPasswordInput: '', - deleteAccountError: false, - changePasswordInputs: [ '', '', '' ], - changedPassword: false, - changePasswordError: false, - activeTab: 'profile', - notificationSettings: this.$store.state.users.currentUser.notification_settings - } - }, - created () { - this.$store.dispatch('fetchTokens') - }, - components: { - StyleSwitcher, - ScopeSelector, - TabSwitcher, - ImageCropper, - BlockList, - MuteList, - EmojiInput, - Autosuggest, - BlockCard, - MuteCard, - ProgressButton, - Importer, - Exporter, - Mfa, - Checkbox - }, - computed: { - user () { - return this.$store.state.users.currentUser - }, - emojiUserSuggestor () { - return suggestor({ - emoji: [ - ...this.$store.state.instance.emoji, - ...this.$store.state.instance.customEmoji - ], - users: this.$store.state.users.users, - updateUsersList: (input) => this.$store.dispatch('searchUsers', input) - }) - }, - emojiSuggestor () { - return suggestor({ emoji: [ - ...this.$store.state.instance.emoji, - ...this.$store.state.instance.customEmoji - ] }) - }, - pleromaBackend () { - return this.$store.state.instance.pleromaBackend - }, - minimalScopesMode () { - return this.$store.state.instance.minimalScopesMode - }, - vis () { - return { - public: { selected: this.newDefaultScope === 'public' }, - unlisted: { selected: this.newDefaultScope === 'unlisted' }, - private: { selected: this.newDefaultScope === 'private' }, - direct: { selected: this.newDefaultScope === 'direct' } - } - }, - currentSaveStateNotice () { - return this.$store.state.interface.settings.currentSaveStateNotice - }, - oauthTokens () { - return this.$store.state.oauthTokens.tokens.map(oauthToken => { - return { - id: oauthToken.id, - appName: oauthToken.app_name, - validUntil: new Date(oauthToken.valid_until).toLocaleDateString() - } - }) - } - }, - methods: { - updateProfile () { - this.$store.state.api.backendInteractor - .updateProfile({ - params: { - note: this.newBio, - locked: this.newLocked, - // Backend notation. - /* eslint-disable camelcase */ - display_name: this.newName, - default_scope: this.newDefaultScope, - no_rich_text: this.newNoRichText, - hide_follows: this.hideFollows, - hide_followers: this.hideFollowers, - discoverable: this.discoverable, - hide_follows_count: this.hideFollowsCount, - hide_followers_count: this.hideFollowersCount, - show_role: this.showRole - /* eslint-enable camelcase */ - } }).then((user) => { - this.$store.commit('addNewUsers', [user]) - this.$store.commit('setCurrentUser', user) - }) - }, - updateNotificationSettings () { - this.$store.state.api.backendInteractor - .updateNotificationSettings({ settings: this.notificationSettings }) - }, - changeVis (visibility) { - this.newDefaultScope = visibility - }, - uploadFile (slot, e) { - const file = e.target.files[0] - if (!file) { return } - if (file.size > this.$store.state.instance[slot + 'limit']) { - const filesize = fileSizeFormatService.fileSizeFormat(file.size) - const allowedsize = fileSizeFormatService.fileSizeFormat(this.$store.state.instance[slot + 'limit']) - this[slot + 'UploadError'] = this.$t('upload.error.base') + ' ' + this.$t('upload.error.file_too_big', { filesize: filesize.num, filesizeunit: filesize.unit, allowedsize: allowedsize.num, allowedsizeunit: allowedsize.unit }) - return - } - // eslint-disable-next-line no-undef - const reader = new FileReader() - reader.onload = ({ target }) => { - const img = target.result - this[slot + 'Preview'] = img - this[slot] = file - } - reader.readAsDataURL(file) - }, - submitAvatar (cropper, file) { - const that = this - return new Promise((resolve, reject) => { - function updateAvatar (avatar) { - that.$store.state.api.backendInteractor.updateAvatar({ avatar }) - .then((user) => { - that.$store.commit('addNewUsers', [user]) - that.$store.commit('setCurrentUser', user) - resolve() - }) - .catch((err) => { - reject(new Error(that.$t('upload.error.base') + ' ' + err.message)) - }) - } - - if (cropper) { - cropper.getCroppedCanvas().toBlob(updateAvatar, file.type) - } else { - updateAvatar(file) - } - }) - }, - clearUploadError (slot) { - this[slot + 'UploadError'] = null - }, - submitBanner () { - if (!this.bannerPreview) { return } - - this.bannerUploading = true - this.$store.state.api.backendInteractor.updateBanner({ banner: this.banner }) - .then((user) => { - this.$store.commit('addNewUsers', [user]) - this.$store.commit('setCurrentUser', user) - this.bannerPreview = null - }) - .catch((err) => { - this.bannerUploadError = this.$t('upload.error.base') + ' ' + err.message - }) - .then(() => { this.bannerUploading = false }) - }, - submitBg () { - if (!this.backgroundPreview) { return } - let background = this.background - this.backgroundUploading = true - this.$store.state.api.backendInteractor.updateBg({ background }).then((data) => { - if (!data.error) { - this.$store.commit('addNewUsers', [data]) - this.$store.commit('setCurrentUser', data) - this.backgroundPreview = null - } else { - this.backgroundUploadError = this.$t('upload.error.base') + data.error - } - this.backgroundUploading = false - }) - }, - importFollows (file) { - return this.$store.state.api.backendInteractor.importFollows(file) - .then((status) => { - if (!status) { - throw new Error('failed') - } - }) - }, - importBlocks (file) { - return this.$store.state.api.backendInteractor.importBlocks(file) - .then((status) => { - if (!status) { - throw new Error('failed') - } - }) - }, - generateExportableUsersContent (users) { - // Get addresses - return users.map((user) => { - // check is it's a local user - if (user && user.is_local) { - // append the instance address - // eslint-disable-next-line no-undef - return user.screen_name + '@' + location.hostname - } - return user.screen_name - }).join('\n') - }, - getFollowsContent () { - return this.$store.state.api.backendInteractor.exportFriends({ id: this.$store.state.users.currentUser.id }) - .then(this.generateExportableUsersContent) - }, - getBlocksContent () { - return this.$store.state.api.backendInteractor.fetchBlocks() - .then(this.generateExportableUsersContent) - }, - confirmDelete () { - this.deletingAccount = true - }, - deleteAccount () { - this.$store.state.api.backendInteractor.deleteAccount({ password: this.deleteAccountConfirmPasswordInput }) - .then((res) => { - if (res.status === 'success') { - this.$store.dispatch('logout') - this.$router.push({ name: 'root' }) - } else { - this.deleteAccountError = res.error - } - }) - }, - changePassword () { - const params = { - password: this.changePasswordInputs[0], - newPassword: this.changePasswordInputs[1], - newPasswordConfirmation: this.changePasswordInputs[2] - } - this.$store.state.api.backendInteractor.changePassword(params) - .then((res) => { - if (res.status === 'success') { - this.changedPassword = true - this.changePasswordError = false - this.logout() - } else { - this.changedPassword = false - this.changePasswordError = res.error - } - }) - }, - changeEmail () { - const params = { - email: this.newEmail, - password: this.changeEmailPassword - } - this.$store.state.api.backendInteractor.changeEmail(params) - .then((res) => { - if (res.status === 'success') { - this.changedEmail = true - this.changeEmailError = false - } else { - this.changedEmail = false - this.changeEmailError = res.error - } - }) - }, - activateTab (tabName) { - this.activeTab = tabName - }, - logout () { - this.$store.dispatch('logout') - this.$router.replace('/') - }, - revokeToken (id) { - if (window.confirm(`${this.$i18n.t('settings.revoke_token')}?`)) { - this.$store.dispatch('revokeToken', id) - } - }, - filterUnblockedUsers (userIds) { - return reject(userIds, (userId) => { - const user = this.$store.getters.findUser(userId) - return !user || user.statusnet_blocking || user.id === this.$store.state.users.currentUser.id - }) - }, - filterUnMutedUsers (userIds) { - return reject(userIds, (userId) => { - const user = this.$store.getters.findUser(userId) - return !user || user.muted || user.id === this.$store.state.users.currentUser.id - }) - }, - queryUserIds (query) { - return this.$store.dispatch('searchUsers', query) - .then((users) => map(users, 'id')) - }, - blockUsers (ids) { - return this.$store.dispatch('blockUsers', ids) - }, - unblockUsers (ids) { - return this.$store.dispatch('unblockUsers', ids) - }, - muteUsers (ids) { - return this.$store.dispatch('muteUsers', ids) - }, - unmuteUsers (ids) { - return this.$store.dispatch('unmuteUsers', ids) - }, - identity (value) { - return value - } - } -} - -export default UserSettings diff --git a/src/components/user_settings/user_settings.vue b/src/components/user_settings/user_settings.vue deleted file mode 100644 index 3f1982a6..00000000 --- a/src/components/user_settings/user_settings.vue +++ /dev/null @@ -1,646 +0,0 @@ -<template> - <div class="settings panel panel-default"> - <div class="panel-heading"> - <div class="title"> - {{ $t('settings.user_settings') }} - </div> - <transition name="fade"> - <template v-if="currentSaveStateNotice"> - <div - v-if="currentSaveStateNotice.error" - class="alert error" - @click.prevent - > - {{ $t('settings.saving_err') }} - </div> - - <div - v-if="!currentSaveStateNotice.error" - class="alert transparent" - @click.prevent - > - {{ $t('settings.saving_ok') }} - </div> - </template> - </transition> - </div> - <div class="panel-body profile-edit"> - <tab-switcher> - <div :label="$t('settings.profile_tab')"> - <div class="setting-item"> - <h2>{{ $t('settings.name_bio') }}</h2> - <p>{{ $t('settings.name') }}</p> - <EmojiInput - v-model="newName" - enable-emoji-picker - :suggest="emojiSuggestor" - > - <input - id="username" - v-model="newName" - classname="name-changer" - > - </EmojiInput> - <p>{{ $t('settings.bio') }}</p> - <EmojiInput - v-model="newBio" - enable-emoji-picker - :suggest="emojiUserSuggestor" - > - <textarea - v-model="newBio" - classname="bio" - /> - </EmojiInput> - <p> - <Checkbox v-model="newLocked"> - {{ $t('settings.lock_account_description') }} - </Checkbox> - </p> - <div> - <label for="default-vis">{{ $t('settings.default_vis') }}</label> - <div - id="default-vis" - class="visibility-tray" - > - <scope-selector - :show-all="true" - :user-default="newDefaultScope" - :initial-scope="newDefaultScope" - :on-scope-change="changeVis" - /> - </div> - </div> - <p> - <Checkbox v-model="newNoRichText"> - {{ $t('settings.no_rich_text_description') }} - </Checkbox> - </p> - <p> - <Checkbox v-model="hideFollows"> - {{ $t('settings.hide_follows_description') }} - </Checkbox> - </p> - <p class="setting-subitem"> - <Checkbox - v-model="hideFollowsCount" - :disabled="!hideFollows" - > - {{ $t('settings.hide_follows_count_description') }} - </Checkbox> - </p> - <p> - <Checkbox - v-model="hideFollowers" - > - {{ $t('settings.hide_followers_description') }} - </Checkbox> - </p> - <p class="setting-subitem"> - <Checkbox - v-model="hideFollowersCount" - :disabled="!hideFollowers" - > - {{ $t('settings.hide_followers_count_description') }} - </Checkbox> - </p> - <p v-if="role === 'admin' || role === 'moderator'"> - <Checkbox v-model="showRole"> - <template v-if="role === 'admin'"> - {{ $t('settings.show_admin_badge') }} - </template> - <template v-if="role === 'moderator'"> - {{ $t('settings.show_moderator_badge') }} - </template> - </Checkbox> - </p> - <p> - <Checkbox v-model="discoverable"> - {{ $t('settings.discoverable') }} - </Checkbox> - </p> - <button - :disabled="newName && newName.length === 0" - class="btn btn-default" - @click="updateProfile" - > - {{ $t('general.submit') }} - </button> - </div> - <div class="setting-item"> - <h2>{{ $t('settings.avatar') }}</h2> - <p class="visibility-notice"> - {{ $t('settings.avatar_size_instruction') }} - </p> - <p>{{ $t('settings.current_avatar') }}</p> - <img - :src="user.profile_image_url_original" - class="current-avatar" - > - <p>{{ $t('settings.set_new_avatar') }}</p> - <button - v-show="pickAvatarBtnVisible" - id="pick-avatar" - class="btn" - type="button" - > - {{ $t('settings.upload_a_photo') }} - </button> - <image-cropper - trigger="#pick-avatar" - :submit-handler="submitAvatar" - @open="pickAvatarBtnVisible=false" - @close="pickAvatarBtnVisible=true" - /> - </div> - <div class="setting-item"> - <h2>{{ $t('settings.profile_banner') }}</h2> - <p>{{ $t('settings.current_profile_banner') }}</p> - <img - :src="user.cover_photo" - class="banner" - > - <p>{{ $t('settings.set_new_profile_banner') }}</p> - <img - v-if="bannerPreview" - class="banner" - :src="bannerPreview" - > - <div> - <input - type="file" - @change="uploadFile('banner', $event)" - > - </div> - <i - v-if="bannerUploading" - class=" icon-spin4 animate-spin uploading" - /> - <button - v-else-if="bannerPreview" - class="btn btn-default" - @click="submitBanner" - > - {{ $t('general.submit') }} - </button> - <div - v-if="bannerUploadError" - class="alert error" - > - Error: {{ bannerUploadError }} - <i - class="button-icon icon-cancel" - @click="clearUploadError('banner')" - /> - </div> - </div> - <div class="setting-item"> - <h2>{{ $t('settings.profile_background') }}</h2> - <p>{{ $t('settings.set_new_profile_background') }}</p> - <img - v-if="backgroundPreview" - class="bg" - :src="backgroundPreview" - > - <div> - <input - type="file" - @change="uploadFile('background', $event)" - > - </div> - <i - v-if="backgroundUploading" - class=" icon-spin4 animate-spin uploading" - /> - <button - v-else-if="backgroundPreview" - class="btn btn-default" - @click="submitBg" - > - {{ $t('general.submit') }} - </button> - <div - v-if="backgroundUploadError" - class="alert error" - > - Error: {{ backgroundUploadError }} - <i - class="button-icon icon-cancel" - @click="clearUploadError('background')" - /> - </div> - </div> - </div> - - <div :label="$t('settings.security_tab')"> - <div class="setting-item"> - <h2>{{ $t('settings.change_email') }}</h2> - <div> - <p>{{ $t('settings.new_email') }}</p> - <input - v-model="newEmail" - type="email" - autocomplete="email" - > - </div> - <div> - <p>{{ $t('settings.current_password') }}</p> - <input - v-model="changeEmailPassword" - type="password" - autocomplete="current-password" - > - </div> - <button - class="btn btn-default" - @click="changeEmail" - > - {{ $t('general.submit') }} - </button> - <p v-if="changedEmail"> - {{ $t('settings.changed_email') }} - </p> - <template v-if="changeEmailError !== false"> - <p>{{ $t('settings.change_email_error') }}</p> - <p>{{ changeEmailError }}</p> - </template> - </div> - - <div class="setting-item"> - <h2>{{ $t('settings.change_password') }}</h2> - <div> - <p>{{ $t('settings.current_password') }}</p> - <input - v-model="changePasswordInputs[0]" - type="password" - > - </div> - <div> - <p>{{ $t('settings.new_password') }}</p> - <input - v-model="changePasswordInputs[1]" - type="password" - > - </div> - <div> - <p>{{ $t('settings.confirm_new_password') }}</p> - <input - v-model="changePasswordInputs[2]" - type="password" - > - </div> - <button - class="btn btn-default" - @click="changePassword" - > - {{ $t('general.submit') }} - </button> - <p v-if="changedPassword"> - {{ $t('settings.changed_password') }} - </p> - <p v-else-if="changePasswordError !== false"> - {{ $t('settings.change_password_error') }} - </p> - <p v-if="changePasswordError"> - {{ changePasswordError }} - </p> - </div> - - <div class="setting-item"> - <h2>{{ $t('settings.oauth_tokens') }}</h2> - <table class="oauth-tokens"> - <thead> - <tr> - <th>{{ $t('settings.app_name') }}</th> - <th>{{ $t('settings.valid_until') }}</th> - <th /> - </tr> - </thead> - <tbody> - <tr - v-for="oauthToken in oauthTokens" - :key="oauthToken.id" - > - <td>{{ oauthToken.appName }}</td> - <td>{{ oauthToken.validUntil }}</td> - <td class="actions"> - <button - class="btn btn-default" - @click="revokeToken(oauthToken.id)" - > - {{ $t('settings.revoke_token') }} - </button> - </td> - </tr> - </tbody> - </table> - </div> - <mfa /> - <div class="setting-item"> - <h2>{{ $t('settings.delete_account') }}</h2> - <p v-if="!deletingAccount"> - {{ $t('settings.delete_account_description') }} - </p> - <div v-if="deletingAccount"> - <p>{{ $t('settings.delete_account_instructions') }}</p> - <p>{{ $t('login.password') }}</p> - <input - v-model="deleteAccountConfirmPasswordInput" - type="password" - > - <button - class="btn btn-default" - @click="deleteAccount" - > - {{ $t('settings.delete_account') }} - </button> - </div> - <p v-if="deleteAccountError !== false"> - {{ $t('settings.delete_account_error') }} - </p> - <p v-if="deleteAccountError"> - {{ deleteAccountError }} - </p> - <button - v-if="!deletingAccount" - class="btn btn-default" - @click="confirmDelete" - > - {{ $t('general.submit') }} - </button> - </div> - </div> - - <div - v-if="pleromaBackend" - :label="$t('settings.notifications')" - > - <div class="setting-item"> - <div class="select-multiple"> - <span class="label">{{ $t('settings.notification_setting') }}</span> - <ul class="option-list"> - <li> - <Checkbox v-model="notificationSettings.follows"> - {{ $t('settings.notification_setting_follows') }} - </Checkbox> - </li> - <li> - <Checkbox v-model="notificationSettings.followers"> - {{ $t('settings.notification_setting_followers') }} - </Checkbox> - </li> - <li> - <Checkbox v-model="notificationSettings.non_follows"> - {{ $t('settings.notification_setting_non_follows') }} - </Checkbox> - </li> - <li> - <Checkbox v-model="notificationSettings.non_followers"> - {{ $t('settings.notification_setting_non_followers') }} - </Checkbox> - </li> - </ul> - </div> - <p>{{ $t('settings.notification_mutes') }}</p> - <p>{{ $t('settings.notification_blocks') }}</p> - <button - class="btn btn-default" - @click="updateNotificationSettings" - > - {{ $t('general.submit') }} - </button> - </div> - </div> - - <div - v-if="pleromaBackend" - :label="$t('settings.data_import_export_tab')" - > - <div class="setting-item"> - <h2>{{ $t('settings.follow_import') }}</h2> - <p>{{ $t('settings.import_followers_from_a_csv_file') }}</p> - <Importer - :submit-handler="importFollows" - :success-message="$t('settings.follows_imported')" - :error-message="$t('settings.follow_import_error')" - /> - </div> - <div class="setting-item"> - <h2>{{ $t('settings.follow_export') }}</h2> - <Exporter - :get-content="getFollowsContent" - filename="friends.csv" - :export-button-label="$t('settings.follow_export_button')" - /> - </div> - <div class="setting-item"> - <h2>{{ $t('settings.block_import') }}</h2> - <p>{{ $t('settings.import_blocks_from_a_csv_file') }}</p> - <Importer - :submit-handler="importBlocks" - :success-message="$t('settings.blocks_imported')" - :error-message="$t('settings.block_import_error')" - /> - </div> - <div class="setting-item"> - <h2>{{ $t('settings.block_export') }}</h2> - <Exporter - :get-content="getBlocksContent" - filename="blocks.csv" - :export-button-label="$t('settings.block_export_button')" - /> - </div> - </div> - - <div :label="$t('settings.blocks_tab')"> - <div class="profile-edit-usersearch-wrapper"> - <Autosuggest - :filter="filterUnblockedUsers" - :query="queryUserIds" - :placeholder="$t('settings.search_user_to_block')" - > - <BlockCard - slot-scope="row" - :user-id="row.item" - /> - </Autosuggest> - </div> - <BlockList - :refresh="true" - :get-key="identity" - > - <template - slot="header" - slot-scope="{selected}" - > - <div class="profile-edit-bulk-actions"> - <ProgressButton - v-if="selected.length > 0" - class="btn btn-default" - :click="() => blockUsers(selected)" - > - {{ $t('user_card.block') }} - <template slot="progress"> - {{ $t('user_card.block_progress') }} - </template> - </ProgressButton> - <ProgressButton - v-if="selected.length > 0" - class="btn btn-default" - :click="() => unblockUsers(selected)" - > - {{ $t('user_card.unblock') }} - <template slot="progress"> - {{ $t('user_card.unblock_progress') }} - </template> - </ProgressButton> - </div> - </template> - <template - slot="item" - slot-scope="{item}" - > - <BlockCard :user-id="item" /> - </template> - <template slot="empty"> - {{ $t('settings.no_blocks') }} - </template> - </BlockList> - </div> - - <div :label="$t('settings.mutes_tab')"> - <div class="profile-edit-usersearch-wrapper"> - <Autosuggest - :filter="filterUnMutedUsers" - :query="queryUserIds" - :placeholder="$t('settings.search_user_to_mute')" - > - <MuteCard - slot-scope="row" - :user-id="row.item" - /> - </Autosuggest> - </div> - <MuteList - :refresh="true" - :get-key="identity" - > - <template - slot="header" - slot-scope="{selected}" - > - <div class="profile-edit-bulk-actions"> - <ProgressButton - v-if="selected.length > 0" - class="btn btn-default" - :click="() => muteUsers(selected)" - > - {{ $t('user_card.mute') }} - <template slot="progress"> - {{ $t('user_card.mute_progress') }} - </template> - </ProgressButton> - <ProgressButton - v-if="selected.length > 0" - class="btn btn-default" - :click="() => unmuteUsers(selected)" - > - {{ $t('user_card.unmute') }} - <template slot="progress"> - {{ $t('user_card.unmute_progress') }} - </template> - </ProgressButton> - </div> - </template> - <template - slot="item" - slot-scope="{item}" - > - <MuteCard :user-id="item" /> - </template> - <template slot="empty"> - {{ $t('settings.no_mutes') }} - </template> - </MuteList> - </div> - </tab-switcher> - </div> - </div> -</template> - -<script src="./user_settings.js"> -</script> - -<style lang="scss"> -@import '../../_variables.scss'; - -.profile-edit { - .bio { - margin: 0; - } - - .visibility-tray { - padding-top: 5px; - } - - input[type=file] { - padding: 5px; - height: auto; - } - - .banner { - max-width: 100%; - } - - .uploading { - font-size: 1.5em; - margin: 0.25em; - } - - .name-changer { - width: 100%; - } - - .bg { - max-width: 100%; - } - - .current-avatar { - display: block; - width: 150px; - height: 150px; - border-radius: $fallback--avatarRadius; - border-radius: var(--avatarRadius, $fallback--avatarRadius); - } - - .oauth-tokens { - width: 100%; - - th { - text-align: left; - } - - .actions { - text-align: right; - } - } - - &-usersearch-wrapper { - padding: 1em; - } - - &-bulk-actions { - text-align: right; - padding: 0 1em; - min-height: 28px; - - button { - width: 10em; - } - } - - .setting-subitem { - margin-left: 1.75em; - } -} -</style> |
