From 2c7406d9a8d8e961b99286f317c6ed0a48427853 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Tue, 12 Feb 2019 21:53:59 +0300 Subject: [PATCH] Add OAuth Tokens management to settings --- src/components/user_settings/user_settings.js | 24 +++++++++++++ .../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 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', () => {