diff --git a/gradle/changelog/delete_for_audit_log.yaml b/gradle/changelog/delete_for_audit_log.yaml new file mode 100644 index 0000000000..0812599746 --- /dev/null +++ b/gradle/changelog/delete_for_audit_log.yaml @@ -0,0 +1,2 @@ +- type: fixed + description: Implement delete for audit log wrapper diff --git a/scm-core/src/main/java/sonia/scm/auditlog/AuditLogConfigurationStoreDecorator.java b/scm-core/src/main/java/sonia/scm/auditlog/AuditLogConfigurationStoreDecorator.java index 176c9d5583..bb9ab4587a 100644 --- a/scm-core/src/main/java/sonia/scm/auditlog/AuditLogConfigurationStoreDecorator.java +++ b/scm-core/src/main/java/sonia/scm/auditlog/AuditLogConfigurationStoreDecorator.java @@ -32,6 +32,7 @@ import sonia.scm.store.StoreDecoratorFactory; import java.util.Optional; import java.util.Set; +import static com.google.common.base.MoreObjects.firstNonNull; import static java.util.Collections.emptySet; public class AuditLogConfigurationStoreDecorator implements ConfigurationStore { @@ -48,29 +49,58 @@ public class AuditLogConfigurationStoreDecorator implements ConfigurationStor this.context = context; } + @Override public T get() { return delegate.get(); } + @Override public void set(T object) { - if (!shouldBeIgnored(object)) { + if (shouldAudit(object)) { auditors.forEach(s -> s.createEntry(createEntryCreationContext(object))); } delegate.set(object); } + @Override + public void delete() { + if (shouldAudit(get())) { + auditors.forEach(s -> s.createEntry(createEntryDeletionContext())); + } + delegate.delete(); + } + private EntryCreationContext createEntryCreationContext(T object) { - String repositoryId = context.getStoreParameters().getRepositoryId(); + return createContext(context.getStoreParameters().getRepositoryId(), get(), object); + } + + private EntryCreationContext createEntryDeletionContext() { + return createContext(context.getStoreParameters().getRepositoryId(), get(), null); + } + + private EntryCreationContext createContext(String repositoryId, T oldObject, T newObject) { if (!Strings.isNullOrEmpty(repositoryId)) { String name = repositoryDAO.get(repositoryId).getNamespaceAndName().toString(); - return new EntryCreationContext<>(object, get(), name, getRepositoryLabels(object)); + return new EntryCreationContext<>( + newObject, + oldObject, + name, + getRepositoryLabels(firstNonNull(newObject, oldObject)) + ); } else { - return new EntryCreationContext<>(object, get(), "", shouldUseStoreNameAsLabel(object) ? Set.of(context.getStoreParameters().getName()) : emptySet()); + return new EntryCreationContext<>( + newObject, + oldObject, + shouldUseStoreNameAsLabel(firstNonNull(newObject, oldObject)) ? Set.of(context.getStoreParameters().getName()) : emptySet() + ); } } - private boolean shouldBeIgnored(T object) { - return getAnnotation(object).map(AuditEntry::ignore).orElse(false); + private boolean shouldAudit(T object) { + return getAnnotation(object) + .map(AuditEntry::ignore) + .map(b -> !b) + .orElse(true); } private Set getRepositoryLabels(T object) { diff --git a/scm-core/src/test/java/sonia/scm/auditlog/AuditLogConfigurationStoreDecoratorTest.java b/scm-core/src/test/java/sonia/scm/auditlog/AuditLogConfigurationStoreDecoratorTest.java index d40843ff9b..e14d9de0ae 100644 --- a/scm-core/src/test/java/sonia/scm/auditlog/AuditLogConfigurationStoreDecoratorTest.java +++ b/scm-core/src/test/java/sonia/scm/auditlog/AuditLogConfigurationStoreDecoratorTest.java @@ -58,6 +58,7 @@ class AuditLogConfigurationStoreDecoratorTest { @Mock private StoreDecoratorFactory.Context storeContext; @Mock + @SuppressWarnings("rawtypes") private TypedStoreParameters parameters; private AuditLogConfigurationStoreDecorator decorator; @@ -71,6 +72,7 @@ class AuditLogConfigurationStoreDecoratorTest { class WithAuditableEntries { @BeforeEach + @SuppressWarnings("unchecked") void setUpStoreContext() { when(storeContext.getStoreParameters()).thenReturn(parameters); lenient().when(parameters.getName()).thenReturn("hog"); @@ -93,6 +95,24 @@ class AuditLogConfigurationStoreDecoratorTest { )); } + @Test + void shouldCallAuditorForDeletedEntry() { + SimpleEntry oldEntry = new SimpleEntry(); + when(delegate.get()).thenReturn(oldEntry); + + decorator.delete(); + + verify(auditor).createEntry(argThat( + context -> { + assertThat(context.getEntity()).isEmpty(); + assertThat(context.getAdditionalLabels()).contains("hog"); + assertThat(context.getObject()).isNull(); + assertThat(context.getOldObject()).isSameAs(oldEntry); + return true; + } + )); + } + @Test void shouldCallAuditorForAdditionalLabelEntry() { Object entry = new ExtraLabelEntry();