Skip to content

Commit d1cefdd

Browse files
authored
Merge pull request #55 from x-team/develop
Merging develop into main!
2 parents bde51a8 + 1320418 commit d1cefdd

21 files changed

+1299
-100
lines changed

.env.test

+9-5
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@ HOST=0.0.0.0
33
PORT=3000
44

55
# DATABASE
6-
DB_USERNAME=postgres
7-
DB_PASSWORD=*games-2021
8-
DB_NAME=gameshq_api_test
9-
DB_HOSTNAME=127.0.0.1
10-
DB_PORT=5435
6+
DB_USERNAME=postgres
7+
DB_PASSWORD=*games-2021
8+
DB_NAME=gameshq_api_test
9+
DB_HOSTNAME=127.0.0.1
10+
DB_PORT=5435
11+
12+
SLACK_ARENA_SIGNING_SECRET=fake
13+
SLACK_ARENA_XHQ_CHANNEL=fake
14+
SLACK_ARENA_TOKEN=fake
1115

1216
# FIREBASE
1317
GOOGLE_APPLICATION_CREDENTIALS={"type": "fake", "project_id": "fake", "private_key": "fake", "client_email": "fake"}

src/api-utils/schemas/gameDev/achievementsSchemas.ts

+6
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ export const getAchievementProgressRequestSchema = Joi.object({
4242
}).optional(),
4343
}).optional();
4444

