Finished implementing match endpoints
This commit is contained in:
@@ -5,13 +5,13 @@ info:
|
|||||||
|
|
||||||
http:
|
http:
|
||||||
method: DELETE
|
method: DELETE
|
||||||
url: "{{BASE_URL}}/{{SECTOR}}/{{UserID}}"
|
url: "{{BASE_URL}}/{{SECTOR}}/{{MatchID}}"
|
||||||
auth: inherit
|
auth: inherit
|
||||||
|
|
||||||
runtime:
|
runtime:
|
||||||
variables:
|
variables:
|
||||||
- name: UserID
|
- name: MatchID
|
||||||
value: ""
|
value: 846M1L
|
||||||
|
|
||||||
settings:
|
settings:
|
||||||
encodeUrl: true
|
encodeUrl: true
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ http:
|
|||||||
runtime:
|
runtime:
|
||||||
variables:
|
variables:
|
||||||
- name: MatchID
|
- name: MatchID
|
||||||
value: 9YQ84M
|
value: 848O12
|
||||||
|
|
||||||
settings:
|
settings:
|
||||||
encodeUrl: true
|
encodeUrl: true
|
||||||
|
|||||||
23
API Tests/BGApp/Matches/Leave.yml
Normal file
23
API Tests/BGApp/Matches/Leave.yml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
info:
|
||||||
|
name: Leave
|
||||||
|
type: http
|
||||||
|
seq: 4
|
||||||
|
|
||||||
|
http:
|
||||||
|
method: POST
|
||||||
|
url: "{{BASE_URL}}/{{SECTOR}}/{{MatchID}}/leave"
|
||||||
|
body:
|
||||||
|
type: json
|
||||||
|
data: ""
|
||||||
|
auth: inherit
|
||||||
|
|
||||||
|
runtime:
|
||||||
|
variables:
|
||||||
|
- name: MatchID
|
||||||
|
value: 848O12
|
||||||
|
|
||||||
|
settings:
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
followRedirects: true
|
||||||
|
maxRedirects: 5
|
||||||
@@ -11,7 +11,7 @@ http:
|
|||||||
runtime:
|
runtime:
|
||||||
variables:
|
variables:
|
||||||
- name: PlayerID
|
- name: PlayerID
|
||||||
value: ""
|
value: 539DPX
|
||||||
|
|
||||||
settings:
|
settings:
|
||||||
encodeUrl: true
|
encodeUrl: true
|
||||||
|
|||||||
@@ -30,7 +30,17 @@ async function get(request: UnwrappedRequest): Promise<Response> {
|
|||||||
|
|
||||||
async function drop(request: UnwrappedRequest): Promise<Response> {
|
async function drop(request: UnwrappedRequest): Promise<Response> {
|
||||||
try {
|
try {
|
||||||
return new OkResponse(await orm.matches.drop(UserId.fromHash(request.params.id), request.claims));
|
return new OkResponse(await orm.matches.drop(MatchId.fromHash(request.params.id), request.claims));
|
||||||
|
} catch (error: any) {
|
||||||
|
return new ErrorResponse(error as Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function leave(request: UnwrappedRequest): Promise<Response> {
|
||||||
|
try {
|
||||||
|
return new OkResponse(
|
||||||
|
await orm.matches.removePlayer(MatchId.fromHash(request.params.id), request.claims.userId as UserId),
|
||||||
|
);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
return new ErrorResponse(error as Error);
|
return new ErrorResponse(error as Error);
|
||||||
}
|
}
|
||||||
@@ -40,4 +50,5 @@ export default {
|
|||||||
create,
|
create,
|
||||||
get,
|
get,
|
||||||
drop,
|
drop,
|
||||||
|
leave,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { first, orderBy } from 'lodash';
|
|||||||
import { BadRequestError, NotFoundError, UnauthorizedError } from '../utilities/errors';
|
import { BadRequestError, NotFoundError, UnauthorizedError } from '../utilities/errors';
|
||||||
import { GameId, MatchId, PlayerId, UserId } from '../utilities/secureIds';
|
import { GameId, MatchId, PlayerId, UserId } from '../utilities/secureIds';
|
||||||
import { calculateElos } from '../utilities/elo';
|
import { calculateElos } from '../utilities/elo';
|
||||||
|
import { orm } from './orm';
|
||||||
|
|
||||||
export class MatchParticipant {
|
export class MatchParticipant {
|
||||||
matchId?: MatchId;
|
matchId?: MatchId;
|
||||||
@@ -125,13 +126,14 @@ export class MatchOrm {
|
|||||||
throw new UnauthorizedError();
|
throw new UnauthorizedError();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dbResult) {
|
const matchData = dbResult?.find((x: any) => x.match_id);
|
||||||
throw new NotFoundError('No matching user exists');
|
if (!matchData?.match_id) {
|
||||||
|
throw new NotFoundError('No matching match exists');
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Match(
|
return new Match(
|
||||||
MatchId.fromID(dbResult?.[0]?.match_id),
|
MatchId.fromID(matchData?.match_id),
|
||||||
GameId.fromID(dbResult?.[0]?.game_id),
|
GameId.fromID(matchData?.game_id),
|
||||||
orderBy(
|
orderBy(
|
||||||
dbResult
|
dbResult
|
||||||
.filter((x: any) => x.player_id)
|
.filter((x: any) => x.player_id)
|
||||||
@@ -152,28 +154,52 @@ export class MatchOrm {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async drop(id: UserId, claims?: Claims): Promise<void> {
|
async drop(id: MatchId, claims?: Claims): Promise<void> {
|
||||||
// if (
|
const match = await this.get(id);
|
||||||
// !(
|
if (
|
||||||
// Claims.test(Claims.ADMIN, claims) ||
|
!(
|
||||||
// Claims.test(Claims.USERS.OTHER.DELETE, claims) ||
|
Claims.test(Claims.ADMIN, claims) ||
|
||||||
// (Claims.test(Claims.USERS.SELF.DELETE, claims) && id === claims?.userId)
|
(Claims.test(Claims.MATCHES.OWNED.DELETE, claims) && match.owner === claims?.userId)
|
||||||
// )
|
)
|
||||||
// ) {
|
) {
|
||||||
// throw new UnauthorizedError();
|
throw new UnauthorizedError();
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// // Ensure user exists before attempting to delete
|
await sql.transaction(async (tx) => {
|
||||||
// await this.get(id);
|
await tx`DELETE
|
||||||
// await sql.transaction(async (tx) => {
|
FROM match_players
|
||||||
// await tx`DELETE
|
WHERE match_id = ${id.raw}`;
|
||||||
// FROM user_claims
|
await tx`DELETE
|
||||||
// WHERE user_id = ${id.raw}`;
|
FROM matches
|
||||||
// await tx`DELETE
|
WHERE id = ${id.raw}`;
|
||||||
// FROM users
|
});
|
||||||
// WHERE id = ${id.raw}`;
|
|
||||||
// });
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async removePlayer(matchId: MatchId, participantId: UserId): Promise<void>;
|
||||||
|
async removePlayer(matchId: MatchId, participantId: PlayerId): Promise<void> {
|
||||||
|
let playerId: PlayerId = participantId;
|
||||||
|
if (participantId instanceof UserId) {
|
||||||
|
playerId = (await orm.users.get(participantId))?.playerId;
|
||||||
|
if (!playerId) {
|
||||||
|
throw new BadRequestError('User is not a participant');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const player = await orm.players.get(playerId);
|
||||||
|
|
||||||
|
sql.transaction(async (tx) => {
|
||||||
|
const eloRefund = parseInt(
|
||||||
|
(
|
||||||
|
await tx`SELECT elo_change FROM public.match_players WHERE match_id=${matchId.raw} AND player_id = ${playerId.raw}`
|
||||||
|
)?.[0]?.elo_change ?? 0,
|
||||||
|
);
|
||||||
|
await tx`DELETE FROM match_players WHERE match_id=${matchId.raw} AND player_id=${playerId.raw}`;
|
||||||
|
if (!player.isRatingLocked) {
|
||||||
|
await tx`UPDATE players SET elo=${player.elo - eloRefund} WHERE id=${playerId.raw}`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,5 +7,8 @@ export default {
|
|||||||
':id': {
|
':id': {
|
||||||
GET: guard(matches.get, [Claims.ADMIN, Claims.MATCHES.OWNED.READ, Claims.MATCHES.PARTICIPANT.READ]),
|
GET: guard(matches.get, [Claims.ADMIN, Claims.MATCHES.OWNED.READ, Claims.MATCHES.PARTICIPANT.READ]),
|
||||||
DELETE: guard(matches.drop, [Claims.ADMIN, Claims.MATCHES.OWNED.DELETE, Claims.USERS.SELF.UPDATE]),
|
DELETE: guard(matches.drop, [Claims.ADMIN, Claims.MATCHES.OWNED.DELETE, Claims.USERS.SELF.UPDATE]),
|
||||||
|
leave: {
|
||||||
|
POST: guard(matches.leave, [Claims.MATCHES.PARTICIPANT.LEAVE]),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user