Create step is now found

pull/10/head
Jens Pelzetter 2021-04-14 20:52:36 +02:00
parent 7d9193c474
commit 2ab4b0c5ed
9 changed files with 195 additions and 109 deletions

View File

@ -76,6 +76,7 @@ public class FolderManager {
* @see #folderIsDeletable(org.librecms.contentsection.Folder) * @see #folderIsDeletable(org.librecms.contentsection.Folder)
*/ */
public enum FolderIsDeletable { public enum FolderIsDeletable {
/** /**
* Folder can be deleted. * Folder can be deleted.
*/ */
@ -92,12 +93,14 @@ public class FolderManager {
* Folder can't be deleted because the folder is a root folder. * Folder can't be deleted because the folder is a root folder.
*/ */
IS_ROOT_FOLDER IS_ROOT_FOLDER
} }
/** /**
* Describes if a folder is movable to another folder or not and why. * Describes if a folder is movable to another folder or not and why.
*/ */
public enum FolderIsMovable { public enum FolderIsMovable {
/** /**
* The folder can be moved to the specified target folder. * The folder can be moved to the specified target folder.
*/ */
@ -127,6 +130,7 @@ public class FolderManager {
* The folder to contains assets which are in use. * The folder to contains assets which are in use.
*/ */
HAS_IN_USE_ASSETS HAS_IN_USE_ASSETS
} }
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)

View File

@ -18,7 +18,6 @@
*/ */
package org.librecms.ui.contentsections.documents; package org.librecms.ui.contentsections.documents;
import org.libreccm.api.Identifier;
import org.libreccm.api.IdentifierParser; import org.libreccm.api.IdentifierParser;
import org.libreccm.l10n.GlobalizationHelper; import org.libreccm.l10n.GlobalizationHelper;
import org.libreccm.l10n.LocalizedString; import org.libreccm.l10n.LocalizedString;
@ -28,17 +27,18 @@ import org.librecms.contentsection.ContentSectionRepository;
import org.librecms.contentsection.Folder; import org.librecms.contentsection.Folder;
import org.librecms.contentsection.FolderManager; import org.librecms.contentsection.FolderManager;
import org.librecms.contentsection.FolderRepository; import org.librecms.contentsection.FolderRepository;
import org.librecms.contentsection.FolderType;
import org.librecms.ui.contentsections.ItemPermissionChecker;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.NavigableMap;
import java.util.SortedMap; import java.util.SortedMap;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.stream.Collectors;
import javax.enterprise.context.Dependent; import javax.enterprise.context.Dependent;
import javax.inject.Inject; import javax.inject.Inject;
import javax.transaction.Transactional;
/** /**
* *
@ -49,12 +49,6 @@ import javax.inject.Inject;
public abstract class AbstractMvcDocumentCreateStep<T extends ContentItem> public abstract class AbstractMvcDocumentCreateStep<T extends ContentItem>
implements MvcDocumentCreateStep<T> { implements MvcDocumentCreateStep<T> {
@Inject
private ContentSectionRepository sectionRepo;
@Inject
private FolderRepository folderRepository;
/** /**
* Provides operations for folders. * Provides operations for folders.
*/ */
@ -67,9 +61,6 @@ public abstract class AbstractMvcDocumentCreateStep<T extends ContentItem>
@Inject @Inject
private GlobalizationHelper globalizationHelper; private GlobalizationHelper globalizationHelper;
@Inject
private IdentifierParser identifierParser;
private boolean canCreate; private boolean canCreate;
/** /**
@ -82,6 +73,8 @@ public abstract class AbstractMvcDocumentCreateStep<T extends ContentItem>
*/ */
private ContentSection section; private ContentSection section;
private Map<String, String> availableWorkflows;
/** /**
* Messages to be shown to the user. * Messages to be shown to the user.
*/ */
@ -91,21 +84,41 @@ public abstract class AbstractMvcDocumentCreateStep<T extends ContentItem>
messages = new TreeMap<>(); messages = new TreeMap<>();
} }
@Transactional(Transactional.TxType.REQUIRED)
@Override
public Map<String, String> getAvailableLocales() {
return globalizationHelper
.getAvailableLocales()
.stream()
.collect(
Collectors.toMap(
locale -> locale.toString(),
locale -> locale.toString(),
(value1, value2) -> value1,
() -> new LinkedHashMap<String, String>()
)
);
}
@Transactional(Transactional.TxType.REQUIRED)
@Override @Override
public ContentSection getContentSection() { public ContentSection getContentSection() {
return section; return section;
} }
@Transactional(Transactional.TxType.REQUIRED)
@Override @Override
public void setContentSection(final ContentSection section) { public void setContentSection(final ContentSection section) {
this.section = section; this.section = section;
} }
@Transactional(Transactional.TxType.REQUIRED)
@Override @Override
public String getContentSectionLabel() { public String getContentSectionLabel() {
return section.getLabel(); return section.getLabel();
} }
@Transactional(Transactional.TxType.REQUIRED)
@Override @Override
public String getContentSectionTitle() { public String getContentSectionTitle() {
return globalizationHelper.getValueFromLocalizedString( return globalizationHelper.getValueFromLocalizedString(
@ -113,6 +126,18 @@ public abstract class AbstractMvcDocumentCreateStep<T extends ContentItem>
); );
} }
@Override
public Map<String, String> getAvailableWorkflows() {
return Collections.unmodifiableMap(availableWorkflows);
}
@Override
public void setAvailableWorkflows(
final Map<String, String> availableWorkflows
) {
this.availableWorkflows = new LinkedHashMap<>(availableWorkflows);
}
// protected final void setContentSectionByIdentifier( // protected final void setContentSectionByIdentifier(
// final String sectionIdentifierParam // final String sectionIdentifierParam
// ) { // ) {
@ -146,7 +171,6 @@ public abstract class AbstractMvcDocumentCreateStep<T extends ContentItem>
// canCreate = false; // canCreate = false;
// } // }
// } // }
// protected final void setFolderByPath(final String folderPath) { // protected final void setFolderByPath(final String folderPath) {
// final Optional<Folder> folderResult = folderRepository.findByPath( // final Optional<Folder> folderResult = folderRepository.findByPath(
// section, // section,
@ -183,7 +207,11 @@ public abstract class AbstractMvcDocumentCreateStep<T extends ContentItem>
@Override @Override
public String getFolderPath() { public String getFolderPath() {
return folderManager.getFolderPath(folder); if (folder.getParentFolder() == null) {
return "";
} else {
return folderManager.getFolderPath(folder);
}
} }
@Override @Override

