Skip to content

Commit

Permalink
Merge branch 'linkedin:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
gabe-lyons authored Feb 4, 2022
2 parents f3272c4 + cc32c30 commit 13d007b
Show file tree
Hide file tree
Showing 163 changed files with 5,833 additions and 1,105 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,5 @@ MANIFEST

# Metadata Ingestion Generated
metadata-ingestion/generated/**

.remote*
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ project.ext.externalDependency = [
'testContainersJunit': 'org.testcontainers:junit-jupiter:1.15.3',
'testContainersPostgresql':'org.testcontainers:postgresql:1.15.3',
'testContainersElasticsearch': 'org.testcontainers:elasticsearch:1.15.3',
'typesafeConfig':'com.typesafe:config:1.4.1',
'wiremock':'com.github.tomakehurst:wiremock:2.10.0',
'zookeeper': 'org.apache.zookeeper:zookeeper:3.4.14'
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,7 @@ private void configureMutationResolvers(final RuntimeWiring.Builder builder) {
.dataFetcher("updateDashboard", new AuthenticatedResolver<>(new MutableTypeResolver<>(dashboardType)))
.dataFetcher("updateDataJob", new AuthenticatedResolver<>(new MutableTypeResolver<>(dataJobType)))
.dataFetcher("updateDataFlow", new AuthenticatedResolver<>(new MutableTypeResolver<>(dataFlowType)))
.dataFetcher("updateCorpUserProperties", new AuthenticatedResolver<>(new MutableTypeResolver<>(corpUserType)))
.dataFetcher("addTag", new AuthenticatedResolver<>(new AddTagResolver(entityService)))
.dataFetcher("removeTag", new AuthenticatedResolver<>(new RemoveTagResolver(entityService)))
.dataFetcher("addTerm", new AuthenticatedResolver<>(new AddTermResolver(entityService)))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import graphql.schema.DataFetchingEnvironment;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.joda.time.DateTime;

Expand Down Expand Up @@ -78,16 +79,31 @@ private List<Highlight> getHighlights() {
}

private Highlight getEntityMetadataStats(String title, String index) {
int numEntities = _analyticsService.getHighlights(index, Optional.empty(), ImmutableMap.of(),
ImmutableMap.of("removed", ImmutableList.of("true")), Optional.empty());
int numEntities = getNumEntitiesFiltered(index, ImmutableMap.of());
int numEntitiesWithOwners =
_analyticsService.getHighlights(index, Optional.empty(), ImmutableMap.of("hasOwners", ImmutableList.of("true")),
ImmutableMap.of("removed", ImmutableList.of("true")), Optional.empty());
getNumEntitiesFiltered(index, ImmutableMap.of("hasOwners", ImmutableList.of("true")));
int numEntitiesWithTags =
getNumEntitiesFiltered(index, ImmutableMap.of("hasTags", ImmutableList.of("true")));
int numEntitiesWithDescription =
getNumEntitiesFiltered(index, ImmutableMap.of("hasDescription", ImmutableList.of("true")));
int numEntitiesWithDomains =
getNumEntitiesFiltered(index, ImmutableMap.of("hasDomain", ImmutableList.of("true")));

String bodyText = "";
if (numEntities > 0) {
double percentChange = 100.0 * numEntitiesWithOwners / numEntities;
bodyText = String.format("%.2f%% have owners assigned!", percentChange);
double percentWithOwners = 100.0 * numEntitiesWithOwners / numEntities;
double percentWithTags = 100.0 * numEntitiesWithTags / numEntities;
double percentWithDescription = 100.0 * numEntitiesWithDescription / numEntities;
double percentWithDomains = 100.0 * numEntitiesWithDomains / numEntities;
bodyText = String.format(
"%.2f%% have owners, %.2f%% have tags, %.2f%% have description, %.2f%% have domain assigned!",
percentWithOwners, percentWithTags, percentWithDescription, percentWithDomains);
}
return Highlight.builder().setTitle(title).setValue(numEntities).setBody(bodyText).build();
}

private int getNumEntitiesFiltered(String index, Map<String, List<String>> filters) {
return _analyticsService.getHighlights(index, Optional.empty(), filters,
ImmutableMap.of("removed", ImmutableList.of("true")), Optional.empty());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ public class ContainerType implements com.linkedin.datahub.graphql.types.EntityT
Constants.SUB_TYPES_ASPECT_NAME,
Constants.GLOBAL_TAGS_ASPECT_NAME,
Constants.GLOSSARY_TERMS_ASPECT_NAME,
Constants.CONTAINER_ASPECT_NAME
Constants.CONTAINER_ASPECT_NAME,
Constants.DOMAINS_ASPECT_NAME
);
private final EntityClient _entityClient;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@
import com.linkedin.container.EditableContainerProperties;
import com.linkedin.datahub.graphql.generated.Container;
import com.linkedin.datahub.graphql.generated.DataPlatform;
import com.linkedin.datahub.graphql.generated.Domain;
import com.linkedin.datahub.graphql.generated.EntityType;
import com.linkedin.datahub.graphql.types.common.mappers.InstitutionalMemoryMapper;
import com.linkedin.datahub.graphql.types.common.mappers.OwnershipMapper;
import com.linkedin.datahub.graphql.types.common.mappers.StringMapMapper;
import com.linkedin.datahub.graphql.types.glossary.mappers.GlossaryTermsMapper;
import com.linkedin.datahub.graphql.types.tag.mappers.GlobalTagsMapper;
import com.linkedin.domain.Domains;
import com.linkedin.entity.EntityResponse;
import com.linkedin.entity.EnvelopedAspect;
import com.linkedin.entity.EnvelopedAspectMap;
Expand Down Expand Up @@ -89,6 +91,17 @@ public static Container map(final EntityResponse entityResponse) {
.build());
}

final EnvelopedAspect envelopedDomains = aspects.get(Constants.DOMAINS_ASPECT_NAME);
if (envelopedDomains != null) {
final Domains domains = new Domains(envelopedDomains.getValue().data());
// Currently we only take the first domain if it exists.
if (domains.getDomains().size() > 0) {
result.setDomain(Domain.builder()
.setType(EntityType.DOMAIN)
.setUrn(domains.getDomains().get(0).toString()).build());
}
}

return result;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package com.linkedin.datahub.graphql.types.corpuser;

import com.linkedin.common.url.Url;
import com.linkedin.common.urn.CorpuserUrn;

import com.linkedin.common.urn.Urn;
import com.linkedin.data.template.RecordTemplate;
import com.linkedin.data.template.StringArray;
import com.linkedin.datahub.graphql.QueryContext;
import com.linkedin.datahub.graphql.generated.CorpUserUpdateInput;
import com.linkedin.datahub.graphql.generated.EntityType;
import com.linkedin.datahub.graphql.types.MutableType;
import com.linkedin.datahub.graphql.types.SearchableEntityType;
import com.linkedin.datahub.graphql.generated.AutoCompleteResults;
import com.linkedin.datahub.graphql.generated.CorpUser;
Expand All @@ -15,10 +20,16 @@
import com.linkedin.datahub.graphql.types.mappers.UrnSearchResultsMapper;
import com.linkedin.entity.Entity;
import com.linkedin.entity.client.EntityClient;
import com.linkedin.events.metadata.ChangeType;
import com.linkedin.identity.CorpUserEditableInfo;
import com.linkedin.metadata.Constants;
import com.linkedin.metadata.query.AutoCompleteResult;
import com.linkedin.metadata.search.SearchResult;

import com.linkedin.metadata.utils.GenericAspectUtils;
import com.linkedin.mxe.MetadataChangeProposal;
import graphql.execution.DataFetcherResult;
import java.util.Optional;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.net.URISyntaxException;
Expand All @@ -29,7 +40,7 @@
import java.util.Map;
import java.util.stream.Collectors;

public class CorpUserType implements SearchableEntityType<CorpUser> {
public class CorpUserType implements SearchableEntityType<CorpUser>, MutableType<CorpUserUpdateInput> {

private final EntityClient _entityClient;

Expand Down Expand Up @@ -99,4 +110,59 @@ private CorpuserUrn getCorpUserUrn(final String urnStr) {
throw new RuntimeException(String.format("Failed to retrieve user with urn %s, invalid urn", urnStr));
}
}

public Class<CorpUserUpdateInput> inputClass() {
return CorpUserUpdateInput.class;
}

@Override
public CorpUser update(@Nonnull String urn, @Nonnull CorpUserUpdateInput input, @Nonnull QueryContext context) throws Exception {
final CorpuserUrn actor = CorpuserUrn.createFromString(context.getAuthentication().getActor().toUrnStr());

// Get existing editable info to merge with
Optional<CorpUserEditableInfo> existingCorpUserEditableInfo =
_entityClient.getVersionedAspect(urn, Constants.CORP_USER_EDITABLE_INFO_NAME, 0L, CorpUserEditableInfo.class,
context.getAuthentication());

// Create the MCP
final MetadataChangeProposal proposal = new MetadataChangeProposal();
proposal.setEntityUrn(Urn.createFromString(urn));
proposal.setEntityType(Constants.CORP_USER_ENTITY_NAME);
proposal.setAspectName(Constants.CORP_USER_EDITABLE_INFO_NAME);
proposal.setAspect(GenericAspectUtils.serializeAspect(mapCorpUserEditableInfo(input, existingCorpUserEditableInfo)));
proposal.setChangeType(ChangeType.UPSERT);
_entityClient.ingestProposal(proposal, context.getAuthentication());

return load(urn, context).getData();
}

private RecordTemplate mapCorpUserEditableInfo(CorpUserUpdateInput input, Optional<CorpUserEditableInfo> existing) {
CorpUserEditableInfo result = existing.orElseGet(() -> new CorpUserEditableInfo());
if (input.getAboutMe() != null) {
result.setAboutMe(input.getAboutMe());
}
if (input.getPictureLink() != null) {
result.setPictureLink(new Url(input.getPictureLink()));
}
if (input.getAboutMe() != null) {
result.setAboutMe(input.getAboutMe());
}
if (input.getSkills() != null) {
result.setSkills(new StringArray(input.getSkills()));
}
if (input.getTeams() != null) {
result.setTeams(new StringArray(input.getTeams()));
}
if (input.getPhone() != null) {
result.setPhone(input.getPhone());
}
if (input.getSlack() != null) {
result.setSlack(input.getSlack());
}
if (input.getEmail() != null) {
result.setEmail(input.getEmail());
}

return result;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.linkedin.datahub.graphql.types.corpuser.mappers;

import com.linkedin.datahub.graphql.generated.CorpUserEditableInfo;
import com.linkedin.datahub.graphql.generated.CorpUserEditableProperties;
import com.linkedin.datahub.graphql.types.mappers.ModelMapper;

import javax.annotation.Nonnull;
Expand All @@ -10,20 +10,23 @@
*
* To be replaced by auto-generated mappers implementations
*/
public class CorpUserEditableInfoMapper implements ModelMapper<com.linkedin.identity.CorpUserEditableInfo, CorpUserEditableInfo> {
public class CorpUserEditableInfoMapper implements ModelMapper<com.linkedin.identity.CorpUserEditableInfo, CorpUserEditableProperties> {

public static final CorpUserEditableInfoMapper INSTANCE = new CorpUserEditableInfoMapper();

public static CorpUserEditableInfo map(@Nonnull final com.linkedin.identity.CorpUserEditableInfo info) {
public static CorpUserEditableProperties map(@Nonnull final com.linkedin.identity.CorpUserEditableInfo info) {
return INSTANCE.apply(info);
}

@Override
public CorpUserEditableInfo apply(@Nonnull final com.linkedin.identity.CorpUserEditableInfo info) {
final CorpUserEditableInfo result = new CorpUserEditableInfo();
public CorpUserEditableProperties apply(@Nonnull final com.linkedin.identity.CorpUserEditableInfo info) {
final CorpUserEditableProperties result = new CorpUserEditableProperties();
result.setAboutMe(info.getAboutMe());
result.setSkills(info.getSkills());
result.setTeams(info.getTeams());
result.setEmail(info.getEmail());
result.setPhone(info.getPhone());
result.setSlack(info.getSlack());
if (info.hasPictureLink()) {
result.setPictureLink(info.getPictureLink().toString());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public CorpUser apply(@Nonnull final CorpUserSnapshot corpUser) {
result.setProperties(CorpUserPropertiesMapper.map(CorpUserInfo.class.cast(aspect)));
result.setInfo(CorpUserInfoMapper.map(CorpUserInfo.class.cast(aspect)));
} else if (aspect instanceof CorpUserEditableInfo) {
result.setEditableInfo(CorpUserEditableInfoMapper.map(CorpUserEditableInfo.class.cast(aspect)));
result.setEditableProperties(CorpUserEditableInfoMapper.map(CorpUserEditableInfo.class.cast(aspect)));
} else if (aspect instanceof GlobalTags) {
result.setGlobalTags(GlobalTagsMapper.map(GlobalTags.class.cast(aspect)));
} else if (aspect instanceof CorpUserStatus) {
Expand Down
68 changes: 67 additions & 1 deletion datahub-graphql-core/src/main/resources/entity.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,11 @@ type Mutation {
Sets the Domain for a Dataset, Chart, Dashboard, Data Flow (Pipeline), or Data Job (Task). Returns true if the Domain was successfully removed, or was already removed. Requires the Edit Domains privilege for an asset.
"""
unsetDomain(entityUrn: String!): Boolean

"""
Update a particular Corp User's editable properties
"""
updateCorpUserProperties(urn: String!, input: CorpUserUpdateInput!): CorpUser
}

"""
Expand Down Expand Up @@ -1178,6 +1183,11 @@ type Container implements Entity {
"""
subTypes: SubTypes

"""
The Domain associated with the Dataset
"""
domain: Domain

"""
Children entities inside of the Container
"""
Expand Down Expand Up @@ -2234,6 +2244,62 @@ type CorpUserEditableProperties {
A URL which points to a picture which user wants to set as a profile photo
"""
pictureLink: String

"""
The slack handle of the user
"""
slack: String

"""
Phone number for the user
"""
phone: String

"""
Email address for the user
"""
email: String
}


"""
Arguments provided to update a CorpUser Entity
"""
input CorpUserUpdateInput {
"""
About me section of the user
"""
aboutMe: String

"""
Teams that the user belongs to
"""
teams: [String!]

"""
Skills that the user possesses
"""
skills: [String!]

"""
A URL which points to a picture which user wants to set as a profile photo
"""
pictureLink: String

"""
The slack handle of the user
"""
slack: String

"""
Phone number for the user
"""
phone: String

"""
Email address for the user
"""
email: String
}

"""
Expand Down Expand Up @@ -5552,4 +5618,4 @@ type ListDomainsResult {
The Domains themselves
"""
domains: [Domain!]!
}
}
3 changes: 2 additions & 1 deletion datahub-web-react/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { BrowserRouter as Router } from 'react-router-dom';
import { ApolloClient, ApolloProvider, createHttpLink, InMemoryCache, ServerError } from '@apollo/client';
import { onError } from '@apollo/client/link/error';
import { ThemeProvider } from 'styled-components';

import './App.less';
import { Routes } from './app/Routes';
import EntityRegistry from './app/entity/EntityRegistry';
Expand All @@ -30,6 +29,7 @@ import { MLFeatureTableEntity } from './app/entity/mlFeatureTable/MLFeatureTable
import { MLModelEntity } from './app/entity/mlModel/MLModelEntity';
import { MLModelGroupEntity } from './app/entity/mlModelGroup/MLModelGroupEntity';
import { DomainEntity } from './app/entity/domain/DomainEntity';
import { ContainerEntity } from './app/entity/container/ContainerEntity';

/*
Construct Apollo Client
Expand Down Expand Up @@ -96,6 +96,7 @@ const App: React.VFC = () => {
register.register(new MLModelEntity());
register.register(new MLModelGroupEntity());
register.register(new DomainEntity());
register.register(new ContainerEntity());
return register;
}, []);

Expand Down
3 changes: 3 additions & 0 deletions datahub-web-react/src/Mocks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ const dataset1 = {
},
],
domain: null,
container: null,
};

const dataset2 = {
Expand Down Expand Up @@ -260,6 +261,7 @@ const dataset2 = {
},
],
domain: null,
container: null,
};

export const dataset3 = {
Expand Down Expand Up @@ -447,6 +449,7 @@ export const dataset3 = {
},
],
domain: null,
container: null,
} as Dataset;

export const dataset4 = {
Expand Down
Loading

0 comments on commit 13d007b

Please sign in to comment.