-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #301 from LukasLohoff/audit-mod-tracking
Auditing: add tracking of modified fields
- Loading branch information
Showing
12 changed files
with
651 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 53 additions & 0 deletions
53
shogun-boot/src/main/resources/db/migration/V0.7.0__Add_mod_columns.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
SET search_path TO shogun_rev, public; | ||
|
||
alter table shogun_rev.applications_rev add column if not exists created_mod bool; | ||
alter table shogun_rev.applications_rev add column if not exists modified_mod bool; | ||
alter table shogun_rev.applications_rev add column if not exists client_config_mod bool; | ||
alter table shogun_rev.applications_rev add column if not exists i18n_mod bool; | ||
alter table shogun_rev.applications_rev add column if not exists layer_config_mod bool; | ||
alter table shogun_rev.applications_rev add column if not exists layer_tree_mod bool; | ||
alter table shogun_rev.applications_rev add column if not exists name_mod bool; | ||
alter table shogun_rev.applications_rev add column if not exists state_only_mod bool; | ||
alter table shogun_rev.applications_rev add column if not exists tool_config_mod bool; | ||
|
||
alter table shogun_rev.groupclasspermissions_rev add column if not exists created_mod bool; | ||
alter table shogun_rev.groupclasspermissions_rev add column if not exists modified_mod bool; | ||
alter table shogun_rev.groupclasspermissions_rev add column if not exists class_name_mod bool; | ||
alter table shogun_rev.groupclasspermissions_rev add column if not exists permissions_mod bool; | ||
alter table shogun_rev.groupclasspermissions_rev add column if not exists group_mod bool; | ||
|
||
alter table shogun_rev.groupinstancepermissions_rev add column if not exists created_mod bool; | ||
alter table shogun_rev.groupinstancepermissions_rev add column if not exists modified_mod bool; | ||
alter table shogun_rev.groupinstancepermissions_rev add column if not exists entity_id_mod bool; | ||
alter table shogun_rev.groupinstancepermissions_rev add column if not exists permissions_mod bool; | ||
alter table shogun_rev.groupinstancepermissions_rev add column if not exists group_mod bool; | ||
|
||
alter table shogun_rev.groups_rev add column if not exists created_mod bool; | ||
alter table shogun_rev.groups_rev add column if not exists modified_mod bool; | ||
alter table shogun_rev.groups_rev add column if not exists keycloak_id_mod bool; | ||
|
||
alter table shogun_rev.layers_rev add column if not exists created_mod bool; | ||
alter table shogun_rev.layers_rev add column if not exists modified_mod bool; | ||
alter table shogun_rev.layers_rev add column if not exists client_config_mod bool; | ||
alter table shogun_rev.layers_rev add column if not exists features_mod bool; | ||
alter table shogun_rev.layers_rev add column if not exists name_mod bool; | ||
alter table shogun_rev.layers_rev add column if not exists source_config_mod bool; | ||
alter table shogun_rev.layers_rev add column if not exists type_mod bool; | ||
|
||
alter table shogun_rev.userclasspermissions_rev add column if not exists created_mod bool; | ||
alter table shogun_rev.userclasspermissions_rev add column if not exists modified_mod bool; | ||
alter table shogun_rev.userclasspermissions_rev add column if not exists class_name_mod bool; | ||
alter table shogun_rev.userclasspermissions_rev add column if not exists permissions_mod bool; | ||
alter table shogun_rev.userclasspermissions_rev add column if not exists user_mod bool; | ||
|
||
alter table shogun_rev.userinstancepermissions_rev add column if not exists created_mod bool; | ||
alter table shogun_rev.userinstancepermissions_rev add column if not exists modified_mod bool; | ||
alter table shogun_rev.userinstancepermissions_rev add column if not exists entity_id_mod bool; | ||
alter table shogun_rev.userinstancepermissions_rev add column if not exists permissions_mod bool; | ||
alter table shogun_rev.userinstancepermissions_rev add column if not exists user_mod bool; | ||
|
||
alter table shogun_rev.users_rev add column if not exists created_mod bool; | ||
alter table shogun_rev.users_rev add column if not exists modified_mod bool; | ||
alter table shogun_rev.users_rev add column if not exists client_config_mod bool; | ||
alter table shogun_rev.users_rev add column if not exists details_mod bool; | ||
alter table shogun_rev.users_rev add column if not exists keycloak_id_mod bool; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
52 changes: 52 additions & 0 deletions
52
...n-lib/src/main/java/de/terrestris/shogun/lib/envers/DefaultRevisionEntityInformation.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/* | ||
* Copyright 2012-2021 the original author or authors. | ||
* See https://github.com/spring-projects/spring-data-envers/ | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package de.terrestris.shogun.lib.envers; | ||
|
||
import org.hibernate.envers.DefaultRevisionEntity; | ||
import org.springframework.data.repository.history.support.RevisionEntityInformation; | ||
|
||
/** | ||
* {@link RevisionEntityInformation} for {@link DefaultRevisionEntity}. | ||
* | ||
* @author Oliver Gierke | ||
*/ | ||
class DefaultRevisionEntityInformation implements RevisionEntityInformation { | ||
|
||
/* | ||
* (non-Javadoc) | ||
* @see org.springframework.data.repository.history.support.RevisionEntityInformation#getRevisionNumberType() | ||
*/ | ||
public Class<?> getRevisionNumberType() { | ||
return Integer.class; | ||
} | ||
|
||
/* | ||
* (non-Javadoc) | ||
* @see org.springframework.data.repository.history.support.RevisionEntityInformation#isDefaultRevisionEntity() | ||
*/ | ||
public boolean isDefaultRevisionEntity() { | ||
return true; | ||
} | ||
|
||
/* | ||
* (non-Javadoc) | ||
* @see org.springframework.data.repository.history.support.RevisionEntityInformation#getRevisionEntityClass() | ||
*/ | ||
public Class<?> getRevisionEntityClass() { | ||
return DefaultRevisionEntity.class; | ||
} | ||
} |
161 changes: 161 additions & 0 deletions
161
...n-lib/src/main/java/de/terrestris/shogun/lib/envers/ShogunAnnotationRevisionMetadata.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
/* | ||
* Modified work - Copyright 2012-2020 the original author or authors. | ||
* See https://github.com/spring-projects/spring-data-envers/ | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package de.terrestris.shogun.lib.envers; | ||
|
||
import org.springframework.data.history.RevisionMetadata; | ||
import org.springframework.data.util.AnnotationDetectionFieldCallback; | ||
import org.springframework.data.util.Lazy; | ||
import org.springframework.util.Assert; | ||
import org.springframework.util.ReflectionUtils; | ||
|
||
import java.lang.annotation.Annotation; | ||
import java.time.Instant; | ||
import java.time.LocalDateTime; | ||
import java.time.ZoneOffset; | ||
import java.util.Date; | ||
import java.util.HashSet; | ||
import java.util.Optional; | ||
import java.util.Set; | ||
|
||
/** | ||
* A {@link RevisionMetadata} implementation that inspects the given object for fields with the configured annotations | ||
* and returns the field's values on calls to {@link #getRevisionInstant()} and | ||
* {@link #getRevisionNumber()}. | ||
* | ||
* @author Oliver Gierke | ||
* @author Jens Schauder | ||
*/ | ||
public class ShogunAnnotationRevisionMetadata<N extends Number & Comparable<N>> implements RevisionMetadata<N> { | ||
|
||
private final Object entity; | ||
private final Lazy<Optional<N>> revisionNumber; | ||
private final Lazy<Optional<Object>> revisionDate; | ||
private final RevisionType revisionType; | ||
private final Set<String> changedFields; | ||
|
||
/** | ||
* Creates a new {@link ShogunAnnotationRevisionMetadata} inspecting the given entity for the given annotations. If no | ||
* annotations will be provided these values will not be looked up from the entity and return {@literal null}. The | ||
* revisionType will be set to {@literal unknown} | ||
* | ||
* @param entity must not be {@literal null}. | ||
* @param revisionNumberAnnotation must not be {@literal null}. | ||
* @param revisionTimeStampAnnotation must not be {@literal null}. | ||
*/ | ||
public ShogunAnnotationRevisionMetadata(Object entity, Class<? extends Annotation> revisionNumberAnnotation, | ||
Class<? extends Annotation> revisionTimeStampAnnotation) { | ||
|
||
this(entity, revisionNumberAnnotation, revisionTimeStampAnnotation, RevisionType.UNKNOWN, new HashSet<>()); | ||
} | ||
|
||
/** | ||
* Creates a new {@link org.springframework.data.history.AnnotationRevisionMetadata} inspecting the given entity for the given annotations. If no | ||
* annotations will be provided these values will not be looked up from the entity and return {@literal null}. | ||
* | ||
* @param entity must not be {@literal null}. | ||
* @param revisionNumberAnnotation must not be {@literal null}. | ||
* @param revisionTimeStampAnnotation must not be {@literal null}. | ||
* @param revisionType must not be {@literal null}. | ||
* @since 2.2.0 | ||
*/ | ||
public ShogunAnnotationRevisionMetadata(Object entity, Class<? extends Annotation> revisionNumberAnnotation, | ||
Class<? extends Annotation> revisionTimeStampAnnotation, RevisionType revisionType, Set<String> changedFields) { | ||
|
||
Assert.notNull(entity, "Entity must not be null!"); | ||
Assert.notNull(revisionNumberAnnotation, "Revision number annotation must not be null!"); | ||
Assert.notNull(revisionTimeStampAnnotation, "Revision time stamp annotation must not be null!"); | ||
Assert.notNull(revisionType, "Revision Type must not be null!"); | ||
Assert.notNull(changedFields, "Changed fields must not be null!"); | ||
|
||
this.entity = entity; | ||
this.revisionNumber = detectAnnotation(entity, revisionNumberAnnotation); | ||
this.revisionDate = detectAnnotation(entity, revisionTimeStampAnnotation); | ||
this.revisionType = revisionType; | ||
this.changedFields = changedFields; | ||
} | ||
|
||
/* | ||
* (non-Javadoc) | ||
* @see org.springframework.data.repository.history.RevisionMetadata#getRevisionNumber() | ||
*/ | ||
public Optional<N> getRevisionNumber() { | ||
return revisionNumber.get(); | ||
} | ||
|
||
/* | ||
* (non-Javadoc) | ||
* @see org.springframework.data.history.RevisionMetadata#getRevisionDate() | ||
*/ | ||
public Optional<Instant> getRevisionInstant() { | ||
return revisionDate.get().map(ShogunAnnotationRevisionMetadata::convertToInstant); | ||
} | ||
|
||
/* | ||
* (non-Javadoc) | ||
* @see org.springframework.data.history.RevisionMetadata#getRevisionDate() | ||
*/ | ||
public RevisionType getRevisionType() { | ||
return revisionType; | ||
} | ||
|
||
/* | ||
* (non-Javadoc) | ||
* @see org.springframework.data.history.RevisionMetadata#getRevisionDate() | ||
*/ | ||
public Set<String> getChangedFields() { | ||
return changedFields; | ||
} | ||
|
||
/* | ||
* (non-Javadoc) | ||
* @see org.springframework.data.repository.history.RevisionMetadata#getDelegate() | ||
*/ | ||
@SuppressWarnings("unchecked") | ||
public <T> T getDelegate() { | ||
return (T) entity; | ||
} | ||
|
||
private static <T> Lazy<Optional<T>> detectAnnotation(Object entity, Class<? extends Annotation> annotationType) { | ||
|
||
return Lazy.of(() -> { | ||
AnnotationDetectionFieldCallback callback = new AnnotationDetectionFieldCallback(annotationType); | ||
ReflectionUtils.doWithFields(entity.getClass(), callback); | ||
return Optional.ofNullable(callback.getValue(entity)); | ||
}); | ||
} | ||
|
||
private static Instant convertToInstant(Object timestamp) { | ||
|
||
if (timestamp instanceof Instant) { | ||
return (Instant) timestamp; | ||
} | ||
|
||
if (timestamp instanceof LocalDateTime) { | ||
return ((LocalDateTime) timestamp).atZone(ZoneOffset.systemDefault()).toInstant(); | ||
} | ||
|
||
if (timestamp instanceof Long) { | ||
return Instant.ofEpochMilli((Long) timestamp); | ||
} | ||
|
||
if (Date.class.isInstance(timestamp)) { | ||
return Date.class.cast(timestamp).toInstant(); | ||
} | ||
|
||
throw new IllegalArgumentException(String.format("Can't convert %s to Instant!", timestamp)); | ||
} | ||
} |
Oops, something went wrong.