View File

@ -40,22 +40,27 @@ import org.librecms.ui.contentsections.ItemPermissionChecker;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.enterprise.context.RequestScoped; import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Any;
import javax.enterprise.inject.Instance; import javax.enterprise.inject.Instance;
import javax.enterprise.util.AnnotationLiteral; import javax.enterprise.util.AnnotationLiteral;
import javax.inject.Inject; import javax.inject.Inject;
import javax.mvc.Controller; import javax.mvc.Controller;
import javax.mvc.Models; import javax.mvc.Models;
import javax.transaction.Transactional; import javax.transaction.Transactional;
import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue; import javax.ws.rs.DefaultValue;
import javax.ws.rs.FormParam; import javax.ws.rs.FormParam;
import javax.ws.rs.GET; import javax.ws.rs.GET;
import javax.ws.rs.POST; import javax.ws.rs.POST;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import javax.ws.rs.core.Form;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.MultivaluedMap;
/** /**
@ -112,6 +117,7 @@ public class DocumentController {
* All available {@link MvcDocumentCreateStep}s. * All available {@link MvcDocumentCreateStep}s.
*/ */
@Inject @Inject
@Any
private Instance<MvcDocumentCreateStep<?>> createSteps; private Instance<MvcDocumentCreateStep<?>> createSteps;
/** /**
@ -253,23 +259,28 @@ public class DocumentController {
@POST @POST
@Path("/@create/{documentType}") @Path("/@create/{documentType}")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@AuthorizationRequired @AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public String createDocument( public String createDocument(
@PathParam("sectionIdentifier") final String sectionIdentifier, @PathParam("sectionIdentifier") final String sectionIdentifier,
@PathParam("documentType") final String documentType, @PathParam("documentType") final String documentType,
final MultivaluedMap<String, String> formParameters //final MultivaluedMap<String, String> formParameters
final Form form
) { ) {
return createDocument( return createDocument(
sectionIdentifier, sectionIdentifier,
"", documentType, "",
formParameters documentType,
//formParameters
form.asMap()
); );
} }
@POST @POST
@Path("/{folderPath:(.+)?}/@create/{documentType}") @Path("/{folderPath:(.+)?}/@create/{documentType}")
@AuthorizationRequired @AuthorizationRequired
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
@SuppressWarnings({"unchecked", "unchecked"}) @SuppressWarnings({"unchecked", "unchecked"})
public String createDocument( public String createDocument(
@ -925,12 +936,8 @@ public class DocumentController {
); );
} }
//final Class<? extends ContentItem> documentClass;
final Class<?> clazz; final Class<?> clazz;
try { try {
// documentClass = (Class<? extends ContentItem>) Class.forName(
// documentType
// );
clazz = Class.forName(documentType); clazz = Class.forName(documentType);
} catch (ClassNotFoundException ex) { } catch (ClassNotFoundException ex) {
return new CreateStepResult( return new CreateStepResult(
@ -964,6 +971,22 @@ public class DocumentController {
.get(); .get();
createStep.setContentSection(section); createStep.setContentSection(section);
createStep.setAvailableWorkflows(
section
.getWorkflowTemplates()
.stream()
.collect(
Collectors.toMap(
workflow -> workflow.getUuid(),
workflow -> globalizationHelper
.getValueFromLocalizedString(
workflow.getName()
),
(value1, value2) -> value1,
() -> new LinkedHashMap<String, String>()
)
)
);
createStep.setFolder(folder); createStep.setFolder(folder);
return new CreateStepResult(createStep); return new CreateStepResult(createStep);

View File

@ -26,7 +26,6 @@ import org.librecms.contentsection.Folder;
import java.util.Map; import java.util.Map;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import javax.ws.rs.core.Form;
import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.MultivaluedMap;
/** /**
@ -80,7 +79,7 @@ public interface MvcDocumentCreateStep<T extends ContentItem> {
* *
* @return Document type generated. * @return Document type generated.
*/ */
Class<T> getDocumentType(); String getDocumentType();
/** /**
* Localized description of the create step. The current locale as returned * Localized description of the create step. The current locale as returned
@ -100,6 +99,13 @@ public interface MvcDocumentCreateStep<T extends ContentItem> {
*/ */
String getBundle(); String getBundle();
/**
* The locales that can be used for documents.
*
* @return The locales that can be used for documents.
*/
Map<String, String> getAvailableLocales();
/** /**
* The current content section. * The current content section.
* *
@ -129,6 +135,23 @@ public interface MvcDocumentCreateStep<T extends ContentItem> {
*/ */
void setContentSection(final ContentSection section); void setContentSection(final ContentSection section);
/**
* Retrieves the workflows available for the current content section.
*
* @return A map of the available workflows. The key is the UUID of the
* workflow, the value is the name of the workflow.
*/
Map<String, String> getAvailableWorkflows();
/**
* Used by the {@link DocumentController} to provide the available
* workflows.
*
* @param availableWorkflows
*/
void setAvailableWorkflows(
final Map<String, String> availableWorkflows);
/** /**
* The parent folder of the new item. * The parent folder of the new item.
* *

View File

@ -20,6 +20,7 @@ package org.librecms.ui.contenttypes;
import org.libreccm.l10n.GlobalizationHelper; import org.libreccm.l10n.GlobalizationHelper;
import org.libreccm.l10n.LocalizedString; import org.libreccm.l10n.LocalizedString;
import org.libreccm.security.AuthorizationRequired;
import org.libreccm.workflow.Workflow; import org.libreccm.workflow.Workflow;
import org.librecms.contentsection.ContentItemManager; import org.librecms.contentsection.ContentItemManager;
import org.librecms.contentsection.ContentItemRepository; import org.librecms.contentsection.ContentItemRepository;
@ -35,6 +36,7 @@ import javax.inject.Named;
import javax.inject.Inject; import javax.inject.Inject;
import javax.mvc.Models; import javax.mvc.Models;
import javax.transaction.Transactional;
import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.MultivaluedMap;
/** /**
@ -109,8 +111,8 @@ public class MvcArticleCreateStep
private String selectedWorkflow; private String selectedWorkflow;
@Override @Override
public Class<Article> getDocumentType() { public String getDocumentType() {
return Article.class; return Article.class.getName();
} }
@Override @Override
@ -141,6 +143,7 @@ public class MvcArticleCreateStep
return initialLocale; return initialLocale;
} }
@Transactional(Transactional.TxType.REQUIRED)
public String getSelectedWorkflow() { public String getSelectedWorkflow() {
if (selectedWorkflow == null || selectedWorkflow.isEmpty()) { if (selectedWorkflow == null || selectedWorkflow.isEmpty()) {
return getContentSection() return getContentSection()
@ -169,6 +172,8 @@ public class MvcArticleCreateStep
return "org/librecms/ui/contenttypes/article/create-article.xhtml"; return "org/librecms/ui/contenttypes/article/create-article.xhtml";
} }
@AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
@Override @Override
public String createItem(final MultivaluedMap<String, String> formParams) { public String createItem(final MultivaluedMap<String, String> formParams) {
if (!formParams.containsKey(FORM_PARAM_NAME) if (!formParams.containsKey(FORM_PARAM_NAME)
@ -180,6 +185,7 @@ public class MvcArticleCreateStep
getBundle() getBundle()
).getText("createstep.name.error.missing") ).getText("createstep.name.error.missing")
); );
return showCreateStep();
} }
name = formParams.getFirst(FORM_PARAM_NAME); name = formParams.getFirst(FORM_PARAM_NAME);
@ -190,6 +196,7 @@ public class MvcArticleCreateStep
getBundle() getBundle()
).getText("createstep.name.error.invalid") ).getText("createstep.name.error.invalid")
); );
return showCreateStep();
} }
if (!formParams.containsKey(FORM_PARAM_TITLE) if (!formParams.containsKey(FORM_PARAM_TITLE)
@ -201,6 +208,7 @@ public class MvcArticleCreateStep
getBundle() getBundle()
).getText("createstep.title.error.missing") ).getText("createstep.title.error.missing")
); );
return showCreateStep();
} }
title = formParams.getFirst(FORM_PARAM_TITLE); title = formParams.getFirst(FORM_PARAM_TITLE);
@ -213,6 +221,7 @@ public class MvcArticleCreateStep
getBundle() getBundle()
).getText("createstep.summary.error.missing") ).getText("createstep.summary.error.missing")
); );
return showCreateStep();
} }
summary = formParams.getFirst(FORM_PARAM_SUMMARY); summary = formParams.getFirst(FORM_PARAM_SUMMARY);
@ -225,6 +234,7 @@ public class MvcArticleCreateStep
getBundle() getBundle()
).getText("createstep.initial_locale.error.missing") ).getText("createstep.initial_locale.error.missing")
); );
return showCreateStep();
} }
final Locale locale = new Locale( final Locale locale = new Locale(
formParams.getFirst(FORM_PARAM_INITIAL_LOCALE) formParams.getFirst(FORM_PARAM_INITIAL_LOCALE)
@ -239,6 +249,7 @@ public class MvcArticleCreateStep
getBundle() getBundle()
).getText("createstep.workflow.none_selected") ).getText("createstep.workflow.none_selected")
); );
return showCreateStep();
} }
selectedWorkflow = formParams.getFirst(FORM_PARAM_SELECTED_WORKFLOW); selectedWorkflow = formParams.getFirst(FORM_PARAM_SELECTED_WORKFLOW);
@ -255,24 +266,11 @@ public class MvcArticleCreateStep
getBundle() getBundle()
).getText("createstep.workflow.error.not_available") ).getText("createstep.workflow.error.not_available")
); );
return showCreateStep();
} }
if (!getMessages().isEmpty()) { if (!getMessages().isEmpty()) {
final String folderPath = getFolderPath(); return showCreateStep();
if (folderPath.isEmpty() || "/".equals(folderPath)) {
return String.format(
"/@contentsections/%s/documents/@create/%s",
getContentSectionLabel(),
getDocumentType().getName()
);
} else {
return String.format(
"/@contentsections/%s/documents/%s/@create/%s",
getContentSectionLabel(),
folderPath,
getDocumentType().getName()
);
}
} }
final Article article = itemManager.createContentItem( final Article article = itemManager.createContentItem(
@ -296,4 +294,6 @@ public class MvcArticleCreateStep
); );
} }
} }

View File

@ -4,7 +4,7 @@
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core" xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:libreccm="http://xmlns.jcp.org/jsf/composite/components/libreccm" xmlns:libreccm="http://xmlns.jcp.org/jsf/composite/components/libreccm"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"> xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<ui:composition template="/WEB-INF/views/org/librecms/ui/content-section/contentsection.xhtml"> <ui:composition template="../contentsection.xhtml">
<ui:param name="activePage" value="documentFolders" /> <ui:param name="activePage" value="documentFolders" />
<ui:param name="title" value="#{CmsAdminMessages['contentsection.documentfolders.title']}" /> <ui:param name="title" value="#{CmsAdminMessages['contentsection.documentfolders.title']}" />

View File

@ -7,71 +7,75 @@
<ui:composition template="/WEB-INF/views/org/librecms/ui/contentsection/contentsection.xhtml"> <ui:composition template="/WEB-INF/views/org/librecms/ui/contentsection/contentsection.xhtml">
<ui:define name="main"> <ui:define name="main">
<div class="container">
<h1>#{CmsArticleMessageBundle['createform.title']}</h1>
<c:forEach items="#{CmsArticleCreateStep.messages.entrySet}" <c:forEach items="#{CmsArticleCreateStep.messages.entrySet}"
var="message"> var="message">
<div class="alert alert-#{message.key}" role="alert"> <div class="alert alert-#{message.key}" role="alert">
#{message.value} #{message.value}
</div> </div>
</c:forEach> </c:forEach>
<form action="#{mvc.basePath}/#{CmsArticleCreateStep.contentSectionLabel}/documents/#{CmsArticleCreateStep.folderPath}/@create/#{CmsArticleCreateStep.documentType}" <form action="#{mvc.basePath}/#{CmsArticleCreateStep.contentSectionLabel}/documents/#{CmsArticleCreateStep.folderPath}@create/#{CmsArticleCreateStep.documentType}"
method="post"> method="post">
<bootstrap:formGroupText <bootstrap:formGroupText
help="#{CmsArticleMessageBundle['createform.name.help']}" help="#{CmsArticleMessageBundle['createform.name.help']}"
inputId="name" inputId="name"
label="#{CmsArticleMessageBundle['createform.name.label']}" label="#{CmsArticleMessageBundle['createform.name.label']}"
name="name" name="name"
pattern="^([a-zA-Z0-9_-]*)$" pattern="^([a-zA-Z0-9_-]*)$"
required="true" required="true"
/> />
<bootstrap:formGroupSelect <bootstrap:formGroupSelect
help="#{CmsArticleMessageBundle['createform.initial_locale.help']}" help="#{CmsArticleMessageBundle['createform.initial_locale.help']}"
inputId="locale" inputId="locale"
label="#{CmsArticleMessageBundle['createform.initial_locale.label']}" label="#{CmsArticleMessageBundle['createform.initial_locale.label']}"
name="locale" name="locale"
options="#{CmsArticleCreateStep.availableLocales}" options="#{CmsArticleCreateStep.availableLocales}"
required="true" required="true"
selectedOptions="#{[CmsArticleCreateStep.initialLocale]}" selectedOptions="#{[CmsArticleCreateStep.initialLocale]}"
/> />
<bootstrap:formGroupText <bootstrap:formGroupText
help="#{CmsArticleMessageBundle['createform.title.help']}" help="#{CmsArticleMessageBundle['createform.title.help']}"
inputId="title" inputId="title"
label="#{CmsArticleMessageBundle['createform.title.label']}" label="#{CmsArticleMessageBundle['createform.title.label']}"
name="title" name="title"
required="true" required="true"
/> />
<bootstrap:formGroupTextarea <bootstrap:formGroupTextarea
help="#{CmsArticleMessageBundle['createform.summary.help']}" cols="80"
inputId="summary" help="#{CmsArticleMessageBundle['createform.summary.help']}"
label="#{CmsArticleMessageBundle['createform.summary.label']}" inputId="summary"
name="summary" label="#{CmsArticleMessageBundle['createform.summary.label']}"
required="true" name="summary"
/> required="true"
rows="16"
/>
<bootstrap:formGroupSelect <bootstrap:formGroupSelect
help="#{CmsArticleMessageBundle['createform.workflow.help']}" help="#{CmsArticleMessageBundle['createform.workflow.help']}"
inputId="workflow" inputId="workflow"
label="#{CmsArticleMessageBundle['createform.workflow.label']}" label="#{CmsArticleMessageBundle['createform.workflow.label']}"
name="workflow" name="workflow"
options="#{CmsArticleCreateStep.availableWorkflows}" options="#{CmsArticleCreateStep.availableWorkflows}"
selectedOptions="#{[CmsArticleCreateStep.selectedWorkflow]}" selectedOptions="#{[CmsArticleCreateStep.selectedWorkflow]}"
/> />
<a class="btn btn-warning" <a class="btn btn-warning"
href="#{mvc.basePath}/#{CmsArticleCreateStep.contentSectionLabel}/documentfolders/#{CmsArticleCreateStep.folderPath}"> href="#{mvc.basePath}/#{CmsArticleCreateStep.contentSectionLabel}/documentfolders/#{CmsArticleCreateStep.folderPath}">
#{CmsArticleMessageBundle['createform.cancel']} #{CmsArticleMessageBundle['createform.cancel']}
</a> </a>
<button class="btn btn-success" <button class="btn btn-success"
type="submit"> type="submit">
#{CmsArticleMessageBundle['createform.submit']} #{CmsArticleMessageBundle['createform.submit']}
</button> </button>
</form>
</form>
</div>
</ui:define> </ui:define>
</ui:composition> </ui:composition>

View File

@ -28,3 +28,5 @@ basicproperties.name.header=Basic Properties
basicproperties.name.edit=Edit basicproperties.name.edit=Edit
basicproperties.title.header=Title basicproperties.title.header=Title
basicproperties.description.header=Summary basicproperties.description.header=Summary
createform.title=Create new article
createform.summary.label=Summary

View File

@ -28,3 +28,5 @@ basicproperties.name.header=Basiseigenschaften
basicproperties.name.edit=Bearbeiten basicproperties.name.edit=Bearbeiten
basicproperties.title.header=Titel basicproperties.title.header=Titel
basicproperties.description.header=Zusammenfassung basicproperties.description.header=Zusammenfassung
createform.title=Neuen Artikel anlegen
createform.summary.label=Zusammenfassung