Compare commits

..

No commits in common. "8067d496f83c24348d94c801a937b24dfaf2abc9" and "38663d97c2639f4c37780fe592cc2a352a4828ef" have entirely different histories.

14 changed files with 218 additions and 231 deletions

View File

@ -20,7 +20,7 @@ jobs:
- name: Set up JDK 17 - name: Set up JDK 17
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:
java-version: '21' java-version: '17.0.12'
distribution: 'graalvm' distribution: 'graalvm'
cache: 'maven' cache: 'maven'

1
.gitignore vendored
View File

@ -50,4 +50,3 @@ nb-configuration.xml
/media/ /media/
/media-ext/ /media-ext/
/sign.jpg /sign.jpg
/.gitea/workflows/test.yml

18
pom.xml
View File

@ -11,7 +11,7 @@
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id> <quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id> <quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
<quarkus.platform.version>3.30.5</quarkus.platform.version> <quarkus.platform.version>3.16.4</quarkus.platform.version>
<skipITs>true</skipITs> <skipITs>true</skipITs>
<surefire-plugin.version>3.2.3</surefire-plugin.version> <surefire-plugin.version>3.2.3</surefire-plugin.version>
</properties> </properties>
@ -56,15 +56,19 @@
<artifactId>quarkus-rest-client-jackson</artifactId> <artifactId>quarkus-rest-client-jackson</artifactId>
</dependency> </dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-mssql-client</artifactId>
<version>4.4.1</version>
</dependency>
<dependency> <dependency>
<groupId>io.quarkus</groupId> <groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId> <artifactId>quarkus-arc</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.quarkiverse.antivirus</groupId> <groupId>io.quarkiverse.tika</groupId>
<artifactId>quarkus-antivirus</artifactId> <artifactId>quarkus-tika</artifactId>
<version>1.3.0</version> <version>2.0.4</version>
</dependency> </dependency>
<dependency> <dependency>
@ -92,7 +96,7 @@
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
<version>1.18.42</version> <version>1.18.22</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
@ -123,7 +127,7 @@
<dependency> <dependency>
<groupId>org.apache.xmlgraphics</groupId> <groupId>org.apache.xmlgraphics</groupId>
<artifactId>fop</artifactId> <artifactId>fop</artifactId>
<version>2.11</version> <version>2.6</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.quarkus</groupId> <groupId>io.quarkus</groupId>

View File

