From aebe64829a389bd2e645934b8f9d18145c259254 Mon Sep 17 00:00:00 2001 From: Bulat Kurbanov Date: Sun, 12 Jan 2025 17:59:27 +0100 Subject: [PATCH] Update --- src/modules/web_app/frontend/index.css | 15 ++++- src/modules/web_app/frontend/index.html | 3 +- src/modules/web_app/frontend/index.js | 70 +++++++++++++++++++-- src/modules/web_app/serializers/streamer.py | 7 ++- src/modules/web_app/views/streamer.py | 27 +++++++- 5 files changed, 113 insertions(+), 9 deletions(-) diff --git a/src/modules/web_app/frontend/index.css b/src/modules/web_app/frontend/index.css index b0cb12c..5777259 100644 --- a/src/modules/web_app/frontend/index.css +++ b/src/modules/web_app/frontend/index.css @@ -1,4 +1,4 @@ -.authorize__container { +.flex__container__center { display: flex; justify-content: center; align-items: center; @@ -14,3 +14,16 @@ a.authorize__twitch_btn { text-decoration: none; font-size: 1.5rem; } + +.settings__container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100%; +} + +.settings__header { + display: flex; + justify-content: end; +} diff --git a/src/modules/web_app/frontend/index.html b/src/modules/web_app/frontend/index.html index 219606b..310353e 100644 --- a/src/modules/web_app/frontend/index.html +++ b/src/modules/web_app/frontend/index.html @@ -8,7 +8,8 @@ { "imports": { "vue": "https://unpkg.com/vue@3/dist/vue.esm-browser.prod.js", - "vue-router": "https://unpkg.com/vue-router@4.5.0/dist/vue-router.esm-browser.prod.js" + "vue-router": "https://unpkg.com/vue-router@4.5.0/dist/vue-router.esm-browser.prod.js", + "jwt-decode": "https://www.unpkg.com/jwt-decode@4.0.0/build/esm/index.js" } } diff --git a/src/modules/web_app/frontend/index.js b/src/modules/web_app/frontend/index.js index 9d70bd3..989a0b8 100644 --- a/src/modules/web_app/frontend/index.js +++ b/src/modules/web_app/frontend/index.js @@ -1,6 +1,48 @@ import { createApp, ref, onMounted } from 'vue'; import { createRouter, createWebHistory, RouterView, useRouter } from 'vue-router'; +import { jwtDecode } from "jwt-decode"; + + +class TokenManager { + static TOKEN_KEY = "token"; + + static getToken() { + return localStorage.getItem(this.TOKEN_KEY); + } + + static getAndValidate() { + const token = this.getToken(); + + if (token === null) { + return null; + } + + let decoded; + + try { + decoded = jwtDecode(token); + } catch (e) { + return null; + } + + if (decoded.exp < Date.now() / 1000) { + this.removeToken(); + return null; + } + + return token; + } + + static setToken(token) { + localStorage.setItem(this.TOKEN_KEY, token); + } + + static removeToken() { + localStorage.removeItem(this.TOKEN_KEY); + } +} + const Authorize = { setup() { @@ -19,7 +61,7 @@ const Authorize = { } }, template: ` -
+
Login with Twitch
Loading...
@@ -28,8 +70,24 @@ const Authorize = { const Settings = { + setup() { + const router = useRouter(); + + const logout = () => { + TokenManager.removeToken(); + router.push('/'); + } + + return { + logout, + }; + }, template: ` -
Settings
+
+
+ +
+
` } @@ -40,7 +98,7 @@ const Main = { Settings }, setup() { - const authorized = localStorage.getItem('token') !== null; + const authorized = TokenManager.getAndValidate() !== null; return { authorized @@ -63,14 +121,16 @@ const AuthCallbackTwitch = { fetch('/api/auth/callback/twitch/' + window.location.search) .then(response => response.json()) .then(data => { - localStorage.setItem('token', data.token); + localStorage.setItem(TOKEN_KEY, data.token); router.push('/'); }); }); }, template: ` -
AuthCallbackTwitch
+
+
Loading...
+
` }; diff --git a/src/modules/web_app/serializers/streamer.py b/src/modules/web_app/serializers/streamer.py index 4b21fd5..7558131 100644 --- a/src/modules/web_app/serializers/streamer.py +++ b/src/modules/web_app/serializers/streamer.py @@ -1,5 +1,10 @@ from pydantic import BaseModel +class TwitchSerializer(BaseModel): + id: int + name: str + + class StreamerSerializer(BaseModel): - pass + twitch: TwitchSerializer diff --git a/src/modules/web_app/views/streamer.py b/src/modules/web_app/views/streamer.py index 349c132..585d63b 100644 --- a/src/modules/web_app/views/streamer.py +++ b/src/modules/web_app/views/streamer.py @@ -2,7 +2,7 @@ from fastapi import APIRouter, Depends from authx import RequestToken from modules.web_app.auth.authx import auth -from modules.web_app.serializers.streamer import StreamerSerializer +from modules.web_app.serializers.streamer import StreamerSerializer, TwitchSerializer from repositories.streamers import StreamerConfigRepository from repositories.users import UserRepository from domain.auth import OAuthProvider @@ -35,3 +35,28 @@ async def get_streamers( )] return [StreamerSerializer(**streamer.model_dump()) for streamer in streamers] + + +@streamer_router.get("/me/") +async def get_me( + token: RequestToken = Depends(RequestToken) +) -> StreamerSerializer: + payload = auth.verify_token(token) + + u_id = payload.sub + user = await UserRepository.get(u_id) + + twith_oauth = user.oauths.get(OAuthProvider.TWITCH) + if not twith_oauth: + raise Exception("Twitch account not linked") + + streamer = await StreamerConfigRepository.get_by_twitch_id( + int(twith_oauth.id) + ) + + return StreamerSerializer( + twitch=TwitchSerializer( + id=streamer.twitch.id, + name=streamer.twitch.name + ) + )