Skip to content

Commit

Permalink
Merge branch 'master' into feature/disable-access-mgmt-tab-when-no-roles
Browse files Browse the repository at this point in the history
  • Loading branch information
githendrik authored Jan 18, 2024
2 parents 22e168b + 68ef1ef commit c08aa92
Show file tree
Hide file tree
Showing 158 changed files with 3,047 additions and 682 deletions.
22 changes: 13 additions & 9 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,21 @@ buildscript {
// Releases: https://github.com/linkedin/rest.li/blob/master/CHANGELOG.md
ext.pegasusVersion = '29.48.4'
ext.mavenVersion = '3.6.3'
ext.springVersion = '5.3.29'
ext.springBootVersion = '2.7.14'
ext.springVersion = '6.1.2'
ext.springBootVersion = '3.2.1'
ext.springKafkaVersion = '3.1.1'
ext.openTelemetryVersion = '1.18.0'
ext.neo4jVersion = '5.14.0'
ext.neo4jTestVersion = '5.14.0'
ext.neo4jApocVersion = '5.14.0'
ext.testContainersVersion = '1.17.4'
ext.elasticsearchVersion = '2.9.0' // ES 7.10, Opensearch 1.x, 2.x
ext.jacksonVersion = '2.15.3'
ext.jettyVersion = '9.4.46.v20220331'
ext.jettyVersion = '11.0.19'
ext.playVersion = '2.8.18'
ext.log4jVersion = '2.19.0'
ext.slf4jVersion = '1.7.36'
ext.logbackClassic = '1.2.13'
ext.logbackClassic = '1.4.14'
ext.hadoop3Version = '3.3.5'
ext.kafkaVersion = '2.3.0'
ext.hazelcastVersion = '5.3.6'
Expand Down Expand Up @@ -104,7 +105,8 @@ project.ext.externalDependency = [
'graphqlJava': 'com.graphql-java:graphql-java:19.5',
'graphqlJavaScalars': 'com.graphql-java:graphql-java-extended-scalars:19.1',
'gson': 'com.google.code.gson:gson:2.8.9',
'guice': 'com.google.inject:guice:4.2.3',
'guice': 'com.google.inject:guice:7.0.0',
'guice4': 'com.google.inject:guice:4.2.3', // Used for frontend while still on old Play version
'guava': 'com.google.guava:guava:32.1.2-jre',
'h2': 'com.h2database:h2:2.2.224',
'hadoopCommon':'org.apache.hadoop:hadoop-common:2.7.2',
Expand All @@ -115,7 +117,7 @@ project.ext.externalDependency = [
'hazelcastSpring':"com.hazelcast:hazelcast-spring:$hazelcastVersion",
'hazelcastTest':"com.hazelcast:hazelcast:$hazelcastVersion:tests",
'hibernateCore': 'org.hibernate:hibernate-core:5.2.16.Final',
'httpClient': 'org.apache.httpcomponents:httpclient:4.5.9',
'httpClient': 'org.apache.httpcomponents.client5:httpclient5:5.3',
'httpAsyncClient': 'org.apache.httpcomponents:httpasyncclient:4.1.5',
'iStackCommons': 'com.sun.istack:istack-commons-runtime:4.0.1',
'jacksonJDK8': "com.fasterxml.jackson.datatype:jackson-datatype-jdk8:$jacksonVersion",
Expand Down Expand Up @@ -192,15 +194,15 @@ project.ext.externalDependency = [
'reflections': 'org.reflections:reflections:0.9.9',
'resilience4j': 'io.github.resilience4j:resilience4j-retry:1.7.1',
'rythmEngine': 'org.rythmengine:rythm-engine:1.3.0',
'servletApi': 'javax.servlet:javax.servlet-api:3.1.0',
'servletApi': 'jakarta.servlet:jakarta.servlet-api:6.0.0',
'shiroCore': 'org.apache.shiro:shiro-core:1.11.0',
'snakeYaml': 'org.yaml:snakeyaml:2.0',
'sparkSql' : 'org.apache.spark:spark-sql_2.12:3.0.3',
'sparkHive' : 'org.apache.spark:spark-hive_2.12:3.0.3',
'springBeans': "org.springframework:spring-beans:$springVersion",
'springContext': "org.springframework:spring-context:$springVersion",
'springCore': "org.springframework:spring-core:$springVersion",
'springDocUI': 'org.springdoc:springdoc-openapi-ui:1.6.14',
'springDocUI': 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0',
'springJdbc': "org.springframework:spring-jdbc:$springVersion",
'springWeb': "org.springframework:spring-web:$springVersion",
'springWebMVC': "org.springframework:spring-webmvc:$springVersion",
Expand All @@ -211,7 +213,7 @@ project.ext.externalDependency = [
'springBootStarterJetty': "org.springframework.boot:spring-boot-starter-jetty:$springBootVersion",
'springBootStarterCache': "org.springframework.boot:spring-boot-starter-cache:$springBootVersion",
'springBootStarterValidation': "org.springframework.boot:spring-boot-starter-validation:$springBootVersion",
'springKafka': 'org.springframework.kafka:spring-kafka:2.9.13',
'springKafka': "org.springframework.kafka:spring-kafka:$springKafkaVersion",
'springActuator': "org.springframework.boot:spring-boot-starter-actuator:$springBootVersion",
'swaggerAnnotations': 'io.swagger.core.v3:swagger-annotations:2.2.15',
'swaggerCli': 'io.swagger.codegen.v3:swagger-codegen-cli:3.0.46',
Expand Down Expand Up @@ -268,6 +270,8 @@ allprojects {
javaCompiler = javaToolchains.compilerFor {
languageVersion = JavaLanguageVersion.of(jdkVersion)
}
// Puts parameter names into compiled class files, necessary for Spring 6
options.compilerArgs.add("-parameters")
}

tasks.withType(JavaExec).configureEach {
Expand Down
2 changes: 1 addition & 1 deletion datahub-frontend/play.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ dependencies {

implementation externalDependency.slf4jApi
compileOnly externalDependency.lombok
runtimeOnly externalDependency.guice
runtimeOnly externalDependency.guice4
runtimeOnly (externalDependency.playDocs) {
exclude group: 'com.typesafe.akka', module: 'akka-http-core_2.12'
}
Expand Down
1 change: 1 addition & 0 deletions datahub-graphql-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ graphqlCodegen {
]
outputDir = new File("$projectDir/src/mainGeneratedGraphQL/java")
packageName = "com.linkedin.datahub.graphql.generated"
generateToString = true
generateApis = true
generateParameterizedFieldsResolvers = false
modelValidationAnnotation = "@javax.annotation.Nonnull"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@
import com.linkedin.datahub.graphql.resolvers.post.CreatePostResolver;
import com.linkedin.datahub.graphql.resolvers.post.DeletePostResolver;
import com.linkedin.datahub.graphql.resolvers.post.ListPostsResolver;
import com.linkedin.datahub.graphql.resolvers.post.UpdatePostResolver;
import com.linkedin.datahub.graphql.resolvers.query.CreateQueryResolver;
import com.linkedin.datahub.graphql.resolvers.query.DeleteQueryResolver;
import com.linkedin.datahub.graphql.resolvers.query.ListQueriesResolver;
Expand Down Expand Up @@ -1103,6 +1104,7 @@ private void configureMutationResolvers(final RuntimeWiring.Builder builder) {
"acceptRole", new AcceptRoleResolver(this.roleService, this.inviteTokenService))
.dataFetcher("createPost", new CreatePostResolver(this.postService))
.dataFetcher("deletePost", new DeletePostResolver(this.postService))
.dataFetcher("updatePost", new UpdatePostResolver(this.postService))
.dataFetcher(
"batchUpdateStepStates", new BatchUpdateStepStatesResolver(this.entityClient))
.dataFetcher("createView", new CreateViewResolver(this.viewService))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.linkedin.datahub.graphql.resolvers.post;

import static com.linkedin.datahub.graphql.resolvers.ResolverUtils.bindArgument;

import com.datahub.authentication.Authentication;
import com.datahub.authentication.post.PostService;
import com.linkedin.common.Media;
import com.linkedin.common.urn.Urn;
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.PostContentType;
import com.linkedin.datahub.graphql.generated.PostType;
import com.linkedin.datahub.graphql.generated.UpdateMediaInput;
import com.linkedin.datahub.graphql.generated.UpdatePostContentInput;
import com.linkedin.datahub.graphql.generated.UpdatePostInput;
import com.linkedin.post.PostContent;
import graphql.GraphQLException;
import graphql.schema.DataFetcher;
import graphql.schema.DataFetchingEnvironment;
import java.util.concurrent.CompletableFuture;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@RequiredArgsConstructor
public class UpdatePostResolver implements DataFetcher<CompletableFuture<Boolean>> {
private final PostService postService;

@Override
public CompletableFuture<Boolean> get(final DataFetchingEnvironment environment)
throws Exception {
final QueryContext context = environment.getContext();

if (!AuthorizationUtils.canCreateGlobalAnnouncements(context)) {
throw new AuthorizationException(
"Unauthorized to update posts. Please contact your DataHub administrator if this needs corrective action.");
}

final UpdatePostInput input =
bindArgument(environment.getArgument("input"), UpdatePostInput.class);
final Urn postUrn = Urn.createFromString(input.getUrn());

final PostType type = input.getPostType();
final UpdatePostContentInput content = input.getContent();
final PostContentType contentType = content.getContentType();
final String title = content.getTitle();
final String link = content.getLink();
final String description = content.getDescription();
final UpdateMediaInput updateMediaInput = content.getMedia();
final Authentication authentication = context.getAuthentication();

Media media =
updateMediaInput == null
? null
: postService.mapMedia(
updateMediaInput.getType().toString(), updateMediaInput.getLocation());
PostContent postContent =
postService.mapPostContent(contentType.toString(), title, description, link, media);

return CompletableFuture.supplyAsync(
() -> {
try {
return postService.updatePost(postUrn, type.toString(), postContent, authentication);
} catch (Exception e) {
throw new GraphQLException("Failed to update or edit post", e);
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
Expand Down Expand Up @@ -67,7 +68,10 @@ public CompletableFuture<AutoCompleteMultipleResults> get(DataFetchingEnvironmen
List<EntityType> types = getEntityTypes(input.getTypes(), maybeResolvedView);
if (types != null && types.size() > 0) {
return AutocompleteUtils.batchGetAutocompleteResults(
types.stream().map(_typeToEntity::get).collect(Collectors.toList()),
types.stream()
.map(_typeToEntity::get)
.filter(Objects::nonNull)
.collect(Collectors.toList()),
sanitizedQuery,
input,
environment,
Expand All @@ -76,7 +80,10 @@ public CompletableFuture<AutoCompleteMultipleResults> get(DataFetchingEnvironmen

// By default, autocomplete only against the Default Set of Autocomplete entities
return AutocompleteUtils.batchGetAutocompleteResults(
AUTO_COMPLETE_ENTITY_TYPES.stream().map(_typeToEntity::get).collect(Collectors.toList()),
AUTO_COMPLETE_ENTITY_TYPES.stream()
.map(_typeToEntity::get)
.filter(Objects::nonNull)
.collect(Collectors.toList()),
sanitizedQuery,
input,
environment,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ private SearchUtils() {}
EntityType.TAG,
EntityType.CORP_USER,
EntityType.CORP_GROUP,
EntityType.ROLE,
EntityType.NOTEBOOK,
EntityType.DATA_PRODUCT);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public SchemaField apply(
}
result.setIsPartOfKey(input.isIsPartOfKey());
result.setIsPartitioningKey(input.isIsPartitioningKey());
result.setJsonProps(input.getJsonProps());
return result;
}

Expand Down
30 changes: 30 additions & 0 deletions datahub-graphql-core/src/main/resources/entity.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,11 @@ type Mutation {
"""
createPost(input: CreatePostInput!): Boolean

"""
Update or edit a post
"""
updatePost(input: UpdatePostInput!): Boolean

"""
Delete a post
"""
Expand Down Expand Up @@ -2892,6 +2897,11 @@ type SchemaField {
Whether the field is part of a partitioning key schema
"""
isPartitioningKey: Boolean

"""
For schema fields that have other properties that are not modeled explicitly, represented as a JSON string.
"""
jsonProps: String
}

"""
Expand Down Expand Up @@ -10211,6 +10221,26 @@ input CreatePostInput {
content: UpdatePostContentInput!
}

"""
Input provided when creating a Post
"""
input UpdatePostInput {
"""
The urn of the post to edit or update
"""
urn: String!,

"""
The type of post
"""
postType: PostType!

"""
The content of the post
"""
content: UpdatePostContentInput!
}

"""
Input provided for filling in a post content
"""
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package com.linkedin.datahub.graphql.resolvers.post;

import static com.linkedin.datahub.graphql.TestUtils.getMockAllowContext;
import static com.linkedin.datahub.graphql.TestUtils.getMockDenyContext;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertThrows;
import static org.testng.Assert.assertTrue;

import com.datahub.authentication.Authentication;
import com.datahub.authentication.post.PostService;
import com.linkedin.common.Media;
import com.linkedin.common.url.Url;
import com.linkedin.common.urn.Urn;
import com.linkedin.common.urn.UrnUtils;
import com.linkedin.datahub.graphql.QueryContext;
import com.linkedin.datahub.graphql.generated.MediaType;
import com.linkedin.datahub.graphql.generated.PostContentType;
import com.linkedin.datahub.graphql.generated.PostType;
import com.linkedin.datahub.graphql.generated.UpdateMediaInput;
import com.linkedin.datahub.graphql.generated.UpdatePostContentInput;
import com.linkedin.datahub.graphql.generated.UpdatePostInput;
import graphql.schema.DataFetchingEnvironment;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

public class UpdatePostResolverTest {

private static final Urn TEST_URN = UrnUtils.getUrn("urn:li:post:post-id");
private static final MediaType POST_MEDIA_TYPE = MediaType.IMAGE;
private static final String POST_MEDIA_LOCATION =
"https://datahubproject.io/img/datahub-logo-color-light-horizontal.svg";
private static final PostContentType POST_CONTENT_TYPE = PostContentType.LINK;
private static final String POST_TITLE = "title";
private static final String POST_DESCRIPTION = "description";
private static final String POST_LINK = "https://datahubproject.io";
private PostService postService;
private UpdatePostResolver resolver;
private DataFetchingEnvironment dataFetchingEnvironment;
private Authentication authentication;

@BeforeMethod
public void setupTest() throws Exception {
postService = mock(PostService.class);
dataFetchingEnvironment = mock(DataFetchingEnvironment.class);
authentication = mock(Authentication.class);

resolver = new UpdatePostResolver(postService);
}

@Test
public void testNotAuthorizedFails() {
QueryContext mockContext = getMockDenyContext();
when(dataFetchingEnvironment.getContext()).thenReturn(mockContext);

assertThrows(() -> resolver.get(dataFetchingEnvironment).join());
}

@Test
public void testUpdatePost() throws Exception {
QueryContext mockContext = getMockAllowContext();
when(dataFetchingEnvironment.getContext()).thenReturn(mockContext);
when(mockContext.getAuthentication()).thenReturn(authentication);

UpdateMediaInput media = new UpdateMediaInput();
media.setType(POST_MEDIA_TYPE);
media.setLocation(POST_MEDIA_LOCATION);
Media mediaObj =
new Media()
.setType(com.linkedin.common.MediaType.valueOf(POST_MEDIA_TYPE.toString()))
.setLocation(new Url(POST_MEDIA_LOCATION));
when(postService.mapMedia(POST_MEDIA_TYPE.toString(), POST_MEDIA_LOCATION))
.thenReturn(mediaObj);

UpdatePostContentInput content = new UpdatePostContentInput();
content.setTitle(POST_TITLE);
content.setDescription(POST_DESCRIPTION);
content.setLink(POST_LINK);
content.setContentType(POST_CONTENT_TYPE);
content.setMedia(media);
com.linkedin.post.PostContent postContentObj =
new com.linkedin.post.PostContent()
.setType(com.linkedin.post.PostContentType.valueOf(POST_CONTENT_TYPE.toString()))
.setTitle(POST_TITLE)
.setDescription(POST_DESCRIPTION)
.setLink(new Url(POST_LINK))
.setMedia(
new Media()
.setType(com.linkedin.common.MediaType.valueOf(POST_MEDIA_TYPE.toString()))
.setLocation(new Url(POST_MEDIA_LOCATION)));
when(postService.mapPostContent(
eq(POST_CONTENT_TYPE.toString()),
eq(POST_TITLE),
eq(POST_DESCRIPTION),
eq(POST_LINK),
any(Media.class)))
.thenReturn(postContentObj);

UpdatePostInput input = new UpdatePostInput();
input.setUrn(TEST_URN.toString());
input.setPostType(PostType.HOME_PAGE_ANNOUNCEMENT);
input.setContent(content);
when(dataFetchingEnvironment.getArgument("input")).thenReturn(input);
when(postService.updatePost(
TEST_URN, PostType.HOME_PAGE_ANNOUNCEMENT.toString(), postContentObj, authentication))
.thenReturn(true);

assertTrue(resolver.get(dataFetchingEnvironment).join());
verify(postService, times(1)).updatePost(any(), any(), any(), any());
}
}
Loading

0 comments on commit c08aa92

Please sign in to comment.