45+
export const updateAchievementProgressRequestSchema = Joi.object({
46+
_userId: Joi.number().required(),
47+
isUnlocked: Joi.boolean().required(),
48+
progress: Joi.number().required(),
49+
}).required();
50+
4551
export const postAchievementProgressResponseSchema = Joi.object({
4652
_achievementId: Joi.number().required(),
4753
_userId: Joi.number().required(),

src/api-utils/schemas/gameDev/leaderboardSchemas.ts

+51-22
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,29 @@ export const getLeaderboardRankResponseSchema = Joi.array()
1212
)
1313
.required();
1414

15+
export const postLeaderboardSchema = Joi.object({
16+
id: Joi.number().optional(),
17+
name: Joi.string().required(),
18+
scoreStrategy: Joi.string()
19+
.valid(...Object.values(ScoreStrategy))
20+
.optional(),
21+
resetStrategy: Joi.string()
22+
.valid(...Object.values(ResetStrategy))
23+
.optional(),
24+
}).required();
25+
26+
export const leaderboardSchema = Joi.object({
27+
id: Joi.number(),
28+
name: Joi.string(),
29+
scoreStrategy: Joi.string(),
30+
resetStrategy: Joi.string(),
31+
_gameTypeId: Joi.number(),
32+
createdAt: Joi.date(),
33+
updatedAt: Joi.date(),
34+
}).optional();
35+
36+
export const multipleLeaderboardSchema = Joi.array().items(leaderboardSchema).optional();
37+
1538
export const getUserLeaderboardResultScoreResponseSchema = Joi.object({
1639
id: Joi.number().required(),
1740
_leaderboardEntryId: Joi.number().required(),
@@ -28,6 +51,10 @@ export const getLeaderboardResultScorePageSchema = Joi.object({
2851
_leaderboardResultsMeta: Joi.array().items(Joi.object()).optional(),
2952
}).optional();
3053

54+
export const multipleLeaderboardResultScoreSchema = Joi.array()
55+
.items(getLeaderboardResultScorePageSchema)
56+
.optional();
57+
3158
export const postLeaderboardResultScoreResquestSchema = Joi.object({
3259
id: Joi.number().optional(),
3360
score: Joi.number().required(),
@@ -45,28 +72,30 @@ export const postLeaderboardResultScoreResponseSchema = Joi.object({
4572
newEntry: Joi.boolean().required(),
4673
}).required();
4774

48-
export const postLeaderboardSchema = Joi.object({
49-
id: Joi.number().optional(),
50-
name: Joi.string().required(),
51-
scoreStrategy: Joi.string()
52-
.valid(...Object.values(ScoreStrategy))
53-
.optional(),
54-
resetStrategy: Joi.string()
55-
.valid(...Object.values(ResetStrategy))
75+
export const updateLeaderboardResultRequestSchema = Joi.object({
76+
id: Joi.number().required(),
77+
score: Joi.number().required(),
78+
_leaderboardResultsMeta: Joi.array()
79+
.items(
80+
Joi.object({
81+
attribute: Joi.string().required(),
82+
value: Joi.string().required(),
83+
})
84+
)
5685
.optional(),
5786
}).required();
5887

59-
export const leaderboardSchema = Joi.object({
60-
id: Joi.number(),
61-
name: Joi.string(),
62-
scoreStrategy: Joi.string(),
63-
resetStrategy: Joi.string(),
64-
_gameTypeId: Joi.number(),
65-
createdAt: Joi.date(),
66-
updatedAt: Joi.date(),
67-
}).optional();
68-
69-
export const multipleLeaderboardSchema = Joi.array().items(leaderboardSchema).optional();
70-
export const multipleLeaderboardResultScoreSchema = Joi.array()
71-
.items(getLeaderboardResultScorePageSchema)
72-
.optional();
88+
export const updateLeaderboardResultResponseSchema = Joi.object({
89+
id: Joi.number().required(),
90+
score: Joi.number().required(),
91+
_userId: Joi.number().required(),
92+
_leaderboardEntryId: Joi.number().required(),
93+
_leaderboardResultsMeta: Joi.array()
94+
.items(
95+
Joi.object({
96+
attribute: Joi.string().required(),
97+
value: Joi.string().required(),
98+
})
99+
)
100+
.optional(),
101+
}).required();

src/games/tower/repositories/tower/actions/admin/tower-floors-operations.ts

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
import {
1010
addTowerFloorEnemies,
1111
addTowerFloorEnemy,
12+
deleteTowerFloorEnemyByTowerFloor,
1213
findTowerFloorEnemyById,
1314
} from '../../../../../../models/TowerFloorEnemy';
1415
import { removeActionsByFloorBattlefieldEnemy } from '../../../../../../models/TowerRoundAction';
@@ -156,6 +157,7 @@ export async function addEnemiesToFloor(
156157
if (!towerFloor) {
157158
return getGameError(towerCommandReply.floorNumberNotValid());
158159
}
160+
await deleteTowerFloorEnemyByTowerFloor(towerFloor.id, transaction);
159161
await addTowerFloorEnemies(towerFloor.id, enemyIds, transaction);
160162
return;
161163
});

src/models/AchievementUnlocked.ts

+14-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ export class AchievementUnlocked
8686
_achievement: Association<AchievementUnlocked, Achievement>;
8787
};
8888
}
89-
interface AchievementUnlockedUnlockedEditorData {
89+
export interface AchievementUnlockedUnlockedEditorData {
9090
_userId: number;
9191
_achievementId: number;
9292
isUnlocked: boolean;
@@ -99,6 +99,19 @@ export async function createOrUpdateAchievementUnlocked(
9999
return await AchievementUnlocked.upsert({ ...achievementUnlockedData });
100100
}
101101

102+
export async function findAchievementUnlocked(_userId: number, _achievementId: number) {
103+
return await AchievementUnlocked.findOne({ where: { _userId, _achievementId } });
104+
}
105+
106+
export function deleteAchievementUnlocked(_userId: number, _achievementId: number) {
107+
return AchievementUnlocked.destroy({
108+
where: {
109+
_userId,
110+
_achievementId,
111+
},
112+
});
113+
}
114+
102115
export function getAchievementUnlockedFromAchievement(
103116
achievement: Achievement,
104117
transaction?: Transaction

src/models/Game.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
PrimaryKey,
1212
AutoIncrement,
1313
HasOne,
14+
HasMany,
1415
} from 'sequelize-typescript';
1516

1617
import { GAME_TYPE } from '../games/consts/global';
@@ -19,7 +20,7 @@ import { GameError } from '../games/utils/GameError';
1920

2021
import { findGameTypeByName } from './GameType';
2122

22-
import { User, ArenaGame, GameType, TowerGame, TowerFloor, TowerFloorEnemy } from './';
23+
import { ArenaPlayer, User, ArenaGame, GameType, TowerGame, TowerFloor, TowerFloorEnemy } from './';
2324

2425
function includeArrayByGameType(gameTypeName: string) {
2526
return gameTypeName === GAME_TYPE.ARENA
@@ -126,11 +127,15 @@ export class Game extends Model<GameAttributes, GameCreationAttributes> implemen
126127
@HasOne(() => TowerGame)
127128
declare _tower?: TowerGame;
128129

130+
@HasMany(() => ArenaPlayer, '_gameId')
131+
declare _arenaPlayers?: ArenaPlayer[];
132+
129133
static associations: {
130134
_arena: Association<Game, ArenaGame>;
131135
_tower: Association<Game, TowerGame>;
132136
_createdBy: Association<Game, User>;
133137
_gameType: Association<Game, GameType>;
138+
_arenaPlayers: Association<Game, ArenaPlayer>;
134139
};
135140

136141
async endGame(transaction?: Transaction) {

src/models/LeaderboardResults.ts

+45
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,42 @@ export function createOrUpdateLeaderBoardResult(data: LeaderboardResultsCreation
180180
});
181181
}
182182

183+
export function updateLeaderBoardResult(
184+
data: LeaderboardResultsCreationAttributes & { id: number }
185+
) {
186+
return withTransaction(async (transaction) => {
187+
const [, rslt] = await LeaderboardResults.update(
188+
{
189+
score: data.score,
190+
},
191+
{
192+
where: {
193+
id: data.id,
194+
},
195+
transaction,
196+
returning: true,
197+
}
198+
);
199+
200+
if (rslt.length && data?._leaderboardResultsMeta) {
201+
for (const meta of data._leaderboardResultsMeta) {
202+
await LeaderboardResultsMeta.upsert(
203+
{
204+
...meta,
205+
_leaderboardResultsId: data.id,
206+
},
207+
{
208+
transaction,
209+
conflictFields: ['attribute', '_leaderboardResultsId'],
210+
}
211+
);
212+
}
213+
}
214+
215+
return rslt[0];
216+
});
217+
}
218+
183219
function shouldUpsert(
184220
data: LeaderboardResultsCreationAttributes,
185221
lbrInDb: LeaderboardResults | null
@@ -287,3 +323,12 @@ function getUserLeaderboardResultWithScoreStrategy(
287323
transaction,
288324
});
289325
}
326+
327+
export function deleteLeaderboardResult(id: number, leaderboardId: number) {
328+
return LeaderboardResults.destroy({
329+
where: {
330+
id,
331+
_leaderboardEntryId: leaderboardId,
332+
},
333+
});
334+
}

src/models/TowerFloorEnemy.ts

+10
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,13 @@ export async function addTowerFloorEnemies(
8080
export async function findTowerFloorEnemyById(id: number, transaction: Transaction) {
8181
return TowerFloorEnemy.findByPk(id, { transaction });
8282
}
83+
84+
export async function deleteTowerFloorEnemyByTowerFloor(
85+
towerFloorId: number,
86+
transaction: Transaction
87+
) {
88+
return TowerFloorEnemy.destroy({
89+
where: { _towerFloorId: towerFloorId },
90+
transaction,
91+
});
92+
}

src/modules/dashboard/admin/adminHandlers/arenaAdminHandlers.ts

+16-15
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,23 @@ import { ArenaGame, findActiveArenaGame } from '../../../../models/ArenaGame';
55

66
export const getCurrentArenaGameState: Lifecycle.Method = async (_request, h) => {
77
const activeGame = await findActiveArenaGame();
8+
89
await activeGame?.reload({
9-
include: {
10-
model: ArenaGame,
11-
include: [
12-
{
13-
model: ArenaPlayer,
14-
include: [
15-
{
16-
association: ArenaPlayer.associations._weapons,
17-
include: [Item.associations._weapon, Item.associations._traits],
18-
as: '_weapons',
19-
},
20-
],
21-
},
22-
],
23-
},
10+
include: [
11+
{
12+
model: ArenaGame,
13+
},
14+
{
15+
model: ArenaPlayer,
16+
include: [
17+
{
18+
association: ArenaPlayer.associations._weapons,
19+
include: [Item.associations._weapon, Item.associations._traits],
20+
as: '_weapons',
21+
},
22+
],
23+
},
24+
],
2425
});
2526

2627
return h.response({ arenaGame: activeGame }).code(200);

0 commit comments

Comments
 (0)