Skip to content

Commit feacf88

Browse files
authored
Merge pull request #63 from WildCodeSchool/dev
merge staging
2 parents e3a165f + 823af67 commit feacf88

File tree

36 files changed

+548
-160
lines changed

36 files changed

+548
-160
lines changed

.github/workflows/CI-cheack-buid.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ on:
77
- main
88

99
jobs:
10-
build-and-push-projects:
10+
build-services-teste:
1111
runs-on: ubuntu-latest
1212
strategy:
1313
# pouvoir voir tout les builds qui échouent pas juste le premier
@@ -22,7 +22,7 @@ jobs:
2222
steps:
2323
- name: Récupérer le code source
2424
uses: actions/checkout@v4
25-
25+
2626
- name: setup Docker Buildx (pour du cache)
2727
uses: docker/setup-buildx-action@v3
2828

@@ -35,4 +35,3 @@ jobs:
3535
load: false
3636
cache-from: type=gha
3737
cache-to: type=gha,mode=max
38-

backend/src/entities/User.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,9 @@ class User extends BaseEntity {
6363
@Field()
6464
updatedAt: Date;
6565

66-
@Column({ default: null, nullable: true })
67-
@Field({ nullable: true })
68-
image_url: string;
66+
@Column({ type: "text", default: null, nullable: true })
67+
@Field(() => String, { nullable: true })
68+
image_url: string | null;
6969

7070
@Column({ default: false })
7171
@Field()

backend/src/resolvers/UserResolver.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import argon2 from "argon2";
22
import axios from "axios";
3+
import jwt from "jsonwebtoken";
34
import {
45
Arg,
56
Ctx,
@@ -15,6 +16,7 @@ import { IsNull } from "typeorm";
1516
import { PendingInvitation } from "../entities/PendingInvitation";
1617
import User from "../entities/User";
1718
import cookieManager from "../lib/cookieManager/cookieManager";
19+
import { getVariableEnv } from "../lib/envManager/envManager";
1820
import { RoleMiddleware } from "../middleware/RoleMiddleware";
1921
import { addMembersToGroup } from "../services/groupMemberService";
2022
import type { ContextType } from "../types/context";
@@ -163,6 +165,9 @@ export default class UserResolver {
163165
try {
164166
urlImage = await axios.post("http://picture-service:3410/service/picture/uploads", {
165167
imageBase64: data.pictureBase64,
168+
tokenService: jwt.sign({ service: "API-graphQL" }, getVariableEnv("INTERNAL_SECRET_KEY"), {
169+
expiresIn: "2m",
170+
}),
166171
});
167172
} catch (_error) {
168173
throw new Error("Erreur lors de l'upload de l'image");
@@ -262,11 +267,18 @@ export default class UserResolver {
262267
async UpdateMyProfile(@Arg("data") data: UpdateMyProfileInput, @Ctx() ctx: ContextType) {
263268
if (!ctx.user) throw new Error("Utilisateur non connecté update impossible");
264269

270+
// récupère l'utilisateur avant la modification
271+
const userBeforeUpdate = await User.findOne({ where: { id: ctx.user.id } });
272+
265273
let urlImage = null;
266274
if (data.pictureBase64) {
267275
try {
268276
urlImage = await axios.post("http://picture-service:3410/service/picture/uploads", {
269277
imageBase64: data.pictureBase64,
278+
tokenService: jwt.sign({ service: "API-graphQL" }, getVariableEnv("INTERNAL_SECRET_KEY"), {
279+
expiresIn: "2m",
280+
}),
281+
urlExistant: userBeforeUpdate?.image_url, // donne a notre service d'image son potentielle url actuelle
270282
});
271283
} catch (_error) {
272284
throw new Error("Erreur lors de l'upload de l'image");
@@ -328,6 +340,12 @@ export default class UserResolver {
328340
{
329341
deletedAt: new Date(),
330342
email: deletedEmail,
343+
firstName: "deleted",
344+
lastName: "user",
345+
phone_number: "0000000000",
346+
image_url: null,
347+
password_hashed: "",
348+
date_of_birth: "1970-01-01",
331349
},
332350
);
333351

@@ -468,13 +486,37 @@ export default class UserResolver {
468486
};
469487
}
470488

489+
// si il existe on fait appel a notres service d'image pour qu'il supprime l'image de profil de l'utilisateur
490+
if (user.image_url) {
491+
try {
492+
await axios.post("http://picture-service:3410/service/picture/delete", {
493+
url: user.image_url,
494+
tokenService: jwt.sign({ service: "API-graphQL" }, getVariableEnv("INTERNAL_SECRET_KEY"), {
495+
expiresIn: "2m",
496+
}),
497+
});
498+
} catch (error) {
499+
// on ne bloque pas la suppression du compte si la suppression de l'image échoue
500+
console.error(
501+
`Erreur lors de la suppression de l'image de profil de l'utilisateur id=${user.id} :`,
502+
error,
503+
);
504+
}
505+
}
506+
471507
// Soft delete : mettre à jour le champ deletedAt et modifier l'email pour permettre la réutilisation
472508
const deletedEmail = `${user.email}_deleted_${Date.now()}`;
473509
await User.update(
474510
{ id: ctx.user.id },
475511
{
476512
deletedAt: new Date(),
477513
email: deletedEmail,
514+
firstName: "deleted",
515+
lastName: "user",
516+
phone_number: "0000000000",
517+
image_url: null,
518+
password_hashed: "",
519+
date_of_birth: "1970-01-01",
478520
},
479521
);
480522

compose.dev.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ services:
6262
environment:
6363
BACKEND_URL: ${SERVEUR_URL}
6464
CLIENT_URL: ${FRONTEND_URL}
65+
INTERNAL_SECRET_KEY: ${INTERNAL_SECRET_KEY}
6566
APP_PORT: ${PICTURE_SERVICE_PORT}
6667

6768
message-service:

frontend/src/App.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,16 @@ const App = () => {
2525
setUserProfile(data.getMyProfile);
2626
// si on était sur une page que on est pas censé étre une foie connecté on redirige vers la page principale
2727
if (["/", "/connexion", "/inscription"].includes(window.location.pathname)) {
28-
navigate("/dashboard");
28+
navigate("/dashboard/conversations", { replace: true });
2929
}
3030
} else if (!loading) {
3131
setUserProfile(null);
3232
// si on est pas connecté on redirige forcement vers la page de connexion ou d'inscription
3333
if (!["/connexion", "/inscription", "/", "/contact"].includes(window.location.pathname)) {
34-
navigate("/");
34+
navigate("/", { replace: true });
3535
}
3636
}
37-
}, [data, loading]);
37+
}, [loading]);
3838

3939
if (loading) return <LoadingHomePage />;
4040

frontend/src/components/forms/auth/LoginForm.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,15 @@ const LoginForm = () => {
6262
theme="dark"
6363
type="text"
6464
name="email"
65+
label="Email"
6566
placeholder="Entrez votre adresse email"
6667
value={form.email}
6768
onChange={(e) => setForm({ ...form, email: e.target.value })}
6869
/>
6970
<Input
7071
theme="dark"
7172
type="password"
73+
label="Password"
7274
name="password"
7375
placeholder="Entrez votre mot de passe"
7476
value={form.password}

frontend/src/components/forms/auth/RegisterForm.tsx

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState } from "react";
1+
import { useId, useState } from "react";
22
import { useNavigate } from "react-router";
33
import { useSignupMutation } from "../../../graphql/generated/graphql-types";
44
import consoleErrorDev from "../../../hooks/erreurMod";
@@ -24,6 +24,7 @@ const RegisterForm = () => {
2424
const navigate = useNavigate();
2525
const [messageError, setMessageError] = useState("");
2626
const { setUserProfile } = useMyProfileStore();
27+
const idInputFile = useId();
2728

2829
const [signup] = useSignupMutation();
2930

@@ -120,6 +121,7 @@ const RegisterForm = () => {
120121
theme="dark"
121122
type="text"
122123
placeholder="Nom"
124+
label="Nom"
123125
name="lastname"
124126
value={form.lastName}
125127
onChange={(e) => setForm({ ...form, lastName: e.target.value })}
@@ -128,6 +130,7 @@ const RegisterForm = () => {
128130
theme="dark"
129131
type="text"
130132
placeholder="Prénom"
133+
label="Prénom"
131134
name="firstname"
132135
value={form.firstName}
133136
onChange={(e) => setForm({ ...form, firstName: e.target.value })}
@@ -136,6 +139,7 @@ const RegisterForm = () => {
136139
theme="dark"
137140
type="text"
138141
placeholder="Adresse email"
142+
label="Adresse email"
139143
name="email"
140144
value={form.email}
141145
onChange={(e) => setForm({ ...form, email: e.target.value })}
@@ -144,6 +148,7 @@ const RegisterForm = () => {
144148
theme="dark"
145149
type="date"
146150
placeholder="Date de naissance"
151+
label="Date de naissance"
147152
name="date_of_birth"
148153
value={form.date_of_birth}
149154
onChange={(e) => setForm({ ...form, date_of_birth: e.target.value })}
@@ -152,6 +157,7 @@ const RegisterForm = () => {
152157
theme="dark"
153158
type="password"
154159
placeholder="Mot de passe"
160+
label="Mot de passe"
155161
name="password"
156162
value={form.password}
157163
onChange={(e) => setForm({ ...form, password: e.target.value })}
@@ -160,6 +166,7 @@ const RegisterForm = () => {
160166
theme="dark"
161167
type="password"
162168
placeholder="Confirmation du mot de passe"
169+
label="Confirmation du mot de passe"
163170
name="passwordConfirmation"
164171
value={form.passwordConfirmation}
165172
onChange={(e) => setForm({ ...form, passwordConfirmation: e.target.value })}
@@ -169,9 +176,16 @@ const RegisterForm = () => {
169176
{/* md:w-auto */}
170177
<label
171178
className={`inline-block w-full bg-dark text-white text-center border-none px-5 py-3 rounded-lg cursor-pointer text-sm md:text-lg font-inter font-bold transition-colors duration-300 overflow-hidden whitespace-nowrap w-[400px] px-4 py-2 text-xl ${file ? "bg-[#292e96]" : ""}`}
179+
htmlFor={idInputFile}
172180
>
173181
<span className="block overflow-hidden text-lg text-ellipsis font-bold">{fileName}</span>
174-
<input type="file" accept="image/*" className="hidden" onChange={handleFileChange} />
182+
<input
183+
id={idInputFile}
184+
type="file"
185+
accept="image/*"
186+
className="sr-only"
187+
onChange={handleFileChange}
188+
/>
175189
</label>
176190
</div>
177191

frontend/src/components/forms/groups/GroupForm.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export default function GroupForm({
3434
<Input
3535
disabled={disabled}
3636
name="name"
37+
label="Nom"
3738
type="text"
3839
value={formData.name}
3940
onChange={handleChange}
@@ -51,6 +52,7 @@ export default function GroupForm({
5152
} as React.ChangeEvent<HTMLInputElement>)
5253
}
5354
placeholder="Quel est l'événement ?"
55+
label="Type événement"
5456
error={errors.event_type}
5557
options={options}
5658
theme="light"
@@ -60,6 +62,7 @@ export default function GroupForm({
6062
disabled={disabled}
6163
name="piggy_bank"
6264
type="number"
65+
label="Piggy bank"
6366
value={String(formData.piggy_bank)}
6467
onChange={handleChange}
6568
placeholder={String(0)}
@@ -84,6 +87,7 @@ export default function GroupForm({
8487
disabled={disabled}
8588
name="deadline"
8689
type="date"
90+
label="Deadline"
8791
value={formData.deadline}
8892
onChange={handleChange}
8993
error={errors.deadline}

frontend/src/components/forms/groups/UsersForm.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ export default function UsersForm({
6464
<SearchInput
6565
disabled={isEdit && !isAdmin}
6666
placeholder="Ajouter des participants..."
67+
label="Ajouter des participants"
6768
theme="light"
6869
name="users"
6970
value={query}

frontend/src/components/forms/groups/index.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ type GroupFormIndex = {
2323
onCancel: () => void;
2424
groupId?: number;
2525
isOpen?: boolean;
26+
onDelete?: () => void;
2627
};
2728

2829
const EMPTY_FORM_STATE: CreateGroupInput = {
@@ -34,7 +35,7 @@ const EMPTY_FORM_STATE: CreateGroupInput = {
3435
user_beneficiary: "",
3536
};
3637

37-
export default function GroupFormindex({ onSuccess, groupId }: GroupFormIndex) {
38+
export default function GroupFormindex({ onSuccess, groupId, onDelete }: GroupFormIndex) {
3839
const [submitError, setSubmitError] = useState<string>("");
3940
const [checked, setChecked] = useState(false);
4041
const [query, setQuery] = useState("");
@@ -221,12 +222,10 @@ export default function GroupFormindex({ onSuccess, groupId }: GroupFormIndex) {
221222
// Reset removal tracking after successful update
222223
setUsersToRemove([]);
223224
} else {
224-
const response = await createGroup({
225+
await createGroup({
225226
variables: commonVariables,
226227
});
227228

228-
console.info("Group created successfully:", response.data);
229-
230229
setFormData(EMPTY_FORM_STATE);
231230
setChecked(false);
232231
setUsersToRemove([]);
@@ -277,7 +276,7 @@ export default function GroupFormindex({ onSuccess, groupId }: GroupFormIndex) {
277276
async function deleteMyGroup() {
278277
try {
279278
await deleteGroup({ variables: { deleteGroupId: groupId! } });
280-
onSuccess();
279+
onDelete?.();
281280
} catch (error) {
282281
console.error("Error deleting group:", error);
283282
}

0 commit comments

Comments
 (0)