mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-12-03 19:16:10 +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.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.json.JsonPatch;
|
||||
import javax.ws.rs.core.Response;
|
||||
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.resources.feeds.MessageParser;
|
||||
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.Authorizer;
|
||||
import org.openmetadata.service.security.policyevaluator.OperationContext;
|
||||
import org.openmetadata.service.security.policyevaluator.ResourceContext;
|
||||
import org.openmetadata.service.util.EntityUtil;
|
||||
import org.openmetadata.service.util.FullyQualifiedName;
|
||||
import org.openmetadata.service.util.JsonUtils;
|
||||
import org.openmetadata.service.util.RestUtil;
|
||||
import org.openmetadata.service.util.ResultList;
|
||||
@ -172,8 +176,7 @@ public class SuggestionRepository {
|
||||
entity, entityLink.getFullyQualifiedFieldValue(), suggestion);
|
||||
} else {
|
||||
if (suggestion.getType().equals(SuggestionType.SuggestTagLabel)) {
|
||||
List<TagLabel> tags = new ArrayList<>(entity.getTags());
|
||||
tags.addAll(suggestion.getTagLabels());
|
||||
List<TagLabel> tags = mergeTags(entity.getTags(), suggestion.getTagLabels());
|
||||
entity.setTags(tags);
|
||||
return entity;
|
||||
} 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(
|
||||
UriInfo uriInfo,
|
||||
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.PERSONAL_DATA_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.util.TestUtils.ADMIN_AUTH_HEADERS;
|
||||
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)
|
||||
throws HttpResponseException {
|
||||
return TestUtils.post(getResource("suggestions"), create, Suggestion.class, authHeaders);
|
||||
@ -552,6 +585,13 @@ public class SuggestionsResourceTest extends OpenMetadataApplicationTest {
|
||||
.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)
|
||||
throws HttpResponseException {
|
||||
WebTarget target = getResource("suggestions/" + id);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user