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

X-data is not added to content when it's created #9952 #10031

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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
@@ -1,21 +1,38 @@
package com.enonic.xp.core.impl.content;

import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.net.MediaType;

import com.enonic.xp.app.ApplicationKey;
import com.enonic.xp.app.ApplicationKeys;
import com.enonic.xp.app.ApplicationWildcardMatcher;
import com.enonic.xp.attachment.CreateAttachment;
import com.enonic.xp.attachment.CreateAttachments;
import com.enonic.xp.content.processor.ContentProcessor;
import com.enonic.xp.content.ContentValidator;
import com.enonic.xp.content.ExtraData;
import com.enonic.xp.content.processor.ContentProcessor;
import com.enonic.xp.context.Context;
import com.enonic.xp.context.ContextAccessor;
import com.enonic.xp.core.internal.FileNames;
import com.enonic.xp.data.PropertyTree;
import com.enonic.xp.form.FormDefaultValuesProcessor;
import com.enonic.xp.schema.content.ContentType;
import com.enonic.xp.schema.content.ContentTypeName;
import com.enonic.xp.schema.content.GetContentTypeParams;
import com.enonic.xp.schema.xdata.XData;
import com.enonic.xp.schema.xdata.XDataService;
import com.enonic.xp.security.User;
import com.enonic.xp.site.SiteService;
import com.enonic.xp.site.XDataMapping;

import static com.google.common.base.Strings.nullToEmpty;

class AbstractCreatingOrUpdatingContentCommand
extends AbstractContentCommand
Expand All @@ -37,6 +54,8 @@ class AbstractCreatingOrUpdatingContentCommand

final boolean allowUnsafeAttachmentNames;

final FormDefaultValuesProcessor formDefaultValuesProcessor;

AbstractCreatingOrUpdatingContentCommand( final Builder<?> builder )
{
super( builder );
Expand All @@ -45,20 +64,23 @@ class AbstractCreatingOrUpdatingContentCommand
this.contentProcessors = List.copyOf( builder.contentProcessors );
this.contentValidators = List.copyOf( builder.contentValidators );
this.allowUnsafeAttachmentNames = builder.allowUnsafeAttachmentNames;
this.formDefaultValuesProcessor = builder.formDefaultValuesProcessor;
}

public static class Builder<B extends Builder<B>>
extends AbstractContentCommand.Builder<B>
{
private XDataService xDataService;
XDataService xDataService;

SiteService siteService;

private SiteService siteService;
List<ContentProcessor> contentProcessors = List.of();

private List<ContentProcessor> contentProcessors = List.of();
List<ContentValidator> contentValidators = List.of();

private List<ContentValidator> contentValidators = List.of();
boolean allowUnsafeAttachmentNames;

private boolean allowUnsafeAttachmentNames;
FormDefaultValuesProcessor formDefaultValuesProcessor;

Builder()
{
Expand Down Expand Up @@ -108,6 +130,13 @@ B allowUnsafeAttachmentNames( final boolean allowUnsafeAttachmentNames )
return (B) this;
}

@SuppressWarnings("unchecked")
B formDefaultValuesProcessor( final FormDefaultValuesProcessor formDefaultValuesProcessor )
{
this.formDefaultValuesProcessor = formDefaultValuesProcessor;
return (B) this;
}

@Override
void validate()
{
Expand Down Expand Up @@ -154,6 +183,47 @@ private boolean isExecutableFileName( final String fileName )
return fileName.endsWith( ".exe" ) || fileName.endsWith( ".msi" ) || fileName.endsWith( ".dmg" ) || fileName.endsWith( ".bat" ) ||
fileName.endsWith( ".sh" );
}

protected Set<ExtraData> getDefaultExtraDatas( final ApplicationKeys applicationKeys, final ContentTypeName contentTypeName )
{
final ContentType contentType = this.contentTypeService.getByName( GetContentTypeParams.from( contentTypeName ) );

Set<ExtraData> result = new HashSet<>();

result.addAll(
xDataService.getByNames( contentType.getXData() ).stream().map( this::createExtraData ).collect( Collectors.toSet() ) );
result.addAll( Objects.requireNonNullElse( applicationKeys, ApplicationKeys.empty() )
.stream()
.map( siteService::getDescriptor )
.filter( Objects::nonNull )
.flatMap( siteDescriptor -> siteDescriptor.getXDataMappings()
.stream()
.filter( xDataMapping -> doFilterXDataMapping( xDataMapping, contentTypeName ) )
.map( this::createExtraData ) )
.collect( Collectors.toList() ) );

return result;
}

private boolean doFilterXDataMapping( final XDataMapping xDataMapping, final ContentTypeName contentTypeName )
{
String wildcard = xDataMapping.getAllowContentTypes();
ApplicationKey applicationKey = xDataMapping.getXDataName().getApplicationKey();
return nullToEmpty( wildcard ).isBlank() ||
new ApplicationWildcardMatcher<>( applicationKey, ContentTypeName::toString, ApplicationWildcardMatcher.Mode.MATCH ).matches(
wildcard, contentTypeName);
}

private ExtraData createExtraData( final XDataMapping xDataMapping )
{
XData xData = xDataService.getByName( xDataMapping.getXDataName() );
return createExtraData( xData );
}

private ExtraData createExtraData( final XData xData )
{
return new ExtraData( xData.getName(), new PropertyTree() );
}
}


Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
Expand All @@ -20,6 +21,7 @@
import com.google.common.io.ByteSource;

