Compare commits
	
		
			No commits in common. "e98bd1f647f85a1b055646b3e662b9207f40681f" and "fcf8f7e3ce5d056aafd120f937778aa8e5045465" have entirely different histories. 
		
	
	
		
			e98bd1f647
			...
			fcf8f7e3ce
		
	
		
	| 
						 | 
				
			
			@ -1400,6 +1400,12 @@
 | 
			
		|||
      "dev": true,
 | 
			
		||||
      "license": "MIT"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@types/web-bluetooth": {
 | 
			
		||||
      "version": "0.0.20",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz",
 | 
			
		||||
      "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==",
 | 
			
		||||
      "license": "MIT"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@types/yauzl": {
 | 
			
		||||
      "version": "2.10.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz",
 | 
			
		||||
| 
						 | 
				
			
			@ -2029,6 +2035,56 @@
 | 
			
		|||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@vueuse/core": {
 | 
			
		||||
      "version": "10.11.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.11.1.tgz",
 | 
			
		||||
      "integrity": "sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==",
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "@types/web-bluetooth": "^0.0.20",
 | 
			
		||||
        "@vueuse/metadata": "10.11.1",
 | 
			
		||||
        "@vueuse/shared": "10.11.1",
 | 
			
		||||
        "vue-demi": ">=0.14.8"
 | 
			
		||||
      },
 | 
			
		||||
      "funding": {
 | 
			
		||||
        "url": "https://github.com/sponsors/antfu"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@vueuse/core/node_modules/vue-demi": {
 | 
			
		||||
      "version": "0.14.10",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
 | 
			
		||||
      "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
 | 
			
		||||
      "hasInstallScript": true,
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "bin": {
 | 
			
		||||
        "vue-demi-fix": "bin/vue-demi-fix.js",
 | 
			
		||||
        "vue-demi-switch": "bin/vue-demi-switch.js"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=12"
 | 
			
		||||
      },
 | 
			
		||||
      "funding": {
 | 
			
		||||
        "url": "https://github.com/sponsors/antfu"
 | 
			
		||||
      },
 | 
			
		||||
      "peerDependencies": {
 | 
			
		||||
        "@vue/composition-api": "^1.0.0-rc.1",
 | 
			
		||||
        "vue": "^3.0.0-0 || ^2.6.0"
 | 
			
		||||
      },
 | 
			
		||||
      "peerDependenciesMeta": {
 | 
			
		||||
        "@vue/composition-api": {
 | 
			
		||||
          "optional": true
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@vueuse/metadata": {
 | 
			
		||||
      "version": "10.11.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.11.1.tgz",
 | 
			
		||||
      "integrity": "sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw==",
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "funding": {
 | 
			
		||||
        "url": "https://github.com/sponsors/antfu"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@vueuse/shared": {
 | 
			
		||||
      "version": "10.11.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.11.1.tgz",
 | 
			
		||||
| 
						 | 
				
			
			@ -6343,62 +6399,6 @@
 | 
			
		|||
        "vue": ">= 3.2.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/radix-vue/node_modules/@types/web-bluetooth": {
 | 
			
		||||
      "version": "0.0.20",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz",
 | 
			
		||||
      "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==",
 | 
			
		||||
      "license": "MIT"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/radix-vue/node_modules/@vueuse/core": {
 | 
			
		||||
      "version": "10.11.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.11.1.tgz",
 | 
			
		||||
      "integrity": "sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==",
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "@types/web-bluetooth": "^0.0.20",
 | 
			
		||||
        "@vueuse/metadata": "10.11.1",
 | 
			
		||||
        "@vueuse/shared": "10.11.1",
 | 
			
		||||
        "vue-demi": ">=0.14.8"
 | 
			
		||||
      },
 | 
			
		||||
      "funding": {
 | 
			
		||||
        "url": "https://github.com/sponsors/antfu"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/radix-vue/node_modules/@vueuse/core/node_modules/vue-demi": {
 | 
			
		||||
      "version": "0.14.10",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
 | 
			
		||||
      "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
 | 
			
		||||
      "hasInstallScript": true,
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "bin": {
 | 
			
		||||
        "vue-demi-fix": "bin/vue-demi-fix.js",
 | 
			
		||||
        "vue-demi-switch": "bin/vue-demi-switch.js"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=12"
 | 
			
		||||
      },
 | 
			
		||||
      "funding": {
 | 
			
		||||
        "url": "https://github.com/sponsors/antfu"
 | 
			
		||||
      },
 | 
			
		||||
      "peerDependencies": {
 | 
			
		||||
        "@vue/composition-api": "^1.0.0-rc.1",
 | 
			
		||||
        "vue": "^3.0.0-0 || ^2.6.0"
 | 
			
		||||
      },
 | 
			
		||||
      "peerDependenciesMeta": {
 | 
			
		||||
        "@vue/composition-api": {
 | 
			
		||||
          "optional": true
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/radix-vue/node_modules/@vueuse/metadata": {
 | 
			
		||||
      "version": "10.11.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.11.1.tgz",
 | 
			
		||||
      "integrity": "sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw==",
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "funding": {
 | 
			
		||||
        "url": "https://github.com/sponsors/antfu"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/radix-vue/node_modules/nanoid": {
 | 
			
		||||
      "version": "5.0.9",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.9.tgz",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -421,69 +421,3 @@ tr:last-child > td:first-child {
 | 
			
		|||
tr:last-child > td:last-child {
 | 
			
		||||
  border-bottom-right-radius: 4px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.sidebar-container {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  gap: 16px;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.sidebar-container nav.sidebar {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: end;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.sidebar-container .view {
 | 
			
		||||
  width: 60%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
nav.sidebar h3 {
 | 
			
		||||
  text-transform: uppercase;
 | 
			
		||||
  color: var(--overlay-0);
 | 
			
		||||
  padding: 0 8px;
 | 
			
		||||
  font-size: 8pt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav.sidebar > .categories {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  width: 192px;
 | 
			
		||||
  gap: 4px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav.sidebar a.tab {
 | 
			
		||||
  font-size: 11pt;
 | 
			
		||||
  color: var(--overlay-0);
 | 
			
		||||
  padding: 6px 10px;
 | 
			
		||||
  font-weight: 500;
 | 
			
		||||
  border-radius: 4px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav.sidebar a.tab:hover {
 | 
			
		||||
  background-color: var(--crust);
 | 
			
		||||
  color: var(--text);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav.sidebar a.tab.router-link-exact-active {
 | 
			
		||||
  background-color: var(--crust);
 | 
			
		||||
  color: var(--text);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav.sidebar button {
 | 
			
		||||
  font-size: 11pt;
 | 
			
		||||
  font-weight: 500;
 | 
			
		||||
  padding: 6px 10px;
 | 
			
		||||
  background-color: transparent;
 | 
			
		||||
  color: var(--overlay-0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav.sidebar button:hover {
 | 
			
		||||
  background-color: var(--crust);
 | 
			
		||||
  color: var(--text);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav.sidebar button.destructive-on-hover:hover {
 | 
			
		||||
  background-color: var(--destructive);
 | 
			
		||||
  color: var(--base);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,12 +22,10 @@ export type { EventWithPlayerSchema } from './models/EventWithPlayerSchema';
 | 
			
		|||
export type { EventWithPlayerSchemaList } from './models/EventWithPlayerSchemaList';
 | 
			
		||||
export type { GetEventPlayersResponse } from './models/GetEventPlayersResponse';
 | 
			
		||||
export type { GetMatchQuery } from './models/GetMatchQuery';
 | 
			
		||||
export type { GetUserResponse } from './models/GetUserResponse';
 | 
			
		||||
export type { MatchSchema } from './models/MatchSchema';
 | 
			
		||||
export type { PlayerEventRolesSchema } from './models/PlayerEventRolesSchema';
 | 
			
		||||
export type { PlayerRoleSchema } from './models/PlayerRoleSchema';
 | 
			
		||||
export type { PlayerSchema } from './models/PlayerSchema';
 | 
			
		||||
export type { PlayerSchemaList } from './models/PlayerSchemaList';
 | 
			
		||||
export type { PlayerTeamAvailabilityRoleSchema } from './models/PlayerTeamAvailabilityRoleSchema';
 | 
			
		||||
export type { PutScheduleForm } from './models/PutScheduleForm';
 | 
			
		||||
export type { RoleSchema } from './models/RoleSchema';
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,12 +0,0 @@
 | 
			
		|||
/* generated using openapi-typescript-codegen -- do not edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
import type { PlayerSchema } from './PlayerSchema';
 | 
			
		||||
export type GetUserResponse = {
 | 
			
		||||
    isAdmin?: boolean;
 | 
			
		||||
    realUser: (PlayerSchema | null);
 | 
			
		||||
    steamId: string;
 | 
			
		||||
    username: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3,7 +3,6 @@
 | 
			
		|||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
export type PlayerSchema = {
 | 
			
		||||
    isAdmin?: boolean;
 | 
			
		||||
    steamId: string;
 | 
			
		||||
    username: string;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +0,0 @@
 | 
			
		|||
/* generated using openapi-typescript-codegen -- do not edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
import type { PlayerSchema } from './PlayerSchema';
 | 
			
		||||
export type PlayerSchemaList = Array<PlayerSchema>;
 | 
			
		||||
| 
						 | 
				
			
			@ -6,7 +6,6 @@ import type { RoleSchema } from './RoleSchema';
 | 
			
		|||
export type ViewTeamMembersResponse = {
 | 
			
		||||
    availability: Array<number>;
 | 
			
		||||
    createdAt: string;
 | 
			
		||||
    isAdmin?: boolean;
 | 
			
		||||
    isTeamLeader?: boolean;
 | 
			
		||||
    playtime: number;
 | 
			
		||||
    roles: Array<RoleSchema>;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,10 +12,8 @@ import type { EventSchema } from '../models/EventSchema';
 | 
			
		|||
import type { EventWithPlayerSchema } from '../models/EventWithPlayerSchema';
 | 
			
		||||
import type { EventWithPlayerSchemaList } from '../models/EventWithPlayerSchemaList';
 | 
			
		||||
import type { GetEventPlayersResponse } from '../models/GetEventPlayersResponse';
 | 
			
		||||
import type { GetUserResponse } from '../models/GetUserResponse';
 | 
			
		||||
import type { MatchSchema } from '../models/MatchSchema';
 | 
			
		||||
import type { PlayerSchema } from '../models/PlayerSchema';
 | 
			
		||||
import type { PlayerSchemaList } from '../models/PlayerSchemaList';
 | 
			
		||||
import type { PutScheduleForm } from '../models/PutScheduleForm';
 | 
			
		||||
import type { SetUsernameJson } from '../models/SetUsernameJson';
 | 
			
		||||
import type { SubmitMatchJson } from '../models/SubmitMatchJson';
 | 
			
		||||
| 
						 | 
				
			
			@ -281,10 +279,10 @@ export class DefaultService {
 | 
			
		|||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * get_user <GET>
 | 
			
		||||
     * @returns GetUserResponse OK
 | 
			
		||||
     * @returns PlayerSchema OK
 | 
			
		||||
     * @throws ApiError
 | 
			
		||||
     */
 | 
			
		||||
    public getUser(): CancelablePromise<GetUserResponse> {
 | 
			
		||||
    public getUser(): CancelablePromise<PlayerSchema> {
 | 
			
		||||
        return this.httpRequest.request({
 | 
			
		||||
            method: 'GET',
 | 
			
		||||
            url: '/api/login/get-user',
 | 
			
		||||
| 
						 | 
				
			
			@ -520,6 +518,28 @@ export class DefaultService {
 | 
			
		|||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * delete_team <DELETE>
 | 
			
		||||
     * @param teamId
 | 
			
		||||
     * @returns any OK
 | 
			
		||||
     * @throws ApiError
 | 
			
		||||
     */
 | 
			
		||||
    public deleteTeam(
 | 
			
		||||
        teamId: number,
 | 
			
		||||
    ): CancelablePromise<any> {
 | 
			
		||||
        return this.httpRequest.request({
 | 
			
		||||
            method: 'DELETE',
 | 
			
		||||
            url: '/api/team/id/{team_id}/',
 | 
			
		||||
            path: {
 | 
			
		||||
                'team_id': teamId,
 | 
			
		||||
            },
 | 
			
		||||
            errors: {
 | 
			
		||||
                403: `Forbidden`,
 | 
			
		||||
                404: `Not Found`,
 | 
			
		||||
                422: `Unprocessable Content`,
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * view_team <GET>
 | 
			
		||||
     * @param teamId
 | 
			
		||||
| 
						 | 
				
			
			@ -781,54 +801,6 @@ export class DefaultService {
 | 
			
		|||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * get_all_users <GET>
 | 
			
		||||
     * @returns PlayerSchemaList OK
 | 
			
		||||
     * @throws ApiError
 | 
			
		||||
     */
 | 
			
		||||
    public getAllUsers(): CancelablePromise<PlayerSchemaList> {
 | 
			
		||||
        return this.httpRequest.request({
 | 
			
		||||
            method: 'GET',
 | 
			
		||||
            url: '/api/user/all',
 | 
			
		||||
            errors: {
 | 
			
		||||
                422: `Unprocessable Content`,
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * unset_doas <DELETE>
 | 
			
		||||
     * @returns void
 | 
			
		||||
     * @throws ApiError
 | 
			
		||||
     */
 | 
			
		||||
    public unsetDoas(): CancelablePromise<void> {
 | 
			
		||||
        return this.httpRequest.request({
 | 
			
		||||
            method: 'DELETE',
 | 
			
		||||
            url: '/api/user/doas',
 | 
			
		||||
            errors: {
 | 
			
		||||
                422: `Unprocessable Content`,
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * set_doas <PUT>
 | 
			
		||||
     * @param steamId
 | 
			
		||||
     * @returns PlayerSchema OK
 | 
			
		||||
     * @throws ApiError
 | 
			
		||||
     */
 | 
			
		||||
    public setDoas(
 | 
			
		||||
        steamId: string,
 | 
			
		||||
    ): CancelablePromise<PlayerSchema> {
 | 
			
		||||
        return this.httpRequest.request({
 | 
			
		||||
            method: 'PUT',
 | 
			
		||||
            url: '/api/user/doas/{steam_id}',
 | 
			
		||||
            path: {
 | 
			
		||||
                'steam_id': steamId,
 | 
			
		||||
            },
 | 
			
		||||
            errors: {
 | 
			
		||||
                422: `Unprocessable Content`,
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * set_username <POST>
 | 
			
		||||
     * @param requestBody
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,9 +19,6 @@ function logout() {
 | 
			
		|||
<template>
 | 
			
		||||
  <DropdownMenuRoot>
 | 
			
		||||
    <DropdownMenuTrigger className="profile-button no-border">
 | 
			
		||||
      <span class="aside" v-if="authStore.realUser">
 | 
			
		||||
        {{ authStore.realUser?.username }}, disguised as
 | 
			
		||||
      </span>
 | 
			
		||||
      {{ authStore.username }}
 | 
			
		||||
      <i class="bi bi-chevron-down" />
 | 
			
		||||
    </DropdownMenuTrigger>
 | 
			
		||||
| 
						 | 
				
			
			@ -43,14 +40,6 @@ function logout() {
 | 
			
		|||
            </button>
 | 
			
		||||
          </RouterLink>
 | 
			
		||||
        </DropdownMenuItem>
 | 
			
		||||
        <DropdownMenuItem v-if="authStore.isAdmin">
 | 
			
		||||
          <RouterLink class="button" :to="{ 'name': 'admin' }">
 | 
			
		||||
            <button>
 | 
			
		||||
              <i class="bi bi-person-check margin" />
 | 
			
		||||
              Super secret admin stuff!
 | 
			
		||||
            </button>
 | 
			
		||||
          </RouterLink>
 | 
			
		||||
        </DropdownMenuItem>
 | 
			
		||||
        <DropdownMenuItem>
 | 
			
		||||
          <button class="destructive" @click="logout">
 | 
			
		||||
            <i class="bi bi-box-arrow-right margin" />
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,9 +13,6 @@ import TeamSettingsIntegrationsView from "@/views/TeamSettings/IntegrationsView.
 | 
			
		|||
import TeamSettingsInvitesView from "@/views/TeamSettings/InvitesView.vue";
 | 
			
		||||
import TeamSettingsMatchesView from "@/views/TeamSettings/MatchesView.vue";
 | 
			
		||||
import UserSettingsView from "@/views/UserSettingsView.vue";
 | 
			
		||||
import AdminView from "@/views/AdminView.vue";
 | 
			
		||||
import AdminGeneralView from "@/views/Admin/GeneralView.vue";
 | 
			
		||||
import AdminDoasView from "@/views/Admin/DoasView.vue";
 | 
			
		||||
 | 
			
		||||
const router = createRouter({
 | 
			
		||||
  history: createWebHistory(import.meta.env.BASE_URL),
 | 
			
		||||
| 
						 | 
				
			
			@ -87,23 +84,6 @@ const router = createRouter({
 | 
			
		|||
      name: "user-settings",
 | 
			
		||||
      component: UserSettingsView,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      path: "/admin",
 | 
			
		||||
      name: "admin",
 | 
			
		||||
      component: AdminView,
 | 
			
		||||
      children: [
 | 
			
		||||
        {
 | 
			
		||||
          path: "",
 | 
			
		||||
          name: "admin/",
 | 
			
		||||
          component: AdminGeneralView,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          path: "doas",
 | 
			
		||||
          name: "admin/doas",
 | 
			
		||||
          component: AdminDoasView,
 | 
			
		||||
        },
 | 
			
		||||
      ],
 | 
			
		||||
    },
 | 
			
		||||
  ]
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,20 +2,18 @@ import { defineStore } from "pinia";
 | 
			
		|||
import { ref } from "vue";
 | 
			
		||||
import { useClientStore } from "./client";
 | 
			
		||||
import { useRouter, type LocationQuery } from "vue-router";
 | 
			
		||||
import { type GetUserResponse, type PlayerSchema } from "@/client";
 | 
			
		||||
import { type PlayerSchema } from "@/client";
 | 
			
		||||
 | 
			
		||||
export const useAuthStore = defineStore("auth", () => {
 | 
			
		||||
  const clientStore = useClientStore();
 | 
			
		||||
  const client = clientStore.client;
 | 
			
		||||
 | 
			
		||||
  const user = ref<GetUserResponse | null>(null);
 | 
			
		||||
  const user = ref<PlayerSchema | null>(null);
 | 
			
		||||
  const steamId = ref("");
 | 
			
		||||
  const username = ref("");
 | 
			
		||||
  const isLoggedIn = ref(false);
 | 
			
		||||
  const isRegistering = ref(false);
 | 
			
		||||
  const hasCheckedAuth = ref(false);
 | 
			
		||||
  const isAdmin = ref(false);
 | 
			
		||||
  const realUser = ref<PlayerSchema | null>(null);
 | 
			
		||||
 | 
			
		||||
  const router = useRouter();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -37,9 +35,6 @@ export const useAuthStore = defineStore("auth", () => {
 | 
			
		|||
        steamId.value = response.steamId;
 | 
			
		||||
        username.value = response.username;
 | 
			
		||||
        user.value = response;
 | 
			
		||||
        isAdmin.value = response.isAdmin || (response.realUser?.isAdmin ?? false);
 | 
			
		||||
        realUser.value = response.realUser ?? null;
 | 
			
		||||
 | 
			
		||||
        return response;
 | 
			
		||||
      },
 | 
			
		||||
      undefined,
 | 
			
		||||
| 
						 | 
				
			
			@ -81,48 +76,13 @@ export const useAuthStore = defineStore("auth", () => {
 | 
			
		|||
      });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async function getAllUsers() {
 | 
			
		||||
    return client.default.getAllUsers();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async function setDoas(doasSteamId: string) {
 | 
			
		||||
    return client.default.setDoas(doasSteamId)
 | 
			
		||||
      .then((response) => {
 | 
			
		||||
        if (user.value) {
 | 
			
		||||
          realUser.value = {
 | 
			
		||||
            steamId: user.value.steamId,
 | 
			
		||||
            username: user.value.username,
 | 
			
		||||
            isAdmin: user.value.isAdmin,
 | 
			
		||||
          };
 | 
			
		||||
        }
 | 
			
		||||
        steamId.value = response.steamId;
 | 
			
		||||
        username.value = response.username;
 | 
			
		||||
      });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async function unsetDoas() {
 | 
			
		||||
    return client.default.unsetDoas()
 | 
			
		||||
      .then((_) => {
 | 
			
		||||
        if (realUser.value) {
 | 
			
		||||
          steamId.value = realUser.value.steamId;
 | 
			
		||||
          username.value = realUser.value.username;
 | 
			
		||||
        }
 | 
			
		||||
        realUser.value = null;
 | 
			
		||||
      });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    steamId,
 | 
			
		||||
    username,
 | 
			
		||||
    isAdmin,
 | 
			
		||||
    realUser,
 | 
			
		||||
    isLoggedIn,
 | 
			
		||||
    hasCheckedAuth,
 | 
			
		||||
    isRegistering,
 | 
			
		||||
    getUser,
 | 
			
		||||
    getAllUsers,
 | 
			
		||||
    setDoas,
 | 
			
		||||
    unsetDoas,
 | 
			
		||||
    login,
 | 
			
		||||
    logout,
 | 
			
		||||
    setUsername,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,64 +0,0 @@
 | 
			
		|||
<script setup lang="ts">
 | 
			
		||||
import { type PlayerSchema, type PlayerSchemaList } from "@/client";
 | 
			
		||||
import { useAuthStore } from "@/stores/auth";
 | 
			
		||||
import { onMounted, ref } from "vue";
 | 
			
		||||
 | 
			
		||||
//const cookies = useCookies(["doas"], { doNotParse: true, autoUpdateDependencies: true }, universalCookie);
 | 
			
		||||
const doas = ref<PlayerSchema | undefined>();
 | 
			
		||||
const users = ref<PlayerSchemaList>([]);
 | 
			
		||||
const authStore = useAuthStore();
 | 
			
		||||
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
  authStore.getAllUsers()
 | 
			
		||||
    .then((response) => {
 | 
			
		||||
      users.value = response;
 | 
			
		||||
      //doas.value = response.find(user => user.steamId === cookies.get("doas"));
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function setDoas() {
 | 
			
		||||
  if (doas.value) {
 | 
			
		||||
    authStore.setDoas(doas.value.steamId);
 | 
			
		||||
  } else {
 | 
			
		||||
    authStore.unsetDoas();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function removeDoas() {
 | 
			
		||||
  doas.value = undefined;
 | 
			
		||||
  authStore.unsetDoas();
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <h2>Become User</h2>
 | 
			
		||||
  <p>
 | 
			
		||||
    Do as/become a specific user.
 | 
			
		||||
  </p>
 | 
			
		||||
  <div>
 | 
			
		||||
    <div class="form-group margin">
 | 
			
		||||
      <h3>User</h3>
 | 
			
		||||
      <v-select
 | 
			
		||||
        v-model="doas"
 | 
			
		||||
        :options="users"
 | 
			
		||||
        label="username"
 | 
			
		||||
        placeholder="Select a user"
 | 
			
		||||
        :clearable="true"
 | 
			
		||||
        :searchable="true"
 | 
			
		||||
        :close-on-select="true"
 | 
			
		||||
        :show-search-input="true"
 | 
			
		||||
      />
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="form-group margin">
 | 
			
		||||
      <div class="action-buttons">
 | 
			
		||||
        <button class="destructive-on-hover" @click="removeDoas">
 | 
			
		||||
          <i class="bi bi-trash" />
 | 
			
		||||
        </button>
 | 
			
		||||
        <button class="accent" @click="setDoas">
 | 
			
		||||
          <i class="bi bi-check" />
 | 
			
		||||
          Become {{ doas?.username }}
 | 
			
		||||
        </button>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,9 +0,0 @@
 | 
			
		|||
<script setup lang="ts">
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <h1>Admin Panel</h1>
 | 
			
		||||
  <p>
 | 
			
		||||
    This is the admin panel. Only admins can access this page.
 | 
			
		||||
  </p>
 | 
			
		||||
</template>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,22 +0,0 @@
 | 
			
		|||
<script setup lang="ts">
 | 
			
		||||
import { RouterLink, RouterView } from "vue-router";
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <main class="sidebar-container admin-panel">
 | 
			
		||||
    <nav class="sidebar">
 | 
			
		||||
      <div class="categories">
 | 
			
		||||
        <h3>Admin Panel</h3>
 | 
			
		||||
        <RouterLink class="tab" :to="{ name: 'admin/' }">
 | 
			
		||||
          General
 | 
			
		||||
        </RouterLink>
 | 
			
		||||
        <RouterLink class="tab" :to="{ name: 'admin/doas' }">
 | 
			
		||||
          Become User
 | 
			
		||||
        </RouterLink>
 | 
			
		||||
      </div>
 | 
			
		||||
    </nav>
 | 
			
		||||
    <div class="view">
 | 
			
		||||
      <RouterView />
 | 
			
		||||
    </div>
 | 
			
		||||
  </main>
 | 
			
		||||
</template>
 | 
			
		||||
| 
						 | 
				
			
			@ -23,7 +23,7 @@ onMounted(() => {
 | 
			
		|||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <main class="sidebar-container team-settings" v-if="team">
 | 
			
		||||
  <main class="team-settings" v-if="team">
 | 
			
		||||
    <nav class="sidebar">
 | 
			
		||||
      <div class="categories">
 | 
			
		||||
        <div class="back-link">
 | 
			
		||||
| 
						 | 
				
			
			@ -59,7 +59,72 @@ onMounted(() => {
 | 
			
		|||
</template>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
.team-settings {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  gap: 16px;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.team-settings nav.sidebar {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: end;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.team-settings .view {
 | 
			
		||||
  width: 60%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.back-link {
 | 
			
		||||
  padding: 8px 16px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav.sidebar h3 {
 | 
			
		||||
  text-transform: uppercase;
 | 
			
		||||
  color: var(--overlay-0);
 | 
			
		||||
  padding: 0 8px;
 | 
			
		||||
  font-size: 8pt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav.sidebar > .categories {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  width: 192px;
 | 
			
		||||
  gap: 4px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav.sidebar a.tab {
 | 
			
		||||
  font-size: 11pt;
 | 
			
		||||
  color: var(--overlay-0);
 | 
			
		||||
  padding: 6px 10px;
 | 
			
		||||
  font-weight: 500;
 | 
			
		||||
  border-radius: 4px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav.sidebar a.tab:hover {
 | 
			
		||||
  background-color: var(--crust);
 | 
			
		||||
  color: var(--text);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav.sidebar a.tab.router-link-exact-active {
 | 
			
		||||
  background-color: var(--crust);
 | 
			
		||||
  color: var(--text);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav.sidebar button {
 | 
			
		||||
  font-size: 11pt;
 | 
			
		||||
  font-weight: 500;
 | 
			
		||||
  padding: 6px 10px;
 | 
			
		||||
  background-color: transparent;
 | 
			
		||||
  color: var(--overlay-0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav.sidebar button:hover {
 | 
			
		||||
  background-color: var(--crust);
 | 
			
		||||
  color: var(--text);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav.sidebar button.destructive-on-hover:hover {
 | 
			
		||||
  background-color: var(--destructive);
 | 
			
		||||
  color: var(--base);
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,36 +21,17 @@ STEAM_OPENID_URL = "https://steamcommunity.com/openid/login"
 | 
			
		|||
def index():
 | 
			
		||||
    return "test"
 | 
			
		||||
 | 
			
		||||
class GetUserResponse(PlayerSchema):
 | 
			
		||||
    real_user: PlayerSchema | None
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def from_model(cls, model: Player):
 | 
			
		||||
        return GetUserResponse(
 | 
			
		||||
            steam_id=str(model.steam_id),
 | 
			
		||||
            username=model.username,
 | 
			
		||||
            is_admin=model.is_admin,
 | 
			
		||||
            real_user=None,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
@api_login.get("/get-user")
 | 
			
		||||
@spec.validate(
 | 
			
		||||
    resp=Response(
 | 
			
		||||
        HTTP_200=GetUserResponse,
 | 
			
		||||
        HTTP_200=PlayerSchema,
 | 
			
		||||
        HTTP_401=None,
 | 
			
		||||
    ),
 | 
			
		||||
    operation_id="get_user"
 | 
			
		||||
)
 | 
			
		||||
@requires_authentication
 | 
			
		||||
def get_user(player: Player, auth_session: AuthSession):
 | 
			
		||||
    if auth_session.player.steam_id != player.steam_id:
 | 
			
		||||
        return GetUserResponse(
 | 
			
		||||
            steam_id=str(player.steam_id),
 | 
			
		||||
            username=player.username,
 | 
			
		||||
            is_admin=player.is_admin,
 | 
			
		||||
            real_user=PlayerSchema.from_model(auth_session.player)
 | 
			
		||||
        ).dict(by_alias=True)
 | 
			
		||||
    return GetUserResponse.from_model(player).dict(by_alias=True)
 | 
			
		||||
    return PlayerSchema.from_model(player).dict(by_alias=True)
 | 
			
		||||
 | 
			
		||||
@api_login.post("/authenticate")
 | 
			
		||||
def steam_authenticate():
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,6 @@ from typing import Optional
 | 
			
		|||
from flask import abort, make_response, request
 | 
			
		||||
from sqlalchemy.sql.operators import json_path_getitem_op
 | 
			
		||||
from app_db import db
 | 
			
		||||
from models import auth_session
 | 
			
		||||
from models.auth_session import AuthSession
 | 
			
		||||
from models.player import Player
 | 
			
		||||
from models.player_team import PlayerTeam
 | 
			
		||||
| 
						 | 
				
			
			@ -14,7 +13,6 @@ def requires_authentication(f):
 | 
			
		|||
    @wraps(f)
 | 
			
		||||
    def decorator(*args, **kwargs):
 | 
			
		||||
        auth = request.cookies.get("auth")
 | 
			
		||||
        doas = request.cookies.get("doas")
 | 
			
		||||
 | 
			
		||||
        if not auth:
 | 
			
		||||
            abort(401)
 | 
			
		||||
| 
						 | 
				
			
			@ -30,30 +28,6 @@ def requires_authentication(f):
 | 
			
		|||
        player = auth_session.player
 | 
			
		||||
        kwargs["player"] = player
 | 
			
		||||
        kwargs["auth_session"] = auth_session
 | 
			
		||||
 | 
			
		||||
        if doas and player.is_admin:
 | 
			
		||||
            doas_int = int(doas)
 | 
			
		||||
            if doas_int and doas_int != player.steam_id:
 | 
			
		||||
                doas_player = db.session.query(
 | 
			
		||||
                    Player
 | 
			
		||||
                ).where(
 | 
			
		||||
                    Player.steam_id == doas_int
 | 
			
		||||
                ).one_or_none()
 | 
			
		||||
 | 
			
		||||
                if doas_player:
 | 
			
		||||
                    kwargs["player"] = doas_player
 | 
			
		||||
 | 
			
		||||
        return f(*args, **kwargs)
 | 
			
		||||
    return decorator
 | 
			
		||||
 | 
			
		||||
def requires_admin(f):
 | 
			
		||||
    @wraps(f)
 | 
			
		||||
    def decorator(*args, **kwargs):
 | 
			
		||||
        auth_session: AuthSession | None = kwargs["auth_session"]
 | 
			
		||||
        if not auth_session or not auth_session.player:
 | 
			
		||||
            abort(401)
 | 
			
		||||
        if not auth_session.player.is_admin:
 | 
			
		||||
            abort(403)
 | 
			
		||||
        return f(*args, **kwargs)
 | 
			
		||||
    return decorator
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,32 +0,0 @@
 | 
			
		|||
"""Add is_admin field
 | 
			
		||||
 | 
			
		||||
Revision ID: f8588cdf998e
 | 
			
		||||
Revises: 3b18d4bfc6ac
 | 
			
		||||
Create Date: 2025-05-13 17:15:53.887878
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
from alembic import op
 | 
			
		||||
import sqlalchemy as sa
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# revision identifiers, used by Alembic.
 | 
			
		||||
revision = 'f8588cdf998e'
 | 
			
		||||
down_revision = '3b18d4bfc6ac'
 | 
			
		||||
branch_labels = None
 | 
			
		||||
depends_on = None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def upgrade():
 | 
			
		||||
    # ### commands auto generated by Alembic - please adjust! ###
 | 
			
		||||
    with op.batch_alter_table('players', schema=None) as batch_op:
 | 
			
		||||
        batch_op.add_column(sa.Column('is_admin', sa.Boolean(), nullable=False, default=False))
 | 
			
		||||
 | 
			
		||||
    # ### end Alembic commands ###
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def downgrade():
 | 
			
		||||
    # ### commands auto generated by Alembic - please adjust! ###
 | 
			
		||||
    with op.batch_alter_table('players', schema=None) as batch_op:
 | 
			
		||||
        batch_op.drop_column('is_admin')
 | 
			
		||||
 | 
			
		||||
    # ### end Alembic commands ###
 | 
			
		||||
| 
						 | 
				
			
			@ -12,7 +12,6 @@ class Player(app_db.BaseModel):
 | 
			
		|||
 | 
			
		||||
    steam_id: Mapped[int] = mapped_column(BigInteger, primary_key=True)
 | 
			
		||||
    username: Mapped[str] = mapped_column(String(63))
 | 
			
		||||
    is_admin: Mapped[bool] = mapped_column(default=False)
 | 
			
		||||
 | 
			
		||||
    teams: Mapped[list["PlayerTeam"]] = relationship(back_populates="player")
 | 
			
		||||
    auth_sessions: Mapped[list["AuthSession"]] = relationship(back_populates="player")
 | 
			
		||||
| 
						 | 
				
			
			@ -24,15 +23,10 @@ class Player(app_db.BaseModel):
 | 
			
		|||
class PlayerSchema(spec.BaseModel):
 | 
			
		||||
    steam_id: str
 | 
			
		||||
    username: str
 | 
			
		||||
    is_admin: bool = False
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def from_model(cls, player: Player):
 | 
			
		||||
        return cls(
 | 
			
		||||
            steam_id=str(player.steam_id),
 | 
			
		||||
            username=player.username,
 | 
			
		||||
            is_admin=player.is_admin
 | 
			
		||||
        )
 | 
			
		||||
        return cls(steam_id=str(player.steam_id), username=player.username)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
from models.auth_session import AuthSession
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
from flask import Blueprint, abort, make_response
 | 
			
		||||
from flask import Blueprint
 | 
			
		||||
from spectree import Response
 | 
			
		||||
from middleware import requires_admin, requires_authentication
 | 
			
		||||
from middleware import requires_authentication
 | 
			
		||||
from models.player import Player, PlayerSchema
 | 
			
		||||
from spec import spec, BaseModel
 | 
			
		||||
from app_db import db
 | 
			
		||||
| 
						 | 
				
			
			@ -23,53 +23,3 @@ def set_username(json: SetUsernameJson, player: Player, **kwargs):
 | 
			
		|||
    player.username = json.username
 | 
			
		||||
    db.session.commit()
 | 
			
		||||
    return PlayerSchema.from_model(player).dict(by_alias=True), 200
 | 
			
		||||
 | 
			
		||||
@api_user.get("/all")
 | 
			
		||||
@spec.validate(
 | 
			
		||||
    resp=Response(
 | 
			
		||||
        HTTP_200=list[PlayerSchema],
 | 
			
		||||
    ),
 | 
			
		||||
    operation_id="get_all_users",
 | 
			
		||||
)
 | 
			
		||||
@requires_authentication
 | 
			
		||||
@requires_admin
 | 
			
		||||
def get_all_users(player: Player, **kwargs):
 | 
			
		||||
    players = db.session.query(Player).all()
 | 
			
		||||
    return list(map(lambda p: PlayerSchema.from_model(p).dict(by_alias=True), players)), 200
 | 
			
		||||
 | 
			
		||||
@api_user.put("/doas/<steam_id>")
 | 
			
		||||
@spec.validate(
 | 
			
		||||
    resp=Response(
 | 
			
		||||
        HTTP_200=PlayerSchema,
 | 
			
		||||
    ),
 | 
			
		||||
    operation_id="set_doas"
 | 
			
		||||
)
 | 
			
		||||
@requires_authentication
 | 
			
		||||
@requires_admin
 | 
			
		||||
def set_doas(steam_id: str, **_):
 | 
			
		||||
    player = db.session.query(Player).where(
 | 
			
		||||
        Player.steam_id == steam_id
 | 
			
		||||
    ).one_or_none()
 | 
			
		||||
 | 
			
		||||
    if not player:
 | 
			
		||||
        abort(404)
 | 
			
		||||
 | 
			
		||||
    resp = make_response(
 | 
			
		||||
        PlayerSchema.from_model(player).dict(by_alias=True)
 | 
			
		||||
    )
 | 
			
		||||
    resp.set_cookie("doas", steam_id, httponly=True)
 | 
			
		||||
    return resp
 | 
			
		||||
 | 
			
		||||
@api_user.delete("/doas")
 | 
			
		||||
@spec.validate(
 | 
			
		||||
    resp=Response(
 | 
			
		||||
        HTTP_204=None,
 | 
			
		||||
    ),
 | 
			
		||||
    operation_id="unset_doas"
 | 
			
		||||
)
 | 
			
		||||
@requires_authentication
 | 
			
		||||
@requires_admin
 | 
			
		||||
def unset_doas(**_):
 | 
			
		||||
    resp = make_response({ }, 204)
 | 
			
		||||
    resp.delete_cookie("doas", httponly=True)
 | 
			
		||||
    return resp
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue