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

feat(users): adding user graphql mutation #4033

Merged
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 @@ -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)))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason we went specific here? Instead of saying "updateCorpUser" like the others?

.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
@@ -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());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow this is awesome - I love how this is basically a patch!

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
63 changes: 62 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 @@ -2234,6 +2239,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 +5613,4 @@ type ListDomainsResult {
The Domains themselves
"""
domains: [Domain!]!
}
}
6 changes: 6 additions & 0 deletions datahub-web-react/src/graphql/user.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,9 @@ mutation removeUser($urn: String!) {
mutation updateUserStatus($urn: String!, $status: CorpUserStatus!) {
updateUserStatus(urn: $urn, status: $status)
}

mutation updateCorpUserProperties($urn: String!, $input: CorpUserUpdateInput!) {
updateCorpUserProperties(urn: $urn, input: $input) {
urn
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,19 @@ record CorpUserEditableInfo {
* A URL which points to a picture which user wants to set as a profile photo
*/
pictureLink: Url = "https://raw.githubusercontent.com/linkedin/datahub/master/datahub-web-react/src/images/default_avatar.png"

/**
* Slack handle for the user
*/
slack: optional string

/**
* Phone number to contact the user
*/
phone: optional string

/**
* Email address to contact the user
*/
email: optional string
}
Original file line number Diff line number Diff line change
Expand Up @@ -1680,6 +1680,21 @@
"type" : "com.linkedin.common.Url",
"doc" : "A URL which points to a picture which user wants to set as a profile photo",
"default" : "https://raw.githubusercontent.com/linkedin/datahub/master/datahub-web-react/src/images/default_avatar.png"
}, {
"name" : "slack",
"type" : "string",
"doc" : "Slack handle for the user",
"optional" : true
}, {
"name" : "phone",
"type" : "string",
"doc" : "Phone number to contact the user",
"optional" : true
}, {
"name" : "email",
"type" : "string",
"doc" : "Email address to contact the user",
"optional" : true
} ],
"Aspect" : {
"EntityUrns" : [ "com.linkedin.common.CorpuserUrn" ],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2097,6 +2097,21 @@
"type" : "com.linkedin.common.Url",
"doc" : "A URL which points to a picture which user wants to set as a profile photo",
"default" : "https://raw.githubusercontent.com/linkedin/datahub/master/datahub-web-react/src/images/default_avatar.png"
}, {
"name" : "slack",
"type" : "string",
"doc" : "Slack handle for the user",
"optional" : true
}, {
"name" : "phone",
"type" : "string",
"doc" : "Phone number to contact the user",
"optional" : true
}, {
"name" : "email",
"type" : "string",
"doc" : "Email address to contact the user",
"optional" : true
} ],
"Aspect" : {
"EntityUrns" : [ "com.linkedin.common.CorpuserUrn" ],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1437,6 +1437,21 @@
"type" : "com.linkedin.common.Url",
"doc" : "A URL which points to a picture which user wants to set as a profile photo",
"default" : "https://raw.githubusercontent.com/linkedin/datahub/master/datahub-web-react/src/images/default_avatar.png"
}, {
"name" : "slack",
"type" : "string",
"doc" : "Slack handle for the user",
"optional" : true
}, {
"name" : "phone",
"type" : "string",
"doc" : "Phone number to contact the user",
"optional" : true
}, {
"name" : "email",
"type" : "string",
"doc" : "Email address to contact the user",
"optional" : true
} ],
"Aspect" : {
"EntityUrns" : [ "com.linkedin.common.CorpuserUrn" ],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public class Constants {

// User
public static final String CORP_USER_KEY_ASPECT_NAME = "corpUserKey";
public static final String CORP_USER_EDITABLE_INFO_NAME = "corpUserEditableInfo";
public static final String GROUP_MEMBERSHIP_ASPECT_NAME = "groupMembership";
public static final String CORP_USER_STATUS_ASPECT_NAME = "corpUserStatus";

Expand Down