All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 10m6s
257 lines
12 KiB
Java
257 lines
12 KiB
Java
package fr.titionfire.ffsaf.domain.service;
|
|
|
|
import fr.titionfire.ffsaf.data.model.CompetitionModel;
|
|
import fr.titionfire.ffsaf.data.repository.CompetitionRepository;
|
|
import fr.titionfire.ffsaf.data.repository.RegisterRepository;
|
|
import fr.titionfire.ffsaf.net2.ServerCustom;
|
|
import fr.titionfire.ffsaf.net2.data.SimpleCompet;
|
|
import fr.titionfire.ffsaf.net2.request.SReqCompet;
|
|
import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
|
|
import fr.titionfire.ffsaf.utils.CompetitionSystem;
|
|
import fr.titionfire.ffsaf.utils.RegisterMode;
|
|
import fr.titionfire.ffsaf.utils.SecurityCtx;
|
|
import io.quarkus.cache.Cache;
|
|
import io.quarkus.cache.CacheName;
|
|
import io.smallrye.mutiny.Uni;
|
|
import io.smallrye.mutiny.unchecked.Unchecked;
|
|
import jakarta.enterprise.context.ApplicationScoped;
|
|
import jakarta.inject.Inject;
|
|
|
|
import java.time.Duration;
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.UUID;
|
|
import java.util.concurrent.CompletableFuture;
|
|
import java.util.concurrent.ExecutionException;
|
|
import java.util.concurrent.TimeUnit;
|
|
import java.util.concurrent.TimeoutException;
|
|
|
|
@ApplicationScoped
|
|
public class CompetPermService {
|
|
|
|
@Inject
|
|
ServerCustom serverCustom;
|
|
|
|
@Inject
|
|
CompetitionRepository competitionRepository;
|
|
|
|
@Inject
|
|
@CacheName("safca-config")
|
|
Cache cache;
|
|
|
|
@Inject
|
|
@CacheName("safca-have-access")
|
|
Cache cacheAccess;
|
|
|
|
@Inject
|
|
@CacheName("have-access")
|
|
Cache cacheNoneAccess;
|
|
@Inject
|
|
RegisterRepository registerRepository;
|
|
|
|
|
|
public Uni<SimpleCompet> getSafcaConfig(long id) {
|
|
return cache.get(id, k -> {
|
|
CompletableFuture<SimpleCompet> f = new CompletableFuture<>();
|
|
SReqCompet.getConfig(serverCustom.clients, id, f);
|
|
try {
|
|
return f.get(1500, TimeUnit.MILLISECONDS);
|
|
} catch (InterruptedException | ExecutionException | TimeoutException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
});
|
|
}
|
|
|
|
public Uni<List<Long>> getAllHaveAdminAccess(SecurityCtx securityCtx) {
|
|
ArrayList<Long> out = new ArrayList<>();
|
|
|
|
Uni<HashMap<Long, String>> safca = cacheAccess.getAsync(securityCtx.getSubject(),
|
|
k -> competitionRepository.list("system = ?1", CompetitionSystem.SAFCA)
|
|
.chain(competitionModels -> {
|
|
CompletableFuture<HashMap<String, String>> f = new CompletableFuture<>();
|
|
SReqCompet.getAllHaveAccess(serverCustom.clients, securityCtx.getSubject(), f);
|
|
return Uni.createFrom().future(f, Duration.ofMillis(1500))
|
|
.map(map_ -> {
|
|
HashMap<Long, String> map = new HashMap<>();
|
|
map_.forEach((key, value) -> map.put(Long.parseLong(key), value));
|
|
|
|
for (CompetitionModel model : competitionModels) {
|
|
if (model.getOwner().equals(securityCtx.getSubject()))
|
|
map.putIfAbsent(model.getId(), "owner");
|
|
else if (securityCtx.roleHas("federation_admin")
|
|
|| securityCtx.roleHas("safca_super_admin"))
|
|
map.putIfAbsent(model.getId(), "admin");
|
|
}
|
|
return map;
|
|
});
|
|
}))
|
|
.onFailure().call(throwable -> cacheAccess.invalidate(securityCtx.getSubject()));
|
|
|
|
Uni<HashMap<Long, String>> none = cacheNoneAccess.getAsync(securityCtx.getSubject(),
|
|
k -> competitionRepository.list("system = ?1", CompetitionSystem.NONE)
|
|
.map(competitionModels -> {
|
|
HashMap<Long, String> map = new HashMap<>();
|
|
for (CompetitionModel model : competitionModels) {
|
|
if (model.getOwner().equals(securityCtx.getSubject()))
|
|
map.putIfAbsent(model.getId(), "owner");
|
|
else if (securityCtx.roleHas("federation_admin"))
|
|
map.putIfAbsent(model.getId(), "admin");
|
|
else if (securityCtx.isInClubGroup(model.getClub().getId()) && (securityCtx.roleHas(
|
|
"club_president")
|
|
|| securityCtx.roleHas("club_respo_intra") || securityCtx.roleHas(
|
|
"club_secretaire")
|
|
|| securityCtx.roleHas("club_tresorier")))
|
|
map.putIfAbsent(model.getId(), "admin");
|
|
}
|
|
return map;
|
|
}));
|
|
|
|
return safca.invoke(map ->
|
|
map.forEach((k, v) -> {
|
|
if (v.equals("owner") || v.equals("admin"))
|
|
out.add(k);
|
|
})
|
|
)
|
|
.call(__ -> none.invoke(map ->
|
|
map.forEach((k, v) -> {
|
|
if (v.equals("owner") || v.equals("admin"))
|
|
out.add(k);
|
|
})
|
|
))
|
|
.map(__ -> out.stream().distinct().toList());
|
|
}
|
|
|
|
|
|
/**
|
|
* @return {@link fr.titionfire.ffsaf.data.model.CompetitionModel} if securityCtx has view perm
|
|
*/
|
|
public Uni<CompetitionModel> hasViewPerm(SecurityCtx securityCtx, CompetitionModel competitionModel) {
|
|
return hasViewPerm(securityCtx, Uni.createFrom().item(competitionModel));
|
|
}
|
|
|
|
/**
|
|
* @return {@link fr.titionfire.ffsaf.data.model.CompetitionModel} if securityCtx has view perm
|
|
*/
|
|
public Uni<CompetitionModel> hasViewPerm(SecurityCtx securityCtx, long id) {
|
|
return hasViewPerm(securityCtx, competitionRepository.findById(id));
|
|
}
|
|
|
|
/**
|
|
* @return {@link fr.titionfire.ffsaf.data.model.CompetitionModel} if securityCtx has view perm
|
|
*/
|
|
public Uni<CompetitionModel> hasViewPerm(SecurityCtx securityCtx, Uni<CompetitionModel> in) {
|
|
return in.call(cm -> (cm.isPublicVisible() || cm.getRegisterMode() == RegisterMode.FREE
|
|
|| cm.getRegisterMode() == RegisterMode.HELLOASSO
|
|
|| (cm.getRegisterMode() == RegisterMode.CLUB_ADMIN && securityCtx.isClubAdmin())) ?
|
|
Uni.createFrom().nullItem() :
|
|
hasAdminViewPerm(securityCtx, cm).onFailure()
|
|
.recoverWithUni(__ ->
|
|
registerRepository.count("membre.userId = ?1 AND competition = ?2",
|
|
securityCtx.getSubject(), cm).map(Unchecked.function(c -> {
|
|
if (c == 0)
|
|
throw new DForbiddenException();
|
|
return cm;
|
|
}))
|
|
));
|
|
}
|
|
|
|
/**
|
|
* @return {@link fr.titionfire.ffsaf.data.model.CompetitionModel} if securityCtx has admin view perm
|
|
*/
|
|
public Uni<CompetitionModel> hasAdminViewPerm(SecurityCtx securityCtx, CompetitionModel competitionModel) {
|
|
return hasAdminViewPerm(securityCtx, Uni.createFrom().item(competitionModel));
|
|
}
|
|
|
|
/**
|
|
* @return {@link fr.titionfire.ffsaf.data.model.CompetitionModel} if securityCtx has admin view perm
|
|
*/
|
|
public Uni<CompetitionModel> hasAdminViewPerm(SecurityCtx securityCtx, long id) {
|
|
return hasAdminViewPerm(securityCtx, competitionRepository.findById(id));
|
|
}
|
|
|
|
/**
|
|
* @return {@link fr.titionfire.ffsaf.data.model.CompetitionModel} if securityCtx has admin view perm
|
|
*/
|
|
public Uni<CompetitionModel> hasAdminViewPerm(SecurityCtx securityCtx, Uni<CompetitionModel> in) {
|
|
return in.call(Unchecked.function(o -> {
|
|
if (securityCtx.getSubject().equals(o.getOwner()) || securityCtx.roleHas("federation_admin"))
|
|
return Uni.createFrom().nullItem();
|
|
|
|
if (o.getSystem() == CompetitionSystem.SAFCA)
|
|
return hasSafcaViewPerm(securityCtx, o.getId());
|
|
|
|
if (!securityCtx.isInClubGroup(o.getClub().getId())) // Only membre club pass here
|
|
throw new DForbiddenException();
|
|
|
|
if (o.getSystem() == CompetitionSystem.NONE)
|
|
if (securityCtx.roleHas("club_president") || securityCtx.roleHas("club_respo_intra")
|
|
|| securityCtx.roleHas("club_secretaire") || securityCtx.roleHas("club_tresorier"))
|
|
return Uni.createFrom().nullItem();
|
|
|
|
throw new DForbiddenException();
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @return {@link fr.titionfire.ffsaf.data.model.CompetitionModel} if securityCtx has edit perm
|
|
*/
|
|
public Uni<CompetitionModel> hasEditPerm(SecurityCtx securityCtx, CompetitionModel competitionModel) {
|
|
return hasEditPerm(securityCtx, Uni.createFrom().item(competitionModel));
|
|
}
|
|
|
|
/**
|
|
* @return {@link fr.titionfire.ffsaf.data.model.CompetitionModel} if securityCtx has edit perm
|
|
*/
|
|
public Uni<CompetitionModel> hasEditPerm(SecurityCtx securityCtx, long id) {
|
|
return hasEditPerm(securityCtx, competitionRepository.findById(id));
|
|
}
|
|
|
|
/**
|
|
* @return {@link fr.titionfire.ffsaf.data.model.CompetitionModel} if securityCtx has edit perm
|
|
*/
|
|
public Uni<CompetitionModel> hasEditPerm(SecurityCtx securityCtx, Uni<CompetitionModel> in) {
|
|
return in.call(Unchecked.function(o -> {
|
|
if (securityCtx.getSubject().equals(o.getOwner()) || securityCtx.roleHas("federation_admin"))
|
|
return Uni.createFrom().nullItem();
|
|
|
|
if (o.getSystem() == CompetitionSystem.SAFCA)
|
|
return hasSafcaEditPerm(securityCtx, o.getId());
|
|
|
|
if (!securityCtx.isInClubGroup(o.getClub().getId())) // Only membre club pass here
|
|
throw new DForbiddenException();
|
|
|
|
if (o.getSystem() == CompetitionSystem.NONE)
|
|
if (securityCtx.isClubAdmin())
|
|
return Uni.createFrom().nullItem();
|
|
|
|
throw new DForbiddenException();
|
|
})
|
|
);
|
|
}
|
|
|
|
private Uni<?> hasSafcaViewPerm(SecurityCtx securityCtx, long id) {
|
|
return securityCtx.roleHas("safca_super_admin") ?
|
|
Uni.createFrom().nullItem()
|
|
:
|
|
getSafcaConfig(id).chain(Unchecked.function(o -> {
|
|
if (!o.admin().contains(UUID.fromString(securityCtx.getSubject())) && !o.table()
|
|
.contains(UUID.fromString(securityCtx.getSubject())))
|
|
throw new DForbiddenException();
|
|
return Uni.createFrom().nullItem();
|
|
}));
|
|
}
|
|
|
|
private Uni<?> hasSafcaEditPerm(SecurityCtx securityCtx, long id) {
|
|
return securityCtx.roleHas("safca_super_admin") ?
|
|
Uni.createFrom().nullItem()
|
|
:
|
|
getSafcaConfig(id).chain(Unchecked.function(o -> {
|
|
if (!o.admin().contains(UUID.fromString(securityCtx.getSubject())))
|
|
throw new DForbiddenException();
|
|
return Uni.createFrom().nullItem();
|
|
}));
|
|
}
|
|
}
|