Skip to content

Commit

Permalink
fix(react): fix updates from the UI (datahub-project#3280)
Browse files Browse the repository at this point in the history
  • Loading branch information
gabe-lyons authored and jgiannuzzi committed Oct 6, 2021
1 parent 3574294 commit b1e6c61
Show file tree
Hide file tree
Showing 16 changed files with 516 additions and 278 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import com.linkedin.datahub.graphql.resolvers.mutate.MutableTypeResolver;
import com.linkedin.datahub.graphql.resolvers.mutate.RemoveTagResolver;
import com.linkedin.datahub.graphql.resolvers.mutate.RemoveTermResolver;
import com.linkedin.datahub.graphql.resolvers.mutate.UpdateFieldDescriptionResolver;
import com.linkedin.datahub.graphql.resolvers.policy.DeletePolicyResolver;
import com.linkedin.datahub.graphql.resolvers.policy.ListPoliciesResolver;
import com.linkedin.datahub.graphql.resolvers.config.AppConfigResolver;
Expand Down Expand Up @@ -390,6 +391,7 @@ private void configureMutationResolvers(final RuntimeWiring.Builder builder) {
.dataFetcher("createPolicy", new UpsertPolicyResolver(GmsClientFactory.getAspectsClient()))
.dataFetcher("updatePolicy", new UpsertPolicyResolver(GmsClientFactory.getAspectsClient()))
.dataFetcher("deletePolicy", new DeletePolicyResolver(GmsClientFactory.getEntitiesClient()))
.dataFetcher("updateDescription", new AuthenticatedResolver<>(new UpdateFieldDescriptionResolver(entityService)))
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ public CompletableFuture<Boolean> get(DataFetchingEnvironment environment) throw
"glossaryTerm",
_entityService
);

if (!targetUrn.getEntityType().equals("dataset")) {
throw new IllegalArgumentException(String.format("Failed to update %s on %s. Subject is not a dataset.", termUrn, targetUrn));
}

try {
log.info("Adding Term. input: {}", input);
Urn actor = CorpuserUrn.createFromString(((QueryContext) environment.getContext()).getActor());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package com.linkedin.datahub.graphql.resolvers.mutate;

import com.google.common.collect.ImmutableList;

import com.linkedin.common.urn.Urn;
import com.linkedin.datahub.graphql.QueryContext;
import com.linkedin.datahub.graphql.authorization.AuthorizationUtils;
import com.linkedin.datahub.graphql.authorization.ConjunctivePrivilegeGroup;
import com.linkedin.datahub.graphql.authorization.DisjunctivePrivilegeGroup;
import com.linkedin.datahub.graphql.generated.SubResourceType;
import com.linkedin.metadata.authorization.PoliciesConfig;
import com.linkedin.metadata.entity.EntityService;
import com.linkedin.schema.EditableSchemaFieldInfo;
import com.linkedin.schema.EditableSchemaMetadata;
import javax.annotation.Nonnull;
import lombok.extern.slf4j.Slf4j;

import static com.linkedin.datahub.graphql.resolvers.mutate.MutationUtils.*;


@Slf4j
public class DescriptionUtils {
private static final ConjunctivePrivilegeGroup ALL_PRIVILEGES_GROUP = new ConjunctivePrivilegeGroup(ImmutableList.of(
PoliciesConfig.EDIT_ENTITY_PRIVILEGE.getType()
));

private DescriptionUtils() { }

public static final String EDITABLE_SCHEMA_METADATA = "editableSchemaMetadata";

public static void updateFieldDescription(
String newDescription,
Urn resourceUrn,
String fieldPath,
Urn actor,
EntityService entityService
) {
EditableSchemaMetadata editableSchemaMetadata =
(EditableSchemaMetadata) getAspectFromEntity(
resourceUrn.toString(), EDITABLE_SCHEMA_METADATA, entityService, new EditableSchemaMetadata());
EditableSchemaFieldInfo editableFieldInfo = getFieldInfoFromSchema(editableSchemaMetadata, fieldPath);

editableFieldInfo.setDescription(newDescription);

persistAspect(resourceUrn, editableSchemaMetadata, actor, entityService);
}

public static Boolean validateFieldDescriptionInput(
Urn resourceUrn,
String subResource,
SubResourceType subResourceType,
EntityService entityService
) {
if (!entityService.exists(resourceUrn)) {
throw new IllegalArgumentException(String.format("Failed to update %s. %s does not exist.", resourceUrn, resourceUrn));
}

validateSubresourceExists(resourceUrn, subResource, subResourceType, entityService);

return true;
}

public static boolean isAuthorizedToUpdateFieldDescription(@Nonnull QueryContext context, Urn targetUrn) {
final DisjunctivePrivilegeGroup orPrivilegeGroups = new DisjunctivePrivilegeGroup(ImmutableList.of(
ALL_PRIVILEGES_GROUP,
new ConjunctivePrivilegeGroup(ImmutableList.of(PoliciesConfig.EDIT_DATASET_COL_DESCRIPTION_PRIVILEGE.getType()))
));

return AuthorizationUtils.isAuthorized(
context.getAuthorizer(),
context.getActor(),
targetUrn.getEntityType(),
targetUrn.toString(),
orPrivilegeGroups);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import com.google.common.collect.ImmutableList;


import com.linkedin.common.AuditStamp;
import com.linkedin.common.GlobalTags;
import com.linkedin.common.GlossaryTermAssociation;
import com.linkedin.common.GlossaryTermAssociationArray;
Expand All @@ -13,26 +12,21 @@
import com.linkedin.common.urn.GlossaryTermUrn;
import com.linkedin.common.urn.TagUrn;
import com.linkedin.common.urn.Urn;
import com.linkedin.data.template.RecordTemplate;
import com.linkedin.datahub.graphql.QueryContext;
import com.linkedin.datahub.graphql.authorization.AuthorizationUtils;
import com.linkedin.datahub.graphql.authorization.ConjunctivePrivilegeGroup;
import com.linkedin.datahub.graphql.authorization.DisjunctivePrivilegeGroup;
import com.linkedin.datahub.graphql.generated.SubResourceType;
import com.linkedin.entity.Entity;
import com.linkedin.metadata.authorization.PoliciesConfig;
import com.linkedin.metadata.entity.EntityService;
import com.linkedin.metadata.snapshot.Snapshot;
import com.linkedin.schema.EditableSchemaFieldInfo;
import com.linkedin.schema.EditableSchemaFieldInfoArray;
import com.linkedin.schema.EditableSchemaMetadata;
import com.linkedin.schema.SchemaField;
import com.linkedin.schema.SchemaMetadata;
import java.net.URISyntaxException;
import java.util.Optional;
import javax.annotation.Nonnull;
import lombok.extern.slf4j.Slf4j;

import static com.linkedin.datahub.graphql.resolvers.mutate.MutationUtils.*;


@Slf4j
public class LabelUtils {
Expand All @@ -45,7 +39,6 @@ private LabelUtils() { }
public static final String GLOSSARY_TERM_ASPECT_NAME = "glossaryTerms";
public static final String EDITABLE_SCHEMA_METADATA = "editableSchemaMetadata";
public static final String TAGS_ASPECT_NAME = "globalTags";
public static final String SCHEMA_ASPECT_NAME = "schemaMetadata";

public static void removeTermFromTarget(
Urn labelUrn,
Expand All @@ -56,7 +49,7 @@ public static void removeTermFromTarget(
) {
if (subResource == null || subResource.equals("")) {
com.linkedin.common.GlossaryTerms terms =
(com.linkedin.common.GlossaryTerms) getAspectFromEntity(
(com.linkedin.common.GlossaryTerms) MutationUtils.getAspectFromEntity(
targetUrn.toString(), GLOSSARY_TERM_ASPECT_NAME, entityService, new GlossaryTerms());
terms.setAuditStamp(getAuditStamp(actor));

Expand Down Expand Up @@ -172,30 +165,6 @@ public static void addTermToTarget(
}
}

private static EditableSchemaFieldInfo getFieldInfoFromSchema(
EditableSchemaMetadata editableSchemaMetadata,
String fieldPath
) {
if (!editableSchemaMetadata.hasEditableSchemaFieldInfo()) {
editableSchemaMetadata.setEditableSchemaFieldInfo(new EditableSchemaFieldInfoArray());
}
EditableSchemaFieldInfoArray editableSchemaMetadataArray =
editableSchemaMetadata.getEditableSchemaFieldInfo();
Optional<EditableSchemaFieldInfo> fieldMetadata = editableSchemaMetadataArray
.stream()
.filter(fieldInfo -> fieldInfo.getFieldPath().equals(fieldPath))
.findFirst();

if (fieldMetadata.isPresent()) {
return fieldMetadata.get();
} else {
EditableSchemaFieldInfo newFieldInfo = new EditableSchemaFieldInfo();
newFieldInfo.setFieldPath(fieldPath);
editableSchemaMetadataArray.add(newFieldInfo);
return newFieldInfo;
}
}

private static void addTermIfNotExistsToEntity(GlossaryTerms terms, Urn termUrn)
throws URISyntaxException {
if (!terms.hasTerms()) {
Expand Down Expand Up @@ -255,45 +224,6 @@ private static void addTagIfNotExists(GlobalTags tags, Urn tagUrn) throws URISyn
return;
}

private static void persistAspect(Urn urn, RecordTemplate aspect, Urn actor, EntityService entityService) {
Snapshot updatedSnapshot = entityService.buildSnapshot(urn, aspect);
Entity entityToPersist = new Entity();
entityToPersist.setValue(updatedSnapshot);
entityService.ingestEntity(entityToPersist, getAuditStamp(actor));
}

private static RecordTemplate getAspectFromEntity(String entityUrn, String aspectName, EntityService entityService, RecordTemplate defaultValue) {
try {
RecordTemplate aspect = entityService.getAspect(
Urn.createFromString(entityUrn),
aspectName,
0
);

if (aspect == null) {
return defaultValue;
}

return aspect;
} catch (Exception e) {
log.error(
"Error constructing aspect from entity. Entity: {} aspect: {}. Error: {}",
entityUrn,
aspectName,
e.toString()
);
e.printStackTrace();
return null;
}
}

private static AuditStamp getAuditStamp(Urn actor) {
AuditStamp auditStamp = new AuditStamp();
auditStamp.setTime(System.currentTimeMillis());
auditStamp.setActor(actor);
return auditStamp;
}

public static boolean isAuthorizedToUpdateTags(@Nonnull QueryContext context, Urn targetUrn, String subResource) {

Boolean isTargetingSchema = subResource != null && subResource.length() > 0;
Expand Down Expand Up @@ -348,10 +278,6 @@ public static Boolean validateInput(
throw new IllegalArgumentException(String.format("Failed to update %s on %s. Was expecting a %s.", labelUrn, targetUrn, labelEntityType));
}

if (!targetUrn.getEntityType().equals("dataset")) {
throw new IllegalArgumentException(String.format("Failed to update %s on %s. Subject is not a dataset.", labelUrn, targetUrn));
}

if (!entityService.exists(targetUrn)) {
throw new IllegalArgumentException(String.format("Failed to update %s on %s. %s does not exist.", labelUrn, targetUrn, targetUrn));
}
Expand All @@ -369,43 +295,9 @@ public static Boolean validateInput(
throw new IllegalArgumentException(String.format(
"Failed to update %s on %s. SubResource (%s) provided without a subResourceType.", labelUrn, targetUrn, subResource));
}
validateSubresourceExists(labelUrn, targetUrn, subResource, subResourceType, entityService);
validateSubresourceExists(targetUrn, subResource, subResourceType, entityService);
}

return true;
}

public static Boolean validateSubresourceExists(
Urn labelUrn,
Urn targetUrn,
String subResource,
SubResourceType subResourceType,
EntityService entityService
) {
if (subResourceType.equals(SubResourceType.FIELD_PATH)) {
SchemaMetadata schemaMetadata = (SchemaMetadata) entityService.getAspect(targetUrn, SCHEMA_ASPECT_NAME, 0);

if (schemaMetadata == null) {
throw new IllegalArgumentException(
String.format("Failed to update %s on %s & field %s. %s has no schema.", labelUrn, targetUrn, subResource, targetUrn)
);
}

Optional<SchemaField> fieldMatch =
schemaMetadata.getFields().stream().filter(field -> field.getFieldPath().equals(subResource)).findFirst();

if (!fieldMatch.isPresent()) {
throw new IllegalArgumentException(String.format(
"Failed to update %s on %s & field %s. Field %s does not exist in the datasets schema.",
labelUrn, targetUrn, subResource, subResource));
}

return true;
}

throw new IllegalArgumentException(String.format(
"Failed to update %s on %s. SubResourceType (%s) is not valid. Types supported: %s.",
labelUrn, targetUrn, subResource, SubResourceType.values()
));
}
}
Loading

0 comments on commit b1e6c61

Please sign in to comment.