mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-12-06 04:25:20 +00:00
parent
96e75373d0
commit
55b945bbb6
@ -15,7 +15,9 @@ import static org.openmetadata.service.jdbi3.UserRepository.TEAMS_FIELD;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import javax.json.JsonPatch;
|
import javax.json.JsonPatch;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.SecurityContext;
|
import javax.ws.rs.core.SecurityContext;
|
||||||
@ -39,11 +41,13 @@ import org.openmetadata.service.exception.CatalogExceptionMessage;
|
|||||||
import org.openmetadata.service.exception.EntityNotFoundException;
|
import org.openmetadata.service.exception.EntityNotFoundException;
|
||||||
import org.openmetadata.service.resources.feeds.MessageParser;
|
import org.openmetadata.service.resources.feeds.MessageParser;
|
||||||
import org.openmetadata.service.resources.feeds.SuggestionsResource;
|
import org.openmetadata.service.resources.feeds.SuggestionsResource;
|
||||||
|
import org.openmetadata.service.resources.tags.TagLabelUtil;
|
||||||
import org.openmetadata.service.security.AuthorizationException;
|
import org.openmetadata.service.security.AuthorizationException;
|
||||||
import org.openmetadata.service.security.Authorizer;
|
import org.openmetadata.service.security.Authorizer;
|
||||||
import org.openmetadata.service.security.policyevaluator.OperationContext;
|
import org.openmetadata.service.security.policyevaluator.OperationContext;
|
||||||
import org.openmetadata.service.security.policyevaluator.ResourceContext;
|
import org.openmetadata.service.security.policyevaluator.ResourceContext;
|
||||||
import org.openmetadata.service.util.EntityUtil;
|
import org.openmetadata.service.util.EntityUtil;
|
||||||
|
import org.openmetadata.service.util.FullyQualifiedName;
|
||||||
import org.openmetadata.service.util.JsonUtils;
|
import org.openmetadata.service.util.JsonUtils;
|
||||||
import org.openmetadata.service.util.RestUtil;
|
import org.openmetadata.service.util.RestUtil;
|
||||||
import org.openmetadata.service.util.ResultList;
|
import org.openmetadata.service.util.ResultList;
|
||||||
@ -172,8 +176,7 @@ public class SuggestionRepository {
|
|||||||
entity, entityLink.getFullyQualifiedFieldValue(), suggestion);
|
entity, entityLink.getFullyQualifiedFieldValue(), suggestion);
|
||||||
} else {
|
} else {
|
||||||
if (suggestion.getType().equals(SuggestionType.SuggestTagLabel)) {
|
if (suggestion.getType().equals(SuggestionType.SuggestTagLabel)) {
|
||||||
List<TagLabel> tags = new ArrayList<>(entity.getTags());
|
List<TagLabel> tags = mergeTags(entity.getTags(), suggestion.getTagLabels());
|
||||||
tags.addAll(suggestion.getTagLabels());
|
|
||||||
entity.setTags(tags);
|
entity.setTags(tags);
|
||||||
return entity;
|
return entity;
|
||||||
} else if (suggestion.getType().equals(SuggestionType.SuggestDescription)) {
|
} else if (suggestion.getType().equals(SuggestionType.SuggestDescription)) {
|
||||||
@ -186,6 +189,50 @@ public class SuggestionRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static List<TagLabel> mergeTags(
|
||||||
|
List<TagLabel> existingTags, List<TagLabel> incomingTags) {
|
||||||
|
if (incomingTags == null || incomingTags.isEmpty()) {
|
||||||
|
return existingTags;
|
||||||
|
}
|
||||||
|
// Throw an error if incoming tags are mutually exclusive
|
||||||
|
TagLabelUtil.checkMutuallyExclusive(incomingTags);
|
||||||
|
|
||||||
|
ArrayList<TagLabel> tags = new ArrayList<>();
|
||||||
|
Set<String> incomingClassification =
|
||||||
|
incomingTags.stream()
|
||||||
|
.map(t -> FullyQualifiedName.getParentFQN(t.getTagFQN()))
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
// We'll give priority to incoming tags over existing tags
|
||||||
|
// so we'll skip any existing tag that is mutually exclusive and clashing with incoming
|
||||||
|
// classification
|
||||||
|
for (TagLabel tag : existingTags) {
|
||||||
|
if (TagLabelUtil.mutuallyExclusive(tag)
|
||||||
|
&& incomingClassification.contains(FullyQualifiedName.getParentFQN(tag.getTagFQN()))) {
|
||||||
|
LOG.debug(
|
||||||
|
String.format(
|
||||||
|
"Incoming tags are mutually exclusive with existing tag [%s]", tag.getTagFQN()));
|
||||||
|
} else {
|
||||||
|
tags.add(tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return naiveMergeTags(tags, incomingTags);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add all tags without repeats
|
||||||
|
private static List<TagLabel> naiveMergeTags(
|
||||||
|
List<TagLabel> existingTags, List<TagLabel> incomingTags) {
|
||||||
|
List<TagLabel> tags = new ArrayList<>(existingTags);
|
||||||
|
Set<String> existingTagFQNs =
|
||||||
|
existingTags.stream().map(TagLabel::getTagFQN).collect(Collectors.toSet());
|
||||||
|
for (TagLabel incomingTag : incomingTags) {
|
||||||
|
if (!existingTagFQNs.contains(incomingTag.getTagFQN())) {
|
||||||
|
tags.add(incomingTag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
|
||||||
public RestUtil.PutResponse<Suggestion> acceptSuggestion(
|
public RestUtil.PutResponse<Suggestion> acceptSuggestion(
|
||||||
UriInfo uriInfo,
|
UriInfo uriInfo,
|
||||||
Suggestion suggestion,
|
Suggestion suggestion,
|
||||||
|
|||||||
@ -12,6 +12,8 @@ import static org.openmetadata.service.resources.EntityResourceTest.C1;
|
|||||||
import static org.openmetadata.service.resources.EntityResourceTest.C2;
|
import static org.openmetadata.service.resources.EntityResourceTest.C2;
|
||||||
import static org.openmetadata.service.resources.EntityResourceTest.PERSONAL_DATA_TAG_LABEL;
|
import static org.openmetadata.service.resources.EntityResourceTest.PERSONAL_DATA_TAG_LABEL;
|
||||||
import static org.openmetadata.service.resources.EntityResourceTest.PII_SENSITIVE_TAG_LABEL;
|
import static org.openmetadata.service.resources.EntityResourceTest.PII_SENSITIVE_TAG_LABEL;
|
||||||
|
import static org.openmetadata.service.resources.EntityResourceTest.TIER1_TAG_LABEL;
|
||||||
|
import static org.openmetadata.service.resources.EntityResourceTest.TIER2_TAG_LABEL;
|
||||||
import static org.openmetadata.service.security.SecurityUtil.authHeaders;
|
import static org.openmetadata.service.security.SecurityUtil.authHeaders;
|
||||||
import static org.openmetadata.service.util.TestUtils.ADMIN_AUTH_HEADERS;
|
import static org.openmetadata.service.util.TestUtils.ADMIN_AUTH_HEADERS;
|
||||||
import static org.openmetadata.service.util.TestUtils.assertResponse;
|
import static org.openmetadata.service.util.TestUtils.assertResponse;
|
||||||
@ -528,6 +530,37 @@ public class SuggestionsResourceTest extends OpenMetadataApplicationTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(6)
|
||||||
|
void put_acceptSuggestion_mutuallyExclusiveTags_200(TestInfo test) throws IOException {
|
||||||
|
TableResourceTest tableResourceTest = new TableResourceTest();
|
||||||
|
CreateTable createTable = tableResourceTest.createRequest(test);
|
||||||
|
Table table = tableResourceTest.createAndCheckEntity(createTable, ADMIN_AUTH_HEADERS);
|
||||||
|
MessageParser.EntityLink entityLink =
|
||||||
|
new MessageParser.EntityLink(Entity.TABLE, table.getFullyQualifiedName());
|
||||||
|
|
||||||
|
CreateSuggestion create = createTierSuggestion(TIER1_TAG_LABEL, entityLink);
|
||||||
|
Suggestion suggestion = createSuggestion(create, USER_AUTH_HEADERS);
|
||||||
|
Assertions.assertEquals(create.getEntityLink(), suggestion.getEntityLink());
|
||||||
|
|
||||||
|
// When accepting the suggestion, we'll get the Tier1 tag applied to the table
|
||||||
|
acceptSuggestion(suggestion.getId(), USER_AUTH_HEADERS);
|
||||||
|
table = tableResourceTest.getEntity(table.getId(), "tags", USER_AUTH_HEADERS);
|
||||||
|
List<TagLabel> expectedTags = new ArrayList<>(table.getTags());
|
||||||
|
expectedTags.addAll(suggestion.getTagLabels());
|
||||||
|
validateAppliedTags(expectedTags, table.getTags());
|
||||||
|
|
||||||
|
// Not, let's try to apply the Tier2 tag, which is mutually exclusive with the Tier1 tag
|
||||||
|
// The table should then only have the Tier2
|
||||||
|
create = createTierSuggestion(TIER2_TAG_LABEL, entityLink);
|
||||||
|
suggestion = createSuggestion(create, USER_AUTH_HEADERS);
|
||||||
|
acceptSuggestion(suggestion.getId(), USER_AUTH_HEADERS);
|
||||||
|
table = tableResourceTest.getEntity(table.getId(), "tags", USER_AUTH_HEADERS);
|
||||||
|
expectedTags = new ArrayList<>(table.getTags());
|
||||||
|
expectedTags.addAll(suggestion.getTagLabels());
|
||||||
|
validateAppliedTags(expectedTags, table.getTags());
|
||||||
|
}
|
||||||
|
|
||||||
public Suggestion createSuggestion(CreateSuggestion create, Map<String, String> authHeaders)
|
public Suggestion createSuggestion(CreateSuggestion create, Map<String, String> authHeaders)
|
||||||
throws HttpResponseException {
|
throws HttpResponseException {
|
||||||
return TestUtils.post(getResource("suggestions"), create, Suggestion.class, authHeaders);
|
return TestUtils.post(getResource("suggestions"), create, Suggestion.class, authHeaders);
|
||||||
@ -552,6 +585,13 @@ public class SuggestionsResourceTest extends OpenMetadataApplicationTest {
|
|||||||
.withEntityLink(TABLE_LINK);
|
.withEntityLink(TABLE_LINK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CreateSuggestion createTierSuggestion(TagLabel tier, MessageParser.EntityLink entityLink) {
|
||||||
|
return new CreateSuggestion()
|
||||||
|
.withTagLabels(List.of(tier))
|
||||||
|
.withType(SuggestionType.SuggestTagLabel)
|
||||||
|
.withEntityLink(entityLink.getLinkString());
|
||||||
|
}
|
||||||
|
|
||||||
public Suggestion getSuggestion(UUID id, Map<String, String> authHeaders)
|
public Suggestion getSuggestion(UUID id, Map<String, String> authHeaders)
|
||||||
throws HttpResponseException {
|
throws HttpResponseException {
|
||||||
WebTarget target = getResource("suggestions/" + id);
|
WebTarget target = getResource("suggestions/" + id);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user