package fr.titionfire.ffsaf.domain.service; import fr.titionfire.ffsaf.data.model.*; import fr.titionfire.ffsaf.data.repository.*; import fr.titionfire.ffsaf.net2.ServerCustom; import fr.titionfire.ffsaf.net2.data.SimpleCompet; import fr.titionfire.ffsaf.net2.request.SReqCompet; import fr.titionfire.ffsaf.net2.request.SReqRegister; import fr.titionfire.ffsaf.rest.client.dto.NotificationData; import fr.titionfire.ffsaf.rest.data.CompetitionData; import fr.titionfire.ffsaf.rest.data.RegisterRequestData; import fr.titionfire.ffsaf.rest.data.SimpleCompetData; import fr.titionfire.ffsaf.rest.data.SimpleRegisterComb; import fr.titionfire.ffsaf.rest.exception.DBadRequestException; import fr.titionfire.ffsaf.rest.exception.DForbiddenException; import fr.titionfire.ffsaf.rest.exception.DNotFoundException; import fr.titionfire.ffsaf.utils.*; import fr.titionfire.ffsaf.ws.send.SRegister; import io.quarkus.cache.Cache; import io.quarkus.cache.CacheName; import io.quarkus.hibernate.reactive.panache.Panache; import io.quarkus.hibernate.reactive.panache.common.WithSession; import io.quarkus.mailer.Mail; import io.quarkus.mailer.reactive.ReactiveMailer; import io.smallrye.mutiny.Multi; import io.smallrye.mutiny.Uni; import io.smallrye.mutiny.unchecked.Unchecked; import io.vertx.mutiny.core.Vertx; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.ws.rs.NotFoundException; import jakarta.ws.rs.core.Response; import org.hibernate.reactive.mutiny.Mutiny; import org.jboss.logging.Logger; import org.keycloak.representations.idm.UserRepresentation; import java.util.*; import java.util.stream.Stream; @WithSession @ApplicationScoped public class CompetitionService { private static final Logger LOGGER = Logger.getLogger(CompetitionService.class); @Inject CompetitionRepository repository; @Inject CategoryRepository categoryRepository; @Inject MatchRepository matchRepository; @Inject RegisterRepository registerRepository; @Inject KeycloakService keycloakService; @Inject CombRepository combRepository; @Inject CompetitionGuestRepository competitionGuestRepository; @Inject ServerCustom serverCustom; @Inject MembreService membreService; @Inject CompetPermService permService; @Inject HelloAssoRegisterRepository helloAssoRepository; @SuppressWarnings("CdiInjectionPointsInspection") @Inject ReactiveMailer reactiveMailer; @Inject Vertx vertx; @Inject SRegister sRegister; @Inject @CacheName("safca-config") Cache cache; @Inject @CacheName("safca-have-access") Cache cacheAccess; @Inject @CacheName("have-access") Cache cacheNoneAccess; @Inject TradService trad; public Uni getById(SecurityCtx securityCtx, Long id) { return permService.hasViewPerm(securityCtx, id).map(cm -> { CompetitionData out = CompetitionData.fromModelLight(cm); if (cm.getAdmin() != null) { out.setCanEditRegisters(cm.getAdmin().stream().anyMatch(u -> u.equals(securityCtx.getSubject()))); } return out; }); } public Uni getByIdAdmin(SecurityCtx securityCtx, Long id) { if (id == 0) { return Uni.createFrom() .item(new CompetitionData(null, "", "", "", "", new Date(), new Date(), CompetitionSystem.INTERNAL, RegisterMode.FREE, new Date(), new Date(), true, null, "", "", null, true, true, "", "", "", "", "{}")); } return permService.hasAdminViewPerm(securityCtx, id) .chain(competitionModel -> Mutiny.fetch(competitionModel.getInsc()) .chain(insc -> Mutiny.fetch(competitionModel.getGuests()) .map(guest -> CompetitionData.fromModel(competitionModel).addInsc(insc, guest)))) .chain(data -> vertx.getOrCreateContext().executeBlocking(() -> { keycloakService.getUser(UUID.fromString(data.getOwner())) .ifPresent(user -> data.setOwner(user.getUsername())); return data; }) ); } public Uni> getAll(SecurityCtx securityCtx) { List out = new ArrayList<>(); return permService.getAllHaveAdminAccess(securityCtx) .call(ids -> repository.list("id IN ?1", ids) .invoke(cm -> { out.addAll(cm.stream().map(CompetitionData::fromModelLight).toList()); out.forEach(competition -> competition.setCanEdit(true)); })) .chain(ids -> repository.list("id NOT IN ?1 AND ?2 IN admin", ids, securityCtx.getSubject()) .map(cm -> { out.addAll(cm.stream().map(CompetitionData::fromModelLight).toList()); out.forEach(competition -> competition.setCanEditRegisters(true)); List ids2 = new ArrayList<>(ids); ids2.addAll(cm.stream().map(CompetitionModel::getId).toList()); return ids2; })) .call(ids -> repository.list("id NOT IN ?1 AND (publicVisible = TRUE OR registerMode IN ?2)", ids, securityCtx.isClubAdmin() ? List.of(RegisterMode.FREE, RegisterMode.HELLOASSO, RegisterMode.CLUB_ADMIN) : List.of(RegisterMode.FREE, RegisterMode.HELLOASSO)) .invoke(cm -> out.addAll(cm.stream().map(CompetitionData::fromModelLight).toList())) .call(cm -> registerRepository.list( "membre.userId = ?1 AND competition.id NOT IN ?2 AND competition NOT IN ?3", securityCtx.getSubject(), ids, cm) .chain(registerModels -> { Uni uni = Uni.createFrom().nullItem(); for (RegisterModel registerModel : registerModels) { uni = uni.call(__ -> Mutiny.fetch(registerModel.getCompetition()) .invoke(cm2 -> out.add(CompetitionData.fromModelLight(cm2)))); } return uni; }) )) .map(__ -> out); } public Uni> getAllAdmin(SecurityCtx securityCtx) { return permService.getAllHaveAdminAccess(securityCtx) .chain(ids -> repository.list("id IN ?1", ids)) .map(pouleModels -> pouleModels.stream().map(CompetitionData::fromModel).toList()); } public Uni> getAllSystemAdmin(SecurityCtx securityCtx, CompetitionSystem system) { return permService.getAllHaveAdminAccess(securityCtx) .chain(ids -> repository.list("system = ?1 AND id IN ?2", system, ids)) .map(pouleModels -> pouleModels.stream().map(CompetitionData::fromModel).toList()); } public Uni> getAllSystemTable(SecurityCtx securityCtx, CompetitionSystem system) { return repository.list("system = ?1", system) .chain(l -> Uni.join().all(l.stream().map(cm -> permService.hasTablePerm(securityCtx, cm).onFailure().recoverWithNull() ).toList()).andCollectFailures()) .map(l -> l.stream().filter(Objects::nonNull).map(CompetitionData::fromModel).toList()); } public Uni addOrUpdate(SecurityCtx securityCtx, CompetitionData data) { if (data.getId() == null) { return combRepository.find("userId = ?1", securityCtx.getSubject()).firstResult() .invoke(Unchecked.consumer(combModel -> { if (!securityCtx.getRoles().contains("create_compet") && !securityCtx.getRoles() .contains("federation_admin")) throw new DForbiddenException(trad.t("vous.ne.pouvez.pas.creer.de.competition")); })) .map(MembreModel::getClub) .chain(clubModel -> { CompetitionModel model = new CompetitionModel(); model.setId(null); model.setSystem(data.getSystem()); model.setClub(clubModel); model.setInsc(new ArrayList<>()); model.setGuests(new ArrayList<>()); model.setUuid(UUID.randomUUID().toString()); model.setOwner(securityCtx.getSubject()); copyData(data, model); return Panache.withTransaction(() -> repository.persist(model)); }).map(CompetitionData::fromModel) .call(c -> (c.getSystem() == CompetitionSystem.SAFCA) ? cacheAccess.invalidate( securityCtx.getSubject()) : Uni.createFrom().nullItem()) .call(c -> (c.getSystem() == CompetitionSystem.INTERNAL) ? cacheNoneAccess.invalidate( securityCtx.getSubject()) : Uni.createFrom().nullItem()); } else { return permService.hasEditPerm(securityCtx, data.getId()) .chain(model -> { copyData(data, model); return vertx.getOrCreateContext().executeBlocking(() -> // Update owner keycloakService.getUser(data.getOwner()).map(UserRepresentation::getId).orElse(null)) .invoke(Unchecked.consumer(newOwner -> { if (newOwner == null) throw new DBadRequestException( String.format(trad.t("user.not.found"), data.getOwner())); if (!newOwner.equals(model.getOwner())) { if (!securityCtx.roleHas("federation_admin") && !securityCtx.roleHas("safca_super_admin") && !securityCtx.getSubject().equals(model.getOwner())) throw new DForbiddenException(); model.setOwner(newOwner); } })) .chain(__ -> Panache.withTransaction(() -> repository.persist(model))); }).map(CompetitionData::fromModel) .call(c -> (c.getSystem() == CompetitionSystem.SAFCA) ? cacheAccess.invalidate( securityCtx.getSubject()) : Uni.createFrom().nullItem()) .call(c -> (c.getSystem() == CompetitionSystem.INTERNAL) ? cacheNoneAccess.invalidate( securityCtx.getSubject()) : Uni.createFrom().nullItem()); } } private void copyData(CompetitionData data, CompetitionModel model) { if (model.getBanMembre() == null) model.setBanMembre(new ArrayList<>()); model.setName(data.getName()); model.setAdresse(data.getAdresse()); model.setDescription(data.getDescription()); model.setDate(data.getDate()); model.setTodate(data.getDate()); model.setPublicVisible(data.isPublicVisible()); model.setStartRegister(data.getStartRegister()); model.setEndRegister(data.getEndRegister()); model.setRegisterMode(data.getRegisterMode()); model.setData1(data.getData1()); model.setData2(data.getData2()); model.setData3(data.getData3()); model.setData4(data.getData4()); } public Uni> getRegister(SecurityCtx securityCtx, Long id, String source) { if ("admin".equals(source)) return permService.hasEditPerm(securityCtx, id) .chain(c -> { Uni> uni = Mutiny.fetch(c.getInsc()) .onItem().transformToMulti(Multi.createFrom()::iterable) .onItem().call(combModel -> Mutiny.fetch(combModel.getMembre().getLicences())) .map(cm -> SimpleRegisterComb.fromModel(cm, cm.getMembre().getLicences())) .collect().asList(); return uni .call(l -> Mutiny.fetch(c.getGuests()) .map(guest -> guest.stream().map(SimpleRegisterComb::fromModel).toList()) .invoke(l::addAll)); }); if ("club".equals(source)) return Uni.createFrom().nullItem() .invoke(Unchecked.consumer(__ -> { if (!securityCtx.isClubAdmin()) throw new DForbiddenException(); })) .chain(__ -> membreService.getByAccountId(securityCtx.getSubject())) .chain(model -> registerRepository.list("competition.id = ?1 AND membre.club = ?2", id, model.getClub())) .onItem().transformToMulti(Multi.createFrom()::iterable) .onItem().call(combModel -> Mutiny.fetch(combModel.getMembre().getLicences())) .map(combModel -> SimpleRegisterComb.fromModel(combModel, combModel.getMembre().getLicences())) .collect().asList(); return membreService.getByAccountId(securityCtx.getSubject()) .chain(model -> registerRepository.find("competition.id = ?1 AND membre = ?2", id, model).firstResult() .map(rm -> rm == null ? List.of() : List.of(SimpleRegisterComb.fromModel(rm, List.of())))); } public Uni addRegisterComb(SecurityCtx securityCtx, Long id, RegisterRequestData data, String source) { if ("admin".equals(source)) if (data.getLicence() == null || data.getLicence() != -1) { // not a guest return permService.hasEditPerm(securityCtx, id) .chain(c -> findComb(data.getLicence(), data.getFname(), data.getLname()) .call(combModel -> Mutiny.fetch(combModel.getLicences())) .call(combModel -> { if (c.getBanMembre() == null) c.setBanMembre(new ArrayList<>()); c.getBanMembre().remove(combModel.getId()); return Panache.withTransaction(() -> repository.persist(c)); }) .chain(combModel -> updateRegister(data, c, combModel, true))) .map(r -> SimpleRegisterComb.fromModel(r, r.getMembre().getLicences())); } else { return permService.hasEditPerm(securityCtx, id) .chain(c -> competitionGuestRepository.findById(data.getId() * -1) .map(g -> { if (g != null) return g; CompetitionGuestModel model = new CompetitionGuestModel(); model.setCompetition(c); return model; })) .chain(model -> { model.setFname(data.getFname()); model.setLname(data.getLname()); model.setGenre(data.getGenre()); model.setClub(data.getClub()); model.setCountry(data.getCountry()); model.setWeight(data.getWeight()); model.setCategorie(data.getCategorie()); return Panache.withTransaction(() -> competitionGuestRepository.persist(model)) .call(r -> model.getCompetition().getSystem() == CompetitionSystem.INTERNAL ? sRegister.sendRegister(model.getCompetition().getUuid(), r) : Uni.createFrom().voidItem()); }) .map(SimpleRegisterComb::fromModel); } if ("club".equals(source)) return repository.findById(id) .invoke(Unchecked.consumer(cm -> { if (!(cm.getRegisterMode() == RegisterMode.CLUB_ADMIN || cm.getRegisterMode() == RegisterMode.FREE) || !securityCtx.isClubAdmin()) throw new DForbiddenException(); if (new Date().before(cm.getStartRegister()) || new Date().after(cm.getEndRegister())) throw new DBadRequestException(trad.t("inscription.fermee")); })) .chain(c -> findComb(data.getLicence(), data.getFname(), data.getLname()) .call(combModel -> Mutiny.fetch(combModel.getLicences())) .invoke(Unchecked.consumer(model -> { if (!securityCtx.isInClubGroup(model.getClub().getId())) throw new DForbiddenException(); if (c.getBanMembre().contains(model.getId())) throw new DForbiddenException(trad.t("insc.err1")); })) .chain(combModel -> updateRegister(data, c, combModel, false))) .map(r -> SimpleRegisterComb.fromModel(r, r.getMembre().getLicences())); return repository.findById(id) .invoke(Unchecked.consumer(cm -> { if (cm.getRegisterMode() != RegisterMode.FREE) throw new DForbiddenException(); if (new Date().before(cm.getStartRegister()) || new Date().after(cm.getEndRegister())) throw new DBadRequestException(trad.t("inscription.fermee")); })) .chain(c -> membreService.getByAccountId(securityCtx.getSubject()) .invoke(Unchecked.consumer(model -> { if (c.getBanMembre().contains(model.getId())) throw new DForbiddenException(trad.t("insc.err2")); })) .chain(combModel -> updateRegister(data, c, combModel, false))) .map(r -> SimpleRegisterComb.fromModel(r, List.of())); } private Uni updateRegister(RegisterRequestData data, CompetitionModel c, MembreModel combModel, boolean admin) { return registerRepository.find("competition = ?1 AND membre = ?2", c, combModel).firstResult() .onFailure().recoverWithNull() .map(Unchecked.function(r -> { if (r != null) { if (!admin && r.isLockEdit()) throw new DForbiddenException(trad.t("insc.err3")); r.setWeight(data.getWeight()); r.setOverCategory(data.getOverCategory()); r.setCategorie( (combModel.getBirth_date() == null) ? combModel.getCategorie() : Utils.getCategoryFormBirthDate(combModel.getBirth_date(), c.getDate())); int days = Utils.getDaysBeforeCompetition(c.getDate()); if (days > -7) r.setClub(combModel.getClub()); if (admin) r.setLockEdit(data.isLockEdit()); } else { r = new RegisterModel(c, combModel, data.getWeight(), data.getOverCategory(), (combModel.getBirth_date() == null) ? combModel.getCategorie() : Utils.getCategoryFormBirthDate(combModel.getBirth_date(), c.getDate()), (combModel.getClub() == null) ? null : combModel.getClub()); if (admin) r.setLockEdit(data.isLockEdit()); else r.setLockEdit(false); } if (c.getSystem() == CompetitionSystem.SAFCA) { SReqRegister.sendIfNeed(serverCustom.clients, new CompetitionData.SimpleRegister(r.getMembre().getId(), r.getOverCategory(), r.getWeight(), r.getCategorie(), (r.getClub() == null) ? null : r.getClub().getId(), (r.getClub() == null) ? null : r.getClub().getName()), c.getId()); } return r; })) .chain(r -> Panache.withTransaction(() -> registerRepository.persist(r))) .call(r -> c.getSystem() == CompetitionSystem.INTERNAL ? sRegister.sendRegister(c.getUuid(), r) : Uni.createFrom().voidItem()); } private Uni findComb(Long licence, String fname, String lname) { if (licence != null && licence > 0) { return combRepository.find("licence = ?1", licence).firstResult() .invoke(Unchecked.consumer(combModel -> { if (combModel == null) throw new DForbiddenException(String.format(trad.t("licence.non.trouve"), licence)); })); } else { if (fname == null || lname == null) return Uni.createFrom().failure(new DBadRequestException(trad.t("nom.et.prenom.requis"))); return combRepository.find("unaccent(lname) ILIKE unaccent(?1) AND unaccent(fname) ILIKE unaccent(?2)", lname, fname).firstResult() .invoke(Unchecked.consumer(combModel -> { if (combModel == null) throw new DForbiddenException(String.format(trad.t("combattant.non.trouve"), fname, lname)); })); } } public Uni removeRegisterComb(SecurityCtx securityCtx, Long id, Long combId, String source, boolean ban) { if ("admin".equals(source)) return permService.hasEditPerm(securityCtx, id) .chain(cm -> { if (cm.getBanMembre() == null) cm.setBanMembre(new ArrayList<>()); if (ban) { if (!cm.getBanMembre().contains(combId)) cm.getBanMembre().add(combId); } else { cm.getBanMembre().remove(combId); } return Panache.withTransaction(() -> repository.persist(cm)); }) .chain(c -> deleteRegister(combId, c, true)); if ("club".equals(source)) return repository.findById(id) .invoke(Unchecked.consumer(cm -> { if (!(cm.getRegisterMode() == RegisterMode.CLUB_ADMIN || cm.getRegisterMode() == RegisterMode.FREE) || !securityCtx.isClubAdmin()) throw new DForbiddenException(); if (new Date().before(cm.getStartRegister()) || new Date().after(cm.getEndRegister())) throw new DBadRequestException(trad.t("inscription.fermee")); })) .call(cm -> membreService.getById(combId) .invoke(Unchecked.consumer(model -> { if (model == null) throw new DNotFoundException(String.format(trad.t("le.membre.n.existe.pas"), combId)); if (!securityCtx.isInClubGroup(model.getClub().getId())) throw new DForbiddenException(); }))) .chain(c -> deleteRegister(combId, c, false)); return repository.findById(id) .call(cm -> membreService.getByAccountId(securityCtx.getSubject()) .invoke(Unchecked.consumer(model -> { if (cm.getRegisterMode() != RegisterMode.FREE || !Objects.equals(model.getId(), combId)) throw new DForbiddenException(); if (new Date().before(cm.getStartRegister()) || new Date().after(cm.getEndRegister())) throw new DBadRequestException(trad.t("inscription.fermee")); }))) .chain(c -> deleteRegister(combId, c, false)); } private Uni deleteRegister(Long combId, CompetitionModel c, boolean admin) { if (admin && combId < 0) { return competitionGuestRepository.find("competition = ?1 AND id = ?2", c, combId * -1).firstResult() .onFailure().transform(t -> new DBadRequestException(trad.t("combattant.non.inscrit"))) .call(Unchecked.function( model -> Panache.withTransaction(() -> competitionGuestRepository.delete(model)) .call(r -> c.getSystem() == CompetitionSystem.INTERNAL ? sRegister.sendRegisterRemove(c.getUuid(), combId) : Uni.createFrom() .voidItem()))) .replaceWithVoid(); } return registerRepository.find("competition = ?1 AND membre.id = ?2", c, combId).firstResult() .onFailure().transform(t -> new DBadRequestException(trad.t("combattant.non.inscrit"))) .call(Unchecked.function(registerModel -> { if (!admin && registerModel.isLockEdit()) throw new DForbiddenException(trad.t("insc.err3")); return Panache.withTransaction(() -> registerRepository.delete(registerModel)) .call(r -> c.getSystem() == CompetitionSystem.INTERNAL ? sRegister.sendRegisterRemove(c.getUuid(), combId) : Uni.createFrom().voidItem()); })) .replaceWithVoid(); } public Uni delete(SecurityCtx securityCtx, Long id) { return repository.findById(id).invoke(Unchecked.consumer(c -> { if (!(securityCtx.getSubject().equals(c.getOwner()) || securityCtx.roleHas("federation_admin"))) throw new DForbiddenException(); })) .call(competitionModel -> categoryRepository.list("compet = ?1", competitionModel) .call(pouleModels -> pouleModels.isEmpty() ? Uni.createFrom().nullItem() : Uni.join().all(pouleModels.stream() .map(pouleModel -> Panache.withTransaction( () -> matchRepository.delete("poule = ?1", pouleModel.getId()))) .toList()) .andCollectFailures())) .call(competitionModel -> Panache.withTransaction( () -> categoryRepository.delete("compet = ?1", competitionModel))) .call(competitionModel -> Panache.withTransaction( () -> registerRepository.delete("competition = ?1", competitionModel))) .call(competitionModel -> Panache.withTransaction( () -> competitionGuestRepository.delete("competition = ?1", competitionModel))) .chain(model -> Panache.withTransaction(() -> repository.delete("id", model.getId()))) .invoke(o -> SReqCompet.rmCompet(serverCustom.clients, id)) .call(__ -> cache.invalidate(id)); } public Uni getInternalData(SecurityCtx securityCtx, Long id) { return permService.hasEditPerm(securityCtx, id) .invoke(Unchecked.consumer(cm -> { if (cm.getSystem() != CompetitionSystem.INTERNAL) throw new DBadRequestException(trad.t("competition.is.not.internal")); })) .chain(competitionModel -> { SimpleCompetData data = SimpleCompetData.fromModel(competitionModel); return vertx.getOrCreateContext().executeBlocking(() -> { if (competitionModel.getAdmin() != null) data.setAdmin( competitionModel.getAdmin().stream().map(uuid -> keycloakService.getUserById(uuid)) .filter(Optional::isPresent) .map(user -> user.get().getUsername()) .toList()); if (competitionModel.getTable() != null) data.setTable( competitionModel.getTable().stream().map(uuid -> keycloakService.getUserById(uuid)) .filter(Optional::isPresent) .map(user -> user.get().getUsername()) .toList()); return data; }); }); } public Uni setInternalData(SecurityCtx securityCtx, SimpleCompetData data) { return permService.hasEditPerm(securityCtx, data.getId()) .invoke(Unchecked.consumer(cm -> { if (cm.getSystem() != CompetitionSystem.INTERNAL) throw new DBadRequestException(trad.t("competition.is.not.internal")); })) .chain(cm -> vertx.getOrCreateContext().executeBlocking(() -> { ArrayList admin = new ArrayList<>(); ArrayList table = new ArrayList<>(); for (String username : data.getAdmin()) { Optional opt = keycloakService.getUser(username); if (opt.isEmpty()) throw new DBadRequestException(String.format(trad.t("user.not.found"), username)); admin.add(opt.get().getId()); } for (String username : data.getTable()) { Optional opt = keycloakService.getUser(username); if (opt.isEmpty()) throw new DBadRequestException(String.format(trad.t("user.not.found"), username)); table.add(opt.get().getId()); } cm.setAdmin(admin); cm.setTable(table); cm.setConfig(data.getConfigForInternal()); return cm; })) .chain(cm -> Panache.withTransaction(() -> repository.persist(cm))) .replaceWithVoid(); } public Uni getSafcaData(SecurityCtx securityCtx, Long id) { return permService.getSafcaConfig(id) .call(Unchecked.function(o -> { if (!securityCtx.getSubject().equals(o.owner()) && !securityCtx.roleHas("federation_admin") && !securityCtx.roleHas("safca_super_admin") && !o.admin().contains(UUID.fromString(securityCtx.getSubject())) && !o.table().contains(UUID.fromString(securityCtx.getSubject()))) throw new DForbiddenException(); return Uni.createFrom().nullItem(); })) .chain(simpleCompet -> { SimpleCompetData data = SimpleCompetData.fromModel(simpleCompet); return vertx.getOrCreateContext().executeBlocking(() -> { data.setAdmin(simpleCompet.admin().stream().map(uuid -> keycloakService.getUser(uuid)) .filter(Optional::isPresent) .map(user -> user.get().getUsername()) .toList()); data.setTable(simpleCompet.table().stream().map(uuid -> keycloakService.getUser(uuid)) .filter(Optional::isPresent) .map(user -> user.get().getUsername()) .toList()); return data; }); }); } public Uni setSafcaData(SecurityCtx securityCtx, SimpleCompetData data) { return permService.hasEditPerm(securityCtx, data.getId()) .chain(__ -> vertx.getOrCreateContext().executeBlocking(() -> { ArrayList admin = new ArrayList<>(); ArrayList table = new ArrayList<>(); for (String username : data.getAdmin()) { Optional opt = keycloakService.getUser(username); if (opt.isEmpty()) throw new DBadRequestException(String.format(trad.t("user.not.found"), username)); admin.add(UUID.fromString(opt.get().getId())); } for (String username : data.getTable()) { Optional opt = keycloakService.getUser(username); if (opt.isEmpty()) throw new DBadRequestException(String.format(trad.t("user.not.found"), username)); table.add(UUID.fromString(opt.get().getId())); } return new SimpleCompet(data.getId(), "", data.isShow_blason(), data.isShow_flag(), admin, table); })) .invoke(simpleCompet -> SReqCompet.sendUpdate(serverCustom.clients, simpleCompet)) .call(simpleCompet -> permService.getSafcaConfig(data.getId()) .call(c -> { List> list = Stream.concat( Stream.concat( c.admin().stream().filter(uuid -> !simpleCompet.admin().contains(uuid)), simpleCompet.admin().stream().filter(uuid -> !c.admin().contains(uuid))), Stream.concat( c.table().stream().filter(uuid -> !simpleCompet.table().contains(uuid)), simpleCompet.table().stream().filter(uuid -> !c.table().contains(uuid))) ).map(uuid -> cacheAccess.invalidate(uuid.toString())).toList(); if (list.isEmpty()) return Uni.createFrom().nullItem(); return Uni.join().all(list).andCollectFailures(); })) .call(__ -> cache.invalidate(data.getId())); } public Uni unregisterHelloAsso(NotificationData data) { if (!data.getState().equals("Refunded")) return Uni.createFrom().item(Response.ok().build()); return helloAssoRepository.list("orderId = ?1", data.getOrder().getId()) .chain(regs -> { Uni uni = Uni.createFrom().nullItem(); for (HelloAssoRegisterModel reg : regs) { if (reg.getCompetition().getRegisterMode() != RegisterMode.HELLOASSO) continue; if (!data.getOrder().getOrganizationSlug().equalsIgnoreCase(reg.getCompetition().getData1())) continue; uni = uni.call(__ -> Panache.withTransaction( () -> registerRepository.delete("competition = ?1 AND membre = ?2", reg.getCompetition(), reg.getMembre()))) .call(r -> reg.getCompetition().getSystem() == CompetitionSystem.INTERNAL ? sRegister.sendRegisterRemove(reg.getCompetition().getUuid(), reg.getMembre().getId()) : Uni.createFrom().voidItem()).onFailure() .recoverWithNull() ; } return uni; }) .onFailure().invoke(Throwable::printStackTrace) .map(__ -> Response.ok().build()); } public Uni registerHelloAsso(NotificationData data) { String organizationSlug = data.getOrganizationSlug(); String formSlug = data.getFormSlug(); RegisterRequestData req = new RegisterRequestData(null, "", "", null, 0, false, null, Categorie.CADET, Genre.NA, null, "fr"); return repository.find("data1 = ?1 AND data2 = ?2", organizationSlug, formSlug).firstResult() .onFailure().recoverWithNull() .chain(cm -> { Uni uni = Uni.createFrom().nullItem(); if (cm == null || cm.getRegisterMode() != RegisterMode.HELLOASSO) return uni; List place = List.of(cm.getData3().toLowerCase().split(";")); List fail = new ArrayList<>(); for (NotificationData.Item item : data.getItems()) { if (!place.contains(item.getName().toLowerCase())) continue; if (item.getCustomFields() == null || item.getCustomFields().isEmpty()) { fail.add("%s %s - licence n°???".formatted(item.getUser().getLastName(), item.getUser().getFirstName())); continue; } Optional optional = item.getCustomFields().stream() .filter(cf -> cf.getName().equalsIgnoreCase("Numéro de licence")).findAny().map( NotificationData.CustomField::getAnswer).map(Long::valueOf); if (optional.isPresent()) { uni = uni.call(__ -> membreService.getByLicence(optional.get()) .invoke(Unchecked.consumer(m -> { if (m == null) throw new NotFoundException(); })) .call(m -> Panache.withTransaction(() -> helloAssoRepository.persist( new HelloAssoRegisterModel(cm, m, data.getId())))) .chain(m -> updateRegister(req, cm, m, true))) .onFailure().recoverWithItem(throwable -> { fail.add("%s %s - licence n°%d".formatted(item.getUser().getLastName(), item.getUser().getFirstName(), optional.get())); return null; }) .replaceWithVoid(); } else { fail.add("%s %s - licence n°???".formatted(item.getUser().getLastName(), item.getUser().getFirstName())); } } return uni.call(__ -> fail.isEmpty() ? Uni.createFrom().nullItem() : reactiveMailer.send( Mail.withText(cm.getData4(), "FFSAF - Compétition - Erreur HelloAsso", String.format( """ Bonjour, Une erreur a été rencontrée lors de l'enregistrement d'une inscription à votre compétition %s pour les combattants suivants: %s Cordialement, L'intranet de la FFSAF """, cm.getName(), String.join("\r\n", fail)) ).setFrom("FFSAF ").setReplyTo("support@ffsaf.fr") ).onFailure().invoke(e -> LOGGER.error("Fail to send email", e))); }) .onFailure().invoke(Throwable::printStackTrace) .map(__ -> Response.ok().build()); } }