Make registration RESTful
							parent
							
								
									6821447c74
								
							
						
					
					
						commit
						afba73e1e8
					
				| 
						 | 
				
			
			@ -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';
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,7 @@
 | 
			
		|||
export type CreateTeamJson = {
 | 
			
		||||
    discordWebhookUrl?: string;
 | 
			
		||||
    leagueTimezone: string;
 | 
			
		||||
    minuteOffset?: number;
 | 
			
		||||
    teamName: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,8 @@
 | 
			
		|||
/* generated using openapi-typescript-codegen -- do not edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
export type SetUsernameJson = {
 | 
			
		||||
    username: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3,7 +3,7 @@
 | 
			
		|||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
export type TeamSchema = {
 | 
			
		||||
    discordWebhookUrl?: string;
 | 
			
		||||
    createdAt: string;
 | 
			
		||||
    id: number;
 | 
			
		||||
    minuteOffset: number;
 | 
			
		||||
    teamName: string;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 <POST>
 | 
			
		||||
     * @param requestBody
 | 
			
		||||
     * @returns PlayerSchema OK
 | 
			
		||||
     * @throws ApiError
 | 
			
		||||
     */
 | 
			
		||||
    public setUsername(
 | 
			
		||||
        requestBody?: SetUsernameJson,
 | 
			
		||||
    ): CancelablePromise<PlayerSchema> {
 | 
			
		||||
        return this.httpRequest.request({
 | 
			
		||||
            method: 'POST',
 | 
			
		||||
            url: '/api/user/username',
 | 
			
		||||
            body: requestBody,
 | 
			
		||||
            mediaType: 'application/json',
 | 
			
		||||
            errors: {
 | 
			
		||||
                422: `Unprocessable Entity`,
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,7 +38,11 @@ const router = createRouter({
 | 
			
		|||
    {
 | 
			
		||||
      path: "/team/id/:id",
 | 
			
		||||
      name: "team-details",
 | 
			
		||||
      component: TeamDetailsView
 | 
			
		||||
      component: TeamDetailsView,
 | 
			
		||||
      //children: [
 | 
			
		||||
      //  path: "members",
 | 
			
		||||
      //  component:
 | 
			
		||||
      //],
 | 
			
		||||
    },
 | 
			
		||||
  ]
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -49,12 +53,14 @@ router
 | 
			
		|||
    const authStore = useAuthStore();
 | 
			
		||||
    console.log("test");
 | 
			
		||||
    if (!authStore.isLoggedIn && !authStore.hasCheckedAuth) {
 | 
			
		||||
      if (to.name != "login") {
 | 
			
		||||
        try {
 | 
			
		||||
          await authStore.getUser();
 | 
			
		||||
        } catch (exception) {
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
export default router;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,48 +1,75 @@
 | 
			
		|||
<script setup lang="ts">
 | 
			
		||||
import { useAuthStore } from "../stores/auth";
 | 
			
		||||
import { onMounted, ref } from "vue";
 | 
			
		||||
import { computed, onMounted, ref } from "vue";
 | 
			
		||||
import { useRoute, useRouter } from "vue-router";
 | 
			
		||||
 | 
			
		||||
const route = useRoute();
 | 
			
		||||
const router = useRouter();
 | 
			
		||||
const queryParams = route.query;
 | 
			
		||||
const queryParams = computed(() => route.query);
 | 
			
		||||
 | 
			
		||||
const auth = useAuthStore();
 | 
			
		||||
 | 
			
		||||
const registerUsername = ref("");
 | 
			
		||||
 | 
			
		||||
function register() {
 | 
			
		||||
  const params = {
 | 
			
		||||
    ...queryParams,
 | 
			
		||||
    username: registerUsername,
 | 
			
		||||
  }
 | 
			
		||||
  //const params = {
 | 
			
		||||
  //  ...queryParams.value,
 | 
			
		||||
  //  username: registerUsername.value,
 | 
			
		||||
  //};
 | 
			
		||||
 | 
			
		||||
  auth.login(params)
 | 
			
		||||
  //auth.login(params)
 | 
			
		||||
  //  .then(() => router.push("/"));
 | 
			
		||||
  auth.setUsername(registerUsername.value)
 | 
			
		||||
    .then(() => router.push("/"));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
  if (Object.keys(queryParams).length == 0) {
 | 
			
		||||
    auth.isRegistering = true;
 | 
			
		||||
    return;
 | 
			
		||||
  auth.login(queryParams.value)
 | 
			
		||||
    .then(() => {
 | 
			
		||||
      if (!auth.isRegistering) {
 | 
			
		||||
        router.push("/");
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
  auth.login(queryParams)
 | 
			
		||||
    .then(() => router.push("/"));
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div>
 | 
			
		||||
  <main>
 | 
			
		||||
    <div class="login-container">
 | 
			
		||||
      <template v-if="auth.isRegistering">
 | 
			
		||||
        <h1>Register</h1>
 | 
			
		||||
        <h1>New account</h1>
 | 
			
		||||
        <p>
 | 
			
		||||
          Your account has been newly created. Select a username to be
 | 
			
		||||
          associated with this account.
 | 
			
		||||
        </p>
 | 
			
		||||
        <div class="form-group margin">
 | 
			
		||||
          <h3>Username</h3>
 | 
			
		||||
          <input v-model="registerUsername" />
 | 
			
		||||
        <button class="accent" type="submit">Register</button>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="form-group margin">
 | 
			
		||||
          <div class="action-buttons">
 | 
			
		||||
            <button class="accent" type="submit" @click="register()">
 | 
			
		||||
              Save
 | 
			
		||||
            </button>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </template>
 | 
			
		||||
      <div v-else>
 | 
			
		||||
        Logging in...
 | 
			
		||||
      </div>
 | 
			
		||||
    </main>
 | 
			
		||||
    </div>
 | 
			
		||||
  </main>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
.login-container {
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  max-width: 500px;
 | 
			
		||||
  margin: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
h3 {
 | 
			
		||||
  font-size: 11pt;
 | 
			
		||||
  font-weight: 700;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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() {
 | 
			
		|||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <em class="aside">
 | 
			
		||||
          Matches will be scheduled against {{ timezone }} at
 | 
			
		||||
          Matches will be scheduled based on {{ timezone }} at
 | 
			
		||||
          {{ minuteOffset }}
 | 
			
		||||
          <span v-if="minuteOffset == 1">
 | 
			
		||||
            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;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.username = str(steam_id)
 | 
			
		||||
            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,
 | 
			
		||||
                })
 | 
			
		||||
            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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
		Loading…
	
		Reference in New Issue