import com.enonic.xp.app.ApplicationKey;
import com.enonic.xp.app.ApplicationKeys;
import com.enonic.xp.archive.ArchiveContentParams;
import com.enonic.xp.archive.ArchiveContentsResult;
import com.enonic.xp.archive.RestoreContentParams;
Expand Down Expand Up @@ -116,25 +118,31 @@
import com.enonic.xp.node.ReorderChildNodesResult;
import com.enonic.xp.node.SetNodeChildOrderParams;
import com.enonic.xp.page.PageDescriptorService;
import com.enonic.xp.project.Project;
import com.enonic.xp.project.ProjectName;
import com.enonic.xp.project.ProjectService;
import com.enonic.xp.query.expr.CompareExpr;
import com.enonic.xp.query.expr.FieldExpr;
import com.enonic.xp.query.expr.QueryExpr;
import com.enonic.xp.query.expr.ValueExpr;
import com.enonic.xp.region.LayoutDescriptorService;
import com.enonic.xp.region.PartDescriptorService;
import com.enonic.xp.repository.RepositoryId;
import com.enonic.xp.schema.content.ContentTypeName;
import com.enonic.xp.schema.content.ContentTypeService;
import com.enonic.xp.schema.xdata.XDataService;
import com.enonic.xp.security.acl.AccessControlList;
import com.enonic.xp.site.CreateSiteParams;
import com.enonic.xp.site.Site;
import com.enonic.xp.site.SiteConfig;
import com.enonic.xp.site.SiteConfigsDataSerializer;
import com.enonic.xp.site.SiteService;
import com.enonic.xp.trace.Trace;
import com.enonic.xp.trace.Tracer;
import com.enonic.xp.util.BinaryReference;

import static java.util.stream.Collectors.toList;

@Component(configurationPid = "com.enonic.xp.content")
public class ContentServiceImpl
implements ContentService
Expand All @@ -159,6 +167,8 @@ public class ContentServiceImpl

private SiteService siteService;

private ProjectService projectService;

private final ContentNodeTranslator translator;

private final List<ContentProcessor> contentProcessors = new CopyOnWriteArrayList<>();
Expand Down Expand Up @@ -240,6 +250,7 @@ public Site create( final CreateSiteParams params )
contentDataSerializer( this.contentDataSerializer ).
allowUnsafeAttachmentNames( config.attachments_allowUnsafeNames() ).
params( createContentParams ).
applicationKeys( getApplicationKeysRelatedWithSiteOrProject( params.getParentContentPath() ) ).
build().
execute();

Expand Down Expand Up @@ -280,6 +291,7 @@ public Content create( final CreateContentParams params )
contentDataSerializer( this.contentDataSerializer ).
allowUnsafeAttachmentNames( config.attachments_allowUnsafeNames() ).
params( params ).
applicationKeys( getApplicationKeysRelatedWithSiteOrProject( params.getParent() ) ).
build().
execute();

Expand Down Expand Up @@ -1339,6 +1351,29 @@ private static void verifyContextBranch( final Branch branch )
}
}

private ApplicationKeys getApplicationKeysRelatedWithSiteOrProject( final ContentPath parentPath )
{
Site nearestSite = findNearestSiteByPath( parentPath );

List<ApplicationKey> applicationKeys = new ArrayList<>();

if ( nearestSite != null )
{
applicationKeys.addAll( nearestSite.getSiteConfigs().stream().map( SiteConfig::getApplicationKey ).collect( toList() ) );
}
else
{
RepositoryId repositoryId = ContextAccessor.current().getRepositoryId();
if ( repositoryId != null )
{
Project project = projectService.get( ProjectName.from( repositoryId ) );
applicationKeys.addAll( project.getSiteConfigs().getApplicationKeys() );
}
}

return applicationKeys.isEmpty() ? ApplicationKeys.empty() : ApplicationKeys.from( applicationKeys );
}

@Reference
public void setContentTypeService( final ContentTypeService contentTypeService )
{
Expand Down Expand Up @@ -1407,8 +1442,7 @@ public void setContentAuditLogSupport( final ContentAuditLogSupport contentAudit
@Reference
public void setProjectService( final ProjectService projectService )
{
//Many starters depend on ContentService available only when default cms repo is fully initialized.
// Starting from 7.3 Initialization happens in ProjectService, so we need a dependency.
this.projectService = projectService;
}

}
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package com.enonic.xp.core.impl.content;

import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Preconditions;

import com.enonic.xp.app.ApplicationKeys;
import com.enonic.xp.content.Content;
import com.enonic.xp.content.ContentAccessException;
import com.enonic.xp.content.ContentAlreadyExistsException;
Expand All @@ -19,6 +22,8 @@
import com.enonic.xp.content.ContentPropertyNames;
import com.enonic.xp.content.CreateContentParams;
import com.enonic.xp.content.CreateContentTranslatorParams;
import com.enonic.xp.content.ExtraData;
import com.enonic.xp.content.ExtraDatas;
import com.enonic.xp.content.ValidationErrors;
import com.enonic.xp.content.processor.ContentProcessor;
import com.enonic.xp.content.processor.ProcessCreateParams;
Expand All @@ -27,7 +32,6 @@
import com.enonic.xp.core.impl.content.serializer.ContentDataSerializer;
import com.enonic.xp.core.impl.content.validate.InputValidator;
import com.enonic.xp.data.Property;
import com.enonic.xp.form.FormDefaultValuesProcessor;
import com.enonic.xp.inputtype.InputTypes;
import com.enonic.xp.media.MediaInfo;
import com.enonic.xp.name.NamePrettyfier;
Expand All @@ -41,6 +45,7 @@
import com.enonic.xp.region.PartDescriptorService;
import com.enonic.xp.schema.content.ContentType;
import com.enonic.xp.schema.content.GetContentTypeParams;
import com.enonic.xp.schema.xdata.XData;
import com.enonic.xp.security.PrincipalKey;
import com.enonic.xp.security.auth.AuthenticationInfo;

Expand All @@ -55,8 +60,6 @@ final class CreateContentCommand

private final MediaInfo mediaInfo;

private final FormDefaultValuesProcessor formDefaultValuesProcessor;

private final PageDescriptorService pageDescriptorService;

private final PartDescriptorService partDescriptorService;
Expand All @@ -68,13 +71,23 @@ final class CreateContentCommand
private CreateContentCommand( final Builder builder )
{
super( builder );
this.params = builder.params;
this.mediaInfo = builder.mediaInfo;
this.formDefaultValuesProcessor = builder.formDefaultValuesProcessor;
this.pageDescriptorService = builder.pageDescriptorService;
this.partDescriptorService = builder.partDescriptorService;
this.layoutDescriptorService = builder.layoutDescriptorService;
this.contentDataSerializer = builder.contentDataSerializer;

final Set<ExtraData> extraDataSet = new HashSet<>();
if ( builder.params.getExtraDatas() != null )
{
extraDataSet.addAll( builder.params.getExtraDatas().getSet() );
}
if ( builder.applicationKeys != null )
{
extraDataSet.addAll( getDefaultExtraDatas( builder.applicationKeys, builder.params.getType() ) );
}

this.params = CreateContentParams.create( builder.params ).extraDatas( ExtraDatas.from( extraDataSet ) ).build();
}

static Builder create()
Expand All @@ -98,7 +111,17 @@ private Content doExecute()
validateContentType( contentType );

formDefaultValuesProcessor.setDefaultValues( contentType.getForm(), params.getData() );
// TODO apply default values to xData

if ( params.getExtraDatas() != null )
{
params.getExtraDatas().forEach( extraData -> {
XData xData = xDataService.getByName( extraData.getName() );
if ( xData != null )
{
formDefaultValuesProcessor.setDefaultValues( xData.getForm(), extraData.getData() );
}
} );
}

CreateContentParams processedParams = runContentProcessors( this.params, contentType );

Expand Down Expand Up @@ -325,7 +348,7 @@ static class Builder

private MediaInfo mediaInfo;

private FormDefaultValuesProcessor formDefaultValuesProcessor;
private ApplicationKeys applicationKeys;

private PageDescriptorService pageDescriptorService;

Expand Down Expand Up @@ -356,12 +379,6 @@ Builder mediaInfo( final MediaInfo value )
return this;
}

Builder formDefaultValuesProcessor( final FormDefaultValuesProcessor formDefaultValuesProcessor )
{
this.formDefaultValuesProcessor = formDefaultValuesProcessor;
return this;
}

Builder pageDescriptorService( final PageDescriptorService value )
{
this.pageDescriptorService = value;
Expand All @@ -386,6 +403,12 @@ Builder contentDataSerializer( final ContentDataSerializer value )
return this;
}

Builder applicationKeys( final ApplicationKeys applicationKeys )
{
this.applicationKeys = applicationKeys;
return this;
}

@Override
void validate()
{
Expand Down
Loading