use some status information to handle errors better

This commit is contained in:
Sven Czarnian
2022-11-05 00:10:27 +01:00
parent 47c09f2fdd
commit df0a6ade57
6 changed files with 107 additions and 24 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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