Add functionality for viewing available teammates
							parent
							
								
									60f96f43f7
								
							
						
					
					
						commit
						325b3529fe
					
				| 
						 | 
				
			
			@ -14,6 +14,7 @@ export type { AddPlayerJson } from './models/AddPlayerJson';
 | 
			
		|||
export type { CreateTeamJson } from './models/CreateTeamJson';
 | 
			
		||||
export type { EditMemberRolesJson } from './models/EditMemberRolesJson';
 | 
			
		||||
export type { PlayerSchema } from './models/PlayerSchema';
 | 
			
		||||
export type { PlayerTeamAvailabilityRoleSchema } from './models/PlayerTeamAvailabilityRoleSchema';
 | 
			
		||||
export type { PutScheduleForm } from './models/PutScheduleForm';
 | 
			
		||||
export type { RoleSchema } from './models/RoleSchema';
 | 
			
		||||
export type { TeamInviteSchema } from './models/TeamInviteSchema';
 | 
			
		||||
| 
						 | 
				
			
			@ -22,7 +23,8 @@ export { TeamRole } from './models/TeamRole';
 | 
			
		|||
export type { TeamSchema } from './models/TeamSchema';
 | 
			
		||||
export type { ValidationError } from './models/ValidationError';
 | 
			
		||||
export type { ValidationErrorElement } from './models/ValidationErrorElement';
 | 
			
		||||
export type { ViewAvailablePlayersForm } from './models/ViewAvailablePlayersForm';
 | 
			
		||||
export type { ViewAvailablePlayersQuery } from './models/ViewAvailablePlayersQuery';
 | 
			
		||||
export type { ViewAvailablePlayersResponse } from './models/ViewAvailablePlayersResponse';
 | 
			
		||||
export type { ViewScheduleForm } from './models/ViewScheduleForm';
 | 
			
		||||
export type { ViewScheduleResponse } from './models/ViewScheduleResponse';
 | 
			
		||||
