Skip to content

Commit 02aefb4

Browse files
authored
Merge branch 'master' into azure-fabric-connector
2 parents 66a8ae2 + d1494c2 commit 02aefb4

File tree

337 files changed

+10847
-2139
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

337 files changed

+10847
-2139
lines changed

datahub-graphql-core/build.gradle

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ dependencies {
2929

3030
testImplementation externalDependency.mockito
3131
testImplementation externalDependency.testng
32+
testImplementation externalDependency.mockitoInline
3233
}
3334

3435
graphqlCodegen {

datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/GmsGraphQLEngine.java

+4
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@
204204
import com.linkedin.datahub.graphql.resolvers.health.EntityHealthResolver;
205205
import com.linkedin.datahub.graphql.resolvers.incident.EntityIncidentsResolver;
206206
import com.linkedin.datahub.graphql.resolvers.incident.RaiseIncidentResolver;
207+
import com.linkedin.datahub.graphql.resolvers.incident.UpdateIncidentResolver;
207208
import com.linkedin.datahub.graphql.resolvers.incident.UpdateIncidentStatusResolver;
208209
import com.linkedin.datahub.graphql.resolvers.ingest.execution.CancelIngestionExecutionRequestResolver;
209210
import com.linkedin.datahub.graphql.resolvers.ingest.execution.CreateIngestionExecutionRequestResolver;
@@ -1397,6 +1398,9 @@ private void configureMutationResolvers(final RuntimeWiring.Builder builder) {
13971398
.dataFetcher(
13981399
"updateIncidentStatus",
13991400
new UpdateIncidentStatusResolver(this.entityClient, this.entityService))
1401+
.dataFetcher(
1402+
"updateIncident",
1403+
new UpdateIncidentResolver(this.entityClient, this.entityService))
14001404
.dataFetcher(
14011405
"createForm", new CreateFormResolver(this.entityClient, this.formService))
14021406
.dataFetcher("deleteForm", new DeleteFormResolver(this.entityClient))

datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/analytics/resolver/GetChartsResolver.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ private Row buildNewUsersRow(@Nonnull final SearchEntity entity) {
186186
private AnalyticsChart getNewUsersChart(OperationContext opContext) {
187187
try {
188188
final List<String> columns = ImmutableList.of("Name", "Title", "Email");
189-
final String newUsersTitle = "Active Users (Last 30 Days)";
189+
final String newUsersTitle = "New Users (Last 30 Days)";
190190
final SearchResult result = searchForNewUsers(opContext);
191191
final List<Row> newUserRows = new ArrayList<>();
192192
for (SearchEntity entity : result.getEntities()) {

datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/businessattribute/AddBusinessAttributeResolver.java

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import static com.linkedin.datahub.graphql.resolvers.ResolverUtils.bindArgument;
44
import static com.linkedin.datahub.graphql.resolvers.mutate.MutationUtils.buildMetadataChangeProposalWithUrn;
5+
import static com.linkedin.datahub.graphql.resolvers.mutate.util.BusinessAttributeUtils.validateInputResources;
56
import static com.linkedin.metadata.Constants.BUSINESS_ATTRIBUTE_ASPECT;
67

78
import com.linkedin.businessattribute.BusinessAttributeAssociation;
@@ -43,6 +44,7 @@ public CompletableFuture<Boolean> get(DataFetchingEnvironment environment) throw
4344
return GraphQLConcurrencyUtils.supplyAsync(
4445
() -> {
4546
try {
47+
validateInputResources(resourceRefInputs, context);
4648
addBusinessAttributeToResource(
4749
context.getOperationContext(),
4850
businessAttributeUrn,

datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/businessattribute/BusinessAttributeAuthorizationUtils.java

+21
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
package com.linkedin.datahub.graphql.resolvers.businessattribute;
22

3+
import static com.linkedin.datahub.graphql.authorization.AuthorizationUtils.ALL_PRIVILEGES_GROUP;
4+
35
import com.datahub.authorization.AuthUtil;
46
import com.datahub.authorization.ConjunctivePrivilegeGroup;
57
import com.datahub.authorization.DisjunctivePrivilegeGroup;
68
import com.google.common.collect.ImmutableList;
9+
import com.linkedin.common.urn.Urn;
710
import com.linkedin.datahub.graphql.QueryContext;
11+
import com.linkedin.datahub.graphql.authorization.AuthorizationUtils;
812
import com.linkedin.metadata.authorization.PoliciesConfig;
13+
import java.net.URISyntaxException;
914
import javax.annotation.Nonnull;
1015

1116
public class BusinessAttributeAuthorizationUtils {
@@ -32,4 +37,20 @@ public static boolean canManageBusinessAttribute(@Nonnull QueryContext context)
3237
PoliciesConfig.MANAGE_BUSINESS_ATTRIBUTE_PRIVILEGE.getType()))));
3338
return AuthUtil.isAuthorized(context.getOperationContext(), orPrivilegeGroups, null);
3439
}
40+
41+
public static boolean isAuthorizedToEditBusinessAttribute(
42+
@Nonnull QueryContext context, String targetUrn) throws URISyntaxException {
43+
Urn schemaFieldUrn = Urn.createFromString(targetUrn);
44+
Urn datasetUrn = schemaFieldUrn.getIdAsUrn();
45+
final DisjunctivePrivilegeGroup orPrivilegeGroups =
46+
new DisjunctivePrivilegeGroup(
47+
ImmutableList.of(
48+
ALL_PRIVILEGES_GROUP,
49+
new ConjunctivePrivilegeGroup(
50+
ImmutableList.of(
51+
PoliciesConfig.EDIT_DATASET_COL_BUSINESS_ATTRIBUTE_PRIVILEGE.getType()))));
52+
53+
return AuthorizationUtils.isAuthorized(
54+
context, datasetUrn.getEntityType(), datasetUrn.toString(), orPrivilegeGroups);
55+
}
3556
}

datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/businessattribute/RemoveBusinessAttributeResolver.java

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import static com.linkedin.datahub.graphql.resolvers.ResolverUtils.bindArgument;
44
import static com.linkedin.datahub.graphql.resolvers.mutate.MutationUtils.buildMetadataChangeProposalWithUrn;
5+
import static com.linkedin.datahub.graphql.resolvers.mutate.util.BusinessAttributeUtils.validateInputResources;
56
import static com.linkedin.metadata.Constants.BUSINESS_ATTRIBUTE_ASPECT;
67

78
import com.linkedin.businessattribute.BusinessAttributes;
@@ -40,6 +41,7 @@ public CompletableFuture<Boolean> get(DataFetchingEnvironment environment) throw
4041
return GraphQLConcurrencyUtils.supplyAsync(
4142
() -> {
4243
try {
44+
validateInputResources(resourceRefInputs, context);
4345
removeBusinessAttribute(
4446
context.getOperationContext(),
4547
resourceRefInputs,

datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/incident/EntityIncidentsResolver.java

+38-8
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.linkedin.datahub.graphql.generated.Entity;
77
import com.linkedin.datahub.graphql.generated.EntityIncidentsResult;
88
import com.linkedin.datahub.graphql.generated.Incident;
9+
import com.linkedin.datahub.graphql.generated.IncidentPriority;
910
import com.linkedin.datahub.graphql.types.incident.IncidentMapper;
1011
import com.linkedin.entity.EntityResponse;
1112
import com.linkedin.entity.client.EntityClient;
@@ -38,6 +39,9 @@ public class EntityIncidentsResolver
3839
static final String INCIDENT_ENTITIES_SEARCH_INDEX_FIELD_NAME = "entities.keyword";
3940
static final String INCIDENT_STATE_SEARCH_INDEX_FIELD_NAME = "state";
4041
static final String CREATED_TIME_SEARCH_INDEX_FIELD_NAME = "created";
42+
static final String INCIDENT_STAGE_SEARCH_INDEX_FIELD_NAME = "stage";
43+
static final String INCIDENT_PRIORITY_SEARCH_INDEX_FIELD_NAME = "priority";
44+
static final String INCIDENT_ASSIGNEES_SEARCH_INDEX_FIELD_NAME = "assignees";
4145

4246
private final EntityClient _entityClient;
4347

@@ -55,12 +59,18 @@ public CompletableFuture<EntityIncidentsResult> get(DataFetchingEnvironment envi
5559
final Integer start = environment.getArgumentOrDefault("start", 0);
5660
final Integer count = environment.getArgumentOrDefault("count", 20);
5761
final Optional<String> maybeState = Optional.ofNullable(environment.getArgument("state"));
58-
62+
final Optional<String> maybeStage = Optional.ofNullable(environment.getArgument("stage"));
63+
final Optional<String> maybePriority =
64+
Optional.ofNullable(environment.getArgument("priority"));
65+
final Optional<List<String>> maybeAssigneeUrns =
66+
Optional.ofNullable(environment.getArgument("assigneeUrns"));
5967
try {
6068
// Step 1: Fetch set of incidents associated with the target entity from the Search
6169
// Index!
6270
// We use the search index so that we can easily sort by the last updated time.
63-
final Filter filter = buildIncidentsEntityFilter(entityUrn, maybeState);
71+
final Filter filter =
72+
buildIncidentsFilter(
73+
entityUrn, maybeState, maybeStage, maybePriority, maybeAssigneeUrns);
6474
final List<SortCriterion> sortCriteria = buildIncidentsSortCriteria();
6575
final SearchResult searchResult =
6676
_entityClient.filter(
@@ -110,13 +120,33 @@ public CompletableFuture<EntityIncidentsResult> get(DataFetchingEnvironment envi
110120
"get");
111121
}
112122

113-
private Filter buildIncidentsEntityFilter(
114-
final String entityUrn, final Optional<String> maybeState) {
115-
final Map<String, String> criterionMap = new HashMap<>();
116-
criterionMap.put(INCIDENT_ENTITIES_SEARCH_INDEX_FIELD_NAME, entityUrn);
123+
private Filter buildIncidentsFilter(
124+
final String entityUrn,
125+
final Optional<String> maybeState,
126+
final Optional<String> maybeStage,
127+
final Optional<String> maybePriority,
128+
final Optional<List<String>> maybeAssigneeUrns) {
129+
final Map<String, List<String>> criterionMap = new HashMap<>();
130+
criterionMap.put(
131+
INCIDENT_ENTITIES_SEARCH_INDEX_FIELD_NAME, Collections.singletonList(entityUrn));
117132
maybeState.ifPresent(
118-
incidentState -> criterionMap.put(INCIDENT_STATE_SEARCH_INDEX_FIELD_NAME, incidentState));
119-
return QueryUtils.newFilter(criterionMap);
133+
incidentState ->
134+
criterionMap.put(
135+
INCIDENT_STATE_SEARCH_INDEX_FIELD_NAME, Collections.singletonList(incidentState)));
136+
maybeStage.ifPresent(
137+
incidentStage ->
138+
criterionMap.put(
139+
INCIDENT_STAGE_SEARCH_INDEX_FIELD_NAME, Collections.singletonList(incidentStage)));
140+
maybePriority.ifPresent(
141+
incidentPriority ->
142+
criterionMap.put(
143+
INCIDENT_PRIORITY_SEARCH_INDEX_FIELD_NAME,
144+
Collections.singletonList(
145+
IncidentUtils.mapIncidentPriority(IncidentPriority.valueOf(incidentPriority))
146+
.toString())));
147+
maybeAssigneeUrns.ifPresent(
148+
assigneeUrns -> criterionMap.put(INCIDENT_ASSIGNEES_SEARCH_INDEX_FIELD_NAME, assigneeUrns));
149+
return QueryUtils.newListsFilter(criterionMap);
120150
}
121151

122152
private List<SortCriterion> buildIncidentsSortCriteria() {

datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/incident/IncidentUtils.java

+85
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,41 @@
33
import com.datahub.authorization.ConjunctivePrivilegeGroup;
44
import com.datahub.authorization.DisjunctivePrivilegeGroup;
55
import com.google.common.collect.ImmutableList;
6+
import com.linkedin.common.AuditStamp;
67
import com.linkedin.common.urn.Urn;
8+
import com.linkedin.common.urn.UrnUtils;
79
import com.linkedin.datahub.graphql.QueryContext;
810
import com.linkedin.datahub.graphql.authorization.AuthorizationUtils;
11+
import com.linkedin.datahub.graphql.generated.IncidentPriority;
12+
import com.linkedin.incident.IncidentAssignee;
13+
import com.linkedin.incident.IncidentAssigneeArray;
14+
import com.linkedin.incident.IncidentStage;
15+
import com.linkedin.incident.IncidentState;
16+
import com.linkedin.incident.IncidentStatus;
917
import com.linkedin.metadata.authorization.PoliciesConfig;
18+
import java.util.List;
19+
import java.util.Objects;
20+
import java.util.stream.Collectors;
21+
import javax.annotation.Nonnull;
22+
import javax.annotation.Nullable;
1023

1124
public class IncidentUtils {
1225

26+
public static List<Urn> stringsToUrns(List<String> urns) {
27+
return urns.stream()
28+
.map(
29+
rawUrn -> {
30+
try {
31+
return Urn.createFromString(rawUrn);
32+
} catch (Exception e) {
33+
return null;
34+
}
35+
})
36+
.filter(Objects::nonNull)
37+
.distinct()
38+
.toList();
39+
}
40+
1341
public static boolean isAuthorizedToEditIncidentForResource(
1442
final Urn resourceUrn, final QueryContext context) {
1543
final DisjunctivePrivilegeGroup orPrivilegeGroups =
@@ -22,4 +50,61 @@ public static boolean isAuthorizedToEditIncidentForResource(
2250
return AuthorizationUtils.isAuthorized(
2351
context, resourceUrn.getEntityType(), resourceUrn.toString(), orPrivilegeGroups);
2452
}
53+
54+
@Nullable
55+
public static Integer mapIncidentPriority(@Nullable final IncidentPriority priority) {
56+
if (priority == null) {
57+
return null;
58+
}
59+
switch (priority) {
60+
case LOW:
61+
return 3;
62+
case MEDIUM:
63+
return 2;
64+
case HIGH:
65+
return 1;
66+
case CRITICAL:
67+
return 0;
68+
default:
69+
throw new IllegalArgumentException("Invalid incident priority: " + priority);
70+
}
71+
}
72+
73+
@Nullable
74+
public static IncidentAssigneeArray mapIncidentAssignees(
75+
@Nullable final List<String> assignees, @Nonnull final AuditStamp auditStamp) {
76+
if (assignees == null) {
77+
return null;
78+
}
79+
return new IncidentAssigneeArray(
80+
assignees.stream()
81+
.map(assignee -> createAssignee(assignee, auditStamp))
82+
.collect(Collectors.toList()));
83+
}
84+
85+
@Nonnull
86+
public static IncidentStatus mapIncidentStatus(
87+
@Nullable final com.linkedin.datahub.graphql.generated.IncidentStatusInput input,
88+
@Nonnull final AuditStamp auditStamp) {
89+
if (input == null) {
90+
return new IncidentStatus().setState(IncidentState.ACTIVE).setLastUpdated(auditStamp);
91+
}
92+
93+
IncidentStatus status = new IncidentStatus();
94+
status.setState(IncidentState.valueOf(input.getState().toString()));
95+
if (input.getStage() != null) {
96+
status.setStage(IncidentStage.valueOf(input.getStage().toString()));
97+
}
98+
if (input.getMessage() != null) {
99+
status.setMessage(input.getMessage());
100+
}
101+
return status;
102+
}
103+
104+
private static IncidentAssignee createAssignee(
105+
@Nonnull final String assigneeUrn, @Nonnull final AuditStamp auditStamp) {
106+
return new IncidentAssignee().setActor(UrnUtils.getUrn(assigneeUrn)).setAssignedAt(auditStamp);
107+
}
108+
109+
private IncidentUtils() {}
25110
}

0 commit comments

Comments
 (0)