import * as api from '@/api' import gradySays from '../grady_speak' import { BareActionContext, getStoreBuilder } from 'vuex-typex' import { UserAccount } from '@/models' import { RootState } from '@/store/store' export interface Credentials { username: string, password: string } export interface AuthState { token: string, lastTokenRefreshTry: number, refreshingToken: boolean, jwtTimeDelta: number, message: string, user: UserAccount } function initialState (): AuthState { return { token: window.sessionStorage.getItem('token') || '', lastTokenRefreshTry: Date.now(), refreshingToken: false, jwtTimeDelta: 0, message: '', user: { pk: '', username: '', isAdmin: false } } } const mb = getStoreBuilder<RootState>().module('Authentication', initialState()) const stateGetter = mb.state() const gradySpeakGetter = mb.read(function gradySpeak () { return gradySays[Math.floor(Math.random() * gradySays.length)] }) const isStudentGetter = mb.read(function isStudent (state: AuthState) { return state.user.role === UserAccount.RoleEnum.Student }) const isTutorGetter = mb.read(function isTutor (state: AuthState) { return state.user.role === UserAccount.RoleEnum.Tutor }) const isReviewerGetter = mb.read(function isReviewer (state: AuthState) { return state.user.role === UserAccount.RoleEnum.Reviewer }) const isTutorOrReviewerGetter = mb.read(function isTutorOrReviewer (state: AuthState, getters) { return getters.isTutor || getters.isReviewer }) const isLoggedInGetter = mb.read(function isLoggedIn (state: AuthState) { return !!state.token }) function SET_MESSAGE (state: AuthState, message: string) { state.message = message } function SET_JWT_TOKEN (state: AuthState, token: string) { window.sessionStorage.setItem('token', token) api.default.defaults.headers['Authorization'] = `JWT ${token}` state.token = token } function SET_JWT_TIME_DELTA (state: AuthState, timeDelta: number) { state.jwtTimeDelta = timeDelta } function SET_USER (state: AuthState, user: UserAccount) { state.user = user } function SET_REFRESHING_TOKEN (state: AuthState, refreshing: boolean) { state.refreshingToken = refreshing } function SET_LAST_TOKEN_REFRESH_TRY (state: AuthState) { state.lastTokenRefreshTry = Date.now() } function RESET_STATE (state: AuthState) { window.sessionStorage.setItem('token', '') Object.assign(state, initialState()) } async function getJWT (context: BareActionContext<AuthState, RootState>, credentials: Credentials) { try { const token = await api.fetchJWT(credentials) Authentication.SET_JWT_TOKEN(token.token) } catch (error) { let errorMsg if (!error.response) { errorMsg = 'Cannot reach server.' } else if (error.response.status === 400) { errorMsg = 'Unable to log in with provided credentials.' } else if (error.response.status === 429) { errorMsg = error.response.data.detail } Authentication.SET_MESSAGE(errorMsg) throw errorMsg } finally { Authentication.SET_LAST_TOKEN_REFRESH_TRY() } } async function refreshJWT ({ state }: BareActionContext<AuthState, RootState>) { Authentication.SET_REFRESHING_TOKEN(true) try { const token = await api.refreshJWT(state.token) Authentication.SET_JWT_TOKEN(token.token) } finally { Authentication.SET_REFRESHING_TOKEN(false) Authentication.SET_LAST_TOKEN_REFRESH_TRY() } } async function getUser () { try { const user = await api.getOwnUser() Authentication.SET_USER(user) } catch (err) { Authentication.SET_MESSAGE('Unable to fetch user.') } } async function getJWTTimeDelta () { try { const delta = await api.fetchJWTTimeDelta() // multiply by 1000 to convert to ms Authentication.SET_JWT_TIME_DELTA(delta * 1000) } catch (err) { console.log(err) } } export const Authentication = { get state () { return stateGetter() }, get gradySpeak () { return gradySpeakGetter() }, get isStudent () { return isStudentGetter() }, get isTutor () { return isTutorGetter() }, get isReviewer () { return isReviewerGetter() }, get isTutorOrReviewer () { return isTutorOrReviewerGetter() }, get isLoggedIn () { return isLoggedInGetter() }, SET_MESSAGE: mb.commit(SET_MESSAGE), SET_JWT_TOKEN: mb.commit(SET_JWT_TOKEN), SET_JWT_TIME_DELTA: mb.commit(SET_JWT_TIME_DELTA), SET_USER: mb.commit(SET_USER), SET_REFRESHING_TOKEN: mb.commit(SET_REFRESHING_TOKEN), SET_LAST_TOKEN_REFRESH_TRY: mb.commit(SET_LAST_TOKEN_REFRESH_TRY), RESET_STATE: mb.commit(RESET_STATE), getJWT: mb.dispatch(getJWT), refreshJWT: mb.dispatch(refreshJWT), getUser: mb.dispatch(getUser), getJWTTimeDelta: mb.dispatch(getJWTTimeDelta) }