This commit is contained in:
sajjad
2023-10-18 01:22:06 -07:00
parent b16da8ab41
commit 98aa208766
157 changed files with 28673 additions and 13308 deletions
+16
View File
@@ -0,0 +1,16 @@
import { TokenService } from '@/services'
const $hasRole = function (roles) {
if (TokenService.getToken()) {
roles = roles.split('|');
for (const role of roles) {
if (TokenService.getInfo().roles && Array.isArray(TokenService.getInfo().roles) && TokenService.getInfo().roles.includes(role)) {
return true;
}
}
}
};
export {
$hasRole
}
+52
View File
@@ -0,0 +1,52 @@
import qs from 'qs';
const TOKEN_KEY = 'access_token'
const REFRESH_TOKEN_KEY = 'refresh_token'
const INFO = 'info'
/**
* Manage the how Access Tokens are being stored and retreived from storage.
*
* Current implementation stores to localStorage. Local Storage should always be
* accessed through this instace.
**/
const TokenService = {
getToken() {
return localStorage.getItem(TOKEN_KEY)
},
saveToken(accessToken = null) {
localStorage.setItem(TOKEN_KEY, accessToken)
},
removeToken() {
localStorage.removeItem(TOKEN_KEY)
},
getRefreshToken() {
return localStorage.getItem(REFRESH_TOKEN_KEY)
},
saveRefreshToken(refreshToken = null) {
localStorage.setItem(REFRESH_TOKEN_KEY, refreshToken)
},
removeRefreshToken() {
localStorage.removeItem(REFRESH_TOKEN_KEY)
},
getInfo() {
return qs.parse(localStorage.getItem(INFO))
},
saveInfo(info = null) {
info = qs.stringify(info);
localStorage.setItem(INFO, info)
},
removeInfo() {
localStorage.removeItem(INFO)
},
}
export { TokenService }
+127
View File
@@ -0,0 +1,127 @@
import { ApiService } from "../global/api.service";
import { TokenService } from "./storage.service";
import { urls } from "@/config/urls";
import toast from "../global/toast.service";
class AuthenticationError extends Error {
constructor(errorCode, message) {
super(message);
this.name = this.constructor.name;
this.message = message;
this.errorCode = errorCode;
}
}
const UserService = {
/**
* Login the user and store the access token to TokenService.
*
* @returns access_token
* @throws AuthenticationError
**/
login: async function(cell_number, password) {
const requestData = {
method: "post",
url: urls.login,
data: {
cell_number,
password,
grant_type: "password"
},
auth: {
username: process.env.MIX_APP_CLIENT_ID,
password: process.env.MIX_APP_CLIENT_SECRET
}
};
try {
const response = await ApiService.customRequest(requestData);
TokenService.saveToken(response.data.access_token);
TokenService.saveRefreshToken(response.data.refresh_token);
ApiService.setAuthHeader();
// NOTE: We haven't covered this yet in our ApiService
// but don't worry about this just yet - I'll come back to it later
ApiService.mount401Interceptor();
return response;
} catch (error) {
toast.error('Username Or Password Is Incorrect', 'Error');
throw new AuthenticationError(
error.response.status,
error.response.data.detail
);
}
},
/**
* Refresh the access token.
**/
refreshToken: async function() {
const refreshToken = TokenService.getRefreshToken();
const requestData = {
method: "post",
url: urls.login,
data: {
grant_type: "refresh_token",
refresh_token: refreshToken
},
auth: {
username: process.env.MIX_APP_CLIENT_ID,
password: process.env.MIX_APP_CLIENT_SECRET
}
};
try {
const response = await ApiService.customRequest(requestData);
TokenService.saveToken(response.data.access_token);
TokenService.saveRefreshToken(response.data.refresh_token);
// Update the header in ApiService
ApiService.setAuthHeader();
return response.data.access_token;
} catch (error) {
throw new AuthenticationError(
error.response.status,
error.response.data.detail
);
}
},
/**
* Logout the current user by removing the token from storage.
*
* Will also remove `Authorization Bearer <token>` header from future requests.
**/
logout: async function() {
try {
await ApiService.post(urls.logout);
// Remove the token and remove Authorization header from Api Service as well
TokenService.removeToken();
TokenService.removeRefreshToken();
TokenService.removeInfo();
ApiService.removeAuthHeader();
// NOTE: Again, we'll cover the 401 Interceptor a bit later.
ApiService.unmount401Interceptor();
return true;
} catch (error) {
return true
}
},
/**
* Get Information the current user ;
*
* Will also Register in Store;
**/
getInfo: async function() {
const response = await ApiService.get(urls.getInfo);
TokenService.saveInfo(response.data.data);
return response.data.data;
}
};
export default UserService;
export { UserService, AuthenticationError };
+100
View File
@@ -0,0 +1,100 @@
import axios from 'axios'
import { TokenService } from '../auth/storage.service'
import store from '@/store'
const ApiService = {
init(baseURL) {
axios.defaults.baseURL = baseURL;
},
setHeader() {
axios.defaults.headers.common["Accept"] = `application/json`;
axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
},
setAuthHeader() {
axios.defaults.headers.common["Authorization"] = `Bearer ${TokenService.getToken()}`;
},
removeAuthHeader() {
axios.defaults.headers.common["Authorization"] = null;
},
get(resource) {
return axios.get(resource)
},
post(resource, data) {
return axios.post(resource, data)
},
put(resource, data) {
data['_method'] = 'put';
return axios.post(resource, data)
},
delete(resource) {
let data = {'_method': 'delete'};
return axios.post(resource, data)
},
/**
* Perform a custom Axios request.
*
* data is an object containing the following properties:
* - method
* - url
* - data ... request payload
* - auth (optional)
* - username
* - password
**/
customRequest(data) {
return axios(data);
},
_401interceptor: null,
mount401Interceptor() {
this._401interceptor = axios.interceptors.response.use(
(response) => {
return response
},
async (error) => {
if (error.request.status == 401) {
if (error.config.url.includes('login')) {
// Refresh token has failed. Logout the user
store.dispatch('auth/logout');
throw error;
} else {
// Refresh the access token
try{
await store.dispatch('refreshToken')
// Retry the original request
return this.customRequest({
method: error.config.method,
url: error.config.url,
data: error.config.data
})
} catch (e) {
// Refresh has failed - reject the original request
throw error
}
}
}
// If error was not 401 just reject as is
throw error
}
)
},
unmount401Interceptor() {
// Eject the interceptor
axios.interceptors.response.eject(this._401interceptor)
}
}
export default ApiService
export { ApiService }
@@ -0,0 +1,49 @@
import axios from "axios";
import toast from "./toast.service";
import {TokenService, ApiService} from '@/services';
import store from "@/store"
import router from '@/router'
function errorResponseHandler(error) {
// check for errorHandle config
if (
error.config.hasOwnProperty("errorHandle") &&
error.config.errorHandle === false
) {
return Promise.reject(error);
}
// if has response show the error
if (error.response) {
if(typeof error.response.data.errors !== 'undefined') {
for (const key in error.response.data.errors) {
if (error.response.data.errors.hasOwnProperty(key)) {
let title = (error.response.data.title) ? error.response.data.title : undefined;
toast.error(error.response.data.errors[key], title);
}
}
}
if(error.response.status == 401) {
TokenService.removeToken();
TokenService.removeRefreshToken();
TokenService.removeInfo();
ApiService.removeAuthHeader();
store.commit('auth/logoutSuccess', {}, {root: true})
router.push({ name: `Dashboard` });
}
}
}
function successHandler(response) {
if(response.status == 200) {
if(typeof response.data.message !== 'undefined') {
toast.success(response.data.message, response.data.title);
}
}
return response;
}
// apply interceptor on response
axios.interceptors.response.use(successHandler, errorResponseHandler);
export default errorResponseHandler;
+21
View File
@@ -0,0 +1,21 @@
import "izitoast/dist/css/iziToast.min.css";
import iZtoast from "izitoast";
const toast = {
error: (message, title = "Error") => {
return iZtoast.error({
title: title,
message: message,
position: "bottomCenter"
});
},
success: (message, title = "Success") => {
return iZtoast.success({
title: title,
message: message,
position: "bottomCenter"
});
}
};
export default toast;
+3
View File
@@ -0,0 +1,3 @@
export * from './global/api.service';
export * from './auth/storage.service';
export * from './auth/user.service';
+6
View File
@@ -0,0 +1,6 @@
import {$hasRole} from '../acl/role';
export default {
methods: {
$hasRole
},
}
Binary file not shown.