Skip to content

Commit 78f6c75

Browse files
author
Chloé Bretnacher
committed
Fix merged issues
2 parents 7cc123a + 228888e commit 78f6c75

30 files changed

+1184
-141
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: check-biome
2+
3+
on: push
4+
5+
jobs:
6+
check-biome:
7+
name: check-biome
8+
runs-on: ubuntu-latest
9+
10+
steps:
11+
- name: Récupère le code du dépôt
12+
uses: actions/checkout@v4
13+
14+
- name: Setup Node
15+
uses: actions/setup-node@v4
16+
with:
17+
node-version: 22.20.0
18+
cache: "npm"
19+
20+
- name: Installe les dépendances
21+
run: npm install
22+
23+
- name: Exécute biome
24+
run: npm run husky-lint
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: Test le build des services
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize, reopened]
6+
branches-ignore:
7+
- main
8+
9+
jobs:
10+
build-and-push-projects:
11+
runs-on: ubuntu-latest
12+
strategy:
13+
# pouvoir voir tout les builds qui échouent pas juste le premier
14+
fail-fast: false
15+
matrix:
16+
include:
17+
- nom_service: frontend
18+
- nom_service: backend
19+
- nom_service: gateway
20+
- nom_service: message-service
21+
- nom_service: picture-service
22+
steps:
23+
- name: Récupérer le code source
24+
uses: actions/checkout@v4
25+
26+
- name: setup Docker Buildx (pour du cache)
27+
uses: docker/setup-buildx-action@v3
28+
29+
- name: Build l'image Docker
30+
uses: docker/build-push-action@v4
31+
with:
32+
context: ./${{ matrix.nom_service }}
33+
file: ./${{ matrix.nom_service }}/Dockerfile.staging
34+
push: false
35+
load: false
36+
cache-from: type=gha
37+
cache-to: type=gha,mode=max
38+

.husky/pre-commit

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
npm run husky-lint
22

33
# si le paramètre bypass-bin est pas actif
4+
# bypass_bin=1 git commit
45
if [ "$bypass_bin" != "1" ]; then
56
# Bloquer toute modification du dossier bin/
67
if git diff --cached --name-only | grep -q "^bin/"; then

backend/src/entities/GroupMember.ts

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,9 @@ export class GroupMember extends BaseEntity {
3939
@Field()
4040
isGroupAdmin: boolean;
4141

42-
@Column({ nullable: true })
43-
@Field({ nullable: true })
44-
firstName?: string;
45-
46-
@Column({ nullable: true })
47-
@Field({ nullable: true })
48-
lastName?: string;
49-
50-
@Column({ nullable: true })
51-
@Field({ nullable: true })
52-
email?: string;
42+
@Column({ type: "timestamptz", default: () => "CURRENT_TIMESTAMP" })
43+
@Field()
44+
lastTempstampVu: Date;
5345

5446
@ManyToOne(
5547
() => User,

backend/src/resolvers/MessageResolver.ts

Lines changed: 101 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
Resolver,
1111
UseMiddleware,
1212
} from "type-graphql";
13+
import { LessThan } from "typeorm";
1314
import Group from "../entities/Group";
1415
import { GroupMember } from "../entities/GroupMember";
1516
import { Message } from "../entities/Message";
@@ -39,6 +40,39 @@ class GroupMessagesOutput {
3940

4041
@Field(() => [Message])
4142
messages: Message[];
43+
44+
@Field()
45+
lastTempstampVu: Date;
46+
}
47+
48+
@InputType()
49+
class GetLazyMessagesInput {
50+
@Field()
51+
groupId: number;
52+
53+
@Field()
54+
oldTimestamp: string;
55+
}
56+
57+
@ObjectType()
58+
class GetLazyMessagesOutput {
59+
@Field()
60+
isMaximumMessages: boolean;
61+
62+
@Field(() => [Message])
63+
messages: Message[];
64+
}
65+
66+
@InputType()
67+
class SetLastMessageVuInput {
68+
@Field()
69+
groupId: number;
70+
}
71+
72+
@ObjectType()
73+
class SetLastMessageVuOutput {
74+
@Field()
75+
sucess: boolean;
4276
}
4377

4478
@Resolver(Group)
@@ -60,17 +94,17 @@ export default class MessageResolver {
6094
order: { id: "DESC" },
6195
});
6296

