Create subfolders

Former-commit-id: 4b4666ce91
pull/10/head
Jens Pelzetter 2021-02-02 21:37:57 +01:00
parent 83cfd6be6c
commit c1bcd77b03
6 changed files with 272 additions and 80 deletions

View File

@ -0,0 +1,54 @@
package org.librecms.ui.contentsections;
import org.libreccm.security.AuthorizationRequired;
import java.net.URI;
import java.net.URISyntaxException;
import javax.inject.Inject;
import javax.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.transaction.Transactional;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@Controller
@Path("/")
public class ContentSectionController {
@Inject
private HttpServletRequest request;
@GET
@Path("/")
@AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public Response redirectToContentSectionsList() {
try {
return Response
.seeOther(
new URI(
request.getScheme(),
"",
request.getServerName(),
request.getServerPort(),
String.format(
"%s/@cms/contentsections",
request.getContextPath()
),
"",
""
)
).build();
} catch (URISyntaxException ex) {
throw new WebApplicationException(ex);
}
}
}

View File

@ -5,6 +5,8 @@
*/ */
package org.librecms.ui.contentsections; package org.librecms.ui.contentsections;
import com.arsdigita.cms.ui.folder.FolderPath;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.libreccm.api.Identifier; import org.libreccm.api.Identifier;
@ -56,6 +58,9 @@ import javax.ws.rs.QueryParam;
import org.librecms.ui.CmsAdminMessages; import org.librecms.ui.CmsAdminMessages;
import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
/** /**
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
@ -65,7 +70,8 @@ import org.librecms.ui.CmsAdminMessages;
@Path("/{sectionIdentifier}/documentfolders") @Path("/{sectionIdentifier}/documentfolders")
public class DocumentFolderController { public class DocumentFolderController {
private static final Logger LOGGER = LogManager.getLogger(DocumentFolderController.class private static final Logger LOGGER = LogManager.getLogger(
DocumentFolderController.class
); );
@Inject @Inject
@ -254,6 +260,13 @@ public class DocumentFolderController {
System.currentTimeMillis() - rowsStart System.currentTimeMillis() - rowsStart
); );
documentFolderModel.setPath(folderPath);
documentFolderModel.setCanCreateSubFolders(
permissionChecker.isPermitted(
ItemPrivileges.CREATE_NEW, folder
)
);
return "org/librecms/ui/contentsection/documentfolder/documentfolder.xhtml"; return "org/librecms/ui/contentsection/documentfolder/documentfolder.xhtml";
} else { } else {
models.put("sectionidentifier", sectionIdentifier); models.put("sectionidentifier", sectionIdentifier);
@ -359,6 +372,89 @@ public class DocumentFolderController {
} }
} }
@POST
@Path("/")
@AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public String newSubFolder(
@PathParam("sectionIdentifier") final String sectionIdentifier,
@FormParam("folderName") final String folderName
) {
return newSubFolder(
sectionIdentifier, "", folderName
);
}
@POST
@Path("/{parentFolderPath:(.+)?}")
@AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public String newSubFolder(
@PathParam("sectionIdentifier") final String sectionIdentifier,
@PathParam("parentFolderPath") final String parentFolderPath,
@FormParam("folderName") final String folderName
) {
final Identifier identifier = identifierParser.parseIdentifier(
sectionIdentifier
);
final Optional<ContentSection> sectionResult;
switch (identifier.getType()) {
case ID:
sectionResult = sectionRepo.findById(
Long.parseLong(identifier.getIdentifier())
);
break;
case UUID:
sectionResult = sectionRepo.findByUuid(identifier
.getIdentifier());
break;
default:
sectionResult = sectionRepo.findByLabel(identifier
.getIdentifier());
break;
}
if (sectionResult.isPresent()) {
final ContentSection section = sectionResult.get();
final Folder parentFolder;
if (parentFolderPath.isEmpty()) {
parentFolder = section.getRootDocumentsFolder();
} else {
final Optional<Folder> parentFolderResult = folderRepo
.findByPath(section, parentFolderPath,
FolderType.DOCUMENTS_FOLDER);
if (parentFolderResult.isPresent()) {
parentFolder = parentFolderResult.get();
} else {
models.put("contentSection", section.getLabel());
models.put("folderPath", parentFolderPath);
return "org/librecms/ui/contentsection/documentfolder/documentfolder-not-found.xhtml";
}
}
if (permissionChecker.isPermitted(
ItemPrivileges.CREATE_NEW, parentFolder
)) {
folderManager.createFolder(folderName, parentFolder);
return String.format(
"redirect:/%s/documentfolders/%s",
sectionIdentifier,
parentFolderPath
);
} else {
models.put("sectionidentifier", sectionIdentifier);
models.put("folderPath", parentFolderPath);
return "org/librecms/ui/contentsection/access-denied.xhtml";
}
} else {
models.put("sectionIdentifier", sectionIdentifier);
return "org/librecms/ui/contentsection/contentsection-not-found.xhtml";
}
}
private List<FolderTreeNode> buildFolderTree( private List<FolderTreeNode> buildFolderTree(
final ContentSection section, final Folder currentFolder final ContentSection section, final Folder currentFolder
) { ) {

View File

@ -31,6 +31,11 @@ public class DocumentFolderModel {
private List<DocumentFolderBreadcrumbModel> breadcrumbs; private List<DocumentFolderBreadcrumbModel> breadcrumbs;
private String path;
private boolean canCreateSubFolders;
public long getCount() { public long getCount() {
return count; return count;
} }
@ -43,7 +48,6 @@ public class DocumentFolderModel {
return firstResult; return firstResult;
} }
protected void setFirstResult(final int firstResult) { protected void setFirstResult(final int firstResult) {
this.firstResult = firstResult; this.firstResult = firstResult;
} }
@ -72,7 +76,6 @@ public class DocumentFolderModel {
this.rows = new ArrayList<>(rows); this.rows = new ArrayList<>(rows);
} }
public List<DocumentFolderBreadcrumbModel> getBreadcrumbs() { public List<DocumentFolderBreadcrumbModel> getBreadcrumbs() {
return Collections.unmodifiableList(breadcrumbs); return Collections.unmodifiableList(breadcrumbs);
} }
@ -83,4 +86,20 @@ public class DocumentFolderModel {
this.breadcrumbs = new ArrayList<>(breadcrumbs); this.breadcrumbs = new ArrayList<>(breadcrumbs);
} }
public String getPath() {
return path;
}
protected void setPath(final String path) {
this.path = path;
}
public boolean isCanCreateSubFolders() {
return canCreateSubFolders;
}
protected void setCanCreateSubFolders(final boolean canCreateSubFolders) {
this.canCreateSubFolders = canCreateSubFolders;
}
} }

View File

@ -5,7 +5,7 @@
xmlns:cms="http://xmlns.jcp.org/jsf/composite/components/cms" xmlns:cms="http://xmlns.jcp.org/jsf/composite/components/cms"
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="/WEB-INF/views/org/librecms/ui/contentsection/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']}" />
@ -49,9 +49,9 @@
<div class="row"> <div class="row">
<div class="col-sm-3"> <div class="col-sm-3">
<form action="#" <form action="#"
class="form-inline mb-3" class="mb-3"
method="get"> method="get">
<div class="form-group">
<label class="sr-only" <label class="sr-only"
for="documentfolders-searchbox"> for="documentfolders-searchbox">
#{CmsAdminMessages['contentsection.documentfolders.searchbox.label']} #{CmsAdminMessages['contentsection.documentfolders.searchbox.label']}
@ -66,13 +66,17 @@
type="submit"> type="submit">
<bootstrap:svgIcon icon="search" /> <bootstrap:svgIcon icon="search" />
<span class="sr-only">#{CmsAdminMessages['contentsection.documentfolders.searchbox.submit']}</span> <span class="sr-only">#{CmsAdminMessages['contentsection.documentfolders.searchbox.submit']}</span>
</div>
</button> </button>
</div> </div>
</div> </div>
</form> </form>
<nav class="documentfolder foldertree"> <nav class="documentfolder foldertree">
<h2>
<a href="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documentfolders">
#{CmsAdminMessages["contentsection.documentfolders.root.title"]}
</a>
</h2>
<ul class="list-group"> <ul class="list-group">
<c:forEach items="#{ContentSectionModel.folders}" <c:forEach items="#{ContentSectionModel.folders}"
var="folder"> var="folder">
@ -81,56 +85,7 @@
value="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documentfolders" /> value="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documentfolders" />
<ui:param name="folder" value="#{folder}" /> <ui:param name="folder" value="#{folder}" />
</ui:include> </ui:include>
<!-- <cms:folderTreeNode basePath="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documentfolders"
collapsed="#{!folder.open}"
name="#{folder.name}"
path="#{folder.path}"
selected="#{folder.selected}"
subFolders="#{folder.subFolders[index]}" />-->
<!-- <cms:folderTreeNode basePath="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documentfolders"
folder="#{folder}" />-->
</c:forEach> </c:forEach>
<!-- <li class="list-group-item">
<a class="" href="#">Folder 1</a>
</li>
<li class="list-group-item">
<div class="d-flex">
<button class="btn btn-light p-0 subfolders-toggler"
data-toggle="collapse"
data-target="#folder-2-subfolders"
aria-expanded="false"
aria-controls="folder-2-subfolders"
type="button">
<bootstrap:svgIcon icon="caret-right-fill" />
<span class="sr-only">
#{CmsAdminMessages['contentsection.documentfolder.foldersnav.subfolders.expand']}
</span>
</button>
<a class="pl-0" href="#">Folder 2</a>
</div>
<ul class="border-0 collapse list-group "
id="folder-2-subfolders">
<li class="border-0 list-group-item">
<a class="" href="#">Folder 2-1</a>
</li>
<li class="border-0 list-group-item">
<a class="" href="#">Folder 2-2</a>
</li>
<li class="border-0 list-group-item">
<a class="" href="#">Folder 2-3</a>
</li>
</ul>
</li>
<li class="list-group-item">
<a class="" href="#">Folder 3</a>
</li>
<li class="list-group-item">
<a class="" href="#">Folder 4</a>
</li>
<li class="list-group-item">
<a class="" href="#">Folder 5</a>
</li>-->
</ul> </ul>
</nav> </nav>
</div> </div>
@ -149,7 +104,7 @@
<div class="input-group-append"> <div class="input-group-append">
<button class="btn btn-secondary" <button class="btn btn-secondary"
type="submit"> type="submit">
<bootstrap:svgIcon icon="search" /> <bootstrap:svgIcon icon="filter" />
<span class="sr-only">#{CmsAdminMessages['contentsection.documentfolder.filter.submit']}</span> <span class="sr-only">#{CmsAdminMessages['contentsection.documentfolder.filter.submit']}</span>
</button> </button>
</div> </div>
@ -159,10 +114,66 @@
${CmsAdminMessages.getMessage("contentsection.documentfolder.pageof", [DocumentFolderModel.currentPage, DocumentFolderModel.numberOfPages])} ${CmsAdminMessages.getMessage("contentsection.documentfolder.pageof", [DocumentFolderModel.currentPage, DocumentFolderModel.numberOfPages])}
</p> </p>
<div> <div>
<button class="btn btn-primary" title="#{CmsAdminMessages['contentsection.documentfolder.add_subfolder']}"> <button class="btn btn-primary"
data-toggle="modal"
data-target="#new-subfolder-dialog"
title="#{CmsAdminMessages['contentsection.documentfolder.add_subfolder']}">
<bootstrap:svgIcon icon="folder-plus" /> <bootstrap:svgIcon icon="folder-plus" />
<span class="sr-only">#{CmsAdminMessages['contentsection.documentfolder.add_subfolder']}</span> <span class="sr-only">#{CmsAdminMessages['contentsection.documentfolder.add_subfolder']}</span>
</button> </button>
<div aria-hidden="true"
aria-labelledby="new-subfolder-dialog-title"
class="modal fade"
id="new-subfolder-dialog"
tabindex="-1">
<div class="modal-dialog">
<form action="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documentfolders/#{DocumentFolderModel.path}"
class="modal-content"
method="post">
<div class="modal-header">
<h2 class="modal-title"
id="new-subfolder-dialog-title">
#{CmsAdminMessages['contentsection.documentfolder.new_subfolder_dialog.title']}
</h2>
<button aria-label="#{CmsAdminMessages['contentsection.documentfolder.new_subfolder_dialog.close']}"
class="close"
data-dismiss="modal"
type="button">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label for="new-subfolder-name">
#{CmsAdminMessages['contentsection.documentfolder.new_subfolder.name.label']}
</label>
<input aria-describedby="new-subfolder-name-help"
class="form-control"
id="new-subfolder-name"
name="folderName"
pattern="^([a-zA-Z0-9-_]*)$"
type="text"
value="" />
<small class="form-text text-muted"
id="new-subfolder-name-help">
#{CmsAdminMessages['contentsection.documentfolder.new_subfolder.name.help']}
</small>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-danger"
data-dismiss="modal"
type="button">
#{CmsAdminMessages['contentsection.documentfolder.new_subfolder_dialog.close']}
</button>
<button class="btn btn-success"
type="submit">
#{CmsAdminMessages['contentsection.documentfolder.new_subfolder_dialog.submit']}
</button>
</div>
</form>
</div>
</div>
<button class="btn btn-primary" title="#{CmsAdminMessages['contentsection.documentfolder.add_document']}"> <button class="btn btn-primary" 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>

View File

@ -44,7 +44,7 @@ contentsection.documentfolder.pagination.next_page=Next page
contentsection.not_found=No content section identifed by {0} available. contentsection.not_found=No content section identifed by {0} available.
contentsection.accessdenied=Your are not permitted to access content section {0}. contentsection.accessdenied=Your are not permitted to access content section {0}.
contentsection.documentfolder.types.folder=Folder contentsection.documentfolder.types.folder=Folder
contentsection.documentfolder.pageof=Page {0} of {1}. contentsection.documentfolder.pageof=Page {0} of {1}
contentsection.documentfolder.add_document=Create document contentsection.documentfolder.add_document=Create document
contentsection.documentfolder.add_subfolder=Add subfolder contentsection.documentfolder.add_subfolder=Add subfolder
contentsection.documentfolder.filter.label=Filter documents contentsection.documentfolder.filter.label=Filter documents
@ -53,6 +53,12 @@ contentsections.documentfolder.not_found=Not folder with path {1} found in conte
contentsection.not_found.title=Content Section not found contentsection.not_found.title=Content Section not found
contentsection.documentfolders.searchbox.label=Search in document folders contentsection.documentfolders.searchbox.label=Search in document folders
contentsection.documentfolders.searchbox.submit=Search contentsection.documentfolders.searchbox.submit=Search
contentsection.assetsfolders.title=Media & Data contentsection.assetfolders.title=Media & Data
contentsection.categories.title=Categories & Page Trees contentsection.categories.title=Categories & Page Trees
contentsection.categories.configuration=Configuration contentsection.configuration.title=Configuration
contentsection.documentfolder.new_subfolder_dialog.title=Create new subfolder
contentsection.documentfolder.new_subfolder.name.label=Name
contentsection.documentfolder.new_subfolder.name.help=The new name of the subfolder. May only contain the letters a to z and A to Z, numbers, the dash and the underscore
contentsection.documentfolder.new_subfolder_dialog.submit=Create new subfolder
contentsection.documentfolder.new_subfolder_dialog.close=Cancel
contentsection.documentfolders.root.title=Documents

View File

@ -44,7 +44,7 @@ contentsection.documentfolder.pagination.next_page=Eine Seite weiter
contentsection.not_found=Keine Content Section mit dem Identifier {0} gefunden. contentsection.not_found=Keine Content Section mit dem Identifier {0} gefunden.
contentsection.accessdenied=Sind sind nicht berechtigt auf die Content Section {0} zuzugreifen. contentsection.accessdenied=Sind sind nicht berechtigt auf die Content Section {0} zuzugreifen.
contentsection.documentfolder.types.folder=Ordner contentsection.documentfolder.types.folder=Ordner
contentsection.documentfolder.pageof=Seite {0} von {1}. contentsection.documentfolder.pageof=Seite {0} von {1}
contentsection.documentfolder.add_document=Neues Dokument erstellen contentsection.documentfolder.add_document=Neues Dokument erstellen
contentsection.documentfolder.add_subfolder=Unterordner erstellen contentsection.documentfolder.add_subfolder=Unterordner erstellen
contentsection.documentfolder.filter.label=Dokumente filtern contentsection.documentfolder.filter.label=Dokumente filtern
@ -53,6 +53,12 @@ contentsections.documentfolder.not_found=Es wurde kein Ordner mit dem Pfad {1} i
contentsection.not_found.title=Content Section nicht gefunden contentsection.not_found.title=Content Section nicht gefunden
contentsection.documentfolders.searchbox.label=In Dokument-Ordnern suchen contentsection.documentfolders.searchbox.label=In Dokument-Ordnern suchen
contentsection.documentfolders.searchbox.submit=Suchen contentsection.documentfolders.searchbox.submit=Suchen
contentsection.assetsfolders.title=Media & Data contentsection.assetfolders.title=Media & Data
contentsection.categories.title=Kategorien & Seitenb\u00e4ume contentsection.categories.title=Kategorien & Seitenb\u00e4ume
contentsection.categories.configuration=Konfiguration contentsection.configuration.title=Konfiguration
contentsection.documentfolder.new_subfolder_dialog.title=Neuen Unterordner erstellen
contentsection.documentfolder.new_subfolder.name.label=Name
contentsection.documentfolder.new_subfolder.name.help=Der Name des neuen Ordners. Darf nur die Buchstaben a bis z und A bis Z, Ziffern, den Bindestrich und den Unterstrich enthalten.
contentsection.documentfolder.new_subfolder_dialog.submit=Neuen Ordner anlegen
contentsection.documentfolder.new_subfolder_dialog.close=Abbrechen
contentsection.documentfolders.root.title=Dokumente