Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Worked on the feature to update group title #6047

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -761,7 +761,7 @@ private void configureMutationResolvers(final RuntimeWiring.Builder builder) {
.dataFetcher("removeUser", new RemoveUserResolver(this.entityClient))
.dataFetcher("removeGroup", new RemoveGroupResolver(this.entityClient))
.dataFetcher("updateUserStatus", new UpdateUserStatusResolver(this.entityClient))
.dataFetcher("createDomain", new CreateDomainResolver(this.entityClient))
.dataFetcher("createDomain", new CreateDomainResolver(this.entityClient, this.entityService))
.dataFetcher("deleteDomain", new DeleteDomainResolver(entityClient))
.dataFetcher("setDomain", new SetDomainResolver(this.entityClient, this.entityService))
.dataFetcher("batchSetDomain", new BatchSetDomainResolver(this.entityService))
Expand All @@ -783,8 +783,8 @@ private void configureMutationResolvers(final RuntimeWiring.Builder builder) {
.dataFetcher("updateTest", new UpdateTestResolver(this.entityClient))
.dataFetcher("deleteTest", new DeleteTestResolver(this.entityClient))
.dataFetcher("reportOperation", new ReportOperationResolver(this.entityClient))
.dataFetcher("createGlossaryTerm", new CreateGlossaryTermResolver(this.entityClient))
.dataFetcher("createGlossaryNode", new CreateGlossaryNodeResolver(this.entityClient))
.dataFetcher("createGlossaryTerm", new CreateGlossaryTermResolver(this.entityClient, this.entityService))
.dataFetcher("createGlossaryNode", new CreateGlossaryNodeResolver(this.entityClient, this.entityService))
.dataFetcher("updateParentNode", new UpdateParentNodeResolver(entityService))
.dataFetcher("deleteGlossaryEntity",
new DeleteGlossaryEntityResolver(this.entityClient, this.entityService))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@
import com.linkedin.datahub.graphql.authorization.AuthorizationUtils;
import com.linkedin.datahub.graphql.exception.AuthorizationException;
import com.linkedin.datahub.graphql.generated.CreateDomainInput;
import com.linkedin.datahub.graphql.generated.OwnerEntityType;
import com.linkedin.datahub.graphql.generated.OwnershipType;
import com.linkedin.datahub.graphql.resolvers.mutate.util.OwnerUtils;
import com.linkedin.domain.DomainProperties;
import com.linkedin.entity.client.EntityClient;
import com.linkedin.events.metadata.ChangeType;
import com.linkedin.metadata.entity.EntityService;
import com.linkedin.metadata.Constants;
import com.linkedin.metadata.key.DomainKey;
import com.linkedin.metadata.utils.EntityKeyUtils;
Expand All @@ -30,6 +34,7 @@
public class CreateDomainResolver implements DataFetcher<CompletableFuture<String>> {

private final EntityClient _entityClient;
private final EntityService _entityService;

@Override
public CompletableFuture<String> get(DataFetchingEnvironment environment) throws Exception {
Expand Down Expand Up @@ -63,7 +68,9 @@ public CompletableFuture<String> get(DataFetchingEnvironment environment) throws
proposal.setAspect(GenericRecordUtils.serializeAspect(mapDomainProperties(input)));
proposal.setChangeType(ChangeType.UPSERT);

return _entityClient.ingestProposal(proposal, context.getAuthentication());
String domainUrn = _entityClient.ingestProposal(proposal, context.getAuthentication());
OwnerUtils.addCreatorAsOwner(context, domainUrn, OwnerEntityType.CORP_USER, OwnershipType.TECHNICAL_OWNER, _entityService);
return domainUrn;
} catch (Exception e) {
log.error("Failed to create Domain with id: {}, name: {}: {}", input.getId(), input.getName(), e.getMessage());
throw new RuntimeException(String.format("Failed to create Domain with id: %s, name: %s", input.getId(), input.getName()), e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@
import com.linkedin.datahub.graphql.authorization.AuthorizationUtils;
import com.linkedin.datahub.graphql.exception.AuthorizationException;
import com.linkedin.datahub.graphql.generated.CreateGlossaryEntityInput;
import com.linkedin.datahub.graphql.generated.OwnerEntityType;
import com.linkedin.datahub.graphql.generated.OwnershipType;
import com.linkedin.datahub.graphql.resolvers.mutate.util.OwnerUtils;
import com.linkedin.entity.client.EntityClient;
import com.linkedin.events.metadata.ChangeType;
import com.linkedin.glossary.GlossaryNodeInfo;
import com.linkedin.metadata.entity.EntityService;
import com.linkedin.metadata.Constants;
import com.linkedin.metadata.key.GlossaryNodeKey;
import com.linkedin.metadata.utils.EntityKeyUtils;
Expand All @@ -30,6 +34,7 @@
public class CreateGlossaryNodeResolver implements DataFetcher<CompletableFuture<String>> {

private final EntityClient _entityClient;
private final EntityService _entityService;

@Override
public CompletableFuture<String> get(DataFetchingEnvironment environment) throws Exception {
Expand All @@ -56,7 +61,9 @@ public CompletableFuture<String> get(DataFetchingEnvironment environment) throws
proposal.setAspect(GenericRecordUtils.serializeAspect(mapGlossaryNodeInfo(input)));
proposal.setChangeType(ChangeType.UPSERT);

return _entityClient.ingestProposal(proposal, context.getAuthentication());
String glossaryNodeUrn = _entityClient.ingestProposal(proposal, context.getAuthentication());
OwnerUtils.addCreatorAsOwner(context, glossaryNodeUrn, OwnerEntityType.CORP_USER, OwnershipType.TECHNICAL_OWNER, _entityService);
return glossaryNodeUrn;
} catch (Exception e) {
log.error("Failed to create GlossaryNode with id: {}, name: {}: {}", input.getId(), input.getName(), e.getMessage());
throw new RuntimeException(String.format("Failed to create GlossaryNode with id: %s, name: %s", input.getId(), input.getName()), e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@
import com.linkedin.datahub.graphql.authorization.AuthorizationUtils;
import com.linkedin.datahub.graphql.exception.AuthorizationException;
import com.linkedin.datahub.graphql.generated.CreateGlossaryEntityInput;
import com.linkedin.datahub.graphql.generated.OwnerEntityType;
import com.linkedin.datahub.graphql.generated.OwnershipType;
import com.linkedin.datahub.graphql.resolvers.mutate.util.OwnerUtils;
import com.linkedin.entity.client.EntityClient;
import com.linkedin.events.metadata.ChangeType;
import com.linkedin.glossary.GlossaryTermInfo;
import com.linkedin.metadata.entity.EntityService;
import com.linkedin.metadata.Constants;
import com.linkedin.metadata.key.GlossaryTermKey;
import com.linkedin.metadata.utils.EntityKeyUtils;
Expand All @@ -30,6 +34,7 @@
public class CreateGlossaryTermResolver implements DataFetcher<CompletableFuture<String>> {

private final EntityClient _entityClient;
private final EntityService _entityService;

@Override
public CompletableFuture<String> get(DataFetchingEnvironment environment) throws Exception {
Expand All @@ -56,7 +61,9 @@ public CompletableFuture<String> get(DataFetchingEnvironment environment) throws
proposal.setAspect(GenericRecordUtils.serializeAspect(mapGlossaryTermInfo(input)));
proposal.setChangeType(ChangeType.UPSERT);

return _entityClient.ingestProposal(proposal, context.getAuthentication());
String glossaryTermUrn = _entityClient.ingestProposal(proposal, context.getAuthentication());
OwnerUtils.addCreatorAsOwner(context, glossaryTermUrn, OwnerEntityType.CORP_USER, OwnershipType.TECHNICAL_OWNER, _entityService);
return glossaryTermUrn;
} catch (Exception e) {
log.error("Failed to create GlossaryTerm with id: {}, name: {}: {}", input.getId(), input.getName(), e.getMessage());
throw new RuntimeException(String.format("Failed to create GlossaryTerm with id: %s, name: %s", input.getId(), input.getName()), e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.linkedin.domain.DomainProperties;
import com.linkedin.glossary.GlossaryTermInfo;
import com.linkedin.glossary.GlossaryNodeInfo;
import com.linkedin.identity.CorpGroupInfo;
import com.linkedin.metadata.Constants;
import com.linkedin.metadata.entity.EntityService;
import graphql.schema.DataFetcher;
Expand Down Expand Up @@ -47,6 +48,8 @@ public CompletableFuture<Boolean> get(DataFetchingEnvironment environment) throw
return updateGlossaryNodeName(targetUrn, input, environment.getContext());
case Constants.DOMAIN_ENTITY_NAME:
return updateDomainName(targetUrn, input, environment.getContext());
case Constants.CORP_GROUP_ENTITY_NAME:
return updateGroupName(targetUrn, input, environment.getContext());
default:
throw new RuntimeException(
String.format("Failed to update name. Unsupported resource type %s provided.", targetUrn));
Expand Down Expand Up @@ -125,4 +128,28 @@ private Boolean updateDomainName(
}
throw new AuthorizationException("Unauthorized to perform this action. Please contact your DataHub administrator.");
}

private Boolean updateGroupName(
Urn targetUrn,
UpdateNameInput input,
QueryContext context
) {
if (AuthorizationUtils.canManageUsersAndGroups(context)) {
try {
CorpGroupInfo corpGroupInfo = (CorpGroupInfo) getAspectFromEntity(
targetUrn.toString(), Constants.CORP_GROUP_INFO_ASPECT_NAME, _entityService, null);
if (corpGroupInfo == null) {
throw new IllegalArgumentException("Group does not exist");
}
corpGroupInfo.setDisplayName(input.getName());
Urn actor = CorpuserUrn.createFromString(context.getActorUrn());
persistAspect(targetUrn, Constants.CORP_GROUP_INFO_ASPECT_NAME, corpGroupInfo, actor, _entityService);

return true;
} catch (Exception e) {
throw new RuntimeException(String.format("Failed to perform update against input %s", input), e);
}
}
throw new AuthorizationException("Unauthorized to perform this action. Please contact your DataHub administrator.");
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.linkedin.datahub.graphql.resolvers.mutate.util;

import com.google.common.collect.ImmutableList;
import com.linkedin.common.urn.CorpuserUrn;

import com.linkedin.common.Owner;
import com.linkedin.common.OwnerArray;
Expand Down Expand Up @@ -34,6 +35,7 @@
// TODO: Move to consuming from OwnerService
@Slf4j
public class OwnerUtils {

private static final ConjunctivePrivilegeGroup ALL_PRIVILEGES_GROUP = new ConjunctivePrivilegeGroup(ImmutableList.of(
PoliciesConfig.EDIT_ENTITY_PRIVILEGE.getType()
));
Expand Down Expand Up @@ -218,4 +220,23 @@ private static void ingestChangeProposals(List<MetadataChangeProposal> changes,
entityService.ingestProposal(change, getAuditStamp(actor));
}
}

public static void addCreatorAsOwner(
QueryContext context,
String urn,
OwnerEntityType ownerEntityType,
com.linkedin.datahub.graphql.generated.OwnershipType ownershipType,
EntityService entityService) {
try {
Urn actorUrn = CorpuserUrn.createFromString(context.getActorUrn());
addOwnersToResources(
ImmutableList.of(new OwnerInput(actorUrn.toString(), ownerEntityType, ownershipType)),
ImmutableList.of(new ResourceRefInput(urn, null, null)),
actorUrn,
entityService
);
} catch (Exception e) {
log.error(String.format("Failed to add creator as owner of tag %s", urn), e);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
package com.linkedin.datahub.graphql.resolvers.tag;

import com.google.common.collect.ImmutableList;
import com.linkedin.common.urn.CorpuserUrn;
import com.linkedin.common.urn.Urn;
import com.linkedin.data.template.SetMode;
import com.linkedin.datahub.graphql.QueryContext;
import com.linkedin.datahub.graphql.authorization.AuthorizationUtils;
import com.linkedin.datahub.graphql.exception.AuthorizationException;
import com.linkedin.datahub.graphql.generated.CreateTagInput;
import com.linkedin.datahub.graphql.generated.OwnerEntityType;
import com.linkedin.datahub.graphql.generated.OwnerInput;
import com.linkedin.datahub.graphql.generated.OwnershipType;
import com.linkedin.datahub.graphql.generated.ResourceRefInput;
import com.linkedin.datahub.graphql.resolvers.mutate.util.OwnerUtils;
import com.linkedin.entity.client.EntityClient;
import com.linkedin.events.metadata.ChangeType;
Expand Down Expand Up @@ -74,7 +69,7 @@ public CompletableFuture<String> get(DataFetchingEnvironment environment) throws
proposal.setChangeType(ChangeType.UPSERT);

String tagUrn = _entityClient.ingestProposal(proposal, context.getAuthentication());
addCreatorAsOwner(context, tagUrn);
OwnerUtils.addCreatorAsOwner(context, tagUrn, OwnerEntityType.CORP_USER, OwnershipType.TECHNICAL_OWNER, _entityService);
return tagUrn;
} catch (Exception e) {
log.error("Failed to create Tag with id: {}, name: {}: {}", input.getId(), input.getName(), e.getMessage());
Expand All @@ -89,18 +84,4 @@ private TagProperties mapTagProperties(final CreateTagInput input) {
result.setDescription(input.getDescription(), SetMode.IGNORE_NULL);
return result;
}

private void addCreatorAsOwner(QueryContext context, String tagUrn) {
try {
Urn actorUrn = CorpuserUrn.createFromString(context.getActorUrn());
OwnerUtils.addOwnersToResources(
ImmutableList.of(new OwnerInput(actorUrn.toString(), OwnerEntityType.CORP_USER, OwnershipType.TECHNICAL_OWNER)),
ImmutableList.of(new ResourceRefInput(tagUrn, null, null)),
actorUrn,
_entityService
);
} catch (Exception e) {
log.error(String.format("Failed to add creator as owner of tag %s", tagUrn), e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.linkedin.metadata.Constants;
import com.linkedin.metadata.key.DomainKey;
import com.linkedin.metadata.utils.GenericRecordUtils;
import com.linkedin.metadata.entity.EntityService;
import com.linkedin.mxe.MetadataChangeProposal;
import com.linkedin.r2.RemoteInvocationException;
import graphql.schema.DataFetchingEnvironment;
Expand All @@ -27,12 +28,16 @@ public class CreateDomainResolverTest {
"test-name",
"test-description"
);
private static final String TEST_ENTITY_URN = "urn:li:dataset:(urn:li:dataPlatform:mysql,my-test,PROD)";
private static final String TEST_TAG_1_URN = "urn:li:tag:test-id-1";
private static final String TEST_TAG_2_URN = "urn:li:tag:test-id-2";

@Test
public void testGetSuccess() throws Exception {
// Create resolver
EntityClient mockClient = Mockito.mock(EntityClient.class);
CreateDomainResolver resolver = new CreateDomainResolver(mockClient);
EntityService mockService = Mockito.mock(EntityService.class);
CreateDomainResolver resolver = new CreateDomainResolver(mockClient, mockService);

// Execute resolver
QueryContext mockContext = getMockAllowContext();
Expand Down Expand Up @@ -65,7 +70,8 @@ public void testGetSuccess() throws Exception {
public void testGetUnauthorized() throws Exception {
// Create resolver
EntityClient mockClient = Mockito.mock(EntityClient.class);
CreateDomainResolver resolver = new CreateDomainResolver(mockClient);
EntityService mockService = Mockito.mock(EntityService.class);
CreateDomainResolver resolver = new CreateDomainResolver(mockClient, mockService);

// Execute resolver
DataFetchingEnvironment mockEnv = Mockito.mock(DataFetchingEnvironment.class);
Expand All @@ -83,10 +89,11 @@ public void testGetUnauthorized() throws Exception {
public void testGetEntityClientException() throws Exception {
// Create resolver
EntityClient mockClient = Mockito.mock(EntityClient.class);
EntityService mockService = Mockito.mock(EntityService.class);
Mockito.doThrow(RemoteInvocationException.class).when(mockClient).ingestProposal(
Mockito.any(),
Mockito.any(Authentication.class));
CreateDomainResolver resolver = new CreateDomainResolver(mockClient);
CreateDomainResolver resolver = new CreateDomainResolver(mockClient, mockService);

// Execute resolver
DataFetchingEnvironment mockEnv = Mockito.mock(DataFetchingEnvironment.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.linkedin.metadata.Constants;
import com.linkedin.metadata.key.GlossaryNodeKey;
import com.linkedin.metadata.utils.GenericRecordUtils;
import com.linkedin.metadata.entity.EntityService;
import com.linkedin.mxe.MetadataChangeProposal;
import graphql.schema.DataFetchingEnvironment;
import org.mockito.Mockito;
Expand Down Expand Up @@ -74,10 +75,11 @@ private MetadataChangeProposal setupTest(
@Test
public void testGetSuccess() throws Exception {
EntityClient mockClient = Mockito.mock(EntityClient.class);
EntityService mockService = Mockito.mock(EntityService.class);
DataFetchingEnvironment mockEnv = Mockito.mock(DataFetchingEnvironment.class);
final MetadataChangeProposal proposal = setupTest(mockEnv, TEST_INPUT, "test-description", parentNodeUrn);

CreateGlossaryNodeResolver resolver = new CreateGlossaryNodeResolver(mockClient);
CreateGlossaryNodeResolver resolver = new CreateGlossaryNodeResolver(mockClient, mockService);
resolver.get(mockEnv).get();

Mockito.verify(mockClient, Mockito.times(1)).ingestProposal(
Expand All @@ -89,10 +91,11 @@ public void testGetSuccess() throws Exception {
@Test
public void testGetSuccessNoDescription() throws Exception {
EntityClient mockClient = Mockito.mock(EntityClient.class);
EntityService mockService = Mockito.mock(EntityService.class);
DataFetchingEnvironment mockEnv = Mockito.mock(DataFetchingEnvironment.class);
final MetadataChangeProposal proposal = setupTest(mockEnv, TEST_INPUT_NO_DESCRIPTION, "", parentNodeUrn);

CreateGlossaryNodeResolver resolver = new CreateGlossaryNodeResolver(mockClient);
CreateGlossaryNodeResolver resolver = new CreateGlossaryNodeResolver(mockClient, mockService);
resolver.get(mockEnv).get();

Mockito.verify(mockClient, Mockito.times(1)).ingestProposal(
Expand All @@ -104,10 +107,11 @@ public void testGetSuccessNoDescription() throws Exception {
@Test
public void testGetSuccessNoParentNode() throws Exception {
EntityClient mockClient = Mockito.mock(EntityClient.class);
EntityService mockService = Mockito.mock(EntityService.class);
DataFetchingEnvironment mockEnv = Mockito.mock(DataFetchingEnvironment.class);
final MetadataChangeProposal proposal = setupTest(mockEnv, TEST_INPUT_NO_PARENT_NODE, "test-description", null);

CreateGlossaryNodeResolver resolver = new CreateGlossaryNodeResolver(mockClient);
CreateGlossaryNodeResolver resolver = new CreateGlossaryNodeResolver(mockClient, mockService);
resolver.get(mockEnv).get();

Mockito.verify(mockClient, Mockito.times(1)).ingestProposal(
Expand Down
Loading