diff --git a/CHANGELOG.md b/CHANGELOG.md index f4733791995a7f6b1fb7bac31bd449c7717c46ee..00ad896e0b47dc07a2f4700c4c1eeb18c02dcdf8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Actions in users module (ActivateUsers, AddRight, DeactivateUsers, DeleteRight, DeleteUsers) now accept an array of users instead of one user ### Added + - Optimistic update for actions in users module and fetching users after api function finished its execution +- Relay management ## [1.2.0] - 2019-09-27 diff --git a/src/api/relays.js b/src/api/relays.js new file mode 100644 index 0000000000000000000000000000000000000000..3be0188db3b15f0d802950a6ff313e6140d0e6ef --- /dev/null +++ b/src/api/relays.js @@ -0,0 +1,34 @@ +import request from '@/utils/request' +import { getToken } from '@/utils/auth' +import { baseName } from './utils' + +export async function fetchRelays(authHost, token) { + return await request({ + baseURL: baseName(authHost), + url: '/api/pleroma/admin/relay', + method: 'get', + headers: authHeaders(token) + }) +} + +export async function addRelay(relay, authHost, token) { + return await request({ + baseURL: baseName(authHost), + url: '/api/pleroma/admin/relay', + method: 'post', + headers: authHeaders(token), + data: { relay_url: relay } + }) +} + +export async function deleteRelay(relay, authHost, token) { + return await request({ + baseURL: baseName(authHost), + url: '/api/pleroma/admin/relay', + method: 'delete', + headers: authHeaders(token), + data: { relay_url: `https://${relay}/actor` } + }) +} + +const authHeaders = (token) => token ? { 'Authorization': `Bearer ${getToken()}` } : {} diff --git a/src/lang/en.js b/src/lang/en.js index 46b4b6417131859b6b8eda254ad1bf905bccd851..8575144aa6cbed6b5413ac7878d75faf37c7c7fd 100644 --- a/src/lang/en.js +++ b/src/lang/en.js @@ -312,6 +312,10 @@ export default { rateLimiters: 'Rate limiters', database: 'Database', other: 'Other', + relays: 'Relays', + follow: 'Follow', + followRelay: 'Follow new relay', + instanceUrl: 'Instance URL', success: 'Settings changed successfully!', emojiPacks: 'Emoji packs', reloadEmoji: 'Reload emoji', diff --git a/src/store/index.js b/src/store/index.js index 668b4d4431ce912421e77ea91962be94576a3e96..c71fca877b61e34f3bca306d5c28c4fe3b947875 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -5,6 +5,7 @@ import errorLog from './modules/errorLog' import moderationLog from './modules/moderationLog' import invites from './modules/invites' import permission from './modules/permission' +import relays from './modules/relays' import reports from './modules/reports' import settings from './modules/settings' import tagsView from './modules/tagsView' @@ -23,6 +24,7 @@ const store = new Vuex.Store({ moderationLog, invites, permission, + relays, reports, settings, tagsView, diff --git a/src/store/modules/relays.js b/src/store/modules/relays.js new file mode 100644 index 0000000000000000000000000000000000000000..6353569e2ebc5eac98e2d8df0b9a5319e149e726 --- /dev/null +++ b/src/store/modules/relays.js @@ -0,0 +1,44 @@ +import { fetchRelays, addRelay, deleteRelay } from '@/api/relays' + +const relays = { + state: { + fetchedRelays: [], + loading: true + }, + mutations: { + SET_LOADING: (state, loading) => { + state.loading = loading + }, + SET_RELAYS: (state, relays) => { + state.fetchedRelays = relays + }, + ADD_RELAY: (state, relay) => { + state.fetchedRelays = [...state.fetchedRelays, relay] + }, + DELETE_RELAY: (state, relay) => { + state.fetchedRelays = state.fetchedRelays.filter(fetchedRelay => fetchedRelay !== relay) + } + }, + actions: { + async FetchRelays({ commit, getters }) { + commit('SET_LOADING', true) + + const response = await fetchRelays(getters.authHost, getters.token) + + commit('SET_RELAYS', response.data.relays) + commit('SET_LOADING', false) + }, + async AddRelay({ commit, getters }, relay) { + commit('ADD_RELAY', relay) + + await addRelay(relay, getters.authHost, getters.token) + }, + async DeleteRelay({ commit, getters }, relay) { + commit('DELETE_RELAY', relay) + + await deleteRelay(relay, getters.authHost, getters.token) + } + } +} + +export default relays diff --git a/src/views/settings/components/Relays.vue b/src/views/settings/components/Relays.vue new file mode 100644 index 0000000000000000000000000000000000000000..ef9264b4acc10db9535cba900f26b9de82bc97a4 --- /dev/null +++ b/src/views/settings/components/Relays.vue @@ -0,0 +1,79 @@ +<template> + <div v-if="!loading"> + <el-row :gutter="5"> + <el-col :span="8"> + <el-input v-model="newRelay" :placeholder="$t('settings.followRelay')" @keyup.enter.native="followRelay"/> + </el-col> + <el-col :span="8"> + <el-button type="primary" @click.native="followRelay">{{ $t('settings.follow') }}</el-button> + </el-col> + </el-row> + <el-table :data="relaysTable"> + <el-table-column + :label="$t('settings.instanceUrl')" + prop="instance"/> + <el-table-column fixed="right" width="120"> + <template slot-scope="scope"> + <el-button + type="text" + size="small" + @click.native="deleteRelay(scope.row.instance)"> + {{ $t('table.delete') }} + </el-button> + </template> + </el-table-column> + </el-table> + </div> +</template> + +<script> +export default { + name: 'Relays', + data() { + return { + newRelay: '' + } + }, + computed: { + relays() { + return this.$store.state.relays.fetchedRelays + }, + relaysTable() { + return this.relays.map(relay => { + return { instance: relay } + }) + }, + loading() { + return this.$store.state.relays.loading + } + }, + mounted() { + this.$store.dispatch('FetchRelays') + }, + methods: { + followRelay() { + try { + this.$store.dispatch('AddRelay', this.newRelay) + } catch (_e) { + return + } finally { + this.$store.dispatch('FetchRelays') + } + }, + deleteRelay(relay) { + try { + this.$store.dispatch('DeleteRelay', relay) + } catch (_e) { + return + } finally { + this.$store.dispatch('FetchRelays') + } + } + } +} +</script> + +<style rel='stylesheet/scss' lang='scss'> +@import '../styles/main'; +@include settings +</style> diff --git a/src/views/settings/components/index.js b/src/views/settings/components/index.js index 4e5b8e8ec06ab495bcb106d5ab7526d72b0b914c..040d67120287bb9ef5721d169498a4a163a1ddf0 100644 --- a/src/views/settings/components/index.js +++ b/src/views/settings/components/index.js @@ -17,5 +17,6 @@ export { default as Metadata } from './Metadata' export { default as Mrf } from './MRF' export { default as Other } from './Other' export { default as RateLimiters } from './RateLimiters' +export { default as Relays } from './Relays' export { default as Upload } from './Upload' export { default as WebPush } from './WebPush' diff --git a/src/views/settings/index.vue b/src/views/settings/index.vue index 5e0c482b3c4c1363ddef738f347853c85df18506..bc5afaad234940ceb4287e9d6268d8e25cd50f7c 100644 --- a/src/views/settings/index.vue +++ b/src/views/settings/index.vue @@ -59,6 +59,9 @@ <el-tab-pane :label="$t('settings.rateLimiters')"> <rate-limiters/> </el-tab-pane> + <el-tab-pane :label="$t('settings.relays')"> + <relays/> + </el-tab-pane> <el-tab-pane :label="$t('settings.upload')"> <upload/> </el-tab-pane> @@ -73,11 +76,11 @@ </template> <script> -import { ActivityPub, Authentication, AutoLinker, Captcha, Database, Endpoint, Esshd, Frontend, Gopher, Http, Instance, JobQueue, Logger, Mailer, MediaProxy, Metadata, Mrf, Other, RateLimiters, Upload, WebPush } from './components' +import { ActivityPub, Authentication, AutoLinker, Captcha, Database, Endpoint, Esshd, Frontend, Gopher, Http, Instance, JobQueue, Logger, Mailer, MediaProxy, Metadata, Mrf, Other, RateLimiters, Relays, Upload, WebPush } from './components' import EmojiPacks from '../emojiPacks/index' export default { - components: { ActivityPub, Authentication, AutoLinker, Captcha, Database, Endpoint, EmojiPacks, Esshd, Frontend, Gopher, Http, Instance, JobQueue, Logger, Mailer, MediaProxy, Metadata, Mrf, Other, RateLimiters, Upload, WebPush }, + components: { ActivityPub, Authentication, AutoLinker, Captcha, Database, Endpoint, EmojiPacks, Esshd, Frontend, Gopher, Http, Instance, JobQueue, Logger, Mailer, MediaProxy, Metadata, Mrf, Other, RateLimiters, Relays, Upload, WebPush }, computed: { isMobile() { return this.$store.state.app.device === 'mobile'