Skip to content

Commit 30dac31

Browse files
feat: asso edition (#117)
Original PR #87 Permet d'éditer les infos d'une asso. Cette PR contient également l'upload et le traitement d'images. Cette PR est basée sur #73 mais je l'ai fait pointer vers `dev` pour générer un coverage (je ne sais pas encore pourquoi mais impossible de le rapport html en local 🤷) --------- Co-authored-by: AlbanSdl <alban.delavoreille@free.fr>
1 parent ca54e21 commit 30dac31

78 files changed

Lines changed: 1392 additions & 428 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.dist

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ LDAP_USER=
1818
LDAP_PWD=
1919

2020
ANNAL_UPLOAD_DIR=uploads/exams/
21+
MEDIA_UPLOAD_DIR=uploads/media
22+
MEDIA_DETACHED_LIFESPAN=1
23+
2124
CAS_URL=https://cas.utt.fr/cas
2225
CAS_SERVICE=http://localhost:8080
2326

.env.test.dist

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ PAGINATION_PAGE_SIZE=20
1414
FAKER_SEED=42
1515

1616
ANNAL_UPLOAD_DIR=uploads/exams/
17+
MEDIA_UPLOAD_DIR=uploads/media
18+
MEDIA_DETACHED_LIFESPAN=1
19+
1720
CAS_URL=https://cas.utt.fr/cas
1821
CAS_SERVICE=https://etu.utt.fr/login
1922
LDAP_URL=ldap://localhost:3002

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
"fast-xml-parser": "^5.0.9",
5656
"file-type": "^20.4.1",
5757
"ldapts": "^7.3.1",
58+
"lexical": "^0.37.0",
5859
"multer": "1.4.5-lts.1",
5960
"pactum-matchers": "^1.1.7",
6061
"passport-jwt": "^4.0.1",

pnpm-lock.yaml

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

prisma/schema.prisma

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,16 @@ model Asso {
5252
mail String @unique @db.VarChar(100)
5353
phoneNumber String? @db.VarChar(30)
5454
website String? @db.VarChar(100)
55-
logo String? @db.VarChar(100)
55+
logoMediaId String? @db.Char(36)
5656
createdAt DateTime @default(now())
5757
updatedAt DateTime @updatedAt
5858
deletedAt DateTime?
5959
descriptionShortTranslationId String? @unique
6060
descriptionTranslationId String? @unique
6161
assoAccountId String @unique // User account of the asso
6262
63+
logo ImageMedia? @relation("logo", fields: [logoMediaId], references: [id], onDelete: SetNull)
64+
descriptionImages ImageMedia[] @relation("descriptionImages")
6365
descriptionShortTranslation Translation? @relation(name: "descriptionShortTranslation", fields: [descriptionShortTranslationId], references: [id], onDelete: Cascade)
6466
descriptionTranslation Translation? @relation(name: "descriptionTranslation", fields: [descriptionTranslationId], references: [id], onDelete: Cascade)
6567
assoMemberships AssoMembership[]
@@ -162,6 +164,22 @@ model GitHubIssue {
162164
user User @relation(fields: [userId], references: [id])
163165
}
164166

167+
model ImageMedia {
168+
id String @id @default(uuid()) @db.Char(36)
169+
size Int @db.UnsignedInt
170+
width Int @db.UnsignedInt
171+
height Int @db.UnsignedInt
172+
uploadedAt DateTime @default(now())
173+
isPublic Boolean @default(false)
174+
uploaderId String?
175+
preset ImageMediaPreset
176+
177+
uploader User? @relation(fields: [uploaderId], references: [id])
178+
avatarForUsers UserInfos[]
179+
logoForAssos Asso[] @relation("logo")
180+
descriptionForAssos Asso[] @relation("descriptionImages")
181+
}
182+
165183
model Semester {
166184
code String @id @db.Char(3)
167185
start DateTime @db.Date
@@ -592,6 +610,7 @@ model User {
592610
apiPermissionsTarget ApiKeyPermission[] @relation(name: "target")
593611
apiPermissionsGrants ApiKeyPermission[] @relation(name: "granter")
594612
asso Asso?
613+
uploadedImages ImageMedia[]
595614
}
596615

597616
model UserAddress {
@@ -662,16 +681,17 @@ model UserFormation {
662681
}
663682

664683
model UserInfos {
665-
id String @id @default(uuid())
666-
sex Sex?
667-
nationality String? @db.VarChar(50)
668-
birthday DateTime? @db.Date
669-
avatar String @default("default.png") @db.VarChar(255)
670-
nickname String? @db.VarChar(50)
671-
passions String? @db.Text
672-
website String? @db.VarChar(255)
684+
id String @id @default(uuid())
685+
sex Sex?
686+
nationality String? @db.VarChar(50)
687+
birthday DateTime? @db.Date
688+
avatarMediaId String? @db.Char(36)
689+
nickname String? @db.VarChar(50)
690+
passions String? @db.Text
691+
website String? @db.VarChar(255)
673692
674-
user User?
693+
user User?
694+
avatar ImageMedia? @relation(fields: [avatarMediaId], references: [id], onDelete: SetNull)
675695
}
676696

677697
model UserMailsPhones {
@@ -899,13 +919,19 @@ enum AddressPrivacy {
899919
ALL_PUBLIC
900920
}
901921

922+
enum ImageMediaPreset {
923+
AVATAR
924+
CUSTOM
925+
}
926+
902927
enum Permission {
903928
API_SEE_OPINIONS_UE // See the rates of an UE
904929
API_GIVE_OPINIONS_UE // Rate an UE you have done or are doing
905930
API_SEE_ANNALS // See and download annals
906931
API_UPLOAD_ANNALS // Upload an annal
907932
API_MODERATE_ANNALS // Moderate annals
908933
API_MODERATE_COMMENTS // Moderate comments
934+
API_UPLOAD_MEDIA // Upload to media enpoints
909935
910936
USER_SEE_DETAILS // See personal details about someone, even the ones the user decided to hide
911937
USER_UPDATE_DETAILS // Update personal details about someone

prisma/seed/modules/asso.seed.ts

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,40 @@ export default function assoSeed(prisma: PrismaClient) {
88
for (let i = 0; i < fakerRounds; i++) {
99
const date: Date = faker.date.past();
1010
const name = faker.company.name();
11-
assos.push(
12-
prisma.asso.create({
11+
assos.push(async () => {
12+
const { id: userId } = await prisma.user.create({
13+
data: {
14+
login: name,
15+
firstName: '',
16+
lastName: '',
17+
userType: UserType.ASSOCIATION,
18+
socialNetwork: { create: {} },
19+
mailsPhones: { create: {} },
20+
rgpd: { create: {} },
21+
preference: { create: {} },
22+
infos: { create: {} },
23+
privacy: { create: {} },
24+
},
25+
select: { id: true },
26+
});
27+
return prisma.asso.create({
1328
data: {
1429
name,
1530
mail: faker.internet.email(),
1631
phoneNumber: faker.phone.number(),
1732
website: faker.internet.domainName(),
18-
logo: faker.image.urlLoremFlickr({ category: 'business' }),
33+
logo: {
34+
create: {
35+
height: 100,
36+
width: 100,
37+
size: 1024,
38+
isPublic: true,
39+
preset: 'AVATAR',
40+
uploader: {
41+
connect: { id: userId },
42+
},
43+
},
44+
},
1945
createdAt: date,
2046
updatedAt: date,
2147
descriptionShortTranslation: {
@@ -31,22 +57,11 @@ export default function assoSeed(prisma: PrismaClient) {
3157
},
3258
},
3359
assoAccount: {
34-
create: {
35-
login: name,
36-
firstName: '',
37-
lastName: '',
38-
userType: UserType.ASSOCIATION,
39-
socialNetwork: { create: {} },
40-
mailsPhones: { create: {} },
41-
rgpd: { create: {} },
42-
preference: { create: {} },
43-
infos: { create: {} },
44-
privacy: { create: {} },
45-
}
46-
}
60+
connect: { id: userId },
61+
},
4762
},
48-
}),
49-
);
63+
});
64+
});
5065
}
51-
return Promise.all(assos);
66+
return Promise.all(assos.map((assoFn) => assoFn()));
5267
}

src/app.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@ import { BranchModule } from './branch/branch.module';
1515
import { AssosModule } from './assos/assos.module';
1616
import { TranslationInterceptor } from './app.interceptor';
1717
import { SemesterModule } from './semester/semester.module';
18+
import { ImageMediaModule } from './media/image/imagemedia.module';
1819
import { MailModule } from './mail/mail.module';
1920

2021
@Module({
2122
imports: [
2223
ConfigModule,
2324
HttpModule,
2425
PrismaModule,
26+
ImageMediaModule,
2527
MailModule,
2628
SemesterModule,
2729
AuthModule,

src/app.pipe.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ import {
33
ParseUUIDPipe,
44
Type,
55
ArgumentMetadata,
6-
BadRequestException,
76
Injectable,
87
PipeTransform,
98
ValidationPipe,
9+
ParseIntPipe,
1010
} from '@nestjs/common';
1111
import { AppException, ERROR_CODE } from './exceptions';
1212
import { validationExceptionFactory } from './validation';
@@ -47,6 +47,18 @@ export const UUIDParam = (property: string, ...pipes: (Type<PipeTransform> | Pip
4747
...pipes,
4848
);
4949

50+
export const IntParam = (property: string, ...pipes: (Type<PipeTransform> | PipeTransform)[]) =>
51+
Param(
52+
property,
53+
new ParseIntPipe({
54+
exceptionFactory: () => new AppException(ERROR_CODE.PARAM_NOT_NUMBER, property),
55+
}),
56+
...pipes,
57+
);
58+
59+
export const PositiveIntParam = (property: string, ...pipes: (Type<PipeTransform> | PipeTransform)[]) =>
60+
Param(property, new PositiveNumberValidationPipe(), ...pipes);
61+
5062
export interface ArrayDto<T> extends Array<T> {
5163
items: T[];
5264
}
@@ -86,14 +98,10 @@ export class AppValidationPipe extends ValidationPipe {
8698

8799
@Injectable()
88100
export class PositiveNumberValidationPipe implements PipeTransform {
89-
async transform(value: string) {
101+
async transform(value: string, metadata: ArgumentMetadata) {
90102
const asNumber = Number.parseInt(value);
91-
if (Number.isNaN(asNumber)) {
92-
throw new BadRequestException('value must be a positive number');
93-
}
94-
if (asNumber <= 0) {
95-
throw new BadRequestException('value must be a positive number');
96-
}
103+
if (Number.isNaN(asNumber)) throw new AppException(ERROR_CODE.PARAM_NOT_NUMBER, metadata.data);
104+
if (asNumber <= 0) throw new AppException(ERROR_CODE.PARAM_NOT_POSITIVE, metadata.data);
97105
return asNumber;
98106
}
99107
}

0 commit comments

Comments
 (0)