File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change 11<script setup lang="ts">
22import { onMounted , watchEffect } from ' vue' ;
33import DefaultLayout from ' ./layouts/DefaultLayout.vue' ;
4+ import { useAuthStore } from ' ./stores/auth' ;
45import { useNavStore } from ' ./stores/nav' ;
56import { useTheme } from ' ./theme/useTheme' ;
67
8+ const auth = useAuthStore ();
79const nav = useNavStore ();
810const theme = useTheme ();
911
@@ -13,7 +15,7 @@ watchEffect(() => {
1315
1416onMounted (async () => {
1517 theme .init ();
16- await nav .hydrate ();
18+ await Promise . all ([ auth . hydrate (), nav .hydrate ()] );
1719});
1820 </script >
1921
Original file line number Diff line number Diff line change 1+ import { apiGet } from './client' ;
2+
3+ export interface AuthStatus {
4+ authenticated : boolean ;
5+ is_admin : boolean ;
6+ is_grading_assistant : boolean ;
7+ }
8+
9+ export function getAuthStatus ( ) : Promise < AuthStatus > {
10+ return apiGet < AuthStatus > ( '/api/v2/auth/me' ) ;
11+ }
Original file line number Diff line number Diff line change 1+ import { defineStore } from 'pinia' ;
2+ import { getAuthStatus } from '../api/auth' ;
3+
4+ interface State {
5+ authenticated : boolean ;
6+ isAdmin : boolean ;
7+ isGradingAssistant : boolean ;
8+ hydrated : boolean ;
9+ }
10+
11+ export const useAuthStore = defineStore ( 'auth' , {
12+ state : ( ) : State => ( {
13+ authenticated : false ,
14+ isAdmin : false ,
15+ isGradingAssistant : false ,
16+ hydrated : false ,
17+ } ) ,
18+
19+ actions : {
20+ async hydrate ( ) {
21+ try {
22+ const status = await getAuthStatus ( ) ;
23+ this . authenticated = status . authenticated ;
24+ this . isAdmin = status . is_admin ;
25+ this . isGradingAssistant = status . is_grading_assistant ;
26+ } catch {
27+ // Leave defaults — not authenticated.
28+ }
29+ this . hydrated = true ;
30+ } ,
31+ } ,
32+ } ) ;
Original file line number Diff line number Diff line change @@ -40,5 +40,6 @@ def spa_api_error(
4040
4141
4242# Importing the submodules registers their routes on `refbp`.
43+ from . import auth # noqa: E402,F401
4344from . import scoreboard # noqa: E402,F401
4445from . import students # noqa: E402,F401
Original file line number Diff line number Diff line change 1+ """SPA endpoint for checking the current user's authentication status."""
2+
3+ from flask_login import current_user
4+
5+ from ref import limiter , refbp
6+ from ref .frontend_api import SPA_READ_LIMIT
7+
8+
9+ @refbp .route ("/api/v2/auth/me" , methods = ("GET" ,))
10+ @limiter .limit (SPA_READ_LIMIT )
11+ def spa_api_auth_me ():
12+ """Return the authentication status of the current session.
13+
14+ Shape (authenticated):
15+
16+ {
17+ "authenticated": true,
18+ "is_admin": true,
19+ "is_grading_assistant": false
20+ }
21+
22+ Shape (not authenticated):
23+
24+ {
25+ "authenticated": false,
26+ "is_admin": false,
27+ "is_grading_assistant": false
28+ }
29+ """
30+ if current_user .is_authenticated :
31+ return {
32+ "authenticated" : True ,
33+ "is_admin" : current_user .is_admin ,
34+ "is_grading_assistant" : current_user .is_grading_assistant ,
35+ }, 200
36+
37+ return {
38+ "authenticated" : False ,
39+ "is_admin" : False ,
40+ "is_grading_assistant" : False ,
41+ }, 200
You can’t perform that action at this time.
0 commit comments