Skip to content

Commit

Permalink
feat(tenant): Update partner synchronization endpoints to return revo…
Browse files Browse the repository at this point in the history
…ked accesses if asked (#675)
  • Loading branch information
juliette-derancourt authored Dec 20, 2023
1 parent 8d48441 commit 469f5e7
Show file tree
Hide file tree
Showing 10 changed files with 157 additions and 35 deletions.
4 changes: 4 additions & 0 deletions dossierfacile-api-tenant/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,10 @@
<artifactId>logstash-logback-encoder</artifactId>
<version>7.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.UriComponentsBuilder;

import java.time.LocalDateTime;
import java.util.List;
Expand All @@ -46,13 +47,21 @@ public class DfcTenantsController {
@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<ResponseWrapper<List<TenantUpdate>, ListMetadata>> list(@RequestParam(value = "after", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime after,
@RequestParam(value = "limit", defaultValue = "1000") Long limit,
@RequestParam(value = "includeDeleted", defaultValue = "false") boolean includeDeleted
@RequestParam(value = "includeDeleted", defaultValue = "false") boolean includeDeleted,
@RequestParam(value = "includeRevoked", defaultValue = "false") boolean includeRevoked
) {
UserApi userApi = clientAuthenticationFacade.getClient();
List<TenantUpdate> result = tenantService.findTenantUpdateByLastUpdateAndPartner(after, userApi, limit, includeDeleted);
LocalDateTime nextTimeToken = (result.size() == 0) ? after : result.get(result.size() - 1).getLastUpdateDate();
List<TenantUpdate> result = tenantService.findTenantUpdateByLastUpdateAndPartner(after, userApi, limit, includeDeleted, includeRevoked);

LocalDateTime nextTimeToken = result.isEmpty() ? after : result.get(result.size() - 1).getLastUpdateDate();

String nextLink = UriComponentsBuilder.fromPath(PATH)
.queryParam("limit", limit)
.queryParam("after", nextTimeToken)
.queryParam("includeDeleted", includeDeleted)
.queryParam("includeRevoked", includeRevoked)
.build().encode().toUriString();

String nextLink = PATH + "?limit=" + limit + "&after=" + nextTimeToken + "&includeDeleted=" + includeDeleted;
return ok(ResponseWrapper.<List<TenantUpdate>, ListMetadata>builder()
.metadata(ListMetadata.builder()
.limit(limit)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.UriComponentsBuilder;

import java.time.LocalDateTime;
import java.util.List;
Expand All @@ -46,27 +47,36 @@ public class ApiPartnerTenantController {
public ResponseEntity<ResponseWrapper<List<TenantUpdate>, ListMetadata>> list(@RequestParam(value = "after", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime after,
@RequestParam(value = "limit", defaultValue = "1000") Long limit,
@RequestParam(value = "orderBy", defaultValue = "LAST_UPDATE_DATE") TenantSortType orderBy,
@RequestParam(value = "includeDeleted", defaultValue = "false") boolean includeDeleted
@RequestParam(value = "includeDeleted", defaultValue = "false") boolean includeDeleted,
@RequestParam(value = "includeRevoked", defaultValue = "false") boolean includeRevoked
) {
System.out.println("after = " + after);
UserApi userApi = clientAuthenticationFacade.getClient();
List<TenantUpdate> result;
LocalDateTime nextTimeToken;
switch (orderBy) {
case CREATION_DATE -> {
if (includeDeleted){
throw new IllegalArgumentException("includeDelete is not available with creationDate order");
if (includeDeleted || includeRevoked) {
throw new IllegalArgumentException("includeDelete and includeRevoked are not available with creationDate order");
}
result = tenantService.findTenantUpdateByCreatedAndPartner(after, userApi, limit);
nextTimeToken = (result.size() == 0) ? after : result.get(result.size() - 1).getCreationDate();
nextTimeToken = result.isEmpty() ? after : result.get(result.size() - 1).getCreationDate();
}
case LAST_UPDATE_DATE -> {
result = tenantService.findTenantUpdateByLastUpdateAndPartner(after, userApi, limit, includeDeleted);
nextTimeToken = (result.size() == 0) ? after : result.get(result.size() - 1).getLastUpdateDate();
result = tenantService.findTenantUpdateByLastUpdateAndPartner(after, userApi, limit, includeDeleted, includeRevoked);
nextTimeToken = result.isEmpty() ? after : result.get(result.size() - 1).getLastUpdateDate();
}
default -> throw new IllegalArgumentException();
}

String nextLink = "/api-partner/tenant?limit=" + limit + "&orderBy=" + orderBy + "&after=" + nextTimeToken + "&includeDeleted=" + includeDeleted;
String nextLink = UriComponentsBuilder.fromPath("/api-partner/tenant")
.queryParam("limit", limit)
.queryParam("orderBy", orderBy)
.queryParam("after", nextTimeToken)
.queryParam("includeDeleted", includeDeleted)
.queryParam("includeRevoked", includeRevoked)
.build().encode().toUriString();

return ok(ResponseWrapper.<List<TenantUpdate>, ListMetadata>builder()
.metadata(ListMetadata.builder()
.limit(limit)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@
import fr.dossierfacile.common.entity.Tenant;
import fr.dossierfacile.common.entity.TenantUserApi;
import fr.dossierfacile.common.entity.UserApi;
import fr.dossierfacile.common.repository.TenantCommonRepository;
import fr.dossierfacile.common.repository.TenantUserApiRepository;
import fr.dossierfacile.common.service.interfaces.LogService;
import fr.dossierfacile.common.service.interfaces.PartnerCallBackService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

@Slf4j
Expand All @@ -26,6 +28,7 @@ public class PartnerAccessServiceImpl implements PartnerAccessService {

private final TenantUserApiRepository tenantUserApiRepository;
private final PartnerCallBackService partnerCallBackService;
private final TenantCommonRepository tenantRepository;
private final PartnerAccessMapper partnerAccessMapper;
private final KeycloakService keycloakService;
private final MailService mailService;
Expand All @@ -46,8 +49,10 @@ public void deleteAccess(Tenant tenant, Long userApiId) {
}

private void deleteAccess(TenantUserApi tenantUserApi) {
Tenant tenant = tenantUserApi.getTenant();
UserApi userApi = tenantUserApi.getUserApi();
Tenant tenant = tenantUserApi.getTenant();
tenant.setLastUpdateDate(LocalDateTime.now());
tenantRepository.save(tenant);

tenantUserApiRepository.delete(tenantUserApi);
partnerCallBackService.sendRevokedAccessCallback(tenant, userApi);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,8 @@ public List<TenantUpdate> findTenantUpdateByCreatedAndPartner(LocalDateTime from
}

@Override
public List<TenantUpdate> findTenantUpdateByLastUpdateAndPartner(LocalDateTime since, UserApi userApi, Long limit, boolean includeDeleted) {
return includeDeleted? tenantRepository.findTenantUpdateWithDeletedByLastUpdateAndPartner(since, userApi.getId(), limit) :
tenantRepository.findTenantUpdateByLastUpdateAndPartner(since, userApi.getId(), limit);
public List<TenantUpdate> findTenantUpdateByLastUpdateAndPartner(LocalDateTime since, UserApi userApi, Long limit, boolean includeDeleted, boolean includeRevoked) {
return tenantRepository.findTenantUpdateByLastUpdateAndPartner(since, userApi.getId(), limit, includeDeleted, includeRevoked);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public interface TenantService {

List<TenantUpdate> findTenantUpdateByCreatedAndPartner(LocalDateTime from, UserApi userApi, Long limit);

List<TenantUpdate> findTenantUpdateByLastUpdateAndPartner(LocalDateTime from, UserApi userApi, Long limit, boolean includeDeleted);
List<TenantUpdate> findTenantUpdateByLastUpdateAndPartner(LocalDateTime from, UserApi userApi, Long limit, boolean includeDeleted, boolean includeRevoked);

void sendFileByMail(Tenant tenant, String email, String shareType);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package fr.dossierfacile.api.front.dfc.controller;

import fr.dossierfacile.api.front.security.interfaces.ClientAuthenticationFacade;
import fr.dossierfacile.api.front.service.interfaces.TenantService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

class DfcTenantsControllerTest {

private MockMvc mvc;

@BeforeEach
public void setUp() {
var controller = new DfcTenantsController(mock(ClientAuthenticationFacade.class), mock(TenantService.class), null, null);
mvc = MockMvcBuilders.standaloneSetup(controller).build();
}

@Test
void should_add_response_metadata() throws Exception {
var request = get("/dfc/api/v1/tenants")
.queryParam("after", "2020-01-31T10:30:00.000-05:00")
.queryParam("limit", "10")
.queryParam("includeDeleted", "true");

String contentAsString = mvc.perform(request)
.andExpect(status().isOk())
.andReturn()
.getResponse().getContentAsString();

assertThat(contentAsString).isEqualToIgnoringNewLines("""
{"data":[],"metadata":{"limit":10,"resultCount":0,"nextLink":"/dfc/api/v1/tenants?limit=10&after=2020-01-31T10:30&includeDeleted=true&includeRevoked=false"}}""");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package fr.dossierfacile.api.front.partner.controller;

import fr.dossierfacile.api.front.security.interfaces.ClientAuthenticationFacade;
import fr.dossierfacile.api.front.service.interfaces.TenantService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;

import java.time.LocalDateTime;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

class ApiPartnerTenantControllerTest {

private MockMvc mvc;

@BeforeEach
public void setUp() {
var controller = new ApiPartnerTenantController(mock(ClientAuthenticationFacade.class), mock(TenantService.class), null, null);
mvc = MockMvcBuilders.standaloneSetup(controller).build();
}

@Test
void should_add_response_metadata() throws Exception {
var request = get("/api-partner/tenant")
.queryParam("after", "2020-01-31T10:30:00.000-05:00")
.queryParam("limit", "10")
.queryParam("includeDeleted", "true");

String contentAsString = mvc.perform(request)
.andExpect(status().isOk())
.andReturn()
.getResponse().getContentAsString();

assertThat(contentAsString).isEqualToIgnoringNewLines("""
{"data":[],"metadata":{"limit":10,"resultCount":0,"nextLink":"/api-partner/tenant?limit=10&orderBy=LAST_UPDATE_DATE&after=2020-01-31T10:30&includeDeleted=true&includeRevoked=false"}}""");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ public interface TenantUpdate {
LocalDateTime getLastUpdateDate();
LocalDateTime getCreationDate();
LocalDateTime getDeletionDate();
LocalDateTime getRevocationDate();
}
Original file line number Diff line number Diff line change
Expand Up @@ -215,20 +215,39 @@ SELECT COUNT(t.id)
@Query(value = """
SELECT * FROM (
SELECT tenant_id as id,
null as apartmentSharingId,
null as lastUpdateDate,
null as creationDate,
creation_date as deletionDate
CAST(null AS bigint) as apartmentSharingId,
CAST(null AS timestamp) as lastUpdateDate,
CAST(null AS timestamp) as creationDate,
creation_date as deletionDate,
CAST(null AS timestamp) as revocationDate
FROM tenant_log
WHERE (CAST(CAST(:lastUpdateFrom AS text) AS timestamp) IS NULL
OR creation_date > CAST(CAST(:lastUpdateFrom AS text) AS timestamp))
AND log_type = 'ACCOUNT_DELETE'
AND :partnerId = ANY (user_apis)
AND :includeDeleted
UNION
(SELECT tenant_id as id,
CAST(null AS bigint) as apartmentSharingId,
CAST(null AS timestamp) as lastUpdateDate,
CAST(null AS timestamp) as creationDate,
CAST(null AS timestamp) as deletionDate,
creation_date as revocationDate
FROM tenant_log tl
WHERE (CAST(CAST(:lastUpdateFrom AS text) AS timestamp) IS NULL
OR creation_date > CAST(CAST(:lastUpdateFrom AS text) AS timestamp))
AND log_type = 'PARTNER_ACCESS_REVOKED'
AND :partnerId = ANY (user_apis)
AND NOT EXISTS (SELECT 1 FROM tenant_userapi tua WHERE tua.tenant_id = tl.tenant_id AND tua.userapi_id = :partnerId)
AND :includeRevoked
ORDER BY revocationDate DESC LIMIT 1)
UNION
SELECT t.id as id,
t.apartment_sharing_id as apartmentSharingId,
t.last_update_date as lastUpdateDate,
ua.creation_date as creationDate,
null as deletionDate
CAST(null AS timestamp) as deletionDate,
CAST(null AS timestamp) as revocationDate
FROM tenant t
INNER JOIN user_account ua ON ua.id = t.id
INNER JOIN tenant_userapi tua ON tua.tenant_id = t.id
Expand All @@ -238,20 +257,10 @@ OR creation_date > CAST(CAST(:lastUpdateFrom AS text) AS timestamp))
ORDER BY lastUpdateDate ASC
LIMIT :limit
""", nativeQuery = true)
List<TenantUpdate> findTenantUpdateWithDeletedByLastUpdateAndPartner(@Param("lastUpdateFrom") LocalDateTime from, @Param("partnerId") Long id, @Param("limit") Long limit);

@Query(value = """
SELECT t.id as id, t.apartment_sharing_id as apartmentSharingId, t.last_update_date as lastUpdateDate, ua.creation_date as creationDate
FROM tenant t
INNER JOIN user_account ua ON ua.id = t.id
INNER JOIN tenant_userapi tua ON tua.tenant_id = t.id
WHERE tua.userapi_id = :partnerId
AND ( CAST( CAST(:lastUpdateFrom AS text) AS timestamp) IS NULL OR t.last_update_date > CAST( CAST(:lastUpdateFrom AS text) AS timestamp))
ORDER BY t.last_update_date ASC
LIMIT :limit
""", nativeQuery = true
)
List<TenantUpdate> findTenantUpdateByLastUpdateAndPartner(@Param("lastUpdateFrom") LocalDateTime from, @Param("partnerId") Long id, @Param("limit") Long limit);
List<TenantUpdate> findTenantUpdateByLastUpdateAndPartner(@Param("lastUpdateFrom") LocalDateTime from,
@Param("partnerId") Long id, @Param("limit") Long limit,
@Param("includeDeleted") boolean includeDeleted,
@Param("includeRevoked") boolean includeRevoked);

@Query(value = """
SELECT t.id as id, t.apartment_sharing_id as apartmentSharingId, t.last_update_date as lastUpdateDate, ua.creation_date as creationDate
Expand Down

0 comments on commit 469f5e7

Please sign in to comment.