Add Become Player admin feature
							parent
							
								
									cb9b6535c1
								
							
						
					
					
						commit
						e98bd1f647
					
				| 
						 | 
					@ -1400,12 +1400,6 @@
 | 
				
			||||||
      "dev": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "license": "MIT"
 | 
					      "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": {
 | 
					    "node_modules/@types/yauzl": {
 | 
				
			||||||
      "version": "2.10.3",
 | 
					      "version": "2.10.3",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz",
 | 
				
			||||||
| 
						 | 
					@ -2035,56 +2029,6 @@
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "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": {
 | 
					    "node_modules/@vueuse/shared": {
 | 
				
			||||||
      "version": "10.11.1",
 | 
					      "version": "10.11.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.11.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.11.1.tgz",
 | 
				
			||||||
| 
						 | 
					@ -6399,6 +6343,62 @@
 | 
				
			||||||
        "vue": ">= 3.2.0"
 | 
					        "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": {
 | 
					    "node_modules/radix-vue/node_modules/nanoid": {
 | 
				
			||||||
      "version": "5.0.9",
 | 
					      "version": "5.0.9",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.9.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.9.tgz",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -421,3 +421,69 @@ tr:last-child > td:first-child {
 | 
				
			||||||
tr:last-child > td:last-child {
 | 
					tr:last-child > td:last-child {
 | 
				
			||||||
  border-bottom-right-radius: 4px;
 | 
					  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,10 +22,12 @@ export type { EventWithPlayerSchema } from './models/EventWithPlayerSchema';
 | 
				
			||||||
export type { EventWithPlayerSchemaList } from './models/EventWithPlayerSchemaList';
 | 
					export type { EventWithPlayerSchemaList } from './models/EventWithPlayerSchemaList';
 | 
				
			||||||
export type { GetEventPlayersResponse } from './models/GetEventPlayersResponse';
 | 
					export type { GetEventPlayersResponse } from './models/GetEventPlayersResponse';
 | 
				
			||||||
export type { GetMatchQuery } from './models/GetMatchQuery';
 | 
					export type { GetMatchQuery } from './models/GetMatchQuery';
 | 
				
			||||||
 | 
					export type { GetUserResponse } from './models/GetUserResponse';
 | 
				
			||||||
export type { MatchSchema } from './models/MatchSchema';
 | 
					export type { MatchSchema } from './models/MatchSchema';
 | 
				
			||||||
export type { PlayerEventRolesSchema } from './models/PlayerEventRolesSchema';
 | 
					export type { PlayerEventRolesSchema } from './models/PlayerEventRolesSchema';
 | 
				
			||||||
export type { PlayerRoleSchema } from './models/PlayerRoleSchema';
 | 
					export type { PlayerRoleSchema } from './models/PlayerRoleSchema';
 | 
				
			||||||
export type { PlayerSchema } from './models/PlayerSchema';
 | 
					export type { PlayerSchema } from './models/PlayerSchema';
 | 
				
			||||||
 | 
					export type { PlayerSchemaList } from './models/PlayerSchemaList';
 | 
				
			||||||
export type { PlayerTeamAvailabilityRoleSchema } from './models/PlayerTeamAvailabilityRoleSchema';
 | 
					export type { PlayerTeamAvailabilityRoleSchema } from './models/PlayerTeamAvailabilityRoleSchema';
 | 
				
			||||||
export type { PutScheduleForm } from './models/PutScheduleForm';
 | 
					export type { PutScheduleForm } from './models/PutScheduleForm';
 | 
				
			||||||
export type { RoleSchema } from './models/RoleSchema';
 | 
					export type { RoleSchema } from './models/RoleSchema';
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,12 @@
 | 
				
			||||||
 | 
					/* 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,6 +3,7 @@
 | 
				
			||||||
/* tslint:disable */
 | 
					/* tslint:disable */
 | 
				
			||||||
/* eslint-disable */
 | 
					/* eslint-disable */
 | 
				
			||||||
export type PlayerSchema = {
 | 
					export type PlayerSchema = {
 | 
				
			||||||
 | 
					    isAdmin?: boolean;
 | 
				
			||||||
    steamId: string;
 | 
					    steamId: string;
 | 
				
			||||||
    username: string;
 | 
					    username: string;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,6 @@
 | 
				
			||||||
 | 
					/* 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,6 +6,7 @@ import type { RoleSchema } from './RoleSchema';
 | 
				
			||||||
export type ViewTeamMembersResponse = {
 | 
					export type ViewTeamMembersResponse = {
 | 
				
			||||||
    availability: Array<number>;
 | 
					    availability: Array<number>;
 | 
				
			||||||
    createdAt: string;
 | 
					    createdAt: string;
 | 
				
			||||||
 | 
					    isAdmin?: boolean;
 | 
				
			||||||
    isTeamLeader?: boolean;
 | 
					    isTeamLeader?: boolean;
 | 
				
			||||||
    playtime: number;
 | 
					    playtime: number;
 | 
				
			||||||
    roles: Array<RoleSchema>;
 | 
					    roles: Array<RoleSchema>;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,8 +12,10 @@ import type { EventSchema } from '../models/EventSchema';
 | 
				
			||||||
import type { EventWithPlayerSchema } from '../models/EventWithPlayerSchema';
 | 
					import type { EventWithPlayerSchema } from '../models/EventWithPlayerSchema';
 | 
				
			||||||
import type { EventWithPlayerSchemaList } from '../models/EventWithPlayerSchemaList';
 | 
					import type { EventWithPlayerSchemaList } from '../models/EventWithPlayerSchemaList';
 | 
				
			||||||
import type { GetEventPlayersResponse } from '../models/GetEventPlayersResponse';
 | 
					import type { GetEventPlayersResponse } from '../models/GetEventPlayersResponse';
 | 
				
			||||||
 | 
					import type { GetUserResponse } from '../models/GetUserResponse';
 | 
				
			||||||
import type { MatchSchema } from '../models/MatchSchema';
 | 
					import type { MatchSchema } from '../models/MatchSchema';
 | 
				
			||||||
import type { PlayerSchema } from '../models/PlayerSchema';
 | 
					import type { PlayerSchema } from '../models/PlayerSchema';
 | 
				
			||||||
 | 
					import type { PlayerSchemaList } from '../models/PlayerSchemaList';
 | 
				
			||||||
import type { PutScheduleForm } from '../models/PutScheduleForm';
 | 
					import type { PutScheduleForm } from '../models/PutScheduleForm';
 | 
				
			||||||
import type { SetUsernameJson } from '../models/SetUsernameJson';
 | 
					import type { SetUsernameJson } from '../models/SetUsernameJson';
 | 
				
			||||||
import type { SubmitMatchJson } from '../models/SubmitMatchJson';
 | 
					import type { SubmitMatchJson } from '../models/SubmitMatchJson';
 | 
				
			||||||
| 
						 | 
					@ -279,10 +281,10 @@ export class DefaultService {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * get_user <GET>
 | 
					     * get_user <GET>
 | 
				
			||||||
     * @returns PlayerSchema OK
 | 
					     * @returns GetUserResponse OK
 | 
				
			||||||
     * @throws ApiError
 | 
					     * @throws ApiError
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public getUser(): CancelablePromise<PlayerSchema> {
 | 
					    public getUser(): CancelablePromise<GetUserResponse> {
 | 
				
			||||||
        return this.httpRequest.request({
 | 
					        return this.httpRequest.request({
 | 
				
			||||||
            method: 'GET',
 | 
					            method: 'GET',
 | 
				
			||||||
            url: '/api/login/get-user',
 | 
					            url: '/api/login/get-user',
 | 
				
			||||||
| 
						 | 
					@ -518,28 +520,6 @@ 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>
 | 
					     * view_team <GET>
 | 
				
			||||||
     * @param teamId
 | 
					     * @param teamId
 | 
				
			||||||
| 
						 | 
					@ -801,6 +781,54 @@ 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>
 | 
					     * set_username <POST>
 | 
				
			||||||
     * @param requestBody
 | 
					     * @param requestBody
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,6 +19,9 @@ function logout() {
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <DropdownMenuRoot>
 | 
					  <DropdownMenuRoot>
 | 
				
			||||||
    <DropdownMenuTrigger className="profile-button no-border">
 | 
					    <DropdownMenuTrigger className="profile-button no-border">
 | 
				
			||||||
 | 
					      <span class="aside" v-if="authStore.realUser">
 | 
				
			||||||
 | 
					        {{ authStore.realUser?.username }}, disguised as
 | 
				
			||||||
 | 
					      </span>
 | 
				
			||||||
      {{ authStore.username }}
 | 
					      {{ authStore.username }}
 | 
				
			||||||
      <i class="bi bi-chevron-down" />
 | 
					      <i class="bi bi-chevron-down" />
 | 
				
			||||||
    </DropdownMenuTrigger>
 | 
					    </DropdownMenuTrigger>
 | 
				
			||||||
| 
						 | 
					@ -40,6 +43,14 @@ function logout() {
 | 
				
			||||||
            </button>
 | 
					            </button>
 | 
				
			||||||
          </RouterLink>
 | 
					          </RouterLink>
 | 
				
			||||||
        </DropdownMenuItem>
 | 
					        </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>
 | 
					        <DropdownMenuItem>
 | 
				
			||||||
          <button class="destructive" @click="logout">
 | 
					          <button class="destructive" @click="logout">
 | 
				
			||||||
            <i class="bi bi-box-arrow-right margin" />
 | 
					            <i class="bi bi-box-arrow-right margin" />
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,6 +13,9 @@ import TeamSettingsIntegrationsView from "@/views/TeamSettings/IntegrationsView.
 | 
				
			||||||
import TeamSettingsInvitesView from "@/views/TeamSettings/InvitesView.vue";
 | 
					import TeamSettingsInvitesView from "@/views/TeamSettings/InvitesView.vue";
 | 
				
			||||||
import TeamSettingsMatchesView from "@/views/TeamSettings/MatchesView.vue";
 | 
					import TeamSettingsMatchesView from "@/views/TeamSettings/MatchesView.vue";
 | 
				
			||||||
import UserSettingsView from "@/views/UserSettingsView.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({
 | 
					const router = createRouter({
 | 
				
			||||||
  history: createWebHistory(import.meta.env.BASE_URL),
 | 
					  history: createWebHistory(import.meta.env.BASE_URL),
 | 
				
			||||||
| 
						 | 
					@ -84,6 +87,23 @@ const router = createRouter({
 | 
				
			||||||
      name: "user-settings",
 | 
					      name: "user-settings",
 | 
				
			||||||
      component: UserSettingsView,
 | 
					      component: UserSettingsView,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      path: "/admin",
 | 
				
			||||||
 | 
					      name: "admin",
 | 
				
			||||||
 | 
					      component: AdminView,
 | 
				
			||||||
 | 
					      children: [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          path: "",
 | 
				
			||||||
 | 
					          name: "admin/",
 | 
				
			||||||
 | 
					          component: AdminGeneralView,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          path: "doas",
 | 
				
			||||||
 | 
					          name: "admin/doas",
 | 
				
			||||||
 | 
					          component: AdminDoasView,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
  ]
 | 
					  ]
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,18 +2,20 @@ import { defineStore } from "pinia";
 | 
				
			||||||
import { ref } from "vue";
 | 
					import { ref } from "vue";
 | 
				
			||||||
import { useClientStore } from "./client";
 | 
					import { useClientStore } from "./client";
 | 
				
			||||||
import { useRouter, type LocationQuery } from "vue-router";
 | 
					import { useRouter, type LocationQuery } from "vue-router";
 | 
				
			||||||
import { type PlayerSchema } from "@/client";
 | 
					import { type GetUserResponse, type PlayerSchema } from "@/client";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const useAuthStore = defineStore("auth", () => {
 | 
					export const useAuthStore = defineStore("auth", () => {
 | 
				
			||||||
  const clientStore = useClientStore();
 | 
					  const clientStore = useClientStore();
 | 
				
			||||||
  const client = clientStore.client;
 | 
					  const client = clientStore.client;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const user = ref<PlayerSchema | null>(null);
 | 
					  const user = ref<GetUserResponse | null>(null);
 | 
				
			||||||
  const steamId = ref("");
 | 
					  const steamId = ref("");
 | 
				
			||||||
  const username = ref("");
 | 
					  const username = ref("");
 | 
				
			||||||
  const isLoggedIn = ref(false);
 | 
					  const isLoggedIn = ref(false);
 | 
				
			||||||
  const isRegistering = ref(false);
 | 
					  const isRegistering = ref(false);
 | 
				
			||||||
  const hasCheckedAuth = ref(false);
 | 
					  const hasCheckedAuth = ref(false);
 | 
				
			||||||
 | 
					  const isAdmin = ref(false);
 | 
				
			||||||
 | 
					  const realUser = ref<PlayerSchema | null>(null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const router = useRouter();
 | 
					  const router = useRouter();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,6 +37,9 @@ export const useAuthStore = defineStore("auth", () => {
 | 
				
			||||||
        steamId.value = response.steamId;
 | 
					        steamId.value = response.steamId;
 | 
				
			||||||
        username.value = response.username;
 | 
					        username.value = response.username;
 | 
				
			||||||
        user.value = response;
 | 
					        user.value = response;
 | 
				
			||||||
 | 
					        isAdmin.value = response.isAdmin || (response.realUser?.isAdmin ?? false);
 | 
				
			||||||
 | 
					        realUser.value = response.realUser ?? null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return response;
 | 
					        return response;
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      undefined,
 | 
					      undefined,
 | 
				
			||||||
| 
						 | 
					@ -76,13 +81,48 @@ 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 {
 | 
					  return {
 | 
				
			||||||
    steamId,
 | 
					    steamId,
 | 
				
			||||||
    username,
 | 
					    username,
 | 
				
			||||||
 | 
					    isAdmin,
 | 
				
			||||||
 | 
					    realUser,
 | 
				
			||||||
    isLoggedIn,
 | 
					    isLoggedIn,
 | 
				
			||||||
    hasCheckedAuth,
 | 
					    hasCheckedAuth,
 | 
				
			||||||
    isRegistering,
 | 
					    isRegistering,
 | 
				
			||||||
    getUser,
 | 
					    getUser,
 | 
				
			||||||
 | 
					    getAllUsers,
 | 
				
			||||||
 | 
					    setDoas,
 | 
				
			||||||
 | 
					    unsetDoas,
 | 
				
			||||||
    login,
 | 
					    login,
 | 
				
			||||||
    logout,
 | 
					    logout,
 | 
				
			||||||
    setUsername,
 | 
					    setUsername,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,64 @@
 | 
				
			||||||
 | 
					<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>
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,9 @@
 | 
				
			||||||
 | 
					<script setup lang="ts">
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <h1>Admin Panel</h1>
 | 
				
			||||||
 | 
					  <p>
 | 
				
			||||||
 | 
					    This is the admin panel. Only admins can access this page.
 | 
				
			||||||
 | 
					  </p>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					<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>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <main class="team-settings" v-if="team">
 | 
					  <main class="sidebar-container team-settings" v-if="team">
 | 
				
			||||||
    <nav class="sidebar">
 | 
					    <nav class="sidebar">
 | 
				
			||||||
      <div class="categories">
 | 
					      <div class="categories">
 | 
				
			||||||
        <div class="back-link">
 | 
					        <div class="back-link">
 | 
				
			||||||
| 
						 | 
					@ -59,72 +59,7 @@ onMounted(() => {
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style scoped>
 | 
					<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 {
 | 
					.back-link {
 | 
				
			||||||
  padding: 8px 16px;
 | 
					  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>
 | 
					</style>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,17 +21,36 @@ STEAM_OPENID_URL = "https://steamcommunity.com/openid/login"
 | 
				
			||||||
def index():
 | 
					def index():
 | 
				
			||||||
    return "test"
 | 
					    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")
 | 
					@api_login.get("/get-user")
 | 
				
			||||||
@spec.validate(
 | 
					@spec.validate(
 | 
				
			||||||
    resp=Response(
 | 
					    resp=Response(
 | 
				
			||||||
        HTTP_200=PlayerSchema,
 | 
					        HTTP_200=GetUserResponse,
 | 
				
			||||||
        HTTP_401=None,
 | 
					        HTTP_401=None,
 | 
				
			||||||
    ),
 | 
					    ),
 | 
				
			||||||
    operation_id="get_user"
 | 
					    operation_id="get_user"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@requires_authentication
 | 
					@requires_authentication
 | 
				
			||||||
def get_user(player: Player, auth_session: AuthSession):
 | 
					def get_user(player: Player, auth_session: AuthSession):
 | 
				
			||||||
    return PlayerSchema.from_model(player).dict(by_alias=True)
 | 
					    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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@api_login.post("/authenticate")
 | 
					@api_login.post("/authenticate")
 | 
				
			||||||
def steam_authenticate():
 | 
					def steam_authenticate():
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@ from typing import Optional
 | 
				
			||||||
from flask import abort, make_response, request
 | 
					from flask import abort, make_response, request
 | 
				
			||||||
from sqlalchemy.sql.operators import json_path_getitem_op
 | 
					from sqlalchemy.sql.operators import json_path_getitem_op
 | 
				
			||||||
from app_db import db
 | 
					from app_db import db
 | 
				
			||||||
 | 
					from models import auth_session
 | 
				
			||||||
from models.auth_session import AuthSession
 | 
					from models.auth_session import AuthSession
 | 
				
			||||||
from models.player import Player
 | 
					from models.player import Player
 | 
				
			||||||
from models.player_team import PlayerTeam
 | 
					from models.player_team import PlayerTeam
 | 
				
			||||||
| 
						 | 
					@ -13,6 +14,7 @@ def requires_authentication(f):
 | 
				
			||||||
    @wraps(f)
 | 
					    @wraps(f)
 | 
				
			||||||
    def decorator(*args, **kwargs):
 | 
					    def decorator(*args, **kwargs):
 | 
				
			||||||
        auth = request.cookies.get("auth")
 | 
					        auth = request.cookies.get("auth")
 | 
				
			||||||
 | 
					        doas = request.cookies.get("doas")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if not auth:
 | 
					        if not auth:
 | 
				
			||||||
            abort(401)
 | 
					            abort(401)
 | 
				
			||||||
| 
						 | 
					@ -28,6 +30,30 @@ def requires_authentication(f):
 | 
				
			||||||
        player = auth_session.player
 | 
					        player = auth_session.player
 | 
				
			||||||
        kwargs["player"] = player
 | 
					        kwargs["player"] = player
 | 
				
			||||||
        kwargs["auth_session"] = auth_session
 | 
					        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 f(*args, **kwargs)
 | 
				
			||||||
    return decorator
 | 
					    return decorator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
from flask import Blueprint
 | 
					from flask import Blueprint, abort, make_response
 | 
				
			||||||
from spectree import Response
 | 
					from spectree import Response
 | 
				
			||||||
from middleware import requires_authentication
 | 
					from middleware import requires_admin, requires_authentication
 | 
				
			||||||
from models.player import Player, PlayerSchema
 | 
					from models.player import Player, PlayerSchema
 | 
				
			||||||
from spec import spec, BaseModel
 | 
					from spec import spec, BaseModel
 | 
				
			||||||
from app_db import db
 | 
					from app_db import db
 | 
				
			||||||
| 
						 | 
					@ -23,3 +23,53 @@ def set_username(json: SetUsernameJson, player: Player, **kwargs):
 | 
				
			||||||
    player.username = json.username
 | 
					    player.username = json.username
 | 
				
			||||||
    db.session.commit()
 | 
					    db.session.commit()
 | 
				
			||||||
    return PlayerSchema.from_model(player).dict(by_alias=True), 200
 | 
					    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