@ -64,9 +64,6 @@ public class AffiliationService {
@Inject @Inject
LoggerService ls; LoggerService ls;
@Inject
VirusScannerService scanner;
@RestClient @RestClient
StateIdService stateIdService; StateIdService stateIdService;
@ -177,12 +174,15 @@ public class AffiliationService {
LOGGER.debug("Affiliation Request Created"); LOGGER.debug("Affiliation Request Created");
LOGGER.debug(form.toString()); LOGGER.debug(form.toString());
// noinspection ReactiveStreamsUnusedPublisher // noinspection ResultOfMethodCallIgnored,ReactiveStreamsUnusedPublisher
return pre_save(form, true) return pre_save(form, true)
.chain(model -> Panache.withTransaction(() -> repositoryRequest.persist(model))) .chain(model -> Panache.withTransaction(() -> repositoryRequest.persist(model)))
.onItem() .onItem()
.invoke(m -> Utils.uploadFile(scanner, form.getLogo(), m.getId(), media, "aff_request/logo")) .invoke(model -> Uni.createFrom().future(Utils.replacePhoto(model.getId(), form.getLogo(), media,
.invoke(m -> Utils.uploadFile(scanner, form.getStatus(), m.getId(), media, "aff_request/status")) "aff_request/logo")))
.onItem()
.invoke(model -> Uni.createFrom().future(Utils.replacePhoto(model.getId(), form.getStatus(), media,
"aff_request/status")))
.call(model -> reactiveMailer.send( .call(model -> reactiveMailer.send(
Mail.withText("no-reply@ffsaf.fr", Mail.withText("no-reply@ffsaf.fr",
"[NOTIF] FFSAF - Nouvelle demande d'affiliation", "[NOTIF] FFSAF - Nouvelle demande d'affiliation",
@ -245,8 +245,11 @@ public class AffiliationService {
}) })
.chain(model -> Panache.withTransaction(() -> repositoryRequest.persist(model))) .chain(model -> Panache.withTransaction(() -> repositoryRequest.persist(model)))
.onItem() .onItem()
.invoke(m -> Utils.uploadFile(scanner, form.getLogo(), m.getId(), media, "aff_request/logo")) .invoke(model -> Uni.createFrom().future(Utils.replacePhoto(model.getId(), form.getLogo(), media,
.invoke(m -> Utils.uploadFile(scanner, form.getStatus(), m.getId(), media, "aff_request/status")) "aff_request/logo")))
.onItem()
.invoke(model -> Uni.createFrom().future(Utils.replacePhoto(model.getId(), form.getStatus(), media,
"aff_request/status")))
.map(__ -> "Ok"); .map(__ -> "Ok");
} }
@ -316,11 +319,13 @@ public class AffiliationService {
.recoverWithNull() .recoverWithNull()
.call(___ -> setMembre(form.new Member(3), club, req.getSaison())))) .call(___ -> setMembre(form.new Member(3), club, req.getSaison()))))
.onItem() .onItem()
.invoke(model -> Utils.uploadFile(scanner, form.getLogo(), form.getId(), media, .invoke(model -> Uni.createFrom()
"aff_request/logo")) .future(Utils.replacePhoto(form.getId(), form.getLogo(), media,
.invoke(model -> Utils.uploadFile(scanner, form.getStatus(), form.getId(), media, "aff_request/logo")))
"aff_request/status"))
.onItem() .onItem()
.invoke(model -> Uni.createFrom()
.future(Utils.replacePhoto(form.getId(), form.getStatus(), media,
"aff_request/status")))
.call(model -> Utils.moveMedia(form.getId(), model.getId(), media, "aff_request/logo", .call(model -> Utils.moveMedia(form.getId(), model.getId(), media, "aff_request/logo",
"ppClub")) "ppClub"))
.call(model -> Utils.moveMedia(form.getId(), model.getId(), media, "aff_request/status", .call(model -> Utils.moveMedia(form.getId(), model.getId(), media, "aff_request/status",

View File

@ -467,7 +467,7 @@ public class MembreService {
.call(membreModel -> licenceRepository.update("club_id = ?1 where membre = ?2 AND saison = ?3", .call(membreModel -> licenceRepository.update("club_id = ?1 where membre = ?2 AND saison = ?3",
(membreModel.getClub() == null) ? null : membreModel.getClub().getId(), membreModel, (membreModel.getClub() == null) ? null : membreModel.getClub().getId(), membreModel,
Utils.getSaison())) Utils.getSaison()))
.call(membreModel -> (membre.getPhoto_data() != null && membre.getPhoto_data().size() > 0) ? ls.logAUpdate("Photo", .call(membreModel -> membre.getPhoto_data().length > 0 ? ls.logAUpdate("Photo",
membreModel) : Uni.createFrom().nullItem()) membreModel) : Uni.createFrom().nullItem())
.map(__ -> "OK"); .map(__ -> "OK");
} }

View File

@ -1,28 +0,0 @@
package fr.titionfire.ffsaf.domain.service;
import io.quarkiverse.antivirus.runtime.Antivirus;
import io.quarkiverse.antivirus.runtime.AntivirusScanResult;
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import java.io.InputStream;
import java.util.List;
@ApplicationScoped
public class VirusScannerService {
@Inject
Antivirus antivirus;
public Uni<List<AntivirusScanResult>> scanFileReactive(String fileName, InputStream inputStream) {
System.out.println("Starting reactive virus scan for file: " + fileName);
// Wrap the blocking antivirus scan in a reactive context
// This moves the blocking operation to a worker thread
return Uni.createFrom().item(() -> {
System.out.println("Scanning file on worker thread: " + fileName);
return antivirus.scan(fileName, inputStream);
}).runSubscriptionOn(io.smallrye.mutiny.infrastructure.Infrastructure.getDefaultWorkerPool());
}
}

View File

@ -3,10 +3,10 @@ package fr.titionfire.ffsaf.rest;
import fr.titionfire.ffsaf.data.model.ClubModel; import fr.titionfire.ffsaf.data.model.ClubModel;
import fr.titionfire.ffsaf.domain.service.ClubService; import fr.titionfire.ffsaf.domain.service.ClubService;
import fr.titionfire.ffsaf.domain.service.PDFService; import fr.titionfire.ffsaf.domain.service.PDFService;
import fr.titionfire.ffsaf.domain.service.VirusScannerService;
import fr.titionfire.ffsaf.net2.data.SimpleClubModel; import fr.titionfire.ffsaf.net2.data.SimpleClubModel;
import fr.titionfire.ffsaf.rest.data.*; import fr.titionfire.ffsaf.rest.data.*;
import fr.titionfire.ffsaf.rest.exception.DForbiddenException; import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
import fr.titionfire.ffsaf.rest.exception.DInternalError;
import fr.titionfire.ffsaf.rest.from.FullClubForm; import fr.titionfire.ffsaf.rest.from.FullClubForm;
import fr.titionfire.ffsaf.rest.from.PartClubForm; import fr.titionfire.ffsaf.rest.from.PartClubForm;
import fr.titionfire.ffsaf.utils.Contact; import fr.titionfire.ffsaf.utils.Contact;
@ -47,9 +47,6 @@ public class ClubEndpoints {
@Inject @Inject
SecurityCtx securityCtx; SecurityCtx securityCtx;
@Inject
VirusScannerService scannerService;
@ConfigProperty(name = "upload_dir") @ConfigProperty(name = "upload_dir")
String media; String media;
@ -124,8 +121,9 @@ public class ClubEndpoints {
}) })
public Uni<SimpleClub> getById( public Uni<SimpleClub> getById(
@Parameter(description = "Identifiant de club") @PathParam("id") long id) { @Parameter(description = "Identifiant de club") @PathParam("id") long id) {
return clubService.getById(id).onItem().invoke(checkPerm).map(SimpleClub::fromModel) return clubService.getById(id).onItem().invoke(checkPerm).map(SimpleClub::fromModel).invoke(m -> {
.invoke(m -> m.setContactMap(Contact.toSite())); m.setContactMap(Contact.toSite());
});
} }
@PUT @PUT
@ -147,9 +145,25 @@ public class ClubEndpoints {
return clubService.update(id, input) return clubService.update(id, input)
.invoke(Unchecked.consumer(out -> { .invoke(Unchecked.consumer(out -> {
if (!out.equals("OK")) throw new InternalError("Fail to update data: " + out); if (!out.equals("OK")) throw new InternalError("Fail to update data: " + out);
})) })).chain(() -> {
.chain(() -> Utils.uploadFile(scannerService, input.getLogo(), id, media, "ppClub")) if (input.getLogo().length > 0)
.chain(() -> Utils.uploadFile(scannerService, input.getStatus(), id, media, "clubStatus")); return Uni.createFrom().future(Utils.replacePhoto(id, input.getLogo(), media, "ppClub"
)).invoke(Unchecked.consumer(out -> {
if (!out.equals("OK"))
throw new DInternalError("Impossible de reconnaitre le fichier: " + out);
})); // TODO log
else
return Uni.createFrom().nullItem();
}).chain(() -> {
if (input.getStatus().length > 0)
return Uni.createFrom().future(Utils.replacePhoto(id, input.getStatus(), media, "clubStatus"
)).invoke(Unchecked.consumer(out -> {
if (!out.equals("OK"))
throw new DInternalError("Impossible de reconnaitre le fichier: " + out);
})); // TODO log
else
return Uni.createFrom().nullItem();
});
} }
@PUT @PUT
@ -167,9 +181,19 @@ public class ClubEndpoints {
return clubService.add(input) return clubService.add(input)
.invoke(Unchecked.consumer(id -> { .invoke(Unchecked.consumer(id -> {
if (id == null) throw new InternalError("Fail to create club data"); if (id == null) throw new InternalError("Fail to create club data");
})) })).call(id -> {
.call(id -> Utils.uploadFile(scannerService, input.getLogo(), id, media, "ppClub")) if (input.getLogo().length > 0)
.call(id -> Utils.uploadFile(scannerService, input.getStatus(), id, media, "clubStatus")); return Uni.createFrom().future(Utils.replacePhoto(id, input.getLogo(), media, "ppClub"
)); // TODO log
else
return Uni.createFrom().nullItem();
}).call(id -> {
if (input.getStatus().length > 0)
return Uni.createFrom().future(Utils.replacePhoto(id, input.getStatus(), media, "clubStatus"
)); // TODO log
else
return Uni.createFrom().nullItem();
});
} }
@DELETE @DELETE

View File

