This is an automated email from the ASF dual-hosted git repository. ilgrosso pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/syncope.git
commit 41e582a30bb434cd0274964cd3a33b97bb71c877 Author: Francesco Chicchiriccò <[email protected]> AuthorDate: Wed Jan 28 13:40:19 2026 +0100 [SYNCOPE-1946] Adding audit history features to Realm page --- .../client/console/audit/AuditHistoryDetails.java | 7 ++- .../syncope/client/console/pages/Realms.java | 56 +++++++++++++++++++--- .../syncope/client/console/panels/Realm.java | 14 ++++++ .../syncope/client/console/pages/Realms.properties | 1 + .../client/console/pages/Realms_fr_CA.properties | 3 +- .../client/console/pages/Realms_it.properties | 1 + .../client/console/pages/Realms_ja.properties | 1 + .../client/console/pages/Realms_pt_BR.properties | 1 + .../client/console/pages/Realms_ru.properties | 1 + .../core/persistence/jpa/dao/JPAAuditEventDAO.java | 8 ++-- .../dao/ElasticsearchAuditEventDAO.java | 2 +- .../opensearch/dao/OpenSearchAuditEventDAO.java | 2 +- 12 files changed, 81 insertions(+), 16 deletions(-) diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/audit/AuditHistoryDetails.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/audit/AuditHistoryDetails.java index eed5a3a622..b44503fbf9 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/audit/AuditHistoryDetails.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/audit/AuditHistoryDetails.java @@ -330,17 +330,20 @@ public abstract class AuditHistoryDetails<T extends Serializable> extends Panel } try { - String content; + String content = null; if (auditEvent.getBefore() == null) { JsonNode output = MAPPER.readTree(auditEvent.getOutput()); if (output.has("entity")) { content = output.get("entity").toPrettyString(); - } else { + } else if ((!output.has("content") && output.get("content").isArray())) { content = output.toPrettyString(); } } else { content = auditEvent.getBefore(); } + if (content == null || "null".equals(content)) { + return Model.of(); + } T entity = MAPPER.reader(). with(StreamReadFeature.STRICT_DUPLICATE_DETECTION). diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/Realms.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/Realms.java index 89b187f0c2..2307193aa9 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/Realms.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/Realms.java @@ -18,15 +18,18 @@ */ package org.apache.syncope.client.console.pages; +import com.fasterxml.jackson.databind.json.JsonMapper; import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal; import java.io.Serializable; import java.util.List; import org.apache.syncope.client.console.BookmarkablePageLinkBuilder; import org.apache.syncope.client.console.SyncopeConsoleSession; +import org.apache.syncope.client.console.audit.AuditHistoryModal; import org.apache.syncope.client.console.panels.Realm; import org.apache.syncope.client.console.panels.RealmChoicePanel; import org.apache.syncope.client.console.panels.RealmChoicePanel.ChosenRealm; import org.apache.syncope.client.console.rest.AnyTypeRestClient; +import org.apache.syncope.client.console.rest.AuditRestClient; import org.apache.syncope.client.console.rest.RealmRestClient; import org.apache.syncope.client.console.tasks.TemplatesTogglePanel; import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal; @@ -40,6 +43,8 @@ import org.apache.syncope.common.lib.to.AnyTypeTO; import org.apache.syncope.common.lib.to.ProvisioningResult; import org.apache.syncope.common.lib.to.RealmTO; import org.apache.syncope.common.lib.to.TemplatableTO; +import org.apache.syncope.common.lib.types.IdRepoEntitlement; +import org.apache.syncope.common.lib.types.OpEvent; import org.apache.wicket.PageReference; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.event.Broadcast; @@ -56,6 +61,8 @@ public class Realms extends BasePage { private static final long serialVersionUID = -1100228004207271270L; + protected static final JsonMapper MAPPER = JsonMapper.builder().findAndAddModules().build(); + public static final String SELECTED_INDEX = "selectedIndex"; public static final String INITIAL_REALM = "initialRealm"; @@ -66,6 +73,9 @@ public class Realms extends BasePage { @SpringBean protected AnyTypeRestClient anyTypeRestClient; + @SpringBean + protected AuditRestClient auditRestClient; + protected final TemplatesTogglePanel templates; protected final RealmChoicePanel realmChoicePanel; @@ -119,7 +129,7 @@ public class Realms extends BasePage { setFooterVisible(false); } }; - templateModal.size(Modal.Size.Large); + templateModal.size(Modal.Size.Extra_large); content.add(templateModal); modal.setWindowClosedCallback(target -> { @@ -194,12 +204,6 @@ public class Realms extends BasePage { super("body", realmTO, anyTypes, selectedIndex, Realms.this.getPageReference()); } - @Override - protected void onClickTemplate(final AjaxRequestTarget target) { - templates.setTargetObject(realmTO); - templates.toggle(target, true); - } - @Override protected void setWindowClosedReloadCallback(final BaseModal<?> modal) { modal.setWindowClosedCallback(target -> { @@ -217,6 +221,12 @@ public class Realms extends BasePage { }); } + @Override + protected void onClickTemplate(final AjaxRequestTarget target) { + templates.setTargetObject(realmTO); + templates.toggle(target, true); + } + @Override protected void onClickCreate(final AjaxRequestTarget target) { this.wizardBuilder.setParent(realmChoicePanel.getCurrentRealm()); @@ -240,6 +250,38 @@ public class Realms extends BasePage { }); } + @Override + protected void onClickAudit(final AjaxRequestTarget target, final RealmTO realmTO) { + target.add(templateModal.setContent(new AuditHistoryModal<>( + OpEvent.CategoryType.LOGIC, + "RealmLogic", + realmTO, + IdRepoEntitlement.REALM_UPDATE, + auditRestClient) { + + private static final long serialVersionUID = -5819724478921691835L; + + @Override + protected void restore(final String json, final AjaxRequestTarget target) { + try { + RealmTO updated = MAPPER.readValue(json, RealmTO.class); + realmRestClient.update(updated); + + SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); + target.add(realmChoicePanel.reloadRealmTree(target)); + } catch (Exception e) { + LOG.error("While restoring realm {}", realmTO.getKey(), e); + SyncopeConsoleSession.get().onException(e); + } + ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target); + } + })); + + templateModal.header(new Model<>(getString("realm.auditHistory.title", new Model<>(realmTO)))); + + templateModal.show(true); + } + @Override protected void onClickDelete(final AjaxRequestTarget target, final RealmTO realmTO) { try { diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java index d3b2e08e74..fe9e6d21e8 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java @@ -234,6 +234,8 @@ public abstract class Realm extends WizardMgtPanel<RealmTO> { protected abstract void onClickEdit(AjaxRequestTarget target, RealmTO realmTO); + protected abstract void onClickAudit(AjaxRequestTarget target, RealmTO realmTO); + protected abstract void onClickDelete(AjaxRequestTarget target, RealmTO realmTO); protected static class RemoteRealmPanel extends RemoteObjectPanel { @@ -306,6 +308,18 @@ public abstract class Realm extends WizardMgtPanel<RealmTO> { }, ActionLink.ActionType.TEMPLATE, IdRepoEntitlement.REALM_UPDATE).hideLabel(); } + if (securityCheck(Set.of(IdRepoEntitlement.AUDIT_LIST))) { + actionPanel.add(new ActionLink<>(realmTO) { + + private static final long serialVersionUID = 2802988981431379827L; + + @Override + public void onClick(final AjaxRequestTarget target, final RealmTO ignore) { + onClickAudit(target, realmTO); + } + }, ActionLink.ActionType.VIEW_AUDIT_HISTORY, IdRepoEntitlement.AUDIT_LIST).hideLabel(); + } + if (securityCheck(Set.of(IdRepoEntitlement.REALM_DELETE))) { actionPanel.add(new ActionLink<>(realmTO) { diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Realms.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Realms.properties index 4cfe42dbe8..7aaf70ef35 100644 --- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Realms.properties +++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Realms.properties @@ -22,3 +22,4 @@ realmLabel=Realm dynRealmLabel=Dynamic Realm realms=Realms dynrealms=Dynamic Realms +realm.auditHistory.title=Realm ${fullPath} history diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Realms_fr_CA.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Realms_fr_CA.properties index d6d208e376..9a980e0093 100644 --- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Realms_fr_CA.properties +++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Realms_fr_CA.properties @@ -16,9 +16,10 @@ # under the License. any.realm.new=Nouveau domaine any.realm.edit=Modifier domaine ${fullPath} -inner.template.edit=Modifier mod�le ${gauche} pour '${right.fullPath}''. +inner.template.edit=Modifier mod\u00e8le ${gauche} pour '${right.fullPath}''. afterObj=Lien d'objet realmLabel=Domaine dynRealmLabel=Domaine dynamique realms=Domaines dynrealms=Domaines dynamiques +realm.auditHistory.title=Realm ${fullPath} histoire diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Realms_it.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Realms_it.properties index c2f149c586..135fd9aafc 100644 --- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Realms_it.properties +++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Realms_it.properties @@ -22,3 +22,4 @@ realmLabel=Realm dynRealmLabel=Realm Dinamico realms=Realm dynrealms=Realm Dinamici +realm.auditHistory.title=Realm ${fullPath} storico diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Realms_ja.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Realms_ja.properties index 3c02474b31..1c31ef35b2 100644 --- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Realms_ja.properties +++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Realms_ja.properties @@ -22,3 +22,4 @@ realmLabel=\u30ec\u30eb\u30e0 dynRealmLabel=\u52d5\u7684\u30ec\u30eb\u30e0 realms=\u30ec\u30eb\u30e0 dynrealms=\u52d5\u7684\u30ec\u30eb\u30e0 +realm.auditHistory.title=Realm ${fullPath} history diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Realms_pt_BR.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Realms_pt_BR.properties index 4cfe42dbe8..7aaf70ef35 100644 --- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Realms_pt_BR.properties +++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Realms_pt_BR.properties @@ -22,3 +22,4 @@ realmLabel=Realm dynRealmLabel=Dynamic Realm realms=Realms dynrealms=Dynamic Realms +realm.auditHistory.title=Realm ${fullPath} history diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Realms_ru.properties b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Realms_ru.properties index d1d026042e..66a1ce9c90 100644 --- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Realms_ru.properties +++ b/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/pages/Realms_ru.properties @@ -23,3 +23,4 @@ realmLabel=Realm dynRealmLabel=Dynamic Realm realms=Realms dynrealms=Dynamic Realms +realm.auditHistory.title=Realm ${fullPath} history diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAuditEventDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAuditEventDAO.java index 1a12103a42..180338ea1b 100644 --- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAuditEventDAO.java +++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAuditEventDAO.java @@ -51,10 +51,10 @@ public class JPAAuditEventDAO implements AuditEventDAO { protected AuditEventCriteriaBuilder entityKey(final String entityKey) { if (entityKey != null) { query.append(andIfNeeded()). - append("(before_value LIKE '%key%").append(entityKey).append("%' OR "). - append("inputs LIKE '%key%").append(entityKey).append("%' OR "). - append("output LIKE '%key%").append(entityKey).append("%' OR "). - append("throwable LIKE '%key%").append(entityKey).append("%')"); + append("(before_value LIKE '%\"key\":\"").append(entityKey).append("\"%' OR "). + append("inputs LIKE '%\"key\":\"").append(entityKey).append("\"%' OR "). + append("output LIKE '%\"key\":\"").append(entityKey).append("\"%' OR "). + append("throwable LIKE '%\"key\":\"").append(entityKey).append("\"%')"); } return this; } diff --git a/ext/elasticsearch/persistence/src/main/java/org/apache/syncope/core/persistence/elasticsearch/dao/ElasticsearchAuditEventDAO.java b/ext/elasticsearch/persistence/src/main/java/org/apache/syncope/core/persistence/elasticsearch/dao/ElasticsearchAuditEventDAO.java index 481ef19833..c654ff1917 100644 --- a/ext/elasticsearch/persistence/src/main/java/org/apache/syncope/core/persistence/elasticsearch/dao/ElasticsearchAuditEventDAO.java +++ b/ext/elasticsearch/persistence/src/main/java/org/apache/syncope/core/persistence/elasticsearch/dao/ElasticsearchAuditEventDAO.java @@ -99,7 +99,7 @@ public class ElasticsearchAuditEventDAO implements AuditEventDAO { multiMatch(QueryBuilders.multiMatch(). fields("before", "inputs", "output", "throwable"). type(TextQueryType.Phrase). - query(entityKey).build()).build()); + query("\"key\":\"" + entityKey + "\"").build()).build()); } queries.add(new Query.Builder().regexp(QueryBuilders.regexp(). diff --git a/ext/opensearch/persistence/src/main/java/org/apache/syncope/core/persistence/opensearch/dao/OpenSearchAuditEventDAO.java b/ext/opensearch/persistence/src/main/java/org/apache/syncope/core/persistence/opensearch/dao/OpenSearchAuditEventDAO.java index 71f487bfb5..abcf7035c1 100644 --- a/ext/opensearch/persistence/src/main/java/org/apache/syncope/core/persistence/opensearch/dao/OpenSearchAuditEventDAO.java +++ b/ext/opensearch/persistence/src/main/java/org/apache/syncope/core/persistence/opensearch/dao/OpenSearchAuditEventDAO.java @@ -98,7 +98,7 @@ public class OpenSearchAuditEventDAO implements AuditEventDAO { multiMatch(QueryBuilders.multiMatch(). fields("before", "inputs", "output", "throwable"). type(TextQueryType.Phrase). - query(entityKey).build()).build()); + query("\"key\":\"" + entityKey + "\"").build()).build()); } queries.add(new Query.Builder().regexp(QueryBuilders.regexp().
