AssetFolder UI classes (controller, models), some refactoring

Former-commit-id: e564c44c3a
pull/10/head
Jens Pelzetter 2021-02-08 20:58:33 +01:00
parent 46058678dd
commit 00e1da3141
33 changed files with 1908 additions and 356 deletions

View File

@ -0,0 +1,117 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.librecms.contentsection;
import java.util.Date;
import java.util.Objects;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class AssetFolderEntry {
private long entryId;
private String entryUuid;
private String displayName;
private boolean folder;
public AssetFolderEntry() {
}
public AssetFolderEntry(
final long entryId,
final String entryUuid,
final String displayName,
final Date creationDate,
final Date lastModified,
final String version,
final boolean folder
) {
this.entryId = entryId;
this.entryUuid = entryUuid;
this.displayName = displayName;
this.folder = folder;
}
public long getEntryId() {
return entryId;
}
public void setEntryId(final long entryId) {
this.entryId = entryId;
}
public String getEntryUuid() {
return entryUuid;
}
public void setEntryUuid(final String entryUuid) {
this.entryUuid = entryUuid;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(final String displayName) {
this.displayName = displayName;
}
public boolean isFolder() {
return folder;
}
public void setFolder(final boolean folder) {
this.folder = folder;
}
@Override
public int hashCode() {
int hash = 3;
hash = 29 * hash + (int) (entryId ^ (entryId >>> 32));
hash = 29 * hash + Objects.hashCode(entryUuid);
hash = 29 * hash + Objects.hashCode(displayName);
hash = 29 * hash + (folder ? 1 : 0);
return hash;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof AssetFolderEntry)) {
return false;
}
final AssetFolderEntry other = (AssetFolderEntry) obj;
if (!other.canEqual(this)) {
return false;
}
if (entryId != other.getEntryId()) {
return false;
}
if (folder != other.isFolder()) {
return false;
}
if (!Objects.equals(entryUuid, other.getEntryUuid())) {
return false;
}
return Objects.equals(displayName, other.getDisplayName());
}
public boolean canEqual(final Object obj) {
return obj instanceof AssetFolderEntry;
}
}

View File

@ -87,19 +87,19 @@ public class DocumentFolderEntry {
} }
public Date getCreationDate() { public Date getCreationDate() {
return creationDate; return new Date(creationDate.getTime());
} }
public void setCreationDate(final Date creationDate) { public void setCreationDate(final Date creationDate) {
this.creationDate = creationDate; this.creationDate = new Date(creationDate.getTime());
} }
public Date getLastModified() { public Date getLastModified() {
return lastModified; return new Date(lastModified.getTime());
} }
public void setLastModified(final Date lastModified) { public void setLastModified(final Date lastModified) {
this.lastModified = lastModified; this.lastModified = new Date(lastModified.getTime());
} }
public String getVersion() { public String getVersion() {
@ -156,13 +156,13 @@ public class DocumentFolderEntry {
if (!Objects.equals(entryUuid, other.getEntryUuid())) { if (!Objects.equals(entryUuid, other.getEntryUuid())) {
return false; return false;
} }
if (!Objects.equals(itemClass, other.getItemClass())) {
return false;
}
if (!Objects.equals(displayName, other.getDisplayName())) { if (!Objects.equals(displayName, other.getDisplayName())) {
return false; return false;
} }
if (version != other.getVersion()) { return Objects.equals(version, other.getVersion());
return false;
}
return true;
} }
public boolean canEqual(final Object obj) { public boolean canEqual(final Object obj) {

View File

@ -26,7 +26,6 @@ import javax.persistence.Table;
import org.libreccm.categorization.Category; import org.libreccm.categorization.Category;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalDate;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@ -124,6 +123,61 @@ import static org.librecms.CmsConstants.*;
) )
}) })
@NamedNativeQueries({ @NamedNativeQueries({
@NamedNativeQuery(
name = "Folder.countAssetFolderEntries",
query = "SELECT ("
+ "("
+ "SELECT COUNT(*) "
+ "FROM ccm_core.ccm_objects "
+ "JOIN ccm_cms.assets "
+ "ON ccm_objects.object_id = assets.object_id "
+ "JOIN ccm_core.categorizations "
+ " ON ccm_objects.object_id "
+ " = categorizations.object_id "
+ "WHERE categorizations.category_id = :folderId "
+ ") "
+ "+ "
+ "("
+ "SELECT COUNT(*) "
+ "FROM ccm_core.categories "
+ "JOIN ccm_core.ccm_objects "
+ " ON categories.object_id = ccm_objects.object_id "
+ "JOIN ccm_cms.folders "
+ " ON categories.object_id = folders.object_id "
+ "WHERE categories.parent_category_id = :folderId "
+ "AND folders.type = 'ASSETS_FOLDER'"
+ ") "
+ ") AS entries_count",
resultSetMapping = "Folder.countAssetFolderEntries"
),
@NamedNativeQuery(
name = "Folder.getAssetFolderEntries",
query = "SELECT ccm_objects.object_id AS entry_id, "
+ " ccm_objects.uuid AS entry_uuid, "
+ " ccm_objects.display_name AS display_name, "
+ " false AS is_folder "
+ "FROM ccm_cms.assets "
+ "JOIN ccm_core.ccm_objects "
+ " ON ccm_cms.assets.object_id "
+ " = ccm_core.ccm_objects.object_id "
+ "JOIN ccm_core.categorizations "
+ " ON ccm_objects.object_id "
+ " = ccm_core.categorizations.object_id "
+ "WHERE categorizations.category_id = :folderId "
+ "UNION "
+ "SELECT categories.object_id AS entry_id, "
+ " ccm_objects.uuid AS entry_uuid, "
+ " categories.\"name\" AS display_name, "
+ " true as is_folder "
+ "FROM ccm_core.categories "
+ "JOIN ccm_core.ccm_objects "
+ " ON categories.object_id = ccm_objects.object_id "
+ "JOIN ccm_cms.folders "
+ " ON categories.object_id = folders.object_id "
+ "WHERE categories.parent_category_id = :folderId "
+ "AND folders.\"type\" = 'ASSETS_FOLDER'",
resultSetMapping = "Folder.DocumentFolderEntry"
),
@NamedNativeQuery( @NamedNativeQuery(
name = "Folder.countDocumentFolderEntries", name = "Folder.countDocumentFolderEntries",
query = "SELECT (" query = "SELECT ("
@ -201,6 +255,26 @@ import static org.librecms.CmsConstants.*;
@ColumnResult(name = "entries_count", type = long.class) @ColumnResult(name = "entries_count", type = long.class)
} }
), ),
@SqlResultSetMapping(
name = "Folder.countAssetFolderEntries",
columns = {
@ColumnResult(name = "entries_count", type = long.class)
}
),
@SqlResultSetMapping(
name = "Folder.getAssetFolderEntries",
classes = {
@ConstructorResult(
columns = {
@ColumnResult(name = "entry_id", type = long.class),
@ColumnResult(name = "entry_uuid"),
@ColumnResult(name = "display_name"),
@ColumnResult(name = "is_folder", type = boolean.class)
},
targetClass = AssetFolderEntry.class
)
}
),
@SqlResultSetMapping( @SqlResultSetMapping(
name = "Folder.DocumentFolderEntry", name = "Folder.DocumentFolderEntry",
classes = { classes = {
@ -216,28 +290,8 @@ import static org.librecms.CmsConstants.*;
@ColumnResult(name = "is_folder", type = boolean.class) @ColumnResult(name = "is_folder", type = boolean.class)
}, },
targetClass = DocumentFolderEntry.class targetClass = DocumentFolderEntry.class
),} )
// entities = { }
// @EntityResult(
// entityClass = DocumentFolderEntry.class,
// fields = {
// @FieldResult(column = "entry_id", name = "entryId"),
// @FieldResult(column = "entry_uuid", name = "entryUuid"),
// @FieldResult(column = "display_name", name = "displayName"),
// @FieldResult(column = "item_class", name = "itemClass"),
// @FieldResult(
// column = "creation_date",
// name = "creation_date"
// ),
// @FieldResult(
// column = "last_modified",
// name = "lastModified"
// ),
// @FieldResult(column = "version", name = "version"),
// @FieldResult(column = "is_folder", name = "folder")
// }
// )
// }
) )
}) })
public class Folder extends Category implements Serializable { public class Folder extends Category implements Serializable {
@ -245,7 +299,6 @@ public class Folder extends Category implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@OneToOne(fetch = FetchType.LAZY) @OneToOne(fetch = FetchType.LAZY)
// @JoinColumn(name = "CONTENT_SECTION_ID")
@JoinTable(name = "FOLDER_CONTENT_SECTION_MAP", schema = DB_SCHEMA, @JoinTable(name = "FOLDER_CONTENT_SECTION_MAP", schema = DB_SCHEMA,
inverseJoinColumns = { inverseJoinColumns = {
@JoinColumn(name = "CONTENT_SECTION_ID")}, @JoinColumn(name = "CONTENT_SECTION_ID")},
@ -291,14 +344,6 @@ public class Folder extends Category implements Serializable {
.collect(Collectors.toList())); .collect(Collectors.toList()));
} }
// public Folder getParentFolder() {
// final Category parent = getParentCategory();
// if (parent == null) {
// return null;
// } else {
// return (Folder) getParentCategory();
// }
// }
@Override @Override
public int hashCode() { public int hashCode() {
int hash = super.hashCode(); int hash = super.hashCode();
@ -330,9 +375,13 @@ public class Folder extends Category implements Serializable {
@Override @Override
public String toString(final String data) { public String toString(final String data) {
return super.toString(String.format(", type = %s%s", return super.toString(
type, String.format(
data)); ", type = %s%s",
type,
data
)
);
} }
} }

View File

@ -306,6 +306,35 @@ public class FolderRepository extends AbstractEntityRepository<Long, Folder> {
).getSingleResult(); ).getSingleResult();
} }
public List<AssetFolderEntry> getAssetFolderEntries(
final Folder folder,
final int firstResult,
final int maxResults,
final String term
) {
return getEntityManager()
.createNamedQuery(
"Folder.getAssetFolderEntries", AssetFolderEntry.class
)
.setParameter(
"folderId", Objects.requireNonNull(folder).getObjectId()
)
.setFirstResult(firstResult)
.setMaxResults(maxResults)
.getResultList();
}
public long countAssetFolderEntries(
final Folder folder,
final String term
) {
return getEntityManager()
.createNamedQuery("Folder.countAssetFolderEntries", Long.class)
.setParameter(
"folderId", Objects.requireNonNull(folder).getObjectId()
).getSingleResult();
}
public long countObjectsInFolder(final Folder folder) { public long countObjectsInFolder(final Folder folder) {
return countObjectsInFolder(folder, ""); return countObjectsInFolder(folder, "");
} }

