From 13725f040bca346a7b35b832f36f4e86c5da11e4 Mon Sep 17 00:00:00 2001 From: taehoon Date: Thu, 7 Feb 2019 03:05:59 -0500 Subject: Add avatar crop popup --- src/components/user_settings/user_settings.js | 29 +++----------- src/components/user_settings/user_settings.vue | 52 +++++++++++++++++++++----- 2 files changed, 48 insertions(+), 33 deletions(-) (limited to 'src/components/user_settings') diff --git a/src/components/user_settings/user_settings.js b/src/components/user_settings/user_settings.js index d20bf308..b3d31d67 100644 --- a/src/components/user_settings/user_settings.js +++ b/src/components/user_settings/user_settings.js @@ -1,6 +1,7 @@ import { unescape } from 'lodash' 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 fileSizeFormatService from '../../services/file_size_format/file_size_format.js' @@ -24,7 +25,6 @@ const UserSettings = { bannerUploading: false, backgroundUploading: false, followListUploading: false, - avatarPreview: null, bannerPreview: null, backgroundPreview: null, avatarUploadError: null, @@ -41,7 +41,8 @@ const UserSettings = { }, components: { StyleSwitcher, - TabSwitcher + TabSwitcher, + ImageCropper }, computed: { user () { @@ -117,31 +118,13 @@ const UserSettings = { } reader.readAsDataURL(file) }, - submitAvatar () { - if (!this.avatarPreview) { return } - - let img = this.avatarPreview - // eslint-disable-next-line no-undef - let imginfo = new Image() - let cropX, cropY, cropW, cropH - imginfo.src = img - if (imginfo.height > imginfo.width) { - cropX = 0 - cropW = imginfo.width - cropY = Math.floor((imginfo.height - imginfo.width) / 2) - cropH = imginfo.width - } else { - cropY = 0 - cropH = imginfo.height - cropX = Math.floor((imginfo.width - imginfo.height) / 2) - cropW = imginfo.height - } + submitAvatar (cropper) { + const img = cropper.getCroppedCanvas({ width: 150, height: 150 }).toDataURL('image/jpeg') this.avatarUploading = true - this.$store.state.api.backendInteractor.updateAvatar({params: {img, cropX, cropY, cropW, cropH}}).then((user) => { + this.$store.state.api.backendInteractor.updateAvatar({ params: { img } }).then((user) => { if (!user.error) { this.$store.commit('addNewUsers', [user]) this.$store.commit('setCurrentUser', user) - this.avatarPreview = null } else { this.avatarUploadError = this.$t('upload.error.base') + user.error } diff --git a/src/components/user_settings/user_settings.vue b/src/components/user_settings/user_settings.vue index d2381da2..9fcd3752 100644 --- a/src/components/user_settings/user_settings.vue +++ b/src/components/user_settings/user_settings.vue @@ -47,20 +47,20 @@

{{$t('settings.avatar')}}

{{$t('settings.avatar_size_instruction')}}

-

{{$t('settings.current_avatar')}}

- -

{{$t('settings.set_new_avatar')}}

- - -
- +
+
+ +
+ +
+
- - -
+ +
Error: {{ avatarUploadError }}
+

{{$t('settings.profile_banner')}}

@@ -167,6 +167,8 @@ -- cgit v1.2.3-70-g09d2 From 09949fc7eea10e592339fd620d140eb92a18e28b Mon Sep 17 00:00:00 2001 From: taehoon Date: Fri, 8 Feb 2019 11:01:50 -0500 Subject: Crop avatar image using minWidth/minHeight --- src/components/user_settings/user_settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/components/user_settings') diff --git a/src/components/user_settings/user_settings.js b/src/components/user_settings/user_settings.js index b3d31d67..8987c691 100644 --- a/src/components/user_settings/user_settings.js +++ b/src/components/user_settings/user_settings.js @@ -119,7 +119,7 @@ const UserSettings = { reader.readAsDataURL(file) }, submitAvatar (cropper) { - const img = cropper.getCroppedCanvas({ width: 150, height: 150 }).toDataURL('image/jpeg') + const img = cropper.getCroppedCanvas({ minWidth: 150, minHeight: 150 }).toDataURL('image/jpeg') this.avatarUploading = true this.$store.state.api.backendInteractor.updateAvatar({ params: { img } }).then((user) => { if (!user.error) { -- cgit v1.2.3-70-g09d2 From b24db12e1cc318e862169355a22f051d3ea2e809 Mon Sep 17 00:00:00 2001 From: taehoon Date: Fri, 8 Feb 2019 21:59:33 -0500 Subject: Make embedded image cropper --- src/components/image_cropper/image_cropper.js | 37 ++++++++++++++-------- src/components/image_cropper/image_cropper.vue | 25 ++++++++------- src/components/user_settings/user_settings.js | 9 ++---- src/components/user_settings/user_settings.vue | 43 ++++---------------------- src/i18n/en.json | 5 +-- 5 files changed, 50 insertions(+), 69 deletions(-) (limited to 'src/components/user_settings') diff --git a/src/components/image_cropper/image_cropper.js b/src/components/image_cropper/image_cropper.js index b2580240..4eaa08d4 100644 --- a/src/components/image_cropper/image_cropper.js +++ b/src/components/image_cropper/image_cropper.js @@ -1,5 +1,4 @@ import Cropper from 'cropperjs' -import Modal from '../modal/modal.vue' import 'cropperjs/dist/cropper.css' const ImageCropper = { @@ -8,6 +7,10 @@ const ImageCropper = { type: [String, window.Element], required: true }, + submitHandler: { + type: Function, + required: true + }, cropperOptions: { type: Object, default () { @@ -25,10 +28,10 @@ const ImageCropper = { type: String, default: 'image/png, image/gif, image/jpeg, image/bmp, image/x-icon' }, - title: { + saveButtonLabel: { type: String }, - saveButtonLabel: { + cancelButtonLabel: { type: String } }, @@ -36,18 +39,17 @@ const ImageCropper = { return { cropper: undefined, dataUrl: undefined, - filename: undefined + filename: undefined, + submitting: false, + submitError: null } }, - components: { - Modal - }, computed: { - modalTitle () { - return this.title || this.$t('image_cropper.crop_picture') - }, - modalSaveButtonLabel () { + saveText () { return this.saveButtonLabel || this.$t('image_cropper.save') + }, + cancelText () { + return this.cancelButtonLabel || this.$t('image_cropper.cancel') } }, methods: { @@ -57,10 +59,15 @@ const ImageCropper = { } this.$refs.input.value = '' this.dataUrl = undefined + this.$emit('close') }, submit () { - this.$emit('submit', this.cropper, this.filename) - this.destroy() + this.submitting = true + this.avatarUploadError = null + this.submitHandler(this.cropper, this.filename) + .then(() => this.destroy()) + .catch(err => this.submitError = err) + .finally(() => this.submitting = false) }, pickImage () { this.$refs.input.click() @@ -77,11 +84,15 @@ const ImageCropper = { let reader = new window.FileReader() reader.onload = (e) => { this.dataUrl = e.target.result + this.$emit('open') } reader.readAsDataURL(fileInput.files[0]) this.filename = fileInput.files[0].name || 'unknown' this.$emit('changed', fileInput.files[0], reader) } + }, + clearError () { + this.submitError = null } }, mounted () { diff --git a/src/components/image_cropper/image_cropper.vue b/src/components/image_cropper/image_cropper.vue index b2367128..aa895863 100644 --- a/src/components/image_cropper/image_cropper.vue +++ b/src/components/image_cropper/image_cropper.vue @@ -1,15 +1,19 @@ @@ -31,9 +35,8 @@ } } - &-btn { - display: block; - width: 100%; + &-buttons-wrapper { + margin-top: 15px; } } diff --git a/src/components/user_settings/user_settings.js b/src/components/user_settings/user_settings.js index 8987c691..2d521c14 100644 --- a/src/components/user_settings/user_settings.js +++ b/src/components/user_settings/user_settings.js @@ -21,13 +21,12 @@ const UserSettings = { followImportError: false, followsImported: false, enableFollowsExport: true, - avatarUploading: false, + pickAvatarBtnVisible: true, bannerUploading: false, backgroundUploading: false, followListUploading: false, bannerPreview: null, backgroundPreview: null, - avatarUploadError: null, bannerUploadError: null, backgroundUploadError: null, deletingAccount: false, @@ -120,15 +119,13 @@ const UserSettings = { }, submitAvatar (cropper) { const img = cropper.getCroppedCanvas({ minWidth: 150, minHeight: 150 }).toDataURL('image/jpeg') - this.avatarUploading = true - this.$store.state.api.backendInteractor.updateAvatar({ params: { img } }).then((user) => { + return this.$store.state.api.backendInteractor.updateAvatar({ params: { img } }).then((user) => { if (!user.error) { this.$store.commit('addNewUsers', [user]) this.$store.commit('setCurrentUser', user) } else { - this.avatarUploadError = this.$t('upload.error.base') + user.error + throw this.$t('upload.error.base') + user.error } - this.avatarUploading = false }) }, clearUploadError (slot) { diff --git a/src/components/user_settings/user_settings.vue b/src/components/user_settings/user_settings.vue index 9fcd3752..8ab92e95 100644 --- a/src/components/user_settings/user_settings.vue +++ b/src/components/user_settings/user_settings.vue @@ -47,20 +47,11 @@

{{$t('settings.avatar')}}

{{$t('settings.avatar_size_instruction')}}

-
-
- -
- -
-
-
- -
- Error: {{ avatarUploadError }} - -
- +

{{$t('settings.current_avatar')}}

+ +

{{$t('settings.set_new_avatar')}}

+ +

{{$t('settings.profile_banner')}}

@@ -196,29 +187,7 @@ max-width: 100%; } - .avatar-upload { - display: inline-block; - position: relative; - } - - .avatar-upload-loading-wrapper { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - display: flex; - justify-content: center; - align-items: center; - background: rgba(0,0,0,.3); - - i { - font-size: 50px; - color: #FFF; - } - } - - .avatar { + .current-avatar { display: block; width: 150px; height: 150px; diff --git a/src/i18n/en.json b/src/i18n/en.json index 3e9ac157..af62acfc 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -23,7 +23,8 @@ }, "image_cropper": { "crop_picture": "Crop picture", - "save": "Save" + "save": "Save", + "cancel": "Cancel" }, "login": { "login": "Log in", @@ -116,7 +117,6 @@ "collapse_subject": "Collapse posts with subjects", "composing": "Composing", "confirm_new_password": "Confirm new password", - "crop_your_new_avatar": "Crop your new avatar", "current_avatar": "Your current avatar", "current_password": "Current password", "current_profile_banner": "Your current profile banner", @@ -211,6 +211,7 @@ "theme_help_v2_1": "You can also override certain component's colors and opacity by toggling the checkbox, use \"Clear all\" button to clear all overrides.", "theme_help_v2_2": "Icons underneath some entries are background/text contrast indicators, hover over for detailed info. Please keep in mind that when using transparency contrast indicators show the worst possible case.", "tooltipRadius": "Tooltips/alerts", + "upload_a_photo": "Upload a photo", "user_settings": "User Settings", "values": { "false": "no", -- cgit v1.2.3-70-g09d2 From 2132d58075c71bd8a445288d052cc05e321fdf24 Mon Sep 17 00:00:00 2001 From: taehoon Date: Fri, 8 Feb 2019 22:06:02 -0500 Subject: Remove cropped image size restriction --- src/components/user_settings/user_settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/components/user_settings') diff --git a/src/components/user_settings/user_settings.js b/src/components/user_settings/user_settings.js index 2d521c14..c1c60102 100644 --- a/src/components/user_settings/user_settings.js +++ b/src/components/user_settings/user_settings.js @@ -118,7 +118,7 @@ const UserSettings = { reader.readAsDataURL(file) }, submitAvatar (cropper) { - const img = cropper.getCroppedCanvas({ minWidth: 150, minHeight: 150 }).toDataURL('image/jpeg') + const img = cropper.getCroppedCanvas().toDataURL('image/jpeg') return this.$store.state.api.backendInteractor.updateAvatar({ params: { img } }).then((user) => { if (!user.error) { this.$store.commit('addNewUsers', [user]) -- cgit v1.2.3-70-g09d2 From 2de756aa0c27ae5267032e07c2e1f998d49d0df5 Mon Sep 17 00:00:00 2001 From: taehoon Date: Fri, 8 Feb 2019 22:17:53 -0500 Subject: Better error handling --- src/components/image_cropper/image_cropper.js | 3 +++ src/components/image_cropper/image_cropper.vue | 2 +- src/components/user_settings/user_settings.js | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) (limited to 'src/components/user_settings') diff --git a/src/components/image_cropper/image_cropper.js b/src/components/image_cropper/image_cropper.js index 4eaa08d4..da94427a 100644 --- a/src/components/image_cropper/image_cropper.js +++ b/src/components/image_cropper/image_cropper.js @@ -50,6 +50,9 @@ const ImageCropper = { }, cancelText () { return this.cancelButtonLabel || this.$t('image_cropper.cancel') + }, + submitErrorMsg () { + return this.submitError && this.submitError instanceof Error ? this.submitError.toString() : this.submitError } }, methods: { diff --git a/src/components/image_cropper/image_cropper.vue b/src/components/image_cropper/image_cropper.vue index aa895863..24a6f3bd 100644 --- a/src/components/image_cropper/image_cropper.vue +++ b/src/components/image_cropper/image_cropper.vue @@ -10,7 +10,7 @@
- Error: {{ submitError }} + {{submitErrorMsg}}
diff --git a/src/components/user_settings/user_settings.js b/src/components/user_settings/user_settings.js index c1c60102..dce3eeed 100644 --- a/src/components/user_settings/user_settings.js +++ b/src/components/user_settings/user_settings.js @@ -124,7 +124,7 @@ const UserSettings = { this.$store.commit('addNewUsers', [user]) this.$store.commit('setCurrentUser', user) } else { - throw this.$t('upload.error.base') + user.error + throw new Error(this.$t('upload.error.base') + user.error) } }) }, -- cgit v1.2.3-70-g09d2 From 63cfe051c7f5419da3942632f3a5453f6cd5c769 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 19 Feb 2019 12:38:49 -0500 Subject: #371: show notification when user setting's saved --- src/components/user_settings/user_settings.js | 3 +++ src/components/user_settings/user_settings.vue | 15 ++++++++++++++- src/lib/persisted_state.js | 4 ++-- 3 files changed, 19 insertions(+), 3 deletions(-) (limited to 'src/components/user_settings') diff --git a/src/components/user_settings/user_settings.js b/src/components/user_settings/user_settings.js index d20bf308..3ad711c2 100644 --- a/src/components/user_settings/user_settings.js +++ b/src/components/user_settings/user_settings.js @@ -60,6 +60,9 @@ const UserSettings = { private: { selected: this.newDefaultScope === 'private' }, direct: { selected: this.newDefaultScope === 'direct' } } + }, + currentSaveStateNotice () { + return this.$store.state.interface.settings.currentSaveStateNotice } }, methods: { diff --git a/src/components/user_settings/user_settings.vue b/src/components/user_settings/user_settings.vue index d2381da2..d1770562 100644 --- a/src/components/user_settings/user_settings.vue +++ b/src/components/user_settings/user_settings.vue @@ -1,7 +1,20 @@ diff --git a/src/components/user_settings/user_settings.js b/src/components/user_settings/user_settings.js index 3bcecdf4..621dcd4b 100644 --- a/src/components/user_settings/user_settings.js +++ b/src/components/user_settings/user_settings.js @@ -9,7 +9,7 @@ import BlockCard from '../block_card/block_card.vue' import withLoadMore from '../../hocs/with_load_more/with_load_more' import withList from '../../hocs/with_list/with_list' -const BlockList = withList(BlockCard, entry => ({ user: entry })) +const BlockList = withList(BlockCard, entry => ({ userId: entry.id })) const BlockListWithLoadMore = withLoadMore( BlockList, (props, $store) => $store.dispatch('fetchBlocks'), diff --git a/src/i18n/en.json b/src/i18n/en.json index 9027803d..eeb95f9c 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -368,7 +368,8 @@ "remote_follow": "Remote follow", "statuses": "Statuses", "unblock": "Unblock", - "unblock_progress": "Unblocking..." + "unblock_progress": "Unblocking...", + "block_progress": "Blocking..." }, "user_profile": { "timeline_title": "User Timeline" diff --git a/src/modules/users.js b/src/modules/users.js index 6ea4e0c9..ce8af68c 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -154,6 +154,14 @@ const users = { return blocks }) }, + blockUser (store, id) { + return store.rootState.api.backendInteractor.blockUser(id) + .then((user) => store.commit('addNewUsers', [user])) + }, + unblockUser (store, id) { + return store.rootState.api.backendInteractor.unblockUser(id) + .then((user) => store.commit('addNewUsers', [user])) + }, addFriends ({ rootState, commit }, fetchBy) { return new Promise((resolve, reject) => { const user = rootState.users.usersObject[fetchBy] -- cgit v1.2.3-70-g09d2 From 8c8a6edc7800bac854ef23f29aa87f5b932cb415 Mon Sep 17 00:00:00 2001 From: taehoon Date: Wed, 13 Feb 2019 21:08:14 -0500 Subject: Remove pagination support from block-list --- src/components/user_settings/user_settings.js | 10 ++++++---- src/components/user_settings/user_settings.vue | 2 +- src/modules/users.js | 17 ++++++----------- .../entity_normalizer/entity_normalizer.service.js | 2 +- 4 files changed, 14 insertions(+), 17 deletions(-) (limited to 'src/components/user_settings') diff --git a/src/components/user_settings/user_settings.js b/src/components/user_settings/user_settings.js index 621dcd4b..8eade382 100644 --- a/src/components/user_settings/user_settings.js +++ b/src/components/user_settings/user_settings.js @@ -7,13 +7,15 @@ import StyleSwitcher from '../style_switcher/style_switcher.vue' import fileSizeFormatService from '../../services/file_size_format/file_size_format.js' import BlockCard from '../block_card/block_card.vue' import withLoadMore from '../../hocs/with_load_more/with_load_more' +import withSubscription from '../../hocs/with_subscription/with_subscription' import withList from '../../hocs/with_list/with_list' -const BlockList = withList(BlockCard, entry => ({ userId: entry.id })) -const BlockListWithLoadMore = withLoadMore( +const BlockList = withList(BlockCard, userId => ({ userId })) +const BlockListWithSubscription = withSubscription( BlockList, (props, $store) => $store.dispatch('fetchBlocks'), - (props, $store) => get($store.state.users.currentUser, 'blocks', []) + (props, $store) => get($store.state.users.currentUser, 'blockIds', []), + 'entries' ) const UserSettings = { @@ -53,7 +55,7 @@ const UserSettings = { StyleSwitcher, TabSwitcher, ImageCropper, - 'block-list': BlockListWithLoadMore + 'block-list': BlockListWithSubscription }, computed: { user () { diff --git a/src/components/user_settings/user_settings.vue b/src/components/user_settings/user_settings.vue index be9f27e7..5cf21815 100644 --- a/src/components/user_settings/user_settings.vue +++ b/src/components/user_settings/user_settings.vue @@ -164,7 +164,7 @@
- +
diff --git a/src/modules/users.js b/src/modules/users.js index ce8af68c..1f03b47e 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -1,5 +1,5 @@ import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js' -import { compact, map, each, merge, find } from 'lodash' +import { compact, map, each, merge, find, union } from 'lodash' import { set } from 'vue' import { registerPushNotifications, unregisterPushNotifications } from '../services/push/push.js' import oauthApi from '../services/new_api/oauth' @@ -85,14 +85,9 @@ export const mutations = { addNewUsers (state, users) { each(users, (user) => mergeOrAdd(state.users, state.usersObject, user)) }, - addBlocks (state, { blocks, page }) { + addBlocks (state, blockIds) { const user = state.currentUser - each(blocks, block => { - if (!find(user.blocks, { id: block.id })) { - user.blocks.push(block) - } - }) - user.blocksPage = page + 1 + user.blockIds = union(user.blockIds, blockIds) }, setUserForStatus (state, status) { status.user = state.usersObject[status.user.id] @@ -147,10 +142,10 @@ const users = { .then((user) => store.commit('addNewUsers', [user])) }, fetchBlocks (store) { - const page = store.state.currentUser.blocksPage || 1 - return store.rootState.api.backendInteractor.fetchBlocks({ page }) + return store.rootState.api.backendInteractor.fetchBlocks() .then((blocks) => { - store.commit('addBlocks', { blocks, page }) + store.commit('addBlocks', map(blocks, 'id')) + store.commit('addNewUsers', blocks) return blocks }) }, diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js index 1192b6cc..0e1be61e 100644 --- a/src/services/entity_normalizer/entity_normalizer.service.js +++ b/src/services/entity_normalizer/entity_normalizer.service.js @@ -120,7 +120,7 @@ export const parseUser = (data) => { if (data.pleroma) { output.follow_request_count = data.pleroma.follow_request_count } - output.blocks = [] + output.blockIds = [] return output } -- cgit v1.2.3-70-g09d2 From 09315b27804beadb7590f8e908ae9d0eb1d6a992 Mon Sep 17 00:00:00 2001 From: taehoon Date: Wed, 13 Feb 2019 21:21:56 -0500 Subject: Add a prop to force-refresh data to withSubscription hoc --- src/components/user_settings/user_settings.vue | 2 +- src/hocs/with_subscription/with_subscription.js | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'src/components/user_settings') diff --git a/src/components/user_settings/user_settings.vue b/src/components/user_settings/user_settings.vue index 5cf21815..5bae583c 100644 --- a/src/components/user_settings/user_settings.vue +++ b/src/components/user_settings/user_settings.vue @@ -164,7 +164,7 @@
- +
diff --git a/src/hocs/with_subscription/with_subscription.js b/src/hocs/with_subscription/with_subscription.js index 31fc106f..633517e3 100644 --- a/src/hocs/with_subscription/with_subscription.js +++ b/src/hocs/with_subscription/with_subscription.js @@ -1,24 +1,25 @@ import Vue from 'vue' -import filter from 'lodash/filter' +import reject from 'lodash/reject' import isEmpty from 'lodash/isEmpty' +import omit from 'lodash/omit' import './with_subscription.scss' const withSubscription = (Component, fetch, select, contentPropName = 'content') => { const originalProps = Component.props || [] - const props = filter(originalProps, v => v !== 'content') + const props = reject(originalProps, v => v === 'content') return Vue.component('withSubscription', { render (createElement) { const props = { props: { - ...this.$props, + ...omit(this.$props, 'refresh'), [contentPropName]: this.fetchedData }, on: this.$listeners } return (
- + {!this.error && !this.loading && } ) }, - props, + props: [...props, 'refresh'], data () { return { loading: false, @@ -39,7 +40,7 @@ const withSubscription = (Component, fetch, select, contentPropName = 'content') } }, created () { - if (isEmpty(this.fetchedData)) { + if (this.refresh || isEmpty(this.fetchedData)) { this.fetchData() } }, -- cgit v1.2.3-70-g09d2 From e91a94ff9c4b9559f53a4b001f8972ceca843771 Mon Sep 17 00:00:00 2001 From: taehoon Date: Wed, 13 Feb 2019 22:04:28 -0500 Subject: Add mutes tab --- src/components/mute_card/mute_card.js | 37 ++++++++++++++++++++++ src/components/mute_card/mute_card.vue | 24 ++++++++++++++ src/components/user_settings/user_settings.js | 13 ++++++-- src/components/user_settings/user_settings.vue | 4 +++ src/i18n/en.json | 1 + src/modules/users.js | 25 ++++++++++++--- .../entity_normalizer/entity_normalizer.service.js | 1 + 7 files changed, 99 insertions(+), 6 deletions(-) create mode 100644 src/components/mute_card/mute_card.js create mode 100644 src/components/mute_card/mute_card.vue (limited to 'src/components/user_settings') diff --git a/src/components/mute_card/mute_card.js b/src/components/mute_card/mute_card.js new file mode 100644 index 00000000..5dd0a9e5 --- /dev/null +++ b/src/components/mute_card/mute_card.js @@ -0,0 +1,37 @@ +import BasicUserCard from '../basic_user_card/basic_user_card.vue' + +const MuteCard = { + props: ['userId'], + data () { + return { + progress: false + } + }, + computed: { + user () { + return this.$store.getters.userById(this.userId) + }, + muted () { + return this.user.muted + } + }, + components: { + BasicUserCard + }, + methods: { + unmuteUser () { + this.progress = true + this.$store.dispatch('unmuteUser', this.user.id).then(() => { + this.progress = false + }) + }, + muteUser () { + this.progress = true + this.$store.dispatch('muteUser', this.user.id).then(() => { + this.progress = false + }) + } + } +} + +export default MuteCard diff --git a/src/components/mute_card/mute_card.vue b/src/components/mute_card/mute_card.vue new file mode 100644 index 00000000..e1bfe20b --- /dev/null +++ b/src/components/mute_card/mute_card.vue @@ -0,0 +1,24 @@ + + + \ No newline at end of file diff --git a/src/components/user_settings/user_settings.js b/src/components/user_settings/user_settings.js index 8eade382..8114d5e2 100644 --- a/src/components/user_settings/user_settings.js +++ b/src/components/user_settings/user_settings.js @@ -6,7 +6,7 @@ import ImageCropper from '../image_cropper/image_cropper.vue' import StyleSwitcher from '../style_switcher/style_switcher.vue' import fileSizeFormatService from '../../services/file_size_format/file_size_format.js' import BlockCard from '../block_card/block_card.vue' -import withLoadMore from '../../hocs/with_load_more/with_load_more' +import MuteCard from '../mute_card/mute_card.vue' import withSubscription from '../../hocs/with_subscription/with_subscription' import withList from '../../hocs/with_list/with_list' @@ -18,6 +18,14 @@ const BlockListWithSubscription = withSubscription( 'entries' ) +const MuteList = withList(MuteCard, userId => ({ userId })) +const MuteListWithSubscription = withSubscription( + MuteList, + (props, $store) => $store.dispatch('fetchMutes'), + (props, $store) => get($store.state.users.currentUser, 'muteIds', []), + 'entries' +) + const UserSettings = { data () { return { @@ -55,7 +63,8 @@ const UserSettings = { StyleSwitcher, TabSwitcher, ImageCropper, - 'block-list': BlockListWithSubscription + 'block-list': BlockListWithSubscription, + 'mute-list': MuteListWithSubscription }, computed: { user () { diff --git a/src/components/user_settings/user_settings.vue b/src/components/user_settings/user_settings.vue index 5bae583c..27f3e7cb 100644 --- a/src/components/user_settings/user_settings.vue +++ b/src/components/user_settings/user_settings.vue @@ -166,6 +166,10 @@
+ +
+ +
diff --git a/src/i18n/en.json b/src/i18n/en.json index eeb95f9c..b41b6db9 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -165,6 +165,7 @@ "lock_account_description": "Restrict your account to approved followers only", "loop_video": "Loop videos", "loop_video_silent_only": "Loop only videos without sound (i.e. Mastodon's \"gifs\")", + "mutes_tab": "Mutes", "play_videos_in_modal": "Play videos directly in the media viewer", "use_contain_fit": "Don't crop the attachment in thumbnails", "name": "Name", diff --git a/src/modules/users.js b/src/modules/users.js index 1f03b47e..71201a77 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -89,6 +89,10 @@ export const mutations = { const user = state.currentUser user.blockIds = union(user.blockIds, blockIds) }, + saveMutes (state, ids) { + const user = state.currentUser + user.muteIds = union(user.muteIds, ids) + }, setUserForStatus (state, status) { status.user = state.usersObject[status.user.id] }, @@ -157,6 +161,22 @@ const users = { return store.rootState.api.backendInteractor.unblockUser(id) .then((user) => store.commit('addNewUsers', [user])) }, + fetchMutes (store) { + return store.rootState.api.backendInteractor.fetchMutes() + .then((mutedUsers) => { + each(mutedUsers, (user) => { user.muted = true }) + store.commit('addNewUsers', mutedUsers) + store.commit('saveMutes', map(mutedUsers, 'id')) + }) + }, + muteUser (store, id) { + return store.state.api.backendInteractor.setUserMute({ id, muted: true }) + .then((user) => store.commit('addNewUsers', [user])) + }, + unmuteUser (store, id) { + return store.state.api.backendInteractor.setUserMute({ id, muted: false }) + .then((user) => store.commit('addNewUsers', [user])) + }, addFriends ({ rootState, commit }, fetchBy) { return new Promise((resolve, reject) => { const user = rootState.users.usersObject[fetchBy] @@ -300,10 +320,7 @@ const users = { store.dispatch('startFetching', { timeline: 'friends' }) // Get user mutes and follower info - store.rootState.api.backendInteractor.fetchMutes().then((mutedUsers) => { - each(mutedUsers, (user) => { user.muted = true }) - store.commit('addNewUsers', mutedUsers) - }) + store.dispatch('fetchMutes') // Fetch our friends store.rootState.api.backendInteractor.fetchFriends({ id: user.id }) diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js index 0e1be61e..49c83811 100644 --- a/src/services/entity_normalizer/entity_normalizer.service.js +++ b/src/services/entity_normalizer/entity_normalizer.service.js @@ -121,6 +121,7 @@ export const parseUser = (data) => { output.follow_request_count = data.pleroma.follow_request_count } output.blockIds = [] + output.muteIds = [] return output } -- cgit v1.2.3-70-g09d2 From f81b82b4714643ba396b69ca54b97259a36a6b9f Mon Sep 17 00:00:00 2001 From: taehoon Date: Wed, 13 Feb 2019 22:52:57 -0500 Subject: Use hoc definitions to be factor of factory --- src/components/user_settings/user_settings.js | 26 ++++++++++++------------- src/hocs/with_list/with_list.js | 8 ++++---- src/hocs/with_load_more/with_load_more.js | 6 +++--- src/hocs/with_subscription/with_subscription.js | 6 +++--- 4 files changed, 22 insertions(+), 24 deletions(-) (limited to 'src/components/user_settings') diff --git a/src/components/user_settings/user_settings.js b/src/components/user_settings/user_settings.js index 8114d5e2..21023841 100644 --- a/src/components/user_settings/user_settings.js +++ b/src/components/user_settings/user_settings.js @@ -10,21 +10,19 @@ import MuteCard from '../mute_card/mute_card.vue' import withSubscription from '../../hocs/with_subscription/with_subscription' import withList from '../../hocs/with_list/with_list' -const BlockList = withList(BlockCard, userId => ({ userId })) -const BlockListWithSubscription = withSubscription( - BlockList, - (props, $store) => $store.dispatch('fetchBlocks'), - (props, $store) => get($store.state.users.currentUser, 'blockIds', []), - 'entries' -) +const BlockList = withList({ getEntryProps: userId => ({ userId }) })(BlockCard) +const BlockListWithSubscription = withSubscription({ + fetch: (props, $store) => $store.dispatch('fetchBlocks'), + select: (props, $store) => get($store.state.users.currentUser, 'blockIds', []), + contentPropName: 'entries' +})(BlockList) -const MuteList = withList(MuteCard, userId => ({ userId })) -const MuteListWithSubscription = withSubscription( - MuteList, - (props, $store) => $store.dispatch('fetchMutes'), - (props, $store) => get($store.state.users.currentUser, 'muteIds', []), - 'entries' -) +const MuteList = withList({ getEntryProps: userId => ({ userId }) })(MuteCard) +const MuteListWithSubscription = withSubscription({ + fetch: (props, $store) => $store.dispatch('fetchMutes'), + select: (props, $store) => get($store.state.users.currentUser, 'muteIds', []), + contentPropName: 'entries' +})(MuteList) const UserSettings = { data () { diff --git a/src/hocs/with_list/with_list.js b/src/hocs/with_list/with_list.js index 5ec37a2b..c31cdcb1 100644 --- a/src/hocs/with_list/with_list.js +++ b/src/hocs/with_list/with_list.js @@ -4,8 +4,8 @@ import map from 'lodash/map' const defaultEntryPropsGetter = entry => ({ entry }) const defaultKeyGetter = entry => entry.id -const withList = (Component, getEntryProps = defaultEntryPropsGetter, getKey = defaultKeyGetter) => { - return Vue.component('withList', { +const withList = ({ getEntryProps = defaultEntryPropsGetter, getKey = defaultKeyGetter }) => (ItemComponent) => ( + Vue.component('withList', { render (createElement) { return (
@@ -18,13 +18,13 @@ const withList = (Component, getEntryProps = defaultEntryPropsGetter, getKey = d }, on: this.$props.entryListeners } - return + return })}
) }, props: ['entries', 'entryProps', 'entryListeners'] }) -} +) export default withList diff --git a/src/hocs/with_load_more/with_load_more.js b/src/hocs/with_load_more/with_load_more.js index 8877f8d3..28c741e3 100644 --- a/src/hocs/with_load_more/with_load_more.js +++ b/src/hocs/with_load_more/with_load_more.js @@ -3,8 +3,8 @@ import filter from 'lodash/filter' import isEmpty from 'lodash/isEmpty' import './with_load_more.scss' -const withLoadMore = (Component, fetch, select, entriesPropName = 'entries') => { - const originalProps = Component.props || [] +const withLoadMore = ({ fetch, select, entriesPropName = 'entries' }) => (WrappedComponent) => { + const originalProps = WrappedComponent.props || [] const props = filter(originalProps, v => v !== 'entries') return Vue.component('withLoadMore', { @@ -18,7 +18,7 @@ const withLoadMore = (Component, fetch, select, entriesPropName = 'entries') => } return (
- + -- cgit v1.2.3-70-g09d2 From 22851a3a967cc5364a95c71bda48eccc3808bf41 Mon Sep 17 00:00:00 2001 From: taehoon Date: Thu, 21 Feb 2019 20:15:51 -0500 Subject: Remove needless code --- src/components/user_settings/user_settings.vue | 6 ------ 1 file changed, 6 deletions(-) (limited to 'src/components/user_settings') diff --git a/src/components/user_settings/user_settings.vue b/src/components/user_settings/user_settings.vue index 5c272114..983cbda0 100644 --- a/src/components/user_settings/user_settings.vue +++ b/src/components/user_settings/user_settings.vue @@ -168,12 +168,6 @@
- - -- cgit v1.2.3-70-g09d2 From 2c7406d9a8d8e961b99286f317c6ed0a48427853 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Tue, 12 Feb 2019 21:53:59 +0300 Subject: Add OAuth Tokens management to settings --- src/components/user_settings/user_settings.js | 24 +++++++++++++++ src/components/user_settings/user_settings.vue | 36 ++++++++++++++++++++++ src/i18n/ar.json | 5 +++ src/i18n/ca.json | 5 +++ src/i18n/de.json | 5 +++ src/i18n/en.json | 5 +++ src/i18n/es.json | 5 +++ src/i18n/fi.json | 5 +++ src/i18n/fr.json | 5 +++ src/i18n/ga.json | 5 +++ src/i18n/he.json | 5 +++ src/i18n/it.json | 5 +++ src/i18n/ja.json | 5 +++ src/i18n/ko.json | 5 +++ src/i18n/nb.json | 5 +++ src/i18n/nl.json | 5 +++ src/i18n/oc.json | 1 + src/i18n/pl.json | 5 +++ src/i18n/ru.json | 5 +++ src/i18n/zh.json | 5 +++ src/main.js | 4 ++- src/modules/oauth_tokens.js | 26 ++++++++++++++++ src/services/api/api.service.js | 19 ++++++++++++ .../backend_interactor_service.js | 4 +++ test/unit/specs/modules/users.spec.js | 10 ++++++ 25 files changed, 208 insertions(+), 1 deletion(-) create mode 100644 src/modules/oauth_tokens.js (limited to 'src/components/user_settings') diff --git a/src/components/user_settings/user_settings.js b/src/components/user_settings/user_settings.js index 06e72112..c7dab754 100644 --- a/src/components/user_settings/user_settings.js +++ b/src/components/user_settings/user_settings.js @@ -1,6 +1,10 @@ +<<<<<<< HEAD import { compose } from 'vue-compose' import unescape from 'lodash/unescape' import get from 'lodash/get' +======= +import { unescape, truncate } from 'lodash' +>>>>>>> Add OAuth Tokens management to settings import TabSwitcher from '../tab_switcher/tab_switcher.js' import ImageCropper from '../image_cropper/image_cropper.vue' @@ -62,6 +66,9 @@ const UserSettings = { activeTab: 'profile' } }, + created () { + this.$store.dispatch('fetchTokens') + }, components: { StyleSwitcher, TabSwitcher, @@ -87,8 +94,20 @@ const UserSettings = { direct: { selected: this.newDefaultScope === 'direct' } } }, +<<<<<<< HEAD currentSaveStateNotice () { return this.$store.state.interface.settings.currentSaveStateNotice +======= + oauthTokens () { + return this.$store.state.oauthTokens.tokens.map(oauthToken => { + return { + id: oauthToken.id, + token: truncate(oauthToken.token, { length: 15 }), + refreshToken: truncate(oauthToken.refresh_token, { length: 15 }), + validUntil: new Date(oauthToken.valid_until).toLocaleDateString() + } + }) +>>>>>>> Add OAuth Tokens management to settings } }, methods: { @@ -308,6 +327,11 @@ const UserSettings = { logout () { this.$store.dispatch('logout') this.$router.replace('/') + }, + revokeToken (id) { + if(confirm('Are you sure?')) { + this.$store.dispatch('revokeToken', id) + } } } } diff --git a/src/components/user_settings/user_settings.vue b/src/components/user_settings/user_settings.vue index 983cbda0..ac75ad86 100644 --- a/src/components/user_settings/user_settings.vue +++ b/src/components/user_settings/user_settings.vue @@ -121,6 +121,30 @@

{{changePasswordError}}

+
+

{{$t('settings.oauth_tokens')}}

+ + + + + + + + + + + + + + + + + +
TokenRefresh TokenValid Until
{{oauthToken.token}}{{oauthToken.refreshToken}}{{oauthToken.validUntil}} + +
+
+

{{$t('settings.delete_account')}}

{{$t('settings.delete_account_description')}}

@@ -213,5 +237,17 @@ border-radius: $fallback--avatarRadius; border-radius: var(--avatarRadius, $fallback--avatarRadius); } + + .oauth-tokens { + width: 100%; + + th { + text-align: left; + } + + .actions { + text-align: right; + } + } } diff --git a/src/i18n/ar.json b/src/i18n/ar.json index ac7d0f1a..242dab78 100644 --- a/src/i18n/ar.json +++ b/src/i18n/ar.json @@ -134,6 +134,11 @@ "notification_visibility_mentions": "الإشارات", "notification_visibility_repeats": "", "nsfw_clickthrough": "", + "oauth_tokens": "رموز OAuth", + "token": "رمز", + "refresh_token": "رمز التحديث", + "valid_until": "صالح حتى", + "revoke_token": "سحب", "panelRadius": "", "pause_on_unfocused": "", "presets": "النماذج", diff --git a/src/i18n/ca.json b/src/i18n/ca.json index fa517e22..d2f285df 100644 --- a/src/i18n/ca.json +++ b/src/i18n/ca.json @@ -132,6 +132,11 @@ "notification_visibility_repeats": "Republica una entrada meva", "no_rich_text_description": "Neteja el formatat de text de totes les entrades", "nsfw_clickthrough": "Amaga el contingut NSFW darrer d'una imatge clicable", + "oauth_tokens": "Llistats OAuth", + "token": "Token", + "refresh_token": "Actualitza el token", + "valid_until": "Vàlid fins", + "revoke_token": "Revocar", "panelRadius": "Panells", "pause_on_unfocused": "Pausa la reproducció en continu quan la pestanya perdi el focus", "presets": "Temes", diff --git a/src/i18n/de.json b/src/i18n/de.json index d0bfba38..07d44348 100644 --- a/src/i18n/de.json +++ b/src/i18n/de.json @@ -159,6 +159,11 @@ "hide_follows_description": "Zeige nicht, wem ich folge", "hide_followers_description": "Zeige nicht, wer mir folgt", "nsfw_clickthrough": "Aktiviere ausblendbares Overlay für Anhänge, die als NSFW markiert sind", + "oauth_tokens": "OAuth-Token", + "token": "Zeichen", + "refresh_token": "Token aktualisieren", + "valid_until": "Gültig bis", + "revoke_token": "Widerrufen", "panelRadius": "Panel", "pause_on_unfocused": "Streaming pausieren, wenn das Tab nicht fokussiert ist", "presets": "Voreinstellungen", diff --git a/src/i18n/en.json b/src/i18n/en.json index 8e837d2f..0aeb70ab 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -189,6 +189,11 @@ "show_admin_badge": "Show Admin badge in my profile", "show_moderator_badge": "Show Moderator badge in my profile", "nsfw_clickthrough": "Enable clickthrough NSFW attachment hiding", + "oauth_tokens": "OAuth tokens", + "token": "Token", + "refresh_token": "Refresh Token", + "valid_until": "Valid Until", + "revoke_token": "Revoke", "panelRadius": "Panels", "pause_on_unfocused": "Pause streaming when tab is not focused", "presets": "Presets", diff --git a/src/i18n/es.json b/src/i18n/es.json index d14e7a31..167e8c42 100644 --- a/src/i18n/es.json +++ b/src/i18n/es.json @@ -171,6 +171,11 @@ "show_admin_badge": "Mostrar la placa de administrador en mi perfil", "show_moderator_badge": "Mostrar la placa de moderador en mi perfil", "nsfw_clickthrough": "Activar el clic para ocultar los adjuntos NSFW", + "oauth_tokens": "Tokens de OAuth", + "token": "Token", + "refresh_token": "Actualizar el token", + "valid_until": "Válido hasta", + "revoke_token": "Revocar", "panelRadius": "Paneles", "pause_on_unfocused": "Parar la transmisión cuando no estés en foco.", "presets": "Por defecto", diff --git a/src/i18n/fi.json b/src/i18n/fi.json index a8259ca8..c7a25fe1 100644 --- a/src/i18n/fi.json +++ b/src/i18n/fi.json @@ -166,6 +166,11 @@ "no_rich_text_description": "Älä näytä tekstin muotoilua.", "hide_network_description": "Älä näytä seurauksiani tai seuraajiani", "nsfw_clickthrough": "Piilota NSFW liitteet klikkauksen taakse", + "oauth_tokens": "OAuth-merkit", + "token": "Token", + "refresh_token": "Päivitä token", + "valid_until": "Voimassa asti", + "revoke_token": "Peruuttaa", "panelRadius": "Ruudut", "pause_on_unfocused": "Pysäytä automaattinen viestien näyttö välilehden ollessa pois fokuksesta", "presets": "Valmiit teemat", diff --git a/src/i18n/fr.json b/src/i18n/fr.json index 129b7d7c..1209556a 100644 --- a/src/i18n/fr.json +++ b/src/i18n/fr.json @@ -137,6 +137,11 @@ "notification_visibility_mentions": "Mentionnés", "notification_visibility_repeats": "Partages", "nsfw_clickthrough": "Masquer les images marquées comme contenu adulte ou sensible", + "oauth_tokens": "Jetons OAuth", + "token": "Jeton", + "refresh_token": "Refresh Token", + "valid_until": "Valable jusque", + "revoke_token": "Révoquer", "panelRadius": "Fenêtres", "pause_on_unfocused": "Suspendre le streaming lorsque l'onglet n'est pas centré", "presets": "Thèmes prédéfinis", diff --git a/src/i18n/ga.json b/src/i18n/ga.json index 64461202..5be9297a 100644 --- a/src/i18n/ga.json +++ b/src/i18n/ga.json @@ -134,6 +134,11 @@ "notification_visibility_repeats": "Atphostáil", "no_rich_text_description": "Bain formáidiú téacs saibhir ó gach post", "nsfw_clickthrough": "Cumasaigh an ceangaltán NSFW cliceáil ar an gcnaipe", + "oauth_tokens": "Tocanna OAuth", + "token": "Token", + "refresh_token": "Athnuachan Comórtas", + "valid_until": "Bailí Go dtí", + "revoke_token": "Athghairm", "panelRadius": "Painéil", "pause_on_unfocused": "Sruthú ar sos nuair a bhíonn an fócas caillte", "presets": "Réamhshocruithe", diff --git a/src/i18n/he.json b/src/i18n/he.json index 99ae9551..213e6170 100644 --- a/src/i18n/he.json +++ b/src/i18n/he.json @@ -129,6 +129,11 @@ "notification_visibility_mentions": "אזכורים", "notification_visibility_repeats": "חזרות", "nsfw_clickthrough": "החל החבאת צירופים לא בטוחים לצפיה בעת עבודה בעזרת לחיצת עכבר", + "oauth_tokens": "אסימוני OAuth", + "token": "אסימון", + "refresh_token": "רענון האסימון", + "valid_until": "בתוקף עד", + "revoke_token": "בטל", "panelRadius": "פאנלים", "pause_on_unfocused": "השהה זרימת הודעות כשהחלון לא בפוקוס", "presets": "ערכים קבועים מראש", diff --git a/src/i18n/it.json b/src/i18n/it.json index 8f69e7c1..385d21aa 100644 --- a/src/i18n/it.json +++ b/src/i18n/it.json @@ -93,6 +93,11 @@ "notification_visibility_mentions": "Menzioni", "notification_visibility_repeats": "Condivisioni", "no_rich_text_description": "Togli la formattazione del testo da tutti i post", + "oauth_tokens": "Token OAuth", + "token": "Token", + "refresh_token": "Aggiorna token", + "valid_until": "Valido fino a", + "revoke_token": "Revocare", "panelRadius": "Pannelli", "pause_on_unfocused": "Metti in pausa l'aggiornamento continuo quando la scheda non è in primo piano", "presets": "Valori predefiniti", diff --git a/src/i18n/ja.json b/src/i18n/ja.json index 7849aa20..b51fa7fd 100644 --- a/src/i18n/ja.json +++ b/src/i18n/ja.json @@ -171,6 +171,11 @@ "show_admin_badge": "アドミンのしるしをみる", "show_moderator_badge": "モデレーターのしるしをみる", "nsfw_clickthrough": "NSFWなファイルをかくす", + "oauth_tokens": "OAuthトークン", + "token": "トークン", + "refresh_token": "トークンを更新", + "valid_until": "まで有効", + "revoke_token": "取り消す", "panelRadius": "パネル", "pause_on_unfocused": "タブにフォーカスがないときストリーミングをとめる", "presets": "プリセット", diff --git a/src/i18n/ko.json b/src/i18n/ko.json index f9e4dfa3..336e464f 100644 --- a/src/i18n/ko.json +++ b/src/i18n/ko.json @@ -159,6 +159,11 @@ "hide_follows_description": "내가 팔로우하는 사람을 표시하지 않음", "hide_followers_description": "나를 따르는 사람을 보여주지 마라.", "nsfw_clickthrough": "NSFW 이미지 \"클릭해서 보이기\"를 활성화", + "oauth_tokens": "OAuth 토큰", + "token": "토큰", + "refresh_token": "토큰 새로 고침", + "valid_until": "까지 유효하다", + "revoke_token": "취소", "panelRadius": "패널", "pause_on_unfocused": "탭이 활성 상태가 아닐 때 스트리밍 멈추기", "presets": "프리셋", diff --git a/src/i18n/nb.json b/src/i18n/nb.json index 0f4dca58..39e054f7 100644 --- a/src/i18n/nb.json +++ b/src/i18n/nb.json @@ -132,6 +132,11 @@ "notification_visibility_repeats": "Gjentakelser", "no_rich_text_description": "Fjern all formatering fra statuser", "nsfw_clickthrough": "Krev trykk for å vise statuser som kan være upassende", + "oauth_tokens": "OAuth Tokens", + "token": "Pollett", + "refresh_token": "Refresh Token", + "valid_until": "Gyldig til", + "revoke_token": "Tilbakekall", "panelRadius": "Panel", "pause_on_unfocused": "Stopp henting av poster når vinduet ikke er i fokus", "presets": "Forhåndsdefinerte tema", diff --git a/src/i18n/nl.json b/src/i18n/nl.json index bb388a90..799e22b9 100644 --- a/src/i18n/nl.json +++ b/src/i18n/nl.json @@ -159,6 +159,11 @@ "no_rich_text_description": "Strip rich text formattering van alle posts", "hide_network_description": "Toon niet wie mij volgt en wie ik volg.", "nsfw_clickthrough": "Schakel doorklikbaar verbergen van NSFW bijlages in", + "oauth_tokens": "OAuth-tokens", + "token": "Token", + "refresh_token": "Token vernieuwen", + "valid_until": "Geldig tot", + "revoke_token": "Intrekken", "panelRadius": "Panelen", "pause_on_unfocused": "Pauzeer streamen wanneer de tab niet gefocused is", "presets": "Presets", diff --git a/src/i18n/oc.json b/src/i18n/oc.json index 2ce666c6..db66bb98 100644 --- a/src/i18n/oc.json +++ b/src/i18n/oc.json @@ -142,6 +142,7 @@ "notification_visibility_mentions": "Mencions", "notification_visibility_repeats": "Repeticions", "no_rich_text_description": "Netejar lo format tèxte de totas las publicacions", + "oauth_tokens": "Llistats OAuth", "pause_on_unfocused": "Pausar la difusion quand l’onglet es pas seleccionat", "profile_tab": "Perfil", "replies_in_timeline": "Responsas del flux", diff --git a/src/i18n/pl.json b/src/i18n/pl.json index a3952d4f..2e1d7488 100644 --- a/src/i18n/pl.json +++ b/src/i18n/pl.json @@ -86,6 +86,11 @@ "name_bio": "Imię i bio", "new_password": "Nowe hasło", "nsfw_clickthrough": "Włącz domyślne ukrywanie załączników o treści nieprzyzwoitej (NSFW)", + "oauth_tokens": "Tokeny OAuth", + "token": "Token", + "refresh_token": "Odśwież token", + "valid_until": "Ważne do", + "revoke_token": "Odwołać", "panelRadius": "Panele", "presets": "Gotowe motywy", "profile_background": "Tło profilu", diff --git a/src/i18n/ru.json b/src/i18n/ru.json index 4b0bd4b4..6799cc96 100644 --- a/src/i18n/ru.json +++ b/src/i18n/ru.json @@ -132,6 +132,11 @@ "show_admin_badge": "Показывать значок администратора в моем профиле", "show_moderator_badge": "Показывать значок модератора в моем профиле", "nsfw_clickthrough": "Включить скрытие NSFW вложений", + "oauth_tokens": "OAuth токены", + "token": "Токен", + "refresh_token": "Рефреш токен", + "valid_until": "Годен до", + "revoke_token": "Удалить", "panelRadius": "Панели", "pause_on_unfocused": "Приостановить загрузку когда вкладка не в фокусе", "presets": "Пресеты", diff --git a/src/i18n/zh.json b/src/i18n/zh.json index 7ad23c57..089a98e2 100644 --- a/src/i18n/zh.json +++ b/src/i18n/zh.json @@ -134,6 +134,11 @@ "notification_visibility_repeats": "转发", "no_rich_text_description": "不显示富文本格式", "nsfw_clickthrough": "将不和谐附件隐藏,点击才能打开", + "oauth_tokens": "OAuth令牌", + "token": "代币", + "refresh_token": "刷新令牌", + "valid_until": "有效期至", + "revoke_token": "撤消", "panelRadius": "面板", "pause_on_unfocused": "在离开页面时暂停时间线推送", "presets": "预置", diff --git a/src/main.js b/src/main.js index adeb0550..2844194e 100644 --- a/src/main.js +++ b/src/main.js @@ -11,6 +11,7 @@ import configModule from './modules/config.js' import chatModule from './modules/chat.js' import oauthModule from './modules/oauth.js' import mediaViewerModule from './modules/media_viewer.js' +import oauthTokensModule from './modules/oauth_tokens.js' import VueTimeago from 'vue-timeago' import VueI18n from 'vue-i18n' @@ -64,7 +65,8 @@ createPersistedState(persistedStateOptions).then((persistedState) => { config: configModule, chat: chatModule, oauth: oauthModule, - mediaViewer: mediaViewerModule + mediaViewer: mediaViewerModule, + oauthTokens: oauthTokensModule }, plugins: [persistedState, pushNotifications], strict: false // Socket modifies itself, let's ignore this for now. diff --git a/src/modules/oauth_tokens.js b/src/modules/oauth_tokens.js new file mode 100644 index 00000000..00ac1431 --- /dev/null +++ b/src/modules/oauth_tokens.js @@ -0,0 +1,26 @@ +const oauthTokens = { + state: { + tokens: [] + }, + actions: { + fetchTokens ({rootState, commit}) { + rootState.api.backendInteractor.fetchOAuthTokens().then((tokens) => { + commit('swapTokens', tokens) + }) + }, + revokeToken ({rootState, commit, state}, id) { + rootState.api.backendInteractor.revokeOAuthToken(id).then((response) => { + if (response.status === 201) { + commit('swapTokens', state.tokens.filter(token => token.id !== id)) + } + }) + } + }, + mutations: { + swapTokens (state, tokens) { + state.tokens = tokens + } + } +} + +export default oauthTokens diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index 3d2e8823..7b04343d 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -531,6 +531,23 @@ const fetchBlocks = ({page, credentials}) => { }) } +const fetchOAuthTokens = ({credentials}) => { + const url = '/api/oauth_tokens.json' + + return fetch(url, { + headers: authHeaders(credentials) + }).then((data) => data.json()) +} + +const revokeOAuthToken = ({id, credentials}) => { + const url = `/api/oauth_tokens/${id}` + + return fetch(url, { + headers: authHeaders(credentials), + method: 'DELETE' + }) +} + const suggestions = ({credentials}) => { return fetch(SUGGESTIONS_URL, { headers: authHeaders(credentials) @@ -573,6 +590,8 @@ const apiService = { setUserMute, fetchMutes, fetchBlocks, + fetchOAuthTokens, + revokeOAuthToken, register, getCaptcha, updateAvatar, diff --git a/src/services/backend_interactor_service/backend_interactor_service.js b/src/services/backend_interactor_service/backend_interactor_service.js index 43c914d9..2278cd45 100644 --- a/src/services/backend_interactor_service/backend_interactor_service.js +++ b/src/services/backend_interactor_service/backend_interactor_service.js @@ -65,6 +65,8 @@ const backendInteractorService = (credentials) => { const fetchMutes = () => apiService.fetchMutes({credentials}) const fetchBlocks = (params) => apiService.fetchBlocks({credentials, ...params}) const fetchFollowRequests = () => apiService.fetchFollowRequests({credentials}) + const fetchOAuthTokens = () => apiService.fetchOAuthTokens({credentials}) + const revokeOAuthToken = (id) => apiService.revokeOAuthToken({id, credentials}) const getCaptcha = () => apiService.getCaptcha() const register = (params) => apiService.register(params) @@ -96,6 +98,8 @@ const backendInteractorService = (credentials) => { setUserMute, fetchMutes, fetchBlocks, + fetchOAuthTokens, + revokeOAuthToken, register, getCaptcha, updateAvatar, diff --git a/test/unit/specs/modules/users.spec.js b/test/unit/specs/modules/users.spec.js index 4d49ee24..96ae845b 100644 --- a/test/unit/specs/modules/users.spec.js +++ b/test/unit/specs/modules/users.spec.js @@ -32,6 +32,16 @@ describe('The users module', () => { expect(user.muted).to.eql(false) }) + + it('sets oauth tokens', () => { + const state = cloneDeep(defaultState) + const tokens = [{ id: 1, token: 'bar' }] + + mutations.addOAuthTokens(state, tokens) + + expect(state.oauthTokens).to.have.length(1) + expect(state.oauthTokens).to.eql(tokens) + }) }) describe('getUserByName', () => { -- cgit v1.2.3-70-g09d2 From c10a15386ab4b58e8537af5b6289f59e902bb489 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Tue, 12 Feb 2019 21:56:43 +0300 Subject: Code style --- src/components/user_settings/user_settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/components/user_settings') diff --git a/src/components/user_settings/user_settings.js b/src/components/user_settings/user_settings.js index c7dab754..5e972d82 100644 --- a/src/components/user_settings/user_settings.js +++ b/src/components/user_settings/user_settings.js @@ -329,7 +329,7 @@ const UserSettings = { this.$router.replace('/') }, revokeToken (id) { - if(confirm('Are you sure?')) { + if (window.confirm('Are you sure?')) { this.$store.dispatch('revokeToken', id) } } -- cgit v1.2.3-70-g09d2 From afbe524a2e7fa7002c4b1f5883e08b2d135a2eda Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Tue, 12 Feb 2019 22:07:10 +0300 Subject: use translations --- src/components/user_settings/user_settings.vue | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src/components/user_settings') diff --git a/src/components/user_settings/user_settings.vue b/src/components/user_settings/user_settings.vue index ac75ad86..116c1335 100644 --- a/src/components/user_settings/user_settings.vue +++ b/src/components/user_settings/user_settings.vue @@ -126,9 +126,9 @@ - - - + + + @@ -138,7 +138,9 @@ -- cgit v1.2.3-70-g09d2 From c71f411ad6593a496a041505f8a6642a4ae55eea Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Mon, 18 Feb 2019 00:01:18 +0300 Subject: Show only "app_name" and "valid_until" (OAuth tokens table) --- src/components/user_settings/user_settings.js | 12 ++---------- src/components/user_settings/user_settings.vue | 6 ++---- src/i18n/en.json | 1 + 3 files changed, 5 insertions(+), 14 deletions(-) (limited to 'src/components/user_settings') diff --git a/src/components/user_settings/user_settings.js b/src/components/user_settings/user_settings.js index 5e972d82..e7a961f1 100644 --- a/src/components/user_settings/user_settings.js +++ b/src/components/user_settings/user_settings.js @@ -1,11 +1,6 @@ -<<<<<<< HEAD import { compose } from 'vue-compose' import unescape from 'lodash/unescape' import get from 'lodash/get' -======= -import { unescape, truncate } from 'lodash' ->>>>>>> Add OAuth Tokens management to settings - import TabSwitcher from '../tab_switcher/tab_switcher.js' import ImageCropper from '../image_cropper/image_cropper.vue' import StyleSwitcher from '../style_switcher/style_switcher.vue' @@ -94,20 +89,17 @@ const UserSettings = { direct: { selected: this.newDefaultScope === 'direct' } } }, -<<<<<<< HEAD currentSaveStateNotice () { return this.$store.state.interface.settings.currentSaveStateNotice -======= + }, oauthTokens () { return this.$store.state.oauthTokens.tokens.map(oauthToken => { return { id: oauthToken.id, - token: truncate(oauthToken.token, { length: 15 }), - refreshToken: truncate(oauthToken.refresh_token, { length: 15 }), + appName: oauthToken.app_name, validUntil: new Date(oauthToken.valid_until).toLocaleDateString() } }) ->>>>>>> Add OAuth Tokens management to settings } }, methods: { diff --git a/src/components/user_settings/user_settings.vue b/src/components/user_settings/user_settings.vue index 116c1335..a1123638 100644 --- a/src/components/user_settings/user_settings.vue +++ b/src/components/user_settings/user_settings.vue @@ -126,16 +126,14 @@
TokenRefresh TokenValid Until{{$t('settings.token')}}{{$t('settings.refresh_token')}}{{$t('settings.valid_until')}}
{{oauthToken.refreshToken}} {{oauthToken.validUntil}} - +
- - + - - +
{{$t('settings.token')}}{{$t('settings.refresh_token')}}{{$t('settings.app_name')}} {{$t('settings.valid_until')}}
{{oauthToken.token}}{{oauthToken.refreshToken}}{{oauthToken.appName}} {{oauthToken.validUntil}}