Skip to content

Commit

Permalink
Merge pull request #850 from navikt/div_fix
Browse files Browse the repository at this point in the history
Div. overhaling
  • Loading branch information
farjamm authored Jul 5, 2024
2 parents 9fe1604 + c39ba05 commit 4f89dd4
Show file tree
Hide file tree
Showing 102 changed files with 1,077 additions and 806 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
@Tag(name = "Audit")
@RequiredArgsConstructor
public class AuditController {

// TODO: Implementerer ikke controller → service → DB. Flytt all forretningslogikk og *Repository-aksess til tjenestelaget.

private final AuditVersionRepository repository;
private final StorageService storage;
Expand All @@ -52,9 +54,9 @@ public ResponseEntity<RestResponsePage<AuditResponse>> getAll(PageParameters pag
Pageable pageable = paging.createSortedPageByFieldDescending(AuditVersion.Fields.time);
Page<AuditResponse> page;
if (table != null) {
page = repository.findAll(exampleFrom(AuditVersion.builder().table(table).build()), pageable).map(AuditVersion::convertToResponse);
page = repository.findAll(exampleFrom(AuditVersion.builder().table(table).build()), pageable).map(AuditResponse::buildFrom);
} else {
page = repository.findAll(pageable).map(AuditVersion::convertToResponse);
page = repository.findAll(pageable).map(AuditResponse::buildFrom);
}
return new ResponseEntity<>(new RestResponsePage<>(page), HttpStatus.OK);
}
Expand All @@ -65,7 +67,7 @@ public ResponseEntity<RestResponsePage<AuditResponse>> getAll(PageParameters pag
public ResponseEntity<AuditLogResponse> findForId(@PathVariable String id) {
log.info("Received request for Audit with the id={}", id);
List<AuditVersion> log = repository.findByTableIdOrderByTimeDesc(id);
return new ResponseEntity<>(new AuditLogResponse(id, convert(log, AuditVersion::convertToResponse)), HttpStatus.OK);
return new ResponseEntity<>(new AuditLogResponse(id, convert(log, AuditResponse::buildFrom)), HttpStatus.OK);
}

@Operation(summary = "Get mail log")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
package no.nav.data.common.auditing;

import lombok.RequiredArgsConstructor;
import no.nav.data.common.auditing.domain.AuditVersionRepository;
import no.nav.data.common.auditing.dto.AuditMetadata;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@RequiredArgsConstructor
public class AuditService {

private final AuditVersionRepository auditVersionRepository;

public AuditService(AuditVersionRepository auditVersionRepository) {
this.auditVersionRepository = auditVersionRepository;
}

public List<AuditMetadata> lastEditedProcessesByUser(String user) {
return auditVersionRepository.getLastChangedProcessesByUser(user, 20);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import no.nav.data.common.utils.MdcUtils;
import no.nav.data.polly.codelist.domain.Codelist;
import org.hibernate.proxy.HibernateProxy;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.Optional;
Expand All @@ -33,7 +35,11 @@
@Slf4j
public class AuditVersionListener {

private static AuditVersionRepository repository;
// Merk: Denne klassen er IKKE håndtert av Spring (siden den instansieres av JPA), men den avhenger av en Spring-managed bønne.
// Dette er løst med et hæck der Spring kaller en statisk metode i denne klassen for å tilby bønna.
// Men dette hacket virker ikke alltid for integrasjonstesting, så det er et hæck til i IntegrationTestBase for å få det til å gå.

private static volatile AuditVersionRepository repository;

private static final ObjectWriter wr;

Expand Down Expand Up @@ -64,16 +70,17 @@ public void preRemove(Object entity) {
audit(entity, Action.DELETE);
}

@Transactional(propagation = Propagation.MANDATORY)
private void audit(Object entity, Action action) {
try {
Assert.isTrue(entity instanceof Auditable, "Invalid object");
if (entity instanceof GenericStorage && !((GenericStorage) entity).getType().isAudit()) {
if (entity instanceof GenericStorage genStorage && !genStorage.getType().isAudit()) {
return;
}
String tableName = AuditVersion.tableName(((Auditable) entity).getClass());
String id = getIdForObject(entity);
String data = wr.writeValueAsString(entity);
String user = Optional.ofNullable(MdcUtils.getUser()).orElse("no user set");
String user = Optional.ofNullable(MdcUtils.getUser()).orElse("no-user-set");
AuditVersion auditVersion = AuditVersion.builder()
.action(action).table(tableName).tableId(id).data(data).user(user)
.build();
Expand All @@ -85,8 +92,8 @@ private void audit(Object entity, Action action) {

public static String getIdForObject(Object entity) {
String id;
if (entity instanceof Codelist) {
id = ((Codelist) entity).getList() + "-" + ((Codelist) entity).getCode();
if (entity instanceof Codelist clEntity) {
id = clEntity.getList() + "-" + clEntity.getCode();
} else {
UUID uuid = HibernateUtils.getId(entity);
Assert.notNull(uuid, "entity has not set id");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,18 +67,7 @@ public class AuditVersion {
@Column(name = "DATA", nullable = false, updatable = false)
private String data;

public AuditResponse convertToResponse() {
return AuditResponse.builder()
.id(id.toString())
.action(action)
.table(table)
.tableId(tableId)
.time(time)
.user(user)
.data(JsonUtils.toJsonNode(data))
.build();
}

// TODO: Snu avhengigheten innover (ikke triviell). Flytt all forretningslogikk i domeneklassen ut til tjenestelaget.
public EventResponse convertToEventResponse() {
return EventResponse.builder()
.id(id.toString())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,29 +24,30 @@ static Example<AuditVersion> exampleFrom(AuditVersion example) {

@Query(value = """
select * from audit_version av
where table_name = ?1 and action = ?2
where table_name = ?1 and action = ?2
and (?2 = 'DELETE' or not exists (select 1 from audit_version av2 where av2.table_id = av.table_id and av2.action = 'DELETE'))
""",
countQuery = """
select count(1) from audit_version av
where table_name = ?1 and action = ?2
and (?2 = 'DELETE' or not exists (select 1 from audit_version av2 where av2.table_id = av.table_id and av2.action = 'DELETE'))
""", nativeQuery = true)
""",
countQuery = """
select count(1) from audit_version av
where table_name = ?1 and action = ?2
and (?2 = 'DELETE' or not exists (select 1 from audit_version av2 where av2.table_id = av.table_id and av2.action = 'DELETE'))
""",
nativeQuery = true)
Page<AuditVersion> findForTableAndAction(String table, String action, Pageable page);

@Query(value = """
select cast(audit_id as text) as id, time, action, table_name as tableName, table_id as tableId
from audit_version where audit_id in (
select distinct on (table_id) audit_id
from audit_version
where table_name = 'PROCESS'
and user_id = ?1
and exists (select 1 from process where process_id = cast(table_id as uuid))
order by table_id, time desc
)
order by time desc
limit ?2
""", nativeQuery = true)
from audit_version where audit_id in (
select distinct on (table_id) audit_id
from audit_version
where table_name = 'PROCESS'
and user_id = ?1
and exists (select 1 from process where process_id = cast(table_id as uuid))
order by table_id, time desc
)
order by time desc
limit ?2
""", nativeQuery = true)
List<AuditMetadata> getLastChangedProcessesByUser(String userId, int limit);

}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public abstract class Auditable {
@Column(name = "LAST_MODIFIED_DATE")
protected LocalDateTime lastModifiedDate;

// TODO: Snu avhengigheten innover
public ChangeStampResponse convertChangeStampResponse() {
return ChangeStampResponse.builder()
.lastModifiedBy(getLastModifiedBy())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@

public interface MailLogRepository extends JpaRepository<GenericStorage, UUID> {

@Override
@Query(value = "select * from generic_storage where type = 'MAIL_LOG' order by created_date desc",
countQuery = "select count(1) from generic_storage where type = 'MAIL_LOG'"
, nativeQuery = true)
countQuery = "select count(1) from generic_storage where type = 'MAIL_LOG'",
nativeQuery = true)
Page<GenericStorage> findAll(Pageable pageable);

@Query(value = "select * from generic_storage where type = 'MAIL_LOG' and data ->> 'to' = ?1 order by created_date desc", nativeQuery = true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import lombok.Data;
import lombok.NoArgsConstructor;
import no.nav.data.common.auditing.domain.Action;
import no.nav.data.common.auditing.domain.AuditVersion;
import no.nav.data.common.utils.JsonUtils;

import java.time.LocalDateTime;

Expand All @@ -25,4 +27,16 @@ public class AuditResponse {
private String user;
private JsonNode data;

public static AuditResponse buildFrom(AuditVersion av) {
return AuditResponse.builder()
.id(av.getId().toString())
.action(av.getAction())
.table(av.getTable())
.tableId(av.getTableId())
.time(av.getTime())
.user(av.getUser())
.data(JsonUtils.toJsonNode(av.getData()))
.build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import no.nav.data.common.auditing.domain.Action;
import no.nav.data.common.auditing.domain.AuditVersion;
Expand All @@ -21,6 +22,7 @@
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
Expand All @@ -31,20 +33,19 @@
import static no.nav.data.common.utils.StreamUtils.convert;

@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping("/event")
@Tag(name = "Event", description = "Domain object events")
public class EventController {

// TODO: Implementerer ikke controller → service → DB. Flytt all forretningslogikk, *Repository-aksess og @Transactional til tjenestelaget.

private final AuditVersionRepository repository;
private final List<String> allowedTables = convert(
List.of(InformationType.class, Process.class, Policy.class, Disclosure.class, Document.class),
AuditVersion::tableName);

public EventController(AuditVersionRepository repository) {
this.repository = repository;
}

@Operation(summary = "Get events")
@ApiResponse(description = "Events fetched")
@GetMapping
Expand All @@ -63,7 +64,6 @@ private void validateTable(String table) {
}

static class EventPage extends RestResponsePage<EventResponse> {

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

import no.nav.data.common.security.SecurityProperties;
import no.nav.data.common.storage.StorageService;
import no.nav.data.common.storage.domain.GenericStorage;
import no.nav.data.common.storage.domain.GenericStorageRepository;
import no.nav.data.common.storage.domain.StorageType;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class EmailServiceImpl implements EmailService {
Expand All @@ -30,17 +32,21 @@ public void sendMail(MailTask mailTask) {
}

@Override
@Transactional
public void scheduleMail(MailTask mailTask) {
storage.save(mailTask);
}

@Scheduled(initialDelayString = "PT3M", fixedRateString = "PT5M")
public void sendMails() {
var tasks = storageRepository.findAllByType(StorageType.MAIL_TASK);

tasks.forEach(task -> {
sendMail(task.getDataObject(MailTask.class));
storageRepository.delete(task);
});
tasks.forEach(this::sendMailAndDeleteTask);
}

@Transactional // Viktig med en transaksjon per mail, slik at ikke allerede sendte mails blir rullet tilbake til repo ved feil
private void sendMailAndDeleteTask(GenericStorage task) {
storageRepository.delete(task);
sendMail(task.getDataObject(MailTask.class));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import no.nav.data.common.auditing.domain.Auditable;
import no.nav.data.common.auditing.domain.Auditable.Fields;

import java.time.LocalDateTime;
Expand All @@ -19,4 +20,13 @@ public class ChangeStampResponse {
private String lastModifiedBy;
private LocalDateTime lastModifiedDate;
private LocalDateTime createdDate;

public static ChangeStampResponse from(Auditable auditable) {
return ChangeStampResponse.builder()
.lastModifiedBy(auditable.getLastModifiedBy())
.lastModifiedDate(auditable.getLastModifiedDate() == null ? LocalDateTime.now() : auditable.getLastModifiedDate())
.createdDate(auditable.getCreatedDate())
.build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ public Collection<String> getIds() {

@Data
static class AuthApps {

private String name;
private String clientId;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ private ConfigurableJWTProcessor<SecurityContext> getAadJwtTokenValidator(JWSAlg
new JWSVerificationKeySelector<>(jwsAlgorithm, keySource);
jwtProcessor.setJWSKeySelector(keySelector);

jwtProcessor.setJWTClaimsSetVerifier(new DefaultJWTClaimsVerifier<>() {
jwtProcessor.setJWTClaimsSetVerifier(new DefaultJWTClaimsVerifier<>(null, null) {
@Override
public void verify(JWTClaimsSet claimsSet, SecurityContext ctx) throws BadJWTException {
super.verify(claimsSet, ctx);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,33 @@

import com.microsoft.graph.serviceclient.GraphServiceClient;
import com.microsoft.graph.users.item.sendmail.SendMailPostRequestBody;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import no.nav.data.common.mail.EmailProvider;
import no.nav.data.common.mail.MailTask;
import no.nav.data.common.storage.StorageService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import static no.nav.data.common.security.azure.support.MailMessage.compose;

@Slf4j
@Service
@RequiredArgsConstructor
public class AzureAdService implements EmailProvider {

private final AzureTokenProvider azureTokenProvider;
private final StorageService storage;

public AzureAdService(AzureTokenProvider azureTokenProvider, StorageService storage) {
this.azureTokenProvider = azureTokenProvider;
this.storage = storage;
}

@Override
@Transactional
public void sendMail(MailTask mailTask) {
log.info("sending mail {} to {}", mailTask.getSubject(), mailTask.getTo());
SendMailPostRequestBody sendMailPostRequestBody = new SendMailPostRequestBody();
sendMailPostRequestBody.setMessage(compose(mailTask.getTo(), mailTask.getSubject(), mailTask.getBody()));
sendMailPostRequestBody.setSaveToSentItems(true);

getMailGraphClient().me().sendMail().post(sendMailPostRequestBody);

storage.save(mailTask.toMailLog());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ public static UserInfoResponse noUser(boolean securityEnabled) {
return responseBuilder.build();
}

@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
public static class UserInfoResponseBuilder {

private List<String> groups = new ArrayList<>();
Expand Down
Loading

0 comments on commit 4f89dd4

Please sign in to comment.