Compare commits
No commits in common. "6f49053dacdfa2d858d0ac851d02f96f7770b88f" and "e1c6a7bb14a568eeb8814b85039c96a3a4f9db7e" have entirely different histories.
6f49053dac
...
e1c6a7bb14
|
@ -16,8 +16,7 @@ export type { CreateEventJson } from './models/CreateEventJson';
|
||||||
export type { CreateTeamJson } from './models/CreateTeamJson';
|
export type { CreateTeamJson } from './models/CreateTeamJson';
|
||||||
export type { EditMemberRolesJson } from './models/EditMemberRolesJson';
|
export type { EditMemberRolesJson } from './models/EditMemberRolesJson';
|
||||||
export type { EventSchema } from './models/EventSchema';
|
export type { EventSchema } from './models/EventSchema';
|
||||||
export type { EventWithPlayerSchema } from './models/EventWithPlayerSchema';
|
export type { EventSchemaList } from './models/EventSchemaList';
|
||||||
export type { EventWithPlayerSchemaList } from './models/EventWithPlayerSchemaList';
|
|
||||||
export type { GetEventPlayersResponse } from './models/GetEventPlayersResponse';
|
export type { GetEventPlayersResponse } from './models/GetEventPlayersResponse';
|
||||||
export type { PlayerEventRolesSchema } from './models/PlayerEventRolesSchema';
|
export type { PlayerEventRolesSchema } from './models/PlayerEventRolesSchema';
|
||||||
export type { PlayerRoleSchema } from './models/PlayerRoleSchema';
|
export type { PlayerRoleSchema } from './models/PlayerRoleSchema';
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
/* generated using openapi-typescript-codegen -- do not edit */
|
||||||
|
/* istanbul ignore file */
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
import type { EventSchema } from './EventSchema';
|
||||||
|
export type EventSchemaList = Array<EventSchema>;
|
|
@ -1,11 +0,0 @@
|
||||||
/* generated using openapi-typescript-codegen -- do not edit */
|
|
||||||
/* istanbul ignore file */
|
|
||||||
/* tslint:disable */
|
|
||||||
/* eslint-disable */
|
|
||||||
import type { EventSchema } from './EventSchema';
|
|
||||||
import type { PlayerEventRolesSchema } from './PlayerEventRolesSchema';
|
|
||||||
export type EventWithPlayerSchema = {
|
|
||||||
event: EventSchema;
|
|
||||||
playerEvent: (PlayerEventRolesSchema | null);
|
|
||||||
};
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
/* generated using openapi-typescript-codegen -- do not edit */
|
|
||||||
/* istanbul ignore file */
|
|
||||||
/* tslint:disable */
|
|
||||||
/* eslint-disable */
|
|
||||||
import type { EventWithPlayerSchema } from './EventWithPlayerSchema';
|
|
||||||
export type EventWithPlayerSchemaList = Array<EventWithPlayerSchema>;
|
|
|
@ -4,7 +4,6 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
export type TeamDiscordIntegrationSchema = {
|
export type TeamDiscordIntegrationSchema = {
|
||||||
webhookBotName: string;
|
webhookBotName: string;
|
||||||
webhookBotProfilePicture: (string | null);
|
|
||||||
webhookUrl: string;
|
webhookUrl: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,7 @@ import type { CreateEventJson } from '../models/CreateEventJson';
|
||||||
import type { CreateTeamJson } from '../models/CreateTeamJson';
|
import type { CreateTeamJson } from '../models/CreateTeamJson';
|
||||||
import type { EditMemberRolesJson } from '../models/EditMemberRolesJson';
|
import type { EditMemberRolesJson } from '../models/EditMemberRolesJson';
|
||||||
import type { EventSchema } from '../models/EventSchema';
|
import type { EventSchema } from '../models/EventSchema';
|
||||||
import type { EventWithPlayerSchema } from '../models/EventWithPlayerSchema';
|
import type { EventSchemaList } from '../models/EventSchemaList';
|
||||||
import type { EventWithPlayerSchemaList } from '../models/EventWithPlayerSchemaList';
|
|
||||||
import type { GetEventPlayersResponse } from '../models/GetEventPlayersResponse';
|
import type { GetEventPlayersResponse } from '../models/GetEventPlayersResponse';
|
||||||
import type { PlayerSchema } from '../models/PlayerSchema';
|
import type { PlayerSchema } from '../models/PlayerSchema';
|
||||||
import type { PutScheduleForm } from '../models/PutScheduleForm';
|
import type { PutScheduleForm } from '../models/PutScheduleForm';
|
||||||
|
@ -51,12 +50,12 @@ export class DefaultService {
|
||||||
/**
|
/**
|
||||||
* get_team_events <GET>
|
* get_team_events <GET>
|
||||||
* @param teamId
|
* @param teamId
|
||||||
* @returns EventWithPlayerSchemaList OK
|
* @returns EventSchemaList OK
|
||||||
* @throws ApiError
|
* @throws ApiError
|
||||||
*/
|
*/
|
||||||
public getTeamEvents(
|
public getTeamEvents(
|
||||||
teamId: number,
|
teamId: number,
|
||||||
): CancelablePromise<EventWithPlayerSchemaList> {
|
): CancelablePromise<EventSchemaList> {
|
||||||
return this.httpRequest.request({
|
return this.httpRequest.request({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: '/api/events/team/id/{team_id}',
|
url: '/api/events/team/id/{team_id}',
|
||||||
|
@ -129,46 +128,6 @@ export class DefaultService {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* unattend_event <DELETE>
|
|
||||||
* @param eventId
|
|
||||||
* @returns EventWithPlayerSchema OK
|
|
||||||
* @throws ApiError
|
|
||||||
*/
|
|
||||||
public unattendEvent(
|
|
||||||
eventId: number,
|
|
||||||
): CancelablePromise<EventWithPlayerSchema> {
|
|
||||||
return this.httpRequest.request({
|
|
||||||
method: 'DELETE',
|
|
||||||
url: '/api/events/{event_id}/attendance',
|
|
||||||
path: {
|
|
||||||
'event_id': eventId,
|
|
||||||
},
|
|
||||||
errors: {
|
|
||||||
422: `Unprocessable Content`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* attend_event <PUT>
|
|
||||||
* @param eventId
|
|
||||||
* @returns EventWithPlayerSchema OK
|
|
||||||
* @throws ApiError
|
|
||||||
*/
|
|
||||||
public attendEvent(
|
|
||||||
eventId: number,
|
|
||||||
): CancelablePromise<EventWithPlayerSchema> {
|
|
||||||
return this.httpRequest.request({
|
|
||||||
method: 'PUT',
|
|
||||||
url: '/api/events/{event_id}/attendance',
|
|
||||||
path: {
|
|
||||||
'event_id': eventId,
|
|
||||||
},
|
|
||||||
errors: {
|
|
||||||
422: `Unprocessable Content`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* get_event_players <GET>
|
* get_event_players <GET>
|
||||||
* @param eventId
|
* @param eventId
|
||||||
|
@ -206,6 +165,52 @@ export class DefaultService {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* unattend_event <DELETE>
|
||||||
|
* @param eventId
|
||||||
|
* @param teamId
|
||||||
|
* @returns void
|
||||||
|
* @throws ApiError
|
||||||
|
*/
|
||||||
|
public deleteApiEventsEventIdTeamIdTeamIdAttendance(
|
||||||
|
eventId: number,
|
||||||
|
teamId: number,
|
||||||
|
): CancelablePromise<void> {
|
||||||
|
return this.httpRequest.request({
|
||||||
|
method: 'DELETE',
|
||||||
|
url: '/api/events/{event_id}/team/id/{team_id}/attendance',
|
||||||
|
path: {
|
||||||
|
'event_id': eventId,
|
||||||
|
'team_id': teamId,
|
||||||
|
},
|
||||||
|
errors: {
|
||||||
|
422: `Unprocessable Content`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* attend_event <PUT>
|
||||||
|
* @param eventId
|
||||||
|
* @param teamId
|
||||||
|
* @returns void
|
||||||
|
* @throws ApiError
|
||||||
|
*/
|
||||||
|
public putApiEventsEventIdTeamIdTeamIdAttendance(
|
||||||
|
eventId: number,
|
||||||
|
teamId: number,
|
||||||
|
): CancelablePromise<void> {
|
||||||
|
return this.httpRequest.request({
|
||||||
|
method: 'PUT',
|
||||||
|
url: '/api/events/{event_id}/team/id/{team_id}/attendance',
|
||||||
|
path: {
|
||||||
|
'event_id': eventId,
|
||||||
|
'team_id': teamId,
|
||||||
|
},
|
||||||
|
errors: {
|
||||||
|
422: `Unprocessable Content`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* logout <DELETE>
|
* logout <DELETE>
|
||||||
* @returns void
|
* @returns void
|
||||||
|
|
|
@ -16,7 +16,6 @@ function enableIntegration() {
|
||||||
model.value = {
|
model.value = {
|
||||||
webhookUrl: "",
|
webhookUrl: "",
|
||||||
webhookBotName: "",
|
webhookBotName: "",
|
||||||
webhookBotProfilePicture: null,
|
|
||||||
};
|
};
|
||||||
saveIntegration();
|
saveIntegration();
|
||||||
}
|
}
|
||||||
|
@ -39,10 +38,6 @@ function disableIntegration() {
|
||||||
<h3>Webhook Bot Name</h3>
|
<h3>Webhook Bot Name</h3>
|
||||||
<input v-model="model.webhookBotName">
|
<input v-model="model.webhookBotName">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group margin">
|
|
||||||
<h3>Webhook Bot Profile Picture URL (optional)</h3>
|
|
||||||
<input v-model="model.webhookBotProfilePicture">
|
|
||||||
</div>
|
|
||||||
<div class="form-group margin">
|
<div class="form-group margin">
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<button class="destructive-on-hover" @click="disableIntegration">
|
<button class="destructive-on-hover" @click="disableIntegration">
|
||||||
|
|
|
@ -1,19 +1,15 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { EventSchema, EventWithPlayerSchema } from "@/client";
|
import type { EventSchema } from "@/client";
|
||||||
import { useRosterStore } from "@/stores/roster";
|
|
||||||
import { useTeamsStore } from "@/stores/teams";
|
import { useTeamsStore } from "@/stores/teams";
|
||||||
import { useTeamsEventsStore } from "@/stores/teams/events";
|
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
|
|
||||||
const teamsStore = useTeamsStore();
|
const teamsStore = useTeamsStore();
|
||||||
const rosterStore = useRosterStore();
|
|
||||||
const teamEventsStore = useTeamsEventsStore();
|
|
||||||
|
|
||||||
const date = computed(() => moment(props.event.event.startTime));
|
const date = computed(() => moment(props.event.startTime));
|
||||||
|
|
||||||
const formattedTime = computed(() => {
|
const formattedTime = computed(() => {
|
||||||
const team = teamsStore.teams[props.event.event.teamId];
|
const team = teamsStore.teams[props.event.teamId];
|
||||||
const offsetDate = date.value.clone().tz(team.tzTimezone);
|
const offsetDate = date.value.clone().tz(team.tzTimezone);
|
||||||
return `${date.value.format("LT")} (${offsetDate.format("LT z")})`;
|
return `${date.value.format("LT")} (${offsetDate.format("LT z")})`;
|
||||||
});
|
});
|
||||||
|
@ -27,24 +23,8 @@ const shortMonth = computed(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
event: EventWithPlayerSchema;
|
event: EventSchema;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
function attend() {
|
|
||||||
teamEventsStore.attendEvent(props.event.event.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
function unattend() {
|
|
||||||
teamEventsStore.unattendEvent(props.event.event.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
function attendOrUnattend() {
|
|
||||||
if (props.event.playerEvent?.hasConfirmed) {
|
|
||||||
unattend();
|
|
||||||
} else {
|
|
||||||
attend();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -59,7 +39,7 @@ function attendOrUnattend() {
|
||||||
</div>
|
</div>
|
||||||
<div class="details">
|
<div class="details">
|
||||||
<div>
|
<div>
|
||||||
<h3>{{ event.event.name }}</h3>
|
<h3>{{ event.name }}</h3>
|
||||||
<div>
|
<div>
|
||||||
<span>
|
<span>
|
||||||
<i class="bi bi-clock-fill margin" />
|
<i class="bi bi-clock-fill margin" />
|
||||||
|
@ -68,33 +48,11 @@ function attendOrUnattend() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="subdetails">
|
<div class="subdetails">
|
||||||
<span v-if="event.event.description">{{ event.event.description }}</span>
|
<span v-if="event.description">{{ event.description }}</span>
|
||||||
<em v-else class="subtext">No description provided.</em>
|
<em v-else class="subtext">No description provided.</em>
|
||||||
</div>
|
<button class="class-info">
|
||||||
<div class="button-group">
|
<i class="tf2class tf2-PocketScout margin" />
|
||||||
<button
|
Accept as Pocket Scout
|
||||||
@click="attendOrUnattend()"
|
|
||||||
v-if="event.playerEvent"
|
|
||||||
:class="{
|
|
||||||
'class-info': true,
|
|
||||||
'confirmed': event.playerEvent.hasConfirmed,
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<template v-if="!event.playerEvent.hasConfirmed">
|
|
||||||
<i class="bi bi-check2" />
|
|
||||||
Confirm
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<i class="bi bi-check2-all" />
|
|
||||||
Confirmed
|
|
||||||
</template>
|
|
||||||
<span v-if="event.playerEvent.role">
|
|
||||||
as {{ rosterStore.roleNames[event.playerEvent.role.role] }}
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
<button @click="attend" v-else>
|
|
||||||
<i class="bi bi-check2" />
|
|
||||||
Attend
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -104,8 +62,11 @@ function attendOrUnattend() {
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.event-card {
|
.event-card {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
padding: 1rem;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
/*background-color: white;*/
|
/*background-color: white;*/
|
||||||
|
border: 1px solid var(--text);
|
||||||
|
border-radius: 8px;
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,10 +77,6 @@ function attendOrUnattend() {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
flex-basis: 4rem;
|
flex-basis: 4rem;
|
||||||
padding: 1rem;
|
|
||||||
background-color: var(--text);
|
|
||||||
color: var(--base);
|
|
||||||
border-radius: 8px 0 0 8px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.date .month {
|
.date .month {
|
||||||
|
@ -134,12 +91,8 @@ function attendOrUnattend() {
|
||||||
}
|
}
|
||||||
|
|
||||||
.details {
|
.details {
|
||||||
padding: 1rem;
|
|
||||||
border: 1px solid var(--text);
|
|
||||||
border-radius: 0 8px 8px 0;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: 100%;
|
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,15 +110,4 @@ function attendOrUnattend() {
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-group {
|
|
||||||
display: flex;
|
|
||||||
gap: 0.5rem;
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.confirmed {
|
|
||||||
background-color: var(--text);
|
|
||||||
color: var(--base);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { EventWithPlayerSchema } from "@/client";
|
import type { EventSchema } from "@/client";
|
||||||
import EventCard from "./EventCard.vue";
|
import EventCard from "./EventCard.vue";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
events: EventWithPlayerSchema[];
|
events: EventSchema[];
|
||||||
}>();
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="events-list" v-if="props.events?.length > 0">
|
<div class="events-list" v-if="props.events?.length > 0">
|
||||||
<EventCard v-for="event in props.events" :key="event.event.id" :event="event" />
|
<EventCard v-for="event in props.events" :key="event.id" :event="event" />
|
||||||
</div>
|
</div>
|
||||||
<div class="events-list" v-else>
|
<div class="events-list" v-else>
|
||||||
<em class="subtext">No upcoming events.</em>
|
<em class="subtext">No upcoming events.</em>
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
<script setup lang="ts">
|
|
||||||
import { useRosterStore } from "@/stores/roster";
|
|
||||||
import moment from "moment";
|
|
||||||
import { useRoute, useRouter } from "vue-router";
|
|
||||||
|
|
||||||
const route = useRoute();
|
|
||||||
const router = useRouter();
|
|
||||||
|
|
||||||
const rosterStore = useRosterStore();
|
|
||||||
|
|
||||||
function saveRoster() {
|
|
||||||
rosterStore.saveRoster(Number(route.params.teamId))
|
|
||||||
.then(() => {
|
|
||||||
router.push({
|
|
||||||
name: "team-details",
|
|
||||||
params: {
|
|
||||||
id: route.params.teamId
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="event-scheduler-container">
|
|
||||||
<h1 class="roster-title">
|
|
||||||
Roster for Snus Brotherhood
|
|
||||||
</h1>
|
|
||||||
<div v-if="rosterStore.startTime">
|
|
||||||
<span class="aside date">
|
|
||||||
{{ moment.unix(rosterStore.startTime).format("LL LT") }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="form-group margin">
|
|
||||||
<h3>Event Name</h3>
|
|
||||||
<input v-model="rosterStore.title" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group margin">
|
|
||||||
<h3>Description (optional)</h3>
|
|
||||||
<input v-model="rosterStore.description" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group margin">
|
|
||||||
<div class="action-buttons">
|
|
||||||
<button class="accent" @click="saveRoster">Save roster</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
em.aside.date {
|
|
||||||
font-size: 11pt;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,14 +0,0 @@
|
||||||
import type { PlayerRoleSchema } from "@/client";
|
|
||||||
import { ref } from "vue";
|
|
||||||
|
|
||||||
export function useEventForm() {
|
|
||||||
const title = ref("");
|
|
||||||
const description = ref("");
|
|
||||||
const players = ref<PlayerRoleSchema[]>([]);
|
|
||||||
|
|
||||||
return {
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
players,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,7 +6,6 @@ import { type EventSchema, type CreateEventJson, type PlayerRoleSchema } from "@
|
||||||
import { useTeamDetails } from "@/composables/team-details";
|
import { useTeamDetails } from "@/composables/team-details";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { useRoute, useRouter } from "vue-router";
|
import { useRoute, useRouter } from "vue-router";
|
||||||
import { useEventForm } from "@/composables/event-form";
|
|
||||||
|
|
||||||
export const useRosterStore = defineStore("roster", () => {
|
export const useRosterStore = defineStore("roster", () => {
|
||||||
const clientStore = useClientStore();
|
const clientStore = useClientStore();
|
||||||
|
@ -170,8 +169,6 @@ export const useRosterStore = defineStore("roster", () => {
|
||||||
|
|
||||||
const startTime = ref<number>();
|
const startTime = ref<number>();
|
||||||
|
|
||||||
const { title, description } = useEventForm();
|
|
||||||
|
|
||||||
function saveRoster(teamId: number) {
|
function saveRoster(teamId: number) {
|
||||||
if (startTime.value == undefined) {
|
if (startTime.value == undefined) {
|
||||||
throw new Error("No start time set");
|
throw new Error("No start time set");
|
||||||
|
@ -179,8 +176,8 @@ export const useRosterStore = defineStore("roster", () => {
|
||||||
|
|
||||||
if (!currentEvent.value) {
|
if (!currentEvent.value) {
|
||||||
const body: CreateEventJson = {
|
const body: CreateEventJson = {
|
||||||
name: title.value,
|
name: "Test",
|
||||||
description: description.value,
|
description: "test description",
|
||||||
startTime: startTime.value.toString(),
|
startTime: startTime.value.toString(),
|
||||||
playerRoles: Object.values(selectedPlayers).map((player) => ({
|
playerRoles: Object.values(selectedPlayers).map((player) => ({
|
||||||
player: {
|
player: {
|
||||||
|
@ -194,10 +191,12 @@ export const useRosterStore = defineStore("roster", () => {
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
|
|
||||||
return clientStore.client.default.createEvent(teamId, body);
|
clientStore.client.default.createEvent(teamId, body)
|
||||||
|
.then(() => {
|
||||||
|
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
// TODO: update event
|
// TODO: update event
|
||||||
throw "Not implemented";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,7 +217,5 @@ export const useRosterStore = defineStore("roster", () => {
|
||||||
fetchPlayersFromEvent,
|
fetchPlayersFromEvent,
|
||||||
startTime,
|
startTime,
|
||||||
saveRoster,
|
saveRoster,
|
||||||
title,
|
|
||||||
description,
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,62 +1,45 @@
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { useClientStore } from "../client";
|
import { useClientStore } from "../client";
|
||||||
import type { EventWithPlayerSchema } from "@/client";
|
import type { EventSchema, EventSchemaList } from "@/client";
|
||||||
import { useEventsStore } from "../events";
|
import { useEventsStore } from "../events";
|
||||||
import { computed, reactive } from "vue";
|
import { computed } from "vue";
|
||||||
|
|
||||||
export const useTeamsEventsStore = defineStore("teamsEvents", () => {
|
export const useTeamsEventsStore = defineStore("teamsEvents", () => {
|
||||||
const clientStore = useClientStore();
|
const clientStore = useClientStore();
|
||||||
const client = clientStore.client;
|
const client = clientStore.client;
|
||||||
//const eventsStore = useEventsStore();
|
const eventsStore = useEventsStore();
|
||||||
|
|
||||||
const teamEvents = reactive<{ [teamId: number]: EventWithPlayerSchema[] }>({ });
|
const teamEvents = computed(() => {
|
||||||
//const teamEvents = computed(() => {
|
console.log("Recomputing teamEvents");
|
||||||
// console.log("Recomputing teamEvents");
|
|
||||||
|
|
||||||
// // map events to objects with teamId as key, and array of events as value
|
// map events to objects with teamId as key, and array of events as value
|
||||||
// return eventsStore.events
|
return eventsStore.events
|
||||||
// .reduce((acc, event) => {
|
.reduce((acc, event) => {
|
||||||
// if (!acc[event.teamId]) {
|
if (!acc[event.teamId]) {
|
||||||
// acc[event.teamId] = [];
|
acc[event.teamId] = [];
|
||||||
// }
|
}
|
||||||
// acc[event.teamId].push(event);
|
acc[event.teamId].push(event);
|
||||||
// return acc;
|
return acc;
|
||||||
// }, { } as { [teamId: number]: EventSchema[] });
|
}, { } as { [teamId: number]: EventSchema[] });
|
||||||
//});
|
});
|
||||||
|
|
||||||
function fetchTeamEvents(teamId: number) {
|
function fetchTeamEvents(teamId: number) {
|
||||||
return clientStore.call(
|
return clientStore.call(
|
||||||
fetchTeamEvents.name,
|
fetchTeamEvents.name,
|
||||||
() => client.default.getTeamEvents(teamId),
|
() => client.default.getTeamEvents(teamId),
|
||||||
(result: EventWithPlayerSchema[]) => {
|
(result: EventSchemaList) => {
|
||||||
teamEvents[teamId] = result;
|
result.forEach((event) => {
|
||||||
|
// insert into event store
|
||||||
|
//eventsStore.events[event.id] = event;
|
||||||
|
eventsStore.events.push(event);
|
||||||
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function attendEvent(eventId: number) {
|
|
||||||
client.default.attendEvent(eventId)
|
|
||||||
.then((response) => {
|
|
||||||
let index = teamEvents[response.event.teamId]
|
|
||||||
.findIndex((event) => event.event.id == response.event.id);
|
|
||||||
teamEvents[response.event.teamId][index] = response;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function unattendEvent(eventId: number) {
|
|
||||||
client.default.unattendEvent(eventId)
|
|
||||||
.then((response) => {
|
|
||||||
let index = teamEvents[response.event.teamId]
|
|
||||||
.findIndex((event) => event.event.id == response.event.id);
|
|
||||||
teamEvents[response.event.teamId][index].playerEvent = null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
teamEvents,
|
teamEvents,
|
||||||
fetchTeamEvents,
|
fetchTeamEvents,
|
||||||
attendEvent,
|
|
||||||
unattendEvent,
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import PlayerCard from "../components/PlayerCard.vue";
|
import PlayerCard from "../components/PlayerCard.vue";
|
||||||
|
import RoleSlot from "../components/RoleSlot.vue";
|
||||||
|
import PlayerTeamRole from "../player.ts";
|
||||||
import { computed, reactive, onMounted } from "vue";
|
import { computed, reactive, onMounted } from "vue";
|
||||||
import { useRosterStore } from "../stores/roster";
|
import { useRosterStore } from "../stores/roster";
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { useEventsStore } from "@/stores/events";
|
import { useEventsStore } from "@/stores/events";
|
||||||
import EventSchedulerForm from "@/components/EventSchedulerForm.vue";
|
|
||||||
|
|
||||||
const rosterStore = useRosterStore();
|
const rosterStore = useRosterStore();
|
||||||
const eventsStore = useEventsStore();
|
const eventsStore = useEventsStore();
|
||||||
|
@ -22,6 +23,10 @@ const hasAlternates = computed(() => {
|
||||||
|
|
||||||
const eventId = computed<number | undefined>(() => Number(route.params.eventId));
|
const eventId = computed<number | undefined>(() => Number(route.params.eventId));
|
||||||
|
|
||||||
|
function saveRoster() {
|
||||||
|
rosterStore.saveRoster(Number(route.params.teamId));
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
if (eventId.value) {
|
if (eventId.value) {
|
||||||
const event = await eventsStore.fetchEvent(eventId.value);
|
const event = await eventsStore.fetchEvent(eventId.value);
|
||||||
|
@ -37,19 +42,26 @@ onMounted(async () => {
|
||||||
<template>
|
<template>
|
||||||
<main>
|
<main>
|
||||||
<div class="top">
|
<div class="top">
|
||||||
<a>
|
<h1 class="roster-title">
|
||||||
<i class="bi bi-arrow-left" />
|
Roster for Snus Brotherhood
|
||||||
Back
|
<em class="aside date" v-if="rosterStore.startTime">
|
||||||
</a>
|
@
|
||||||
|
{{ moment.unix(rosterStore.startTime).format("L LT") }}
|
||||||
|
</em>
|
||||||
|
</h1>
|
||||||
|
<div class="button-group">
|
||||||
|
<button>Cancel</button>
|
||||||
|
<button class="accent" @click="saveRoster">Save Roster</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="columns">
|
<div class="columns">
|
||||||
<div class="form-group margin column">
|
<div class="column">
|
||||||
<PlayerCard v-for="role in rosterStore.neededRoles"
|
<PlayerCard v-for="role in rosterStore.neededRoles"
|
||||||
:player="rosterStore.selectedPlayers[role]"
|
:player="rosterStore.selectedPlayers[role]"
|
||||||
:role-title="role"
|
:role-title="role"
|
||||||
is-roster />
|
is-roster />
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group margin column" v-if="rosterStore.selectedRole">
|
<div class="column">
|
||||||
<PlayerCard v-for="player in rosterStore.mainRoles"
|
<PlayerCard v-for="player in rosterStore.mainRoles"
|
||||||
:player="player"
|
:player="player"
|
||||||
:role-title="player.role" />
|
:role-title="player.role" />
|
||||||
|
@ -63,15 +75,6 @@ onMounted(async () => {
|
||||||
<PlayerCard v-if="rosterStore.selectedRole"
|
<PlayerCard v-if="rosterStore.selectedRole"
|
||||||
is-ringer
|
is-ringer
|
||||||
:role-title="rosterStore.selectedRole" />
|
:role-title="rosterStore.selectedRole" />
|
||||||
<div class="action-buttons">
|
|
||||||
<button class="accent">
|
|
||||||
<i class="bi bi-check" />
|
|
||||||
Done
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="column" v-else>
|
|
||||||
<EventSchedulerForm />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
@ -117,4 +120,9 @@ onMounted(async () => {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 0.5em;
|
gap: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
em.aside.date {
|
||||||
|
font-size: 14px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -7,14 +7,12 @@
|
||||||
|
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from flask import Blueprint, abort, make_response
|
from flask import Blueprint, abort, make_response
|
||||||
from spectree import Response
|
from spectree import Response
|
||||||
from sqlalchemy import Row
|
|
||||||
from sqlalchemy.sql import tuple_
|
from sqlalchemy.sql import tuple_
|
||||||
from models.player import Player
|
from models.player import Player
|
||||||
from models.player_event import EventWithPlayerSchema, PlayerEvent, PlayerEventRolesSchema
|
from models.player_event import PlayerEvent, PlayerEventRolesSchema
|
||||||
from models.player_team_availability import PlayerTeamAvailability
|
from models.player_team_availability import PlayerTeamAvailability
|
||||||
from models.player_team_role import PlayerRoleSchema, PlayerTeamRole
|
from models.player_team_role import PlayerRoleSchema, PlayerTeamRole
|
||||||
from models.team import Team
|
from models.team import Team
|
||||||
|
@ -45,30 +43,23 @@ def get_event(event_id: int):
|
||||||
@api_events.get("/team/id/<int:team_id>")
|
@api_events.get("/team/id/<int:team_id>")
|
||||||
@spec.validate(
|
@spec.validate(
|
||||||
resp=Response(
|
resp=Response(
|
||||||
HTTP_200=list[EventWithPlayerSchema],
|
HTTP_200=list[EventSchema],
|
||||||
),
|
),
|
||||||
operation_id="get_team_events",
|
operation_id="get_team_events",
|
||||||
)
|
)
|
||||||
@requires_authentication
|
def get_team_events(team_id: int):
|
||||||
@requires_team_membership()
|
events = db.session.query(
|
||||||
def get_team_events(player_team: PlayerTeam, team_id: int, **_):
|
Event
|
||||||
rows = db.session.query(
|
).filter(
|
||||||
Event, PlayerEvent
|
|
||||||
).outerjoin(
|
|
||||||
PlayerEvent,
|
|
||||||
(PlayerEvent.event_id == Event.id) & (PlayerEvent.player_id == player_team.player_id)
|
|
||||||
).where(
|
|
||||||
Event.team_id == team_id
|
Event.team_id == team_id
|
||||||
).order_by(
|
).order_by(
|
||||||
Event.start_time
|
Event.start_time
|
||||||
).all()
|
).all()
|
||||||
|
|
||||||
def map_to_schema(row: Row[tuple[Event, PlayerEvent]]):
|
def map_to_schema(event: Event):
|
||||||
return EventWithPlayerSchema.from_event_player_event(
|
return EventSchema.from_model(event).dict(by_alias=True)
|
||||||
*row.tuple()
|
|
||||||
).dict(by_alias=True)
|
|
||||||
|
|
||||||
return list(map(map_to_schema, rows))
|
return list(map(map_to_schema, events))
|
||||||
|
|
||||||
@api_events.get("/user/id/<int:user_id>")
|
@api_events.get("/user/id/<int:user_id>")
|
||||||
def get_user_events(user_id: int):
|
def get_user_events(user_id: int):
|
||||||
|
@ -138,33 +129,28 @@ def create_event(player_team: PlayerTeam, team_id: int, json: CreateEventJson, *
|
||||||
@api_events.put("/<int:event_id>/attendance")
|
@api_events.put("/<int:event_id>/attendance")
|
||||||
@spec.validate(
|
@spec.validate(
|
||||||
resp=Response(
|
resp=Response(
|
||||||
HTTP_200=EventWithPlayerSchema,
|
HTTP_204=None,
|
||||||
),
|
)
|
||||||
operation_id="attend_event",
|
|
||||||
)
|
)
|
||||||
@requires_authentication
|
@requires_authentication
|
||||||
def attend_event(player: Player, event_id: int, **_):
|
@requires_team_membership()
|
||||||
event = db.session.query(Event).where(Event.id == event_id).one_or_none()
|
def attend_event(player_team: PlayerTeam, event_id: int, **_):
|
||||||
|
|
||||||
if not event:
|
|
||||||
abort(404)
|
|
||||||
|
|
||||||
assert_team_membership(player, event.team)
|
|
||||||
|
|
||||||
player_event = db.session.query(
|
player_event = db.session.query(
|
||||||
PlayerEvent
|
PlayerEvent
|
||||||
).where(
|
).where(
|
||||||
PlayerEvent.event_id == event_id
|
PlayerEvent.event_id == event_id
|
||||||
).where(
|
).where(
|
||||||
PlayerEvent.player_id == player.steam_id
|
PlayerEvent.player_id == player_team.player_id
|
||||||
).join(
|
).join(
|
||||||
Event
|
Event
|
||||||
|
).where(
|
||||||
|
Event.team_id == player_team.team_id
|
||||||
).one_or_none()
|
).one_or_none()
|
||||||
|
|
||||||
if not player_event:
|
if not player_event:
|
||||||
player_event = PlayerEvent()
|
player_event = PlayerEvent()
|
||||||
player_event.event_id = event_id
|
player_event.event_id = event_id
|
||||||
player_event.player_id = player.steam_id
|
player_event.player_id = player_team.player_id
|
||||||
db.session.add(player_event)
|
db.session.add(player_event)
|
||||||
|
|
||||||
player_event.has_confirmed = True
|
player_event.has_confirmed = True
|
||||||
|
@ -173,28 +159,27 @@ def attend_event(player: Player, event_id: int, **_):
|
||||||
|
|
||||||
player_event.event.update_discord_message()
|
player_event.event.update_discord_message()
|
||||||
|
|
||||||
return EventWithPlayerSchema.from_event_player_event(
|
return make_response({ }, 204)
|
||||||
player_event.event,
|
|
||||||
player_event,
|
|
||||||
).dict(by_alias=True)
|
|
||||||
|
|
||||||
@api_events.delete("/<int:event_id>/attendance")
|
@api_events.delete("/<int:event_id>/attendance")
|
||||||
@spec.validate(
|
@spec.validate(
|
||||||
resp=Response(
|
resp=Response(
|
||||||
HTTP_200=EventWithPlayerSchema,
|
HTTP_204=None,
|
||||||
),
|
)
|
||||||
operation_id="unattend_event",
|
|
||||||
)
|
)
|
||||||
@requires_authentication
|
@requires_authentication
|
||||||
def unattend_event(player: Player, event_id: int, **_):
|
@requires_team_membership()
|
||||||
|
def unattend_event(player_team: PlayerTeam, event_id: int, **_):
|
||||||
result = db.session.query(
|
result = db.session.query(
|
||||||
PlayerEvent, Event
|
PlayerEvent, Event
|
||||||
).where(
|
).where(
|
||||||
PlayerEvent.player_id == player.steam_id
|
PlayerEvent.event_id == event_id
|
||||||
|
).where(
|
||||||
|
PlayerEvent.player_id == player_team.player_id
|
||||||
).join(
|
).join(
|
||||||
Event
|
Event
|
||||||
).where(
|
).where(
|
||||||
Event.id == event_id
|
Event.team_id == player_team.team_id
|
||||||
).one_or_none()
|
).one_or_none()
|
||||||
|
|
||||||
if not result:
|
if not result:
|
||||||
|
@ -207,10 +192,7 @@ def unattend_event(player: Player, event_id: int, **_):
|
||||||
|
|
||||||
event.update_discord_message()
|
event.update_discord_message()
|
||||||
|
|
||||||
return EventWithPlayerSchema.from_event_player_event(
|
return make_response({ }, 204)
|
||||||
event,
|
|
||||||
None,
|
|
||||||
).dict(by_alias=True)
|
|
||||||
|
|
||||||
class GetEventPlayersResponse(BaseModel):
|
class GetEventPlayersResponse(BaseModel):
|
||||||
players: list[PlayerEventRolesSchema]
|
players: list[PlayerEventRolesSchema]
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
"""Add webhook profile picture
|
|
||||||
|
|
||||||
Revision ID: c242e3f99c64
|
|
||||||
Revises: 286ee26b9e5d
|
|
||||||
Create Date: 2024-11-27 10:40:39.027786
|
|
||||||
|
|
||||||
"""
|
|
||||||
from alembic import op
|
|
||||||
import sqlalchemy as sa
|
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
|
||||||
revision = 'c242e3f99c64'
|
|
||||||
down_revision = '286ee26b9e5d'
|
|
||||||
branch_labels = None
|
|
||||||
depends_on = None
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
with op.batch_alter_table('team_discord_integrations', schema=None) as batch_op:
|
|
||||||
batch_op.add_column(sa.Column('webhook_bot_profile_picture', sa.String(), nullable=True))
|
|
||||||
|
|
||||||
# ### end Alembic commands ###
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade():
|
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
|
||||||
with op.batch_alter_table('team_discord_integrations', schema=None) as batch_op:
|
|
||||||
batch_op.drop_column('webhook_bot_profile_picture')
|
|
||||||
|
|
||||||
# ### end Alembic commands ###
|
|
|
@ -1,5 +1,4 @@
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import threading
|
|
||||||
from sqlalchemy.orm import mapped_column, relationship
|
from sqlalchemy.orm import mapped_column, relationship
|
||||||
from sqlalchemy.orm.attributes import Mapped
|
from sqlalchemy.orm.attributes import Mapped
|
||||||
from sqlalchemy.orm.properties import ForeignKey
|
from sqlalchemy.orm.properties import ForeignKey
|
||||||
|
@ -64,7 +63,7 @@ class Event(app_db.BaseModel):
|
||||||
f"<t:{start_timestamp}:f>",
|
f"<t:{start_timestamp}:f>",
|
||||||
"\n".join(players_info),
|
"\n".join(players_info),
|
||||||
"",
|
"",
|
||||||
"[Confirm attendance here]" +
|
"[Confirm availability here]" +
|
||||||
f"(https://availabili.tf/team/id/{self.team.id}/events/{self.id})",
|
f"(https://availabili.tf/team/id/{self.team.id}/events/{self.id})",
|
||||||
])
|
])
|
||||||
|
|
||||||
|
@ -82,23 +81,16 @@ class Event(app_db.BaseModel):
|
||||||
return DiscordWebhook(
|
return DiscordWebhook(
|
||||||
integration.webhook_url,
|
integration.webhook_url,
|
||||||
id=str(self.discord_message_id),
|
id=str(self.discord_message_id),
|
||||||
username=integration.webhook_bot_name,
|
|
||||||
avatar_url=integration.webhook_bot_profile_picture,
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return DiscordWebhook(
|
return DiscordWebhook(integration.webhook_url)
|
||||||
integration.webhook_url,
|
|
||||||
username=integration.webhook_bot_name,
|
|
||||||
avatar_url=integration.webhook_bot_profile_picture,
|
|
||||||
)
|
|
||||||
|
|
||||||
def update_discord_message(self):
|
def update_discord_message(self):
|
||||||
webhook = self.get_or_create_webhook()
|
webhook = self.get_or_create_webhook()
|
||||||
if webhook:
|
if webhook:
|
||||||
webhook.content = self.get_discord_content()
|
webhook.content = self.get_discord_content()
|
||||||
if webhook.id:
|
if webhook.id:
|
||||||
# fire and forget
|
webhook.edit()
|
||||||
threading.Thread(target=webhook.edit).start()
|
|
||||||
else:
|
else:
|
||||||
webhook.execute()
|
webhook.execute()
|
||||||
if webhook_id := webhook.id:
|
if webhook_id := webhook.id:
|
||||||
|
|
|
@ -26,24 +26,6 @@ class PlayerEvent(app_db.BaseModel):
|
||||||
)
|
)
|
||||||
role: Mapped["PlayerTeamRole"] = relationship("PlayerTeamRole")
|
role: Mapped["PlayerTeamRole"] = relationship("PlayerTeamRole")
|
||||||
|
|
||||||
class EventWithPlayerSchema(spec.BaseModel):
|
|
||||||
event: "EventSchema"
|
|
||||||
player_event: Optional["PlayerEventRolesSchema"]
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_event_player_event(cls, event: "Event", player_event: Optional["PlayerEvent"]):
|
|
||||||
res = cls(
|
|
||||||
event=EventSchema.from_model(event),
|
|
||||||
player_event=None,
|
|
||||||
)
|
|
||||||
|
|
||||||
if player_event:
|
|
||||||
res.player_event = PlayerEventRolesSchema.from_event_player_team(
|
|
||||||
player_event, player_event.player_team
|
|
||||||
)
|
|
||||||
|
|
||||||
return res
|
|
||||||
|
|
||||||
class PlayerEventRolesSchema(spec.BaseModel):
|
class PlayerEventRolesSchema(spec.BaseModel):
|
||||||
player: "PlayerSchema"
|
player: "PlayerSchema"
|
||||||
role: Optional["RoleSchema"]
|
role: Optional["RoleSchema"]
|
||||||
|
@ -62,7 +44,7 @@ class PlayerEventRolesSchema(spec.BaseModel):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
from models.event import Event, EventSchema
|
from models.event import Event
|
||||||
from models.player import Player, PlayerSchema
|
from models.player import Player, PlayerSchema
|
||||||
from models.player_team_role import PlayerTeamRole, RoleSchema
|
from models.player_team_role import PlayerTeamRole, RoleSchema
|
||||||
from models.player_team import PlayerTeam
|
from models.player_team import PlayerTeam
|
||||||
|
|
|
@ -36,6 +36,7 @@ class Team(app_db.BaseModel):
|
||||||
|
|
||||||
def update_integrations(self, integrations: "TeamIntegrationSchema"):
|
def update_integrations(self, integrations: "TeamIntegrationSchema"):
|
||||||
if integrations.discord_integration:
|
if integrations.discord_integration:
|
||||||
|
print("DISCORD!!!")
|
||||||
discord_integration = self.discord_integration \
|
discord_integration = self.discord_integration \
|
||||||
or TeamDiscordIntegration()
|
or TeamDiscordIntegration()
|
||||||
discord_integration.webhook_url = integrations \
|
discord_integration.webhook_url = integrations \
|
||||||
|
@ -43,10 +44,6 @@ class Team(app_db.BaseModel):
|
||||||
discord_integration.webhook_bot_name = integrations \
|
discord_integration.webhook_bot_name = integrations \
|
||||||
.discord_integration.webhook_bot_name
|
.discord_integration.webhook_bot_name
|
||||||
|
|
||||||
if integrations.discord_integration.webhook_bot_profile_picture:
|
|
||||||
discord_integration.webhook_bot_profile_picture = integrations \
|
|
||||||
.discord_integration.webhook_bot_profile_picture
|
|
||||||
|
|
||||||
if discord_integration.team_id is None:
|
if discord_integration.team_id is None:
|
||||||
discord_integration.team_id = self.id
|
discord_integration.team_id = self.id
|
||||||
app_db.db.session.add(discord_integration)
|
app_db.db.session.add(discord_integration)
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
from typing import Optional
|
|
||||||
from sqlalchemy.orm import mapped_column, relationship
|
from sqlalchemy.orm import mapped_column, relationship
|
||||||
from sqlalchemy.orm.attributes import Mapped
|
from sqlalchemy.orm.attributes import Mapped
|
||||||
from sqlalchemy.orm.properties import ForeignKey
|
from sqlalchemy.orm.properties import ForeignKey
|
||||||
|
@ -13,21 +12,18 @@ class TeamDiscordIntegration(app_db.BaseModel):
|
||||||
team_id: Mapped[int] = mapped_column(ForeignKey("teams.id"), primary_key=True)
|
team_id: Mapped[int] = mapped_column(ForeignKey("teams.id"), primary_key=True)
|
||||||
webhook_url: Mapped[str] = mapped_column(String)
|
webhook_url: Mapped[str] = mapped_column(String)
|
||||||
webhook_bot_name: Mapped[str] = mapped_column(String)
|
webhook_bot_name: Mapped[str] = mapped_column(String)
|
||||||
webhook_bot_profile_picture: Mapped[str] = mapped_column(String(255), nullable=True)
|
|
||||||
|
|
||||||
team: Mapped["Team"] = relationship("Team", back_populates="discord_integration")
|
team: Mapped["Team"] = relationship("Team", back_populates="discord_integration")
|
||||||
|
|
||||||
class TeamDiscordIntegrationSchema(spec.BaseModel):
|
class TeamDiscordIntegrationSchema(spec.BaseModel):
|
||||||
webhook_url: str
|
webhook_url: str
|
||||||
webhook_bot_name: str
|
webhook_bot_name: str
|
||||||
webhook_bot_profile_picture: Optional[str]
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_model(cls, model: TeamDiscordIntegration) -> "TeamDiscordIntegrationSchema":
|
def from_model(cls, model: TeamDiscordIntegration) -> "TeamDiscordIntegrationSchema":
|
||||||
return cls(
|
return cls(
|
||||||
webhook_url=model.webhook_url,
|
webhook_url=model.webhook_url,
|
||||||
webhook_bot_name=model.webhook_bot_name,
|
webhook_bot_name=model.webhook_bot_name,
|
||||||
webhook_bot_profile_picture=model.webhook_bot_profile_picture,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
class TeamLogsTfIntegration(app_db.BaseModel):
|
class TeamLogsTfIntegration(app_db.BaseModel):
|
||||||
|
|
Loading…
Reference in New Issue