diff --git a/src/components/user_settings/user_settings.js b/src/components/user_settings/user_settings.js index fd20a6ad8240cd602eeae28758722aa69df7a230..25ee1f359ad51f4ed95d52c53097b00c3a90cccb 100644 --- a/src/components/user_settings/user_settings.js +++ b/src/components/user_settings/user_settings.js @@ -5,7 +5,10 @@ const UserSettings = { return { newname: this.$store.state.users.currentUser.name, newbio: this.$store.state.users.currentUser.description, - uploading: [ false, false, false ], + followList: null, + followImportError: false, + followsImported: false, + uploading: [ false, false, false, false ], previews: [ null, null, null ] } }, @@ -15,6 +18,9 @@ const UserSettings = { computed: { user () { return this.$store.state.users.currentUser + }, + pleromaBackend () { + return this.$store.state.config.pleromaBackend } }, methods: { @@ -117,6 +123,29 @@ const UserSettings = { } this.uploading[2] = false }) + }, + importFollows () { + this.uploading[3] = true + const followList = this.followList + this.$store.state.api.backendInteractor.followImport({params: followList}) + .then((status) => { + if (status) { + this.followsImported = true + } else { + this.followImportError = true + } + this.uploading[3] = false + }) + }, + followListChange () { + // eslint-disable-next-line no-undef + let formData = new FormData() + formData.append('list', this.$refs.followlist.files[0]) + this.followList = formData + }, + dismissImported () { + this.followsImported = false + this.followImportError = false } } } diff --git a/src/components/user_settings/user_settings.vue b/src/components/user_settings/user_settings.vue index 515fd253a1551e2adcab2203643d0d268e78e421..da78cdc2c8dbf42c920afcce144b2550975be3da 100644 --- a/src/components/user_settings/user_settings.vue +++ b/src/components/user_settings/user_settings.vue @@ -49,6 +49,23 @@ <i class="base09 icon-spin4 animate-spin uploading" v-if="uploading[2]"></i> <button class="btn btn-default base05 base02-background" v-else-if="previews[2]" @click="submitBg">{{$t('general.submit')}}</button> </div> + <div class="setting-item" v-if="pleromaBackend"> + <h3>{{$t('settings.follow_import')}}</h3> + <p>{{$t('settings.import_followers_from_a_csv_file')}}</p> + <form v-model="followImportForm"> + <input type="file" ref="followlist" v-on:change="followListChange"></input> + </form> + <i class="base09 icon-spin4 animate-spin uploading" v-if="uploading[3]"></i> + <button class="btn btn-default base05 base02-background" v-else @click="importFollows">{{$t('general.submit')}}</button> + <div v-if="followsImported"> + <i class="icon-cross" @click="dismissImported"></i> + <p>{{$t('settings.follows_imported')}}</p> + </div> + <div v-else-if="followImportError"> + <i class="icon-cross" @click="dismissImported"</i> + <p>{{$t('settings.follow_import_error')}}</p> + </div> + </div> </div> </div> </template> diff --git a/src/i18n/messages.js b/src/i18n/messages.js index 4c5be15165819843483b9e78af0067fb262a95b6..360f9eb8ab0dcf2dd14566ca1b33fac8bb9f8706 100644 --- a/src/i18n/messages.js +++ b/src/i18n/messages.js @@ -242,7 +242,11 @@ const en = { nsfw_clickthrough: 'Enable clickthrough NSFW attachment hiding', autoload: 'Enable automatic loading when scrolled to the bottom', streaming: 'Enable automatic streaming of new posts when scrolled to the top', - reply_link_preview: 'Enable reply-link preview on mouse hover' + reply_link_preview: 'Enable reply-link preview on mouse hover', + follow_import: 'Follow import', + import_followers_from_a_csv_file: 'Import followers from a csv file', + follows_imported: 'Follows imported! Processing them will take a while.', + follow_import_error: 'Error importing followers' }, notifications: { notifications: 'Notifications', diff --git a/src/main.js b/src/main.js index 1540c2185f34bba4bb01f2fe502ec802790daab4..2dd6aed17501e5dcd8964ab2a846b41814a3d490 100644 --- a/src/main.js +++ b/src/main.js @@ -137,8 +137,11 @@ window.fetch('/api/pleroma/emoji.json') return { shortcode: key, image_url: values[key] } }) store.dispatch('setOption', { name: 'emoji', value: emoji }) + store.dispatch('setOption', { name: 'pleromaBackend', value: true }) }, - (failure) => {} + (failure) => { + store.dispatch('setOption', { name: 'pleromaBackend', value: false }) + } ), (error) => console.log(error) ) diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index 5b078bc85a257c5991229d495646e43bf5e203d0..1f5b3ad2965b682977dbc0e8ee79ace427abda7d 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -29,6 +29,7 @@ const QVITTER_USER_TIMELINE_URL = '/api/qvitter/statuses/user_timeline.json' const BLOCKING_URL = '/api/blocks/create.json' const UNBLOCKING_URL = '/api/blocks/destroy.json' const USER_URL = '/api/users/show.json' +const FOLLOW_IMPORT_URL = '/api/pleroma/follow_import' import { each, map } from 'lodash' import 'whatwg-fetch' @@ -362,6 +363,15 @@ const uploadMedia = ({formData, credentials}) => { .then((text) => (new DOMParser()).parseFromString(text, 'application/xml')) } +const followImport = ({params, credentials}) => { + return fetch(FOLLOW_IMPORT_URL, { + body: params, + method: 'POST', + headers: authHeaders(credentials) + }) + .then((response) => response.ok) +} + const fetchMutes = ({credentials}) => { const url = '/api/qvitter/mutes.json' @@ -396,7 +406,8 @@ const apiService = { updateBg, updateProfile, updateBanner, - externalProfile + externalProfile, + followImport } export default apiService diff --git a/src/services/backend_interactor_service/backend_interactor_service.js b/src/services/backend_interactor_service/backend_interactor_service.js index ddaae3b229b5e08630170013786d4365268332b4..52b8286b56a45910a04912a70118a229a6107c67 100644 --- a/src/services/backend_interactor_service/backend_interactor_service.js +++ b/src/services/backend_interactor_service/backend_interactor_service.js @@ -59,6 +59,7 @@ const backendInteractorService = (credentials) => { const updateProfile = ({params}) => apiService.updateProfile({credentials, params}) const externalProfile = (profileUrl) => apiService.externalProfile({profileUrl, credentials}) + const followImport = ({params}) => apiService.followImport({params, credentials}) const backendInteractorServiceInstance = { fetchStatus, @@ -80,7 +81,8 @@ const backendInteractorService = (credentials) => { updateBg, updateBanner, updateProfile, - externalProfile + externalProfile, + followImport } return backendInteractorServiceInstance