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: `
-
+
@@ -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
+
`
};
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
+ )
+ )