@ -2,7 +2,6 @@ package fr.titionfire.ffsaf.rest;
import fr.titionfire.ffsaf.data.model.MembreModel; import fr.titionfire.ffsaf.data.model.MembreModel;
import fr.titionfire.ffsaf.domain.service.MembreService; import fr.titionfire.ffsaf.domain.service.MembreService;
import fr.titionfire.ffsaf.domain.service.VirusScannerService;
import fr.titionfire.ffsaf.rest.data.SimpleMembre; import fr.titionfire.ffsaf.rest.data.SimpleMembre;
import fr.titionfire.ffsaf.rest.exception.DForbiddenException; import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
import fr.titionfire.ffsaf.rest.exception.DInternalError; import fr.titionfire.ffsaf.rest.exception.DInternalError;
@ -22,7 +21,6 @@ import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponses; import org.eclipse.microprofile.openapi.annotations.responses.APIResponses;
import org.eclipse.microprofile.openapi.annotations.tags.Tag; import org.eclipse.microprofile.openapi.annotations.tags.Tag;
import org.jboss.logging.Logger;
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -31,14 +29,10 @@ import java.util.function.Consumer;
@Path("api/member") @Path("api/member")
@RolesAllowed({"federation_admin"}) @RolesAllowed({"federation_admin"})
public class MembreAdminEndpoints { public class MembreAdminEndpoints {
private static final Logger LOGGER = Logger.getLogger(MembreAdminEndpoints.class);
@Inject @Inject
MembreService membreService; MembreService membreService;
@Inject
VirusScannerService scannerService;
@ConfigProperty(name = "upload_dir") @ConfigProperty(name = "upload_dir")
String media; String media;
@ -103,8 +97,16 @@ public class MembreAdminEndpoints {
.invoke(Unchecked.consumer(out -> { .invoke(Unchecked.consumer(out -> {
if (!out.equals("OK")) if (!out.equals("OK"))
throw new DInternalError("Impossible de reconnaitre le fichier: " + out); throw new DInternalError("Impossible de reconnaitre le fichier: " + out);
})) })).chain(() -> {
.call(__ -> Utils.uploadFile(scannerService, input.getPhoto_data(), id, media, "ppMembre")); if (input.getPhoto_data().length > 0)
return Uni.createFrom().future(Utils.replacePhoto(id, input.getPhoto_data(), media, "ppMembre"
)).invoke(Unchecked.consumer(out -> {
if (!out.equals("OK"))
throw new DInternalError("Impossible de reconnaitre le fichier: " + out);
}));
else
return Uni.createFrom().nullItem();
});
} }
@POST @POST
@ -121,8 +123,13 @@ public class MembreAdminEndpoints {
return membreService.add(input) return membreService.add(input)
.invoke(Unchecked.consumer(id -> { .invoke(Unchecked.consumer(id -> {
if (id == null) throw new InternalError("Fail to creat member data"); if (id == null) throw new InternalError("Fail to creat member data");
})) })).call(id -> {
.call(id -> Utils.uploadFile(scannerService, input.getPhoto_data(), id, media, "ppMembre")); if (input.getPhoto_data().length > 0)
return Uni.createFrom().future(Utils.replacePhoto(id, input.getPhoto_data(), media, "ppMembre"
));
else
return Uni.createFrom().nullItem();
});
} }
@DELETE @DELETE

View File

@ -1,9 +1,9 @@
package fr.titionfire.ffsaf.rest; package fr.titionfire.ffsaf.rest;
import fr.titionfire.ffsaf.domain.service.MembreService; import fr.titionfire.ffsaf.domain.service.MembreService;
import fr.titionfire.ffsaf.domain.service.VirusScannerService;
import fr.titionfire.ffsaf.rest.data.SimpleMembre; import fr.titionfire.ffsaf.rest.data.SimpleMembre;
import fr.titionfire.ffsaf.rest.data.SimpleMembreInOutData; import fr.titionfire.ffsaf.rest.data.SimpleMembreInOutData;
import fr.titionfire.ffsaf.rest.exception.DInternalError;
import fr.titionfire.ffsaf.rest.from.FullMemberForm; import fr.titionfire.ffsaf.rest.from.FullMemberForm;
import fr.titionfire.ffsaf.utils.PageResult; import fr.titionfire.ffsaf.utils.PageResult;
import fr.titionfire.ffsaf.utils.SecurityCtx; import fr.titionfire.ffsaf.utils.SecurityCtx;
@ -37,9 +37,6 @@ public class MembreClubEndpoints {
@Inject @Inject
SecurityCtx securityCtx; SecurityCtx securityCtx;
@Inject
VirusScannerService scannerService;
@GET @GET
@Path("/find/club") @Path("/find/club")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@ -62,8 +59,7 @@ public class MembreClubEndpoints {
limit = 50; limit = 50;
if (page == null || page < 1) if (page == null || page < 1)
page = 1; page = 1;
return membreService.search(limit, page - 1, search, licenceRequest, payment, order, categorie, archive, return membreService.search(limit, page - 1, search, licenceRequest, payment, order, categorie, archive, securityCtx.getSubject());
securityCtx.getSubject());
} }
@GET @GET
@ -111,7 +107,16 @@ public class MembreClubEndpoints {
return membreService.update(id, input, securityCtx) return membreService.update(id, input, securityCtx)
.invoke(Unchecked.consumer(out -> { .invoke(Unchecked.consumer(out -> {
if (!out.equals("OK")) throw new InternalError("Fail to update data: " + out); if (!out.equals("OK")) throw new InternalError("Fail to update data: " + out);
})).chain(() -> Utils.uploadFile(scannerService, input.getPhoto_data(), id, media, "ppMembre")); })).chain(() -> {
if (input.getPhoto_data().length > 0)
return Uni.createFrom().future(Utils.replacePhoto(id, input.getPhoto_data(), media, "ppMembre"
)).invoke(Unchecked.consumer(out -> {
if (!out.equals("OK"))
throw new DInternalError("Impossible de reconnaitre le fichier: " + out);
}));
else
return Uni.createFrom().nullItem();
});
} }
@POST @POST
@ -129,7 +134,13 @@ public class MembreClubEndpoints {
return membreService.add(input, securityCtx.getSubject()) return membreService.add(input, securityCtx.getSubject())
.invoke(Unchecked.consumer(id -> { .invoke(Unchecked.consumer(id -> {
if (id == null) throw new InternalError("Fail to creat member data"); if (id == null) throw new InternalError("Fail to creat member data");
})).call(id -> Utils.uploadFile(scannerService, input.getPhoto_data(), id, media, "ppMembre")); })).call(id -> {
if (input.getPhoto_data().length > 0)
return Uni.createFrom().future(Utils.replacePhoto(id, input.getPhoto_data(), media, "ppMembre"
));
else
return Uni.createFrom().nullItem();
});
} }
@DELETE @DELETE