63-
const reponse: { groupId: number; messages: Message[] }[] = [];
97+
const reponse: { groupId: number; messages: Message[]; lastTempstampVu: Date }[] = [];
6498

65-
// charge les 10 derniers messages de chaque groupe
99+
// charge les 40 derniers messages de chaque groupe
66100
for (const group of groups) {
67101
const messages = await Message.find({
68102
where: { group: { id: group.id } },
69103
relations: { user: true },
70104
order: { createdAt: "DESC" },
71-
take: 20,
105+
take: 40,
72106
});
73-
reponse.push({ groupId: group.id, messages });
107+
reponse.push({ groupId: group.id, messages, lastTempstampVu: group.groupMember[0].lastTempstampVu });
74108
}
75109

76110
return reponse;
@@ -112,4 +146,67 @@ export default class MessageResolver {
112146
relations: ["user", "group"],
113147
});
114148
}
149+
150+
@UseMiddleware(RoleMiddleware())
151+
@Query(() => GetLazyMessagesOutput)
152+
async getLazyMessages(@Arg("data") data: GetLazyMessagesInput) {
153+
const { groupId, oldTimestamp } = data;
154+
155+
let oldDate: Date;
156+
try {
157+
oldDate = new Date(oldTimestamp);
158+
if (Number.isNaN(oldDate.getTime())) {
159+
throw new Error("Invalid date");
160+
}
161+
} catch {
162+
throw new Error("Invalid date format");
163+
}
164+
165+
// récupère les 40 premiers messages plus anciens que oldTimestamp
166+
const messages = await Message.find({
167+
where: { group: { id: groupId }, createdAt: LessThan(oldDate) },
168+
relations: { user: true },
169+
order: { createdAt: "DESC" },
170+
take: 40,
171+
});
172+
173+
const oldestMessage = await Message.findOne({
174+
where: { group: { id: groupId } },
175+
order: { createdAt: "ASC" },
176+
select: { id: true, createdAt: true },
177+
});
178+
179+
const isMaximumMessages = oldestMessage ? messages.some((msg) => msg.id === oldestMessage.id) : true;
180+
181+
// renvoie les messages et si c'est tout les messages
182+
return { isMaximumMessages, messages: messages };
183+
}
184+
185+
// met a jour le vu du dernier message pour un groupe donné
186+
@UseMiddleware(RoleMiddleware())
187+
@Mutation(() => SetLastMessageVuOutput)
188+
async setLastMessageVu(@Arg("data") data: SetLastMessageVuInput, @Ctx() ctx: ContextType) {
189+
const { groupId } = data;
190+
191+
const userId = ctx.user?.id;
192+
if (!userId) throw new Error("Utilisateur non authentifié");
193+
194+
// récupère le dernier message du groupe
195+
const lastMessage = await Message.findOne({
196+
where: { group: { id: groupId } },
197+
order: { createdAt: "DESC" },
198+
});
199+
200+
if (lastMessage) {
201+
// met a jour le vu du dernier message pour l'utilisateur
202+
await GroupMember.update(
203+
{ user: { id: userId }, group: { id: groupId } },
204+
{ lastTempstampVu: lastMessage.createdAt },
205+
);
206+
207+
return { sucess: true };
208+
}
209+
210+
return { sucess: false };
211+
}
115212
}

backend/src/resolvers/UserResolver.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class UpdateMyProfileInput {
4747
@Field()
4848
date_of_birth!: string;
4949
@Field()
50-
phone_number!: string;
50+
phone_number?: string;
5151
@Field(() => String, { nullable: true })
5252
pictureBase64?: string;
5353
}
@@ -261,13 +261,14 @@ export default class UserResolver {
261261
password: undefined,
262262
image_url: urlImage ? urlImage.data.url : undefined,
263263
pictureBase64: undefined,
264+
phone_number: data.phone_number ?? undefined,
264265
};
265266

266267
// modifie l'utilisateur connecté
267268
await User.update({ id: ctx.user.id }, newData);
268269

269270
//récupère le profil de l'utilisateur connecté
270-
const user = await User.findOne({ where: { id: ctx.user.id } });
271+
const user = await User.findOne({ where: { id: ctx.user.id }, relations: ["lists"] });
271272

272273
return user as User;
273274
}

