frontend and backend progress
This commit is contained in:
parent
7788369b73
commit
888cdae3cd
|
|
@ -11,7 +11,7 @@ const store = useStore<AppStore>();
|
|||
|
||||
const logout = () => {
|
||||
store.dispatch('auth/logout');
|
||||
router.push('/login');
|
||||
router.push({path: '/login'});
|
||||
}
|
||||
|
||||
const isOnline = ref(navigator.onLine);
|
||||
|
|
@ -23,7 +23,7 @@ onMounted(() => {
|
|||
window.addEventListener("offline", () => isOnline.value = false);
|
||||
|
||||
if (isOnline.value) {
|
||||
router.push("/login");
|
||||
router.push({path: '/login'});
|
||||
} else {
|
||||
// checkStoredUserData();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,9 @@ class EventBus {
|
|||
document.addEventListener(type, listener as EventListener, options);
|
||||
}
|
||||
|
||||
dispatch<T extends Event>(event: T): void {
|
||||
document.dispatchEvent(event);
|
||||
// dispatch<T extends Event>(event: T): void {
|
||||
dispatch(event: string, data: any = null): void {
|
||||
document.dispatchEvent(new CustomEvent(event, { detail: data }));
|
||||
}
|
||||
|
||||
remove<T extends Event>(type: string, listener: (event: T) => void, options?: boolean | EventListenerOptions): void {
|
||||
|
|
|
|||
|
|
@ -1,93 +0,0 @@
|
|||
import User from "@/types/User";
|
||||
|
||||
export const pitchers: Map<number, User> = new Map([
|
||||
[
|
||||
1,
|
||||
{
|
||||
id: 1,
|
||||
firstName: "Nolan",
|
||||
lastName: "Ryan",
|
||||
dateOfBirth: new Date("1947-01-31")
|
||||
}
|
||||
],
|
||||
[
|
||||
2,
|
||||
{
|
||||
id: 2,
|
||||
firstName: "Sandy",
|
||||
lastName: "Koufax",
|
||||
dateOfBirth: new Date("1935-12-30")
|
||||
}
|
||||
],
|
||||
[
|
||||
3,
|
||||
{
|
||||
id: 3,
|
||||
firstName: "Pedro",
|
||||
lastName: "Martinez",
|
||||
dateOfBirth: new Date("1971-10-25")
|
||||
}
|
||||
],
|
||||
[
|
||||
4,
|
||||
{
|
||||
id: 4,
|
||||
firstName: "Randy",
|
||||
lastName: "Johnson",
|
||||
dateOfBirth: new Date("1963-09-10")
|
||||
}
|
||||
],
|
||||
[
|
||||
5,
|
||||
{
|
||||
id: 5,
|
||||
firstName: "Greg",
|
||||
lastName: "Maddux",
|
||||
dateOfBirth: new Date("1966-04-14")
|
||||
}
|
||||
],
|
||||
[
|
||||
6,
|
||||
{
|
||||
id: 6,
|
||||
firstName: "Bob",
|
||||
lastName: "Gibson",
|
||||
dateOfBirth: new Date("1935-11-09")
|
||||
}
|
||||
],
|
||||
[
|
||||
7,
|
||||
{
|
||||
id: 7,
|
||||
firstName: "Tom",
|
||||
lastName: "Seaver",
|
||||
dateOfBirth: new Date("1944-11-17")
|
||||
}
|
||||
],
|
||||
[
|
||||
8,
|
||||
{
|
||||
id: 8,
|
||||
firstName: "Roger",
|
||||
lastName: "Clemens",
|
||||
dateOfBirth: new Date("1962-08-04")
|
||||
}
|
||||
],
|
||||
[
|
||||
9,
|
||||
{
|
||||
id: 9,
|
||||
firstName: "Walter",
|
||||
lastName: "Johnson",
|
||||
dateOfBirth: new Date("1887-11-06")
|
||||
}
|
||||
],
|
||||
[
|
||||
10,
|
||||
{
|
||||
id: 10,
|
||||
firstName: "Clayton",
|
||||
lastName: "Kershaw",
|
||||
dateOfBirth: new Date("1988-03-19")
|
||||
}
|
||||
]]);
|
||||
|
|
@ -8,6 +8,7 @@ import BullpenView from "@/views/BullpenView.vue";
|
|||
import BullpenSummaryView from "@/views/BullpenSummaryView.vue";
|
||||
import SetupView from '@/views/SetupView.vue';
|
||||
import backendService from '@/services/BackendService'
|
||||
import BullpenListView from "@/views/BullpenListView.vue";
|
||||
|
||||
const routes: Array<RouteRecordRaw> = [
|
||||
{ path: '/', redirect: '/login' },
|
||||
|
|
@ -16,6 +17,7 @@ const routes: Array<RouteRecordRaw> = [
|
|||
{ path: '/home', component: HomeView },
|
||||
{ path: '/pitchers', component: PitcherList },
|
||||
{ path: '/bullpen', component: BullpenView },
|
||||
{ path: '/stats', component: BullpenListView },
|
||||
{ path: '/summary', component: BullpenSummaryView }
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import axios from "axios";
|
||||
import backendService from '@/services/BackendService'
|
||||
|
||||
const server = JSON.parse(localStorage.getItem("server") || '""');
|
||||
const server = backendService.getServer()
|
||||
|
||||
const instance = axios.create({
|
||||
baseURL: `${server.protocol}://${server.host}:${server.port}/api`,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
import api from "@/services/Api";
|
||||
import authHeader from "@/services/AuthHeader";
|
||||
import {AxiosError, AxiosResponse} from "axios";
|
||||
import EventBus from "@/common/EventBus";
|
||||
|
||||
export class ApiService<Type> {
|
||||
protected name: string;
|
||||
|
||||
constructor(name: string) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public save(entity: Type): Promise<Type> {
|
||||
return api
|
||||
.post(`${this.name}`, entity)
|
||||
.then(response => {
|
||||
return response.data;
|
||||
}, (error) => {
|
||||
this.handleExpiredToken(error);
|
||||
return Promise.reject(error);
|
||||
});
|
||||
}
|
||||
|
||||
public fetchAll(): Promise<Type[]> {
|
||||
return api
|
||||
.get(`/${this.name}`, { headers: authHeader() })
|
||||
.then((response: AxiosResponse<Type[]>) => {
|
||||
return response.data;
|
||||
}, (error) => {
|
||||
this.handleExpiredToken(error);
|
||||
return Promise.reject(error);
|
||||
});
|
||||
}
|
||||
|
||||
public fetchById(id: number): Promise<Type> {
|
||||
return api
|
||||
.get(`/${this.name}/${id}`, { headers: authHeader() })
|
||||
.then((response: AxiosResponse<Type>) => {
|
||||
return response.data;
|
||||
}, (error: AxiosError) => {
|
||||
this.handleExpiredToken(error);
|
||||
return Promise.reject(error);
|
||||
});
|
||||
}
|
||||
|
||||
protected handleExpiredToken(error: any) {
|
||||
if (error.response && error.response.status === 403) {
|
||||
console.log('Refresh token expired. Logout and redirect to login page.');
|
||||
EventBus.dispatch("logout");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@ import api from './Api';
|
|||
import TokenService from './TokenService';
|
||||
|
||||
class AuthService {
|
||||
public login(email: string, password: string) {
|
||||
public async login(email: string, password: string) {
|
||||
return api
|
||||
.post('/auth/login', {
|
||||
email,
|
||||
|
|
@ -17,7 +17,7 @@ class AuthService {
|
|||
});
|
||||
}
|
||||
|
||||
public logout(): Promise<void> {
|
||||
public async logout(): Promise<void> {
|
||||
TokenService.removeUser();
|
||||
|
||||
return Promise.resolve();
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@ class BackendService {
|
|||
return localStorage.getItem("server") !== null;
|
||||
}
|
||||
getServer(): Server {
|
||||
return JSON.parse(localStorage.getItem("server") || '{"protocol":"https","host":"localhost","port":8124}');
|
||||
return JSON.parse(localStorage.getItem("server") || '{"protocol":"http","host":"localhost","port":8080}');
|
||||
// return JSON.parse(localStorage.getItem("server") || '{"protocol":"https","host":"bullpen-api.palaeomatiker.home64.de","port":443}');
|
||||
}
|
||||
updateServer(server: Server): void {
|
||||
localStorage.setItem("server", JSON.stringify(server));
|
||||
|
|
|
|||
|
|
@ -1,9 +1,15 @@
|
|||
import Pitch from "@/types/Pitch";
|
||||
import User from "@/types/User";
|
||||
import Bullpen from '@/types/Bullpen';
|
||||
import Pageable from "@/types/PagingDecorator";
|
||||
import api from '@/services/Api';
|
||||
import {ApiService} from "@/services/ApiService";
|
||||
|
||||
export class BullpenSessionService extends ApiService<Bullpen> {
|
||||
public constructor() {
|
||||
super('bullpen_session');
|
||||
}
|
||||
|
||||
export class BullpenSessionService {
|
||||
public create(user: User): Bullpen {
|
||||
return {
|
||||
id: null,
|
||||
|
|
@ -14,16 +20,6 @@ export class BullpenSessionService {
|
|||
}
|
||||
}
|
||||
|
||||
public save(bullpen: Bullpen): Promise<Bullpen> {
|
||||
return api
|
||||
.post('/bullpen_session', bullpen)
|
||||
.then(response => {
|
||||
return response.data;
|
||||
}, (error) => {
|
||||
console.log(JSON.stringify(error, null, 2));
|
||||
});
|
||||
}
|
||||
|
||||
public createPitch(): Pitch {
|
||||
return {
|
||||
id: undefined,
|
||||
|
|
@ -33,6 +29,20 @@ export class BullpenSessionService {
|
|||
hitArea: 0
|
||||
}
|
||||
}
|
||||
|
||||
public findByPitcherId(id: number, page: number, size: number): Promise<Pageable<Bullpen>> {
|
||||
return api
|
||||
.get('/bullpen_session', { params: {
|
||||
user: id,
|
||||
page: page,
|
||||
size: size
|
||||
}}).then(response => {
|
||||
return response.data;
|
||||
}, (error) => {
|
||||
this.handleExpiredToken(error);
|
||||
return Promise.reject(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default new BullpenSessionService();
|
||||
|
|
|
|||
|
|
@ -1,14 +1,18 @@
|
|||
import PitchType from "@/types/PitchType";
|
||||
import { ApiService } from './ApiService';
|
||||
|
||||
class PitchTypeService {
|
||||
getLocalPitchTypes(): PitchType[] {
|
||||
class PitchTypeService extends ApiService<PitchType> {
|
||||
constructor() {
|
||||
super('pitch_types');
|
||||
}
|
||||
|
||||
public getLocalPitchTypes(): PitchType[] {
|
||||
return JSON.parse(localStorage.getItem("pitchTypes") || '""');
|
||||
}
|
||||
|
||||
updateLocalPitchTypes(pitchTypes: PitchType[]): void {
|
||||
public updateLocalPitchTypes(pitchTypes: PitchType[]): void {
|
||||
localStorage.setItem("pitchTypes", JSON.stringify(pitchTypes));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default new PitchTypeService();
|
||||
|
|
|
|||
|
|
@ -1,13 +1,9 @@
|
|||
import User from "@/types/User";
|
||||
import api from './Api';
|
||||
import { ApiService } from './ApiService';
|
||||
|
||||
class UserService {
|
||||
async getAllUsers(): Promise<User[]> {
|
||||
return (await api.get('/users')).data;
|
||||
}
|
||||
|
||||
async getUser(id: number): Promise<User> {
|
||||
return (await api.get(`/users/${id}`)).data;
|
||||
class UserService extends ApiService<User> {
|
||||
constructor() {
|
||||
super('users');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ const auth: Module<AuthState, RootState> = {
|
|||
login({ commit }: AuthActionContext, user) {
|
||||
return AuthService.login(user.email, user.password).then(
|
||||
auth => {
|
||||
return UserService.getUser(auth.id).then(
|
||||
return UserService.fetchById(auth.id).then(
|
||||
(user: User) => {
|
||||
commit('loginSuccess', user);
|
||||
return Promise.resolve(user);
|
||||
|
|
@ -62,6 +62,9 @@ const auth: Module<AuthState, RootState> = {
|
|||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
},
|
||||
refreshToken({ commit }: AuthActionContext, accessToken) {
|
||||
commit('refreshToken', accessToken);
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
|
|
@ -83,6 +86,10 @@ const auth: Module<AuthState, RootState> = {
|
|||
},
|
||||
registerFailure(state) {
|
||||
state.isAuthenticated = false;
|
||||
},
|
||||
refreshToken(state, accessToken: string) {
|
||||
state.isAuthenticated = true;
|
||||
TokenService.updateLocalAccessToken(accessToken);
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
|
|
|
|||
|
|
@ -4,25 +4,26 @@ import Bullpen from '@/types/Bullpen';
|
|||
import User from '@/types/User';
|
||||
import BullpenSessionService from '@/services/BullpenSessionService';
|
||||
import Pitch from '@/types/Pitch';
|
||||
import Pageable from "@/types/PagingDecorator";
|
||||
|
||||
export interface BullpenState {
|
||||
bullpen: Bullpen | null;
|
||||
bullpens: Pageable<Bullpen> | null;
|
||||
}
|
||||
|
||||
type BullpenActionContext = ActionContext<BullpenState, RootState>;
|
||||
|
||||
const bullpen: Module<BullpenState, RootState> = {
|
||||
namespaced: true,
|
||||
state: { bullpen: null },
|
||||
state: {
|
||||
bullpen: null,
|
||||
bullpens: null
|
||||
},
|
||||
actions: {
|
||||
start({commit}: BullpenActionContext, user: User) {
|
||||
const bullpen = BullpenSessionService.create(user);
|
||||
commit('start', bullpen);
|
||||
},
|
||||
async finish({commit}: BullpenActionContext, bullpen: Bullpen) {
|
||||
await BullpenSessionService.save(bullpen);
|
||||
commit('finish');
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
start(state, bullpen: Bullpen) {
|
||||
|
|
@ -34,6 +35,9 @@ const bullpen: Module<BullpenState, RootState> = {
|
|||
},
|
||||
finish(state) {
|
||||
state.bullpen = null;
|
||||
},
|
||||
fetch(state: BullpenState, bullpens: Pageable<Bullpen>) {
|
||||
state.bullpens = bullpens;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,36 +1,18 @@
|
|||
import pitchTypeService from '@/services/PitchTypeService'
|
||||
import PitchType from "@/types/PitchType";
|
||||
import api from "@/services/Api";
|
||||
import authHeader from '@/services/AuthHeader';
|
||||
|
||||
import { Module, ActionContext } from 'vuex';
|
||||
import { Module } from 'vuex';
|
||||
import { RootState } from './index';
|
||||
import {AxiosResponse} from 'axios';
|
||||
|
||||
export interface PitchTypeState {
|
||||
pitchTypes: PitchType[];
|
||||
}
|
||||
|
||||
type PitchTypeActionContext = ActionContext<PitchTypeState, RootState>;
|
||||
|
||||
const pitchTypes: Module<PitchTypeState, RootState> = {
|
||||
namespaced: true,
|
||||
state: {pitchTypes: []},
|
||||
actions: {
|
||||
initialize({ commit }: PitchTypeActionContext) {
|
||||
api.get('/pitch_types', { headers: authHeader() }).then(
|
||||
(response: AxiosResponse) => {
|
||||
commit('initializedPitchTypes', response.data);
|
||||
return Promise.resolve(response.data);
|
||||
},
|
||||
error => {
|
||||
return Promise.reject(error);
|
||||
});
|
||||
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
initializedPitchTypes(state, pitchTypeList: PitchType[]) {
|
||||
initialize(state, pitchTypeList: PitchType[]) {
|
||||
pitchTypeService.updateLocalPitchTypes(pitchTypeList);
|
||||
state.pitchTypes = pitchTypeList;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
export default interface Pageable<Type> {
|
||||
totalCount: number,
|
||||
totalPages: number,
|
||||
currentPage: number,
|
||||
data: Type[]
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
<script setup lang="ts">
|
||||
import {
|
||||
IonButton,
|
||||
IonCard,
|
||||
IonContent,
|
||||
IonFooter,
|
||||
IonHeader,
|
||||
IonLabel,
|
||||
IonPage,
|
||||
IonTitle,
|
||||
IonToolbar
|
||||
} from "@ionic/vue";
|
||||
import {useStore} from 'vuex';
|
||||
import {useRouter} from 'vue-router';
|
||||
import {computed} from "vue";
|
||||
|
||||
const router = useRouter();
|
||||
const store = useStore();
|
||||
|
||||
const isAuthenticated = computed(() => store.state.auth.isAuthenticated);
|
||||
const pitcher = computed(() => store.state.auth.user);
|
||||
const bullpens = computed(() => store.state.bullpen.bullpens);
|
||||
|
||||
const gotoHome = () => {
|
||||
router.push({path: '/home'});
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ion-page>
|
||||
<ion-header :translucent="true">
|
||||
<ion-toolbar>
|
||||
<ion-title v-if="isAuthenticated">Bullpens of {{ pitcher.firstName }} {{ pitcher.lastName }}</ion-title>
|
||||
<ion-title v-else>Bullpens</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<ion-card v-for="(bullpen, index) in bullpens.data" :key="index">
|
||||
<ion-label>Bullpen {{bullpen.id}} ({{bullpen.startedAt}})</ion-label>
|
||||
</ion-card>
|
||||
</ion-content>
|
||||
<ion-footer>
|
||||
<ion-button expand="full" color="success" @click="gotoHome">Home</ion-button>
|
||||
</ion-footer>
|
||||
</ion-page>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
|
|
@ -20,6 +20,7 @@ import PitchType from "@/types/PitchType";
|
|||
import {useRouter} from 'vue-router';
|
||||
import {computed} from 'vue';
|
||||
import {useStore} from 'vuex';
|
||||
import BullpenSessionService from "@/services/BullpenSessionService";
|
||||
|
||||
const router = useRouter();
|
||||
const store = useStore();
|
||||
|
|
@ -36,8 +37,13 @@ const determinePitchTypeName = (id: number): string => {
|
|||
}
|
||||
|
||||
const gotoHome = () => {
|
||||
store.dispatch("bullpen/finish", bullpen.value.bullpen);
|
||||
BullpenSessionService.save(bullpen.value.bullpen).then((bullpen) => {
|
||||
store.commit("bullpen/finish", bullpen);
|
||||
router.push({path: '/home'});
|
||||
}, (error) => {
|
||||
// Todo: Handle error
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import {computed, onMounted, ref} from "vue";
|
||||
import {computed, ref} from "vue";
|
||||
import {
|
||||
IonContent,
|
||||
IonHeader,
|
||||
|
|
@ -32,10 +32,6 @@ const isAuthenticated = computed(() => store.state.auth.isAuthenticated);
|
|||
const pitchTypes = computed(() => store.state.pitchTypes.pitchTypes);
|
||||
const bullpen = computed(() => store.state.bullpen);
|
||||
|
||||
onMounted(async () => {
|
||||
await store.dispatch("bullpen/start", pitcher.value);
|
||||
});
|
||||
|
||||
const setPitchType = (pitchType: PitchType) => {
|
||||
pitch.value.pitchTypeId = pitchType.id;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { playOutline, statsChartOutline, personOutline, logOutOutline } from 'io
|
|||
// import userImage from '../assets/groot.jpg'
|
||||
import {useStore} from "vuex";
|
||||
import {useRouter} from "vue-router";
|
||||
import BullpenSessionService from "@/services/BullpenSessionService";
|
||||
|
||||
const router = useRouter();
|
||||
const store = useStore();
|
||||
|
|
@ -20,11 +21,15 @@ if (pitcher.value === undefined || pitcher.value === null || pitcher.value === '
|
|||
}
|
||||
|
||||
const startBullpen = () => {
|
||||
store.dispatch("bullpen/start", pitcher.value);
|
||||
router.push({ path: '/bullpen' });
|
||||
};
|
||||
|
||||
const showStats = () => {
|
||||
BullpenSessionService.fetchAll().then((bullpens) => {
|
||||
store.commit("bullpen/fetch", bullpens);
|
||||
router.push({ path: '/stats' });
|
||||
})
|
||||
};
|
||||
|
||||
const showProfile = () => {
|
||||
|
|
|
|||
|
|
@ -9,8 +9,6 @@ import {
|
|||
IonInput
|
||||
} from "@ionic/vue";
|
||||
|
||||
// Todo: https://github.com/alanmontgomery/ionic-react-login
|
||||
|
||||
import {
|
||||
lockClosedOutline,
|
||||
personOutline,
|
||||
|
|
@ -21,6 +19,9 @@ import {Field, useForm} from 'vee-validate';
|
|||
import { useRouter } from 'vue-router';
|
||||
import { useStore } from 'vuex'
|
||||
import * as yup from 'yup';
|
||||
import PitchTypeService from "@/services/PitchTypeService";
|
||||
import EventBus from "@/common/EventBus";
|
||||
import PitchType from "@/types/PitchType";
|
||||
|
||||
const loading = ref(false);
|
||||
const server = JSON.parse(localStorage.getItem("server") || '""');
|
||||
|
|
@ -31,7 +32,7 @@ const schema = yup.object({
|
|||
.string()
|
||||
.min(8, 'Minimum 8 characters')
|
||||
.matches(/\d/, 'Must include a number')
|
||||
// .matches(/[^A-Za-z\d]/, 'Must include a special character')
|
||||
.matches(/[^A-Za-z\d]/, 'Must include a special character')
|
||||
.required('Password is required'),
|
||||
});
|
||||
|
||||
|
|
@ -75,9 +76,10 @@ const submit = handleSubmit((values, { resetForm }) => {
|
|||
const onLogin = () => {
|
||||
console.log('check if pitch types are available.');
|
||||
|
||||
store.dispatch('pitchTypes/initialize').then(() => {
|
||||
router.push({ path: '/home'});
|
||||
}, error => {
|
||||
PitchTypeService.fetchAll().then((pitchTypes: PitchType[]) => {
|
||||
store.commit('pitchTypes/initialize', pitchTypes);
|
||||
router.push({path: '/home'});
|
||||
}, (error) => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,20 +4,21 @@ import { useRouter } from "vue-router";
|
|||
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar, IonList, IonItem, IonLabel } from '@ionic/vue';
|
||||
import UserService from "@/services/UserService";
|
||||
import User from "@/types/User";
|
||||
import BullpenSessionService from "@/services/BullpenSessionService";
|
||||
// import BullpenSessionService from "@/services/BullpenSessionService";
|
||||
|
||||
const pitchers = ref<User[]>([]);
|
||||
const router = useRouter();
|
||||
const bps = ref(BullpenSessionService);
|
||||
// const bps = ref(BullpenSessionService);
|
||||
|
||||
bps.value.clear();
|
||||
// bps.value.clear();
|
||||
|
||||
onMounted(async () => {
|
||||
pitchers.value = await UserService.getAllUsers();
|
||||
pitchers.value = await UserService.fetchAll();
|
||||
});
|
||||
|
||||
const goToPreparePitch = (pitcher: User) => {
|
||||
bps.value.startSession( pitcher );
|
||||
console.log(pitcher);
|
||||
// bps.value.startSession( pitcher );
|
||||
router.push({ path: '/bullpen' });
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,12 @@ const saveServerAddress = () => {
|
|||
<ion-content class="ion-padding">
|
||||
<ion-row>
|
||||
<ion-col class="ion-padding">
|
||||
<ion-input name="ipaddress" v-model="server.host" type="text" required placeholder="Enter server address"></ion-input>
|
||||
<ion-input name="ipaddress" v-model="server.host" type="text" required placeholder="Bullpen Server"></ion-input>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
<ion-row>
|
||||
<ion-col>
|
||||
<ion-input name="port" v-model="server.port" type="number" required placeholder="Port"></ion-input>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
<ion-row>
|
||||
|
|
|
|||
|
|
@ -3,27 +3,26 @@ FROM node:${NODE_VERSION}-alpine AS base
|
|||
WORKDIR /user/src/app
|
||||
EXPOSE 8080
|
||||
|
||||
FROM base as production
|
||||
FROM base AS production
|
||||
ENV NODE_ENV=production
|
||||
COPY .env.production .env
|
||||
RUN --mount=type=bind,source=package.json,target=package.json \
|
||||
--mount=type=bind,source=package-lock.json,target=package-lock.json \
|
||||
--mount=type=cache,target=/root/.npm \
|
||||
npm ci --omit=dev
|
||||
USER node
|
||||
COPY . .
|
||||
EXPOSE 8080
|
||||
COPY .env.production .env
|
||||
CMD ["node", "server.js"]
|
||||
|
||||
FROM base as development
|
||||
FROM base AS development
|
||||
ENV NODE_ENV=development
|
||||
COPY .env.development .env
|
||||
RUN --mount=type=bind,source=package.json,target=package.json \
|
||||
--mount=type=bind,source=package-lock.json,target=package-lock.json \
|
||||
--mount=type=cache,target=/root/.npm \
|
||||
npm ci --include=dev
|
||||
USER node
|
||||
COPY . .
|
||||
COPY .env.development .env
|
||||
CMD ["npm", "run", "start:dev"]
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3,23 +3,13 @@ const cors = require("cors");
|
|||
|
||||
const app = express();
|
||||
|
||||
const corsOptions = {
|
||||
origin: "http://localhost:5173"
|
||||
};
|
||||
app.use(cors());
|
||||
|
||||
app.use(cors(corsOptions));
|
||||
// parse requests of content-type - application/json
|
||||
app.use(express.json());
|
||||
// parse requests of content-type - application/x-www-form-urlencoded
|
||||
app.use(express.urlencoded({ extended: true }));
|
||||
|
||||
// db.sequelize.sync();
|
||||
// force: true will drop the table if it already exists
|
||||
// db.sequelize.sync({force: true}).then(() => {
|
||||
// console.log('Drop and Re-sync Database with { force: true }');
|
||||
// initial();
|
||||
// });
|
||||
|
||||
// routes
|
||||
require('./routes/info.routes')(app);
|
||||
require('./routes/auth.routes')(app);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,6 @@ module.exports = {
|
|||
// jwtRefreshExpiration: 86400, // 24 hours
|
||||
|
||||
/* for test */
|
||||
jwtExpiration: 60, // 1 minute
|
||||
jwtRefreshExpiration: 120 // 2 minutes
|
||||
jwtExpiration: 30, // 30 seconds
|
||||
jwtRefreshExpiration: 60 // 1 minute
|
||||
};
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ exports.refreshToken = async (req, res) => {
|
|||
return;
|
||||
}
|
||||
|
||||
let newAccessToken = jwt.sign({ id: auth.id }, config.secret, {
|
||||
let newAccessToken = jwt.sign({ id: refreshToken.authId }, config.secret, {
|
||||
expiresIn: config.jwtExpiration,
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
test123!
|
||||
|
|
@ -21,9 +21,10 @@ services:
|
|||
timeout: 5s
|
||||
retries: 5
|
||||
app:
|
||||
build:
|
||||
context: .
|
||||
target: development
|
||||
image: git.palaeomatiker.home64.de/sascha/bullpen:latest
|
||||
# build:
|
||||
# context: .
|
||||
# target: development
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
|
|
@ -31,7 +32,7 @@ services:
|
|||
- "8124:8080"
|
||||
container_name: bullpen
|
||||
environment:
|
||||
NODE_ENV: development
|
||||
NODE_ENV: production
|
||||
POSTGRES_HOST: ${DB_HOST}
|
||||
POSTGRES_USER: ${DB_USER}
|
||||
POSTGRES_PASSWORD_FILE: /run/secrets/db-password
|
||||
|
|
|
|||
|
|
@ -46,28 +46,28 @@ const isAdmin = (req, res, next) => {
|
|||
});
|
||||
};
|
||||
|
||||
const isModerator = (req, res, next) => {
|
||||
const isCoach = (req, res, next) => {
|
||||
User.findByPk(req.userId).then(user => {
|
||||
user.getRoles().then(roles => {
|
||||
for (let i = 0; i < roles.length; i++) {
|
||||
if (roles[i].name === "moderator") {
|
||||
if (roles[i].name === "coach") {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
res.status(403).send({
|
||||
message: "Require Moderator Role!"
|
||||
message: "Require Coach Role!"
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const isModeratorOrAdmin = (req, res, next) => {
|
||||
const isCoachOrAdmin = (req, res, next) => {
|
||||
User.findByPk(req.userId).then(user => {
|
||||
user.getRoles().then(roles => {
|
||||
for (let i = 0; i < roles.length; i++) {
|
||||
if (roles[i].name === "moderator") {
|
||||
if (roles[i].name === "coach") {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
|
@ -79,7 +79,7 @@ const isModeratorOrAdmin = (req, res, next) => {
|
|||
}
|
||||
|
||||
res.status(403).send({
|
||||
message: "Require Moderator or Admin Role!"
|
||||
message: "Require Coach or Admin Role!"
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -88,7 +88,7 @@ const isModeratorOrAdmin = (req, res, next) => {
|
|||
const authJwt = {
|
||||
verifyToken: verifyToken,
|
||||
isAdmin: isAdmin,
|
||||
isModerator: isModerator,
|
||||
isModeratorOrAdmin: isModeratorOrAdmin
|
||||
isModerator: isCoach,
|
||||
isModeratorOrAdmin: isCoachOrAdmin
|
||||
};
|
||||
module.exports = authJwt;
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
"bcryptjs": "^3.0.2",
|
||||
"body-parser": "^1.20.3",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.5.0",
|
||||
"express": "^4.21.2",
|
||||
"express-validator": "^7.2.1",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
|
|
@ -35,17 +36,16 @@
|
|||
"pg-hstore": "^2.3.4",
|
||||
"process": "^0.11.10",
|
||||
"sequelize": "^6.37.5",
|
||||
"sequelize-cli": "^6.6.2",
|
||||
"sqlite3": "^5.1.7",
|
||||
"uuid": "^11.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@jest/globals": "^29.7.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"dotenv": "^16.5.0",
|
||||
"dotenv-cli": "^8.0.0",
|
||||
"jest": "^29.7.0",
|
||||
"nodemon": "^3.1.9",
|
||||
"sequelize-cli": "^6.6.2",
|
||||
"supertest": "^7.0.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
# Replace with your actual Gitea Docker registry
|
||||
REGISTRY_URL=git.palaeomatiker.home64.de
|
||||
IMAGE_NAME=express-sequelize-app
|
||||
IMAGE_NAME=bullpen
|
||||
TAG=latest
|
||||
|
||||
# Authenticate with Docker registry
|
||||
|
|
|
|||
|
|
@ -1,6 +1,20 @@
|
|||
# Build and push docker image
|
||||
|
||||
```bash
|
||||
docker buildx build --target production -t bullpen:latest .
|
||||
docker tag bullpen git.palaeomatiker.home64.de/sascha/bullpen:latest
|
||||
|
||||
docker login git.paleaomatiker.home64.de
|
||||
|
||||
docker push git.palaeomatiker.home64.de/sascha/bullpen:latest
|
||||
|
||||
docker logout git.paleaomatiker.home64.de
|
||||
```
|
||||
|
||||
```bash
|
||||
docker-compose up --build -d
|
||||
docker-compose exec app npx sequelize-cli db:migrate
|
||||
docker-compose exec app npx sequelize-cli db:seed:all
|
||||
|
||||
docker-compose exec app sh
|
||||
```
|
||||
|
|
|
|||
|
|
@ -7,11 +7,15 @@ module.exports = {
|
|||
if (process.env.NODE_ENV !== 'production') return;
|
||||
|
||||
await queryInterface.bulkInsert('Authentications', [
|
||||
{ email: 'admin@example.com', password: bcrypt.hashSync('admin$123', 8), createdAt: new Date(), updatedAt: new Date() }
|
||||
{ email: 'admin@example.com', password: bcrypt.hashSync('admin$123', 8), createdAt: new Date(), updatedAt: new Date() },
|
||||
{ email: 'kuehl.julian@gmail.com', password: bcrypt.hashSync('julian$123', 8), createdAt: new Date(), updatedAt: new Date() },
|
||||
{ email: 'cichocki.c@gmail.com', password: bcrypt.hashSync('clemens$123', 8), createdAt: new Date(), updatedAt: new Date() }
|
||||
]);
|
||||
|
||||
const auths = await queryInterface.select(null, 'Authentications');
|
||||
const adminAuthId = auths.filter((auth) => auth.email === 'admin@example.com').map((auth) => auth.id).shift();
|
||||
const julianAuthId = auths.filter((auth) => auth.email === 'kuehl.julian@gmail.com').map((auth) => auth.id).shift();
|
||||
const clemensAuthId = auths.filter((auth) => auth.email === 'cichocki.c@gmail.com').map((auth) => auth.id).shift();
|
||||
|
||||
await queryInterface.bulkInsert('Users', [{
|
||||
firstName: 'Admin',
|
||||
|
|
@ -21,19 +25,40 @@ module.exports = {
|
|||
authId: adminAuthId,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
}]
|
||||
);
|
||||
}, {
|
||||
firstName: 'Julian',
|
||||
lastName: 'Kühl',
|
||||
dateOfBirth: '2009-08-08',
|
||||
gender: 'male',
|
||||
authId: julianAuthId,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
}, {
|
||||
firstName: 'Clemens',
|
||||
lastName: 'Cichocki',
|
||||
dateOfBirth: '1970-01-01',
|
||||
gender: 'male',
|
||||
authId: clemensAuthId,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
}]);
|
||||
|
||||
const users = await queryInterface.select(null, 'Users');
|
||||
const adminUserId = users.filter((user) => user.firstName === 'Admin').map((user) => user.id).shift();
|
||||
const julianUserId = users.filter((user) => user.firstName === 'Julian').map((user) => user.id).shift();
|
||||
const clemensUserId = users.filter((user) => user.firstName === 'Clemens').map((user) => user.id).shift();
|
||||
|
||||
const roles = await queryInterface.select(null, 'Roles');
|
||||
const adminRoleId = roles.filter((role) => role.name === 'admin').map((role) => role.id).shift();
|
||||
const playerRoleId = roles.filter((role) => role.name === 'player').map((role) => role.id).shift();
|
||||
const coachRoleId = roles.filter((role) => role.name === 'coach').map((role) => role.id).shift();
|
||||
|
||||
await queryInterface.bulkInsert('UserRoles', [
|
||||
{ userId: adminUserId, roleId: adminRoleId, createdAt: new Date(), updatedAt: new Date() }
|
||||
{ userId: adminUserId, roleId: adminRoleId, createdAt: new Date(), updatedAt: new Date() },
|
||||
{ userId: julianUserId, roleId: playerRoleId, createdAt: new Date(), updatedAt: new Date() },
|
||||
{ userId: clemensUserId, roleId: coachRoleId, createdAt: new Date(), updatedAt: new Date() },
|
||||
{ userId: clemensUserId, roleId: playerRoleId, createdAt: new Date(), updatedAt: new Date() },
|
||||
]);
|
||||
|
||||
},
|
||||
|
||||
async down (queryInterface, /*Sequelize*/) {
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ describe("Test bullpen session", () => {
|
|||
const user = response.body;
|
||||
|
||||
response = await request(app)
|
||||
.get("/api/bullpen_session")
|
||||
.get("/api/bullpen_session", { params: { user: user.id } })
|
||||
.set('x-access-token', user.accessToken)
|
||||
.query({ user: user.id });
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue