From eae7c190528bfb6d91b5c1e33001f97de3130d0c Mon Sep 17 00:00:00 2001 From: Anatol Sialitski Date: Wed, 14 Feb 2024 18:05:23 +0100 Subject: [PATCH] PortalRequest must use correct application in resolve function #741 --- .../graphql/ExtensionsProcessor.java | 5 +- .../graphql/fetchers/DynamicDataFetcher.java | 23 +++++- .../graphql/helper/PortalRequestHelper.java | 74 +++++++++++++++++++ .../transformer/ContextualFieldResolver.java | 27 +++++++ .../ExtensionsExtractorService.java | 42 +++++++---- .../graphql/transformer/SchemaExtensions.java | 10 +-- 6 files changed, 157 insertions(+), 24 deletions(-) create mode 100644 src/main/java/com/enonic/app/guillotine/graphql/helper/PortalRequestHelper.java create mode 100644 src/main/java/com/enonic/app/guillotine/graphql/transformer/ContextualFieldResolver.java diff --git a/src/main/java/com/enonic/app/guillotine/graphql/ExtensionsProcessor.java b/src/main/java/com/enonic/app/guillotine/graphql/ExtensionsProcessor.java index 3fcb29e6..aead90fe 100644 --- a/src/main/java/com/enonic/app/guillotine/graphql/ExtensionsProcessor.java +++ b/src/main/java/com/enonic/app/guillotine/graphql/ExtensionsProcessor.java @@ -14,6 +14,7 @@ import com.enonic.app.guillotine.graphql.fetchers.DynamicTypeResolver; import com.enonic.app.guillotine.graphql.helper.CastHelper; import com.enonic.app.guillotine.graphql.helper.GraphQLHelper; +import com.enonic.app.guillotine.graphql.transformer.ContextualFieldResolver; import com.enonic.app.guillotine.graphql.transformer.SchemaExtensions; import com.enonic.xp.script.ScriptValue; @@ -107,10 +108,10 @@ private void processTypeResolvers( final Map typeResolvers ( typeName, typeResolver ) -> typesRegister.addTypeResolver( typeName, new DynamicTypeResolver( typeResolver ) ) ); } - private void processResolvers( final Map> resolvers ) + private void processResolvers( final Map> resolvers ) { resolvers.forEach( ( typeName, typeResolver ) -> { - Map fieldResolvers = resolvers.get( typeName ); + Map fieldResolvers = resolvers.get( typeName ); fieldResolvers.forEach( ( fieldName, fieldResolver ) -> typesRegister.addResolver( typeName, fieldName, new DynamicDataFetcher( fieldResolver ) ) ); } ); diff --git a/src/main/java/com/enonic/app/guillotine/graphql/fetchers/DynamicDataFetcher.java b/src/main/java/com/enonic/app/guillotine/graphql/fetchers/DynamicDataFetcher.java index 4529a4ee..6c36e644 100644 --- a/src/main/java/com/enonic/app/guillotine/graphql/fetchers/DynamicDataFetcher.java +++ b/src/main/java/com/enonic/app/guillotine/graphql/fetchers/DynamicDataFetcher.java @@ -4,7 +4,12 @@ import graphql.schema.DataFetchingEnvironment; import com.enonic.app.guillotine.graphql.GuillotineSerializer; +import com.enonic.app.guillotine.graphql.helper.PortalRequestHelper; +import com.enonic.app.guillotine.graphql.transformer.ContextualFieldResolver; import com.enonic.app.guillotine.mapper.DataFetchingEnvironmentMapper; +import com.enonic.xp.app.ApplicationKey; +import com.enonic.xp.portal.PortalRequest; +import com.enonic.xp.portal.PortalRequestAccessor; import com.enonic.xp.script.ScriptValue; public class DynamicDataFetcher @@ -12,15 +17,27 @@ public class DynamicDataFetcher { private final ScriptValue resolveFunction; - public DynamicDataFetcher( final ScriptValue resolveFunction ) + private final ApplicationKey applicationKey; + + public DynamicDataFetcher( final ContextualFieldResolver fieldResolver ) { - this.resolveFunction = resolveFunction; + this.resolveFunction = fieldResolver.getResolveFunction(); + this.applicationKey = fieldResolver.getApplicationKey(); } @Override public Object get( final DataFetchingEnvironment environment ) throws Exception { - return GuillotineSerializer.serialize( resolveFunction.call( new DataFetchingEnvironmentMapper( environment ) ) ); + PortalRequest oldPortalRequest = PortalRequestAccessor.get(); + PortalRequestAccessor.set( PortalRequestHelper.createPortalRequest( oldPortalRequest, applicationKey ) ); + try + { + return GuillotineSerializer.serialize( resolveFunction.call( new DataFetchingEnvironmentMapper( environment ) ) ); + } + finally + { + PortalRequestAccessor.set( oldPortalRequest ); + } } } diff --git a/src/main/java/com/enonic/app/guillotine/graphql/helper/PortalRequestHelper.java b/src/main/java/com/enonic/app/guillotine/graphql/helper/PortalRequestHelper.java new file mode 100644 index 00000000..40bc0455 --- /dev/null +++ b/src/main/java/com/enonic/app/guillotine/graphql/helper/PortalRequestHelper.java @@ -0,0 +1,74 @@ +package com.enonic.app.guillotine.graphql.helper; + +import graphql.schema.DataFetchingEnvironment; + +import com.enonic.xp.app.ApplicationKey; +import com.enonic.xp.portal.PortalRequest; + +public final class PortalRequestHelper +{ + private PortalRequestHelper() + { + } + + public static PortalRequest createPortalRequest( final PortalRequest source, final DataFetchingEnvironment environment ) + { + if ( source == null ) + { + return null; + } + + final PortalRequest result = createDefaultPortalRequest( source ); + result.setRepositoryId( GuillotineLocalContextHelper.getRepositoryId( environment, source.getRepositoryId() ) ); + result.setBranch( GuillotineLocalContextHelper.getBranch( environment, source.getBranch() ) ); + return result; + } + + public static PortalRequest createPortalRequest( final PortalRequest source, final ApplicationKey applicationKey ) + { + if ( source == null ) + { + return null; + } + + final PortalRequest result = createDefaultPortalRequest( source ); + result.setApplicationKey( applicationKey ); + return result; + } + + private static PortalRequest createDefaultPortalRequest( final PortalRequest source ) + { + final PortalRequest result = new PortalRequest(); + + result.setRepositoryId( source.getRepositoryId() ); + result.setBranch( source.getBranch() ); + result.setApplicationKey( source.getApplicationKey() ); + result.setContentPath( source.getContentPath() ); + result.setMode( source.getMode() ); + result.setRawRequest( source.getRawRequest() ); + result.setContent( source.getContent() ); + result.setSite( source.getSite() ); + result.setMethod( source.getMethod() ); + result.setBaseUri( source.getBaseUri() ); + result.setRawPath( source.getRawPath() ); + result.setWebSocketContext( source.getWebSocketContext() ); + result.setComponent( source.getComponent() ); + result.setControllerScript( source.getControllerScript() ); + result.setPageDescriptor( source.getPageDescriptor() ); + result.setPageTemplate( source.getPageTemplate() ); + result.setContextPath( source.getContextPath() ); + result.setValidTicket( source.isValidTicket() ); + result.setBody( source.getBody() ); + result.setIdProvider( source.getIdProvider() ); + result.setHost( source.getHost() ); + result.setPort( source.getPort() ); + result.setScheme( source.getScheme() ); + result.setPath( source.getPath() ); + result.setEndpointPath( source.getEndpointPath() ); + result.setUrl( source.getUrl() ); + result.setContentType( source.getContentType() ); + result.setRemoteAddress( source.getRemoteAddress() ); + + return result; + } +} diff --git a/src/main/java/com/enonic/app/guillotine/graphql/transformer/ContextualFieldResolver.java b/src/main/java/com/enonic/app/guillotine/graphql/transformer/ContextualFieldResolver.java new file mode 100644 index 00000000..ce798a08 --- /dev/null +++ b/src/main/java/com/enonic/app/guillotine/graphql/transformer/ContextualFieldResolver.java @@ -0,0 +1,27 @@ +package com.enonic.app.guillotine.graphql.transformer; + +import com.enonic.xp.app.ApplicationKey; +import com.enonic.xp.script.ScriptValue; + +public class ContextualFieldResolver +{ + private final ApplicationKey applicationKey; + + private final ScriptValue resolveFunction; + + public ContextualFieldResolver( final ApplicationKey applicationKey, final ScriptValue resolveFunction ) + { + this.applicationKey = applicationKey; + this.resolveFunction = resolveFunction; + } + + public ApplicationKey getApplicationKey() + { + return applicationKey; + } + + public ScriptValue getResolveFunction() + { + return resolveFunction; + } +} diff --git a/src/main/java/com/enonic/app/guillotine/graphql/transformer/ExtensionsExtractorService.java b/src/main/java/com/enonic/app/guillotine/graphql/transformer/ExtensionsExtractorService.java index b37bdd43..38a1efb3 100644 --- a/src/main/java/com/enonic/app/guillotine/graphql/transformer/ExtensionsExtractorService.java +++ b/src/main/java/com/enonic/app/guillotine/graphql/transformer/ExtensionsExtractorService.java @@ -11,6 +11,8 @@ import com.enonic.app.guillotine.mapper.GuillotineMapGenerator; import com.enonic.xp.app.ApplicationKey; import com.enonic.xp.app.ApplicationService; +import com.enonic.xp.portal.PortalRequest; +import com.enonic.xp.portal.PortalRequestAccessor; import com.enonic.xp.portal.script.PortalScriptService; import com.enonic.xp.resource.ResourceKey; import com.enonic.xp.resource.ResourceService; @@ -81,7 +83,7 @@ public SchemaExtensions extractSchemaExtensions() extractEnums( schemaExtensionsBuilder, enums ); extractUnions( schemaExtensionsBuilder, unions ); extractInterfaces( schemaExtensionsBuilder, interfaces ); - extractResolvers( schemaExtensionsBuilder, resolvers ); + extractResolvers( schemaExtensionsBuilder, resolvers, application.getKey() ); extractTypeResolvers( schemaExtensionsBuilder, typeResolvers ); extractCreationCallbacks( schemaExtensionsBuilder, creationCallbacks ); } @@ -116,7 +118,8 @@ private static void extractTypeResolvers( final SchemaExtensions.Builder schemaE } } - private static void extractResolvers( final SchemaExtensions.Builder schemaExtensionsBuilder, final ScriptValue resolvers ) + private static void extractResolvers( final SchemaExtensions.Builder schemaExtensionsBuilder, final ScriptValue resolvers, + final ApplicationKey applicationKey ) { if ( resolvers != null ) { @@ -128,7 +131,8 @@ private static void extractResolvers( final SchemaExtensions.Builder schemaExten { typeResolverDef.getKeys().forEach( fieldName -> { ScriptValue resolverDef = typeResolverDef.getMember( fieldName ); - schemaExtensionsBuilder.addResolver( typeName, fieldName, resolverDef ); + ContextualFieldResolver fieldResolver = new ContextualFieldResolver( applicationKey, resolverDef ); + schemaExtensionsBuilder.addResolver( typeName, fieldName, fieldResolver ); } ); } } ); @@ -189,25 +193,35 @@ private Object getGraphQLObject() private ScriptValue executeMethod( ApplicationKey applicationKey, Object graphQL ) { - ResourceKey resourceKey = ResourceKey.from( applicationKey, SCRIPT_PATH ); - if ( resourceService.getResource( resourceKey ).exists() ) + PortalRequest oldPortalRequest = PortalRequestAccessor.get(); + PortalRequestAccessor.remove(); + try { - ScriptExports scriptExports = portalScriptService.execute( resourceKey ); - if ( scriptExports != null ) + ResourceKey resourceKey = ResourceKey.from( applicationKey, SCRIPT_PATH ); + if ( resourceService.getResource( resourceKey ).exists() ) { - if ( scriptExports.hasMethod( EXTENSIONS_METHOD_NAME ) ) + ScriptExports scriptExports = portalScriptService.execute( resourceKey ); + if ( scriptExports != null ) { - try + if ( scriptExports.hasMethod( EXTENSIONS_METHOD_NAME ) ) { - return scriptExports.executeMethod( EXTENSIONS_METHOD_NAME, graphQL ); - } - catch ( Exception e ) - { - LOG.warn( "{} function can not be extracted from {}", EXTENSIONS_METHOD_NAME, SCRIPT_PATH, e ); + try + { + return scriptExports.executeMethod( EXTENSIONS_METHOD_NAME, graphQL ); + } + catch ( Exception e ) + { + LOG.warn( "{} function can not be extracted from {}", EXTENSIONS_METHOD_NAME, SCRIPT_PATH, e ); + } } } } } + finally + { + PortalRequestAccessor.set( oldPortalRequest ); + } + return null; } } diff --git a/src/main/java/com/enonic/app/guillotine/graphql/transformer/SchemaExtensions.java b/src/main/java/com/enonic/app/guillotine/graphql/transformer/SchemaExtensions.java index aeafe008..3345ed3b 100644 --- a/src/main/java/com/enonic/app/guillotine/graphql/transformer/SchemaExtensions.java +++ b/src/main/java/com/enonic/app/guillotine/graphql/transformer/SchemaExtensions.java @@ -19,7 +19,7 @@ public class SchemaExtensions private final Map interfaces; - private final Map> resolvers; + private final Map> resolvers; private final Map typeResolvers; @@ -62,7 +62,7 @@ public Map getInterfaces() return interfaces; } - public Map> getResolvers() + public Map> getResolvers() { return resolvers; } @@ -94,7 +94,7 @@ public static class Builder private final Map interfaces = new LinkedHashMap<>(); - private final Map> resolvers = new LinkedHashMap<>(); + private final Map> resolvers = new LinkedHashMap<>(); private final Map typeResolvers = new LinkedHashMap<>(); @@ -137,10 +137,10 @@ public Builder addInterface( String typeName, ScriptValue typeDef ) return this; } - public Builder addResolver( String typeName, String fieldName, ScriptValue resolverDef ) + public Builder addResolver( String typeName, String fieldName, ContextualFieldResolver fieldResolver ) { this.resolvers.computeIfAbsent( typeName, k -> new LinkedHashMap<>() ); - this.resolvers.get( typeName ).put( fieldName, resolverDef ); + this.resolvers.get( typeName ).put( fieldName, fieldResolver ); return this; }