Skip to content

Commit 5c88a76

Browse files
authored
feat(mobile_team_logo): retrive team logo from backend and display them if exist (#1259)
1 parent 2f37c1b commit 5c88a76

36 files changed

+1062
-302
lines changed

yaki_backend/src/__test__/team-repository.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ describe("TeamRepository", () => {
3333
];
3434
pgClient.query.mockResolvedValue({rows: mockRows});
3535

36-
const result = await teamRepository.getTeamLogoByTeamsId(teamIds);
36+
const result = await teamRepository.getTeamsLogoByTeamsId(teamIds);
3737

3838
expect(pgClient.connect).toHaveBeenCalled();
3939
expect(pgClient.query).toHaveBeenCalledWith(expect.stringContaining("1,2,3"));
@@ -47,7 +47,7 @@ describe("TeamRepository", () => {
4747
const teamIds = [1, 2, 3];
4848
pgClient.query.mockResolvedValue({rows: []});
4949

50-
const result = await teamRepository.getTeamLogoByTeamsId(teamIds);
50+
const result = await teamRepository.getTeamsLogoByTeamsId(teamIds);
5151

5252
expect(pgClient.connect).toHaveBeenCalled();
5353
expect(pgClient.query).toHaveBeenCalledWith(expect.stringContaining("1,2,3"));

yaki_backend/src/__test__/team-service.test.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jest.mock("../features/team/team.repository", () => {
88
TeamRepository: jest.fn().mockImplementation(() => {
99
return {
1010
getTeamByTeammateId: jest.fn(),
11-
getTeamLogoByTeamsId: jest.fn(),
11+
getTeamsLogoByTeamsId: jest.fn(),
1212
};
1313
}),
1414
};
@@ -48,7 +48,7 @@ describe("TeamService", () => {
4848
});
4949
});
5050

51-
describe("getTeamLogoByTeamsId", () => {
51+
describe("getTeamsLogoByTeamsId", () => {
5252
it("should return a teams logo list if it exists", async () => {
5353
const buffer1 = Buffer.from("mock buffer data 1");
5454
const buffer2 = Buffer.from("mock buffer data 2");
@@ -57,23 +57,23 @@ describe("TeamService", () => {
5757
{teamLogoTeamId: 1, teamLogoBlob: buffer1},
5858
{teamLogoTeamId: 2, teamLogoBlob: buffer2},
5959
];
60-
mockTeamRepository.getTeamLogoByTeamsId.mockResolvedValueOnce(teamLogo);
60+
mockTeamRepository.getTeamsLogoByTeamsId.mockResolvedValueOnce(teamLogo);
6161

62-
const result = await service.getTeamLogoByTeamsId([1, 2]);
62+
const result = await service.getTeamsLogoByTeamsId([1, 2]);
6363
expect(result).toEqual(teamLogo);
64-
expect(mockTeamRepository.getTeamLogoByTeamsId).toHaveBeenCalledWith([1, 2]);
65-
expect(mockTeamRepository.getTeamLogoByTeamsId).toHaveBeenCalledTimes(1);
64+
expect(mockTeamRepository.getTeamsLogoByTeamsId).toHaveBeenCalledWith([1, 2]);
65+
expect(mockTeamRepository.getTeamsLogoByTeamsId).toHaveBeenCalledTimes(1);
6666
});
6767

6868
it("should return an empty array if the team does not exist", async () => {
6969
const teamLogo: TeamLogoDto[] = [];
7070

71-
mockTeamRepository.getTeamLogoByTeamsId.mockResolvedValueOnce(teamLogo);
71+
mockTeamRepository.getTeamsLogoByTeamsId.mockResolvedValueOnce(teamLogo);
7272

73-
const result = await service.getTeamLogoByTeamsId([1, 2]);
73+
const result = await service.getTeamsLogoByTeamsId([1, 2]);
7474
expect(result).toEqual(teamLogo);
75-
expect(mockTeamRepository.getTeamLogoByTeamsId).toHaveBeenCalledWith([1, 2]);
76-
expect(mockTeamRepository.getTeamLogoByTeamsId).toHaveBeenCalledTimes(1);
75+
expect(mockTeamRepository.getTeamsLogoByTeamsId).toHaveBeenCalledWith([1, 2]);
76+
expect(mockTeamRepository.getTeamsLogoByTeamsId).toHaveBeenCalledTimes(1);
7777
});
7878
});
7979

yaki_backend/src/features/team/team.controller.ts

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {TeamService} from "./team.service";
2+
import {TeamLogoDto} from "./teamLogo.dto";
23

34
export class TeamController {
45
private teamService: TeamService;
@@ -30,6 +31,26 @@ export class TeamController {
3031
}
3132
};
3233

34+
/**
35+
* Verify if the query param is either teamIds or userId.
36+
* If the query param is teamIds, it will call the getTeamsLogoByTeamsId function.
37+
* If the query param is userId, it will call the getTeamsLogoByUserId function.
38+
* If the query param is neither teamIds or userId, it will return a 400 error.
39+
* @param req
40+
* @param res
41+
*/
42+
getTeamsLogo = async (req: any, res: any) => {
43+
const queryParams = Object.keys(req.query)[0];
44+
45+
if (queryParams === "teamIds") {
46+
this.getTeamsLogoByTeamsId(req, res);
47+
} else if (queryParams === "userId") {
48+
this.getTeamsLogoByUserId(req, res);
49+
} else {
50+
res.status(400).json({message: "invalid query param"});
51+
}
52+
};
53+
3354
/**
3455
* Retrive a list of team logo given a list of team id.
3556
* If a team id does not have a logo, it will not be returned.
@@ -38,13 +59,12 @@ export class TeamController {
3859
* @param req
3960
* @param res
4061
*/
41-
getTeamImageByTeamsId = async (req: any, res: any) => {
62+
getTeamsLogoByTeamsId = async (req: any, res: any) => {
4263
const teamIds = req.query.teamIds;
43-
4464
const idsArray = this.teamsIdsValidation(teamIds);
4565

4666
try {
47-
const teamsLogo = await this.teamService.getTeamLogoByTeamsId(idsArray);
67+
const teamsLogo = await this.teamService.getTeamsLogoByTeamsId(idsArray);
4868

4969
if (teamsLogo.length === 0) {
5070
console.log("404 no team logo was found");
@@ -82,4 +102,37 @@ export class TeamController {
82102

83103
return idsArray;
84104
};
105+
106+
/**
107+
* Retrive a list of team logo given a user id, meaning its all teams the user is into.
108+
* If a team id does not have a logo, it will not be returned.
109+
* User query param, ex : ?userId=1
110+
* @param req
111+
* @param res
112+
*/
113+
getTeamsLogoByUserId = async (req: any, res: any) => {
114+
const userId = Number(req.query.userId);
115+
116+
if (isNaN(userId)) {
117+
throw new Error("invalid user id provided");
118+
}
119+
120+
try {
121+
const teamsLogo = await this.teamService.getTeamsLogoByUserId(userId);
122+
123+
if (teamsLogo.length === 0) {
124+
console.log("404 no team logo was found");
125+
res.status(404).json({message: "No team logo was found"});
126+
} else {
127+
console.log(
128+
"200 team logo was found for the teams :",
129+
teamsLogo.map((team: TeamLogoDto) => team.teamLogoTeamId)
130+
);
131+
res.status(200).json(teamsLogo);
132+
}
133+
} catch (error: any) {
134+
// catch server errors
135+
res.status(500).json({message: error.message});
136+
}
137+
};
85138
}

yaki_backend/src/features/team/team.repository.ts

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export class TeamRepository {
4949
* @param teamIds list of team id
5050
* @returns promise of list of TeamLogoDto
5151
*/
52-
getTeamLogoByTeamsId = async (teamIds: number[]): Promise<TeamLogoDto[]> => {
52+
getTeamsLogoByTeamsId = async (teamIds: number[]): Promise<TeamLogoDto[]> => {
5353
let teamIdListString = teamIds.join(",");
5454

5555
const client = new Client({
@@ -87,6 +87,46 @@ export class TeamRepository {
8787
}
8888
};
8989

90+
/**
91+
* Retrive the list of team logo given a user id, meaning its all teams the user is into.
92+
* @param userId
93+
* @returns promise of list of TeamLogoDto
94+
*/
95+
getTeamsLogoByUserId = async (userId: number): Promise<TeamLogoDto[]> => {
96+
const client = new Client({
97+
host: process.env.DB_HOST,
98+
user: process.env.DB_USER,
99+
password: process.env.DB_PASSWORD,
100+
database: process.env.DB_DATABASE,
101+
port: Number(process.env.DB_PORT),
102+
});
103+
104+
const query = `
105+
SELECT
106+
tl.team_logo_team_id,
107+
tl.team_logo_blob
108+
FROM public.team_logo tl
109+
JOIN public.teammate tm on tm.teammate_team_id = tl.team_logo_team_id
110+
WHERE tm.teammate_user_id= $1
111+
`;
112+
113+
await client.connect();
114+
try {
115+
const result = await client.query(query, [userId]);
116+
117+
if (result.rows.length === 0) {
118+
return [];
119+
}
120+
const teamLogoList: TeamLogoDto[] = result.rows.map(
121+
(teamImageRow) =>
122+
new TeamLogoDto(teamImageRow.team_logo_team_id, teamImageRow.team_logo_blob)
123+
);
124+
return teamLogoList;
125+
} catch (error: any) {
126+
throw new DataError("Error during users avatar fetching: " + error.message);
127+
}
128+
};
129+
90130
// DEPRECIATED - TO BE REMOVED WHEN 1.10 isnt used anymore
91131
//========================================================
92132
/**

yaki_backend/src/features/team/team.service.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ export class TeamService {
2828
* @param teamIds list of team id
2929
* @returns promise of list of TeamLogoDto
3030
*/
31-
getTeamLogoByTeamsId = async (teamIds: number[]): Promise<TeamLogoDto[]> => {
31+
getTeamsLogoByTeamsId = async (teamIds: number[]): Promise<TeamLogoDto[]> => {
3232
try {
33-
const teamsLogo = await this.teamRepository.getTeamLogoByTeamsId(teamIds);
33+
const teamsLogo = await this.teamRepository.getTeamsLogoByTeamsId(teamIds);
3434

3535
return teamsLogo;
3636
} catch (error: any) {
@@ -39,6 +39,22 @@ export class TeamService {
3939
}
4040
};
4141

42+
/**
43+
* Team service method, Retrive a list of team logo given a User id.
44+
* If a team id does not have a logo, it will not be returned.
45+
* @param teamId
46+
* @returns promise of list of TeamLogoDto
47+
*/
48+
getTeamsLogoByUserId = async (teamId: number): Promise<TeamLogoDto[]> => {
49+
try {
50+
const teamLogo = await this.teamRepository.getTeamsLogoByUserId(teamId);
51+
return teamLogo;
52+
} catch (error: any) {
53+
console.error("Error get team logo : ", error.message);
54+
throw error;
55+
}
56+
};
57+
4258
// DEPRECIATED - TO BE REMOVED WHEN 1.10 isnt used anymore
4359
//========================================================
4460
/**

yaki_backend/src/team.router.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ teamRouter.get(
2727
teamRouter.get(
2828
"/teams-logo",
2929
(req, res, next) => authService.verifyToken(req, res, next),
30-
(req, res) => teamController.getTeamImageByTeamsId(req, res)
30+
(req, res) => teamController.getTeamsLogo(req, res)
3131
);
3232

3333
export default teamRouter;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import 'package:json_annotation/json_annotation.dart';
2+
3+
part 'team_logo_model.g.dart';
4+
5+
@JsonSerializable()
6+
class TeamLogoModel {
7+
int teamLogoTeamId;
8+
TeamLogoBlob teamLogoBlob;
9+
10+
TeamLogoModel({
11+
required this.teamLogoTeamId,
12+
required this.teamLogoBlob,
13+
});
14+
15+
factory TeamLogoModel.fromJson(Map<String, dynamic> json) =>
16+
_$TeamLogoModelFromJson(json);
17+
Map<String, dynamic> toJson() => _$TeamLogoModelToJson(this);
18+
19+
@override
20+
String toString() {
21+
return 'TeamLogoModel{teamLogoTeamId: $teamLogoTeamId, teamLogoBlob: $teamLogoBlob}';
22+
}
23+
}
24+
25+
@JsonSerializable()
26+
class TeamLogoBlob {
27+
String type;
28+
List<int> data;
29+
30+
TeamLogoBlob({
31+
required this.type,
32+
required this.data,
33+
});
34+
35+
factory TeamLogoBlob.fromJson(Map<String, dynamic> json) =>
36+
_$TeamLogoBlobFromJson(json);
37+
Map<String, dynamic> toJson() => _$TeamLogoBlobToJson(this);
38+
39+
@override
40+
String toString() {
41+
return 'TeamLogoBlob{type: $type, data: $data}';
42+
}
43+
}

yaki_mobile/lib/data/models/team_logo_model.g.dart

Lines changed: 31 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)