import { ActionTree } from "vuex";
|
|
import { Actions } from "./generics";
|
|
import { IState } from "./state";
|
|
import { Mutation, MutationsTypes } from "./mutations";
|
|
import router from "../routes";
|
|
import { GettersTypes } from "./getters";
|
|
|
|
// Payload types
|
|
type IAuthenticatePayload = { email: string, password: string, remember: boolean };
|
|
type IAuthenticateResult = { email?: string[], password?: string[] } | null;
|
|
type IAuthFetchPayload = { path: string, options?: RequestInit };
|
|
|
|
/**
|
|
* The available actions te perform
|
|
*/
|
|
export enum Action {
|
|
// Authentication
|
|
AuthAuthenticate = "AUTH_AUTHENTICATE",
|
|
AuthForget = "AUHT_FORGET",
|
|
AuthLoad = "AUTH_LOAD",
|
|
|
|
// RESTful
|
|
AuthFetch = "AUTH_FETCH"
|
|
}
|
|
|
|
/**
|
|
* The action function signatures
|
|
*/
|
|
export type ActionsTypes = {
|
|
// Authentication
|
|
[Action.AuthAuthenticate]: (payload: IAuthenticatePayload) => Promise<IAuthenticateResult>,
|
|
[Action.AuthForget] : () => void,
|
|
[Action.AuthLoad] : () => boolean
|
|
|
|
// RESTful
|
|
[Action.AuthFetch]: (payload: IAuthFetchPayload) => Promise<Response>
|
|
}
|
|
|
|
/**
|
|
* The action function implementations
|
|
*/
|
|
export const actions: Actions<IState, GettersTypes, MutationsTypes, ActionsTypes> & ActionTree<IState, IState> = {
|
|
|
|
// Authentication ------------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Authenticate the credentials of a user and log them in
|
|
*/
|
|
[Action.AuthAuthenticate]({commit, dispatch}, {email, password, remember = false}) {
|
|
return new Promise((resolve, reject) => {
|
|
fetch(`/auth/login?use_cookies=${navigator.cookieEnabled}`, {
|
|
method: "post",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({email, password})
|
|
})
|
|
.then(async response => {
|
|
let body = await response.json();
|
|
if (response.status !== 200) {
|
|
if (response.status === 401) {
|
|
body.errors = { "email": [ "Email or password is incorrect" ] };
|
|
}
|
|
resolve(body.errors || {});
|
|
return;
|
|
}
|
|
commit(Mutation.LoadUser, body.token);
|
|
commit(Mutation.StoreUser, remember);
|
|
resolve(null);
|
|
})
|
|
.catch(e => {
|
|
console.error("Error occurred during submission:", e);
|
|
reject(e);
|
|
});
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Forget the login token and log the user out
|
|
*/
|
|
[Action.AuthForget]({commit}) {
|
|
commit(Mutation.ForgetUser, undefined);
|
|
},
|
|
|
|
/**
|
|
* Load the user from local storage
|
|
*/
|
|
[Action.AuthLoad]({getters, commit, dispatch}) {
|
|
let token = getters.storedToken;
|
|
if (!token) {
|
|
return false;
|
|
}
|
|
try {
|
|
commit(Mutation.LoadUser, token);
|
|
} catch(e) {
|
|
dispatch(Action.AuthForget, undefined);
|
|
return false;
|
|
}
|
|
return true;
|
|
},
|
|
|
|
// RESTful -------------------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Fetch request providing authentication and logout upon unauthorized requests
|
|
*/
|
|
async [Action.AuthFetch]({commit, state}, {path, options = {}}) {
|
|
if (state.user == null) {
|
|
router.push({ name: "Login" });
|
|
throw Error("Unauthorized");
|
|
}
|
|
options.credentials = "include";
|
|
options.headers = Object.assign(options.headers ?? {}, {
|
|
"Authorization": `Bearer ${state.user.token}`
|
|
});
|
|
let response = await fetch(path, options);
|
|
if (response.status === 401) {
|
|
commit(Mutation.ForgetUser, undefined);
|
|
router.push({ name: "Login" });
|
|
throw Error("Unauthorized");
|
|
}
|
|
return response;
|
|
}
|
|
};
|