bin/dockerTools.sh

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
#!/bin/bash
2+
#chmod +x create.sh
3+
4+
# arrete le script avec des sécurités
5+
set -euo pipefail
6+
7+
# affiche le menu de sélection d'une liste d'options passées en argument
8+
# $1 titre, $2 options
9+
input_select() {
10+
local selected=0
11+
local titre="$1"
12+
local -n OPTIONS="$2"
13+
local key
14+
15+
draw_menu() {
16+
clear
17+
echo "$titre"
18+
echo
19+
20+
for i in "${!OPTIONS[@]}"; do
21+
if [[ $i -eq $selected ]]; then
22+
echo -e " 🟢 \e[32m${OPTIONS[$i]}\e[0m"
23+
else
24+
echo -e " ⚫ \e[31m${OPTIONS[$i]}\e[0m"
25+
fi
26+
done
27+
}
28+
29+
set +e
30+
while true; do
31+
draw_menu
32+
33+
# Lit une touche sans affichage
34+
IFS= read -rsn1 key
35+
36+
# Flèches = séquence ESC + [A/[B
37+
if [[ $key == $'\x1b' ]]; then
38+
IFS= read -rsn2 key
39+
case "$key" in
40+
"[A") ((selected--)) ;; # haut
41+
"[B") ((selected++)) ;; # bas
42+
esac
43+
elif [[ $key == "" ]]; then
44+
# Entrée
45+
break
46+
fi
47+
48+
# si on dépasse les bornes, on revient au début/fin
49+
(( selected < 0 )) && selected=$((${#OPTIONS[@]} - 1))
50+
(( selected >= ${#OPTIONS[@]} )) && selected=0
51+
done
52+
53+
set -e
54+
menu_selected=$selected
55+
# option selectionnée efface le menu
56+
clear
57+
return 0
58+
}
59+
60+
mapfile -t CONTAINERS < <(docker ps -a --format "{{.Names}}")
61+
CONTAINERS+=("Tous les conteneurs")
62+
63+
input_select "Quelle contenaire choisir" CONTAINERS
64+
selectedNbPages=$menu_selected
65+
contenaire=("${CONTAINERS[$selectedNbPages]}")
66+
67+
# action demander
68+
optionAction=(
69+
"logs -f"
70+
"start"
71+
"stop"
72+
"restart"
73+
"exec -it bash"
74+
)
75+
input_select "Quelle est action que vous voulez effectuer sur $contenaire" optionAction
76+
indexSelectedAction=$menu_selected
77+
action=("${optionAction[$indexSelectedAction]}")
78+
79+
# exécuter la commande docker
80+
if [ "$contenaire" == "Tous les conteneurs" ]; then
81+
chemainCompose="./compose.dev.yaml"
82+
# log du docker compose
83+
if [ "$action" == "logs -f" ]; then
84+
docker-compose -f "$chemainCompose" logs -f
85+
elif [ "$action" == "start" ]; then
86+
docker compose --env-file .env.dev -f "$chemainCompose" up -d --build
87+
elif [ "$action" == "stop" ]; then
88+
docker compose --env-file .env.dev -f "$chemainCompose" down
89+
elif [ "$action" == "restart" ]; then
90+
docker compose --env-file .env.dev -f "$chemainCompose" down && docker compose --env-file .env.dev -f "$chemainCompose" up -d --build
91+
elif [ "$action" == "exec -it bash" ]; then
92+
echo "⚠️ Impossible d'exécuter 'exec -it bash' sur tous les conteneurs en même temps."
93+
else
94+
echo "⚠️ Action non reconnue."
95+
fi
96+
else
97+
# log du docker compose
98+
if [ "$action" == "logs -f" ]; then
99+
docker logs -f "$contenaire"
100+
101+
elif [ "$action" == "start" ]; then
102+
docker start "$contenaire"
103+
echo "✅ Le contenaire "$contenaire" a démarré."
104+
105+
elif [ "$action" == "stop" ]; then
106+
docker stop "$contenaire"
107+
echo "✅ Le contenaire "$contenaire" a été arrêté."
108+
109+
elif [ "$action" == "restart" ]; then
110+
docker restart "$contenaire"
111+
echo "✅ Le contenaire "$contenaire" a été redémarré."
112+
113+
elif [ "$action" == "exec -it bash" ]; then
114+
docker exec -it "$contenaire" sh
115+
116+
else
117+
echo "⚠️ Action non reconnue."
118+
fi
119+
fi

frontend/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!doctype html>
2-
<html lang="en">
2+
<html lang="fr">
33

44
<head>
55
<meta charset="UTF-8" />

0 commit comments

Comments
 (0)