Skip to content

Commit

Permalink
Merge branch 'release/2024.02.27'
Browse files Browse the repository at this point in the history
  • Loading branch information
juliette-derancourt committed Feb 27, 2024
2 parents 1845e4d + 22fcf86 commit 976ad5e
Show file tree
Hide file tree
Showing 31 changed files with 455 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
"/api/application/fullPdf/**", "/api/tenant/property/**",
"/api/support/email",
"/api/stats/**",
"/api/onetimesecret/**",
"/actuator/health")
.permitAll()
.antMatchers("/api-partner/**").access("hasAuthority(\"SCOPE_api-partner\") && isClient()")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package fr.dossierfacile.api.front.controller;

import fr.dossierfacile.common.entity.OperationAccessToken;
import fr.dossierfacile.common.service.interfaces.OperationAccessTokenService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import static org.springframework.http.ResponseEntity.ok;

@RestController
@RequestMapping("/api/onetimesecret")
@RequiredArgsConstructor
@Slf4j
public class OneTimeSecretController {
private final OperationAccessTokenService operationAccessTokenService;

@GetMapping(value = "/{token}", produces = MediaType.TEXT_PLAIN_VALUE)
public ResponseEntity<String> displayContent(@PathVariable String token) {
OperationAccessToken operationAccessToken = operationAccessTokenService.findByToken(token);
String content = operationAccessToken.getContent();
operationAccessTokenService.delete(operationAccessToken);
return ok(content);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package fr.dossierfacile.api.front.dfc.controller;

import fr.dossierfacile.api.front.aop.annotation.MethodLogTime;
import fr.dossierfacile.api.front.mapper.PartnerSettingsMapper;
import fr.dossierfacile.api.front.model.dfc.PartnerSettings;
import fr.dossierfacile.api.front.security.interfaces.ClientAuthenticationFacade;
import fr.dossierfacile.api.front.service.interfaces.UserApiService;
import fr.dossierfacile.common.entity.UserApi;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import static org.springframework.http.ResponseEntity.ok;

@RestController
@AllArgsConstructor
@RequestMapping("/dfc/api/v1/settings")
@Slf4j
@MethodLogTime
public class DfcSettingsController {
private final ClientAuthenticationFacade clientAuthenticationFacade;
private UserApiService userApiService;
private PartnerSettingsMapper partnerSettingsMapper;

@ApiOperation(value = "Get current partner settings")
@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<PartnerSettings> get() {
UserApi userApi = clientAuthenticationFacade.getClient();
return ok(partnerSettingsMapper.toPartnerSettings(userApi));
}

@ApiOperation(value = "Update partner settings")
@PatchMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<PartnerSettings> update(@RequestBody PartnerSettings settings) {
UserApi userApi = clientAuthenticationFacade.getClient();
UserApi result = userApiService.update(userApi, settings);
return ok(partnerSettingsMapper.toPartnerSettings(result));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package fr.dossierfacile.api.front.mapper;

import fr.dossierfacile.api.front.model.dfc.PartnerSettings;
import fr.dossierfacile.common.entity.UserApi;
import org.mapstruct.Mapper;
import org.springframework.stereotype.Component;

@Component
@Mapper(componentModel = "spring")
public interface PartnerSettingsMapper {
PartnerSettings toPartnerSettings(UserApi userApi);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package fr.dossierfacile.api.front.model.dfc;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
public class PartnerSettings {
private String name;
private Integer version;
@JsonProperty("callbackUrl")
private String urlCallback;
@JsonProperty("callbackApiKey")
private String partnerApiKeyCallback;
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public ResponseEntity<TenantModel> documentIdentification(@Validated({ApiPartner

@PreAuthorize("hasPermissionOnTenant(#form.tenantId)")
@PostMapping("/documentCertificate")
public ResponseEntity<TenantModel> documentCertificate(@Validated({ApiPartner.class, DocumentGuaranteeProviderCertificateForm.class}) DocumentGuaranteeProviderCertificateForm form) {
public ResponseEntity<TenantModel> documentCertificate(@Validated({ApiPartner.class}) DocumentGuaranteeProviderCertificateForm form) {
var tenant = tenantService.findById(form.getTenantId());
var tenantModel = tenantService.saveStepRegister(tenant, form, StepRegister.DOCUMENT_GUARANTEE_PROVIDER_CERTIFICATE);
return ok(tenantModel);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,7 @@
import com.google.common.base.Strings;
import fr.dossierfacile.api.front.form.ContactForm;
import fr.dossierfacile.api.front.service.interfaces.MailService;
import fr.dossierfacile.common.entity.ConfirmationToken;
import fr.dossierfacile.common.entity.PasswordRecoveryToken;
import fr.dossierfacile.common.entity.Tenant;
import fr.dossierfacile.common.entity.User;
import fr.dossierfacile.common.entity.UserApi;
import fr.dossierfacile.common.entity.*;
import fr.dossierfacile.common.enums.ApplicationType;
import fr.dossierfacile.common.utils.OptionalString;
import io.sentry.Sentry;
Expand All @@ -24,6 +20,7 @@
import sibModel.SendSmtpEmailReplyTo;
import sibModel.SendSmtpEmailTo;

import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -68,6 +65,8 @@ public class MailServiceImpl implements MailService {
private Long templateEmailWhenTenantYESAssociatedToPartnersAndValidated;
@Value("${sendinblue.template.id.contact.support}")
private Long templateIdContactSupport;
@Value("${sendinblue.template.id.token.expiration}")
private Long templateIdTokenExpiration;
@Value("${link.after.completed.default}")
private String defaultCompletedUrl;
@Value("${link.after.created.default}")
Expand Down Expand Up @@ -303,6 +302,27 @@ public void sendEmailPartnerAccessRevoked(Tenant receiver, UserApi userApi, Tena
sendEmailToTenant(receiver, variables, templateIDPartnerAccessRevoked);
}

@Override
public void sendDefaultEmailExpiredToken(String email, OperationAccessToken token) {
SendSmtpEmailTo sendSmtpEmailTo = new SendSmtpEmailTo();
sendSmtpEmailTo.setEmail(email);

Map<String, String> params = new HashMap<>();
params.put("operation", token.getOperationAccessType().name());
params.put("createdDate", token.getCreatedDate().format(DateTimeFormatter.ISO_DATE));

SendSmtpEmail sendSmtpEmail = new SendSmtpEmail();
sendSmtpEmail.templateId(templateIdTokenExpiration);
sendSmtpEmail.params(params);
sendSmtpEmail.to(Collections.singletonList(sendSmtpEmailTo));

try {
apiInstance.sendTransacEmail(sendSmtpEmail);
} catch (ApiException e) {
log.error("Email Api Exception" + Sentry.captureException(e), e);
}
}

private record RevocationRequest(Tenant requester, Tenant emailReceiver) {

String getOrigin() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
import fr.dossierfacile.api.front.service.interfaces.ScheduledTasksService;
import fr.dossierfacile.api.front.service.interfaces.StatsService;
import fr.dossierfacile.common.entity.ConfirmationToken;
import fr.dossierfacile.common.entity.OperationAccessToken;
import fr.dossierfacile.common.entity.Tenant;
import fr.dossierfacile.common.enums.ApplicationType;
import fr.dossierfacile.common.enums.TenantFileStatus;
import fr.dossierfacile.common.repository.ConfirmationTokenRepository;
import fr.dossierfacile.common.repository.TenantCommonRepository;
import fr.dossierfacile.common.service.interfaces.OperationAccessTokenService;
import io.sentry.Sentry;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -32,6 +34,7 @@
public class ScheduledTasksServiceImpl implements ScheduledTasksService {
private final TenantCommonRepository tenantRepository;
private final ConfirmationTokenRepository confirmationTokenRepository;
private final OperationAccessTokenService operationAccessTokenService;
private final MailService mailService;
private final StatsService statsService;
private final Object sendEmailLock = new Object();
Expand Down Expand Up @@ -146,4 +149,20 @@ public void satisfactionEmails() {
public void updateStats() {
statsService.updateStats();
}

@Scheduled(cron = "0 0 * * * *")
@Override
public void updateOperationAccessTokenStatus() {
synchronized (sendEmailLock) {
List<OperationAccessToken> tokens = operationAccessTokenService.findExpiredToken();
log.info(tokens.size() + " expired tokens found - delete the tokens and send notification");
for (OperationAccessToken token : tokens) {
if (StringUtils.isNotBlank(token.getEmail())) {
mailService.sendDefaultEmailExpiredToken(token.getEmail(), token);
}
operationAccessTokenService.delete(token);
}
}
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package fr.dossierfacile.api.front.service;

import fr.dossierfacile.api.front.exception.UserApiNotFoundException;
import fr.dossierfacile.api.front.model.dfc.PartnerSettings;
import fr.dossierfacile.api.front.repository.UserApiRepository;
import fr.dossierfacile.api.front.service.interfaces.UserApiService;
import fr.dossierfacile.common.entity.Tenant;
Expand All @@ -9,6 +10,7 @@
import fr.dossierfacile.common.repository.TenantUserApiRepository;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;
Expand All @@ -25,14 +27,34 @@ public UserApi findById(Long id) {
return userApiRepository.findById(id)
.orElseThrow(() -> new UserApiNotFoundException(id));
}

@Override
public Optional<UserApi> findByName(String partner) {
return userApiRepository.findByName(partner);
}

@Override
public boolean anyTenantIsLinked(UserApi partner, List<Tenant> tenants) {
Optional<TenantUserApi> result = tenantUserApiRepository.findFirstByUserApiAndTenantIn(partner, tenants);
return result.isPresent();
}

@Transactional
@Override
public UserApi update(UserApi userApiParam, PartnerSettings settings) {
UserApi userApi = userApiRepository.findById(userApiParam.getId()).get();

if (settings.getVersion() != null) {
userApi.setVersion(settings.getVersion());
}
if (settings.getUrlCallback() != null) {
userApi.setUrlCallback(settings.getUrlCallback());
}
if (settings.getPartnerApiKeyCallback() != null) {
userApi.setPartnerApiKeyCallback(settings.getPartnerApiKeyCallback());
}
userApiRepository.save(userApi);

return userApi;
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
package fr.dossierfacile.api.front.service.interfaces;

import fr.dossierfacile.api.front.form.ContactForm;
import fr.dossierfacile.common.entity.ConfirmationToken;
import fr.dossierfacile.common.entity.PasswordRecoveryToken;
import fr.dossierfacile.common.entity.Tenant;
import fr.dossierfacile.common.entity.User;
import fr.dossierfacile.common.entity.UserApi;
import fr.dossierfacile.common.entity.*;
import fr.dossierfacile.common.enums.ApplicationType;

public interface MailService {
Expand Down Expand Up @@ -37,4 +33,5 @@ public interface MailService {

void sendEmailPartnerAccessRevoked(Tenant receiver, UserApi userApi, Tenant revocationRequester);

void sendDefaultEmailExpiredToken(String email, OperationAccessToken token);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@
public interface ScheduledTasksService {

void emailAccountValidationReminder();

void accountCompletionReminder();

void accountDeclinationReminder();

void satisfactionEmails();

void updateOperationAccessTokenStatus();
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package fr.dossierfacile.api.front.service.interfaces;

import fr.dossierfacile.api.front.model.dfc.PartnerSettings;
import fr.dossierfacile.common.entity.Tenant;
import fr.dossierfacile.common.entity.UserApi;

Expand All @@ -10,4 +11,5 @@ public interface UserApiService {
UserApi findById(Long id);
Optional<UserApi> findByName(String partner);
boolean anyTenantIsLinked(UserApi partner, List<Tenant> tenants);
UserApi update(UserApi userApi, PartnerSettings settings);
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,6 @@ springdoc.api-docs.groups.enabled=true
application.name=api-tenant
environment=


sendinblue.template.id.token.expiration=109

Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import fr.dossierfacile.common.enums.ApplicationType;
import fr.dossierfacile.common.repository.ConfirmationTokenRepository;
import fr.dossierfacile.common.repository.TenantCommonRepository;
import fr.dossierfacile.common.service.interfaces.OperationAccessTokenService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;
Expand All @@ -26,8 +27,9 @@ class ScheduledTasksServiceImplTest {
private final ConfirmationTokenRepository confirmationTokenRepository = mock(ConfirmationTokenRepository.class);
private final MailService mailService = mock(MailService.class);
private final StatsService statsService = mock(StatsService.class);
private final OperationAccessTokenService operationAccessTokenService = mock(OperationAccessTokenService.class);
private final ScheduledTasksService scheduledTasksService =
new ScheduledTasksServiceImpl(tenantRepository, confirmationTokenRepository, mailService, statsService);
new ScheduledTasksServiceImpl(tenantRepository, confirmationTokenRepository, operationAccessTokenService, mailService, statsService);

@BeforeEach
void beforEach() {
Expand Down
Loading

0 comments on commit 976ad5e

Please sign in to comment.