2021-02-06 00:56:21 +08:00
|
|
|
import { Context } from '@nuxt/types';
|
|
|
|
import { Inject } from '@nuxt/types/app';
|
|
|
|
import { AxiosError } from 'axios';
|
|
|
|
import { HangarException, User } from 'hangar-api';
|
|
|
|
import { NamedPermission } from '~/types/enums';
|
|
|
|
import { RootState } from '~/store';
|
2021-02-06 03:50:18 +08:00
|
|
|
import { ErrorPayload } from '~/store/snackbar';
|
2021-02-07 11:22:37 +08:00
|
|
|
import { AuthState } from '~/store/auth';
|
2021-01-23 02:44:49 +08:00
|
|
|
|
2021-02-05 14:51:51 +08:00
|
|
|
type Validation = (v: string) => boolean | string;
|
|
|
|
type ValidationArgument = (field?: string) => Validation;
|
|
|
|
|
2021-02-08 07:19:16 +08:00
|
|
|
function handleRequestError(err: AxiosError, error: Context['error']) {
|
|
|
|
if (!err.isAxiosError) {
|
|
|
|
// everything should be an AxiosError
|
|
|
|
error({
|
|
|
|
statusCode: 500,
|
|
|
|
});
|
|
|
|
console.log(err);
|
|
|
|
} else if (err.response) {
|
|
|
|
if (err.response.data.isHangarApiException || err.response.data.isHangarValidationException) {
|
|
|
|
const data: HangarException = err.response.data;
|
|
|
|
error({
|
|
|
|
statusCode: data.httpError.statusCode,
|
|
|
|
message: data.message,
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
error({
|
|
|
|
statusCode: err.response.status,
|
|
|
|
message: err.response.statusText,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
error({
|
|
|
|
message: "This shouldn't happen...",
|
|
|
|
});
|
|
|
|
console.log(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-06 00:56:21 +08:00
|
|
|
const createUtil = ({ store, error }: Context) => {
|
2021-01-23 02:44:49 +08:00
|
|
|
class Util {
|
2021-02-05 23:29:14 +08:00
|
|
|
dummyUser(): User {
|
|
|
|
return {
|
2021-02-06 00:56:21 +08:00
|
|
|
name: 'Dummy',
|
2021-02-05 23:29:14 +08:00
|
|
|
id: 42,
|
|
|
|
tagline: null,
|
|
|
|
createdAt: this.prettyDate(new Date()),
|
|
|
|
roles: [],
|
|
|
|
headerData: {
|
2021-02-06 00:56:21 +08:00
|
|
|
globalPermission: '',
|
2021-02-08 06:06:06 +08:00
|
|
|
unreadNotifications: 1,
|
|
|
|
projectApprovals: 3,
|
|
|
|
reviewQueueCount: 0,
|
|
|
|
unresolvedFlags: 2,
|
2021-02-05 23:29:14 +08:00
|
|
|
},
|
2021-02-06 00:56:21 +08:00
|
|
|
joinDate: this.prettyDate(new Date()),
|
|
|
|
};
|
2021-02-05 23:29:14 +08:00
|
|
|
}
|
|
|
|
|
2021-02-08 06:06:06 +08:00
|
|
|
avatarUrl(name: string): string {
|
|
|
|
return `/avatar/${name}?size=120x120`;
|
2021-01-23 02:44:49 +08:00
|
|
|
}
|
|
|
|
|
2021-02-05 23:29:14 +08:00
|
|
|
forumUrl(name: string): string {
|
2021-01-23 02:44:49 +08:00
|
|
|
return 'https://papermc.io/forums/u/' + name;
|
|
|
|
}
|
|
|
|
|
2021-02-05 23:29:14 +08:00
|
|
|
prettyDate(date: Date): string {
|
2021-02-05 04:30:47 +08:00
|
|
|
return date.toLocaleDateString(undefined, {
|
|
|
|
day: 'numeric',
|
|
|
|
month: 'long',
|
|
|
|
year: 'numeric',
|
|
|
|
});
|
2021-01-23 02:44:49 +08:00
|
|
|
}
|
2021-01-23 15:37:57 +08:00
|
|
|
|
2021-02-05 08:22:22 +08:00
|
|
|
/**
|
|
|
|
* Checks if the supplier permission has all named permissions.
|
|
|
|
* @param namedPermission perms required
|
|
|
|
*/
|
2021-02-07 11:22:37 +08:00
|
|
|
hasPerms(...namedPermission: NamedPermission[]): boolean {
|
|
|
|
const perms = (store.state.auth as AuthState).routePermissions;
|
|
|
|
if (perms === null) return false;
|
|
|
|
const _perms: bigint = BigInt('0b' + perms);
|
|
|
|
let result = true;
|
2021-02-05 08:22:22 +08:00
|
|
|
for (const np of namedPermission) {
|
|
|
|
const perm = (store.state as RootState).permissions.get(np);
|
|
|
|
if (!perm) {
|
|
|
|
throw new Error(namedPermission + ' is not valid');
|
|
|
|
}
|
2021-02-07 11:22:37 +08:00
|
|
|
const val = BigInt('0b' + perm.permission.toString(2));
|
|
|
|
result = result && (_perms & val) === val;
|
2021-01-23 15:37:57 +08:00
|
|
|
}
|
2021-02-05 08:22:22 +08:00
|
|
|
return result;
|
|
|
|
}
|
2021-02-07 11:22:37 +08:00
|
|
|
|
|
|
|
isCurrentUser(id: number): boolean {
|
|
|
|
return (store.state.auth as AuthState).user?.id === id;
|
|
|
|
}
|
2021-02-07 13:44:53 +08:00
|
|
|
|
|
|
|
isLoggedIn(): boolean {
|
|
|
|
return (store.state.auth as AuthState).user != null;
|
|
|
|
}
|
2021-02-05 08:22:22 +08:00
|
|
|
|
2021-02-08 07:19:16 +08:00
|
|
|
/**
|
|
|
|
* Used when an auth error should redirect to 404
|
|
|
|
* @param err the axios request error
|
|
|
|
*/
|
|
|
|
handlePageRequestError(err: AxiosError) {
|
|
|
|
handleRequestError(err, error);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Used for showing error popups. See handlePageRequestError to show an error page.
|
|
|
|
* @param err the axios request error
|
|
|
|
* @param msg optional error message
|
|
|
|
*/
|
|
|
|
handleRequestError(err: AxiosError, msg: string | undefined = 'Could not load data') {
|
|
|
|
if (process.server) {
|
|
|
|
handleRequestError(err, error);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!err.isAxiosError) {
|
|
|
|
// everything should be an AxiosError
|
|
|
|
error({
|
|
|
|
statusCode: 500,
|
|
|
|
});
|
|
|
|
console.log(err);
|
|
|
|
} else if (err.response) {
|
|
|
|
if (err.response.data.isHangarValidationException || err.response.data.isHangarApiException) {
|
2021-02-05 08:22:22 +08:00
|
|
|
const data: HangarException = err.response.data;
|
2021-02-08 07:19:16 +08:00
|
|
|
store.dispatch('snackbar/SHOW_ERROR', {
|
|
|
|
message: msg || data.message,
|
|
|
|
timeout: 3000,
|
|
|
|
} as ErrorPayload);
|
2021-02-05 08:22:22 +08:00
|
|
|
} else {
|
2021-02-08 07:19:16 +08:00
|
|
|
store.dispatch('snackbar/SHOW_ERROR', {
|
|
|
|
message: msg || err.response.statusText,
|
|
|
|
timeout: 2000,
|
|
|
|
} as ErrorPayload);
|
2021-02-05 08:22:22 +08:00
|
|
|
}
|
2021-01-23 15:37:57 +08:00
|
|
|
} else {
|
2021-02-08 07:19:16 +08:00
|
|
|
console.log(err);
|
2021-01-23 15:37:57 +08:00
|
|
|
}
|
|
|
|
}
|
2021-02-05 14:51:51 +08:00
|
|
|
|
|
|
|
$vc: Record<string, ValidationArgument> = {
|
|
|
|
require: ((name: string = 'Field') => (v: string) => !!v || `${name} is required`) as ValidationArgument,
|
|
|
|
};
|
|
|
|
|
|
|
|
$v: Record<string, Validation> = {};
|
2021-02-06 03:50:18 +08:00
|
|
|
|
|
|
|
error(err: string | ErrorPayload) {
|
|
|
|
if (typeof err === 'string') {
|
|
|
|
store.dispatch('snackbar/SHOW_ERROR', { message: err });
|
|
|
|
} else {
|
|
|
|
store.dispatch('snackbar/SHOW_ERROR', err);
|
|
|
|
}
|
|
|
|
}
|
2021-01-23 02:44:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return new Util();
|
|
|
|
};
|
|
|
|
|
|
|
|
type utilType = ReturnType<typeof createUtil>;
|
|
|
|
|
|
|
|
declare module 'vue/types/vue' {
|
|
|
|
interface Vue {
|
|
|
|
$util: utilType;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
declare module '@nuxt/types' {
|
|
|
|
interface NuxtAppOptions {
|
|
|
|
$util: utilType;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface Context {
|
|
|
|
$util: utilType;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
declare module 'vuex/types/index' {
|
2021-01-31 10:00:11 +08:00
|
|
|
// eslint-disable-next-line no-unused-vars,@typescript-eslint/no-unused-vars
|
2021-01-23 02:44:49 +08:00
|
|
|
interface Store<S> {
|
|
|
|
$util: utilType;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export default (ctx: Context, inject: Inject) => {
|
|
|
|
inject('util', createUtil(ctx));
|
|
|
|
};
|