mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-08-27 18:36:08 +00:00
Event filter restricted usageSummary, added for testCase(with default disabled) (#7107)
This commit is contained in:
parent
f4c0d82882
commit
9e689f7f8b
@ -22,6 +22,7 @@ import javax.ws.rs.core.Response;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.openmetadata.catalog.filter.FilterRegistry;
|
||||
import org.openmetadata.catalog.filter.Filters;
|
||||
import org.openmetadata.catalog.resources.settings.SettingsCache;
|
||||
import org.openmetadata.catalog.settings.Settings;
|
||||
import org.openmetadata.catalog.settings.SettingsType;
|
||||
import org.openmetadata.catalog.util.FilterUtil;
|
||||
@ -118,6 +119,7 @@ public class SettingsRepository {
|
||||
.insertSettings(setting.getConfigType().toString(), JsonUtils.pojoToJson(setting.getConfigValue()));
|
||||
if (setting.getConfigType().equals(ACTIVITY_FEED_FILTER_SETTING)) {
|
||||
FilterRegistry.add(FilterUtil.getEventFilterFromSettings(setting));
|
||||
SettingsCache.getInstance().putSettings(setting);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
|
@ -1,86 +0,0 @@
|
||||
package org.openmetadata.catalog.kafka;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import java.util.Properties;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.kafka.clients.CommonClientConfigs;
|
||||
import org.apache.kafka.clients.producer.KafkaProducer;
|
||||
import org.apache.kafka.clients.producer.ProducerConfig;
|
||||
import org.apache.kafka.clients.producer.ProducerRecord;
|
||||
import org.apache.kafka.common.config.SslConfigs;
|
||||
import org.openmetadata.catalog.events.WebhookPublisher;
|
||||
import org.openmetadata.catalog.jdbi3.CollectionDAO;
|
||||
import org.openmetadata.catalog.resources.events.EventResource;
|
||||
import org.openmetadata.catalog.type.ChangeEvent;
|
||||
import org.openmetadata.catalog.type.Webhook;
|
||||
import org.openmetadata.catalog.util.JsonUtils;
|
||||
|
||||
@Slf4j
|
||||
public class KafkaWebhookEventPublisher extends WebhookPublisher {
|
||||
|
||||
protected final Webhook webhook;
|
||||
private static KafkaProducer<String, String> producer;
|
||||
Properties properties = new Properties();
|
||||
|
||||
public KafkaWebhookEventPublisher(Webhook webhook, CollectionDAO dao) {
|
||||
super(webhook, dao);
|
||||
this.webhook = webhook;
|
||||
if (webhook.getKafkaProperties().getSecurityProtocol().equals(KafkaEventConfiguration.SecurityProtocol.SSL)) {
|
||||
// configuration for SSL Encryption
|
||||
if (webhook.getKafkaProperties().getSSLProtocol() != null
|
||||
&& webhook.getKafkaProperties().getSSLTrustStoreLocation() != null
|
||||
&& webhook.getKafkaProperties().getSSLTrustStorePassword() != null
|
||||
&& webhook.getKafkaProperties().getSSLKeystoreLocation() != null
|
||||
&& webhook.getKafkaProperties().getSSLKeystorePassword() != null
|
||||
&& webhook.getKafkaProperties().getSSLKeyPassword() != null) {
|
||||
properties.put(
|
||||
CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, webhook.getKafkaProperties().getSecurityProtocol());
|
||||
properties.put(SslConfigs.SSL_PROTOCOL_CONFIG, webhook.getKafkaProperties().getSSLProtocol());
|
||||
properties.put(
|
||||
SslConfigs.SSL_TRUSTSTORE_LOCATION_CONFIG, webhook.getKafkaProperties().getSSLTrustStoreLocation());
|
||||
properties.put(
|
||||
SslConfigs.SSL_TRUSTSTORE_PASSWORD_CONFIG, webhook.getKafkaProperties().getSSLTrustStorePassword());
|
||||
// configuration for SSL Authentication
|
||||
properties.put(SslConfigs.SSL_KEYSTORE_LOCATION_CONFIG, webhook.getKafkaProperties().getSSLKeystoreLocation());
|
||||
properties.put(SslConfigs.SSL_KEYSTORE_PASSWORD_CONFIG, webhook.getKafkaProperties().getSSLKeystorePassword());
|
||||
properties.put(SslConfigs.SSL_KEY_PASSWORD_CONFIG, webhook.getKafkaProperties().getSSLKeyPassword());
|
||||
} else {
|
||||
LOG.info("The SSL could not be configured as the required properties are not defined!");
|
||||
}
|
||||
}
|
||||
properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, webhook.getEndpoint().toString());
|
||||
properties.put(ProducerConfig.ACKS_CONFIG, webhook.getKafkaProperties().getAcks());
|
||||
properties.put(ProducerConfig.RETRIES_CONFIG, webhook.getKafkaProperties().getRetries());
|
||||
properties.put(ProducerConfig.BATCH_SIZE_CONFIG, webhook.getBatchSize());
|
||||
properties.put(ProducerConfig.LINGER_MS_CONFIG, webhook.getKafkaProperties().getLingerMS());
|
||||
properties.put(ProducerConfig.BUFFER_MEMORY_CONFIG, webhook.getKafkaProperties().getBufferMemory());
|
||||
properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, webhook.getKafkaProperties().getKeySerializer());
|
||||
properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, webhook.getKafkaProperties().getValueSerializer());
|
||||
producer = new KafkaProducer<>(properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
LOG.info("Kafka Webhook Publisher Started");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShutdown() {
|
||||
producer.flush();
|
||||
producer.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publish(EventResource.ChangeEventList events) throws JsonProcessingException {
|
||||
if (webhook.getKafkaProperties().getTopics() != null) {
|
||||
for (String topic : webhook.getKafkaProperties().getTopics()) {
|
||||
for (ChangeEvent event : events.getData()) {
|
||||
String eventJson = JsonUtils.pojoToJson(event);
|
||||
producer.send(new ProducerRecord<>(topic, eventJson));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG.info("Topics are null");
|
||||
}
|
||||
}
|
||||
}
|
@ -358,8 +358,7 @@ public class WebhookResource extends EntityResource<Webhook, WebhookRepository>
|
||||
.withTimeout(create.getTimeout())
|
||||
.withEnabled(create.getEnabled())
|
||||
.withSecretKey(create.getSecretKey())
|
||||
.withKafkaProperties(create.getKafkaProperties())
|
||||
.withStatus(Boolean.TRUE.equals(create.getEnabled()) ? Status.ACTIVE : Status.DISABLED)
|
||||
.withWebhookType(WebhookType.fromValue(create.getWebhookType().value()));
|
||||
.withWebhookType(create.getWebhookType() == null ? WebhookType.generic : create.getWebhookType());
|
||||
}
|
||||
}
|
||||
|
@ -61,6 +61,10 @@ public class SettingsCache {
|
||||
}
|
||||
}
|
||||
|
||||
public void putSettings(Settings setting) throws RuntimeException {
|
||||
SETTINGS_CACHE.put(setting.getConfigType().toString(), setting);
|
||||
}
|
||||
|
||||
public static void cleanUp() {
|
||||
SETTINGS_CACHE.invalidateAll();
|
||||
INITIALIZED = false;
|
||||
|
@ -401,7 +401,10 @@ public final class EntityUtil {
|
||||
deleteFilter.ifPresent(
|
||||
eventFilter ->
|
||||
filters.add(
|
||||
new Filters().withEventType(EventType.ENTITY_SOFT_DELETED).withFields(eventFilter.getFields())));
|
||||
new Filters()
|
||||
.withEventType(EventType.ENTITY_SOFT_DELETED)
|
||||
.withInclude(eventFilter.getInclude())
|
||||
.withExclude(eventFilter.getExclude())));
|
||||
}
|
||||
|
||||
public static EntityReference copy(EntityReference from, EntityReference to) {
|
||||
|
@ -22,6 +22,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.openmetadata.catalog.Entity;
|
||||
import org.openmetadata.catalog.filter.EventFilter;
|
||||
import org.openmetadata.catalog.filter.Filters;
|
||||
import org.openmetadata.catalog.settings.Settings;
|
||||
@ -36,6 +37,7 @@ import org.openmetadata.catalog.type.FieldChange;
|
||||
public class FilterUtil {
|
||||
|
||||
private static final String TEST_CASE_RESULT = "testCaseResult";
|
||||
private static final String WILDCARD_FILTER = "all";
|
||||
|
||||
public static boolean shouldProcessRequest(ChangeEvent changeEvent, Map<String, Map<EventType, Filters>> filtersMap) {
|
||||
if (filtersMap != null && !filtersMap.isEmpty()) {
|
||||
@ -44,20 +46,16 @@ public class FilterUtil {
|
||||
Map<EventType, Filters> filtersOfEntity = filtersMap.get(entityType);
|
||||
if (filtersOfEntity == null || filtersOfEntity.size() == 0) {
|
||||
// check if we have all entities Filter
|
||||
return handleWithWildCardFilter(filtersMap.get("all"), eventType, getUpdateField(changeEvent));
|
||||
return handleWithWildCardFilter(filtersMap.get(WILDCARD_FILTER), eventType, getUpdateField(changeEvent));
|
||||
} else {
|
||||
Filters sf;
|
||||
if ((sf = filtersOfEntity.get(eventType)) == null) {
|
||||
return false;
|
||||
} else {
|
||||
if (sf.getFields().contains("all")) {
|
||||
return true;
|
||||
if (entityType.equals(Entity.TEST_CASE)) {
|
||||
return handleTestCaseFilter(changeEvent, sf);
|
||||
} else {
|
||||
if (entityType.equals("testCase")) {
|
||||
return handleTestCaseFilter(changeEvent, sf);
|
||||
} else {
|
||||
return checkIfFilterContainField(sf, getUpdateField(changeEvent));
|
||||
}
|
||||
return checkIfFilterContainField(sf, getUpdateField(changeEvent));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -68,15 +66,18 @@ public class FilterUtil {
|
||||
private static boolean handleTestCaseFilter(ChangeEvent changeEvent, Filters sf) {
|
||||
List<FieldChange> fieldChanges = getAllFieldChange(changeEvent);
|
||||
for (FieldChange fieldChange : fieldChanges) {
|
||||
if (fieldChange.getName().equals(TEST_CASE_RESULT)) {
|
||||
if (fieldChange.getName().equals(TEST_CASE_RESULT) && fieldChange.getNewValue() != null) {
|
||||
TestCaseResult testCaseResult = (TestCaseResult) fieldChange.getNewValue();
|
||||
TestCaseStatus status = testCaseResult.getTestCaseStatus();
|
||||
if (sf.getFields().contains(TEST_CASE_RESULT + status.toString())) {
|
||||
String statusField = TEST_CASE_RESULT + status.toString();
|
||||
if (sf.getInclude().contains(statusField)) {
|
||||
return true;
|
||||
} else if (sf.getExclude().contains(statusField)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return checkIfFilterContainField(sf, getUpdateField(changeEvent));
|
||||
return sf.getInclude().contains(WILDCARD_FILTER);
|
||||
}
|
||||
|
||||
public static boolean handleWithWildCardFilter(
|
||||
@ -84,8 +85,7 @@ public class FilterUtil {
|
||||
if (wildCardFilter != null && !wildCardFilter.isEmpty()) {
|
||||
// check if we have all entities Filter
|
||||
Filters f = wildCardFilter.get(type);
|
||||
boolean allFieldCheck = checkIfFilterContainField(f, updatedField);
|
||||
return f != null && (f.getFields().contains("all") || allFieldCheck);
|
||||
return checkIfFilterContainField(f, updatedField);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -93,10 +93,14 @@ public class FilterUtil {
|
||||
public static boolean checkIfFilterContainField(Filters f, List<String> updatedField) {
|
||||
if (f != null) {
|
||||
for (String changed : updatedField) {
|
||||
if (f.getFields().contains(changed)) {
|
||||
// field is present in excluded
|
||||
if (f.getExclude().contains(changed)) {
|
||||
return false;
|
||||
} else if (f.getInclude().contains(changed)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return f.getInclude().contains(WILDCARD_FILTER);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -111,12 +115,13 @@ public class FilterUtil {
|
||||
}
|
||||
|
||||
public static List<FieldChange> getAllFieldChange(ChangeEvent changeEvent) {
|
||||
ChangeDescription description = changeEvent.getChangeDescription();
|
||||
List<FieldChange> allFieldChange = new ArrayList<>();
|
||||
allFieldChange.addAll(description.getFieldsAdded());
|
||||
allFieldChange.addAll(description.getFieldsUpdated());
|
||||
allFieldChange.addAll(description.getFieldsDeleted());
|
||||
|
||||
ChangeDescription description = changeEvent.getChangeDescription();
|
||||
if (description != null) {
|
||||
allFieldChange.addAll(description.getFieldsAdded());
|
||||
allFieldChange.addAll(description.getFieldsUpdated());
|
||||
allFieldChange.addAll(description.getFieldsDeleted());
|
||||
}
|
||||
return allFieldChange;
|
||||
}
|
||||
|
||||
|
@ -7,27 +7,210 @@
|
||||
"filters": [
|
||||
{
|
||||
"eventType": "entityCreated",
|
||||
"fields": [
|
||||
"include": [
|
||||
"all"
|
||||
]
|
||||
],
|
||||
"exclude": []
|
||||
},
|
||||
{
|
||||
"eventType": "entityUpdated",
|
||||
"fields": [
|
||||
"include": [
|
||||
"all"
|
||||
]
|
||||
],
|
||||
"exclude": ["usageSummary"]
|
||||
},
|
||||
{
|
||||
"eventType": "entityDeleted",
|
||||
"fields": [
|
||||
"include": [
|
||||
"all"
|
||||
]
|
||||
],
|
||||
"exclude": []
|
||||
},
|
||||
{
|
||||
"eventType": "entitySoftDeleted",
|
||||
"fields": [
|
||||
"include": [
|
||||
"all"
|
||||
]
|
||||
],
|
||||
"exclude": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"entityType": "table",
|
||||
"filters": [
|
||||
{
|
||||
"eventType": "entityCreated",
|
||||
"include": [
|
||||
"all"
|
||||
],
|
||||
"exclude": []
|
||||
},
|
||||
{
|
||||
"eventType": "entityUpdated",
|
||||
"include": [
|
||||
"description",
|
||||
"owner",
|
||||
"tags",
|
||||
"followers"
|
||||
],
|
||||
"exclude": []
|
||||
},
|
||||
{
|
||||
"eventType": "entityDeleted",
|
||||
"include": [
|
||||
"all"
|
||||
],
|
||||
"exclude": []
|
||||
},
|
||||
{
|
||||
"eventType": "entitySoftDeleted",
|
||||
"include": [
|
||||
"all"
|
||||
],
|
||||
"exclude": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"entityType": "dashboard",
|
||||
"filters": [
|
||||
{
|
||||
"eventType": "entityCreated",
|
||||
"include": [
|
||||
"all"
|
||||
],
|
||||
"exclude": []
|
||||
},
|
||||
{
|
||||
"eventType": "entityUpdated",
|
||||
"include": [
|
||||
"description",
|
||||
"owner",
|
||||
"tags",
|
||||
"followers"
|
||||
],
|
||||
"exclude": []
|
||||
},
|
||||
{
|
||||
"eventType": "entityDeleted",
|
||||
"include": [
|
||||
"all"
|
||||
],
|
||||
"exclude": []
|
||||
},
|
||||
{
|
||||
"eventType": "entitySoftDeleted",
|
||||
"include": [
|
||||
"all"
|
||||
],
|
||||
"exclude": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"entityType": "pipeline",
|
||||
"filters": [
|
||||
{
|
||||
"eventType": "entityCreated",
|
||||
"include": [
|
||||
"all"
|
||||
],
|
||||
"exclude": []
|
||||
},
|
||||
{
|
||||
"eventType": "entityUpdated",
|
||||
"include": [
|
||||
"description",
|
||||
"owner",
|
||||
"tags",
|
||||
"followers"
|
||||
],
|
||||
"exclude": []
|
||||
},
|
||||
{
|
||||
"eventType": "entityDeleted",
|
||||
"include": [
|
||||
"all"
|
||||
],
|
||||
"exclude": []
|
||||
},
|
||||
{
|
||||
"eventType": "entitySoftDeleted",
|
||||
"include": [
|
||||
"all"
|
||||
],
|
||||
"exclude": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"entityType": "mlmodel",
|
||||
"filters": [
|
||||
{
|
||||
"eventType": "entityCreated",
|
||||
"include": [
|
||||
"all"
|
||||
],
|
||||
"exclude": []
|
||||
},
|
||||
{
|
||||
"eventType": "entityUpdated",
|
||||
"include": [
|
||||
"description",
|
||||
"owner",
|
||||
"tags",
|
||||
"followers"
|
||||
],
|
||||
"exclude": []
|
||||
},
|
||||
{
|
||||
"eventType": "entityDeleted",
|
||||
"include": [
|
||||
"all"
|
||||
],
|
||||
"exclude": []
|
||||
},
|
||||
{
|
||||
"eventType": "entitySoftDeleted",
|
||||
"include": [
|
||||
"all"
|
||||
],
|
||||
"exclude": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"entityType": "testCase",
|
||||
"filters": [
|
||||
{
|
||||
"eventType": "entityCreated",
|
||||
"include": [
|
||||
"all"
|
||||
],
|
||||
"exclude": []
|
||||
},
|
||||
{
|
||||
"eventType": "entityUpdated",
|
||||
"include": [
|
||||
"testCaseResultSuccess",
|
||||
"testCaseResultFailed",
|
||||
"testCaseResultAborted"
|
||||
],
|
||||
"exclude": []
|
||||
},
|
||||
{
|
||||
"eventType": "entityDeleted",
|
||||
"include": [
|
||||
"all"
|
||||
],
|
||||
"exclude": []
|
||||
},
|
||||
{
|
||||
"eventType": "entitySoftDeleted",
|
||||
"include": [
|
||||
"all"
|
||||
],
|
||||
"exclude": []
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -51,12 +51,8 @@
|
||||
"description": "Secret set by the webhook client used for computing HMAC SHA256 signature of webhook payload and sent in `X-OM-Signature` header in POST requests to publish the events.",
|
||||
"type": "string"
|
||||
},
|
||||
"kafkaProperties": {
|
||||
"description": "Properties of Kafka Producer",
|
||||
"$ref": "../../configuration/kafkaEventConfiguration.json"
|
||||
},
|
||||
"webhookType": {
|
||||
"description": "Type of webhook slack,generic,kafka etc",
|
||||
"description": "Type of webhook slack,generic,msteams etc",
|
||||
"$ref": "../../entity/events/webhook.json#/definitions/webhookType"
|
||||
}
|
||||
},
|
||||
|
@ -8,7 +8,7 @@
|
||||
"javaInterfaces": ["org.openmetadata.catalog.EntityInterface"],
|
||||
"definitions": {
|
||||
"webhookType": {
|
||||
"description": "Type of webhook slack, generic, kafka, etc.",
|
||||
"description": "Type of webhook slack, generic, msteams, etc.",
|
||||
"type": "string",
|
||||
"javaType": "org.openmetadata.catalog.type.WebhookType",
|
||||
"default": "generic",
|
||||
@ -44,7 +44,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"webhookType": {
|
||||
"description": "Type of webhook slack, generic, kafka, etc.",
|
||||
"description": "Type of webhook slack, generic, msteams, etc.",
|
||||
"$ref": "#/definitions/webhookType"
|
||||
},
|
||||
"description": {
|
||||
@ -68,10 +68,6 @@
|
||||
"type": "integer",
|
||||
"default": 10
|
||||
},
|
||||
"kafkaProperties": {
|
||||
"description": "Properties of Kafka Producer",
|
||||
"$ref": "../../configuration/kafkaEventConfiguration.json"
|
||||
},
|
||||
"timeout": {
|
||||
"description": "Connection timeout in seconds. (Default 10s).",
|
||||
"type": "integer",
|
||||
|
@ -17,6 +17,140 @@
|
||||
"entityDeleted"
|
||||
]
|
||||
},
|
||||
"entityTypes": {
|
||||
"javaType": "org.openmetadata.catalog.filter.EntityTypes",
|
||||
"description": "Type of event.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"All",
|
||||
"Chart",
|
||||
"Dashboard",
|
||||
"Database",
|
||||
"Database Schema",
|
||||
"Glossary",
|
||||
"Glossary Term",
|
||||
"Location",
|
||||
"Metrics",
|
||||
"Ml Model",
|
||||
"Pipeline",
|
||||
"Report",
|
||||
"Table",
|
||||
"Topic",
|
||||
"Test Case"
|
||||
],
|
||||
"javaEnums": [
|
||||
{
|
||||
"name": "all"
|
||||
},
|
||||
{
|
||||
"name": "chart"
|
||||
},
|
||||
{
|
||||
"name": "dashboard"
|
||||
},
|
||||
{
|
||||
"name": "database"
|
||||
},
|
||||
{
|
||||
"name": "databaseSchema"
|
||||
},
|
||||
{
|
||||
"name": "glossary"
|
||||
},
|
||||
{
|
||||
"name": "glossaryTerm"
|
||||
},
|
||||
{
|
||||
"name": "location"
|
||||
},
|
||||
{
|
||||
"name": "metrics"
|
||||
},
|
||||
{
|
||||
"name": "mlmodel"
|
||||
},
|
||||
{
|
||||
"name": "pipeline"
|
||||
},
|
||||
{
|
||||
"name": "report"
|
||||
},
|
||||
{
|
||||
"name": "table"
|
||||
},
|
||||
{
|
||||
"name": "topic"
|
||||
},
|
||||
{
|
||||
"name": "testCase"
|
||||
}
|
||||
]
|
||||
},
|
||||
"fieldTypes": {
|
||||
"javaType": "org.openmetadata.catalog.filter.FieldType",
|
||||
"description": "Type of event.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"All",
|
||||
"Display Name",
|
||||
"Description",
|
||||
"Owner",
|
||||
"Location",
|
||||
"Tags",
|
||||
"Usage Summary",
|
||||
"Followers",
|
||||
"Sample Data",
|
||||
"Synonyms",
|
||||
"Glossary",
|
||||
"Test Case Result Success",
|
||||
"Test Case Result Failed",
|
||||
"Test Case Result Aborted"
|
||||
],
|
||||
"javaEnums": [
|
||||
{
|
||||
"name": "all"
|
||||
},
|
||||
{
|
||||
"name": "displayName"
|
||||
},
|
||||
{
|
||||
"name": "description"
|
||||
},
|
||||
{
|
||||
"name": "owner"
|
||||
},
|
||||
{
|
||||
"name": "location"
|
||||
},
|
||||
{
|
||||
"name": "tags"
|
||||
},
|
||||
{
|
||||
"name": "usageSummary"
|
||||
},
|
||||
{
|
||||
"name": "followers"
|
||||
},
|
||||
{
|
||||
"name": "sampleData"
|
||||
},
|
||||
{
|
||||
"name": "synonyms"
|
||||
},
|
||||
{
|
||||
"name": "glossary"
|
||||
},
|
||||
{
|
||||
"name": "testCaseResultSuccess"
|
||||
},
|
||||
{
|
||||
"name": "testCaseResultFailure"
|
||||
},
|
||||
{
|
||||
"name": "testCaseResultAborted"
|
||||
}
|
||||
]
|
||||
},
|
||||
"filters": {
|
||||
"type": "object",
|
||||
"javaType": "org.openmetadata.catalog.filter.Filters",
|
||||
@ -25,14 +159,23 @@
|
||||
"description": "Event type that is being requested.",
|
||||
"$ref": "#/definitions/eventType"
|
||||
},
|
||||
"fields": {
|
||||
"description": "Field on which to apply the filter on",
|
||||
"include": {
|
||||
"description": "Field which are allowed to pass",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": ["all"],
|
||||
"uniqueItems": true
|
||||
},
|
||||
"exclude": {
|
||||
"description": "Field which are not allowed to pass",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": [],
|
||||
"uniqueItems": true
|
||||
}
|
||||
},
|
||||
"required": ["eventType"],
|
||||
|
@ -22,7 +22,6 @@ import static org.openmetadata.catalog.util.EntityUtil.fieldDeleted;
|
||||
import static org.openmetadata.catalog.util.EntityUtil.fieldUpdated;
|
||||
import static org.openmetadata.catalog.util.TestUtils.ADMIN_AUTH_HEADERS;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
@ -65,16 +64,14 @@ public class WebhookResourceTest extends EntityResourceTest<Webhook, CreateWebho
|
||||
allEntityFilter.setEntityType("all");
|
||||
allEntityFilter.setFilters(
|
||||
List.of(
|
||||
new Filters().withEventType(EventType.ENTITY_CREATED).withFields(allFilter),
|
||||
new Filters().withEventType(EventType.ENTITY_UPDATED).withFields(allFilter),
|
||||
new Filters().withEventType(EventType.ENTITY_DELETED).withFields(allFilter),
|
||||
new Filters().withEventType(EventType.ENTITY_SOFT_DELETED).withFields(allFilter)));
|
||||
new Filters().withEventType(EventType.ENTITY_CREATED).withInclude(allFilter).withExclude(new HashSet<>()),
|
||||
new Filters().withEventType(EventType.ENTITY_UPDATED).withInclude(allFilter).withExclude(new HashSet<>()),
|
||||
new Filters().withEventType(EventType.ENTITY_DELETED).withInclude(allFilter).withExclude(new HashSet<>()),
|
||||
new Filters()
|
||||
.withEventType(EventType.ENTITY_SOFT_DELETED)
|
||||
.withInclude(allFilter)
|
||||
.withExclude(new HashSet<>())));
|
||||
ALL_EVENTS_FILTER.add(allEntityFilter);
|
||||
try {
|
||||
System.out.println(JsonUtils.pojoToJson(ALL_EVENTS_FILTER));
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public WebhookResourceTest() {
|
||||
@ -189,9 +186,12 @@ public class WebhookResourceTest extends EntityResourceTest<Webhook, CreateWebho
|
||||
Set<String> allFilter = new HashSet<>();
|
||||
allFilter.add("all");
|
||||
|
||||
Filters createFilter = new Filters().withEventType(EventType.ENTITY_CREATED).withFields(allFilter);
|
||||
Filters updateFilter = new Filters().withEventType(EventType.ENTITY_UPDATED).withFields(allFilter);
|
||||
Filters deleteFilter = new Filters().withEventType(EventType.ENTITY_DELETED).withFields(allFilter);
|
||||
Filters createFilter =
|
||||
new Filters().withEventType(EventType.ENTITY_CREATED).withInclude(allFilter).withExclude(new HashSet<>());
|
||||
Filters updateFilter =
|
||||
new Filters().withEventType(EventType.ENTITY_UPDATED).withInclude(allFilter).withExclude(new HashSet<>());
|
||||
Filters deleteFilter =
|
||||
new Filters().withEventType(EventType.ENTITY_DELETED).withInclude(allFilter).withExclude(new HashSet<>());
|
||||
|
||||
EventFilter f1 = new EventFilter().withEntityType("all").withFilters(List.of(createFilter));
|
||||
EventFilter f2 =
|
||||
@ -300,16 +300,18 @@ public class WebhookResourceTest extends EntityResourceTest<Webhook, CreateWebho
|
||||
String name = EventType.ENTITY_CREATED + ":" + entity;
|
||||
String uri = baseUri + "/" + EventType.ENTITY_CREATED + "/" + entity;
|
||||
|
||||
Set<String> allFiler = new HashSet<>();
|
||||
allFiler.add("all");
|
||||
Filters createFilter = new Filters().withEventType(EventType.ENTITY_CREATED).withFields(allFiler);
|
||||
Set<String> allFilter = new HashSet<>();
|
||||
allFilter.add("all");
|
||||
Filters createFilter =
|
||||
new Filters().withEventType(EventType.ENTITY_CREATED).withInclude(allFilter).withExclude(new HashSet<>());
|
||||
EventFilter f1 = new EventFilter().withEntityType(entity).withFilters(List.of(createFilter));
|
||||
createWebhook(name, uri, List.of(f1));
|
||||
|
||||
// Create webhook with endpoint api/v1/test/webhook/entityUpdated/<entity> to receive entityUpdated events
|
||||
name = EventType.ENTITY_UPDATED + ":" + entity;
|
||||
uri = baseUri + "/" + EventType.ENTITY_UPDATED + "/" + entity;
|
||||
Filters updateFilter = new Filters().withEventType(EventType.ENTITY_UPDATED).withFields(allFiler);
|
||||
Filters updateFilter =
|
||||
new Filters().withEventType(EventType.ENTITY_UPDATED).withInclude(allFilter).withExclude(new HashSet<>());
|
||||
EventFilter f2 = new EventFilter().withEntityType(entity).withFilters(List.of(updateFilter));
|
||||
createWebhook(name, uri, List.of(f2));
|
||||
|
||||
|
@ -90,19 +90,23 @@ const mockData = {
|
||||
filters: [
|
||||
{
|
||||
eventType: 'entityCreated',
|
||||
fields: ['all'],
|
||||
include: ['all'],
|
||||
exclude: [],
|
||||
},
|
||||
{
|
||||
eventType: 'entityUpdated',
|
||||
fields: ['all'],
|
||||
include: ['all'],
|
||||
exclude: [],
|
||||
},
|
||||
{
|
||||
eventType: 'entityDeleted',
|
||||
fields: ['all'],
|
||||
include: ['all'],
|
||||
exclude: [],
|
||||
},
|
||||
{
|
||||
eventType: 'entitySoftDeleted',
|
||||
fields: ['all'],
|
||||
include: ['all'],
|
||||
exclude: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -38,8 +38,8 @@ const EventFilterSelect = ({
|
||||
metric === EventType.EntityUpdated
|
||||
? Object.values(EventUpdateTypes).map((updateType) => ({
|
||||
title: startCase(updateType),
|
||||
value: updateType,
|
||||
key: updateType,
|
||||
value: `${EventType.EntityUpdated}-${updateType}`,
|
||||
key: `${EventType.EntityUpdated}-${updateType}`,
|
||||
}))
|
||||
: undefined,
|
||||
})),
|
||||
|
@ -34,19 +34,23 @@ export const EVENT_FILTERS_DEFAULT_VALUE = {
|
||||
filters: [
|
||||
{
|
||||
eventType: 'entityCreated',
|
||||
fields: ['all'],
|
||||
include: ['all'],
|
||||
exclude: [],
|
||||
},
|
||||
{
|
||||
eventType: 'entityUpdated',
|
||||
fields: ['all'],
|
||||
include: ['all'],
|
||||
exclude: [],
|
||||
},
|
||||
{
|
||||
eventType: 'entityDeleted',
|
||||
fields: ['all'],
|
||||
include: ['all'],
|
||||
exclude: [],
|
||||
},
|
||||
{
|
||||
eventType: 'entitySoftDeleted',
|
||||
fields: ['all'],
|
||||
include: ['all'],
|
||||
exclude: [],
|
||||
},
|
||||
],
|
||||
} as EventFilter;
|
||||
|
@ -3,19 +3,23 @@ import { Filters } from '../../generated/settings/settings';
|
||||
export const formData = [
|
||||
{
|
||||
eventType: 'entityCreated',
|
||||
fields: [],
|
||||
include: [],
|
||||
exclude: [],
|
||||
},
|
||||
{
|
||||
eventType: 'entityUpdated',
|
||||
fields: [],
|
||||
include: [],
|
||||
exclude: [],
|
||||
},
|
||||
{
|
||||
eventType: 'entitySoftDeleted',
|
||||
fields: [],
|
||||
include: [],
|
||||
exclude: [],
|
||||
},
|
||||
{
|
||||
eventType: 'entityDeleted',
|
||||
fields: [],
|
||||
include: [],
|
||||
exclude: [],
|
||||
},
|
||||
] as Filters[];
|
||||
|
||||
@ -25,4 +29,5 @@ export const ActivityFeedEntity = {
|
||||
dashboard: 'Dashboard',
|
||||
pipeline: 'Pipeline',
|
||||
mlmodel: 'ML Model',
|
||||
testCase: 'Test Case',
|
||||
} as Record<string, string>;
|
||||
|
@ -93,13 +93,13 @@ const ActivityFeedSettingsPage: React.FC = () => {
|
||||
};
|
||||
|
||||
const generateTreeData = (entityType: string, data?: Filters[]) => {
|
||||
return data?.map(({ eventType, fields }) => {
|
||||
return data?.map(({ eventType, include }) => {
|
||||
const key = `${entityType}-${eventType}` as string;
|
||||
|
||||
return {
|
||||
key: key,
|
||||
title: startCase(eventType),
|
||||
data: fields,
|
||||
data: include,
|
||||
children:
|
||||
eventType === 'entityUpdated'
|
||||
? [
|
||||
@ -133,13 +133,13 @@ const ActivityFeedSettingsPage: React.FC = () => {
|
||||
filters &&
|
||||
filters.map((obj) => {
|
||||
if (
|
||||
obj?.fields &&
|
||||
obj.fields.length === 1 &&
|
||||
obj.fields[0] === 'all'
|
||||
obj.include &&
|
||||
obj.include.length === 1 &&
|
||||
obj.include[0] === 'all'
|
||||
) {
|
||||
checkedArray.push(`${entityType}-${obj.eventType}`);
|
||||
} else {
|
||||
obj?.fields?.forEach((entityUpdated) => {
|
||||
obj?.include?.forEach((entityUpdated) => {
|
||||
const name = `${entityType}-${obj.eventType}-${entityUpdated}`;
|
||||
checkedArray.push(name);
|
||||
});
|
||||
|
@ -1,5 +1,8 @@
|
||||
import { isEmpty, isUndefined } from 'lodash';
|
||||
import { Filters } from '../../generated/settings/settings';
|
||||
import { getDiffArray } from '../../utils/CommonUtils';
|
||||
|
||||
const entityUpdatedFields = ['description', 'owner', 'tags', 'followers'];
|
||||
|
||||
export const getPayloadFromSelected = (
|
||||
selectedOptions: Record<string, string[]>,
|
||||
@ -25,7 +28,8 @@ export const getPayloadFromSelected = (
|
||||
...valueAcc,
|
||||
{
|
||||
eventType: selected[1],
|
||||
fields: ['all'],
|
||||
include: ['all'],
|
||||
exclude: [],
|
||||
},
|
||||
];
|
||||
} else {
|
||||
@ -39,11 +43,14 @@ export const getPayloadFromSelected = (
|
||||
resultArr.push(...arr[0]);
|
||||
|
||||
if (!isUndefined(nonUpdatedFields) && !isEmpty(nonUpdatedFields)) {
|
||||
const selectedUpdatedData = nonUpdatedFields.filter(
|
||||
(name) => !isUndefined(name) || (!isEmpty(name) && name)
|
||||
);
|
||||
|
||||
resultArr.push({
|
||||
eventType: 'entityUpdated',
|
||||
fields: nonUpdatedFields.filter(
|
||||
(name) => !isUndefined(name) || (!isEmpty(name) && name)
|
||||
),
|
||||
include: selectedUpdatedData,
|
||||
exclude: getDiffArray(entityUpdatedFields, selectedUpdatedData),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,15 @@
|
||||
import { Popover } from 'antd';
|
||||
import { AxiosError } from 'axios';
|
||||
import classNames from 'classnames';
|
||||
import { capitalize, isEmpty, isNil, isNull, isUndefined } from 'lodash';
|
||||
import {
|
||||
capitalize,
|
||||
differenceWith,
|
||||
isEmpty,
|
||||
isEqual,
|
||||
isNil,
|
||||
isNull,
|
||||
isUndefined,
|
||||
} from 'lodash';
|
||||
import {
|
||||
EntityFieldThreadCount,
|
||||
ExtraInfo,
|
||||
@ -879,3 +887,10 @@ export const getIngestionStatuses = (ingestion: IngestionPipeline) => {
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
export const getDiffArray = (
|
||||
compareWith: string[],
|
||||
toCompare: string[]
|
||||
): string[] => {
|
||||
return differenceWith(compareWith, toCompare, isEqual);
|
||||
};
|
||||
|
@ -1,11 +1,15 @@
|
||||
import { Store } from 'antd/lib/form/interface';
|
||||
import { isEqual } from 'lodash';
|
||||
import { isEqual, isUndefined } from 'lodash';
|
||||
import {
|
||||
EVENT_FILTERS_DEFAULT_VALUE,
|
||||
EVENT_FILTER_FORM_INITIAL_VALUE,
|
||||
} from '../components/AddWebhook/WebhookConstants';
|
||||
import { TERM_ALL } from '../constants/constants';
|
||||
import { EventFilter, Filters } from '../generated/entity/events/webhook';
|
||||
import {
|
||||
EventFilter,
|
||||
EventType,
|
||||
Filters,
|
||||
} from '../generated/entity/events/webhook';
|
||||
|
||||
export const getEventFilters = (data: Store): EventFilter[] => {
|
||||
if (isEqual(data, EVENT_FILTER_FORM_INITIAL_VALUE)) {
|
||||
@ -18,17 +22,39 @@ export const getEventFilters = (data: Store): EventFilter[] => {
|
||||
}
|
||||
if (value) {
|
||||
const selectedFilter = data[`${key}-tree`] as string[];
|
||||
const entityUpdatedFields = selectedFilter
|
||||
?.map((filter) =>
|
||||
filter.includes(`${EventType.EntityUpdated}-`)
|
||||
? filter.split('-')[1]
|
||||
: undefined
|
||||
)
|
||||
.filter((filter) => filter);
|
||||
|
||||
const eventFilters = [
|
||||
...selectedFilter.filter(
|
||||
(filter) => !filter.includes(`${EventType.EntityUpdated}-`)
|
||||
),
|
||||
entityUpdatedFields ? EventType.EntityUpdated : undefined,
|
||||
];
|
||||
|
||||
const includeData = (entityUpdatedFields as string[]).filter(
|
||||
(entityUpdatedField) => !isUndefined(entityUpdatedField)
|
||||
);
|
||||
|
||||
return [
|
||||
...acc,
|
||||
{
|
||||
entityType: key,
|
||||
filters:
|
||||
selectedFilter[0] === TERM_ALL
|
||||
eventFilters[0] === TERM_ALL
|
||||
? EVENT_FILTERS_DEFAULT_VALUE.filters
|
||||
: (selectedFilter.map((filter) => ({
|
||||
: (eventFilters.map((filter) => ({
|
||||
eventType: filter,
|
||||
fields: [TERM_ALL],
|
||||
include:
|
||||
filter === EventType.EntityUpdated
|
||||
? includeData
|
||||
: [TERM_ALL],
|
||||
exclude: [],
|
||||
})) as Filters[]),
|
||||
},
|
||||
];
|
||||
|
Loading…
x
Reference in New Issue
Block a user