/*
* 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;
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.librecms.contentsection.ContentItem;
import org.librecms.contentsection.ContentItemL10NManager;
import org.librecms.contentsection.ContentItemManager;
import org.librecms.contentsection.ContentItemRepository;
import org.librecms.contentsection.ContentSection;
import org.librecms.contentsection.ContentSectionRepository;
import org.librecms.contentsection.ContentType;
import org.librecms.contentsection.ContentTypeManager;
import org.librecms.contentsection.ContentTypeRepository;
import org.librecms.contentsection.DocumentFolderEntry;
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.ItemPrivileges;
import org.librecms.contenttypes.Article;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import java.util.TreeSet;
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.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
/**
*
* @author Jens Pelzetter
*/
@RequestScoped
@Controller
@Path("/{sectionIdentifier}")
public class ContentSectionController {
private static final Logger LOGGER = LogManager.getLogger(
ContentSectionController.class
);
@Inject
private CmsAdminMessages cmsAdminMessages;
@Inject
private ContentItemManager itemManager;
@Inject
private ContentItemRepository itemRepo;
@Inject
private ContentItemL10NManager itemL10NManager;
@Inject
private ContentSectionModel contentSectionModel;
@Inject
private ContentTypeManager contentTypeManager;
@Inject
private ContentTypeRepository contentTypeRepo;
@Inject
private DocumentFolderModel documentFolderModel;
@Inject
private FolderManager folderManager;
@Inject
private FolderRepository folderRepo;
@Inject
private GlobalizationHelper globalizationHelper;
@Inject
private Models models;
@Inject
private ContentSectionRepository sectionRepo;
@Inject
private IdentifierParser identifierParser;
@Inject
private PermissionChecker permissionChecker;
@GET
@Path("/document-folders{folderPath:(/.+)?}")
@AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public String listItems(
@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 long start = System.currentTimeMillis();
final Identifier identifier = identifierParser.parseIdentifier(
sectionIdentifier
);
final Optional 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;
}
LOGGER.info("Retrieved content section in {} ms", System
.currentTimeMillis() - start);
if (sectionResult.isPresent()) {
final ContentSection section = sectionResult.get();
final long permissionCheckStart = System.currentTimeMillis();
if (permissionChecker.isPermitted(
ItemPrivileges.EDIT, section.getRootDocumentsFolder()
)) {
contentSectionModel.setSection(section);
LOGGER.info(
"Checked in permisisons in {} ms.",
System.currentTimeMillis() - permissionCheckStart
);
final Folder folder;
if (folderPath.isBlank()) {
folder = section.getRootDocumentsFolder();
documentFolderModel.setBreadcrumbs(Collections.emptyList());
} else {
final Optional folderResult = folderRepo
.findByPath(section,
folderPath,
FolderType.DOCUMENTS_FOLDER
);
if (folderResult.isPresent()) {
folder = folderResult.get();
final List breadcrumbs
= new ArrayList<>();
final List tokens = Arrays
.stream(folderPath.split("/"))
.filter(token -> !token.isEmpty())
.collect(Collectors.toList());
for (final String token : tokens) {
final String path = breadcrumbs
.stream()
.map(DocumentFolderBreadcrumbModel::getPathToken)
.collect(Collectors.joining("/"));
final DocumentFolderBreadcrumbModel breadcrumb
= new DocumentFolderBreadcrumbModel();
breadcrumb.setPath(path);
breadcrumb.setPathToken(token);
breadcrumbs.add(breadcrumb);
}
breadcrumbs
.get(breadcrumbs.size() - 1)
.setCurrentFolder(true);
documentFolderModel.setBreadcrumbs(breadcrumbs);
} else {
models.put("contentSection", section.getLabel());
models.put("folderPath", folderPath);
return "org/librecms/ui/content-section/document-folder-not-found.xhtml";
}
}
final long objectsStart = System.currentTimeMillis();
final List folderEntries = folderRepo
.getDocumentFolderEntries(
folder,
firstResult,
maxResults,
filterTerm
);
LOGGER.info(
"Retrieved objects in {} ms",
System.currentTimeMillis() - objectsStart
);
documentFolderModel.setCount(
folderRepo.countDocumentFolderEntries(folder, filterTerm)
);
documentFolderModel.setFirstResult(firstResult);
documentFolderModel.setMaxResults(maxResults);
LOGGER.info(
"Retrieved and counted objects in {} ms",
System.currentTimeMillis() - objectsStart
);
contentSectionModel.setFolders(buildFolderTree(section, folder));
final long rowsStart = System.currentTimeMillis();
documentFolderModel.setRows(
folderEntries
.stream()
.map(entry -> buildRowModel(section, entry))
.collect(Collectors.toList())
);
LOGGER.info(
"Build rows in {} ms.",
System.currentTimeMillis() - rowsStart
);
return "org/librecms/ui/content-section/document-folder.xhtml";
} else {
models.put("sectionidentifier", sectionIdentifier);
return "org/librecms/ui/content-section/access-denied.xhtml";
}
} else {
models.put("sectionIdentifier", sectionIdentifier);
return "org/librecms/ui/content-section/contentsection-not-found.xhtml";
}
}
@GET
@Path("/create-testdata")
@AuthorizationRequired
@Transactional(Transactional.TxType.REQUIRED)
public String createTestData(
@PathParam("sectionIdentifier") final String sectionIdentifier
) {
final Identifier identifier = identifierParser.parseIdentifier(
sectionIdentifier
);
final Optional 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();
if (permissionChecker.isPermitted(
ItemPrivileges.EDIT, section.getRootDocumentsFolder()
)) {
if (section.getRootDocumentsFolder().getObjects().isEmpty()) {
folderManager.createFolder(
"folder-1", section.getRootDocumentsFolder()
);
final Folder folder2 = folderManager.createFolder(
"folder-2", section.getRootDocumentsFolder()
);
folderManager.createFolder(
"folder-3", section.getRootDocumentsFolder()
);
final Article article = itemManager.createContentItem(
"test-article",
section,
section.getRootDocumentsFolder(),
Article.class,
Locale.ENGLISH
);
article.getTitle().addValue(Locale.ENGLISH, "Article 1");
article.getTitle().addValue(Locale.GERMAN, "Artikel 1");
itemRepo.save(article);
final Folder folder2a = folderManager.createFolder(
"folder-2a", folder2
);
final Article article2 = itemManager.createContentItem(
"test-article-in-folder-2",
section,
folder2,
Article.class,
Locale.ENGLISH
);
article2.getTitle().addValue(
Locale.ENGLISH, "Article in Folder 2"
);
article2.getTitle().addValue(
Locale.GERMAN, "Artikel in Ordner 2"
);
models.put(
"testdataMessage", "Test data created successfully."
);
return "org/librecms/ui/content-section/testdata.xhtml";
} else {
models.put(
"testdataMessage", "Test data was already created..."
);
return "org/librecms/ui/content-section/testdata.xhtml";
}
} else {
models.put("sectionidentifier", sectionIdentifier);
return "org/librecms/ui/content-section/access-denied.xhtml";
}
} else {
models.put("sectionIdentifier", sectionIdentifier);
return "org/librecms/ui/content-section/contentsection-not-found.xhtml";
}
}
private List buildFolderTree(
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()
.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.setOpen(currentFolderPath.startsWith(folderPath));
node.setSelected(currentFolderPath.equals(folderPath));
node.setSubFolders(
folder
.getSubFolders()
.stream()
.sorted()
.map(subFolder -> buildFolderTreeNode(section,
currentFolderPath,
subFolder))
.collect(Collectors.toList())
);
return node;
}
private DocumentFolderRowModel buildRowModel(
final ContentSection section, final DocumentFolderEntry entry
) {
Objects.requireNonNull(section);
Objects.requireNonNull(entry);
final DocumentFolderRowModel row = new DocumentFolderRowModel();
if (entry.isFolder()) {
final Folder folder = folderRepo
.findById(entry.getEntryId())
.get();
row.setCreated("");
row.setDeletable(
folderManager
.folderIsDeletable(folder)
== FolderManager.FolderIsDeletable.YES
);
row.setFolder(true);
row.setFolderPath(
folderManager
.getFolderPath(folder)
.substring(
folderManager
.getFolderPath(section.getRootDocumentsFolder())
.length()
)
);
row.setLanguages(Collections.emptySortedSet());
row.setLastEditPublished(false);
row.setLastEdited("");
row.setName(entry.getDisplayName());
row.setTitle(
globalizationHelper.getValueFromLocalizedString(
folder.getTitle()
)
);
row.setType(
globalizationHelper.getLocalizedTextsUtil(
"org.librecms.CmsAdminMessages"
).getText("contentsection.documentfolder.types.folder")
);
} else {
final ContentItem contentItem = itemRepo
.findById(entry.getEntryId())
.get();
row.setCreated(
DateTimeFormatter.ISO_DATE.format(
LocalDate.ofInstant(
contentItem.getCreationDate().toInstant(),
ZoneId.systemDefault()
)
)
);
row.setDeletable(!itemManager.isLive(contentItem));
row.setFolder(false);
row.setLanguages(
new TreeSet<>(
itemL10NManager
.availableLanguages(contentItem)
.stream()
.map(Locale::toString)
.collect(Collectors.toSet())
)
);
if (itemManager.isLive(contentItem)) {
final LocalDate draftLastModified = LocalDate.ofInstant(
contentItem.getLastModified().toInstant(),
ZoneId.systemDefault()
);
final LocalDate liveLastModified = LocalDate.ofInstant(
itemManager
.getLiveVersion(contentItem, contentItem.getClass())
.map(ContentItem::getLastModified)
.map(Date::toInstant)
.get(),
ZoneId.systemDefault()
);
row.setLastEditPublished(
liveLastModified.isBefore(draftLastModified)
);
} else {
row.setLastEditPublished(false);
}
row.setLastEdited(
DateTimeFormatter.ISO_DATE.format(
LocalDate.ofInstant(
contentItem.getLastModified().toInstant(),
ZoneId.systemDefault()
)
)
);
row.setName(entry.getDisplayName());
row.setNoneCmsObject(false);
row.setTitle(
globalizationHelper.getValueFromLocalizedString(
contentItem.getTitle()
)
);
row.setType(
contentTypeRepo
.findByContentSectionAndClass(section, contentItem
.getClass())
.map(ContentType::getLabel)
.map(
label -> globalizationHelper
.getValueFromLocalizedString(
label
)
).orElse("?")
);
}
return row;
}
// private DocumentFolderRowModel buildRowModel(
// final ContentSection section, final CcmObject object
// ) {
// Objects.requireNonNull(section);
// Objects.requireNonNull(object);
// if (object instanceof ContentItem) {
// return buildRowModel(section, (ContentItem) object);
// } else if (object instanceof Folder) {
// return buildRowModel(section, (Folder) object);
// } else {
// final DocumentFolderRowModel row = new DocumentFolderRowModel();
//
// row.setCreated("");
// row.setDeletable(false);
// row.setIsFolder(false);
// row.setLanguages(Collections.emptySortedSet());
// row.setLastEditPublished(false);
// row.setLastEdited("");
// row.setName(object.getDisplayName());
// row.setTitle("");
// row.setType(object.getClass().getSimpleName());
//
// return row;
// }
// }
//
// private DocumentFolderRowModel buildRowModel(
// final ContentSection section, final ContentItem contentItem
// ) {
// Objects.requireNonNull(section);
// Objects.requireNonNull(contentItem);
//
// final DocumentFolderRowModel row = new DocumentFolderRowModel();
// row.setCreated(
// DateTimeFormatter.ISO_DATE.format(
// LocalDate.ofInstant(
// contentItem.getCreationDate().toInstant(),
// ZoneId.systemDefault()
// )
// )
// );
// row.setDeletable(!itemManager.isLive(contentItem));
// row.setIsFolder(false);
// row.setLanguages(
// new TreeSet<>(
// itemL10NManager
// .availableLanguages(contentItem)
// .stream()
// .map(Locale::toString)
// .collect(Collectors.toSet())
// )
// );
// if (itemManager.isLive(contentItem)) {
// final LocalDate draftLastModified = LocalDate.ofInstant(
// contentItem.getLastModified().toInstant(),
// ZoneId.systemDefault()
// );
// final LocalDate liveLastModified = LocalDate.ofInstant(
// itemManager
// .getLiveVersion(contentItem, contentItem.getClass())
// .map(ContentItem::getLastModified)
// .map(Date::toInstant)
// .get(),
// ZoneId.systemDefault()
// );
// row.setLastEditPublished(
// liveLastModified.isBefore(draftLastModified)
// );
//
// } else {
// row.setLastEditPublished(false);
// }
//
// row.setLastEdited(
// DateTimeFormatter.ISO_DATE.format(
// LocalDate.ofInstant(
// contentItem.getLastModified().toInstant(),
// ZoneId.systemDefault()
// )
// )
// );
// row.setName(contentItem.getDisplayName());
// row.setNoneCmsObject(false);
// row.setTitle(
// globalizationHelper.getValueFromLocalizedString(
// contentItem.getTitle()
// )
// );
// row.setType(
// contentTypeRepo
// .findByContentSectionAndClass(section, contentItem.getClass())
// .map(ContentType::getLabel)
// .map(
// label -> globalizationHelper.getValueFromLocalizedString(
// label
// )
// ).orElse("?")
// );
//
// return row;
// }
//
// private DocumentFolderRowModel buildRowModel(
// final ContentSection section, final Folder folder
// ) {
// Objects.requireNonNull(section);
// Objects.requireNonNull(folder);
//
// final DocumentFolderRowModel row = new DocumentFolderRowModel();
// row.setCreated("");
// row.setDeletable(
// folderManager.folderIsDeletable(folder)
// == FolderManager.FolderIsDeletable.YES
// );
// row.setIsFolder(true);
// row.setLanguages(Collections.emptySortedSet());
// row.setLastEditPublished(false);
// row.setLastEdited("");
// row.setName(folder.getDisplayName());
// row.setNoneCmsObject(false);
// row.setTitle(
// globalizationHelper.getValueFromLocalizedString(folder.getTitle())
// );
// row.setType(
// globalizationHelper.getLocalizedTextsUtil(
// "org.librecms.CmsAdminMessages"
// ).getText("contentsection.documentfolder.types.folder")
// );
//
// return row;
// }
}