Dialog for creating new items

pull/10/head
Jens Pelzetter 2021-04-07 21:31:24 +02:00
parent fe0bfd2d31
commit fa9fab7ad0
9 changed files with 171 additions and 12 deletions

View File

@ -95,14 +95,15 @@ public class ConfigurationDocumentTypesController {
private ContentSectionsUi sectionsUi; private ContentSectionsUi sectionsUi;
/** /**
* Provides functions for working with content types. * Provides function for managing the content types assigned to a content
* section.
*/ */
@Inject @Inject
private ContentTypeManager typeManager; private ContentTypeManager typeManager;
/** /**
* Provides function for managing the content types assigned to a content * Provides functions for working with content types.
* section. *
*/ */
@Inject @Inject
private ContentTypesManager typesManager; private ContentTypesManager typesManager;

View File

@ -18,19 +18,23 @@
*/ */
package org.librecms.ui.contentsections; package org.librecms.ui.contentsections;
import org.libreccm.l10n.GlobalizationHelper;
import org.libreccm.security.PermissionChecker; import org.libreccm.security.PermissionChecker;
import org.librecms.contentsection.ContentSection; import org.librecms.contentsection.ContentSection;
import org.librecms.contentsection.privileges.AdminPrivileges; import org.librecms.contentsection.privileges.AdminPrivileges;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import javax.enterprise.context.RequestScoped; import javax.enterprise.context.RequestScoped;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import javax.transaction.Transactional;
/** /**
* Model for providing data about a {@link ContentSection}. * Model for providing data about a {@link ContentSection}.
@ -47,6 +51,9 @@ public class ContentSectionModel {
@Inject @Inject
private PermissionChecker permissionChecker; private PermissionChecker permissionChecker;
@Inject
private GlobalizationHelper globalizationHelper;
/** /**
* The content section. * The content section.
*/ */
@ -62,7 +69,12 @@ public class ContentSectionModel {
*/ */
private List<DocumentFolderTreeNode> documentFolders; private List<DocumentFolderTreeNode> documentFolders;
private Map<String, String> availableDocumentTypes;
/** /**
*
*
* /**
* Sets the section for the model * Sets the section for the model
* *
* @param section The content section. * @param section The content section.
@ -105,6 +117,18 @@ public class ContentSectionModel {
this.documentFolders = new ArrayList<>(documentFolders); this.documentFolders = new ArrayList<>(documentFolders);
} }
@Transactional(Transactional.TxType.REQUIRED)
public Map<String, String> getAvailableDocumentTypes() {
return Collections.unmodifiableMap(availableDocumentTypes);
}
protected void setAvailableDocumentTypes(
final Map<String, String> availableDocumentTypes
) {
this.availableDocumentTypes
= new LinkedHashMap<>(availableDocumentTypes);
}
/** /**
* Can the current user administer the categories of the domains/category * Can the current user administer the categories of the domains/category
* sytems assigned to the section? * sytems assigned to the section?

View File

@ -22,6 +22,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.libreccm.l10n.GlobalizationHelper; import org.libreccm.l10n.GlobalizationHelper;
import org.libreccm.security.AuthorizationRequired; import org.libreccm.security.AuthorizationRequired;
import org.libreccm.security.PermissionChecker;
import org.libreccm.security.PermissionManager; import org.libreccm.security.PermissionManager;
import org.libreccm.security.Role; import org.libreccm.security.Role;
import org.libreccm.security.RoleRepository; import org.libreccm.security.RoleRepository;
@ -38,7 +39,9 @@ import org.librecms.contentsection.FolderManager;
import org.librecms.contentsection.FolderRepository; import org.librecms.contentsection.FolderRepository;
import org.librecms.contentsection.FolderType; import org.librecms.contentsection.FolderType;
import org.librecms.contentsection.privileges.ItemPrivileges; import org.librecms.contentsection.privileges.ItemPrivileges;
import org.librecms.contentsection.privileges.TypePrivileges;
import org.librecms.contenttypes.Article; import org.librecms.contenttypes.Article;
import org.librecms.contenttypes.ContentTypesManager;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.ZoneId; import java.time.ZoneId;
@ -47,10 +50,13 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -113,6 +119,13 @@ public class DocumentFolderController {
@Inject @Inject
private ContentSectionsUi sectionsUi; private ContentSectionsUi sectionsUi;
/**
* Provides functions for working with content types.
*
*/
@Inject
private ContentTypesManager typesManager;
/** /**
* Used to retrieve {@link ContentType}s. * Used to retrieve {@link ContentType}s.
*/ */
@ -149,6 +162,10 @@ public class DocumentFolderController {
@Inject @Inject
private Models models; private Models models;
// Used to check permissions
@Inject
private PermissionChecker permissionChecker;
/** /**
* Used to update the permissions of the folder. * Used to update the permissions of the folder.
*/ */
@ -305,6 +322,37 @@ public class DocumentFolderController {
documentFolderTree.buildFolderTree(section, folder) documentFolderTree.buildFolderTree(section, folder)
); );
contentSectionModel.setAvailableDocumentTypes(
section
.getContentTypes()
.stream()
.filter(
type -> permissionChecker.isPermitted(
TypePrivileges.USE_TYPE, type)
)
.map(typesManager::getContentTypeInfo)
.sorted(
(typeInfo1, typeInfo2) -> globalizationHelper
.getLocalizedTextsUtil(
typeInfo1.getLabelBundle()).getText(
typeInfo1.getLabelKey()).compareTo(globalizationHelper
.getLocalizedTextsUtil(typeInfo2.getLabelBundle())
.getText(typeInfo2.getLabelKey()))
)
.collect(
Collectors.toMap(
typeInfo -> typeInfo.getContentItemClass().getName(),
typeInfo -> globalizationHelper
.getLocalizedTextsUtil(
typeInfo.getLabelBundle()).getText(
typeInfo.getLabelKey()
),
(key1, key2) -> key1,
() -> new LinkedHashMap<>()
)
)
);
documentFolderModel.setRows( documentFolderModel.setRows(
folderEntries folderEntries
.stream() .stream()
@ -871,4 +919,23 @@ public class DocumentFolderController {
return "org/librecms/ui/contentsection/documentfolder/documentfolder-not-found.xhtml"; return "org/librecms/ui/contentsection/documentfolder/documentfolder-not-found.xhtml";
} }
private DocumentTypeInfoModel buildContentTypeInfo(
final ContentType contentType
) {
final DocumentTypeInfoModel model = new DocumentTypeInfoModel();
model.setContentItemClass(contentType.getContentItemClass());
model.setDescription(
globalizationHelper.getValueFromLocalizedString(
contentType.getDescription()
)
);
model.setLabel(
globalizationHelper.getValueFromLocalizedString(
contentType.getLabel()
)
);
return model;
}
} }

View File

@ -24,6 +24,9 @@ import org.librecms.contentsection.Folder;
import java.util.Map; import java.util.Map;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
/** /**
* A pseudo implemention of the {@link MvcDocumentCreateStep} interface used by * A pseudo implemention of the {@link MvcDocumentCreateStep} interface used by
* the {@link DocumentController} to show an error message when not create step * the {@link DocumentController} to show an error message when not create step
@ -72,11 +75,15 @@ public class CreateStepNotAvailable
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
} }
@POST
@Path("/")
@Override @Override
public String showCreateForm() { public String showCreateForm() {
return "org/librecms/ui/contentsection/documents/create-step-not-available.xhtml"; return "org/librecms/ui/contentsection/documents/create-step-not-available.xhtml";
} }
@POST
@Path("/@create")
@Override @Override
public String createContentItem() { public String createContentItem() {
return "org/librecms/ui/contentsection/documents/create-step-not-available.xhtml"; return "org/librecms/ui/contentsection/documents/create-step-not-available.xhtml";

View File

@ -207,14 +207,14 @@ public class DocumentController {
* *
* @return The create step subresource. * @return The create step subresource.
*/ */
@Path("/{folderPath:(.+)?}/@create/{documentType}") @Path("/{folderPath:(.+)?}/@create/")
@AuthorizationRequired @AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public MvcDocumentCreateStep<? extends ContentItem> createDocument( public MvcDocumentCreateStep<? extends ContentItem> createDocument(
@PathParam("sectionIdentifier") final String sectionIdentifier, @PathParam("sectionIdentifier") final String sectionIdentifier,
@PathParam("folderPath") final String folderPath, @PathParam("folderPath") final String folderPath,
@PathParam("documentType") final String documentType @FormParam("documentType") final String documentType
) { ) {
final Optional<ContentSection> sectionResult = sectionsUi final Optional<ContentSection> sectionResult = sectionsUi
.findContentSection(sectionIdentifier); .findContentSection(sectionIdentifier);

View File

@ -28,6 +28,7 @@ import org.librecms.contentsection.Folder;
import org.librecms.contentsection.FolderManager; import org.librecms.contentsection.FolderManager;
import org.librecms.contenttypes.Article; import org.librecms.contenttypes.Article;
import org.librecms.ui.contentsections.ItemPermissionChecker; import org.librecms.ui.contentsections.ItemPermissionChecker;
import org.librecms.ui.contentsections.documents.CreatesDocumentOfType;
import org.librecms.ui.contentsections.documents.DocumentUi; import org.librecms.ui.contentsections.documents.DocumentUi;
import javax.enterprise.context.RequestScoped; import javax.enterprise.context.RequestScoped;
@ -46,6 +47,8 @@ import java.util.stream.Collectors;
import javax.inject.Inject; import javax.inject.Inject;
import javax.mvc.Models; import javax.mvc.Models;
import javax.ws.rs.FormParam; import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
/** /**
* Describes the create step for {@link Article}. * Describes the create step for {@link Article}.
@ -54,6 +57,7 @@ import javax.ws.rs.FormParam;
*/ */
@RequestScoped @RequestScoped
@Named("CmsArticleCreateStep") @Named("CmsArticleCreateStep")
@CreatesDocumentOfType(Article.class)
public class MvcArticleCreateStep implements MvcDocumentCreateStep<Article> { public class MvcArticleCreateStep implements MvcDocumentCreateStep<Article> {
@Inject @Inject
@ -212,8 +216,8 @@ public class MvcArticleCreateStep implements MvcDocumentCreateStep<Article> {
this.messages = new TreeMap<>(messages); this.messages = new TreeMap<>(messages);
} }
// @GET @POST
// @Path("/") @Path("/")
@Override @Override
public String showCreateForm() { public String showCreateForm() {
if (itemPermissionChecker.canCreateNewItems(folder)) { if (itemPermissionChecker.canCreateNewItems(folder)) {
@ -227,8 +231,8 @@ public class MvcArticleCreateStep implements MvcDocumentCreateStep<Article> {
} }
} }
// @POST @POST
// @Path("/") @Path("/@create")
@Override @Override
public String createContentItem() { public String createContentItem() {
if (name == null || name.isEmpty()) { if (name == null || name.isEmpty()) {

View File

@ -141,7 +141,7 @@
class="close" class="close"
data-dismiss="modal" data-dismiss="modal"
type="button"> type="button">
<span aria-hidden="true">&times;</span> <bootstrap:svgIcon icon="x-circle" />
</button> </button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
@ -163,7 +163,7 @@
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button class="btn btn-danger" <button class="btn btn-warning"
data-dismiss="modal" data-dismiss="modal"
type="button"> type="button">
#{CmsAdminMessages['contentsection.documentfolder.new_subfolder_dialog.close']} #{CmsAdminMessages['contentsection.documentfolder.new_subfolder_dialog.close']}
@ -188,10 +188,56 @@
</c:choose> </c:choose>
<c:choose> <c:choose>
<c:when test="#{DocumentFolderModel.canCreateItems}"> <c:when test="#{DocumentFolderModel.canCreateItems}">
<button class="btn btn-primary" title="#{CmsAdminMessages['contentsection.documentfolder.add_document']}"> <button class="btn btn-primary"
data-toggle="modal"
data-target="#new-document-dialog"
title="#{CmsAdminMessages['contentsection.documentfolder.add_document']}">
<bootstrap:svgIcon icon="file-earmark-plus" /> <bootstrap:svgIcon icon="file-earmark-plus" />
<span class="sr-only">#{CmsAdminMessages['contentsection.documentfolder.add_document']}</span> <span class="sr-only">#{CmsAdminMessages['contentsection.documentfolder.add_document']}</span>
</button> </button>
<div aria-hidden="true"
aria-labelledby="new-document-dialog-title"
class="modal fade"
id="new-document-dialog"
tabindex="-1">
<div class="modal-dialog">
<form action="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{DocumentFolderModel.path}/@create"
class="modal-content"
method="post">
<div class="modal-header">
<h2 class="modal-title"
id="new-document-dialog-title">
#{CmsAdminMessages['contentsection.documentfolder.new_document_dialog.title']}
</h2>
<button aria-label="#{CmsAdminMessages['contentsection.documentfolder.new_document_dialog.close']}"
class="close"
data-dismiss="modal"
type="button">
<bootstrap:svgIcon icon="x-circle" />
</button>
</div>
<div class="modal-body">
<bootstrap:formGroupSelect
help="#{CmsAdminMessages['contentsection.documentfolder.new_document_dialog.documenttype.help']}"
inputId="documentType"
label="#{CmsAdminMessages['contentsection.documentfolder.new_document_dialog.documenttype.label']}"
name="documentType"
options="#{ContentSectionModel.availableDocumentTypes}" />
</div>
<div class="modal-footer">
<button class="btn btn-warning"
data-dismiss="modal"
type="button">
#{CmsAdminMessages['contentsection.documentfolder.new_document_dialog.close']}
</button>
<button class="btn btn-success"
type="submit">
#{CmsAdminMessages['contentsection.documentfolder.new_document_dialog.submit']}
</button>
</div>
</form>
</div>
</div>
</c:when> </c:when>
<c:otherwise> <c:otherwise>
<button class="btn btn-primary" <button class="btn btn-primary"

View File

@ -751,3 +751,8 @@ contentsection.document.publishstep.title=Publish Document
contentsection.document.access_denied.message=Access to authoring step {2} of document {1} of content section {0} denied contentsection.document.access_denied.message=Access to authoring step {2} of document {1} of content section {0} denied
contentsection.document_access_denied.title=Access to authoring step denied contentsection.document_access_denied.title=Access to authoring step denied
contentsection.document_access_denied.breadcrumb=Access denied contentsection.document_access_denied.breadcrumb=Access denied
contentsection.documentfolder.new_document_dialog.title=Create new document
contentsection.documentfolder.new_document_dialog.close=Cancel
contentsection.documentfolder.new_document_dialog.documenttype.help=The type of the new document
contentsection.documentfolder.new_document_dialog.documenttype.label=Document Type
contentsection.documentfolder.new_document_dialog.submit=Create document

View File

@ -752,3 +752,8 @@ contentsection.document.publishstep.title=Dokument publizeren
contentsection.document.access_denied.message=Access to authoring step {2} of document {1} of content section {0} denied contentsection.document.access_denied.message=Access to authoring step {2} of document {1} of content section {0} denied
contentsection.document_access_denied.title=Zugriff auf Bearbeitungsschritt verweigert contentsection.document_access_denied.title=Zugriff auf Bearbeitungsschritt verweigert
contentsection.document_access_denied.breadcrumb=Zugriff verweigert contentsection.document_access_denied.breadcrumb=Zugriff verweigert
contentsection.documentfolder.new_document_dialog.title=Neues Dokument anlegen
contentsection.documentfolder.new_document_dialog.close=Abbrechen
contentsection.documentfolder.new_document_dialog.documenttype.help=Der Typ des neuen Dokumentes
contentsection.documentfolder.new_document_dialog.documenttype.label=Dokument Typ
contentsection.documentfolder.new_document_dialog.submit=Dokument anlegen