View File

@ -9,7 +9,6 @@ import lombok.ToString;
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType; import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
import org.eclipse.microprofile.openapi.annotations.media.Schema; import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.jboss.resteasy.reactive.PartType; import org.jboss.resteasy.reactive.PartType;
import org.jboss.resteasy.reactive.multipart.FileUpload;
@Getter @Getter
@ToString(exclude = {"status", "logo"}) @ToString(exclude = {"status", "logo"})
@ -18,85 +17,85 @@ public class AffiliationRequestForm {
@FormParam("id") @FormParam("id")
private Long id = null; private Long id = null;
@Schema(description = "Le nom de l'association.", examples = "Association sportive", required = true) @Schema(description = "Le nom de l'association.", example = "Association sportive", required = true)
@FormParam("name") @FormParam("name")
private String name = null; private String name = null;
@Schema(description = "Le numéro SIRET/RNA de l'association.", examples = "12345678901234", required = true) @Schema(description = "Le numéro SIRET/RNA de l'association.", example = "12345678901234", required = true)
@FormParam("state_id") @FormParam("state_id")
private String state_id = null; private String state_id = null;
@Schema(description = "L'adresse de l'association.", examples = "1 rue de l'exemple, 75000 Paris", required = true) @Schema(description = "L'adresse de l'association.", example = "1 rue de l'exemple, 75000 Paris", required = true)
@FormParam("adresse") @FormParam("adresse")
private String adresse = null; private String adresse = null;
@Schema(description = "Email de contact de l'association", examples = "test@test.fr") @Schema(description = "Email de contact de l'association", example = "test@test.fr")
@FormParam("contact") @FormParam("contact")
private String contact = null; private String contact = null;
@Schema(description = "La saison de l'affiliation.", examples = "2025", required = true) @Schema(description = "La saison de l'affiliation.", example = "2025", required = true)
@FormParam("saison") @FormParam("saison")
private int saison = -1; private int saison = -1;
@Schema(description = "Le statut de l'association.", type = SchemaType.ARRAY) @Schema(description = "Le statut de l'association.", type = SchemaType.ARRAY, implementation = byte.class)
@FormParam("status") @FormParam("status")
@PartType(MediaType.APPLICATION_OCTET_STREAM) @PartType(MediaType.APPLICATION_OCTET_STREAM)
private FileUpload status = null; private byte[] status = new byte[0];
@Schema(description = "Le logo de l'association.", type = SchemaType.ARRAY) @Schema(description = "Le logo de l'association.", type = SchemaType.ARRAY, implementation = byte.class)
@FormParam("logo") @FormParam("logo")
@PartType(MediaType.APPLICATION_OCTET_STREAM) @PartType(MediaType.APPLICATION_OCTET_STREAM)
private FileUpload logo = null; private byte[] logo = new byte[0];
@Schema(description = "Le nom du premier membre de l'association.", examples = "Doe", required = true) @Schema(description = "Le nom du premier membre de l'association.", example = "Doe", required = true)
@FormParam("m1_nom") @FormParam("m1_nom")
private String m1_lname = null; private String m1_lname = null;
@Schema(description = "Le prénom du premier membre de l'association.", examples = "John", required = true) @Schema(description = "Le prénom du premier membre de l'association.", example = "John", required = true)
@FormParam("m1_prenom") @FormParam("m1_prenom")
private String m1_fname = null; private String m1_fname = null;
@Schema(description = "L'adresse e-mail du premier membre de l'association.", examples = "john.doe@test.com", required = true) @Schema(description = "L'adresse e-mail du premier membre de l'association.", example = "john.doe@test.com", required = true)
@FormParam("m1_mail") @FormParam("m1_mail")
private String m1_email = null; private String m1_email = null;
@Schema(description = "Le numéro de licence du premier membre de l'association. (null si non licencié)", examples = "12345") @Schema(description = "Le numéro de licence du premier membre de l'association. (null si non licencié)", example = "12345")
@FormParam("m1_licence") @FormParam("m1_licence")
private String m1_lincence = null; private String m1_lincence = null;
@Schema(description = "Le rôle du premier membre de l'association. (doit être PRESIDENT)", examples = "PRESIDENT", required = true) @Schema(description = "Le rôle du premier membre de l'association. (doit être PRESIDENT)", example = "PRESIDENT", required = true)
@FormParam("m1_role") @FormParam("m1_role")
private RoleAsso m1_role = null; private RoleAsso m1_role = null;
@Schema(description = "Le nom du deuxième membre de l'association.", examples = "Xavier", required = true) @Schema(description = "Le nom du deuxième membre de l'association.", example = "Xavier", required = true)
@FormParam("m2_nom") @FormParam("m2_nom")
private String m2_lname = null; private String m2_lname = null;
@Schema(description = "Le prénom du deuxième membre de l'association.", examples = "Login", required = true) @Schema(description = "Le prénom du deuxième membre de l'association.", example = "Login", required = true)
@FormParam("m2_prenom") @FormParam("m2_prenom")
private String m2_fname = null; private String m2_fname = null;
@Schema(description = "L'adresse e-mail du deuxième membre de l'association.", examples = "xavier.login@test.com", required = true) @Schema(description = "L'adresse e-mail du deuxième membre de l'association.", example = "xavier.login@test.com", required = true)
@FormParam("m2_mail") @FormParam("m2_mail")
private String m2_email = null; private String m2_email = null;
@Schema(description = "Le numéro de licence du deuxième membre de l'association. (null si non licencié)", examples = "04242") @Schema(description = "Le numéro de licence du deuxième membre de l'association. (null si non licencié)", example = "04242")
@FormParam("m2_licence") @FormParam("m2_licence")
private String m2_lincence = null; private String m2_lincence = null;
@Schema(description = "Le rôle du deuxième membre de l'association.", examples = "SECRETAIRE", required = true) @Schema(description = "Le rôle du deuxième membre de l'association.", example = "SECRETAIRE", required = true)
@FormParam("m2_role") @FormParam("m2_role")
private RoleAsso m2_role = null; private RoleAsso m2_role = null;
@Schema(description = "Le nom du troisième membre de l'association.", examples = "Doe2", required = true) @Schema(description = "Le nom du troisième membre de l'association.", example = "Doe2", required = true)
@FormParam("m3_nom") @FormParam("m3_nom")
private String m3_lname = null; private String m3_lname = null;
@Schema(description = "Le prénom du troisième membre de l'association.", examples = "John2", required = true) @Schema(description = "Le prénom du troisième membre de l'association.", example = "John2", required = true)
@FormParam("m3_prenom") @FormParam("m3_prenom")
private String m3_fname = null; private String m3_fname = null;
@Schema(description = "L'adresse e-mail du troisième membre de l'association.", examples = "john.doe22@test.com", required = true) @Schema(description = "L'adresse e-mail du troisième membre de l'association.", example = "john.doe22@test.com", required = true)
@FormParam("m3_mail") @FormParam("m3_mail")
private String m3_email = null; private String m3_email = null;
@ -104,7 +103,7 @@ public class AffiliationRequestForm {
@FormParam("m3_licence") @FormParam("m3_licence")
private String m3_lincence = null; private String m3_lincence = null;
@Schema(description = "Le rôle du troisième membre de l'association.", examples = "MEMBREBUREAU", required = true) @Schema(description = "Le rôle du troisième membre de l'association.", example = "MEMBREBUREAU", required = true)
@FormParam("m3_role") @FormParam("m3_role")
private RoleAsso m3_role = null; private RoleAsso m3_role = null;

View File

@ -6,124 +6,123 @@ import jakarta.ws.rs.core.MediaType;
import lombok.Getter; import lombok.Getter;
import org.eclipse.microprofile.openapi.annotations.media.Schema; import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.jboss.resteasy.reactive.PartType; import org.jboss.resteasy.reactive.PartType;
import org.jboss.resteasy.reactive.multipart.FileUpload;
@Getter @Getter
public class AffiliationRequestSaveForm { public class AffiliationRequestSaveForm {
@Schema(description = "L'identifiant de l'affiliation.", examples = "1", required = true) @Schema(description = "L'identifiant de l'affiliation.", example = "1", required = true)
@FormParam("id") @FormParam("id")
private Long id = null; private Long id = null;
@Schema(description = "Le nom de l'association.", examples = "Association sportive", required = true) @Schema(description = "Le nom de l'association.", example = "Association sportive", required = true)
@FormParam("name") @FormParam("name")
private String name = null; private String name = null;
@Schema(description = "Le numéro SIRET ou RNA de l'association.", examples = "12345678901234", required = true) @Schema(description = "Le numéro SIRET ou RNA de l'association.", example = "12345678901234", required = true)
@FormParam("state_id") @FormParam("state_id")
private String state_id = null; private String state_id = null;
@Schema(description = "L'adresse de l'association.", examples = "1 rue de l'exemple, 75000 Paris", required = true) @Schema(description = "L'adresse de l'association.", example = "1 rue de l'exemple, 75000 Paris", required = true)
@FormParam("address") @FormParam("address")
private String address = null; private String address = null;
@Schema(description = "Email de contact de l'association", examples = "test@test.fr") @Schema(description = "Email de contact de l'association", example = "test@test.fr")
@FormParam("contact") @FormParam("contact")
private String contact = null; private String contact = null;
@Schema(description = "Le statut de l'association.") @Schema(description = "Le statut de l'association.")
@FormParam("status") @FormParam("status")
@PartType(MediaType.APPLICATION_OCTET_STREAM) @PartType(MediaType.APPLICATION_OCTET_STREAM)
private FileUpload status = null; private byte[] status = new byte[0];
@Schema(description = "Le logo de l'association.") @Schema(description = "Le logo de l'association.")
@FormParam("logo") @FormParam("logo")
@PartType(MediaType.APPLICATION_OCTET_STREAM) @PartType(MediaType.APPLICATION_OCTET_STREAM)
private FileUpload logo = null; private byte[] logo = new byte[0];
@Schema(description = "Mode utiliser pour la sauvegarde du membre 1 (0 = licence mode, 2 = nom, prénom)", examples = "0", required = true) @Schema(description = "Mode utiliser pour la sauvegarde du membre 1 (0 = licence mode, 2 = nom, prénom)", example = "0", required = true)
@FormParam("m1_mode") @FormParam("m1_mode")
private Integer m1_mode = null; private Integer m1_mode = null;
@Schema(description = "Le rôle du premier membre de l'association.", examples = "PRÉSIDENT", required = true) @Schema(description = "Le rôle du premier membre de l'association.", example = "PRÉSIDENT", required = true)
@FormParam("m1_role") @FormParam("m1_role")
private RoleAsso m1_role = null; private RoleAsso m1_role = null;
@Schema(description = "Le numéro de licence du premier membre de l'association. (null si non licencié)", examples = "1234567", required = true) @Schema(description = "Le numéro de licence du premier membre de l'association. (null si non licencié)", example = "1234567", required = true)
@FormParam("m1_licence") @FormParam("m1_licence")
private String m1_lincence = null; private String m1_lincence = null;
@Schema(description = "Le nom du premier membre de l'association.", examples = "Dupont", required = true) @Schema(description = "Le nom du premier membre de l'association.", example = "Dupont", required = true)
@FormParam("m1_lname") @FormParam("m1_lname")
private String m1_lname = null; private String m1_lname = null;
@Schema(description = "Le prénom du premier membre de l'association.", examples = "Jean", required = true) @Schema(description = "Le prénom du premier membre de l'association.", example = "Jean", required = true)
@FormParam("m1_fname") @FormParam("m1_fname")
private String m1_fname = null; private String m1_fname = null;
@Schema(description = "L'adresse e-mail du premier membre de l'association.", examples = "jean.dupont@examples.com", required = true) @Schema(description = "L'adresse e-mail du premier membre de l'association.", example = "jean.dupont@example.com", required = true)
@FormParam("m1_email") @FormParam("m1_email")
private String m1_email = null; private String m1_email = null;
@Schema(name = "keep_email", @Schema(name = "keep_email",
description = "Conserver l'email de la base de donner (1 = conserve, 0 = replacer par 'm1_email')", examples = "1", required = true) description = "Conserver l'email de la base de donner (1 = conserve, 0 = replacer par 'm1_email')", example = "1", required = true)
@FormParam("m1_email_mode") @FormParam("m1_email_mode")
private Integer m1_email_mode = null; private Integer m1_email_mode = null;
@Schema(description = "Mode utiliser pour la sauvegarde du membre 2 (0 = licence mode, 2 = nom, prénom)", examples = "0", required = true) @Schema(description = "Mode utiliser pour la sauvegarde du membre 2 (0 = licence mode, 2 = nom, prénom)", example = "0", required = true)
@FormParam("m2_mode") @FormParam("m2_mode")
private Integer m2_mode = null; private Integer m2_mode = null;
@Schema(description = "Le rôle du deuxième membre de l'association.", examples = "TRÉSORIER", required = true) @Schema(description = "Le rôle du deuxième membre de l'association.", example = "TRÉSORIER", required = true)
@FormParam("m2_role") @FormParam("m2_role")
private RoleAsso m2_role = null; private RoleAsso m2_role = null;
@Schema(description = "Le numéro de licence du deuxième membre de l'association. (null si non licencié)", examples = "2345678", required = true) @Schema(description = "Le numéro de licence du deuxième membre de l'association. (null si non licencié)", example = "2345678", required = true)
@FormParam("m2_licence") @FormParam("m2_licence")
private String m2_lincence = null; private String m2_lincence = null;
@Schema(description = "Le nom du deuxième membre de l'association.", examples = "Durand", required = true) @Schema(description = "Le nom du deuxième membre de l'association.", example = "Durand", required = true)
@FormParam("m2_lname") @FormParam("m2_lname")
private String m2_lname = null; private String m2_lname = null;
@Schema(description = "Le prénom du deuxième membre de l'association.", examples = "Paul", required = true) @Schema(description = "Le prénom du deuxième membre de l'association.", example = "Paul", required = true)
@FormParam("m2_fname") @FormParam("m2_fname")
private String m2_fname = null; private String m2_fname = null;
@Schema(description = "L'adresse e-mail du deuxième membre de l'association.", examples = "paul.durand@examples.com", required = true) @Schema(description = "L'adresse e-mail du deuxième membre de l'association.", example = "paul.durand@example.com", required = true)
@FormParam("m2_email") @FormParam("m2_email")
private String m2_email = null; private String m2_email = null;
@Schema(name = "keep_email", @Schema(name = "keep_email",
description = "Conserver l'email de la base de donner (1 = conserve, 0 = replacer par 'm2_email')", examples = "1", required = true) description = "Conserver l'email de la base de donner (1 = conserve, 0 = replacer par 'm2_email')", example = "1", required = true)
@FormParam("m2_email_mode") @FormParam("m2_email_mode")
private Integer m2_email_mode = null; private Integer m2_email_mode = null;
@Schema(description = "Mode utiliser pour la sauvegarde du membre 3 (0 = licence mode, 2 = nom, prénom)", examples = "0", required = true) @Schema(description = "Mode utiliser pour la sauvegarde du membre 3 (0 = licence mode, 2 = nom, prénom)", example = "0", required = true)
@FormParam("m3_mode") @FormParam("m3_mode")
private Integer m3_mode = null; private Integer m3_mode = null;
@Schema(description = "Le rôle du troisième membre de l'association.", examples = "SECRÉTAIRE", required = true) @Schema(description = "Le rôle du troisième membre de l'association.", example = "SECRÉTAIRE", required = true)
@FormParam("m3_role") @FormParam("m3_role")
private RoleAsso m3_role = null; private RoleAsso m3_role = null;
@Schema(description = "Le numéro de licence du troisième membre de l'association. (null si non licencié)", examples = "3456789", required = true) @Schema(description = "Le numéro de licence du troisième membre de l'association. (null si non licencié)", example = "3456789", required = true)
@FormParam("m3_licence") @FormParam("m3_licence")
private String m3_lincence = null; private String m3_lincence = null;
@Schema(description = "Le nom du troisième membre de l'association.", examples = "Martin", required = true) @Schema(description = "Le nom du troisième membre de l'association.", example = "Martin", required = true)
@FormParam("m3_lname") @FormParam("m3_lname")
private String m3_lname = null; private String m3_lname = null;
@Schema(description = "Le prénom du troisième membre de l'association.", examples = "Pierre", required = true) @Schema(description = "Le prénom du troisième membre de l'association.", example = "Pierre", required = true)
@FormParam("m3_fname") @FormParam("m3_fname")
private String m3_fname = null; private String m3_fname = null;
@Schema(description = "L'adresse e-mail du troisième membre de l'association.", examples = "pierre.martin@examples.com", required = true) @Schema(description = "L'adresse e-mail du troisième membre de l'association.", example = "pierre.martin@example.com", required = true)
@FormParam("m3_email") @FormParam("m3_email")
private String m3_email = null; private String m3_email = null;
@Schema(name = "keep_email", @Schema(name = "keep_email",
description = "Conserver l'email de la base de donner (1 = conserve, 0 = replacer par 'm3_email')", examples = "1", required = true) description = "Conserver l'email de la base de donner (1 = conserve, 0 = replacer par 'm3_email')", example = "1", required = true)
@FormParam("m3_email_mode") @FormParam("m3_email_mode")
private Integer m3_email_mode = null; private Integer m3_email_mode = null;
@ -175,6 +174,8 @@ public class AffiliationRequestSaveForm {
", state_id=" + state_id + ", state_id=" + state_id +
", address='" + address + '\'' + ", address='" + address + '\'' +
", contact='" + contact + '\'' + ", contact='" + contact + '\'' +
", status_len=" + status.length +
", logo_len=" + logo.length +
", m1_mode=" + m1_mode + ", m1_mode=" + m1_mode +
", m1_role=" + m1_role + ", m1_role=" + m1_role +
", m1_lincence='" + m1_lincence + '\'' + ", m1_lincence='" + m1_lincence + '\'' +

View File

@ -7,58 +7,57 @@ import lombok.ToString;
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType; import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
import org.eclipse.microprofile.openapi.annotations.media.Schema; import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.jboss.resteasy.reactive.PartType; import org.jboss.resteasy.reactive.PartType;
import org.jboss.resteasy.reactive.multipart.FileUpload;
@ToString @ToString
@Getter @Getter
public class FullClubForm { public class FullClubForm {
@FormParam("id") @FormParam("id")
@Schema(description = "Identifiant du club", examples = "1", required = true) @Schema(description = "Identifiant du club", example = "1", required = true)
private String id = null; private String id = null;
@FormParam("name") @FormParam("name")
@Schema(description = "Nom du club", examples = "Association sportive", required = true) @Schema(description = "Nom du club", example = "Association sportive", required = true)
private String name = null; private String name = null;
@FormParam("country") @FormParam("country")
@Schema(description = "Pays du club", examples = "FR", required = true) @Schema(description = "Pays du club", example = "FR", required = true)
private String country = null; private String country = null;
@FormParam("contact") @FormParam("contact")
@Schema(description = "Les contacts du club", examples = "{\"SITE\": \"www.test.com\", \"COURRIEL\": \"test@test.com\"}", required = true) @Schema(description = "Les contacts du club", example = "{\"SITE\": \"www.test.com\", \"COURRIEL\": \"test@test.com\"}", required = true)
private String contact = null; private String contact = null;
@FormParam("training_location") @FormParam("training_location")
@Schema(description = "Liste des lieux d'entraînement", examples = "[{\"text\":\"addr 1\",\"lng\":2.24654,\"lat\":52.4868658},{\"text\":\"addr 2\",\"lng\":2.88654,\"lat\":52.7865456}]", required = true) @Schema(description = "Liste des lieux d'entraînement", example = "[{\"text\":\"addr 1\",\"lng\":2.24654,\"lat\":52.4868658},{\"text\":\"addr 2\",\"lng\":2.88654,\"lat\":52.7865456}]", required = true)
private String training_location = null; private String training_location = null;
@FormParam("training_day_time") @FormParam("training_day_time")
@Schema(description = "Liste des jours et horaires d'entraînement (jours 0-6, 0=>lundi) (temps en minute depuis 00:00, 122=>2h02)", examples = "[{\"day\":0,\"time_start\":164,\"time_end\":240},{\"day\":3,\"time_start\":124,\"time_end\":250}]", required = true) @Schema(description = "Liste des jours et horaires d'entraînement (jours 0-6, 0=>lundi) (temps en minute depuis 00:00, 122=>2h02)", example = "[{\"day\":0,\"time_start\":164,\"time_end\":240},{\"day\":3,\"time_start\":124,\"time_end\":250}]", required = true)
private String training_day_time = null; private String training_day_time = null;
@FormParam("contact_intern") @FormParam("contact_intern")
@Schema(description = "Contact interne du club", examples = "john.doe@test.com") @Schema(description = "Contact interne du club", example = "john.doe@test.com")
private String contact_intern = null; private String contact_intern = null;
@FormParam("address") @FormParam("address")
@Schema(description = "Adresse postale du club", examples = "1 rue de l'exemple, 75000 Paris", required = true) @Schema(description = "Adresse postale du club", example = "1 rue de l'exemple, 75000 Paris", required = true)
private String address = null; private String address = null;
@FormParam("state_id") @FormParam("state_id")
@Schema(description = "Numéro SIRET ou RNA du club", examples = "12345678901234", required = true) @Schema(description = "Numéro SIRET ou RNA du club", example = "12345678901234", required = true)
private String state_id = null; private String state_id = null;
@FormParam("international") @FormParam("international")
@Schema(description = "Club international", examples = "false", required = true) @Schema(description = "Club international", example = "false", required = true)
private boolean international = false; private boolean international = false;
@FormParam("status") @FormParam("status")
@PartType(MediaType.APPLICATION_OCTET_STREAM) @PartType(MediaType.APPLICATION_OCTET_STREAM)
@Schema(description = "Le statut de l'association.", type = SchemaType.ARRAY) @Schema(description = "Le statut de l'association.", type = SchemaType.ARRAY, implementation = byte.class)
private FileUpload status = null; private byte[] status = new byte[0];
@FormParam("logo") @FormParam("logo")
@PartType(MediaType.APPLICATION_OCTET_STREAM) @PartType(MediaType.APPLICATION_OCTET_STREAM)
@Schema(description = "Le logo de l'association.", type = SchemaType.ARRAY) @Schema(description = "Le logo de l'association.", type = SchemaType.ARRAY, implementation = byte.class)
private FileUpload logo = null; private byte[] logo = new byte[0];
} }

View File

@ -8,33 +8,32 @@ import jakarta.ws.rs.core.MediaType;
import lombok.Getter; import lombok.Getter;
import org.eclipse.microprofile.openapi.annotations.media.Schema; import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.jboss.resteasy.reactive.PartType; import org.jboss.resteasy.reactive.PartType;
import org.jboss.resteasy.reactive.multipart.FileUpload;
import java.util.Date; import java.util.Date;
@Getter @Getter
public class FullMemberForm { public class FullMemberForm {
@Schema(description = "L'identifiant du membre.", examples = "1") @Schema(description = "L'identifiant du membre.", example = "1")
@FormParam("id") @FormParam("id")
private String id = null; private String id = null;
@Schema(description = "Le nom du membre.", examples = "Dupont") @Schema(description = "Le nom du membre.", example = "Dupont")
@FormParam("lname") @FormParam("lname")
private String lname = null; private String lname = null;
@Schema(description = "Le prénom du membre.", examples = "Jean") @Schema(description = "Le prénom du membre.", example = "Jean")
@FormParam("fname") @FormParam("fname")
private String fname = null; private String fname = null;
@Schema(description = "L'identifiant du club du membre.", examples = "1") @Schema(description = "L'identifiant du club du membre.", example = "1")
@FormParam("club") @FormParam("club")
private Long club = null; private Long club = null;
@Schema(description = "Le genre du membre.", examples = "H") @Schema(description = "Le genre du membre.", example = "H")
@FormParam("genre") @FormParam("genre")
private Genre genre; private Genre genre;
@Schema(description = "Le pays du membre.", examples = "FR") @Schema(description = "Le pays du membre.", example = "FR")
@FormParam("country") @FormParam("country")
private String country; private String country;
@ -42,22 +41,22 @@ public class FullMemberForm {
@FormParam("birth_date") @FormParam("birth_date")
private Date birth_date = null; private Date birth_date = null;
@Schema(description = "L'adresse e-mail du membre.", examples = "jean.dupont@example.com") @Schema(description = "L'adresse e-mail du membre.", example = "jean.dupont@example.com")
@FormParam("email") @FormParam("email")
private String email; private String email;
@Schema(description = "Le rôle du membre dans l'association.", examples = "MEMBRE") @Schema(description = "Le rôle du membre dans l'association.", example = "MEMBRE")
@FormParam("role") @FormParam("role")
private RoleAsso role; private RoleAsso role;
@Schema(description = "Le grade d'arbitrage du membre.", examples = "ASSESSEUR") @Schema(description = "Le grade d'arbitrage du membre.", example = "ASSESSEUR")
@FormParam("grade_arbitrage") @FormParam("grade_arbitrage")
private GradeArbitrage grade_arbitrage = GradeArbitrage.NA; private GradeArbitrage grade_arbitrage = GradeArbitrage.NA;
@Schema(description = "La photo du membre.") @Schema(description = "La photo du membre.")
@FormParam("photo_data") @FormParam("photo_data")
@PartType(MediaType.APPLICATION_OCTET_STREAM) @PartType(MediaType.APPLICATION_OCTET_STREAM)
private FileUpload photo_data = null; private byte[] photo_data = new byte[0];
@Override @Override
public String toString() { public String toString() {
@ -71,6 +70,7 @@ public class FullMemberForm {
", email='" + email + '\'' + ", email='" + email + '\'' +
", role=" + role + ", role=" + role +
", grade_arbitrage=" + grade_arbitrage + ", grade_arbitrage=" + grade_arbitrage +
", url_photo=" + photo_data.length +
'}'; '}';
} }
} }

View File

@ -2,19 +2,13 @@ package fr.titionfire.ffsaf.utils;
import fr.titionfire.ffsaf.data.model.CompetitionGuestModel; import fr.titionfire.ffsaf.data.model.CompetitionGuestModel;
import fr.titionfire.ffsaf.data.model.MembreModel; import fr.titionfire.ffsaf.data.model.MembreModel;
import fr.titionfire.ffsaf.domain.service.VirusScannerService;
import fr.titionfire.ffsaf.rest.exception.DBadRequestException;
import fr.titionfire.ffsaf.rest.exception.DInternalError;
import fr.titionfire.ffsaf.rest.exception.DetailException;
import io.quarkiverse.antivirus.runtime.AntivirusScanResult;
import io.smallrye.mutiny.Uni; import io.smallrye.mutiny.Uni;
import io.smallrye.mutiny.unchecked.Unchecked;
import jakarta.ws.rs.core.HttpHeaders; import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
import jodd.net.MimeTypes; import jodd.net.MimeTypes;
import org.apache.tika.Tika;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.jboss.resteasy.reactive.multipart.FileUpload;
import java.io.*; import java.io.*;
import java.net.URISyntaxException; import java.net.URISyntaxException;
@ -189,72 +183,44 @@ public class Utils {
}); });
} }
public static Uni<String> uploadFile(VirusScannerService ss, FileUpload file, long id, String media, String dir) { public static Future<String> replacePhoto(long id, byte[] input, String media, String dir) {
if (file == null || file.size() == 0) return CompletableFuture.supplyAsync(() -> {
return Uni.createFrom().item("Ok"); if (input == null || input.length == 0)
return "OK";
LOGGER.infof("Received file upload request for: %s (size: %d bytes)", file.fileName(), file.size()); try (InputStream is = new BufferedInputStream(new ByteArrayInputStream(input))) {
return Uni.createFrom().<InputStream>item(() -> { String mimeType;
try { try {
// Read the entire file into memory for virus scanning Tika tika = new Tika();
// ByteArrayInputStream fully supports mark/reset operations required by ClamAV mimeType = tika.detect(is);// Magic.getMagicMatch(input, false).getMimeType();
// This ensures we can scan the file content before any filesystem storage
InputStream fileStream = java.nio.file.Files.newInputStream(file.uploadedFile());
byte[] fileBytes = fileStream.readAllBytes();
fileStream.close(); // Close the file stream immediately
return new ByteArrayInputStream(fileBytes);
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException("Failed to read uploaded file: " + e.getMessage(), e); mimeType = URLConnection.guessContentTypeFromStream(is);
} }
}).runSubscriptionOn(io.smallrye.mutiny.infrastructure.Infrastructure.getDefaultWorkerPool()).onItem() String[] detectedExtensions = MimeTypes.findExtensionsByMimeTypes(mimeType, false);
.transformToUni(inputStream -> {
// Perform virus scanning reactively using the input stream
return ss.scanFileReactive(file.fileName(), inputStream).onItem().invoke(() -> {
try {
inputStream.close();
} catch (IOException e) {
LOGGER.warn("Warning: Failed to close input stream: " + e.getMessage());
}
});
})
.onItem().transformToUni(scanResults -> Uni.createFrom().item(Unchecked.supplier(() -> {
// Check if any scanner found a threat
for (AntivirusScanResult result : scanResults) {
if (result.getStatus() != Response.Status.OK.getStatusCode()) {
LOGGER.warnf("THREAT DETECTED in %s: %s", file.fileName(), result.getMessage());
throw new DetailException(Response.Status.fromStatusCode(result.getStatus()),
"THREAT_DETECTED on File " + file.fileName() + " is infected: " + result.getMessage());
}
}
// File is clean - now we can safely process it
LOGGER.infof("File is clean: %s (size=%d) (contentType=%s)", file.fileName(), file.size(),
file.contentType());
String[] detectedExtensions = MimeTypes.findExtensionsByMimeTypes(file.contentType(), false);
if (detectedExtensions.length == 0) if (detectedExtensions.length == 0)
throw new DBadRequestException( throw new IOException("Fail to detect file extension for MIME type " + mimeType);
"Fail to detect file extension for MIME type " + file.contentType());
File dirFile = new File(media, dir); File dirFile = new File(media, dir);
if (!dirFile.exists()) if (!dirFile.exists())
if (!dirFile.mkdirs()) if (!dirFile.mkdirs())
throw new DInternalError("Fail to create directory " + dir); throw new IOException("Fail to create directory " + dir);
FilenameFilter filter = (directory, filename) -> filename.startsWith(id + "."); FilenameFilter filter = (directory, filename) -> filename.startsWith(id + ".");
File[] files = dirFile.listFiles(filter); File[] files = dirFile.listFiles(filter);
if (files != null) { if (files != null) {
for (File f : files) { for (File file : files) {
//noinspection ResultOfMethodCallIgnored //noinspection ResultOfMethodCallIgnored
f.delete(); file.delete();
} }
} }
File f = file.filePath().toFile(); String extension = "." + detectedExtensions[0];
//noinspection ResultOfMethodCallIgnored Files.write(new File(dirFile, id + extension).toPath(), input);
f.renameTo(new File(dirFile, id + "." + detectedExtensions[0])); return "OK";
return "ok"; } catch (IOException e) {
}))); return e.getMessage();
}
});
} }
public static Uni<Response> getMediaFile(long id, String media, String dirname, public static Uni<Response> getMediaFile(long id, String media, String dirname,
@ -402,8 +368,8 @@ public class Utils {
return result.toString().trim(); return result.toString().trim();
} }
public static String getFullName(Object... models) { public static String getFullName(Object ...models) {
for (Object model : models) { for (Object model : models){
if (model == null) if (model == null)
continue; continue;
if (model instanceof MembreModel membreModel) if (model instanceof MembreModel membreModel)