export type { ViewTeamMembersResponse } from './models/ViewTeamMembersResponse';
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
/* generated using openapi-typescript-codegen -- do not edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
import type { PlayerSchema } from './PlayerSchema';
 | 
			
		||||
import type { RoleSchema } from './RoleSchema';
 | 
			
		||||
export type PlayerTeamAvailabilityRoleSchema = {
 | 
			
		||||
    availability: number;
 | 
			
		||||
    player: PlayerSchema;
 | 
			
		||||
    playtime: number;
 | 
			
		||||
    roles: Array<RoleSchema>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
export type ViewAvailablePlayersForm = {
 | 
			
		||||
export type ViewAvailablePlayersQuery = {
 | 
			
		||||
    startTime: string;
 | 
			
		||||
    teamId: number;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
/* generated using openapi-typescript-codegen -- do not edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
import type { PlayerTeamAvailabilityRoleSchema } from './PlayerTeamAvailabilityRoleSchema';
 | 
			
		||||
export type ViewAvailablePlayersResponse = {
 | 
			
		||||
    players: Array<PlayerTeamAvailabilityRoleSchema>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -9,6 +9,7 @@ import type { PlayerSchema } from '../models/PlayerSchema';
 | 
			
		|||
import type { PutScheduleForm } from '../models/PutScheduleForm';
 | 
			
		||||
import type { TeamInviteSchema } from '../models/TeamInviteSchema';
 | 
			
		||||
import type { TeamInviteSchemaList } from '../models/TeamInviteSchemaList';
 | 
			
		||||
import type { ViewAvailablePlayersResponse } from '../models/ViewAvailablePlayersResponse';
 | 
			
		||||
import type { ViewScheduleResponse } from '../models/ViewScheduleResponse';
 | 
			
		||||
import type { ViewTeamMembersResponseList } from '../models/ViewTeamMembersResponseList';
 | 
			
		||||
import type { ViewTeamResponse } from '../models/ViewTeamResponse';
 | 
			
		||||
| 
						 | 
				
			
			@ -130,16 +131,16 @@ export class DefaultService {
 | 
			
		|||
        });
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * view_available <GET>
 | 
			
		||||
     * view_available_at_time <GET>
 | 
			
		||||
     * @param startTime
 | 
			
		||||
     * @param teamId
 | 
			
		||||
     * @returns void
 | 
			
		||||
     * @returns ViewAvailablePlayersResponse OK
 | 
			
		||||
     * @throws ApiError
 | 
			
		||||
     */
 | 
			
		||||
    public getApiScheduleViewAvailable(
 | 
			
		||||
    public viewAvailableAtTime(
 | 
			
		||||
        startTime: string,
 | 
			
		||||
        teamId: number,
 | 
			
		||||
    ): CancelablePromise<void> {
 | 
			
		||||
    ): CancelablePromise<ViewAvailablePlayersResponse> {
 | 
			
		||||
        return this.httpRequest.request({
 | 
			
		||||
            method: 'GET',
 | 
			
		||||
            url: '/api/schedule/view-available',
 | 
			
		||||
| 
						 | 
				
			
			@ -147,6 +148,9 @@ export class DefaultService {
 | 
			
		|||
                'startTime': startTime,
 | 
			
		||||
                'teamId': teamId,
 | 
			
		||||
            },
 | 
			
		||||
            errors: {
 | 
			
		||||
                422: `Unprocessable Entity`,
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,11 +3,11 @@ export interface Player {
 | 
			
		|||
  name: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface PlayerTeamRole {
 | 
			
		||||
  steamId: number;
 | 
			
		||||
export interface PlayerTeamRoleFlat {
 | 
			
		||||
  steamId: string;
 | 
			
		||||
  name: string;
 | 
			
		||||
  role: string;
 | 
			
		||||
  main: boolean;
 | 
			
		||||
  isMain: boolean;
 | 
			
		||||
  availability: number;
 | 
			
		||||
  playtime: number;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,7 +26,7 @@ const router = createRouter({
 | 
			
		|||
      component: ScheduleView
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      path: "/schedule/roster",
 | 
			
		||||
      path: "/schedule/roster/:teamId/:startTime",
 | 
			
		||||
      name: "roster-builder",
 | 
			
		||||
      component: RosterBuilderView
 | 
			
		||||
    },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,12 @@
 | 
			
		|||
import { type Player, type PlayerTeamRole } from "@/player";
 | 
			
		||||
import { type Player, type PlayerTeamRoleFlat } from "@/player";
 | 
			
		||||
import { defineStore } from "pinia";
 | 
			
		||||
import { computed, reactive, ref, type Reactive, type Ref } from "vue";
 | 
			
		||||
import { useClientStore } from "./client";
 | 
			
		||||
 | 
			
		||||
export const useRosterStore = defineStore("roster", () => {
 | 
			
		||||
  const clientStore = useClientStore();
 | 
			
		||||
  const client = clientStore.client;
 | 
			
		||||
 | 
			
		||||
  const neededRoles: Reactive<Array<String>> = reactive([
 | 
			
		||||
    "PocketScout",
 | 
			
		||||
    "FlankScout",
 | 
			
		||||
| 
						 | 
				
			
			@ -12,134 +16,31 @@ export const useRosterStore = defineStore("roster", () => {
 | 
			
		|||
    "Medic",
 | 
			
		||||
  ]);
 | 
			
		||||
 | 
			
		||||
  const selectedPlayers: Reactive<{ [key: string]: PlayerTeamRole }> = reactive({});
 | 
			
		||||
  const selectedPlayers: Reactive<{ [key: string]: PlayerTeamRoleFlat }> = reactive({});
 | 
			
		||||
 | 
			
		||||
  const selectedRole: Ref<String | undefined> = ref(undefined);
 | 
			
		||||
 | 
			
		||||
  const availablePlayers: Reactive<Array<PlayerTeamRole>> = reactive([
 | 
			
		||||
  const availablePlayers: Ref<Array<PlayerTeamRoleFlat>> = ref([
 | 
			
		||||
    {
 | 
			
		||||
      steamId: 2840,
 | 
			
		||||
      steamId: "342534598",
 | 
			
		||||
      name: "Wesker U",
 | 
			
		||||
      role: "Flank Scout",
 | 
			
		||||
      main: true,
 | 
			
		||||
      isMain: true,
 | 
			
		||||
      availability: 1,
 | 
			
		||||
      playtime: 35031,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      steamId: 2839,
 | 
			
		||||
      steamId: "342534298",
 | 
			
		||||
      name: "JustGetAHouse",
 | 
			
		||||
      role: "Flank Scout",
 | 
			
		||||
      main: false,
 | 
			
		||||
      isMain: false,
 | 
			
		||||
      availability: 1,
 | 
			
		||||
      playtime: 28811,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      steamId: 2839,
 | 
			
		||||
      name: "JustGetAHouse",
 | 
			
		||||
      role: "Pocket Scout",
 | 
			
		||||
      main: true,
 | 
			
		||||
      availability: 1,
 | 
			
		||||
      playtime: 28811,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      steamId: 2841,
 | 
			
		||||
      name: "VADIKUS007",
 | 
			
		||||
      role: "Pocket Soldier",
 | 
			
		||||
      main: true,
 | 
			
		||||
      availability: 2,
 | 
			
		||||
      playtime: 98372,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      steamId: 2841,
 | 
			
		||||
      name: "VADIKUS007",
 | 
			
		||||
      role: "Roamer",
 | 
			
		||||
      main: false,
 | 
			
		||||
      availability: 2,
 | 
			
		||||
      playtime: 98372,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      steamId: 2282,
 | 
			
		||||
      name: "Bergman777",
 | 
			
		||||
      role: "Demoman",
 | 
			
		||||
      main: true,
 | 
			
		||||
      availability: 2,
 | 
			
		||||
      playtime: 47324,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      steamId: 2083,
 | 
			
		||||
      name: "IF_YOU_READ_THIS_",
 | 
			
		||||
      role: "Demoman",
 | 
			
		||||
      main: true,
 | 
			
		||||
      availability: 1,
 | 
			
		||||
      playtime: 32812,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      steamId: 2842,
 | 
			
		||||
      name: "BossOfThisGym",
 | 
			
		||||
      role: "Roamer",
 | 
			
		||||
      main: false,
 | 
			
		||||
      availability: 2,
 | 
			
		||||
      playtime: 12028,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      steamId: 2842,
 | 
			
		||||
      name: "BossOfThisGym",
 | 
			
		||||
      role: "Demoman",
 | 
			
		||||
      main: false,
 | 
			
		||||
      availability: 2,
 | 
			
		||||
      playtime: 12028,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      steamId: 2842,
 | 
			
		||||
      name: "BossOfThisGym",
 | 
			
		||||
      role: "Pocket Scout",
 | 
			
		||||
      main: false,
 | 
			
		||||
      availability: 2,
 | 
			
		||||
      playtime: 12028,
 | 
			
		||||
    },
 | 
			
		||||
    //{
 | 
			
		||||
    //  steamId: 2843,
 | 
			
		||||
    //  name: "samme1g",
 | 
			
		||||
    //  role: "Medic",
 | 
			
		||||
    //  main: true,
 | 
			
		||||
    //  availability: 2,
 | 
			
		||||
    //},
 | 
			
		||||
    {
 | 
			
		||||
      steamId: 2843,
 | 
			
		||||
      name: "samme1g",
 | 
			
		||||
      role: "Pocket Soldier",
 | 
			
		||||
      main: false,
 | 
			
		||||
      availability: 2,
 | 
			
		||||
      playtime: 50201,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      steamId: 2843,
 | 
			
		||||
      name: "samme1g",
 | 
			
		||||
      role: "Demoman",
 | 
			
		||||
      main: true,
 | 
			
		||||
      availability: 2,
 | 
			
		||||
      playtime: 50201,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      steamId: 2844,
 | 
			
		||||
      name: "FarbrorBarbro",
 | 
			
		||||
      role: "Roamer",
 | 
			
		||||
      main: true,
 | 
			
		||||
      availability: 1,
 | 
			
		||||
      playtime: 4732,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      steamId: 2844,
 | 
			
		||||
      name: "FarbrorBarbro",
 | 
			
		||||
      role: "Pocket Soldier",
 | 
			
		||||
      main: false,
 | 
			
		||||
      availability: 1,
 | 
			
		||||
      playtime: 4732,
 | 
			
		||||
    },
 | 
			
		||||
  ]);
 | 
			
		||||
 | 
			
		||||
  const availablePlayerRoles = computed(() => {
 | 
			
		||||
    return availablePlayers.filter((player) => player.role == selectedRole.value);
 | 
			
		||||
    return availablePlayers.value.filter((player) => player.role == selectedRole.value);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  const definitelyAvailable = computed(() => {
 | 
			
		||||
| 
						 | 
				
			
			@ -150,7 +51,7 @@ export const useRosterStore = defineStore("roster", () => {
 | 
			
		|||
    return availablePlayerRoles.value.filter((player) => player.availability == 1);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  function comparator(p1: PlayerTeamRole, p2: PlayerTeamRole) {
 | 
			
		||||
  function comparator(p1: PlayerTeamRoleFlat, p2: PlayerTeamRoleFlat) {
 | 
			
		||||
    // definitely available > can be available
 | 
			
		||||
    let availabilityDiff = p1.availability - p2.availability;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -161,12 +62,12 @@ export const useRosterStore = defineStore("roster", () => {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  const mainRoles = computed(() => {
 | 
			
		||||
    return availablePlayerRoles.value.filter((player) => player.main)
 | 
			
		||||
    return availablePlayerRoles.value.filter((player) => player.isMain)
 | 
			
		||||
      .sort(comparator);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  const alternateRoles = computed(() => {
 | 
			
		||||
    return availablePlayerRoles.value.filter((player) => !player.main)
 | 
			
		||||
    return availablePlayerRoles.value.filter((player) => !player.isMain)
 | 
			
		||||
      .sort(comparator);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -188,8 +89,8 @@ export const useRosterStore = defineStore("roster", () => {
 | 
			
		|||
    "Medic": "Medic",
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  function selectPlayerForRole(player: PlayerTeamRole, role: string) {
 | 
			
		||||
    if (player && player.steamId > 0) {
 | 
			
		||||
  function selectPlayerForRole(player: PlayerTeamRoleFlat, role: string) {
 | 
			
		||||
    if (player && player.steamId) {
 | 
			
		||||
      const existingRole = Object.keys(selectedPlayers).find((selectedRole) => {
 | 
			
		||||
        return selectedPlayers[selectedRole]?.steamId == player.steamId &&
 | 
			
		||||
          role != selectedRole;
 | 
			
		||||
| 
						 | 
				
			
			@ -203,6 +104,27 @@ export const useRosterStore = defineStore("roster", () => {
 | 
			
		|||
    selectedPlayers[role] = player;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function fetchAvailablePlayers(startTime: number, teamId: number) {
 | 
			
		||||
    clientStore.call(
 | 
			
		||||
      fetchAvailablePlayers.name,
 | 
			
		||||
      () => client.default.viewAvailableAtTime(startTime.toString(), teamId),
 | 
			
		||||
      (response) => {
 | 
			
		||||
        availablePlayers.value = response.players.flatMap((schema) => {
 | 
			
		||||
          return schema.roles.map((role) => ({
 | 
			
		||||
            steamId: schema.player.steamId,
 | 
			
		||||
            name: schema.player.username,
 | 
			
		||||
            role: role.role,
 | 
			
		||||
            isMain: role.isMain,
 | 
			
		||||
            availability: schema.availability,
 | 
			
		||||
            playtime: schema.playtime,
 | 
			
		||||
          }));
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return response;
 | 
			
		||||
      }
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    neededRoles,
 | 
			
		||||
    selectedPlayers,
 | 
			
		||||
| 
						 | 
				
			
			@ -216,5 +138,6 @@ export const useRosterStore = defineStore("roster", () => {
 | 
			
		|||
    roleNames,
 | 
			
		||||
    mainRoles,
 | 
			
		||||
    alternateRoles,
 | 
			
		||||
    fetchAvailablePlayers,
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,11 +2,15 @@
 | 
			
		|||
import PlayerCard from "../components/PlayerCard.vue";
 | 
			
		||||
import RoleSlot from "../components/RoleSlot.vue";
 | 
			
		||||
import PlayerTeamRole from "../player.ts";
 | 
			
		||||
import { computed, reactive } from "vue";
 | 
			
		||||
import { computed, reactive, onMounted } from "vue";
 | 
			
		||||
import { useRosterStore } from "../stores/roster";
 | 
			
		||||
import { useRoute } from "vue-router";
 | 
			
		||||
import moment from "moment";
 | 
			
		||||
 | 
			
		||||
const rosterStore = useRosterStore();
 | 
			
		||||
 | 
			
		||||
const route = useRoute();
 | 
			
		||||
 | 
			
		||||
const hasAvailablePlayers = computed(() => {
 | 
			
		||||
  return rosterStore.availablePlayerRoles.length > 0;
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -14,6 +18,10 @@ const hasAvailablePlayers = computed(() => {
 | 
			
		|||
const hasAlternates = computed(() => {
 | 
			
		||||
  return rosterStore.alternateRoles.length > 0;
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
  rosterStore.fetchAvailablePlayers(route.params.startTime, route.params.teamId);
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
| 
						 | 
				
			
			@ -21,7 +29,10 @@ const hasAlternates = computed(() => {
 | 
			
		|||
    <div class="top">
 | 
			
		||||
      <h1 class="roster-title">
 | 
			
		||||
        Roster for Snus Brotherhood
 | 
			
		||||
        <em class="aside date">Aug. 13, 2036 @ 11:30 PM EST</em>
 | 
			
		||||
        <em class="aside date">
 | 
			
		||||
          @
 | 
			
		||||
          {{ moment(startTime).format("L LT") }}
 | 
			
		||||
        </em>
 | 
			
		||||
      </h1>
 | 
			
		||||
      <div class="button-group">
 | 
			
		||||
        <button>Cancel</button>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,7 +21,6 @@ def index():
 | 
			
		|||
    return "test"
 | 
			
		||||
 | 
			
		||||
@api_login.get("/get-user")
 | 
			
		||||
@requires_authentication
 | 
			
		||||
@spec.validate(
 | 
			
		||||
    resp=Response(
 | 
			
		||||
        HTTP_200=PlayerSchema,
 | 
			
		||||
| 
						 | 
				
			
			@ -29,11 +28,9 @@ def index():
 | 
			
		|||
    ),
 | 
			
		||||
    operation_id="get_user"
 | 
			
		||||
)
 | 
			
		||||
@requires_authentication
 | 
			
		||||
def get_user(player: Player, auth_session: AuthSession):
 | 
			
		||||
    return PlayerSchema(
 | 
			
		||||
        steam_id=str(player.steam_id),
 | 
			
		||||
        username=player.username,
 | 
			
		||||
    ).dict(by_alias=True), 200
 | 
			
		||||
    return PlayerSchema.from_model(player).dict(by_alias=True)
 | 
			
		||||
 | 
			
		||||
@api_login.post("/authenticate")
 | 
			
		||||
def steam_authenticate():
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,6 +22,10 @@ class PlayerSchema(spec.BaseModel):
 | 
			
		|||
    steam_id: str
 | 
			
		||||
    username: str
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def from_model(cls, player: Player):
 | 
			
		||||
        return cls(steam_id=str(player.steam_id), username=player.username)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
from models.auth_session import AuthSession
 | 
			
		||||
from models.player_team import PlayerTeam
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
from datetime import datetime
 | 
			
		||||
from datetime import datetime, timedelta
 | 
			
		||||
import spec
 | 
			
		||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
 | 
			
		||||
from sqlalchemy.schema import ForeignKeyConstraint
 | 
			
		||||
from sqlalchemy.types import Integer
 | 
			
		||||
| 
						 | 
				
			
			@ -28,3 +29,12 @@ class PlayerTeamAvailability(app_db.BaseModel):
 | 
			
		|||
            [PlayerTeam.player_id, PlayerTeam.team_id]
 | 
			
		||||
        ),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
class PlayerTeamAvailabilityRoleSchema(spec.BaseModel):
 | 
			
		||||
    from models.player import PlayerSchema
 | 
			
		||||
    from models.player_team_role import RoleSchema
 | 
			
		||||
 | 
			
		||||
    player: PlayerSchema
 | 
			
		||||
    playtime: int
 | 
			
		||||
    availability: int
 | 
			
		||||
    roles: list[RoleSchema]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
import enum
 | 
			
		||||
 | 
			
		||||
import spec
 | 
			
		||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
 | 
			
		||||
from sqlalchemy.schema import ForeignKeyConstraint
 | 
			
		||||
from sqlalchemy.types import Boolean, Enum
 | 
			
		||||
| 
						 | 
				
			
			@ -46,3 +47,11 @@ class PlayerTeamRole(app_db.BaseModel):
 | 
			
		|||
            [PlayerTeam.player_id, PlayerTeam.team_id]
 | 
			
		||||
        ),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
class RoleSchema(spec.BaseModel):
 | 
			
		||||
    role: str
 | 
			
		||||
    is_main: bool
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def from_model(cls, role: PlayerTeamRole):
 | 
			
		||||
        return cls(role=role.role.name, is_main=role.is_main)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,11 +2,12 @@ import datetime
 | 
			
		|||
from typing import cast
 | 
			
		||||
from flask import Blueprint, abort, jsonify, make_response, request
 | 
			
		||||
from spectree import Response
 | 
			
		||||
from sqlalchemy.orm import joinedload
 | 
			
		||||
from app_db import db
 | 
			
		||||
from models.player import Player
 | 
			
		||||
from models.player import Player, PlayerSchema
 | 
			
		||||
from models.player_team import PlayerTeam
 | 
			
		||||
from models.player_team_availability import PlayerTeamAvailability
 | 
			
		||||
from models.player_team_role import PlayerTeamRole
 | 
			
		||||
from models.player_team_availability import PlayerTeamAvailability, PlayerTeamAvailabilityRoleSchema
 | 
			
		||||
from models.player_team_role import PlayerTeamRole, RoleSchema
 | 
			
		||||
from middleware import requires_authentication
 | 
			
		||||
from spec import spec, BaseModel
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -184,20 +185,32 @@ def put(json: PutScheduleForm, player: Player, **kwargs):
 | 
			
		|||
    db.session.commit()
 | 
			
		||||
    return make_response({ }, 200)
 | 
			
		||||
 | 
			
		||||
class ViewAvailablePlayersForm(BaseModel):
 | 
			
		||||
class ViewAvailablePlayersQuery(BaseModel):
 | 
			
		||||
    start_time: datetime.datetime
 | 
			
		||||
    team_id: int
 | 
			
		||||
 | 
			
		||||
class ViewAvailablePlayersResponse(BaseModel):
 | 
			
		||||
    players: list[PlayerTeamAvailabilityRoleSchema]
 | 
			
		||||
 | 
			
		||||
@api_schedule.get("/view-available")
 | 
			
		||||
@spec.validate()
 | 
			
		||||
@spec.validate(
 | 
			
		||||
    resp=Response(
 | 
			
		||||
        HTTP_200=ViewAvailablePlayersResponse,
 | 
			
		||||
    ),
 | 
			
		||||
    operation_id="view_available_at_time"
 | 
			
		||||
)
 | 
			
		||||
@requires_authentication
 | 
			
		||||
def view_available(query: ViewAvailablePlayersForm, player: Player, **kwargs):
 | 
			
		||||
def view_available_at_time(query: ViewAvailablePlayersQuery, player: Player, **kwargs):
 | 
			
		||||
    start_time = query.start_time
 | 
			
		||||
 | 
			
		||||
    availability = db.session.query(
 | 
			
		||||
    records = db.session.query(
 | 
			
		||||
        PlayerTeamAvailability
 | 
			
		||||
    ).where(
 | 
			
		||||
        PlayerTeamAvailability.player_id == player.steam_id
 | 
			
		||||
    ).join(
 | 
			
		||||
        PlayerTeam
 | 
			
		||||
    ).join(
 | 
			
		||||
        Player
 | 
			
		||||
    ).join(
 | 
			
		||||
        PlayerTeamRole
 | 
			
		||||
    ).where(
 | 
			
		||||
        PlayerTeamAvailability.team_id == query.team_id
 | 
			
		||||
    ).where(
 | 
			
		||||
| 
						 | 
				
			
			@ -205,22 +218,18 @@ def view_available(query: ViewAvailablePlayersForm, player: Player, **kwargs):
 | 
			
		|||
            (PlayerTeamAvailability.end_time > start_time)
 | 
			
		||||
    ).all()
 | 
			
		||||
 | 
			
		||||
    def map_roles_to_json(roles: list[PlayerTeamRole],
 | 
			
		||||
                          player_team: PlayerTeam,
 | 
			
		||||
                          entry: PlayerTeamAvailability):
 | 
			
		||||
        for role in roles:
 | 
			
		||||
            yield {
 | 
			
		||||
                "steamId": entry.player_id,
 | 
			
		||||
                "username": entry.player_team.player.username,
 | 
			
		||||
                "role": role.role.name,
 | 
			
		||||
                "isMain": role.is_main,
 | 
			
		||||
                "availability": entry.availability,
 | 
			
		||||
                "playtime": int(player_team.playtime.total_seconds()),
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
    def map_availability_to_json(entry: PlayerTeamAvailability):
 | 
			
		||||
        player_team = entry.player_team
 | 
			
		||||
    def map_to_response(player_avail: PlayerTeamAvailability):
 | 
			
		||||
        player_team = player_avail.player_team
 | 
			
		||||
        player = player_team.player
 | 
			
		||||
        player_roles = player_team.player_roles
 | 
			
		||||
        return list(map_roles_to_json(player_roles, player_team, entry))
 | 
			
		||||
 | 
			
		||||
    return jsonify(list(map(map_availability_to_json, availability)))
 | 
			
		||||
        return PlayerTeamAvailabilityRoleSchema(
 | 
			
		||||
            player=PlayerSchema.from_model(player),
 | 
			
		||||
            playtime=int(player_team.playtime.total_seconds()),
 | 
			
		||||
            availability=player_avail.availability,
 | 
			
		||||
            roles=list(map(RoleSchema.from_model, player_roles)),
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    return ViewAvailablePlayersResponse(
 | 
			
		||||
        players=list(map(map_to_response, records))
 | 
			
		||||
    ).dict(by_alias=True), 200
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,7 @@ from app_db import db
 | 
			
		|||
from models.player import Player, PlayerSchema
 | 
			
		||||
from models.player_team import PlayerTeam
 | 
			
		||||
from models.player_team_availability import PlayerTeamAvailability
 | 
			
		||||
from models.player_team_role import PlayerTeamRole
 | 
			
		||||
from models.player_team_role import PlayerTeamRole, RoleSchema
 | 
			
		||||
from models.team import Team, TeamSchema
 | 
			
		||||
from models.team_invite import TeamInvite, TeamInviteSchema
 | 
			
		||||
from middleware import requires_authentication
 | 
			
		||||
| 
						 | 
				
			
			@ -302,10 +302,6 @@ def fetch_teams_for_player(player: Player, team_id: int | None):
 | 
			
		|||
            )
 | 
			
		||||
 | 
			
		||||
class ViewTeamMembersResponse(PlayerSchema):
 | 
			
		||||
    class RoleSchema(BaseModel):
 | 
			
		||||
        role: str
 | 
			
		||||
        is_main: bool
 | 
			
		||||
 | 
			
		||||
    roles: list[RoleSchema]
 | 
			
		||||
    availability: list[int]
 | 
			
		||||
    playtime: float
 | 
			
		||||
| 
						 | 
				
			
			@ -346,7 +342,7 @@ def view_team_members(player: Player, team_id: int, **kwargs):
 | 
			
		|||
        abort(404)
 | 
			
		||||
 | 
			
		||||
    def map_role_to_schema(player_team_role: PlayerTeamRole):
 | 
			
		||||
        return ViewTeamMembersResponse.RoleSchema(
 | 
			
		||||
        return RoleSchema(
 | 
			
		||||
            role=player_team_role.role.name,
 | 
			
		||||
            is_main=player_team_role.is_main,
 | 
			
		||||
        )
 | 
			
		||||
| 
						 | 
				
			
			@ -376,7 +372,7 @@ def view_team_members(player: Player, team_id: int, **kwargs):
 | 
			
		|||
    return list(map(map_to_response, player_teams))
 | 
			
		||||
 | 
			
		||||
class EditMemberRolesJson(BaseModel):
 | 
			
		||||
    roles: list[ViewTeamMembersResponse.RoleSchema]
 | 
			
		||||
    roles: list[RoleSchema]
 | 
			
		||||
 | 
			
		||||
@api_team.patch("/id/<team_id>/edit-player/<target_player_id>")
 | 
			
		||||
@spec.validate(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue