Browse Source

use some status information to handle errors better

Sven Czarnian 2 years ago
parent
commit
df0a6ade57

+ 3 - 2
src/components/login.tsx

@@ -3,6 +3,7 @@ import { Button } from 'primereact/button';
 import { Card } from 'primereact/card';
 import { useNavigate } from 'react-router-dom';
 import { Auth, Configuration, Session } from '../services';
+import { BackendReturnStatus } from '../types';
 
 export const Login: React.FC = () => {
   const [loading, setLoading] = useState<boolean>(true);
@@ -10,8 +11,8 @@ export const Login: React.FC = () => {
 
   // check if the known bearer token is still valid
   useEffect(() => {
-    Auth.tokenIsValid().then((valid) => {
-      if (!valid) {
+    Auth.tokenIsValid().then((status) => {
+      if (status !== BackendReturnStatus.Ok) {
         Session.reset();
         setLoading(false);
       } else {

+ 6 - 4
src/components/navbar.tsx

@@ -4,7 +4,7 @@ import { useNavigate } from 'react-router-dom';
 import { AuthContext, TimeContext } from '../contexts';
 import { Configuration } from '../services';
 import { Airport } from '../services';
-import { AirportOverview, IAuthState } from '../types';
+import { AirportOverview, BackendReturnStatus, IAuthState } from '../types';
 
 export const NavBar: React.FC = () => {
   const [timestamp, setTimestamp] = useState<string>('');
@@ -63,7 +63,9 @@ export const NavBar: React.FC = () => {
   const updateMenuItems = async () => {
     if (currentAuth.current === undefined || !currentAuth.current.valid) return [];
 
-    Airport.all().then((airports) => {
+    Airport.all().then((response) => {
+      if (response.status !== BackendReturnStatus.Ok) return [];
+
       const newMenuTree: { label: string; items?: any[]; command?: () => void }[] = [
         {
           label: 'Airports',
@@ -72,12 +74,12 @@ export const NavBar: React.FC = () => {
       ];
 
       // create the airports subtree
-      const airportSubtree = firBasedSubMenu(airports, '/sequence');
+      const airportSubtree = firBasedSubMenu(response.airports, '/sequence');
       newMenuTree[0].items = airportSubtree;
 
       // collect all configuration airports
       const configurationAirports: AirportOverview[] = [];
-      airports.forEach((airport) => {
+      response.airports.forEach((airport) => {
         const idx = currentAuth.current?.user.airportConfigurationAccess.findIndex((value) => airport.icao === value);
         if (idx !== -1) configurationAirports.push(airport);
       });

+ 4 - 4
src/contexts/authcontext.tsx

@@ -1,7 +1,7 @@
 import { createContext, Dispatch, SetStateAction, useEffect, useState } from 'react';
 import { useNavigate } from 'react-router-dom';
 import { Auth } from '../services';
-import { IAuthState } from '../types';
+import { BackendReturnStatus, IAuthState } from '../types';
 
 const InitialAuthState: IAuthState = {
   valid: false,
@@ -27,9 +27,9 @@ export const AuthProvider = ({ children }: { children: any }) => {
   const resetAuth = () => setAuth(InitialAuthState);
 
   useEffect(() => {
-    Auth.user().then((user) => {
-      if (user !== undefined) {
-        setAuth({ valid: true, user });
+    Auth.user().then((response) => {
+      if (response.status === BackendReturnStatus.Ok) {
+        setAuth({ valid: true, user: response.user });
       } else {
         setAuth(InitialAuthState);
       }

+ 24 - 5
src/services/airport.ts

@@ -1,12 +1,21 @@
 import axios from 'axios';
 import { Configuration } from './configuration';
 import { Session } from './session';
-import { AirportOverview } from '../types';
+import {
+  AirportOverviewBackend,
+  AirportOverview,
+  BackendReturnStatus,
+} from '../types';
 
 export class Airport {
-  static async all(): Promise<AirportOverview[]> {
+  static async all(): Promise<AirportOverviewBackend> {
     const token = Session.bearerToken();
-    if (!token) return [];
+    if (!token) {
+      return {
+        status: BackendReturnStatus.Unauthorized,
+        airports: [],
+      };
+    }
 
     return axios
       .get<AirportOverview[]>(`${Configuration.resourceServer}/airport/all`, {
@@ -14,7 +23,17 @@ export class Airport {
           Authorization: `Bearer ${token}`,
         },
       })
-      .then((response) => response.data)
-      .catch(() => []);
+      .then((response) => {
+        return {
+          status: BackendReturnStatus.Ok,
+          airports: response.data,
+        };
+      })
+      .catch((err) => {
+        return {
+          status: err.status === 401 ? BackendReturnStatus.Unauthorized : BackendReturnStatus.Failure,
+          airports: [],
+        };
+      });
   }
 }

+ 46 - 9
src/services/auth.ts

@@ -1,12 +1,17 @@
 import axios from 'axios';
 import { Configuration } from './configuration';
 import { Session } from './session';
-import { User } from '../types';
+import {
+  BackendReturnStatus,
+  DefaultUser,
+  UserBackend,
+  User,
+} from '../types';
 
 export class Auth {
-  static async tokenIsValid(): Promise<boolean> {
+  static async tokenIsValid(): Promise<BackendReturnStatus> {
     const token = Session.bearerToken();
-    if (!token) return false;
+    if (!token) return BackendReturnStatus.Unauthorized;
 
     return axios
       .get<void>(`${Configuration.resourceServer}/auth/validate`, {
@@ -14,13 +19,21 @@ export class Auth {
           Authorization: `Bearer ${token}`,
         },
       })
-      .then(() => true)
-      .catch(() => false);
+      .then(() => BackendReturnStatus.Ok)
+      .catch((err) => {
+        if (err.status === 401) return BackendReturnStatus.Unauthorized;
+        return BackendReturnStatus.Failure;
+      });
   }
 
-  static async user(): Promise<User | undefined> {
+  static async user(): Promise<UserBackend> {
     const token = Session.bearerToken();
-    if (!token) return undefined;
+    if (!token) {
+      return {
+        status: BackendReturnStatus.Unauthorized,
+        user: DefaultUser,
+      };
+    }
 
     return axios
       .get<User>(`${Configuration.resourceServer}/auth/user`, {
@@ -28,7 +41,31 @@ export class Auth {
           Authorization: `Bearer ${token}`,
         },
       })
-      .then((response) => response.data)
-      .catch(() => undefined);
+      .then((response) => {
+        return {
+          status: BackendReturnStatus.Ok,
+          user: response.data,
+        };
+      })
+      .catch((err) => {
+        return {
+          status: err.status === 401 ? BackendReturnStatus.Unauthorized : BackendReturnStatus.Failure,
+          user: DefaultUser,
+        };
+      });
+  }
+
+  static async refreshRadarScopeKey(): Promise<boolean> {
+    const token = Session.bearerToken();
+    if (!token) return false;
+
+    return axios
+      .get<void>(`${Configuration.resourceServer}/auth/refreshRadarScopeKey`, {
+        headers: {
+          Authorization: `Bearer ${token}`,
+        },
+      })
+      .then(() => true)
+      .catch(() => false);
   }
 }

+ 24 - 0
src/types/index.ts

@@ -1,9 +1,20 @@
+export enum BackendReturnStatus {
+  Ok,
+  Unauthorized,
+  Failure,
+};
+
 export interface AirportOverview {
   icao: string;
   name: string;
   flightInformationRegion: string;
 };
 
+export interface AirportOverviewBackend {
+  status: BackendReturnStatus;
+  airports: AirportOverview[];
+};
+
 export interface User {
   vatsimId: string;
   fullName: string;
@@ -12,6 +23,19 @@ export interface User {
   airportConfigurationAccess: string[];
 };
 
+export const DefaultUser: User = {
+  vatsimId: '',
+  fullName: '',
+  radarScopeKey: '',
+  administrator: false,
+  airportConfigurationAccess: [],
+};
+
+export interface UserBackend {
+  status: BackendReturnStatus;
+  user: User;
+}
+
 export interface IAuthState {
   valid: boolean,
   user: User,