View File

@ -24,9 +24,6 @@ import org.librecms.contentsection.ContentSection;
import org.librecms.contentsection.Folder; import org.librecms.contentsection.Folder;
import org.librecms.contentsection.rs.ContentItems; import org.librecms.contentsection.rs.ContentItems;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/** /**
* Constants for privileges allowing actions on the items of a content section. * Constants for privileges allowing actions on the items of a content section.

View File

@ -0,0 +1,50 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.librecms.ui.contentsections;
import org.libreccm.security.PermissionChecker;
import org.libreccm.security.PermissionManager;
import org.librecms.contentsection.Folder;
import java.util.List;
import java.util.stream.Collectors;
import javax.inject.Inject;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
abstract class AbstractCurrentUserPermissions {
@Inject
private PermissionChecker permissionChecker;
@Inject
private PermissionManager permissionManager;
public List<GrantedPrivilegeModel> buildCurrentUserPermissions(
final Folder folder
) {
return permissionManager
.listDefiniedPrivileges(getPrivilegesClass())
.stream()
.map(privilege -> buildCurrentUserPermission(folder, privilege))
.collect(Collectors.toList());
}
protected abstract Class<?> getPrivilegesClass();
private GrantedPrivilegeModel buildCurrentUserPermission(
final Folder folder, final String privilege
) {
final GrantedPrivilegeModel model = new GrantedPrivilegeModel();
model.setPrivilege(privilege);
model.setGranted(permissionChecker.isPermitted(privilege, folder));
return model;
}
}

View File

@ -0,0 +1,100 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.librecms.ui.contentsections;
import org.librecms.contentsection.ContentSection;
import org.librecms.contentsection.Folder;
import org.librecms.contentsection.FolderManager;
import java.util.List;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.transaction.Transactional;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
abstract class AbstractFolderTree<T extends FolderTreeNode<T, P>, P extends PermissionsModel> {
@Inject
private FolderManager folderManager;
@Transactional(Transactional.TxType.REQUIRED)
public List<T> buildFolderTree(
final ContentSection section, final Folder currentFolder
) {
final Folder root = getRootFolder(section);
final String currentFolderPath = folderManager
.getFolderPath(currentFolder)
.substring(
folderManager
.getFolderPath(section.getRootDocumentsFolder())
.length() - 1
);
return root
.getSubFolders()
.stream()
.sorted(this::compareFolders)
.map(
folder -> buildFolderTreeNode(
section, currentFolderPath, folder
)
).collect(Collectors.toList());
}
protected abstract T newFolderTreeNode();
@Transactional(Transactional.TxType.REQUIRED)
protected abstract Folder getRootFolder(final ContentSection section);
@Transactional(Transactional.TxType.REQUIRED)
protected abstract P buildPermissionsModel(final Folder folder);
private T buildFolderTreeNode(
final ContentSection section,
final String currentFolderPath,
final Folder folder
) {
final String folderPath = folderManager
.getFolderPath(folder)
.substring(
folderManager
.getFolderPath(section.getRootDocumentsFolder())
.length() - 1
);
final T node = newFolderTreeNode();
node.setFolderId(folder.getObjectId());
node.setUuid(folder.getUuid());
node.setName(folder.getName());
node.setPath(folderPath);
node.setOpen(currentFolderPath.startsWith(folderPath));
node.setSelected(currentFolderPath.equals(folderPath));
node.setPermissions(buildPermissionsModel(folder));
node.setSubFolders(
folder
.getSubFolders()
.stream()
.sorted(this::compareFolders)
.map(
subFolder -> buildFolderTreeNode(
section, currentFolderPath, subFolder
)
)
.collect(Collectors.toList())
);
return node;
}
private int compareFolders(final Folder folder1, final Folder folder2) {
return folder1.getName().compareTo(folder2.getName());
}
}

View File

@ -0,0 +1,95 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.librecms.ui.contentsections;
import org.libreccm.security.Permission;
import org.libreccm.security.PermissionChecker;
import org.libreccm.security.PermissionManager;
import org.libreccm.security.Role;
import org.librecms.contentsection.ContentSection;
import org.librecms.contentsection.Folder;
import java.util.List;
import java.util.stream.Collectors;
import javax.inject.Inject;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
abstract class AbstractGrantedPrivileges {
@Inject
private PermissionChecker permissionChecker;
@Inject
private PermissionManager permissionManager;
public List<PrivilegesGrantedToRoleModel> buildPermissionsMatrix(
final ContentSection section, final Folder folder
) {
return section
.getRoles()
.stream()
.map(role -> buildPrivilegesGrantedToRoleModel(role, folder))
.collect(Collectors.toList());
}
private PrivilegesGrantedToRoleModel buildPrivilegesGrantedToRoleModel(
final Role role, final Folder folder
) {
final List<GrantedPrivilegeModel> grantedPrivilges = permissionManager
.listDefiniedPrivileges(getPrivilegesClass())
.stream()
.map(
privilege -> buildGrantedPrivilegeModel(
role,
folder,
privilege,
permissionManager.findPermissionsForRoleAndObject(
role, folder
)
)
)
.collect(Collectors.toList());
final PrivilegesGrantedToRoleModel model
= new PrivilegesGrantedToRoleModel();
model.setGrantedPrivileges(grantedPrivilges);
model.setGrantee(role.getName());
return model;
}
private GrantedPrivilegeModel buildGrantedPrivilegeModel(
final Role role,
final Folder folder,
final String privilege,
final List<Permission> permissions
) {
final GrantedPrivilegeModel model = new GrantedPrivilegeModel();
model.setGranted(permissionChecker.isPermitted(privilege, folder, role));
model.setInherited(
model.isGranted()
&& permissions
.stream()
.anyMatch(
permission
-> permission.getGrantee().equals(role)
&& permission.getGrantedPrivilege().equals(privilege)
&& permission.getObject().equals(folder)
&& permission.getInheritedFrom() != null
)
);
model.setPrivilege(privilege);
return model;
}
protected abstract Class<?> getPrivilegesClass();
}

View File

@ -0,0 +1,580 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.librecms.ui.contentsections;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.libreccm.api.Identifier;
import org.libreccm.api.IdentifierParser;
import org.libreccm.l10n.GlobalizationHelper;
import org.libreccm.security.AuthorizationRequired;
import org.libreccm.security.PermissionChecker;
import org.libreccm.security.PermissionManager;
import org.libreccm.security.Role;
import org.libreccm.security.RoleRepository;
import org.librecms.contentsection.Asset;
import org.librecms.contentsection.AssetFolderEntry;
import org.librecms.contentsection.AssetManager;
import org.librecms.contentsection.AssetRepository;
import org.librecms.contentsection.ContentSection;
import org.librecms.contentsection.ContentSectionRepository;
import org.librecms.contentsection.Folder;
import org.librecms.contentsection.FolderManager;
import org.librecms.contentsection.FolderRepository;
import org.librecms.contentsection.FolderType;
import org.librecms.contentsection.privileges.AssetPrivileges;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.mvc.Controller;
import javax.mvc.Models;
import javax.transaction.Transactional;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@Controller
@Path("/{sectionIdentifier}/assetfolders")
public class AssetFolderController {
@Inject
private AssetFolderModel assetFolderModel;
@Inject
private AssetFolderTree assetFolderTree;
@Inject
private AssetPermissions assetPermissions;
@Inject
private AssetManager assetManager;
@Inject
private AssetRepository assetRepo;
@Inject
private ContentSectionModel contentSectionModel;
@Inject
private ContentSectionRepository sectionRepo;
@Inject
private CurrentUserAssetPermissions currentUserPermissions;
@Inject
private FolderManager folderManager;
@Inject
private FolderRepository folderRepo;
@Inject
private GlobalizationHelper globalizationHelper;
@Inject
private GrantedAssetPrivileges grantedPrivileges;
@Inject
private IdentifierParser identifierParser;
@Inject
private Models models;
@Inject
private PermissionChecker permissionChecker;
@Inject
private PermissionManager permissionManager;
@Inject
private RoleRepository roleRepo;
private static final Logger LOGGER = LogManager.getLogger(
AssetFolderController.class
);
@GET
@Path("/")
@AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public String list(
@PathParam("sectionIdentifier") final String sectionIdentifier,
@QueryParam("filterTerm") @DefaultValue("") final String filterTerm,
@QueryParam("firstResult") @DefaultValue("0") final int firstResult,
@QueryParam("maxResults") @DefaultValue("20") final int maxResults
) {
return list(
sectionIdentifier, "", filterTerm, firstResult, maxResults
);
}
@GET
@Path("/{folderPath:(.+)?}")
@AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public String list(
@PathParam("sectionIdentifier") final String sectionIdentifier,
@PathParam("folderPath") final String folderPath,
@QueryParam("filterTerm") @DefaultValue("") final String filterTerm,
@QueryParam("firstResult") @DefaultValue("0") final int firstResult,
@QueryParam("maxResults") @DefaultValue("20") final int maxResults
) {
final Optional<ContentSection> sectionResult = retrieveContentSection(
sectionIdentifier
);
if (!sectionResult.isPresent()) {
models.put("sectionIdentifier", sectionIdentifier);
return "org/librecms/ui/contentsection/contentsection-not-found.xhtml";
}
final ContentSection section = sectionResult.get();
if (!permissionChecker.isPermitted(
AssetPrivileges.EDIT, section.getRootAssetsFolder()
)) {
models.put("sectionidentifier", sectionIdentifier);
return "org/librecms/ui/contentsection/access-denied.xhtml";
}
contentSectionModel.setSection(section);
final Folder folder;
if (folderPath.isEmpty()) {
folder = section.getRootAssetsFolder();
assetFolderModel.setBreadcrumbs(Collections.emptyList());
} else {
final Optional<Folder> folderResult = folderRepo
.findByPath(
section,
folderPath,
FolderType.ASSETS_FOLDER
);
if (folderResult.isPresent()) {
folder = folderResult.get();
assetFolderModel.setBreadcrumbs(buildBreadcrumbs(folderPath));
} else {
models.put("contentSection", section.getLabel());
models.put("folderPath", folderPath);
return "org/librecms/ui/contentsection/assetfolder/asssetfolder-not-found.xhtml";
}
}
if (!permissionChecker.isPermitted(AssetPrivileges.EDIT, folder)) {
models.put("sectionidentifier", sectionIdentifier);
models.put("folderPath", folderPath);
return "org/librecms/ui/contentsection/access-denied.xhtml";
}
final List<AssetFolderEntry> folderEntries = folderRepo
.getAssetFolderEntries(folder, firstResult, maxResults, filterTerm);
assetFolderModel.setCount(
folderRepo.countAssetFolderEntries(folder, filterTerm)
);
assetFolderModel.setFirstResult(firstResult);
assetFolderModel.setMaxResults(maxResults);
contentSectionModel.setAssetFolders(
assetFolderTree.buildFolderTree(section, folder)
);
assetFolderModel.setRows(
folderEntries
.stream()
.map(entry -> buildRowModel(section, entry))
.collect(Collectors.toList())
);
assetFolderModel.setPath(folderPath);
assetFolderModel.setCanCreateSubFolders(
permissionChecker.isPermitted(AssetPrivileges.CREATE_NEW, folder)
);
assetFolderModel.setCanCreateAssets(
permissionChecker.isPermitted(AssetPrivileges.CREATE_NEW, folder)
);
assetFolderModel.setGrantedPermissions(
grantedPrivileges.buildPermissionsMatrix(section, folder)
);
assetFolderModel.setPrivileges(
permissionManager.listDefiniedPrivileges(AssetPrivileges.class)
);
assetFolderModel.setCurrentUserPermissions(
currentUserPermissions.buildCurrentUserPermissions(folder)
);
return "org/librecms/ui/contentsection/assetfolder/assetfolder.xhtml";
}
@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 Optional<ContentSection> sectionResult = retrieveContentSection(
sectionIdentifier
);
if (!sectionResult.isPresent()) {
models.put("sectionIdentifier", sectionIdentifier);
return "org/librecms/ui/contentsection/contentsection-not-found.xhtml";
}
final ContentSection section = sectionResult.get();
if (!permissionChecker.isPermitted(
AssetPrivileges.EDIT, section.getRootAssetsFolder()
)) {
models.put("sectionidentifier", sectionIdentifier);
return "org/librecms/ui/contentsection/access-denied.xhtml";
}
final Folder parentFolder;
if (parentFolderPath.isEmpty()) {
parentFolder = section.getRootAssetsFolder();
} else {
final Optional<Folder> parentFolderResult = folderRepo
.findByPath(
section,
parentFolderPath,
FolderType.ASSETS_FOLDER
);
if (parentFolderResult.isPresent()) {
parentFolder = parentFolderResult.get();
} else {
models.put("contentSection", section.getLabel());
models.put("folderPath", parentFolderPath);
return "org/librecms/ui/contentsection/assetfolder/assetfolder-not-found.xhtml";
}
}
if (!permissionChecker.isPermitted(
AssetPrivileges.CREATE_NEW, parentFolder
)) {
models.put("sectionidentifier", sectionIdentifier);
models.put("folderPath", parentFolderPath);
return "org/librecms/ui/contentsection/access-denied.xhtml";
}
folderManager.createFolder(folderName, parentFolder);
return String.format(
"redirect:/%s/assetfolders/%s",
sectionIdentifier,
parentFolderPath
);
}
@POST
@Path("/@permissions/{role}/")
@AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public String updatePermissions(
@PathParam("sectionIdentifier") final String sectionIdentifier,
@PathParam("role") final String roleParam,
@FormParam("permissions") final List<String> permissions
) {
return updatePermissions(
sectionIdentifier, "", roleParam, permissions
);
}
@POST
@Path("/@permissions/{role}/{folderPath:(.+)?}")
@AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public String updatePermissions(
@PathParam("sectionIdentifier") final String sectionIdentifier,
@PathParam("folderPath") final String folderPath,
@PathParam("role") final String roleParam,
@FormParam("permissions") final List<String> permissions
) {
final Optional<ContentSection> sectionResult = retrieveContentSection(
sectionIdentifier
);
if (!sectionResult.isPresent()) {
models.put("sectionIdentifier", sectionIdentifier);
return "org/librecms/ui/contentsection/contentsection-not-found.xhtml";
}
final ContentSection section = sectionResult.get();
if (!permissionChecker.isPermitted(
AssetPrivileges.EDIT, section.getRootAssetsFolder()
)) {
models.put("sectionidentifier", sectionIdentifier);
return "org/librecms/ui/contentsection/access-denied.xhtml";
}
final Folder folder;
if (folderPath.isEmpty()) {
folder = section.getRootAssetsFolder();
assetFolderModel.setBreadcrumbs(Collections.emptyList());
} else {
final Optional<Folder> folderResult = folderRepo
.findByPath(
section,
folderPath,
FolderType.ASSETS_FOLDER
);
if (folderResult.isPresent()) {
folder = folderResult.get();
assetFolderModel.setBreadcrumbs(buildBreadcrumbs(folderPath));
} else {
models.put("contentSection", section.getLabel());
models.put("folderPath", folderPath);
return "org/librecms/ui/contentsection/assestfolder/assetfolder-not-found.xhtml";
}
}
if (!permissionChecker.isPermitted(AssetPrivileges.EDIT, folder)) {
models.put("sectionidentifier", sectionIdentifier);
models.put("folderPath", folderPath);
return "org/librecms/ui/contentsection/access-denied.xhtml";
}
final Optional<Role> roleResult = roleRepo.findByName(roleParam);
if (!roleResult.isPresent()) {
models.put("role", roleParam);
}
final Role role = roleResult.get();
final List<String> privileges = permissionManager
.listDefiniedPrivileges(AssetPrivileges.class);
privileges
.stream()
.filter(privilege -> permissions.contains(privilege))
.forEach(
privilege -> permissionManager.grantPrivilege(
privilege, role, folder
)
);
privileges
.stream()
.filter(privilege -> !permissions.contains(privilege))
.forEach(
privilege -> permissionManager.revokePrivilege(
privilege, role, folder
)
);
return String.format(
"redirect:/%s/assetfolders/%s",
sectionIdentifier,
folderPath
);
}
@POST
@Path("/@rename/{folderPath:(.+)?}")
@AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public String renameFolder(
@PathParam("sectionIdentifier") final String sectionIdentifier,
@PathParam("folderPath") final String folderPath,
@FormParam("folderName") final String folderName
) {
final Optional<ContentSection> sectionResult = retrieveContentSection(
sectionIdentifier
);
if (!sectionResult.isPresent()) {
models.put("sectionIdentifier", sectionIdentifier);
return "org/librecms/ui/contentsection/contentsection-not-found.xhtml";
}
final ContentSection section = sectionResult.get();
if (!permissionChecker.isPermitted(
AssetPrivileges.EDIT, section.getRootAssetsFolder()
)) {
models.put("sectionidentifier", sectionIdentifier);
return "org/librecms/ui/contentsection/access-denied.xhtml";
}
final Folder folder;
final Optional<Folder> folderResult = folderRepo
.findByPath(
section,
folderPath,
FolderType.ASSETS_FOLDER
);
if (folderResult.isPresent()) {
folder = folderResult.get();
assetFolderModel.setBreadcrumbs(buildBreadcrumbs(folderPath));
} else {
models.put("contentSection", section.getLabel());
models.put("folderPath", folderPath);
return "org/librecms/ui/contentsection/assetfolder/assetfolder-not-found.xhtml";
}
if (!permissionChecker.isPermitted(AssetPrivileges.EDIT, folder)) {
models.put("sectionidentifier", sectionIdentifier);
models.put("folderPath", folderPath);
return "org/librecms/ui/contentsection/access-denied.xhtml";
}
folder.setName(folderName);
folderRepo.save(folder);
final String[] folderPathTokens = folderPath.split("/");
final String returnFolderPath = String.join(
"/",
Arrays.copyOf(folderPathTokens, folderPathTokens.length - 1)
);
return String.format(
"redirect:/%s/assetfolders/%s",
sectionIdentifier,
returnFolderPath
);
}
private Optional<ContentSection> retrieveContentSection(
final String sectionIdentifier
) {
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;
}
return sectionResult;
}
private List<FolderBreadcrumbsModel> buildBreadcrumbs(
final String folderPath
) {
final List<FolderBreadcrumbsModel> breadcrumbs
= new ArrayList<>();
final List<String> tokens = Arrays
.stream(folderPath.split("/"))
.filter(token -> !token.isEmpty())
.collect(Collectors.toList());
for (final String token : tokens) {
final String path = breadcrumbs
.stream()
.map(FolderBreadcrumbsModel::getPathToken)
.collect(Collectors.joining("/"));
final FolderBreadcrumbsModel breadcrumb
= new FolderBreadcrumbsModel();
breadcrumb.setPath(path);
breadcrumb.setPathToken(token);
breadcrumbs.add(breadcrumb);
}
breadcrumbs
.get(breadcrumbs.size() - 1)
.setCurrentFolder(true);
return breadcrumbs;
}
private AssetFolderRowModel buildRowModel(
final ContentSection section, final AssetFolderEntry entry
) {
Objects.requireNonNull(section);
Objects.requireNonNull(entry);
final AssetFolderRowModel row = new AssetFolderRowModel();
if (entry.isFolder()) {
final Folder folder = folderRepo
.findById(entry.getEntryId())
.get();
row.setDeletable(
folderManager.folderIsDeletable(folder)
== FolderManager.FolderIsDeletable.YES
);
row.setFolder(true);
row.setFolderPath(
folderManager
.getFolderPath(folder)
.substring(
folderManager
.getFolderPath(section.getRootAssetsFolder())
.length()
)
);
row.setName(entry.getDisplayName());
row.setTitle(
globalizationHelper.getValueFromLocalizedString(
folder.getTitle()
)
);
row.setType(
globalizationHelper.getLocalizedTextsUtil(
"org.librecms.CmsAdminMessages"
).getText("contentsection.assetfolder.types.folder")
);
row.setPermissions(
assetPermissions.buildAssetPermissionsModel(folder)
);
} else {
final Asset asset = assetRepo
.findById(entry.getEntryId())
.get();
row.setDeletable(!assetManager.isAssetInUse(asset));
row.setFolder(false);
row.setName(entry.getDisplayName());
row.setNoneCmsObject(false);
row.setTitle(
globalizationHelper.getValueFromLocalizedString(
asset.getTitle()
)
);
row.setType(asset.getClass().getName());
row.setPermissions(
assetPermissions.buildAssetPermissionsModel(asset)
);
}
return row;
}
}

View File

@ -0,0 +1,139 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.librecms.ui.contentsections;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@RequestScoped
@Named("AssetFolderModel")
public class AssetFolderModel {
private long count;
private int firstResult;
private int maxResults;
private List<AssetFolderRowModel> rows;
private List<FolderBreadcrumbsModel> breadcrumbs;
private String path;
private boolean canCreateSubFolders;
private boolean canCreateAssets;
private List<GrantedPrivilegeModel> currentUserPermissions;
private List<PrivilegesGrantedToRoleModel> grantedPermissions;
private List<String> privileges;
public long getCount() {
return count;
}
public void setCount(final long count) {
this.count = count;
}
public int getFirstResult() {
return firstResult;
}
public void setFirstResult(final int firstResult) {
this.firstResult = firstResult;
}
public int getMaxResults() {
return maxResults;
}
public void setMaxResults(final int maxResults) {
this.maxResults = maxResults;
}
public List<AssetFolderRowModel> getRows() {
return Collections.unmodifiableList(rows);
}
public void setRows(final List<AssetFolderRowModel> rows) {
this.rows = new ArrayList<>(rows);
}
public List<FolderBreadcrumbsModel> getBreadcrumbs() {
return Collections.unmodifiableList(breadcrumbs);
}
public void setBreadcrumbs(
final List<FolderBreadcrumbsModel> breadcrumbs
) {
this.breadcrumbs = new ArrayList<>(breadcrumbs);
}
public String getPath() {
return path;
}
public void setPath(final String path) {
this.path = path;
}
public boolean isCanCreateSubFolders() {
return canCreateSubFolders;
}
public void setCanCreateSubFolders(final boolean canCreateSubFolders) {
this.canCreateSubFolders = canCreateSubFolders;
}
public boolean isCanCreateAssets() {
return canCreateAssets;
}
public void setCanCreateAssets(final boolean canCreateAssets) {
this.canCreateAssets = canCreateAssets;
}
public List<GrantedPrivilegeModel> getCurrentUserPermissions() {
return Collections.unmodifiableList(currentUserPermissions);
}
public void setCurrentUserPermissions(
final List<GrantedPrivilegeModel> currentUserPermissions
) {
this.currentUserPermissions = new ArrayList<>(currentUserPermissions);
}
public List<PrivilegesGrantedToRoleModel> getGrantedPermissions() {
return Collections.unmodifiableList(grantedPermissions);
}
public void setGrantedPermissions(
final List<PrivilegesGrantedToRoleModel> grantedPermissions
) {
this.grantedPermissions = new ArrayList<>(grantedPermissions);
}
public List<String> getPrivileges() {
return Collections.unmodifiableList(privileges);
}
public void setPrivileges(final List<String> privileges) {
this.privileges = new ArrayList<>(privileges);
}
}

View File

@ -0,0 +1,94 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.librecms.ui.contentsections;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class AssetFolderRowModel {
private boolean deletable;
private boolean folder;
private String folderPath;
private String name;
private boolean noneCmsObject;
private String title;
private String type;
private AssetPermissionsModel permissions;
public boolean isDeletable() {
return deletable;
}
public void setDeletable(final boolean deletable) {
this.deletable = deletable;
}
public boolean isFolder() {
return folder;
}
public void setFolder(final boolean folder) {
this.folder = folder;
}
public String getFolderPath() {
return folderPath;
}
public void setFolderPath(final String folderPath) {
this.folderPath = folderPath;
}
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
public boolean isNoneCmsObject() {
return noneCmsObject;
}
public void setNoneCmsObject(final boolean noneCmsObject) {
this.noneCmsObject = noneCmsObject;
}
public String getTitle() {
return title;
}
public void setTitle(final String title) {
this.title = title;
}
public String getType() {
return type;
}
public void setType(final String type) {
this.type = type;
}
public AssetPermissionsModel getPermissions() {
return permissions;
}
public void setPermissions(final AssetPermissionsModel permissions) {
this.permissions = permissions;
}
}

View File

@ -0,0 +1,40 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.librecms.ui.contentsections;
import org.librecms.contentsection.ContentSection;
import org.librecms.contentsection.Folder;
import javax.enterprise.context.Dependent;
import javax.inject.Inject;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@Dependent
public class AssetFolderTree
extends AbstractFolderTree<AssetFolderTreeNode, AssetPermissionsModel> {
@Inject
private AssetPermissions assetPermissions;
@Override
public AssetFolderTreeNode newFolderTreeNode() {
return new AssetFolderTreeNode();
}
@Override
public Folder getRootFolder(final ContentSection section) {
return section.getRootAssetsFolder();
}
@Override
public AssetPermissionsModel buildPermissionsModel(final Folder folder) {
return assetPermissions.buildAssetPermissionsModel(folder);
}
}

View File

@ -0,0 +1,15 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.librecms.ui.contentsections;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class AssetFolderTreeNode
extends FolderTreeNode<AssetFolderTreeNode, AssetPermissionsModel> {
}

View File

@ -0,0 +1,72 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.librecms.ui.contentsections;
import org.libreccm.security.PermissionChecker;
import org.librecms.contentsection.Asset;
import org.librecms.contentsection.Folder;
import org.librecms.contentsection.privileges.AssetPrivileges;
import javax.enterprise.context.Dependent;
import javax.inject.Inject;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@Dependent
class AssetPermissions {
@Inject
private PermissionChecker permissionChecker;
public AssetPermissionsModel buildAssetPermissionsModel(
final Folder folder
) {
final AssetPermissionsModel model = new AssetPermissionsModel();
model.setGrantedCreateNew(
permissionChecker.isPermitted(AssetPrivileges.CREATE_NEW, folder)
);
model.setGrantedDelete(
permissionChecker.isPermitted(AssetPrivileges.DELETE, folder)
);
model.setGrantedEdit(
permissionChecker.isPermitted(AssetPrivileges.EDIT, folder)
);
model.setGrantedUse(
permissionChecker.isPermitted(AssetPrivileges.USE, folder)
);
model.setGrantedView(
permissionChecker.isPermitted(AssetPrivileges.VIEW, folder)
);
return model;
}
public AssetPermissionsModel buildAssetPermissionsModel(
final Asset asset
) {
final AssetPermissionsModel model = new AssetPermissionsModel();
model.setGrantedCreateNew(
permissionChecker.isPermitted(AssetPrivileges.CREATE_NEW, asset)
);
model.setGrantedDelete(
permissionChecker.isPermitted(AssetPrivileges.DELETE, asset)
);
model.setGrantedEdit(
permissionChecker.isPermitted(AssetPrivileges.EDIT, asset)
);
model.setGrantedUse(
permissionChecker.isPermitted(AssetPrivileges.USE, asset)
);
model.setGrantedView(
permissionChecker.isPermitted(AssetPrivileges.VIEW, asset)
);
return model;
}
}

View File

@ -0,0 +1,64 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.librecms.ui.contentsections;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class AssetPermissionsModel implements PermissionsModel {
private boolean grantedCreateNew;
private boolean grantedDelete;
private boolean grantedUse;
private boolean grantedEdit;
private boolean grantedView;
public boolean isGrantedCreateNew() {
return grantedCreateNew;
}
public void setGrantedCreateNew(final boolean grantedCreateNew) {
this.grantedCreateNew = grantedCreateNew;
}
public boolean isGrantedDelete() {
return grantedDelete;
}
public void setGrantedDelete(final boolean grantedDelete) {
this.grantedDelete = grantedDelete;
}
public boolean isGrantedUse() {
return grantedUse;
}
public void setGrantedUse(final boolean grantedUse) {
this.grantedUse = grantedUse;
}
public boolean isGrantedEdit() {
return grantedEdit;
}
public void setGrantedEdit(final boolean grantedEdit) {
this.grantedEdit = grantedEdit;
}
public boolean isGrantedView() {
return grantedView;
}
public void setGrantedView(final boolean grantedView) {
this.grantedView = grantedView;
}
}

View File

@ -24,8 +24,9 @@ public class ContentSectionApplication extends Application {
public Set<Class<?>> getClasses() { public Set<Class<?>> getClasses() {
final Set<Class<?>> classes = new HashSet<>(); final Set<Class<?>> classes = new HashSet<>();
classes.add(IsAuthenticatedFilter.class); classes.add(AssetFolderController.class);
classes.add(DocumentFolderController.class); classes.add(DocumentFolderController.class);
classes.add(IsAuthenticatedFilter.class);
return classes; return classes;
} }

View File

@ -23,30 +23,44 @@ import javax.inject.Named;
@RequestScoped @RequestScoped
@Named("ContentSectionModel") @Named("ContentSectionModel")
public class ContentSectionModel { public class ContentSectionModel {
private ContentSection section; private ContentSection section;
private List<FolderTreeNode> folders; private List<AssetFolderTreeNode> assetFolders;
private List<DocumentFolderTreeNode> documentFolders;
protected void setSection(final ContentSection section) { protected void setSection(final ContentSection section) {
this.section = Objects.requireNonNull( this.section = Objects.requireNonNull(
section, "Parameter section can't be null" section, "Parameter section can't be null"
); );
} }
public String getSectionName() { public String getSectionName() {
return Optional return Optional
.ofNullable(section) .ofNullable(section)
.map(ContentSection::getLabel) .map(ContentSection::getLabel)
.orElse(""); .orElse("");
} }
public List<FolderTreeNode> getFolders() { public List<AssetFolderTreeNode> getAssetFolders() {
return Collections.unmodifiableList(folders); return Collections.unmodifiableList(assetFolders);
} }
protected void setFolders(final List<FolderTreeNode> folders) { protected void setAssetFolders(
this.folders = new ArrayList<>(folders); final List<AssetFolderTreeNode> assetFolders
) {
this.assetFolders = new ArrayList<>(assetFolders);
} }
public List<DocumentFolderTreeNode> getDocumentFolders() {
return Collections.unmodifiableList(documentFolders);
}
protected void setDocumentFolders(
final List<DocumentFolderTreeNode> documentFolders
) {
this.documentFolders = new ArrayList<>(documentFolders);
}
} }

View File

@ -0,0 +1,25 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.librecms.ui.contentsections;
import org.librecms.contentsection.privileges.AssetPrivileges;
import javax.enterprise.context.Dependent;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@Dependent
public class CurrentUserAssetPermissions
extends AbstractCurrentUserPermissions {
@Override
protected Class<?> getPrivilegesClass() {
return AssetPrivileges.class;
}
}

View File

@ -0,0 +1,25 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.librecms.ui.contentsections;
import org.librecms.contentsection.privileges.ItemPrivileges;
import javax.enterprise.context.Dependent;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@Dependent
public class CurrentUserDocumentPermissions
extends AbstractCurrentUserPermissions {
@Override
protected Class<?> getPrivilegesClass() {
return ItemPrivileges.class;
}
}

View File

@ -11,7 +11,6 @@ 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.security.AuthorizationRequired; import org.libreccm.security.AuthorizationRequired;
import org.libreccm.security.Permission;
import org.libreccm.security.PermissionChecker; 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;
@ -57,7 +56,6 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam; import javax.ws.rs.QueryParam;
import javax.ws.rs.FormParam; import javax.ws.rs.FormParam;
import javax.ws.rs.POST; import javax.ws.rs.POST;
@ -119,17 +117,29 @@ public class DocumentFolderController {
@Inject @Inject
private RoleRepository roleRepo; private RoleRepository roleRepo;
@Inject
private DocumentPermissions documentPermissions;
@Inject
private DocumentFolderTree documentFolderTree;
@Inject
private GrantedItemPrivileges grantedPrivileges;
@Inject
private CurrentUserDocumentPermissions currentUserPermissions;
@GET @GET
@Path("/") @Path("/")
@AuthorizationRequired @AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public String listItems( public String list(
@PathParam("sectionIdentifier") final String sectionIdentifier, @PathParam("sectionIdentifier") final String sectionIdentifier,
@QueryParam("filterTerm") @DefaultValue("") final String filterTerm, @QueryParam("filterTerm") @DefaultValue("") final String filterTerm,
@QueryParam("firstResult") @DefaultValue("0") final int firstResult, @QueryParam("firstResult") @DefaultValue("0") final int firstResult,
@QueryParam("maxResults") @DefaultValue("20") final int maxResults @QueryParam("maxResults") @DefaultValue("20") final int maxResults
) { ) {
return listItems( return list(
sectionIdentifier, "", filterTerm, firstResult, maxResults sectionIdentifier, "", filterTerm, firstResult, maxResults
); );
} }
@ -138,7 +148,7 @@ public class DocumentFolderController {
@Path("/{folderPath:(.+)?}") @Path("/{folderPath:(.+)?}")
@AuthorizationRequired @AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED) @Transactional(Transactional.TxType.REQUIRED)
public String listItems( public String list(
@PathParam("sectionIdentifier") final String sectionIdentifier, @PathParam("sectionIdentifier") final String sectionIdentifier,
@PathParam("folderPath") final String folderPath, @PathParam("folderPath") final String folderPath,
@QueryParam("filterTerm") @DefaultValue("") final String filterTerm, @QueryParam("filterTerm") @DefaultValue("") final String filterTerm,
@ -209,10 +219,9 @@ public class DocumentFolderController {
documentFolderModel.setFirstResult(firstResult); documentFolderModel.setFirstResult(firstResult);
documentFolderModel.setMaxResults(maxResults); documentFolderModel.setMaxResults(maxResults);
final List<FolderTreeNode> folderTree = buildFolderTree( contentSectionModel.setDocumentFolders(
section, folder documentFolderTree.buildFolderTree(section, folder)
); );
contentSectionModel.setFolders(folderTree);
documentFolderModel.setRows( documentFolderModel.setRows(
folderEntries folderEntries
@ -238,13 +247,13 @@ public class DocumentFolderController {
) )
); );
documentFolderModel.setGrantedPermissions( documentFolderModel.setGrantedPermissions(
buildPermissionsMatrix(section, folder) grantedPrivileges.buildPermissionsMatrix(section, folder)
); );
documentFolderModel.setPrivileges( documentFolderModel.setPrivileges(
permissionManager.listDefiniedPrivileges(ItemPrivileges.class) permissionManager.listDefiniedPrivileges(ItemPrivileges.class)
); );
documentFolderModel.setCurrentUserPermissions( documentFolderModel.setCurrentUserPermissions(
buildCurrentUserPermissions(folder) currentUserPermissions.buildCurrentUserPermissions(folder)
); );
return "org/librecms/ui/contentsection/documentfolder/documentfolder.xhtml"; return "org/librecms/ui/contentsection/documentfolder/documentfolder.xhtml";
@ -387,8 +396,11 @@ public class DocumentFolderController {
parentFolder = section.getRootDocumentsFolder(); parentFolder = section.getRootDocumentsFolder();
} else { } else {
final Optional<Folder> parentFolderResult = folderRepo final Optional<Folder> parentFolderResult = folderRepo
.findByPath(section, parentFolderPath, .findByPath(
FolderType.DOCUMENTS_FOLDER); section,
parentFolderPath,
FolderType.DOCUMENTS_FOLDER
);
if (parentFolderResult.isPresent()) { if (parentFolderResult.isPresent()) {
parentFolder = parentFolderResult.get(); parentFolder = parentFolderResult.get();
} else { } else {
@ -569,10 +581,10 @@ public class DocumentFolderController {
final String[] folderPathTokens = folderPath.split("/"); final String[] folderPathTokens = folderPath.split("/");
final String returnFolderPath = String.join( final String returnFolderPath = String.join(
"/", "/",
Arrays.copyOf(folderPathTokens, folderPathTokens.length - 1) Arrays.copyOf(folderPathTokens, folderPathTokens.length - 1)
); );
return String.format( return String.format(
"redirect:/%s/documentfolders/%s", "redirect:/%s/documentfolders/%s",
sectionIdentifier, sectionIdentifier,
@ -606,74 +618,10 @@ public class DocumentFolderController {
return sectionResult; return sectionResult;
} }
private List<FolderTreeNode> buildFolderTree( private List<FolderBreadcrumbsModel> buildBreadcrumbs(
final ContentSection section, final Folder currentFolder
) {
final Folder root = section.getRootDocumentsFolder();
final String currentFolderPath = folderManager
.getFolderPath(currentFolder)
.substring(
folderManager
.getFolderPath(section.getRootDocumentsFolder())
.length() - 1
);
return root
.getSubFolders()
.stream()
.sorted(
(folder1, folder2)
-> folder1.getName().compareTo(folder2.getName())
)
.map(folder -> buildFolderTreeNode(section, currentFolderPath,
folder))
.collect(Collectors.toList());
}
private FolderTreeNode buildFolderTreeNode(
final ContentSection section,
final String currentFolderPath,
final Folder folder
) {
final String folderPath = folderManager
.getFolderPath(folder)
.substring(
folderManager
.getFolderPath(section.getRootDocumentsFolder())
.length() - 1
);
final FolderTreeNode node = new FolderTreeNode();
node.setFolderId(folder.getObjectId());
node.setUuid(folder.getUuid());
node.setName(folder.getName());
node.setPath(folderPath);
node.setOpen(currentFolderPath.startsWith(folderPath));
node.setSelected(currentFolderPath.equals(folderPath));
node.setPermissions(buildItemPermissionsModel(folder));
node.setSubFolders(
folder
.getSubFolders()
.stream()
.sorted(
(folder1, folder2)
-> folder1.getName().compareTo(folder2.getName())
)
.map(
subFolder -> buildFolderTreeNode(
section, currentFolderPath, subFolder
)
)
.collect(Collectors.toList())
);
return node;
}
private List<DocumentFolderBreadcrumbModel> buildBreadcrumbs(
final String folderPath final String folderPath
) { ) {
final List<DocumentFolderBreadcrumbModel> breadcrumbs final List<FolderBreadcrumbsModel> breadcrumbs
= new ArrayList<>(); = new ArrayList<>();
final List<String> tokens = Arrays final List<String> tokens = Arrays
.stream(folderPath.split("/")) .stream(folderPath.split("/"))
@ -682,10 +630,10 @@ public class DocumentFolderController {
for (final String token : tokens) { for (final String token : tokens) {
final String path = breadcrumbs final String path = breadcrumbs
.stream() .stream()
.map(DocumentFolderBreadcrumbModel::getPathToken) .map(FolderBreadcrumbsModel::getPathToken)
.collect(Collectors.joining("/")); .collect(Collectors.joining("/"));
final DocumentFolderBreadcrumbModel breadcrumb final FolderBreadcrumbsModel breadcrumb
= new DocumentFolderBreadcrumbModel(); = new FolderBreadcrumbsModel();
breadcrumb.setPath(path); breadcrumb.setPath(path);
breadcrumb.setPathToken(token); breadcrumb.setPathToken(token);
breadcrumbs.add(breadcrumb); breadcrumbs.add(breadcrumb);
@ -737,7 +685,9 @@ public class DocumentFolderController {
"org.librecms.CmsAdminMessages" "org.librecms.CmsAdminMessages"
).getText("contentsection.documentfolder.types.folder") ).getText("contentsection.documentfolder.types.folder")
); );
row.setPermissions(buildItemPermissionsModel(folder)); row.setPermissions(
documentPermissions.buildDocumentPermissionsModel(folder)
);
} else { } else {
final ContentItem contentItem = itemRepo final ContentItem contentItem = itemRepo
.findById(entry.getEntryId()) .findById(entry.getEntryId())
@ -809,204 +759,12 @@ public class DocumentFolderController {
) )
).orElse("?") ).orElse("?")
); );
row.setPermissions(buildItemPermissionsModel(contentItem)); row.setPermissions(
documentPermissions.buildDocumentPermissionsModel(contentItem)
);
} }
return row; return row;
} }
private ItemPermissionsModel buildItemPermissionsModel(
final Folder folder
) {
final ItemPermissionsModel model = new ItemPermissionsModel();
model.setGrantedAdminister(
permissionChecker.isPermitted(
ItemPrivileges.ADMINISTER, folder
)
);
model.setGrantedApplyAlternateWorkflow(
permissionChecker.isPermitted(
ItemPrivileges.APPLY_ALTERNATE_WORKFLOW, folder
)
);
model.setGrantedApprove(
permissionChecker.isPermitted(
ItemPrivileges.APPROVE, folder
)
);
model.setGrantedCategorize(
permissionChecker.isPermitted(
ItemPrivileges.CATEGORIZE, folder
)
);
model.setGrantedCreateNew(
permissionChecker.isPermitted(
ItemPrivileges.CREATE_NEW, folder
)
);
model.setGrantedDelete(
permissionChecker.isPermitted(
ItemPrivileges.DELETE, folder
)
);
model.setGrantedEdit(
permissionChecker.isPermitted(
ItemPrivileges.EDIT, folder
)
);
model.setGrantedPreview(
permissionChecker.isPermitted(
ItemPrivileges.PREVIEW, folder
)
);
model.setGrantedPublish(
permissionChecker.isPermitted(
ItemPrivileges.PUBLISH, folder
)
);
model.setGrantedViewPublished(
permissionChecker.isPermitted(
ItemPrivileges.VIEW_PUBLISHED, folder
)
);
return model;
}
private ItemPermissionsModel buildItemPermissionsModel(
final ContentItem item
) {
final ItemPermissionsModel model = new ItemPermissionsModel();
model.setGrantedAdminister(
permissionChecker.isPermitted(
ItemPrivileges.ADMINISTER, item
)
);
model.setGrantedApplyAlternateWorkflow(
permissionChecker.isPermitted(
ItemPrivileges.APPLY_ALTERNATE_WORKFLOW, item
)
);
model.setGrantedApprove(
permissionChecker.isPermitted(
ItemPrivileges.APPROVE, item
)
);
model.setGrantedCategorize(
permissionChecker.isPermitted(
ItemPrivileges.CATEGORIZE, item
)
);
model.setGrantedCreateNew(
permissionChecker.isPermitted(
ItemPrivileges.CREATE_NEW, item
)
);
model.setGrantedDelete(
permissionChecker.isPermitted(
ItemPrivileges.DELETE, item
)
);
model.setGrantedEdit(
permissionChecker.isPermitted(
ItemPrivileges.EDIT, item
)
);
model.setGrantedPreview(
permissionChecker.isPermitted(
ItemPrivileges.PREVIEW, item
)
);
model.setGrantedPublish(
permissionChecker.isPermitted(
ItemPrivileges.PUBLISH, item
)
);
model.setGrantedViewPublished(
permissionChecker.isPermitted(
ItemPrivileges.VIEW_PUBLISHED, item
)
);
return model;
}
private List<PrivilegesGrantedToRoleModel> buildPermissionsMatrix(
final ContentSection section, final Folder folder
) {
return section
.getRoles()
.stream()
.map(role -> buildPrivilegesGrantedToRoleModel(role, folder))
.collect(Collectors.toList());
}
private PrivilegesGrantedToRoleModel buildPrivilegesGrantedToRoleModel(
final Role role, final Folder folder
) {
final List<GrantedPrivilegeModel> grantedPrivilges = permissionManager
.listDefiniedPrivileges(ItemPrivileges.class)
.stream()
.map(
privilege -> buildGrantedPrivilegeModel(
role,
folder,
privilege,
permissionManager.findPermissionsForRoleAndObject(
role, folder
)
)
)
.collect(Collectors.toList());
final PrivilegesGrantedToRoleModel model
= new PrivilegesGrantedToRoleModel();
model.setGrantedPrivileges(grantedPrivilges);
model.setGrantee(role.getName());
return model;
}
private GrantedPrivilegeModel buildGrantedPrivilegeModel(
final Role role,
final Folder folder,
final String privilege,
final List<Permission> permissions
) {
final GrantedPrivilegeModel model = new GrantedPrivilegeModel();
model.setGranted(permissionChecker.isPermitted(privilege, folder, role));
model.setInherited(
model.isGranted()
&& permissions
.stream()
.anyMatch(
permission
-> permission.getGrantee().equals(role)
&& permission.getGrantedPrivilege().equals(privilege)
&& permission.getObject().equals(folder)
&& permission.getInheritedFrom() != null
)
);
model.setPrivilege(privilege);
return model;
}
private List<GrantedPrivilegeModel> buildCurrentUserPermissions(
final Folder folder
) {
return permissionManager
.listDefiniedPrivileges(ItemPrivileges.class)
.stream()
.map(privilege -> buildCurrentUserPermission(folder, privilege))
.collect(Collectors.toList());
}
private GrantedPrivilegeModel buildCurrentUserPermission(
final Folder folder, final String privilege
) {
final GrantedPrivilegeModel model = new GrantedPrivilegeModel();
model.setPrivilege(privilege);
model.setGranted(permissionChecker.isPermitted(privilege, folder));
return model;
}
} }

View File

@ -29,7 +29,7 @@ public class DocumentFolderModel {
private List<DocumentFolderRowModel> rows; private List<DocumentFolderRowModel> rows;
private List<DocumentFolderBreadcrumbModel> breadcrumbs; private List<FolderBreadcrumbsModel> breadcrumbs;
private String path; private String path;
@ -85,12 +85,12 @@ public class DocumentFolderModel {
this.rows = new ArrayList<>(rows); this.rows = new ArrayList<>(rows);
} }
public List<DocumentFolderBreadcrumbModel> getBreadcrumbs() { public List<FolderBreadcrumbsModel> getBreadcrumbs() {
return Collections.unmodifiableList(breadcrumbs); return Collections.unmodifiableList(breadcrumbs);
} }
public void setBreadcrumbs( public void setBreadcrumbs(
final List<DocumentFolderBreadcrumbModel> breadcrumbs final List<FolderBreadcrumbsModel> breadcrumbs
) { ) {
this.breadcrumbs = new ArrayList<>(breadcrumbs); this.breadcrumbs = new ArrayList<>(breadcrumbs);
} }

View File

@ -36,7 +36,7 @@ public class DocumentFolderRowModel {
private String type; private String type;
private ItemPermissionsModel permissions; private DocumentPermissionsModel permissions;
public String getCreated() { public String getCreated() {
return created; return created;
@ -130,12 +130,12 @@ public class DocumentFolderRowModel {
this.type = type; this.type = type;
} }
public ItemPermissionsModel getPermissions() { public DocumentPermissionsModel getPermissions() {
return permissions; return permissions;
} }
protected void setPermissions( protected void setPermissions(
final ItemPermissionsModel permissions final DocumentPermissionsModel permissions
) { ) {
this.permissions = permissions; this.permissions = permissions;
} }

View File

@ -0,0 +1,44 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.librecms.ui.contentsections;
import org.librecms.contentsection.ContentSection;
import org.librecms.contentsection.Folder;
import javax.enterprise.context.Dependent;
import javax.inject.Inject;
import javax.transaction.Transactional;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@Dependent
public class DocumentFolderTree
extends AbstractFolderTree<DocumentFolderTreeNode, DocumentPermissionsModel>{
@Inject
private DocumentPermissions documentPermissions;
@Override
public DocumentFolderTreeNode newFolderTreeNode() {
return new DocumentFolderTreeNode();
}
@Transactional(Transactional.TxType.REQUIRED)
@Override
public Folder getRootFolder(final ContentSection section) {
return section.getRootDocumentsFolder();
}
@Override
public DocumentPermissionsModel buildPermissionsModel(final Folder folder) {
return documentPermissions.buildDocumentPermissionsModel(folder);
}
}

View File

@ -0,0 +1,15 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.librecms.ui.contentsections;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public class DocumentFolderTreeNode
extends FolderTreeNode<DocumentFolderTreeNode, DocumentPermissionsModel> {
}

View File

@ -0,0 +1,140 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.librecms.ui.contentsections;
import org.libreccm.security.PermissionChecker;
import org.librecms.contentsection.ContentItem;
import org.librecms.contentsection.Folder;
import org.librecms.contentsection.privileges.ItemPrivileges;
import javax.enterprise.context.Dependent;
import javax.inject.Inject;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@Dependent
class DocumentPermissions {
@Inject
private PermissionChecker permissionChecker;
public DocumentPermissionsModel buildDocumentPermissionsModel(
final Folder folder
) {
final DocumentPermissionsModel model = new DocumentPermissionsModel();
model.setGrantedAdminister(
permissionChecker.isPermitted(
ItemPrivileges.ADMINISTER, folder
)
);
model.setGrantedApplyAlternateWorkflow(
permissionChecker.isPermitted(
ItemPrivileges.APPLY_ALTERNATE_WORKFLOW, folder
)
);
model.setGrantedApprove(
permissionChecker.isPermitted(
ItemPrivileges.APPROVE, folder
)
);
model.setGrantedCategorize(
permissionChecker.isPermitted(
ItemPrivileges.CATEGORIZE, folder
)
);
model.setGrantedCreateNew(
permissionChecker.isPermitted(
ItemPrivileges.CREATE_NEW, folder
)
);
model.setGrantedDelete(
permissionChecker.isPermitted(
ItemPrivileges.DELETE, folder
)
);
model.setGrantedEdit(
permissionChecker.isPermitted(
ItemPrivileges.EDIT, folder
)
);
model.setGrantedPreview(
permissionChecker.isPermitted(
ItemPrivileges.PREVIEW, folder
)
);
model.setGrantedPublish(
permissionChecker.isPermitted(
ItemPrivileges.PUBLISH, folder
)
);
model.setGrantedViewPublished(
permissionChecker.isPermitted(
ItemPrivileges.VIEW_PUBLISHED, folder
)
);
return model;
}
public DocumentPermissionsModel buildDocumentPermissionsModel(
final ContentItem item
) {
final DocumentPermissionsModel model = new DocumentPermissionsModel();
model.setGrantedAdminister(
permissionChecker.isPermitted(
ItemPrivileges.ADMINISTER, item
)
);
model.setGrantedApplyAlternateWorkflow(
permissionChecker.isPermitted(
ItemPrivileges.APPLY_ALTERNATE_WORKFLOW, item
)
);
model.setGrantedApprove(
permissionChecker.isPermitted(
ItemPrivileges.APPROVE, item
)
);
model.setGrantedCategorize(
permissionChecker.isPermitted(
ItemPrivileges.CATEGORIZE, item
)
);
model.setGrantedCreateNew(
permissionChecker.isPermitted(
ItemPrivileges.CREATE_NEW, item
)
);
model.setGrantedDelete(
permissionChecker.isPermitted(
ItemPrivileges.DELETE, item
)
);
model.setGrantedEdit(
permissionChecker.isPermitted(
ItemPrivileges.EDIT, item
)
);
model.setGrantedPreview(
permissionChecker.isPermitted(
ItemPrivileges.PREVIEW, item
)
);
model.setGrantedPublish(
permissionChecker.isPermitted(
ItemPrivileges.PUBLISH, item
)
);
model.setGrantedViewPublished(
permissionChecker.isPermitted(
ItemPrivileges.VIEW_PUBLISHED, item
)
);
return model;
}
}

View File

@ -9,7 +9,7 @@ package org.librecms.ui.contentsections;
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
public class ItemPermissionsModel { public class DocumentPermissionsModel implements PermissionsModel {
private boolean grantedAdminister; private boolean grantedAdminister;

View File

@ -9,7 +9,7 @@ package org.librecms.ui.contentsections;
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/ */
public class DocumentFolderBreadcrumbModel { public class FolderBreadcrumbsModel {
private String pathToken; private String pathToken;

View File

@ -11,8 +11,10 @@ import java.util.List;
/** /**
* *
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a> * @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
* @param <T>
* @param <P>
*/ */
public class FolderTreeNode { public class FolderTreeNode<T extends FolderTreeNode, P extends PermissionsModel> {
private long folderId; private long folderId;
@ -22,13 +24,13 @@ public class FolderTreeNode {
private String path; private String path;
private List<FolderTreeNode> subFolders; private List<T> subFolders;
private boolean open; private boolean open;
private boolean selected; private boolean selected;
private ItemPermissionsModel permissions; private P permissions;
public long getFolderId() { public long getFolderId() {
return folderId; return folderId;
@ -62,11 +64,11 @@ public class FolderTreeNode {
this.path = path; this.path = path;
} }
public List<FolderTreeNode> getSubFolders() { public List<T> getSubFolders() {
return Collections.unmodifiableList(subFolders); return Collections.unmodifiableList(subFolders);
} }
public void setSubFolders(final List<FolderTreeNode> subFolders) { public void setSubFolders(final List<T> subFolders) {
this.subFolders = subFolders; this.subFolders = subFolders;
} }
@ -86,13 +88,11 @@ public class FolderTreeNode {
this.selected = selected; this.selected = selected;
} }
public ItemPermissionsModel getPermissions() { public P getPermissions() {
return permissions; return permissions;
} }
public void setPermissions( public void setPermissions(final P permissions) {
final ItemPermissionsModel permissions
) {
this.permissions = permissions; this.permissions = permissions;
} }

View File

@ -0,0 +1,24 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.librecms.ui.contentsections;
import org.librecms.contentsection.privileges.AssetPrivileges;
import javax.enterprise.context.Dependent;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@Dependent
public class GrantedAssetPrivileges extends AbstractGrantedPrivileges {
@Override
protected Class<?> getPrivilegesClass() {
return AssetPrivileges.class;
}
}

View File

@ -0,0 +1,24 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.librecms.ui.contentsections;
import org.librecms.contentsection.privileges.ItemPrivileges;
import javax.enterprise.context.Dependent;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@Dependent
public class GrantedItemPrivileges extends AbstractGrantedPrivileges {
@Override
protected Class<?> getPrivilegesClass() {
return ItemPrivileges.class;
}
}

View File

@ -0,0 +1,14 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.librecms.ui.contentsections;
/**
*
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
public interface PermissionsModel {
}

View File

@ -0,0 +1,27 @@
<!DOCTYPE html [<!ENTITY times '&#215;'>]>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:bootstrap="http://xmlns.jcp.org/jsf/composite/components/bootstrap"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:libreccm="http://xmlns.jcp.org/jsf/composite/components/libreccm"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<ui:composition template="/WEB-INF/views/org/librecms/ui/content-section/contentsection.xhtml">
<ui:param name="activePage" value="assetFolders" />
<ui:param name="title" value="#{CmsAdminMessages['contentsection.documentfolders.title']}" />
<ui:define name="breadcrumb">
<li class="breadcrumb-item">
#{CmsAdminMessages['contentsection.assetfolders.title']}
</li>
</ui:define>
<ui:define name="main">
<div class="container">
<div class="alert alert-warning">
#{CmsAdminMessages.getMessage("contentsections.assetfolders.not_found", [contentSection, folderPath])}
</div>
</div>
</ui:define>
</ui:composition>
</html>

View File

@ -78,7 +78,7 @@
</a> </a>
</h2> </h2>
<ul class="list-group"> <ul class="list-group">
<c:forEach items="#{ContentSectionModel.folders}" <c:forEach items="#{ContentSectionModel.documentFolders}"
var="folder"> var="folder">
<ui:include src="document-folder-tree-node.xhtml"> <ui:include src="document-folder-tree-node.xhtml">
<ui:param name="basePath" <ui:param name="basePath"