From afba73e1e858dda743848db46fddfce3bda3700b Mon Sep 17 00:00:00 2001 From: HumanoidSandvichDispenser Date: Fri, 15 Nov 2024 19:37:41 -0800 Subject: [PATCH] Make registration RESTful --- availabili.tf/src/client/index.ts | 1 + .../src/client/models/CreateTeamJson.ts | 1 + .../src/client/models/SetUsernameJson.ts | 8 +++ availabili.tf/src/client/models/TeamSchema.ts | 2 +- .../src/client/services/DefaultService.ts | 20 ++++++ availabili.tf/src/router/index.ts | 14 ++-- availabili.tf/src/stores/auth.ts | 5 ++ availabili.tf/src/stores/teams.ts | 4 +- availabili.tf/src/views/LoginView.vue | 69 +++++++++++++------ .../src/views/TeamRegistrationView.vue | 26 +------ backend-flask/app.py | 2 + backend-flask/login.py | 30 ++++---- backend-flask/user.py | 25 +++++++ 13 files changed, 142 insertions(+), 65 deletions(-) create mode 100644 availabili.tf/src/client/models/SetUsernameJson.ts create mode 100644 backend-flask/user.py diff --git a/availabili.tf/src/client/index.ts b/availabili.tf/src/client/index.ts index 65f54fc..14b2bea 100644 --- a/availabili.tf/src/client/index.ts +++ b/availabili.tf/src/client/index.ts @@ -18,6 +18,7 @@ export type { PlayerSchema } from './models/PlayerSchema'; export type { PlayerTeamAvailabilityRoleSchema } from './models/PlayerTeamAvailabilityRoleSchema'; export type { PutScheduleForm } from './models/PutScheduleForm'; export type { RoleSchema } from './models/RoleSchema'; +export type { SetUsernameJson } from './models/SetUsernameJson'; export type { TeamInviteSchema } from './models/TeamInviteSchema'; export type { TeamInviteSchemaList } from './models/TeamInviteSchemaList'; export { TeamRole } from './models/TeamRole'; diff --git a/availabili.tf/src/client/models/CreateTeamJson.ts b/availabili.tf/src/client/models/CreateTeamJson.ts index 4308733..16b4907 100644 --- a/availabili.tf/src/client/models/CreateTeamJson.ts +++ b/availabili.tf/src/client/models/CreateTeamJson.ts @@ -5,6 +5,7 @@ export type CreateTeamJson = { discordWebhookUrl?: string; leagueTimezone: string; + minuteOffset?: number; teamName: string; }; diff --git a/availabili.tf/src/client/models/SetUsernameJson.ts b/availabili.tf/src/client/models/SetUsernameJson.ts new file mode 100644 index 0000000..e7ff0df --- /dev/null +++ b/availabili.tf/src/client/models/SetUsernameJson.ts @@ -0,0 +1,8 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type SetUsernameJson = { + username: string; +}; + diff --git a/availabili.tf/src/client/models/TeamSchema.ts b/availabili.tf/src/client/models/TeamSchema.ts index 8189561..49ce029 100644 --- a/availabili.tf/src/client/models/TeamSchema.ts +++ b/availabili.tf/src/client/models/TeamSchema.ts @@ -3,7 +3,7 @@ /* tslint:disable */ /* eslint-disable */ export type TeamSchema = { - discordWebhookUrl?: string; + createdAt: string; id: number; minuteOffset: number; teamName: string; diff --git a/availabili.tf/src/client/services/DefaultService.ts b/availabili.tf/src/client/services/DefaultService.ts index c96288b..4b07ef2 100644 --- a/availabili.tf/src/client/services/DefaultService.ts +++ b/availabili.tf/src/client/services/DefaultService.ts @@ -7,6 +7,7 @@ import type { CreateTeamJson } from '../models/CreateTeamJson'; import type { EditMemberRolesJson } from '../models/EditMemberRolesJson'; import type { PlayerSchema } from '../models/PlayerSchema'; import type { PutScheduleForm } from '../models/PutScheduleForm'; +import type { SetUsernameJson } from '../models/SetUsernameJson'; import type { TeamInviteSchema } from '../models/TeamInviteSchema'; import type { TeamInviteSchemaList } from '../models/TeamInviteSchemaList'; import type { ViewAvailablePlayersResponse } from '../models/ViewAvailablePlayersResponse'; @@ -455,4 +456,23 @@ export class DefaultService { }, }); } + /** + * set_username + * @param requestBody + * @returns PlayerSchema OK + * @throws ApiError + */ + public setUsername( + requestBody?: SetUsernameJson, + ): CancelablePromise { + return this.httpRequest.request({ + method: 'POST', + url: '/api/user/username', + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Unprocessable Entity`, + }, + }); + } } diff --git a/availabili.tf/src/router/index.ts b/availabili.tf/src/router/index.ts index c93085d..3359ec6 100644 --- a/availabili.tf/src/router/index.ts +++ b/availabili.tf/src/router/index.ts @@ -38,7 +38,11 @@ const router = createRouter({ { path: "/team/id/:id", name: "team-details", - component: TeamDetailsView + component: TeamDetailsView, + //children: [ + // path: "members", + // component: + //], }, ] }); @@ -49,10 +53,12 @@ router const authStore = useAuthStore(); console.log("test"); if (!authStore.isLoggedIn && !authStore.hasCheckedAuth) { - try { - await authStore.getUser(); - } catch (exception) { + if (to.name != "login") { + try { + await authStore.getUser(); + } catch (exception) { + } } } }); diff --git a/availabili.tf/src/stores/auth.ts b/availabili.tf/src/stores/auth.ts index ca6b2d1..05cba92 100644 --- a/availabili.tf/src/stores/auth.ts +++ b/availabili.tf/src/stores/auth.ts @@ -46,6 +46,10 @@ export const useAuthStore = defineStore("auth", () => { }); } + async function setUsername(username: string) { + return client.default.setUsername({ username }); + } + return { steamId, username, @@ -54,5 +58,6 @@ export const useAuthStore = defineStore("auth", () => { isRegistering, getUser, login, + setUsername, } }); diff --git a/availabili.tf/src/stores/teams.ts b/availabili.tf/src/stores/teams.ts index 0b566ae..242053a 100644 --- a/availabili.tf/src/stores/teams.ts +++ b/availabili.tf/src/stores/teams.ts @@ -65,11 +65,11 @@ export const useTeamsStore = defineStore("teams", () => { ); } - async function createTeam(teamName: string, tz: string, webhook?: string) { + async function createTeam(teamName: string, tz: string, minuteOffset: number) { return await client.default.createTeam({ teamName, leagueTimezone: tz, - discordWebhookUrl: webhook, + minuteOffset, }); } diff --git a/availabili.tf/src/views/LoginView.vue b/availabili.tf/src/views/LoginView.vue index e59eb91..08b4e9b 100644 --- a/availabili.tf/src/views/LoginView.vue +++ b/availabili.tf/src/views/LoginView.vue @@ -1,48 +1,75 @@ + + diff --git a/availabili.tf/src/views/TeamRegistrationView.vue b/availabili.tf/src/views/TeamRegistrationView.vue index 5e05de3..e51698f 100644 --- a/availabili.tf/src/views/TeamRegistrationView.vue +++ b/availabili.tf/src/views/TeamRegistrationView.vue @@ -24,7 +24,7 @@ watch(minuteOffset, (newValue) => { const webhook = ref(""); function createTeam() { - teams.createTeam(teamName.value, timezone.value, webhook.value) + teams.createTeam(teamName.value, timezone.value, minuteOffset.value) .then(() => { router.push("/"); }); @@ -64,7 +64,7 @@ function createTeam() { - Matches will be scheduled against {{ timezone }} at + Matches will be scheduled based on {{ timezone }} at {{ minuteOffset }} minute @@ -107,23 +107,6 @@ function createTeam() { font-size: 9pt; } -.form-group { - display: flex; - flex-direction: column; - gap: 4px; - flex-grow: 1; -} - -.form-group.margin { - margin-top: 16px; - margin-bottom: 16px; -} - -.form-group.row { - flex-direction: row; - margin: none; -} - #minute-offset-group { flex-grow: unset; flex-shrink: 1; @@ -135,9 +118,4 @@ input { width: 100%; color: var(--text); } - -.action-buttons { - display: flex; - justify-content: end; -} diff --git a/backend-flask/app.py b/backend-flask/app.py index 0f67939..1b48ef5 100644 --- a/backend-flask/app.py +++ b/backend-flask/app.py @@ -5,6 +5,7 @@ import login import schedule import team from spec import spec +import user connect_db_with_app() @@ -12,6 +13,7 @@ api = Blueprint("api", __name__, url_prefix="/api") api.register_blueprint(login.api_login) api.register_blueprint(schedule.api_schedule) api.register_blueprint(team.api_team) +api.register_blueprint(user.api_user) @api.get("/debug/set-cookie") @api.post("/debug/set-cookie") diff --git a/backend-flask/login.py b/backend-flask/login.py index d57b2a9..baee8ed 100644 --- a/backend-flask/login.py +++ b/backend-flask/login.py @@ -11,6 +11,7 @@ from app_db import db from models.auth_session import AuthSession from models.player import Player, PlayerSchema from middleware import requires_authentication +import sys api_login = Blueprint("login", __name__, url_prefix="/login") @@ -36,7 +37,14 @@ def get_user(player: Player, auth_session: AuthSession): def steam_authenticate(): params = request.get_json() params["openid.mode"] = "check_authentication" - response = requests.post(STEAM_OPENID_URL, data=params) + + steam_params = params + if "username" in steam_params: + del steam_params["username"] + + response = requests.post(STEAM_OPENID_URL, data=steam_params) + print("response text = ", file=sys.stderr) + print(response.text, file=sys.stderr) # check if authentication was successful if "is_valid:true" in response.text: @@ -50,19 +58,14 @@ def steam_authenticate(): Player.steam_id == steam_id ).one_or_none() + is_registering = False if not player: - if "username" in params: - # we are registering, so create user - player = Player() - player.username = params["username"] - player.steam_id = steam_id - else: - # prompt client to resend with username field - return make_response({ - "message": "Awaiting registration", - "hint": "Resend the POST request with a username field", - "isRegistering": True, - }) + # we are registering, so create user + player = Player() + player.username = str(steam_id) + player.steam_id = steam_id + is_registering = True + db.session.add(player) auth_session = create_auth_session_for_player(player) @@ -70,6 +73,7 @@ def steam_authenticate(): "message": "Logged in", "steamId": player.steam_id, "username": player.username, + "isRegistering": is_registering, }) # TODO: secure=True in production diff --git a/backend-flask/user.py b/backend-flask/user.py new file mode 100644 index 0000000..28be115 --- /dev/null +++ b/backend-flask/user.py @@ -0,0 +1,25 @@ +from flask import Blueprint +from spectree import Response +from middleware import requires_authentication +from models.player import Player, PlayerSchema +from spec import spec, BaseModel +from app_db import db + + +api_user = Blueprint("user", __name__, url_prefix="/user") + +class SetUsernameJson(BaseModel): + username: str + +@api_user.post("username") +@spec.validate( + resp=Response( + HTTP_200=PlayerSchema, + ), + operation_id="set_username", +) +@requires_authentication +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