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 { 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';
|
||||||
|
export type { SetUsernameJson } from './models/SetUsernameJson';
|
||||||
export type { TeamInviteSchema } from './models/TeamInviteSchema';
|
export type { TeamInviteSchema } from './models/TeamInviteSchema';
|
||||||
export type { TeamInviteSchemaList } from './models/TeamInviteSchemaList';
|
export type { TeamInviteSchemaList } from './models/TeamInviteSchemaList';
|
||||||
export { TeamRole } from './models/TeamRole';
|
export { TeamRole } from './models/TeamRole';
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
export type CreateTeamJson = {
|
export type CreateTeamJson = {
|
||||||
discordWebhookUrl?: string;
|
discordWebhookUrl?: string;
|
||||||
leagueTimezone: string;
|
leagueTimezone: string;
|
||||||
|
minuteOffset?: number;
|
||||||
teamName: string;
|
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 */
|
/* tslint:disable */
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
export type TeamSchema = {
|
export type TeamSchema = {
|
||||||
discordWebhookUrl?: string;
|
createdAt: string;
|
||||||
id: number;
|
id: number;
|
||||||
minuteOffset: number;
|
minuteOffset: number;
|
||||||
teamName: string;
|
teamName: string;
|
||||||
|
|
|
@ -7,6 +7,7 @@ import type { CreateTeamJson } from '../models/CreateTeamJson';
|
||||||
import type { EditMemberRolesJson } from '../models/EditMemberRolesJson';
|
import type { EditMemberRolesJson } from '../models/EditMemberRolesJson';
|
||||||
import type { PlayerSchema } from '../models/PlayerSchema';
|
import type { PlayerSchema } from '../models/PlayerSchema';
|
||||||
import type { PutScheduleForm } from '../models/PutScheduleForm';
|
import type { PutScheduleForm } from '../models/PutScheduleForm';
|
||||||
|
import type { SetUsernameJson } from '../models/SetUsernameJson';
|
||||||
import type { TeamInviteSchema } from '../models/TeamInviteSchema';
|
import type { TeamInviteSchema } from '../models/TeamInviteSchema';
|
||||||
import type { TeamInviteSchemaList } from '../models/TeamInviteSchemaList';
|
import type { TeamInviteSchemaList } from '../models/TeamInviteSchemaList';
|
||||||
import type { ViewAvailablePlayersResponse } from '../models/ViewAvailablePlayersResponse';
|
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",
|
path: "/team/id/:id",
|
||||||
name: "team-details",
|
name: "team-details",
|
||||||
component: TeamDetailsView
|
component: TeamDetailsView,
|
||||||
|
//children: [
|
||||||
|
// path: "members",
|
||||||
|
// component:
|
||||||
|
//],
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
@ -49,10 +53,12 @@ router
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
console.log("test");
|
console.log("test");
|
||||||
if (!authStore.isLoggedIn && !authStore.hasCheckedAuth) {
|
if (!authStore.isLoggedIn && !authStore.hasCheckedAuth) {
|
||||||
try {
|
if (to.name != "login") {
|
||||||
await authStore.getUser();
|
try {
|
||||||
} catch (exception) {
|
await authStore.getUser();
|
||||||
|
} catch (exception) {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -46,6 +46,10 @@ export const useAuthStore = defineStore("auth", () => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function setUsername(username: string) {
|
||||||
|
return client.default.setUsername({ username });
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
steamId,
|
steamId,
|
||||||
username,
|
username,
|
||||||
|
@ -54,5 +58,6 @@ export const useAuthStore = defineStore("auth", () => {
|
||||||
isRegistering,
|
isRegistering,
|
||||||
getUser,
|
getUser,
|
||||||
login,
|
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({
|
return await client.default.createTeam({
|
||||||
teamName,
|
teamName,
|
||||||
leagueTimezone: tz,
|
leagueTimezone: tz,
|
||||||
discordWebhookUrl: webhook,
|
minuteOffset,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,48 +1,75 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useAuthStore } from "../stores/auth";
|
import { useAuthStore } from "../stores/auth";
|
||||||
import { onMounted, ref } from "vue";
|
import { computed, onMounted, ref } from "vue";
|
||||||
import { useRoute, useRouter } from "vue-router";
|
import { useRoute, useRouter } from "vue-router";
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const queryParams = route.query;
|
const queryParams = computed(() => route.query);
|
||||||
|
|
||||||
const auth = useAuthStore();
|
const auth = useAuthStore();
|
||||||
|
|
||||||
const registerUsername = ref("");
|
const registerUsername = ref("");
|
||||||
|
|
||||||
function register() {
|
function register() {
|
||||||
const params = {
|
//const params = {
|
||||||
...queryParams,
|
// ...queryParams.value,
|
||||||
username: registerUsername,
|
// username: registerUsername.value,
|
||||||
}
|
//};
|
||||||
|
|
||||||
auth.login(params)
|
//auth.login(params)
|
||||||
|
// .then(() => router.push("/"));
|
||||||
|
auth.setUsername(registerUsername.value)
|
||||||
.then(() => router.push("/"));
|
.then(() => router.push("/"));
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (Object.keys(queryParams).length == 0) {
|
auth.login(queryParams.value)
|
||||||
auth.isRegistering = true;
|
.then(() => {
|
||||||
return;
|
if (!auth.isRegistering) {
|
||||||
}
|
router.push("/");
|
||||||
|
}
|
||||||
auth.login(queryParams)
|
});
|
||||||
.then(() => router.push("/"));
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<main>
|
||||||
<main>
|
<div class="login-container">
|
||||||
<template v-if="auth.isRegistering">
|
<template v-if="auth.isRegistering">
|
||||||
<h1>Register</h1>
|
<h1>New account</h1>
|
||||||
<input v-model="registerUsername" />
|
<p>
|
||||||
<button class="accent" type="submit">Register</button>
|
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" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group margin">
|
||||||
|
<div class="action-buttons">
|
||||||
|
<button class="accent" type="submit" @click="register()">
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
Logging in...
|
Logging in...
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</div>
|
||||||
</div>
|
</main>
|
||||||
</template>
|
</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("");
|
const webhook = ref("");
|
||||||
|
|
||||||
function createTeam() {
|
function createTeam() {
|
||||||
teams.createTeam(teamName.value, timezone.value, webhook.value)
|
teams.createTeam(teamName.value, timezone.value, minuteOffset.value)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
router.push("/");
|
router.push("/");
|
||||||
});
|
});
|
||||||
|
@ -64,7 +64,7 @@ function createTeam() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<em class="aside">
|
<em class="aside">
|
||||||
Matches will be scheduled against {{ timezone }} at
|
Matches will be scheduled based on {{ timezone }} at
|
||||||
{{ minuteOffset }}
|
{{ minuteOffset }}
|
||||||
<span v-if="minuteOffset == 1">
|
<span v-if="minuteOffset == 1">
|
||||||
minute
|
minute
|
||||||
|
@ -107,23 +107,6 @@ function createTeam() {
|
||||||
font-size: 9pt;
|
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 {
|
#minute-offset-group {
|
||||||
flex-grow: unset;
|
flex-grow: unset;
|
||||||
flex-shrink: 1;
|
flex-shrink: 1;
|
||||||
|
@ -135,9 +118,4 @@ input {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-buttons {
|
|
||||||
display: flex;
|
|
||||||
justify-content: end;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -5,6 +5,7 @@ import login
|
||||||
import schedule
|
import schedule
|
||||||
import team
|
import team
|
||||||
from spec import spec
|
from spec import spec
|
||||||
|
import user
|
||||||
|
|
||||||
connect_db_with_app()
|
connect_db_with_app()
|
||||||
|
|
||||||
|
@ -12,6 +13,7 @@ api = Blueprint("api", __name__, url_prefix="/api")
|
||||||
api.register_blueprint(login.api_login)
|
api.register_blueprint(login.api_login)
|
||||||
api.register_blueprint(schedule.api_schedule)
|
api.register_blueprint(schedule.api_schedule)
|
||||||
api.register_blueprint(team.api_team)
|
api.register_blueprint(team.api_team)
|
||||||
|
api.register_blueprint(user.api_user)
|
||||||
|
|
||||||
@api.get("/debug/set-cookie")
|
@api.get("/debug/set-cookie")
|
||||||
@api.post("/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.auth_session import AuthSession
|
||||||
from models.player import Player, PlayerSchema
|
from models.player import Player, PlayerSchema
|
||||||
from middleware import requires_authentication
|
from middleware import requires_authentication
|
||||||
|
import sys
|
||||||
|
|
||||||
api_login = Blueprint("login", __name__, url_prefix="/login")
|
api_login = Blueprint("login", __name__, url_prefix="/login")
|
||||||
|
|
||||||
|
@ -36,7 +37,14 @@ def get_user(player: Player, auth_session: AuthSession):
|
||||||
def steam_authenticate():
|
def steam_authenticate():
|
||||||
params = request.get_json()
|
params = request.get_json()
|
||||||
params["openid.mode"] = "check_authentication"
|
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
|
# check if authentication was successful
|
||||||
if "is_valid:true" in response.text:
|
if "is_valid:true" in response.text:
|
||||||
|
@ -50,19 +58,14 @@ def steam_authenticate():
|
||||||
Player.steam_id == steam_id
|
Player.steam_id == steam_id
|
||||||
).one_or_none()
|
).one_or_none()
|
||||||
|
|
||||||
|
is_registering = False
|
||||||
if not player:
|
if not player:
|
||||||
if "username" in params:
|
# we are registering, so create user
|
||||||
# we are registering, so create user
|
player = Player()
|
||||||
player = Player()
|
player.username = str(steam_id)
|
||||||
player.username = params["username"]
|
player.steam_id = steam_id
|
||||||
player.steam_id = steam_id
|
is_registering = True
|
||||||
else:
|
db.session.add(player)
|
||||||
# prompt client to resend with username field
|
|
||||||
return make_response({
|
|
||||||
"message": "Awaiting registration",
|
|
||||||
"hint": "Resend the POST request with a username field",
|
|
||||||
"isRegistering": True,
|
|
||||||
})
|
|
||||||
|
|
||||||
auth_session = create_auth_session_for_player(player)
|
auth_session = create_auth_session_for_player(player)
|
||||||
|
|
||||||
|
@ -70,6 +73,7 @@ def steam_authenticate():
|
||||||
"message": "Logged in",
|
"message": "Logged in",
|
||||||
"steamId": player.steam_id,
|
"steamId": player.steam_id,
|
||||||
"username": player.username,
|
"username": player.username,
|
||||||
|
"isRegistering": is_registering,
|
||||||
})
|
})
|
||||||
|
|
||||||
# TODO: secure=True in production
|
# 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