CCM NG:
- Additional methods and implementations of ContentItemManager (not tested yet!) - Refactored several UI classes to work with CCM NG, primarly in ccm-cms/com.arsdigita.cms.ui.folder git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@4231 8810af33-2d31-482b-a856-94f89814c4dfpull/2/head
parent
0838a6df5f
commit
e6b3630786
|
|
@ -29,21 +29,24 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* <p>The <tt>ItemResolver</tt> is responsible for mapping a URL in a
|
||||
* particular content section to a content item.</p>
|
||||
* <p>
|
||||
* The <tt>ItemResolver</tt> is responsible for mapping a URL in a particular
|
||||
* content section to a content item.</p>
|
||||
*
|
||||
* <p>As an example, here is the item resolution process for a request to
|
||||
* <p>
|
||||
* As an example, here is the item resolution process for a request to
|
||||
* <tt>http://yourserver/cms/cheese</tt>:</p>
|
||||
*
|
||||
* <p>The item resolver would be asked to map the URL stub <tt>/cheese</tt>
|
||||
* in the content section mounted at <tt>/cms</tt> to a content item. To
|
||||
* this end, the dispatcher calls the <tt>getItem</tt> method, passing in
|
||||
* the {@link com.arsdigita.cms.ContentSection} and the URL stub for the
|
||||
* item within the section, <tt>/cheese</tt> in our example. As a final
|
||||
* argument, the dispatcher passes either <tt>ContentItem.DRAFT</tt> or
|
||||
* <tt>ContentItem.LIVE</tt> to the <tt>ItemResolver</tt>, depending on
|
||||
* whether the returned item should be the live version (for public pages)
|
||||
* or the draft version (for previewing).</p>
|
||||
* <p>
|
||||
* The item resolver would be asked to map the URL stub <tt>/cheese</tt>
|
||||
* in the content section mounted at <tt>/cms</tt> to a content item. To this
|
||||
* end, the dispatcher calls the <tt>getItem</tt> method, passing in the
|
||||
* {@link com.arsdigita.cms.ContentSection} and the URL stub for the item within
|
||||
* the section, <tt>/cheese</tt> in our example. As a final argument, the
|
||||
* dispatcher passes either <tt>ContentItem.DRAFT</tt> or
|
||||
* <tt>ContentItem.LIVE</tt> to the <tt>ItemResolver</tt>, depending on whether
|
||||
* the returned item should be the live version (for public pages) or the draft
|
||||
* version (for previewing).</p>
|
||||
*
|
||||
* @author Michael Pih (pihman@arsdigita.com)
|
||||
* @author Stanislav Freidin (sfreidin@arsdigita.com)
|
||||
|
|
@ -60,7 +63,8 @@ public interface ItemResolver {
|
|||
* @param context The use context
|
||||
* @return The content item, or null if no such item exists
|
||||
*/
|
||||
public ContentItem getItem(ContentSection section, String url,
|
||||
public ContentItem getItem(ContentSection section,
|
||||
String url,
|
||||
String context);
|
||||
|
||||
/**
|
||||
|
|
@ -82,10 +86,11 @@ public interface ItemResolver {
|
|||
* @return The URL of the item
|
||||
* @see #getCurrentContext
|
||||
*/
|
||||
public String generateItemURL (
|
||||
PageState state, BigDecimal itemId, String name,
|
||||
ContentSection section, String context
|
||||
);
|
||||
public String generateItemURL(PageState state,
|
||||
Long itemId,
|
||||
String name,
|
||||
ContentSection section,
|
||||
String context);
|
||||
|
||||
/**
|
||||
* Generates a URL for a content item.
|
||||
|
|
@ -99,10 +104,13 @@ public interface ItemResolver {
|
|||
* @return The URL of the item
|
||||
* @see #getCurrentContext
|
||||
*/
|
||||
public String generateItemURL (
|
||||
PageState state, BigDecimal itemId, String name,
|
||||
ContentSection section, String context, String templateContext
|
||||
);
|
||||
public String generateItemURL(PageState state,
|
||||
Long itemId,
|
||||
String name,
|
||||
ContentSection section,
|
||||
String context,
|
||||
String templateContext
|
||||
);
|
||||
|
||||
/**
|
||||
* Generates a URL for a content item.
|
||||
|
|
@ -114,9 +122,10 @@ public interface ItemResolver {
|
|||
* @return The URL of the item
|
||||
* @see #getCurrentContext
|
||||
*/
|
||||
public String generateItemURL (
|
||||
PageState state, ContentItem item, ContentSection section, String context
|
||||
);
|
||||
public String generateItemURL(PageState state,
|
||||
ContentItem item,
|
||||
ContentSection section,
|
||||
String context);
|
||||
|
||||
/**
|
||||
* Generates a URL for a content item.
|
||||
|
|
@ -129,21 +138,22 @@ public interface ItemResolver {
|
|||
* @return The URL of the item
|
||||
* @see #getCurrentContext
|
||||
*/
|
||||
public String generateItemURL (
|
||||
PageState state, ContentItem item, ContentSection section, String context,
|
||||
String templateContext
|
||||
);
|
||||
public String generateItemURL(PageState state,
|
||||
ContentItem item,
|
||||
ContentSection section,
|
||||
String context,
|
||||
String templateContext);
|
||||
|
||||
/**
|
||||
* Return a master page based on page state (and content section).
|
||||
*
|
||||
* @param item The content item
|
||||
* @param item The content item
|
||||
* @param request The HTTP request
|
||||
* @return The master page
|
||||
*/
|
||||
public CMSPage getMasterPage(ContentItem item, HttpServletRequest request)
|
||||
throws ServletException;
|
||||
|
||||
throws ServletException;
|
||||
|
||||
|
||||
/*
|
||||
* Having to stick the following methods, getTemplateFromURL, and
|
||||
|
|
@ -152,16 +162,16 @@ public interface ItemResolver {
|
|||
* to be cleaned up to fix this. As it is, ItemResolver parses URL's for
|
||||
* template contexts, and TemplateResolver sets the actual template contexts
|
||||
* in the request.
|
||||
*/
|
||||
|
||||
*/
|
||||
/**
|
||||
* Finds the template context from the URL and returns it, if it is there.
|
||||
* Otherwise, returns null.
|
||||
*
|
||||
* @param inUrl the URL from which to get the template context
|
||||
* @return the template context, or null if there is no template context
|
||||
*/
|
||||
public String getTemplateFromURL(String inUrl);
|
||||
|
||||
*/
|
||||
public String getTemplateFromURL(String inUrl);
|
||||
|
||||
/**
|
||||
* Removes the template context from the <code>inUrl</code>.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,881 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui.folder;
|
||||
|
||||
import com.arsdigita.bebop.Component;
|
||||
import com.arsdigita.bebop.ControlLink;
|
||||
import com.arsdigita.bebop.Image;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.Link;
|
||||
import com.arsdigita.bebop.Page;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.PaginationModelBuilder;
|
||||
import com.arsdigita.bebop.Paginator;
|
||||
import com.arsdigita.bebop.SimpleContainer;
|
||||
import com.arsdigita.bebop.Table;
|
||||
import com.arsdigita.bebop.event.ActionEvent;
|
||||
import com.arsdigita.bebop.event.ActionListener;
|
||||
import com.arsdigita.bebop.event.TableActionAdapter;
|
||||
import com.arsdigita.bebop.event.TableActionEvent;
|
||||
import com.arsdigita.bebop.event.TableActionListener;
|
||||
import com.arsdigita.bebop.parameters.StringParameter;
|
||||
import com.arsdigita.bebop.table.AbstractTableModelBuilder;
|
||||
import com.arsdigita.bebop.table.DefaultTableCellRenderer;
|
||||
import com.arsdigita.bebop.table.DefaultTableColumnModel;
|
||||
import com.arsdigita.bebop.table.TableCellRenderer;
|
||||
import com.arsdigita.bebop.table.TableColumn;
|
||||
import com.arsdigita.bebop.table.TableHeader;
|
||||
import com.arsdigita.bebop.table.TableModel;
|
||||
import com.arsdigita.cms.*;
|
||||
import com.arsdigita.cms.dispatcher.ItemResolver;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
import com.arsdigita.kernel.KernelConfig;
|
||||
import com.arsdigita.toolbox.ui.FormatStandards;
|
||||
import com.arsdigita.util.Assert;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.libreccm.auditing.CcmRevision;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.libreccm.categorization.Categorization;
|
||||
import org.libreccm.categorization.Category;
|
||||
import org.libreccm.categorization.CategoryManager;
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.configuration.ConfigurationManager;
|
||||
import org.libreccm.core.CcmObject;
|
||||
import org.libreccm.security.PermissionChecker;
|
||||
import org.librecms.CmsConstants;
|
||||
import org.librecms.contentsection.ContentItem;
|
||||
import org.librecms.contentsection.ContentItemManager;
|
||||
import org.librecms.contentsection.ContentItemRepository;
|
||||
import org.librecms.contentsection.ContentSection;
|
||||
import org.librecms.contentsection.ContentSectionManager;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Browse folders and items. If the user clicks on a folder, the folder
|
||||
* selection model is updated. If the user clicks on any other item, an separate
|
||||
* item selection model is updated.
|
||||
*
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
* @author <a href="mailto:quasi@quasiweb.de">Sören Bernstein</a>
|
||||
* @author <a href="mailto:lutter@arsdigita.com">David Lutterkort</a>
|
||||
*/
|
||||
public class FolderBrowser extends Table {
|
||||
|
||||
private static final Logger s_log = Logger.getLogger(FolderBrowser.class);
|
||||
private static GlobalizedMessage[] s_headers = {
|
||||
globalize("cms.ui.folder.name"),
|
||||
globalize("cms.ui.folder.languages"),
|
||||
globalize("cms.ui.folder.title"),
|
||||
globalize("cms.ui.folder.additionalInfo"),
|
||||
globalize("cms.ui.folder.type"),
|
||||
globalize("cms.ui.folder.creation_date"),
|
||||
globalize("cms.ui.folder.last_modified"),
|
||||
globalize("cms.ui.folder.action"),
|
||||
globalize("cms.ui.folder.index")};
|
||||
private static GlobalizedMessage[] s_noIndexHeaders = {
|
||||
globalize("cms.ui.folder.name"),
|
||||
globalize("cms.ui.folder.languages"),
|
||||
globalize("cms.ui.folder.title"),
|
||||
globalize("cms.ui.folder.additionalInfo"),
|
||||
globalize("cms.ui.folder.type"),
|
||||
globalize("cms.ui.folder.creation_date"),
|
||||
globalize("cms.ui.folder.last_modified"),
|
||||
globalize("cms.ui.folder.action")};
|
||||
private static final String SORT_ACTION_UP = "sortActionUp";
|
||||
private static final String SORT_ACTION_DOWN = "sortActionDown";
|
||||
private FolderSelectionModel m_currentFolder;
|
||||
private TableActionListener m_folderChanger;
|
||||
private TableActionListener m_deleter;
|
||||
private TableActionListener m_indexChanger;
|
||||
private TableColumn m_nameColumn;
|
||||
private TableColumn m_deleteColumn;
|
||||
private TableColumn m_indexColumn;
|
||||
private final static String SORT_KEY_NAME = "name";
|
||||
private final static String SORT_KEY_TITLE = "title";
|
||||
private final static String SORT_KEY_LAST_MODIFIED_DATE = "lastModified";
|
||||
private final static String SORT_KEY_CREATION_DATE = "creationDate";
|
||||
private StringParameter m_sortType = new StringParameter("sortType");
|
||||
private StringParameter m_sortDirection = new StringParameter("sortDirn");
|
||||
private StringParameter m_aToZfilter = null;
|
||||
private StringParameter m_filter = null;
|
||||
private FolderManipulator.FilterForm m_filterForm;
|
||||
private long m_folderSize;
|
||||
|
||||
public FolderBrowser(FolderSelectionModel currentFolder) {
|
||||
//super(new FolderTableModelBuilder(), s_headers);
|
||||
super();
|
||||
m_sortType.setDefaultValue(SORT_KEY_NAME);
|
||||
m_sortDirection.setDefaultValue(SORT_ACTION_UP);
|
||||
|
||||
setModelBuilder(new FolderTableModelBuilder(currentFolder));
|
||||
setColumnModel(new DefaultTableColumnModel(hideIndexColumn()
|
||||
? s_noIndexHeaders
|
||||
: s_headers));
|
||||
setHeader(new TableHeader(getColumnModel()));
|
||||
|
||||
m_currentFolder = currentFolder;
|
||||
|
||||
/*
|
||||
*
|
||||
* This code should be uncommented if the desired behaviour is for a
|
||||
* change of folder to cause reversion to default ordering of contained
|
||||
* items (by name ascending). Our feeling is that the user selected
|
||||
* ordering should be retained for the duration of the folder browsing
|
||||
* session. If anyone wants this alternative behaviour it should be
|
||||
* brought in under the control of a config parameter.
|
||||
*
|
||||
* m_currentFolder.addChangeListener(new ChangeListener() {
|
||||
*
|
||||
* public void stateChanged(ChangeEvent e) { PageState state =
|
||||
* e.getPageState(); state.setValue(m_sortType,
|
||||
* m_sortType.getDefaultValue()); state.setValue(m_sortDirection,
|
||||
* m_sortDirection.getDefaultValue());
|
||||
*
|
||||
* }});
|
||||
*/
|
||||
setClassAttr("dataTable");
|
||||
|
||||
getHeader().setDefaultRenderer(
|
||||
new com.arsdigita.cms.ui.util.DefaultTableCellRenderer());
|
||||
|
||||
m_nameColumn = getColumn(0);
|
||||
m_nameColumn.setCellRenderer(new NameCellRenderer());
|
||||
m_nameColumn.setHeaderRenderer(new HeaderCellRenderer(SORT_KEY_NAME));
|
||||
getColumn(1).setCellRenderer(new LanguagesCellRenderer());
|
||||
getColumn(2).setHeaderRenderer(new HeaderCellRenderer(SORT_KEY_TITLE));
|
||||
getColumn(5).setHeaderRenderer(new HeaderCellRenderer(
|
||||
SORT_KEY_CREATION_DATE));
|
||||
getColumn(6).setHeaderRenderer(new HeaderCellRenderer(
|
||||
SORT_KEY_LAST_MODIFIED_DATE));
|
||||
m_deleteColumn = getColumn(7);
|
||||
m_deleteColumn.setCellRenderer(new ActionCellRenderer());
|
||||
m_deleteColumn.setAlign("center");
|
||||
m_folderChanger = new FolderChanger();
|
||||
addTableActionListener(m_folderChanger);
|
||||
|
||||
m_deleter = new ItemDeleter();
|
||||
addTableActionListener(m_deleter);
|
||||
|
||||
setEmptyView(new Label(globalize("cms.ui.folder.no_items")));
|
||||
|
||||
Assert.exists(m_currentFolder.getStateParameter());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(Page p) {
|
||||
super.register(p);
|
||||
|
||||
p.addComponentStateParam(this, m_currentFolder.getStateParameter());
|
||||
p.addComponentStateParam(this, m_sortType);
|
||||
p.addComponentStateParam(this, m_sortDirection);
|
||||
p.addActionListener(new ActionListener() {
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
final PageState state = e.getPageState();
|
||||
|
||||
if (state.isVisibleOnPage(FolderBrowser.this)) {
|
||||
showHideFolderActions(state);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private void showHideFolderActions(PageState state) {
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final PermissionChecker permissionChecker = cdiUtil.findBean(
|
||||
PermissionChecker.class);
|
||||
Category folder = (Category) m_currentFolder.getSelectedObject(state);
|
||||
Assert.exists(folder);
|
||||
|
||||
final boolean canDelete = permissionChecker.isPermitted(
|
||||
CmsConstants.PRIVILEGE_ITEMS_DELETE, folder);
|
||||
m_deleteColumn.setVisible(state, canDelete);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void respond(PageState state) throws ServletException {
|
||||
String key = state.getControlEventName();
|
||||
String value = state.getControlEventValue();
|
||||
if (SORT_ACTION_UP.equals(key)) {
|
||||
state.setValue(m_sortType, value);
|
||||
state.setValue(m_sortDirection, SORT_ACTION_UP);
|
||||
} else if (SORT_ACTION_DOWN.equals(key)) {
|
||||
state.setValue(m_sortType, value);
|
||||
state.setValue(m_sortDirection, SORT_ACTION_DOWN);
|
||||
} else {
|
||||
super.respond(state);
|
||||
//throw new ServletException("Unknown control event: " + key);
|
||||
}
|
||||
}
|
||||
|
||||
public FolderSelectionModel getFolderSelectionModel() {
|
||||
return m_currentFolder;
|
||||
}
|
||||
|
||||
protected void setFilterForm(FolderManipulator.FilterForm filterForm) {
|
||||
m_filterForm = filterForm;
|
||||
}
|
||||
|
||||
protected void setAtoZfilterParameter(StringParameter aToZfilter) {
|
||||
m_aToZfilter = aToZfilter;
|
||||
}
|
||||
|
||||
protected void setFilterParameter(StringParameter filter) {
|
||||
m_filter = filter;
|
||||
}
|
||||
|
||||
protected long getFolderSize() {
|
||||
return m_folderSize;
|
||||
}
|
||||
|
||||
private class FolderTableModelBuilder
|
||||
extends AbstractTableModelBuilder
|
||||
implements PaginationModelBuilder,
|
||||
FolderManipulator.FilterFormModelBuilder {
|
||||
|
||||
private final FolderSelectionModel folderModel;
|
||||
private final FolderBrowser folderBrowser;
|
||||
private final ContentItemRepository itemRepo;
|
||||
private final ConfigurationManager confManager;
|
||||
private final ContentSectionManager sectionManager;
|
||||
|
||||
public FolderTableModelBuilder(final FolderSelectionModel folderModel) {
|
||||
this(folderModel, null);
|
||||
}
|
||||
|
||||
public FolderTableModelBuilder(final FolderSelectionModel folderModel,
|
||||
final FolderBrowser folderBrowser) {
|
||||
this.folderModel = folderModel;
|
||||
this.folderBrowser = folderBrowser;
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
itemRepo = cdiUtil.findBean(ContentItemRepository.class);
|
||||
confManager = cdiUtil.findBean(ConfigurationManager.class);
|
||||
sectionManager = cdiUtil.findBean(ContentSectionManager.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableModel makeModel(final Table table, final PageState state) {
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTotalSize(final Paginator paginator,
|
||||
final PageState state) {
|
||||
final Category folder = (Category) folderModel.getSelectedObject(
|
||||
state);
|
||||
|
||||
|
||||
/*
|
||||
SELECT c.categorizedObject FROM Categorization c "
|
||||
+ "WHERE c.category = :folder "
|
||||
+ "AND TYPE(c.categorizedObject) IN ContentItem"
|
||||
+ "AND (LOWER(c.categorizationObject.displayName) LIKE CONCAT(LOWER(:name), '%') "
|
||||
44+ "OR LOWER(c.categorizedObject.name.value) LIKE CONCAT(:name), '%')
|
||||
*/
|
||||
final CriteriaBuilder criteriaBuilder = itemRepo.
|
||||
getCriteriaBuilder();
|
||||
final CriteriaQuery<ContentItem> query = criteriaBuilder.
|
||||
createQuery(ContentItem.class);
|
||||
final Root<Categorization> root = query.from(Categorization.class);
|
||||
final Root<ContentItem> itemRoot = query.from(ContentItem.class);
|
||||
//final List<Predicate> predicates = new ArrayList<>();
|
||||
final Predicate categoryPredicate = criteriaBuilder.equal(
|
||||
root.get("Categorization.category"), folder);
|
||||
final Predicate typePredicate = criteriaBuilder.equal(
|
||||
itemRoot.type(), ContentItem.class);
|
||||
final List<Predicate> filters = new ArrayList<>();
|
||||
final KernelConfig kernelConfig = confManager.findConfiguration(
|
||||
KernelConfig.class);
|
||||
final Locale defaultLocale = new Locale(kernelConfig.
|
||||
getDefaultLanguage());
|
||||
if (state.getValue(m_aToZfilter) != null) {
|
||||
filters.add(criteriaBuilder.like(criteriaBuilder.lower(
|
||||
root.get("Categorization.categorizedObject.displayName")),
|
||||
String.format("%s%%",
|
||||
((String) state.
|
||||
getValue(
|
||||
m_aToZfilter)).
|
||||
toLowerCase(
|
||||
defaultLocale))));
|
||||
filters.add(criteriaBuilder.like(criteriaBuilder.lower(
|
||||
root.get("Categorization.categoriziedObject.name.value")),
|
||||
String.format("%s%%",
|
||||
(String) state.
|
||||
getValue(
|
||||
m_aToZfilter))
|
||||
.toLowerCase(defaultLocale)));
|
||||
}
|
||||
|
||||
if (state.getValue(m_filter) != null) {
|
||||
filters.add(criteriaBuilder.like(criteriaBuilder.lower(
|
||||
root.get("Categorization.categorizedObject.displayName")),
|
||||
String.format("%s%%",
|
||||
((String) state.
|
||||
getValue(
|
||||
m_filter)))));
|
||||
filters.add(criteriaBuilder.like(criteriaBuilder.lower(
|
||||
root.get("Categorization.categorizedObject.name.value")),
|
||||
String.format("%s%%",
|
||||
((String) state.
|
||||
getValue(
|
||||
m_filter)))));
|
||||
}
|
||||
|
||||
final Predicate filtersPredicate = criteriaBuilder.or(filters.
|
||||
toArray(new Predicate[filters.size()]));
|
||||
final Predicate predicates = criteriaBuilder.and(categoryPredicate,
|
||||
typePredicate,
|
||||
filtersPredicate);
|
||||
|
||||
query.where(predicates).select(itemRoot);
|
||||
|
||||
return itemRepo.executeCriteriaQuery(query.where(predicates).select(
|
||||
itemRoot)).size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisible(final PageState state) {
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFolderSize(final PageState state) {
|
||||
return itemRepo.countItemsInFolder((Category) folderModel.
|
||||
getSelectedObject(state));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class HeaderCellRenderer
|
||||
extends com.arsdigita.cms.ui.util.DefaultTableCellRenderer {
|
||||
|
||||
private String m_key;
|
||||
|
||||
public HeaderCellRenderer(String key) {
|
||||
super(true);
|
||||
m_key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getComponent(final Table table, final PageState state,
|
||||
Object value,
|
||||
boolean isSelected, Object key,
|
||||
int row, int column) {
|
||||
String headerName = (String) ((GlobalizedMessage) value).localize();
|
||||
String sortKey = (String) state.getValue(m_sortType);
|
||||
final boolean isCurrentKey = sortKey.equals(m_key);
|
||||
final String currentSortDirection = (String) state.getValue(
|
||||
m_sortDirection);
|
||||
String imageURLStub;
|
||||
|
||||
if (SORT_ACTION_UP.equals(currentSortDirection)) {
|
||||
imageURLStub = "gray-triangle-up.gif";
|
||||
} else {
|
||||
imageURLStub = "gray-triangle-down.gif";
|
||||
}
|
||||
|
||||
ControlLink cl = new ControlLink(headerName) {
|
||||
|
||||
@Override
|
||||
public void setControlEvent(PageState ps) {
|
||||
String sortDirectionAction;
|
||||
// by default, everything sorts "up" unless it
|
||||
// is the current key and it is already pointing up
|
||||
if (SORT_ACTION_UP.equals(currentSortDirection)
|
||||
&& isCurrentKey) {
|
||||
sortDirectionAction = SORT_ACTION_DOWN;
|
||||
} else {
|
||||
sortDirectionAction = SORT_ACTION_UP;
|
||||
}
|
||||
ps.setControlEvent(table,
|
||||
sortDirectionAction,
|
||||
m_key);
|
||||
}
|
||||
|
||||
};
|
||||
Label l = new Label();
|
||||
l.setLabel(headerName);
|
||||
l.setClassAttr("folderBrowserLink");
|
||||
l.setOutputEscaping(false);
|
||||
l.setFontWeight(Label.BOLD);
|
||||
|
||||
SimpleContainer container = new SimpleContainer();
|
||||
container.add(l);
|
||||
if (isCurrentKey) {
|
||||
Image image = new Image("/assets/" + imageURLStub);
|
||||
image.setBorder("0");
|
||||
container.add(image);
|
||||
}
|
||||
cl.setChild(container);
|
||||
return cl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce links to view an item or control links for folders to change into
|
||||
* the folder.
|
||||
*/
|
||||
private class NameCellRenderer extends DefaultTableCellRenderer {
|
||||
|
||||
public NameCellRenderer() {
|
||||
super(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getComponent(Table table,
|
||||
PageState state,
|
||||
Object value,
|
||||
boolean isSelected,
|
||||
Object key,
|
||||
int row,
|
||||
int column) {
|
||||
|
||||
final ContentItem item = (ContentItem) value;
|
||||
String name = item.getDisplayName();
|
||||
// final ContentSection section = item.getContentType().
|
||||
// getContentSection();
|
||||
final ContentSection section = CMS.getContext().getContentSection();
|
||||
final ContentSectionManager sectionManager = CdiUtil.createCdiUtil()
|
||||
.findBean(ContentSectionManager.class);
|
||||
final ItemResolver itemResolver = sectionManager.getItemResolver(
|
||||
section);
|
||||
|
||||
return new Link(name,
|
||||
itemResolver.generateItemURL(
|
||||
state,
|
||||
item.getObjectId(),
|
||||
name,
|
||||
section,
|
||||
item.getVersion().name()));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Added by: Sören Bernstein <quasi@quasiweb.de>
|
||||
*
|
||||
* Produce links to view an item in a specific language and show all
|
||||
* existing language version and the live status in the folder browser.
|
||||
*/
|
||||
private class LanguagesCellRenderer extends DefaultTableCellRenderer {
|
||||
|
||||
public LanguagesCellRenderer() {
|
||||
super(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getComponent(Table table,
|
||||
PageState state,
|
||||
Object value,
|
||||
boolean isSelected,
|
||||
Object key,
|
||||
int row,
|
||||
int column) {
|
||||
|
||||
final ContentItem item = (ContentItem) value;
|
||||
String name = item.getDisplayName();
|
||||
|
||||
final SimpleContainer container = new SimpleContainer();
|
||||
final ContentSection section = CMS.getContext().getContentSection();
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final ContentItemManager itemManager = cdiUtil.findBean(
|
||||
ContentItemManager.class);
|
||||
final ContentSectionManager sectionManager = cdiUtil.findBean(
|
||||
ContentSectionManager.class);
|
||||
final ItemResolver itemResolver = sectionManager.getItemResolver(
|
||||
section);
|
||||
|
||||
item.getName().getAvailableLocales().forEach(locale -> {
|
||||
final String lang = locale.toString();
|
||||
final StringBuilder fontWeight = new StringBuilder(2);
|
||||
final StringBuilder styleClasses = new StringBuilder(20);
|
||||
if (itemManager.isLive(item)) {
|
||||
fontWeight.append(Label.BOLD);
|
||||
styleClasses.append("live ");
|
||||
}
|
||||
|
||||
final Label langLabel = new Label(lang);
|
||||
langLabel.setFontWeight(fontWeight.toString().trim());
|
||||
langLabel.setClassAttr(styleClasses.toString().trim());
|
||||
|
||||
container.add(new Link(
|
||||
langLabel,
|
||||
itemResolver.generateItemURL(state,
|
||||
item.getObjectId(),
|
||||
name,
|
||||
section,
|
||||
item.getVersion().name())));
|
||||
});
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce delete links for items and non-empty folders.
|
||||
*/
|
||||
private static class ActionCellRenderer implements TableCellRenderer {
|
||||
|
||||
private static final Label s_noAction;
|
||||
private static final ControlLink s_link;
|
||||
private static final Logger logger = Logger.getLogger(
|
||||
ActionCellRenderer.class);
|
||||
|
||||
static {
|
||||
logger.debug("Static initializer is starting...");
|
||||
s_noAction = new Label(" ", false);
|
||||
s_noAction.lock();
|
||||
s_link = new ControlLink(
|
||||
new Label(globalize("cms.ui.folder.delete")));
|
||||
s_link.setConfirmation(
|
||||
globalize("cms.ui.folder.delete_confirmation"));
|
||||
logger.debug("Static initializer finished.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getComponent(Table table, PageState state, Object value,
|
||||
boolean isSelected, Object key,
|
||||
int row, int column) {
|
||||
if (((Boolean) value)) {
|
||||
return s_link;
|
||||
} else {
|
||||
return s_noAction;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final class IndexToggleRenderer implements TableCellRenderer {
|
||||
|
||||
@Override
|
||||
public Component getComponent(Table table,
|
||||
PageState state,
|
||||
Object value,
|
||||
boolean isSelected,
|
||||
Object key,
|
||||
int row,
|
||||
int column) {
|
||||
|
||||
if (value == null) {
|
||||
return new Label(new GlobalizedMessage(
|
||||
"cms.ui.folder.na",
|
||||
CmsConstants.CMS_FOLDER_BUNDLE));
|
||||
}
|
||||
ControlLink link = new ControlLink("");
|
||||
|
||||
if (((Boolean) value)) {
|
||||
link.setClassAttr("checkBoxChecked");
|
||||
} else {
|
||||
link.setClassAttr("checkBoxUnchecked");
|
||||
}
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Deletes an item
|
||||
private class ItemDeleter extends TableActionAdapter {
|
||||
|
||||
@Override
|
||||
public void cellSelected(TableActionEvent e) {
|
||||
int col = e.getColumn();
|
||||
|
||||
if (m_deleteColumn != getColumn(col)) {
|
||||
return;
|
||||
}
|
||||
|
||||
PageState s = e.getPageState();
|
||||
long itemId = Long.parseLong(e.getRowKey().toString());
|
||||
|
||||
final ContentItemRepository itemRepo = CdiUtil.createCdiUtil().
|
||||
findBean(ContentItemRepository.class);
|
||||
final Optional<ContentItem> item = itemRepo.findById(itemId);
|
||||
if (item.isPresent()) {
|
||||
itemRepo.delete(item.get());
|
||||
}
|
||||
|
||||
((Table) e.getSource()).clearSelection(s);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Table model around ItemCollection
|
||||
*/
|
||||
private static class FolderTableModel implements TableModel {
|
||||
|
||||
private static final int NAME = 0;
|
||||
private static final int LANGUAGES = 1;
|
||||
private static final int TITLE = 2;
|
||||
private static final int ADDITIONAL_INFO = 3;
|
||||
private static final int TYPE = 4;
|
||||
private static final int CREATION_DATE = 5;
|
||||
private static final int LAST_MODIFIED = 6;
|
||||
private static final int DELETABLE = 7;
|
||||
private static final int IS_INDEX = 8;
|
||||
private PageState m_state;
|
||||
private FolderBrowser m_table;
|
||||
private List<ContentItem> m_itemColl;
|
||||
private Category m_fol;
|
||||
private Long m_folIndexID;
|
||||
private final ContentItemRepository itemRepo;
|
||||
private final ContentItemManager itemManager;
|
||||
private final CategoryManager categoryManager;
|
||||
private int index = -1;
|
||||
|
||||
//old constructor before using paginator
|
||||
//public FolderTableModel(Folder folder) {
|
||||
//m_itemColl = folder.getItems();
|
||||
//}
|
||||
public FolderTableModel(FolderBrowser table,
|
||||
PageState state,
|
||||
List<ContentItem> itemColl) {
|
||||
m_state = state;
|
||||
m_table = table;
|
||||
m_itemColl = itemColl;
|
||||
|
||||
m_fol = (Category) table.getFolderSelectionModel()
|
||||
.getSelectedObject(state);
|
||||
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
itemRepo = cdiUtil.findBean(ContentItemRepository.class);
|
||||
itemManager = cdiUtil.findBean(ContentItemManager.class);
|
||||
categoryManager = cdiUtil.findBean(CategoryManager.class);
|
||||
|
||||
if (!hideIndexColumn()) {
|
||||
final Optional<CcmObject> indexItem = categoryManager
|
||||
.getIndexObject(m_fol);
|
||||
if (indexItem.isPresent()) {
|
||||
m_folIndexID = indexItem.get().getObjectId();
|
||||
} else {
|
||||
m_folIndexID = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return 7;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean nextRow() {
|
||||
index++;
|
||||
return index < m_itemColl.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getElementAt(int columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case NAME:
|
||||
return m_itemColl.get(index);
|
||||
case LANGUAGES:
|
||||
return m_itemColl.get(index);
|
||||
case TITLE:
|
||||
return m_itemColl.get(index).getDisplayName();
|
||||
case ADDITIONAL_INFO:
|
||||
return "";
|
||||
case TYPE:
|
||||
return m_itemColl.get(index).getContentType().getLabel()
|
||||
.getValue();
|
||||
case CREATION_DATE: {
|
||||
final CcmRevision firstRevision = itemRepo
|
||||
.retrieveFirstRevision(
|
||||
m_itemColl.get(index), m_itemColl.get(index)
|
||||
.getObjectId());
|
||||
if (firstRevision == null) {
|
||||
return "--";
|
||||
} else {
|
||||
return FormatStandards.formatDate(new Date(firstRevision
|
||||
.getTimestamp()));
|
||||
}
|
||||
}
|
||||
case LAST_MODIFIED: {
|
||||
final CcmRevision currentRevision = itemRepo
|
||||
.retrieveCurrentRevision(
|
||||
m_itemColl.get(index),
|
||||
m_itemColl.get(index).getObjectId());
|
||||
if (currentRevision == null) {
|
||||
return "--";
|
||||
} else {
|
||||
return FormatStandards.formatDate(new Date(
|
||||
currentRevision.getTimestamp()));
|
||||
}
|
||||
}
|
||||
case DELETABLE:
|
||||
return isDeletable();
|
||||
case IS_INDEX: {
|
||||
if (hideIndexColumn()) {
|
||||
throw new IndexOutOfBoundsException(
|
||||
"Column index " + columnIndex
|
||||
+ " not in table model.");
|
||||
}
|
||||
if (m_folIndexID == null) {
|
||||
return false;
|
||||
}
|
||||
return m_folIndexID.compareTo(
|
||||
m_itemColl.get(index).getObjectId()) == 0;
|
||||
}
|
||||
default:
|
||||
throw new IndexOutOfBoundsException("Column index "
|
||||
+ columnIndex
|
||||
+ " not in table model.");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isDeletable() {
|
||||
if (s_log.isDebugEnabled()) {
|
||||
s_log.debug("Checking to see if " + this + " is deletable");
|
||||
}
|
||||
|
||||
// if (m_itemColl.isFolder()) {
|
||||
//
|
||||
// if (!m_itemColl.hasChildren()) {
|
||||
// if (s_log.isDebugEnabled()) {
|
||||
// s_log.debug(
|
||||
// "The item is an empty folder; it may be deleted");
|
||||
// }
|
||||
// return true;
|
||||
//
|
||||
// } else {
|
||||
//
|
||||
// if (s_log.isDebugEnabled()) {
|
||||
// s_log.debug(
|
||||
// "The folder is not empty; it cannot be deleted");
|
||||
// }
|
||||
// return false;
|
||||
//
|
||||
// }
|
||||
// } else
|
||||
if (itemManager.isLive(m_itemColl.get(index))) {
|
||||
|
||||
if (s_log.isDebugEnabled()) {
|
||||
s_log.debug(
|
||||
"This item has a live instance; it cannot be deleted");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (s_log.isDebugEnabled()) {
|
||||
s_log.debug(
|
||||
"The item is not a folder and doesn't have a live instance; it may be deleted");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public Object getKeyAt(int columnIndex) {
|
||||
// Note: Folders were marked by negative IDs
|
||||
return m_itemColl.get(index).getObjectId();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class FolderChanger extends TableActionAdapter {
|
||||
|
||||
@Override
|
||||
public void cellSelected(TableActionEvent e) {
|
||||
PageState s = e.getPageState();
|
||||
int col = e.getColumn().intValue();
|
||||
|
||||
if (m_nameColumn != getColumn(col)) {
|
||||
return;
|
||||
}
|
||||
String key = (String) e.getRowKey();
|
||||
if (key.startsWith("-")) { // XXX dirty dirty
|
||||
clearSelection(s);
|
||||
getFolderSelectionModel().setSelectedKey(
|
||||
s, Long.parseLong(key.substring(1)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// private class IndexChanger extends TableActionAdapter {
|
||||
//
|
||||
// private FolderSelectionModel m_fol;
|
||||
//
|
||||
// public IndexChanger(FolderSelectionModel fol) {
|
||||
// super();
|
||||
// m_fol = fol;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void cellSelected(TableActionEvent e) {
|
||||
// PageState state = e.getPageState();
|
||||
//
|
||||
// BigDecimal rowkey = new BigDecimal((String) e.getRowKey());
|
||||
// if (rowkey == null) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// try {
|
||||
// ContentBundle contentItem = new ContentBundle(rowkey);
|
||||
//
|
||||
// Folder folder = (Folder) m_fol.getSelectedObject(state);
|
||||
//
|
||||
// ContentBundle currentIndexItem = (ContentBundle) folder.
|
||||
// getIndexItem();
|
||||
// if (currentIndexItem == null || (currentIndexItem.getID().
|
||||
// compareTo(contentItem.getID())
|
||||
// != 0)) {
|
||||
// folder.setIndexItem(contentItem);
|
||||
// } else {
|
||||
// folder.removeIndexItem();
|
||||
// }
|
||||
// folder.save();
|
||||
// } catch (DataObjectNotFoundException donfe) {
|
||||
// // Do nothing
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
/**
|
||||
* Getting the GlobalizedMessage using a CMS Class targetBundle.
|
||||
*
|
||||
* @param key The resource key @pre ( key != null )
|
||||
*/
|
||||
private static GlobalizedMessage globalize(String key) {
|
||||
return new GlobalizedMessage(key, CmsConstants.CMS_FOLDER_BUNDLE);
|
||||
|
||||
}
|
||||
|
||||
private static boolean hideIndexColumn() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -61,36 +61,11 @@ import com.arsdigita.bebop.table.TableCellRenderer;
|
|||
import com.arsdigita.bebop.table.TableColumn;
|
||||
import com.arsdigita.bebop.tree.TreeCellRenderer;
|
||||
import com.arsdigita.cms.CMS;
|
||||
import com.arsdigita.cms.CMSConfig;
|
||||
import com.arsdigita.cms.ContentBundle;
|
||||
import com.arsdigita.cms.ContentItem;
|
||||
import com.arsdigita.cms.ContentSection;
|
||||
import com.arsdigita.cms.ContentTypeLifecycleDefinition;
|
||||
import com.arsdigita.cms.Folder;
|
||||
import com.arsdigita.cms.ItemCollection;
|
||||
import com.arsdigita.cms.SecurityManager;
|
||||
import com.arsdigita.cms.lifecycle.LifecycleDefinition;
|
||||
import com.arsdigita.cms.ui.lifecycle.PublishLock;
|
||||
import com.arsdigita.cms.util.GlobalizationUtil;
|
||||
import com.arsdigita.domain.DataObjectNotFoundException;
|
||||
import com.arsdigita.domain.DomainObjectFactory;
|
||||
import com.arsdigita.kernel.ACSObject;
|
||||
import com.arsdigita.kernel.Party;
|
||||
import com.arsdigita.kernel.PartyCollection;
|
||||
import com.arsdigita.kernel.User;
|
||||
import com.arsdigita.notification.Notification;
|
||||
import com.arsdigita.persistence.CompoundFilter;
|
||||
import com.arsdigita.persistence.DataCollection;
|
||||
import com.arsdigita.persistence.Filter;
|
||||
import com.arsdigita.persistence.OID;
|
||||
import com.arsdigita.persistence.SessionManager;
|
||||
import com.arsdigita.toolbox.GlobalisationUtil;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
import com.arsdigita.toolbox.ui.ActionGroup;
|
||||
import com.arsdigita.util.Assert;
|
||||
import com.arsdigita.util.UncheckedWrapperException;
|
||||
import com.arsdigita.web.Web;
|
||||
import com.arsdigita.workflow.simple.TaskException;
|
||||
import com.arsdigita.workflow.simple.Workflow;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
|
|
@ -99,24 +74,37 @@ import org.apache.log4j.Logger;
|
|||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import javax.persistence.TypedQuery;
|
||||
import org.arsdigita.cms.CMSConfig;
|
||||
import org.libreccm.categorization.Category;
|
||||
import org.libreccm.categorization.CategoryManager;
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.security.PermissionChecker;
|
||||
import org.libreccm.security.Shiro;
|
||||
import org.libreccm.security.User;
|
||||
import org.librecms.CmsConstants;
|
||||
import org.librecms.contentsection.ContentItem;
|
||||
import org.librecms.contentsection.ContentItemManager;
|
||||
import org.librecms.contentsection.ContentItemRepository;
|
||||
import org.librecms.contentsection.ContentSectionConfig;
|
||||
|
||||
/**
|
||||
* Browse folders and manipulate them with various actions (move/copy/delete).
|
||||
*
|
||||
* @author <a href="mailto:lutter@arsdigita.com">David Lutterkort</a>
|
||||
* @version $Id: FolderManipulator.java 1940 2009-05-29 07:15:05Z terry $
|
||||
* @version $Id$
|
||||
*/
|
||||
@SuppressWarnings("PMD.BeanMembersShouldSerialize")
|
||||
public class FolderManipulator extends SimpleContainer implements
|
||||
//FormProcessListener,
|
||||
//FormValidationListener,
|
||||
//FormSubmissionListener,
|
||||
Resettable {
|
||||
//FormProcessListener,
|
||||
//FormValidationListener,
|
||||
//FormSubmissionListener,
|
||||
Resettable {
|
||||
|
||||
//public static final String RESOURCE_BUNDLE = "com.arsdigita.cms.ui.folder.CMSFolderResources";
|
||||
private final GlobalisationUtil globalizationUtil = new com.arsdigita.toolbox.GlobalisationUtil(
|
||||
"com.arsdigita.cms.ui.folder.CMSFolderResources");
|
||||
private static final Logger LOGGER = Logger.getLogger(FolderManipulator.class);
|
||||
private static final Logger LOGGER = Logger.getLogger(
|
||||
FolderManipulator.class);
|
||||
private static final String ATOZ_FILTER_PARAM = "aToZfilter";
|
||||
private static final String ACTION_PARAM = "act";
|
||||
private static final String FILTER_PARAM = "filter";
|
||||
|
|
@ -128,7 +116,7 @@ public class FolderManipulator extends SimpleContainer implements
|
|||
//private static final String UNPUBLISH = "UnPublish";
|
||||
|
||||
private final ArrayParameter sourcesParam = new ArrayParameter(
|
||||
new BigDecimalParameter(SOURCES_PARAM));
|
||||
new BigDecimalParameter(SOURCES_PARAM));
|
||||
private final StringParameter actionParam = new StringParameter(ACTION_PARAM);
|
||||
;
|
||||
/**
|
||||
|
|
@ -138,9 +126,10 @@ public class FolderManipulator extends SimpleContainer implements
|
|||
private final ItemView itemView;
|
||||
private final TargetSelector targetSelector = new TargetSelector();
|
||||
//private final PublishDialog publishDialog = new PublishDialog();
|
||||
|
||||
|
||||
private FilterForm filterForm;
|
||||
private final StringParameter atozFilterParam = new StringParameter(ATOZ_FILTER_PARAM);
|
||||
private final StringParameter atozFilterParam = new StringParameter(
|
||||
ATOZ_FILTER_PARAM);
|
||||
private final StringParameter filterParam = new StringParameter(FILTER_PARAM);
|
||||
|
||||
public FolderManipulator(final FolderSelectionModel folderModel) {
|
||||
|
|
@ -154,12 +143,13 @@ public class FolderManipulator extends SimpleContainer implements
|
|||
add(itemView);
|
||||
|
||||
targetSelector.addProcessListener(new TargetSelectorProcessListener());
|
||||
targetSelector.addValidationListener(new TargetSelectorValidationListener());
|
||||
targetSelector.addSubmissionListener(new TargetSelectorSubmissionListener());
|
||||
targetSelector.addValidationListener(
|
||||
new TargetSelectorValidationListener());
|
||||
targetSelector.addSubmissionListener(
|
||||
new TargetSelectorSubmissionListener());
|
||||
add(targetSelector);
|
||||
|
||||
//publishDialog.addProcessListener(new PublishDialogProcessListener());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -175,13 +165,13 @@ public class FolderManipulator extends SimpleContainer implements
|
|||
|
||||
}
|
||||
|
||||
public final BigDecimal[] getSources(final PageState state) {
|
||||
public final Long[] getSources(final PageState state) {
|
||||
|
||||
final BigDecimal[] result = (BigDecimal[]) state.getValue(sourcesParam);
|
||||
final Long[] result = (Long[]) state.getValue(sourcesParam);
|
||||
|
||||
//Return empty array instead of null.
|
||||
if (result == null) {
|
||||
return new BigDecimal[0];
|
||||
return new Long[0];
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
|
|
@ -191,7 +181,7 @@ public class FolderManipulator extends SimpleContainer implements
|
|||
return sourceFolderModel;
|
||||
}
|
||||
|
||||
public final Folder getTarget(final PageState state) {
|
||||
public final Category getTarget(final PageState state) {
|
||||
return targetSelector.getTarget(state);
|
||||
}
|
||||
|
||||
|
|
@ -210,61 +200,58 @@ public class FolderManipulator extends SimpleContainer implements
|
|||
// protected final boolean isUnPublish(final PageState state) {
|
||||
// return UNPUBLISH.equals(getAction(state));
|
||||
// }
|
||||
|
||||
private String getAction(final PageState state) {
|
||||
return (String) state.getValue(actionParam);
|
||||
}
|
||||
|
||||
protected void moveItems(final Folder target, final BigDecimal[] itemIds) {
|
||||
protected void moveItems(final Category target,
|
||||
final Long[] itemIds) {
|
||||
|
||||
for (BigDecimal itemId : itemIds) {
|
||||
try {
|
||||
changeItemParent(itemId, target);
|
||||
} catch (DataObjectNotFoundException e) {
|
||||
LOGGER.warn("object not found in content move", e);
|
||||
throw new IllegalStateException(String.format("Item '%s' to move not found.",
|
||||
itemId.toString()));
|
||||
for (Long itemId : itemIds) {
|
||||
|
||||
changeItemParent(itemId, target);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void changeItemParent(final BigDecimal itemId, final Folder newParent)
|
||||
throws DataObjectNotFoundException {
|
||||
private void changeItemParent(final Long itemId, final Category newParent) {
|
||||
|
||||
final ContentItem item = new ContentItem(itemId);
|
||||
item.setParent(newParent);
|
||||
item.save();
|
||||
//ToDo
|
||||
throw new UnsupportedOperationException();
|
||||
|
||||
// final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
// final ContentItemRepository itemRepo = cdiUtil.findBean(
|
||||
// ContentItemRepository.class);
|
||||
// final ContentItemManager itemManager = cdiUtil.findBean(
|
||||
// ContentItemManager.class);
|
||||
// final CategoryManager categoryManager = cdiUtil.findBean(
|
||||
// CategoryManager.class);
|
||||
// final ContentItem item = itemRepo.findById(itemId);
|
||||
// final Category itemFolder = itemManager.getItemFolders(item).
|
||||
// item.addCategory(newParent);
|
||||
// item.setParent(newParent);
|
||||
// item.save();
|
||||
}
|
||||
|
||||
protected void copyItems(final Folder target,
|
||||
final BigDecimal[] itemIds) {
|
||||
protected void copyItems(final Category target,
|
||||
final Long[] itemIds) {
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Copying items " + Arrays.asList(itemIds) + " to " + target);
|
||||
}
|
||||
for (BigDecimal itemId : itemIds) {
|
||||
|
||||
// ContentItem source = (ContentItem) DomainObjectFactory.newInstance(
|
||||
// new OID(ContentItem.BASE_DATA_OBJECT_TYPE, itemId));
|
||||
// Assert.exists(source, ContentItem.class);
|
||||
//ToDo
|
||||
throw new UnsupportedOperationException();
|
||||
//
|
||||
// final ACSObject parent = source.getParent();
|
||||
// if (parent instanceof ContentBundle) {
|
||||
// source = (ContentBundle) parent;
|
||||
// }
|
||||
// if (LOGGER.isDebugEnabled()) {
|
||||
// LOGGER.debug("Copying items " + Arrays.asList(itemIds) + " to "
|
||||
// + target);
|
||||
// }
|
||||
// for (BigDecimal itemId : itemIds) {
|
||||
//
|
||||
// if (LOGGER.isDebugEnabled()) {
|
||||
// LOGGER.debug("Copying item " + source);
|
||||
// }
|
||||
final ContentItem source = retrieveSourceItem(itemId);
|
||||
|
||||
final ContentItem newItem = source.copy(target, true);
|
||||
Assert.isEqual(target, newItem.getParent());
|
||||
|
||||
}
|
||||
// final ContentItem source = retrieveSourceItem(itemId);
|
||||
//
|
||||
// final ContentItem newItem = source.copy(target, true);
|
||||
// Assert.isEqual(target, newItem.getParent());
|
||||
//
|
||||
// }
|
||||
}
|
||||
|
||||
// protected void publishItems(final BigDecimal[] itemIds) {
|
||||
|
|
@ -291,7 +278,6 @@ public class FolderManipulator extends SimpleContainer implements
|
|||
//
|
||||
// }
|
||||
// }
|
||||
|
||||
// private void publish(final BigDecimal itemId) {
|
||||
//
|
||||
// }
|
||||
|
|
@ -385,27 +371,26 @@ public class FolderManipulator extends SimpleContainer implements
|
|||
//
|
||||
// thread.start();
|
||||
// }
|
||||
|
||||
private ContentItem retrieveSourceItem(final BigDecimal itemToCopyId) {
|
||||
|
||||
ContentItem source = (ContentItem) DomainObjectFactory.newInstance(
|
||||
new OID(ContentItem.BASE_DATA_OBJECT_TYPE, itemToCopyId));
|
||||
Assert.exists(source, ContentItem.class);
|
||||
|
||||
final ACSObject parent = source.getParent();
|
||||
if (parent instanceof ContentBundle) {
|
||||
source = (ContentBundle) parent;
|
||||
}
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Copying item " + source);
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
// private ContentItem retrieveSourceItem(final BigDecimal itemToCopyId) {
|
||||
//
|
||||
// ContentItem source = (ContentItem) DomainObjectFactory.newInstance(
|
||||
// new OID(ContentItem.BASE_DATA_OBJECT_TYPE, itemToCopyId));
|
||||
// Assert.exists(source, ContentItem.class);
|
||||
//
|
||||
// final ACSObject parent = source.getParent();
|
||||
// if (parent instanceof ContentBundle) {
|
||||
// source = (ContentBundle) parent;
|
||||
// }
|
||||
//
|
||||
// if (LOGGER.isDebugEnabled()) {
|
||||
// LOGGER.debug("Copying item " + source);
|
||||
// }
|
||||
//
|
||||
// return source;
|
||||
// }
|
||||
/**
|
||||
* Returns the form that contains the folder browser and the move/copy dropdown.
|
||||
* Returns the form that contains the folder browser and the move/copy
|
||||
* dropdown.
|
||||
*
|
||||
* @return The form containing the folder browser and dropdown menu
|
||||
*/
|
||||
|
|
@ -438,7 +423,8 @@ public class FolderManipulator extends SimpleContainer implements
|
|||
}
|
||||
|
||||
@Override
|
||||
public void process(final FormSectionEvent event) throws FormProcessException {
|
||||
public void process(final FormSectionEvent event) throws
|
||||
FormProcessException {
|
||||
final PageState state = event.getPageState();
|
||||
|
||||
itemView.setVisible(state, false);
|
||||
|
|
@ -455,15 +441,16 @@ public class FolderManipulator extends SimpleContainer implements
|
|||
}
|
||||
|
||||
@Override
|
||||
public void process(final FormSectionEvent event) throws FormProcessException {
|
||||
public void process(final FormSectionEvent event) throws
|
||||
FormProcessException {
|
||||
|
||||
final PageState state = event.getPageState();
|
||||
|
||||
itemView.setVisible(state, true);
|
||||
targetSelector.setVisible(state, false);
|
||||
|
||||
final Folder folder = targetSelector.getTarget(state);
|
||||
final BigDecimal[] itemIds = getSources(state);
|
||||
final Category folder = targetSelector.getTarget(state);
|
||||
final Long[] itemIds = getSources(state);
|
||||
|
||||
if (isCopy(state)) {
|
||||
copyItems(folder, itemIds);
|
||||
|
|
@ -503,7 +490,6 @@ public class FolderManipulator extends SimpleContainer implements
|
|||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
private class ItemViewValidationListener implements FormValidationListener {
|
||||
|
||||
public ItemViewValidationListener() {
|
||||
|
|
@ -511,26 +497,30 @@ public class FolderManipulator extends SimpleContainer implements
|
|||
}
|
||||
|
||||
@Override
|
||||
public void validate(final FormSectionEvent event) throws FormProcessException {
|
||||
public void validate(final FormSectionEvent event) throws
|
||||
FormProcessException {
|
||||
|
||||
final PageState state = event.getPageState();
|
||||
final FormData data = event.getFormData();
|
||||
|
||||
if (getSources(state).length <= 0) {
|
||||
data.addError(globalizationUtil.globalize("cms.ui.folder.must_select_item"));
|
||||
data.addError("cms.ui.folder.must_select_item",
|
||||
CmsConstants.CMS_FOLDER_BUNDLE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class TargetSelectorValidationListener implements FormValidationListener {
|
||||
private class TargetSelectorValidationListener implements
|
||||
FormValidationListener {
|
||||
|
||||
public TargetSelectorValidationListener() {
|
||||
//Nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(final FormSectionEvent event) throws FormProcessException {
|
||||
public void validate(final FormSectionEvent event) throws
|
||||
FormProcessException {
|
||||
|
||||
final PageState state = event.getPageState();
|
||||
|
||||
|
|
@ -538,70 +528,82 @@ public class FolderManipulator extends SimpleContainer implements
|
|||
throw new IllegalStateException("No source items specified");
|
||||
}
|
||||
|
||||
final Folder target = targetSelector.getTarget(state);
|
||||
final Category target = targetSelector.getTarget(state);
|
||||
final FormData data = event.getFormData();
|
||||
if (target == null) {
|
||||
data.addError(globalizationUtil.globalize(
|
||||
"cms.ui.folder.need_select_target_folder"));
|
||||
data.addError(new GlobalizedMessage(
|
||||
"cms.ui.folder.need_select_target_folder",
|
||||
CmsConstants.CMS_FOLDER_BUNDLE));
|
||||
//If the target is null, we can skip the rest of the checks
|
||||
return;
|
||||
}
|
||||
|
||||
if (target.equals(sourceFolderModel.getSelectedObject(state))) {
|
||||
data.addError(globalizationUtil.globalize("cms.ui.folder.not_within_same_folder"));
|
||||
data.addError(new GlobalizedMessage(
|
||||
"cms.ui.folder.not_within_same_folder",
|
||||
CmsConstants.CMS_FOLDER_BUNDLE));
|
||||
}
|
||||
|
||||
// check create item permission
|
||||
final User user = Web.getWebContext().getUser();
|
||||
final SecurityManager securityManager = CMS.getSecurityManager(state);
|
||||
if (!securityManager.canAccess(user, SecurityManager.NEW_ITEM, target)) {
|
||||
data.addError(globalizationUtil.globalize("cms.ui.folder.no_permission_for_item"));
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final Shiro shiro = cdiUtil.findBean(Shiro.class);
|
||||
final PermissionChecker permissionChecker = cdiUtil.findBean(
|
||||
PermissionChecker.class);
|
||||
if (!permissionChecker.isPermitted(
|
||||
CmsConstants.PRIVILEGE_ITEMS_CREATE_NEW, target)) {
|
||||
data.addError("cms.ui.folder.no_permission_for_item",
|
||||
CmsConstants.CMS_FOLDER_BUNDLE);
|
||||
}
|
||||
|
||||
for (BigDecimal source : getSources(state)) {
|
||||
try {
|
||||
validateItem(source, target, state, data);
|
||||
} catch (DataObjectNotFoundException ex) {
|
||||
LOGGER.warn("Object not found in validation", ex);
|
||||
throw new IllegalStateException(String.format(
|
||||
"There is no item with the id '%s'", source.toString()));
|
||||
}
|
||||
for (Long source : getSources(state)) {
|
||||
|
||||
validateItem(source, target, state, data);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void validateItem(final BigDecimal itemId,
|
||||
final Folder target,
|
||||
private void validateItem(final Long itemId,
|
||||
final Category target,
|
||||
final PageState state,
|
||||
final FormData data) {
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final ContentItemRepository itemRepo = cdiUtil.findBean(
|
||||
ContentItemRepository.class);
|
||||
final ContentItemManager itemManager = cdiUtil.findBean(
|
||||
ContentItemManager.class);
|
||||
final PermissionChecker permissionChecker = cdiUtil.findBean(
|
||||
PermissionChecker.class);
|
||||
|
||||
final ContentItem item = new ContentItem(itemId);
|
||||
final String name = item.getName();
|
||||
final ContentItem item = itemRepo.findById(itemId);
|
||||
final String name = item.getDisplayName();
|
||||
|
||||
final ItemCollection items = target.getItems();
|
||||
items.addNameFilter(name);
|
||||
if (items.next()) {
|
||||
final long count = itemRepo.countByNameInFolder(target, name);
|
||||
if (count > 0) {
|
||||
// there is an item in the target folder that already has this name
|
||||
addErrorMessage(data, "cms.ui.folder.item_already_exists", name);
|
||||
}
|
||||
items.close();
|
||||
|
||||
if (item.isLive() && isMove(state)) {
|
||||
if (itemManager.isLive(item) && isMove(state)) {
|
||||
addErrorMessage(data, "cms.ui.folder.item_is_live", name);
|
||||
}
|
||||
|
||||
final SecurityManager securityManager = CMS.getSecurityManager(state);
|
||||
final User user = Web.getWebContext().getUser();
|
||||
if ((!securityManager.canAccess(user, SecurityManager.DELETE_ITEM, item))
|
||||
&& isMove(state)) {
|
||||
addErrorMessage(data, "cms.ui.folder.no_permission_for_item", name);
|
||||
if (!(permissionChecker.isPermitted(
|
||||
CmsConstants.PRIVILEGE_ITEMS_DELETE, item))
|
||||
&& isMove(state)) {
|
||||
addErrorMessage(data, "cms.ui.folder.no_permission_for_item",
|
||||
name);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void addErrorMessage(final FormData data, final String message, final String itemName) {
|
||||
data.addError(globalizationUtil.globalize(message, new Object[]{itemName}));
|
||||
private void addErrorMessage(final FormData data,
|
||||
final String message,
|
||||
final String itemName) {
|
||||
data.addError(new GlobalizedMessage(message,
|
||||
CmsConstants.CMS_FOLDER_BUNDLE,
|
||||
new Object[]{itemName}));
|
||||
}
|
||||
|
||||
// @Override
|
||||
|
|
@ -615,20 +617,24 @@ public class FolderManipulator extends SimpleContainer implements
|
|||
//
|
||||
// }
|
||||
// }
|
||||
private class TargetSelectorSubmissionListener implements FormSubmissionListener {
|
||||
private class TargetSelectorSubmissionListener implements
|
||||
FormSubmissionListener {
|
||||
|
||||
public TargetSelectorSubmissionListener() {
|
||||
//Nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void submitted(final FormSectionEvent event) throws FormProcessException {
|
||||
public void submitted(final FormSectionEvent event) throws
|
||||
FormProcessException {
|
||||
|
||||
final PageState state = event.getPageState();
|
||||
|
||||
if (targetSelector.isCancelled(state)) {
|
||||
reset(state);
|
||||
throw new FormProcessException(GlobalizationUtil.globalize("cms.ui.folder.cancelled"));
|
||||
throw new FormProcessException(new GlobalizedMessage(
|
||||
"cms.ui.folder.cancelled",
|
||||
CmsConstants.CMS_FOLDER_BUNDLE));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -671,15 +677,26 @@ public class FolderManipulator extends SimpleContainer implements
|
|||
final PageState state = event.getPageState();
|
||||
final Label label = (Label) event.getTarget();
|
||||
final int numberOfItems = getSources(state).length;
|
||||
final Folder folder = (Folder) sourceFolderModel.getSelectedObject(state);
|
||||
final Category folder = (Category) sourceFolderModel.
|
||||
getSelectedObject(state);
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final CategoryManager categoryManager = cdiUtil.
|
||||
findBean(CategoryManager.class);
|
||||
|
||||
if (isMove(state)) {
|
||||
label.setLabel(globalizationUtil.globalize(
|
||||
"cms.ui.folder.move", new Object[]{numberOfItems,
|
||||
folder.getPathNoJsp()}));
|
||||
|
||||
label.setLabel(new GlobalizedMessage(
|
||||
"cms.ui.folder.move",
|
||||
CmsConstants.CMS_FOLDER_BUNDLE,
|
||||
new Object[]{numberOfItems,
|
||||
categoryManager.getCategoryPath(
|
||||
folder)}));
|
||||
} else if (isCopy(state)) {
|
||||
label.setLabel(globalizationUtil.globalize(
|
||||
"cms.ui.folder.copy", new Object[]{numberOfItems,
|
||||
folder.getPathNoJsp()}));
|
||||
label.setLabel(new GlobalizedMessage(
|
||||
"cms.ui.folder.copy",
|
||||
new Object[]{numberOfItems,
|
||||
categoryManager.getCategoryPath(
|
||||
folder)}));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -702,14 +719,21 @@ public class FolderManipulator extends SimpleContainer implements
|
|||
|
||||
// Set things up the first time the selector gets visible
|
||||
public void expose(final PageState state) {
|
||||
final Folder folder = (Folder) sourceFolderModel.getSelectedObject(state);
|
||||
final Category folder = (Category) sourceFolderModel.
|
||||
getSelectedObject(
|
||||
state);
|
||||
targetModel.clearSelection(state);
|
||||
if (folder != null) {
|
||||
final ItemCollection items = folder.getPathInfo(true);
|
||||
while (items.next()) {
|
||||
folderTree.expand(items.getID().toString(), state);
|
||||
}
|
||||
items.close();
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final ContentItemManager itemManager = cdiUtil.findBean(
|
||||
ContentItemManager.class);
|
||||
|
||||
//ToDo
|
||||
// final ItemCollection items = folder.getPathInfo(true);
|
||||
// while (items.next()) {
|
||||
// folderTree.expand(items.getID().toString(), state);
|
||||
// }
|
||||
// items.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -718,11 +742,12 @@ public class FolderManipulator extends SimpleContainer implements
|
|||
folderTree.clearSelection(state);
|
||||
// FIXME: add a reset method to Tree and call that instead of this
|
||||
// hack
|
||||
state.setValue(folderTree.getSelectionModel().getStateParameter(), null);
|
||||
state.setValue(folderTree.getSelectionModel().getStateParameter(),
|
||||
null);
|
||||
}
|
||||
|
||||
public Folder getTarget(final PageState state) {
|
||||
return (Folder) targetModel.getSelectedObject(state);
|
||||
public Category getTarget(final PageState state) {
|
||||
return (Category) targetModel.getSelectedObject(state);
|
||||
}
|
||||
|
||||
public boolean isCancelled(final PageState state) {
|
||||
|
|
@ -769,7 +794,6 @@ public class FolderManipulator extends SimpleContainer implements
|
|||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
// The form containing the browser and the drop down for selecting an
|
||||
// action
|
||||
private class ItemView extends Form implements Resettable {
|
||||
|
|
@ -797,13 +821,15 @@ public class FolderManipulator extends SimpleContainer implements
|
|||
folderBrowser.setAtoZfilterParameter(atozFilterParam);
|
||||
folderBrowser.setFilterParameter(filterParam);
|
||||
folderBrowser.setFilterForm(filterForm);
|
||||
paginator = new Paginator((PaginationModelBuilder) folderBrowser.getModelBuilder(),
|
||||
ContentSection.getConfig().getFolderBrowseListSize());
|
||||
paginator = new Paginator(
|
||||
(PaginationModelBuilder) folderBrowser.getModelBuilder(),
|
||||
CMSConfig.getConfig().getFolderBrowseListSize());
|
||||
panel.add(paginator);
|
||||
panel.add(folderBrowser);
|
||||
|
||||
LOGGER.debug("Adding filter form...");
|
||||
filterForm = new FilterForm((FilterFormModelBuilder) folderBrowser.getModelBuilder());
|
||||
filterForm = new FilterForm((FilterFormModelBuilder) folderBrowser.
|
||||
getModelBuilder());
|
||||
FolderManipulator.this.add(filterForm);
|
||||
|
||||
checkboxGroup = new CheckboxGroup(sourcesParam);
|
||||
|
|
@ -814,14 +840,20 @@ public class FolderManipulator extends SimpleContainer implements
|
|||
final Container container = new SimpleContainer();
|
||||
group.addAction(container);
|
||||
|
||||
container.add(new Label(globalizationUtil.globalize("cms.ui.folder.edit_selection")));
|
||||
container.add(new Label(new GlobalizedMessage(
|
||||
"cms.ui.folder.edit_selection",
|
||||
CmsConstants.CMS_FOLDER_BUNDLE)));
|
||||
actionSelect = new SingleSelect(actionParam);
|
||||
actionSelect.addOption(new Option(COPY,
|
||||
new Label(globalizationUtil.globalize(
|
||||
"cms.ui.folder.copy.action"))));
|
||||
actionSelect.addOption(new Option(MOVE,
|
||||
new Label(globalizationUtil.globalize(
|
||||
"cms.ui.folder.move.action"))));
|
||||
actionSelect.addOption(
|
||||
new Option(COPY,
|
||||
new Label(new GlobalizedMessage(
|
||||
"cms.ui.folder.copy.action",
|
||||
CmsConstants.CMS_FOLDER_BUNDLE))));
|
||||
actionSelect.addOption(
|
||||
new Option(MOVE,
|
||||
new Label(new GlobalizedMessage(
|
||||
"cms.ui.folder.move.action",
|
||||
CmsConstants.CMS_FOLDER_BUNDLE))));
|
||||
//Publishing in the folder browser only works if threaded publishing is active
|
||||
// if (CMSConfig.getInstanceOf().getThreadedPublishing()) {
|
||||
// actionSelect.addOption(new Option(PUBLISH,
|
||||
|
|
@ -832,7 +864,10 @@ public class FolderManipulator extends SimpleContainer implements
|
|||
// "cms.ui.folder.unpublish.action"))));
|
||||
// }
|
||||
container.add(actionSelect);
|
||||
submit = new Submit("Go", globalizationUtil.globalize("cms.ui.folder.go"));
|
||||
submit = new Submit("Go",
|
||||
new GlobalizedMessage(
|
||||
"cms.ui.folder.go",
|
||||
CmsConstants.CMS_FOLDER_BUNDLE));
|
||||
container.add(submit);
|
||||
|
||||
// Add a new first column to the table
|
||||
|
|
@ -872,7 +907,8 @@ public class FolderManipulator extends SimpleContainer implements
|
|||
final int row,
|
||||
final int column) {
|
||||
final BigDecimal n = (BigDecimal) key;
|
||||
Option result = new Option(sourcesParam.marshalElement(n.abs()), "");
|
||||
Option result = new Option(sourcesParam.marshalElement(n.abs()),
|
||||
"");
|
||||
result.setGroup(checkboxGroup);
|
||||
return result;
|
||||
}
|
||||
|
|
@ -904,7 +940,8 @@ public class FolderManipulator extends SimpleContainer implements
|
|||
panel = new BoxPanel(BoxPanel.HORIZONTAL);
|
||||
|
||||
final ActionLink allLink = new ActionLink(
|
||||
globalizationUtil.globalize("cms.ui.folder.filter.all"));
|
||||
new GlobalizedMessage("cms.ui.folder.filter.all",
|
||||
CmsConstants.CMS_FOLDER_BUNDLE));
|
||||
allLink.addActionListener(new ActionListener() {
|
||||
|
||||
@Override
|
||||
|
|
@ -929,11 +966,15 @@ public class FolderManipulator extends SimpleContainer implements
|
|||
// });
|
||||
// panel.add(link);
|
||||
// }
|
||||
panel.add(new Label(globalizationUtil.globalize("cms.ui.folder.filter")));
|
||||
panel.add(new Label(new GlobalizedMessage(
|
||||
"cms.ui.folder.filter",
|
||||
CmsConstants.CMS_FOLDER_BUNDLE)));
|
||||
filterField = new TextField(filterParam);
|
||||
panel.add(filterField);
|
||||
panel.add(new Submit("filterFolderSubmit",
|
||||
globalizationUtil.globalize("cms.ui.folder.filter_do")));
|
||||
new GlobalizedMessage(
|
||||
"cms.ui.folder.filter_do",
|
||||
CmsConstants.CMS_FOLDER_BUNDLE)));
|
||||
|
||||
add(panel);
|
||||
|
||||
|
|
@ -944,25 +985,29 @@ public class FolderManipulator extends SimpleContainer implements
|
|||
}
|
||||
|
||||
@Override
|
||||
public void process(final FormSectionEvent event) throws FormProcessException {
|
||||
public void process(final FormSectionEvent event) throws
|
||||
FormProcessException {
|
||||
//Nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(final FormSectionEvent event) throws FormProcessException {
|
||||
public void init(final FormSectionEvent event) throws
|
||||
FormProcessException {
|
||||
//fse.getPageState().setValue(FolderManipulator.this.m_filter, null);
|
||||
//filterField.setValue(fse.getPageState(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void submitted(final FormSectionEvent event) throws FormProcessException {
|
||||
public void submitted(final FormSectionEvent event) throws
|
||||
FormProcessException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisible(PageState state) {
|
||||
if (super.isVisible(state)
|
||||
&& (modelBuilder.getFolderSize(state)
|
||||
>= CMSConfig.getInstanceOf().getFolderAtoZShowLimit())) {
|
||||
&& (modelBuilder.getFolderSize(state)
|
||||
>= CMSConfig.getConfig().
|
||||
getFolderAtoZShowLimit())) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
|
@ -996,9 +1041,10 @@ public class FolderManipulator extends SimpleContainer implements
|
|||
private RequestLocal m_invalidFolders = new RequestLocal();
|
||||
|
||||
/**
|
||||
* Render the folders appropriately. The selected folder is a bold label. Invalid folders
|
||||
* are plain labels. Unselected, valid folders are control links. Invalid folders are: the
|
||||
* parent folder of the sources, any of the sources, and any subfolders of the sources.
|
||||
* Render the folders appropriately. The selected folder is a bold
|
||||
* label. Invalid folders are plain labels. Unselected, valid folders
|
||||
* are control links. Invalid folders are: the parent folder of the
|
||||
* sources, any of the sources, and any subfolders of the sources.
|
||||
*/
|
||||
@Override
|
||||
public Component getComponent(final Tree tree,
|
||||
|
|
@ -1012,60 +1058,52 @@ public class FolderManipulator extends SimpleContainer implements
|
|||
// Get the list of invalid folders once per request.
|
||||
ArrayList invalidFolders = (ArrayList) m_invalidFolders.get(state);
|
||||
|
||||
if (invalidFolders == null) {
|
||||
// The list of invalid folders has not been set for this
|
||||
// request. Setting now.
|
||||
invalidFolders = new ArrayList();
|
||||
|
||||
final DataCollection collection = SessionManager.getSession().retrieve(
|
||||
ContentItem.BASE_DATA_OBJECT_TYPE);
|
||||
CompoundFilter filter = collection.getFilterFactory().or();
|
||||
// The sources themselves are not valid.
|
||||
final BigDecimal[] sources = getSources(state);
|
||||
|
||||
for (int i = 0; i < sources.length; i++) {
|
||||
invalidFolders.add(sources[i].toString());
|
||||
|
||||
final Filter temp = filter.addFilter("id = :id" + i);
|
||||
temp.set("id" + i, sources[i]);
|
||||
}
|
||||
collection.addFilter(filter);
|
||||
|
||||
final DataCollection folders = SessionManager.getSession().retrieve(
|
||||
Folder.BASE_DATA_OBJECT_TYPE);
|
||||
folders.addEqualsFilter(Folder.IS_DELETED, Boolean.FALSE);
|
||||
|
||||
filter = collection.getFilterFactory().or();
|
||||
int count = 0;
|
||||
while (collection.next()) {
|
||||
filter.addFilter(Folder.ANCESTORS + " like :ancestors"
|
||||
+ count + " || '%'");
|
||||
filter.set("ancestors" + count,
|
||||
collection.get(ContentItem.ANCESTORS));
|
||||
count++;
|
||||
}
|
||||
folders.addFilter(filter);
|
||||
|
||||
while (folders.next()) {
|
||||
invalidFolders.add(folders.get(Folder.ID).toString());
|
||||
}
|
||||
|
||||
// Get all subfolders of the sources. These are also not valid.
|
||||
/*
|
||||
DataQuery dq = SessionManager.getSession().retrieveQuery("com.arsdigita.cms.FoldersAndAllSubFolders");
|
||||
dq.setParameter("item_list", invalidFolders);
|
||||
|
||||
while (dq.next()) {
|
||||
invalidFolders.add (dq.get("folder_id").toString());
|
||||
}
|
||||
*/
|
||||
// The folder from which the sources are being moved/copied is
|
||||
// not allowed.
|
||||
invalidFolders.add(sourceFolderModel.getSelectedKey(state).toString());
|
||||
|
||||
// Save the invalid folder list
|
||||
m_invalidFolders.set(state, invalidFolders);
|
||||
}
|
||||
// if (invalidFolders == null) {
|
||||
// // The list of invalid folders has not been set for this
|
||||
// // request. Setting now.
|
||||
// invalidFolders = new ArrayList();
|
||||
//
|
||||
// final DataCollection collection = SessionManager.getSession().
|
||||
// retrieve(
|
||||
// ContentItem.BASE_DATA_OBJECT_TYPE);
|
||||
// CompoundFilter filter = collection.getFilterFactory().or();
|
||||
// // The sources themselves are not valid.
|
||||
// final Long[] sources = getSources(state);
|
||||
//
|
||||
// for (int i = 0; i < sources.length; i++) {
|
||||
// invalidFolders.add(sources[i].toString());
|
||||
//
|
||||
// final Filter temp = filter.addFilter("id = :id" + i);
|
||||
// temp.set("id" + i, sources[i]);
|
||||
// }
|
||||
// collection.addFilter(filter);
|
||||
//
|
||||
// final DataCollection folders = SessionManager.getSession().
|
||||
// retrieve(
|
||||
// Folder.BASE_DATA_OBJECT_TYPE);
|
||||
// folders.addEqualsFilter(Folder.IS_DELETED, Boolean.FALSE);
|
||||
//
|
||||
// filter = collection.getFilterFactory().or();
|
||||
// int count = 0;
|
||||
// while (collection.next()) {
|
||||
// filter.addFilter(Folder.ANCESTORS + " like :ancestors"
|
||||
// + count + " || '%'");
|
||||
// filter.set("ancestors" + count,
|
||||
// collection.get(ContentItem.ANCESTORS));
|
||||
// count++;
|
||||
// }
|
||||
// folders.addFilter(filter);
|
||||
//
|
||||
// while (folders.next()) {
|
||||
// invalidFolders.add(folders.get(Folder.ID).toString());
|
||||
// }
|
||||
//
|
||||
// invalidFolders.add(sourceFolderModel.getSelectedKey(state).
|
||||
// toString());
|
||||
//
|
||||
// // Save the invalid folder list
|
||||
// m_invalidFolders.set(state, invalidFolders);
|
||||
// }
|
||||
|
||||
final Label label = new Label(value.toString());
|
||||
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui.folder;
|
||||
|
||||
import com.arsdigita.bebop.Tree;
|
||||
|
||||
public class FolderTree extends Tree {
|
||||
|
||||
public FolderTree(FolderSelectionModel folderSel) {
|
||||
super(new FolderTreeModelBuilder());
|
||||
setSelectionModel(folderSel);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.cms.ui.util;
|
||||
|
||||
import com.arsdigita.bebop.Component;
|
||||
import com.arsdigita.bebop.ControlLink;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.Table;
|
||||
import com.arsdigita.bebop.table.TableCellRenderer;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
import com.arsdigita.util.Assert;
|
||||
import com.arsdigita.util.LockableImpl;
|
||||
import org.librecms.CmsConstants;
|
||||
|
||||
/**
|
||||
* The default renderer for table cells. This renderer is used by the
|
||||
* {@link com.arsdigita.bebop.Table} component for rendering the table headers
|
||||
* and cells if no other renderer is specified.
|
||||
*
|
||||
* <p>
|
||||
* This renderer can operate in two different modes: <em>active</em>
|
||||
* and <em>inactive</em> mode. In inactive mode, all objects are rendered by
|
||||
* converting them to a string and enclosing that string in a {@link
|
||||
* com.arsdigita.bebop.Label}. If the renderer is in active mode, this label is
|
||||
* further enclosed in a control link. When the user clicks on this link, the
|
||||
* table will fire an <code>TableActionEvent</code> whose <code>getKey()</code>
|
||||
* and <code>getColumn()</code> method return the values of the <code>key</code>
|
||||
* and <code>column</code> parameters that were passed into
|
||||
* {@link #getComponent getComponent}.
|
||||
*
|
||||
* <p>
|
||||
* In a nutshell, an active renderer will let the user click a link that causes
|
||||
* a <code>TableActionEvent</code> for the corresponding cell, while an inactive
|
||||
* renderer will display the values just as strings, thus making it impossible
|
||||
* for the user to cause such an event.
|
||||
*
|
||||
* @author <a href="mailto:lutter@arsdigita.com">David Lutterkort</a>
|
||||
* @author Michael Pih (pihman@arsdigita.com)
|
||||
* @see com.arsdigita.bebop.Table
|
||||
* @see com.arsdigita.bebop.event.TableActionEvent
|
||||
*
|
||||
* @version $Id: DefaultTableCellRenderer.java 287 2005-02-22 00:29:02Z sskracic
|
||||
* $
|
||||
*/
|
||||
public class DefaultTableCellRenderer extends LockableImpl
|
||||
implements TableCellRenderer {
|
||||
|
||||
private boolean m_active;
|
||||
private ThreadLocal m_label;
|
||||
private ThreadLocal m_controlLink;
|
||||
|
||||
/**
|
||||
* Creates a new table cell renderer. The table cell renderer is in inactive
|
||||
* mode.
|
||||
*/
|
||||
public DefaultTableCellRenderer() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new table cell renderer. The <code>active</code> argument
|
||||
* specifies whether the renderer should be active or not.
|
||||
*
|
||||
* @param active <code>true</code> if the renderer should generate links
|
||||
* instead of just static labels.
|
||||
*/
|
||||
public DefaultTableCellRenderer(boolean active) {
|
||||
m_active = active;
|
||||
m_label = new ThreadLocal() {
|
||||
protected Object initialValue() {
|
||||
return new Label("");
|
||||
}
|
||||
};
|
||||
m_controlLink = new ThreadLocal() {
|
||||
protected Object initialValue() {
|
||||
return new ControlLink((Label) m_label.get());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Return <code>true</code> if the renderer is in active mode. A rendererin
|
||||
* active mode will enclose the objects it renders in links that, when
|
||||
* clicked, will cause the containing table to fire a
|
||||
* <code>TableActionEvent</code>.
|
||||
*
|
||||
* @return <code>true</code> if the renderer is in active mode.
|
||||
*/
|
||||
public final boolean isActive() {
|
||||
return m_active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the renderer to active or inactive mode.
|
||||
*
|
||||
* @param v <code>true</code> if the renderer should operate in active mode.
|
||||
* @pre ! isLocked()
|
||||
*/
|
||||
public void setActive(boolean v) {
|
||||
Assert.isUnlocked(this);
|
||||
m_active = v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the component that should be used to render the given
|
||||
* <code>value</code>. Returns a {@link com.arsdigita.bebop.Label} if the
|
||||
* renderer is active, and a {@link com.arsdigita.bebop.ControlLink} if the
|
||||
* renderer is inactive.
|
||||
*
|
||||
* @pre table == null || table != null
|
||||
*/
|
||||
public Component getComponent(Table table, PageState state, Object value,
|
||||
boolean isSelected, Object key,
|
||||
int row, int column) {
|
||||
if (!isLocked() && table != null && table.isLocked()) {
|
||||
lock();
|
||||
}
|
||||
|
||||
Label l = (Label) m_label.get();
|
||||
if (value == null) {
|
||||
l.setLabel(new GlobalizedMessage("cms.ui.util.",
|
||||
CmsConstants.CMS_BUNDLE));
|
||||
l.setOutputEscaping(false);
|
||||
} else {
|
||||
l.setLabel((GlobalizedMessage) value);
|
||||
l.setOutputEscaping(true);
|
||||
}
|
||||
l.setFontWeight((isSelected && m_active) ? Label.BOLD : null);
|
||||
if (m_active && !isSelected) {
|
||||
return (ControlLink) m_controlLink.get();
|
||||
} else {
|
||||
return l;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -70,8 +70,47 @@ import static org.librecms.CmsConstants.*;
|
|||
@NamedQuery(
|
||||
name = "ContentItem.findByFolder",
|
||||
query = "SELECT c.categorizedObject FROM Categorization c "
|
||||
+ "WHERE c.category = :folder"
|
||||
)
|
||||
+ "WHERE c.category = :folder "
|
||||
+ "AND TYPE(c.categorizedObject) IN ContentItem"),
|
||||
@NamedQuery(
|
||||
name = "ContentItem.countItemsInFolder",
|
||||
query = "SELECT COUNT(c) FROM Categorization c "
|
||||
+ "WHERE c.category = :folder "
|
||||
+ "AND TYPE(c.categorizedObject) IN ContentItem"),
|
||||
@NamedQuery(
|
||||
name = "ContentItem.countByNameInFolder",
|
||||
query = "SELECT count(c) FROM Categorization c "
|
||||
+ "WHERE c.category = :folder "
|
||||
+ "AND c.categorizedObject.displayName = :name"),
|
||||
@NamedQuery(
|
||||
name = "ContentItem.filterByNameAndFolder",
|
||||
query = "SELECT c.categorizedObject FROM Categorization c "
|
||||
+ "WHERE c.category = :folder "
|
||||
+ "AND TYPE(c.categorizedObject) IN (ContentItem)"
|
||||
+ "AND (LOWER(c.categorizedObject.displayName) LIKE CONCAT(LOWER(:name), '%') "),
|
||||
@NamedQuery(
|
||||
name = "ContentItem.countFilterByNameAndFolder",
|
||||
query = "SELECT count(c) FROM Categorization c "
|
||||
+ "WHERE c.category = :folder "
|
||||
+ "AND TYPE(c.categorizedObject) IN (ContentItem)"
|
||||
+ "AND LOWER(c.categorizedObject.displayName) LIKE CONCAT(LOWER(:name), '%s') "),
|
||||
@NamedQuery(
|
||||
name = "ContentItem.hasLiveVersion",
|
||||
query = "SELECT (CASE WHEN COUNT(i) > 0 THEN true ELSE false END) "
|
||||
+ "FROM ContentItem i "
|
||||
+ "WHERE i.uuid = :uuid "
|
||||
+ "AND i.version = \"LIVE\""),
|
||||
@NamedQuery(
|
||||
name = "ContentItem.findDraftVersion",
|
||||
query = "SELECT i FROM ContentItem i "
|
||||
+ "WHERE i.uuid = :uuid "
|
||||
+ "AND i.version = \"DRAFT\""),
|
||||
@NamedQuery(
|
||||
name = "ContentItem.findLiveVersion",
|
||||
query = "SELECT i FROM ContentItem i "
|
||||
+ "WHERE i.uuid = :uuid "
|
||||
+ "AND i.version = \"LIVE\"")
|
||||
|
||||
})
|
||||
public class ContentItem extends CcmObject implements Serializable,
|
||||
InheritsPermissions {
|
||||
|
|
@ -258,7 +297,8 @@ public class ContentItem extends CcmObject implements Serializable,
|
|||
@Override
|
||||
public Optional<CcmObject> getParent() {
|
||||
final List<Categorization> result = getCategories().stream().filter(
|
||||
categorization -> CmsConstants.CATEGORIZATION_TYPE_FOLDER.equals(
|
||||
categorization -> CmsConstants.CATEGORIZATION_TYPE_FOLDER.
|
||||
equals(
|
||||
categorization.getType()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
|
|
|
|||
|
|
@ -18,8 +18,14 @@
|
|||
*/
|
||||
package org.librecms.contentsection;
|
||||
|
||||
import com.arsdigita.kernel.KernelConfig;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.libreccm.categorization.Category;
|
||||
import org.libreccm.workflow.WorkflowTemplate;
|
||||
import org.librecms.lifecycle.LifecycleDefinition;
|
||||
|
|
@ -30,8 +36,31 @@ import java.util.stream.Collectors;
|
|||
|
||||
import javax.enterprise.context.RequestScoped;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.libreccm.categorization.Categorization;
|
||||
import org.libreccm.categorization.CategoryManager;
|
||||
import org.libreccm.categorization.ObjectNotAssignedToCategoryException;
|
||||
import org.libreccm.configuration.ConfigurationManager;
|
||||
import org.libreccm.l10n.LocalizedString;
|
||||
import org.libreccm.workflow.Workflow;
|
||||
import org.libreccm.workflow.WorkflowManager;
|
||||
import org.librecms.CmsConstants;
|
||||
import org.librecms.lifecycle.Lifecycle;
|
||||
import org.librecms.lifecycle.LifecycleManager;
|
||||
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.TypedQuery;
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -40,6 +69,18 @@ import org.librecms.CmsConstants;
|
|||
@RequestScoped
|
||||
public class ContentItemManager {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger(
|
||||
ContentItemManager.class);
|
||||
|
||||
@Inject
|
||||
private EntityManager entityManager;
|
||||
|
||||
@Inject
|
||||
private ConfigurationManager confManager;
|
||||
|
||||
@Inject
|
||||
private CategoryManager categoryManager;
|
||||
|
||||
@Inject
|
||||
private ContentItemRepository contentItemRepo;
|
||||
|
||||
|
|
@ -49,6 +90,12 @@ public class ContentItemManager {
|
|||
@Inject
|
||||
private ContentSectionManager sectionManager;
|
||||
|
||||
@Inject
|
||||
private LifecycleManager lifecycleManager;
|
||||
|
||||
@Inject
|
||||
private WorkflowManager workflowManager;
|
||||
|
||||
/**
|
||||
* Creates a new content item in the provided content section and folder
|
||||
* with the default lifecycle and workflow.
|
||||
|
|
@ -65,6 +112,7 @@ public class ContentItemManager {
|
|||
*
|
||||
* @return The new content item.
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public <T extends ContentItem> T createContentItem(
|
||||
final String name,
|
||||
final ContentSection section,
|
||||
|
|
@ -112,6 +160,7 @@ public class ContentItemManager {
|
|||
*
|
||||
* @return The new content item.
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public <T extends ContentItem> T createContentItem(
|
||||
final String name,
|
||||
final ContentSection section,
|
||||
|
|
@ -119,7 +168,47 @@ public class ContentItemManager {
|
|||
final WorkflowTemplate workflowTemplate,
|
||||
final LifecycleDefinition lifecycleDefinition,
|
||||
final Class<T> type) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
||||
final Optional<ContentType> contentType = typeRepo
|
||||
.findByContentSectionAndClass(section, type);
|
||||
|
||||
if (!contentType.isPresent()) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"ContentSection \"%s\" has no content type for \"%s\".",
|
||||
section.getLabel(),
|
||||
type.getName()));
|
||||
}
|
||||
|
||||
final Lifecycle lifecycle = lifecycleManager.createLifecycle(
|
||||
lifecycleDefinition);
|
||||
final Workflow workflow = workflowManager.createWorkflow(
|
||||
workflowTemplate);
|
||||
|
||||
final T item;
|
||||
try {
|
||||
item = type.newInstance();
|
||||
} catch (InstantiationException | IllegalAccessException ex) {
|
||||
LOGGER.error("Failed to create new content item of type \"{}\" "
|
||||
+ "in content section \"{}\".",
|
||||
type.getName(),
|
||||
section.getLabel());
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
final KernelConfig kernelConfig = confManager.findConfiguration(
|
||||
KernelConfig.class);
|
||||
|
||||
item.setDisplayName(name);
|
||||
item.getName().addValue(new Locale(kernelConfig.getDefaultLanguage()),
|
||||
name);
|
||||
item.setLifecycle(lifecycle);
|
||||
item.setWorkflow(workflow);
|
||||
|
||||
categoryManager.addObjectToCategory(item, folder);
|
||||
|
||||
contentItemRepo.save(item);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -130,8 +219,22 @@ public class ContentItemManager {
|
|||
* @param item The item to move.
|
||||
* @param targetFolder The folder to which the item is moved.
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public void move(final ContentItem item, final Category targetFolder) {
|
||||
throw new UnsupportedOperationException();
|
||||
final ContentItem draftItem = getDraftVersion(item, item.getClass());
|
||||
final Optional<Category> currentFolder = getItemFolder(item);
|
||||
|
||||
if (currentFolder.isPresent()) {
|
||||
try {
|
||||
categoryManager.removeObjectFromCategory(draftItem,
|
||||
currentFolder.get());
|
||||
} catch (ObjectNotAssignedToCategoryException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
categoryManager.addObjectToCategory(draftItem, targetFolder);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -144,10 +247,190 @@ public class ContentItemManager {
|
|||
* original item an index is appended to the name of the
|
||||
* item.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void copy(final ContentItem item, final Category targetFolder) {
|
||||
final Optional<ContentType> contentType = typeRepo
|
||||
.findByContentSectionAndClass(
|
||||
item.getContentType().getContentSection(), item.getClass());
|
||||
|
||||
if (!contentType.isPresent()) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"ContentSection \"%s\" has no content type for \"%s\".",
|
||||
item.getContentType().getContentSection(),
|
||||
item.getClass().getName()));
|
||||
}
|
||||
|
||||
final ContentItem draftItem = getDraftVersion(item, item.getClass());
|
||||
|
||||
final ContentItem copy;
|
||||
try {
|
||||
copy = item.getClass().newInstance();
|
||||
} catch (InstantiationException | IllegalAccessException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
copy.setContentType(contentType.get());
|
||||
|
||||
final Lifecycle lifecycle = lifecycleManager.createLifecycle(
|
||||
contentType.get().getDefaultLifecycle());
|
||||
final Workflow workflow = workflowManager.createWorkflow(contentType
|
||||
.get().getDefaultWorkflow());
|
||||
|
||||
copy.setLifecycle(lifecycle);
|
||||
copy.setWorkflow(workflow);
|
||||
|
||||
draftItem.getCategories().forEach(categorization -> categoryManager
|
||||
.addObjectToCategory(copy, categorization.getCategory()));
|
||||
|
||||
final Optional<Category> itemFolder = getItemFolder(draftItem);
|
||||
if (itemFolder.isPresent()) {
|
||||
try {
|
||||
categoryManager.removeObjectFromCategory(
|
||||
copy, getItemFolder(draftItem).get());
|
||||
} catch (ObjectNotAssignedToCategoryException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
categoryManager.addObjectToCategory(
|
||||
copy,
|
||||
targetFolder,
|
||||
CmsConstants.CATEGORIZATION_TYPE_FOLDER);
|
||||
|
||||
// !!!!!!!!!!!!!!!!!!!!!
|
||||
// ToDo copy Attachments
|
||||
// !!!!!!!!!!!!!!!!!!!!!
|
||||
//
|
||||
//
|
||||
final BeanInfo beanInfo;
|
||||
try {
|
||||
beanInfo = Introspector.getBeanInfo(item.getClass());
|
||||
} catch (IntrospectionException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
for (final PropertyDescriptor propertyDescriptor : beanInfo
|
||||
.getPropertyDescriptors()) {
|
||||
if (propertyIsExcluded(propertyDescriptor.getName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final Class<?> propType = propertyDescriptor.getPropertyType();
|
||||
final Method readMethod = propertyDescriptor.getReadMethod();
|
||||
final Method writeMethod = propertyDescriptor.getWriteMethod();
|
||||
|
||||
if (LocalizedString.class.equals(propType)) {
|
||||
final LocalizedString source;
|
||||
final LocalizedString target;
|
||||
try {
|
||||
source = (LocalizedString) readMethod.invoke(draftItem);
|
||||
target = (LocalizedString) readMethod.invoke(copy);
|
||||
} catch (IllegalAccessException |
|
||||
IllegalArgumentException |
|
||||
InvocationTargetException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
source.getAvailableLocales().forEach(
|
||||
locale -> target.addValue(locale, source.getValue(locale)));
|
||||
} else if (propType != null
|
||||
&& propType.isAssignableFrom(ContentItem.class)) {
|
||||
|
||||
final ContentItem linkedItem;
|
||||
try {
|
||||
linkedItem = (ContentItem) readMethod.invoke(draftItem);
|
||||
} catch (IllegalAccessException |
|
||||
IllegalArgumentException |
|
||||
InvocationTargetException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
final ContentItem linkedDraftItem = getDraftVersion(
|
||||
linkedItem, linkedItem.getClass());
|
||||
|
||||
try {
|
||||
writeMethod.invoke(copy, linkedDraftItem);
|
||||
} catch (IllegalAccessException |
|
||||
IllegalArgumentException |
|
||||
InvocationTargetException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
} else if (propType != null
|
||||
&& propType.isAssignableFrom(List.class)) {
|
||||
final List<Object> source;
|
||||
final List<Object> target;
|
||||
try {
|
||||
source = (List<Object>) readMethod.invoke(draftItem);
|
||||
target = (List<Object>) readMethod.invoke(copy);
|
||||
} catch (IllegalAccessException |
|
||||
IllegalArgumentException |
|
||||
InvocationTargetException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
target.addAll(source);
|
||||
} else if (propType != null
|
||||
&& propType.isAssignableFrom(Map.class)) {
|
||||
final Map<Object, Object> source;
|
||||
final Map<Object, Object> target;
|
||||
|
||||
try {
|
||||
source = (Map<Object, Object>) readMethod.invoke(draftItem);
|
||||
target = (Map<Object, Object>) readMethod.invoke(copy);
|
||||
} catch (IllegalAccessException |
|
||||
IllegalArgumentException |
|
||||
InvocationTargetException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
source.forEach((key, value) -> target.put(key, value));
|
||||
} else if (propType != null
|
||||
&& propType.isAssignableFrom(Set.class)) {
|
||||
final Set<Object> source;
|
||||
final Set<Object> target;
|
||||
|
||||
try {
|
||||
source = (Set<Object>) readMethod.invoke(draftItem);
|
||||
target = (Set<Object>) readMethod.invoke(copy);
|
||||
} catch (IllegalAccessException |
|
||||
IllegalArgumentException |
|
||||
InvocationTargetException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
target.addAll(source);
|
||||
} else {
|
||||
final Object value;
|
||||
try {
|
||||
value = readMethod.invoke(item);
|
||||
writeMethod.invoke(copy, value);
|
||||
} catch (IllegalAccessException |
|
||||
IllegalArgumentException |
|
||||
InvocationTargetException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
private boolean propertyIsExcluded(final String name) {
|
||||
final String[] excluded = new String[]{
|
||||
"objectId", "uuid", "lifecycle", "workflow", "categories",
|
||||
"attachments"
|
||||
};
|
||||
|
||||
boolean result = false;
|
||||
for (final String current : excluded) {
|
||||
if (current.equals(name)) {
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a live version of content item or updates the live version of a
|
||||
* content item if there already a live version.
|
||||
|
|
@ -156,8 +439,151 @@ public class ContentItemManager {
|
|||
*
|
||||
* @return The published content item.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public ContentItem publish(final ContentItem item) {
|
||||
throw new UnsupportedOperationException();
|
||||
final ContentItem draftItem = getDraftVersion(item, ContentItem.class);
|
||||
final ContentItem liveItem;
|
||||
|
||||
if (isLive(item)) {
|
||||
liveItem = getLiveVersion(item, ContentItem.class).get();
|
||||
} else {
|
||||
try {
|
||||
liveItem = draftItem.getClass().newInstance();
|
||||
} catch (InstantiationException | IllegalAccessException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
liveItem.setContentType(draftItem.getContentType());
|
||||
liveItem.setLifecycle(draftItem.getLifecycle());
|
||||
liveItem.setWorkflow(draftItem.getWorkflow());
|
||||
|
||||
draftItem.getCategories().forEach(categorization -> categoryManager
|
||||
.addObjectToCategory(item, categorization.getCategory()));
|
||||
|
||||
liveItem.setUuid(draftItem.getUuid());
|
||||
|
||||
// !!!!!!!!!!!!!!!!!!!!!
|
||||
// ToDo copy Attachments
|
||||
// !!!!!!!!!!!!!!!!!!!!!
|
||||
//
|
||||
//
|
||||
final BeanInfo beanInfo;
|
||||
try {
|
||||
beanInfo = Introspector.getBeanInfo(item.getClass());
|
||||
} catch (IntrospectionException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
for (final PropertyDescriptor propertyDescriptor : beanInfo
|
||||
.getPropertyDescriptors()) {
|
||||
|
||||
if (propertyIsExcluded(propertyDescriptor.getName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final Class<?> propType = propertyDescriptor.getPropertyType();
|
||||
final Method readMethod = propertyDescriptor.getReadMethod();
|
||||
final Method writeMethod = propertyDescriptor.getWriteMethod();
|
||||
|
||||
if (LocalizedString.class.equals(propType)) {
|
||||
final LocalizedString source;
|
||||
final LocalizedString target;
|
||||
try {
|
||||
source = (LocalizedString) readMethod.invoke(draftItem);
|
||||
target = (LocalizedString) readMethod.invoke(liveItem);
|
||||
} catch (IllegalAccessException |
|
||||
IllegalArgumentException |
|
||||
InvocationTargetException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
source.getAvailableLocales().forEach(
|
||||
locale -> target.addValue(locale, source.getValue(locale)));
|
||||
} else if (propType != null
|
||||
&& propType.isAssignableFrom(ContentItem.class)) {
|
||||
final ContentItem linkedItem;
|
||||
try {
|
||||
linkedItem = (ContentItem) readMethod.invoke(draftItem);
|
||||
} catch (IllegalAccessException |
|
||||
IllegalArgumentException |
|
||||
InvocationTargetException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
final ContentItem linkedDraftItem = getDraftVersion(
|
||||
linkedItem, linkedItem.getClass());
|
||||
|
||||
if (isLive(linkedDraftItem)) {
|
||||
try {
|
||||
final Optional<ContentItem> linkedLiveItem
|
||||
= getLiveVersion(
|
||||
linkedDraftItem, ContentItem.class);
|
||||
writeMethod.invoke(liveItem, linkedLiveItem);
|
||||
} catch (IllegalAccessException |
|
||||
IllegalArgumentException |
|
||||
InvocationTargetException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
} else if (propType != null
|
||||
&& propType.isAssignableFrom(List.class)) {
|
||||
final List<Object> source;
|
||||
final List<Object> target;
|
||||
try {
|
||||
source = (List<Object>) readMethod.invoke(draftItem);
|
||||
target = (List<Object>) readMethod.invoke(liveItem);
|
||||
} catch (IllegalAccessException |
|
||||
IllegalArgumentException |
|
||||
InvocationTargetException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
target.addAll(source);
|
||||
} else if (propType != null
|
||||
&& propType.isAssignableFrom(Map.class)) {
|
||||
final Map<Object, Object> source;
|
||||
final Map<Object, Object> target;
|
||||
|
||||
try {
|
||||
source = (Map<Object, Object>) readMethod.invoke(draftItem);
|
||||
target = (Map<Object, Object>) readMethod.invoke(liveItem);
|
||||
} catch (IllegalAccessException |
|
||||
IllegalArgumentException |
|
||||
InvocationTargetException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
source.forEach((key, value) -> target.put(key, value));
|
||||
} else if (propType != null
|
||||
&& propType.isAssignableFrom(Set.class)) {
|
||||
final Set<Object> source;
|
||||
final Set<Object> target;
|
||||
|
||||
try {
|
||||
source = (Set<Object>) readMethod.invoke(draftItem);
|
||||
target = (Set<Object>) readMethod.invoke(liveItem);
|
||||
} catch (IllegalAccessException |
|
||||
IllegalArgumentException |
|
||||
InvocationTargetException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
target.addAll(source);
|
||||
} else {
|
||||
final Object value;
|
||||
try {
|
||||
value = readMethod.invoke(item);
|
||||
writeMethod.invoke(liveItem, value);
|
||||
} catch (IllegalAccessException |
|
||||
IllegalArgumentException |
|
||||
InvocationTargetException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return liveItem;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -165,8 +591,16 @@ public class ContentItemManager {
|
|||
*
|
||||
* @param item
|
||||
*/
|
||||
public void unpublish(final ContentItem item) {
|
||||
throw new UnsupportedOperationException();
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public void unpublish(final ContentItem item
|
||||
) {
|
||||
final Optional<ContentItem> liveItem = getLiveVersion(
|
||||
item, ContentItem.class);
|
||||
|
||||
if (liveItem.isPresent()) {
|
||||
entityManager.remove(liveItem);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -178,7 +612,11 @@ public class ContentItemManager {
|
|||
* {@code false} if not.
|
||||
*/
|
||||
public boolean isLive(final ContentItem item) {
|
||||
throw new UnsupportedOperationException();
|
||||
final TypedQuery<Boolean> query = entityManager.createNamedQuery(
|
||||
"ContentItem.hasLiveVersion", Boolean.class);
|
||||
query.setParameter("uuid", item.getUuid());
|
||||
|
||||
return query.getSingleResult();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -196,7 +634,16 @@ public class ContentItemManager {
|
|||
public <T extends ContentItem> Optional<T> getLiveVersion(
|
||||
final ContentItem item,
|
||||
final Class<T> type) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
||||
if (isLive(item)) {
|
||||
final TypedQuery<T> query = entityManager.createNamedQuery(
|
||||
"ContentItem.findLiveVersion", type);
|
||||
query.setParameter("uuid", item.getUuid());
|
||||
|
||||
return Optional.of(query.getSingleResult());
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -230,7 +677,11 @@ public class ContentItemManager {
|
|||
*/
|
||||
public <T extends ContentItem> T getDraftVersion(final ContentItem item,
|
||||
final Class<T> type) {
|
||||
throw new UnsupportedOperationException();
|
||||
final TypedQuery<T> query = entityManager.createNamedQuery(
|
||||
"ContentItem.findDraftVersion", type);
|
||||
query.setParameter("uuid", item.getUuid());
|
||||
|
||||
return query.getSingleResult();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -262,11 +713,11 @@ public class ContentItemManager {
|
|||
* {@code /research/computer-science/artificial-intelligence/neural-nets}.
|
||||
* If the parameter {@code withContentSection} is set to {@code true} the
|
||||
* the path will be prefixed with the name of the content section. For
|
||||
* instance if the item {@link neural-nets} is part of the content section
|
||||
* instance if the item {@code neural-nets} is part of the content section
|
||||
* {@code info}, the path including the content section would be
|
||||
* {@link info:/research/computer-science/artificial-intelligence/neural-nets}.
|
||||
* {@code info:/research/computer-science/artificial-intelligence/neural-nets}.
|
||||
*
|
||||
* @param item The item which path is generated.
|
||||
* @param item The item whose path is generated.
|
||||
* @param withContentSection Wether to include the content section into the
|
||||
* path.
|
||||
*
|
||||
|
|
@ -339,4 +790,26 @@ public class ContentItemManager {
|
|||
return folders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the folder in which in item is placed (if the item is part of
|
||||
* folder).
|
||||
*
|
||||
* @param item The item
|
||||
*
|
||||
* @return An {@link Optional} containing the folder of the item if the item
|
||||
* is part of a folder.
|
||||
*/
|
||||
public Optional<Category> getItemFolder(final ContentItem item) {
|
||||
final List<Categorization> result = item.getCategories().stream().
|
||||
filter(categorization -> CmsConstants.CATEGORIZATION_TYPE_FOLDER.
|
||||
equals(categorization.getType()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (result.size() > 0) {
|
||||
return Optional.of(result.get(0).getCategory());
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,10 +26,12 @@ import org.libreccm.core.CcmObjectRepository;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.enterprise.context.RequestScoped;
|
||||
import javax.inject.Inject;
|
||||
import javax.persistence.TypedQuery;
|
||||
import jdk.nashorn.internal.objects.NativeArray;
|
||||
|
||||
/**
|
||||
* Repository for content items.
|
||||
|
|
@ -38,7 +40,7 @@ import javax.persistence.TypedQuery;
|
|||
*/
|
||||
@RequestScoped
|
||||
public class ContentItemRepository
|
||||
extends AbstractAuditedEntityRepository<Long, ContentItem> {
|
||||
extends AbstractAuditedEntityRepository<Long, ContentItem> {
|
||||
|
||||
@Inject
|
||||
private CcmObjectRepository ccmObjectRepo;
|
||||
|
|
@ -64,7 +66,7 @@ public class ContentItemRepository
|
|||
* @param itemId The id of item to retrieve.
|
||||
*
|
||||
* @return The content item identified by the provided {@code itemId} or
|
||||
* nothing if there is such content item.
|
||||
* nothing if there is such content item.
|
||||
*/
|
||||
public Optional<ContentItem> findById(final long itemId) {
|
||||
final CcmObject result = ccmObjectRepo.findObjectById(itemId);
|
||||
|
|
@ -78,13 +80,13 @@ public class ContentItemRepository
|
|||
/**
|
||||
* Finds a content item by its ID and ensures that is a the requested type.
|
||||
*
|
||||
* @param <T> The type of the content item.
|
||||
* @param <T> The type of the content item.
|
||||
* @param itemId The id of item to retrieve.
|
||||
* @param type The type of the content item.
|
||||
* @param type The type of the content item.
|
||||
*
|
||||
* @return The content item identified by the provided id or an empty
|
||||
* {@link Optional} if there is no such item or if it is not of the
|
||||
* requested type.
|
||||
* {@link Optional} if there is no such item or if it is not of the
|
||||
* requested type.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends ContentItem> Optional<T> findById(final long itemId,
|
||||
|
|
@ -103,7 +105,7 @@ public class ContentItemRepository
|
|||
* @param uuid The id of item to retrieve.
|
||||
*
|
||||
* @return The content item identified by the provided {@code uuid} or
|
||||
* nothing if there is such content item.
|
||||
* nothing if there is such content item.
|
||||
*/
|
||||
public ContentItem findByUuid(final String uuid) {
|
||||
final CcmObject result = ccmObjectRepo.findObjectByUuid(uuid);
|
||||
|
|
@ -118,13 +120,13 @@ public class ContentItemRepository
|
|||
* Finds a content item by its UUID and ensures that is a the requested
|
||||
* type.
|
||||
*
|
||||
* @param <T> The type of the content item.
|
||||
* @param <T> The type of the content item.
|
||||
* @param uuid The UUID of item to retrieve.
|
||||
* @param type The type of the content item.
|
||||
*
|
||||
* @return The content item identified by the provided UUID or an empty
|
||||
* {@link Optional} if there is no such item or if it is not of the
|
||||
* requested type.
|
||||
* {@link Optional} if there is no such item or if it is not of the
|
||||
* requested type.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends ContentItem> Optional<T> findByUuid(final String uuid,
|
||||
|
|
@ -141,7 +143,7 @@ public class ContentItemRepository
|
|||
/**
|
||||
* Finds all content items of a specific type.
|
||||
*
|
||||
* @param <T> The type of the items.
|
||||
* @param <T> The type of the items.
|
||||
* @param type The type of the items.
|
||||
*
|
||||
* @return A list of all content items of the requested type.
|
||||
|
|
@ -149,7 +151,7 @@ public class ContentItemRepository
|
|||
@SuppressWarnings("unchecked")
|
||||
public <T extends ContentItem> List<T> findByType(final Class<T> type) {
|
||||
final TypedQuery<ContentItem> query = getEntityManager()
|
||||
.createNamedQuery("ContentItem.findByType", ContentItem.class);
|
||||
.createNamedQuery("ContentItem.findByType", ContentItem.class);
|
||||
query.setParameter("type", type);
|
||||
|
||||
return (List<T>) query.getResultList();
|
||||
|
|
@ -163,16 +165,51 @@ public class ContentItemRepository
|
|||
* @return A list of all items in the provided folder.
|
||||
*/
|
||||
public List<ContentItem> findByFolder(final Category folder) {
|
||||
final TypedQuery<CcmObject> query = getEntityManager()
|
||||
.createNamedQuery("ContentItem.findByFolder", CcmObject.class);
|
||||
final TypedQuery<ContentItem> query = getEntityManager()
|
||||
.createNamedQuery("ContentItem.findByFolder",
|
||||
ContentItem.class);
|
||||
query.setParameter("folder", folder);
|
||||
|
||||
final List<ContentItem> result = new ArrayList<>();
|
||||
query.getResultList().stream()
|
||||
.filter(obj -> (obj instanceof ContentItem))
|
||||
.forEach(obj -> result.add((ContentItem) obj));
|
||||
return query.getResultList();
|
||||
}
|
||||
|
||||
public long countItemsInFolder(final Category folder) {
|
||||
final TypedQuery<Long> query = getEntityManager()
|
||||
.createNamedQuery("ContentItem.countItemsInFolder", Long.class);
|
||||
query.setParameter("folder", folder);
|
||||
|
||||
return query.getSingleResult();
|
||||
}
|
||||
|
||||
return result;
|
||||
public long countByNameInFolder(final Category folder, final String name) {
|
||||
final TypedQuery<Long> query = getEntityManager().createNamedQuery(
|
||||
"ContentItem.countByNameInFolder", Long.class);
|
||||
query.setParameter("folder", folder);
|
||||
query.setParameter("name", name);
|
||||
|
||||
return query.getSingleResult();
|
||||
}
|
||||
|
||||
public List<ContentItem> filterByFolderAndName(final Category folder,
|
||||
final String name) {
|
||||
final TypedQuery<ContentItem> query = getEntityManager()
|
||||
.createNamedQuery("ContentItem.filterByNameAndFolder",
|
||||
ContentItem.class);
|
||||
query.setParameter("folder", folder);
|
||||
query.setParameter("name", name);
|
||||
|
||||
return query.getResultList();
|
||||
}
|
||||
|
||||
public long countFilterByFolderAndName(final Category folder,
|
||||
final String name) {
|
||||
final TypedQuery<Long> query = getEntityManager()
|
||||
.createNamedQuery("ContentItem.countFilterByNameAndFolder",
|
||||
Long.class);
|
||||
query.setParameter("folder", folder);
|
||||
query.setParameter("name", name);
|
||||
|
||||
return query.getSingleResult();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ public class ContentSectionConfig {
|
|||
|
||||
public static ContentSectionConfig getConfig() {
|
||||
final ConfigurationManager confManager = CdiUtil.createCdiUtil()
|
||||
.findBean(ConfigurationManager.class);
|
||||
.findBean(ConfigurationManager.class);
|
||||
return confManager.findConfiguration(ContentSectionConfig.class);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
package org.librecms.contentsection;
|
||||
|
||||
import com.arsdigita.cms.dispatcher.ItemResolver;
|
||||
import com.arsdigita.kernel.KernelConfig;
|
||||
|
||||
import org.libreccm.categorization.Category;
|
||||
|
|
@ -34,7 +35,6 @@ import org.libreccm.security.RoleRepository;
|
|||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.enterprise.context.RequestScoped;
|
||||
import javax.inject.Inject;
|
||||
|
|
@ -86,13 +86,13 @@ public class ContentSectionManager {
|
|||
public ContentSection createContentSection(final String name) {
|
||||
if (name == null || name.isEmpty()) {
|
||||
throw new IllegalArgumentException(
|
||||
"The name of a ContentSection can't be blank.");
|
||||
"The name of a ContentSection can't be blank.");
|
||||
}
|
||||
|
||||
final KernelConfig kernelConfig = confManager.findConfiguration(
|
||||
KernelConfig.class);
|
||||
KernelConfig.class);
|
||||
final Locale defautLocale
|
||||
= new Locale(kernelConfig.getDefaultLanguage());
|
||||
= new Locale(kernelConfig.getDefaultLanguage());
|
||||
|
||||
final ContentSection section = new ContentSection();
|
||||
section.setLabel(name);
|
||||
|
|
@ -232,12 +232,12 @@ public class ContentSectionManager {
|
|||
@RequiresPrivilege(CoreConstants.ADMIN_PRIVILEGE)
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public void removeRoleFromContentSection(
|
||||
final ContentSection contentSection,
|
||||
final Role role) {
|
||||
final ContentSection contentSection,
|
||||
final Role role) {
|
||||
|
||||
if (contentSection == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Can't remove role from ContentSection null");
|
||||
"Can't remove role from ContentSection null");
|
||||
}
|
||||
|
||||
if (role == null) {
|
||||
|
|
@ -248,10 +248,10 @@ public class ContentSectionManager {
|
|||
sectionRepo.save(contentSection);
|
||||
|
||||
final TypedQuery<Permission> query = entityManager
|
||||
.createNamedQuery("ContentSection.findPermissions",
|
||||
Permission.class);
|
||||
.createNamedQuery("ContentSection.findPermissions",
|
||||
Permission.class);
|
||||
query.setParameter("section", contentSection);
|
||||
query.setParameter("rootDocumentsFolder",
|
||||
query.setParameter("rootDocumentsFolder",
|
||||
contentSection.getRootDocumentsFolder());
|
||||
query.setParameter("role", role);
|
||||
|
||||
|
|
@ -275,4 +275,16 @@ public class ContentSectionManager {
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public ItemResolver getItemResolver(final ContentSection section) {
|
||||
try {
|
||||
final Class<ItemResolver> itemResolverClazz = (Class<ItemResolver>) Class.
|
||||
forName(section.getItemResolverClass());
|
||||
return itemResolverClazz.newInstance();
|
||||
} catch (ClassNotFoundException |
|
||||
IllegalAccessException |
|
||||
InstantiationException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -285,6 +285,7 @@
|
|||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<groups>org.libreccm.tests.categories.UnitTest</groups>
|
||||
<trimStackTrace>false</trimStackTrace>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
|
|
@ -425,6 +426,9 @@
|
|||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-report-plugin</artifactId>
|
||||
<version>2.19.1</version>
|
||||
<configuration>
|
||||
<trimStackTrace>false</trimStackTrace>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
|
|
@ -708,6 +712,7 @@
|
|||
<additionalClasspathElements>
|
||||
<additionalClasspathElement>${project.build.directory}/generated-resources</additionalClasspathElement>
|
||||
</additionalClasspathElements>
|
||||
<trimStackTrace>false</trimStackTrace>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
|
@ -784,6 +789,7 @@
|
|||
org.libreccm.tests.categories.UnitTest,
|
||||
org.libreccm.tests.categories.IntegrationTest
|
||||
</groups>
|
||||
<trimStackTrace>false</trimStackTrace>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
|
@ -1083,6 +1089,7 @@
|
|||
org.libreccm.tests.categories.UnitTest,
|
||||
org.libreccm.tests.categories.IntegrationTest
|
||||
</groups>
|
||||
<trimStackTrace>false</trimStackTrace>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
|
@ -1169,6 +1176,7 @@
|
|||
org.libreccm.tests.categories.UnitTest,
|
||||
org.libreccm.tests.categories.IntegrationTest
|
||||
</groups>
|
||||
<trimStackTrace>false</trimStackTrace>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.toolbox.ui;
|
||||
|
||||
import com.arsdigita.bebop.Component;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.util.Assert;
|
||||
import com.arsdigita.xml.Element;
|
||||
import java.util.Iterator;
|
||||
import java.util.ArrayList;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
* <p>A simple layout panel with top, bottom, left, right, and body
|
||||
* sections.</p>
|
||||
*
|
||||
* @author Justin Ross <jross@redhat.com>
|
||||
* @version $Id$
|
||||
*/
|
||||
public class ActionGroup extends ComponentSet {
|
||||
|
||||
private static final Logger s_log = Logger.getLogger(ActionGroup.class);
|
||||
|
||||
private Component m_subject;
|
||||
private final ArrayList m_actions = new ArrayList();
|
||||
|
||||
public static final String ADD = "add";
|
||||
public static final String EDIT = "edit";
|
||||
public static final String DELETE = "delete";
|
||||
public static final String RETURN = "return";
|
||||
|
||||
public final void setSubject(final Component subject) {
|
||||
Assert.exists(subject, "Component subject");
|
||||
Assert.isUnlocked(this);
|
||||
|
||||
m_subject = subject;
|
||||
add(m_subject);
|
||||
}
|
||||
|
||||
public final void addAction(final Component action, final String clacc) {
|
||||
Assert.exists(action, "Component action");
|
||||
Assert.isUnlocked(this);
|
||||
|
||||
m_actions.add(new Object[] {action, clacc});
|
||||
add(action);
|
||||
}
|
||||
|
||||
public final void addAction(final Component action) {
|
||||
addAction(action, null);
|
||||
}
|
||||
|
||||
public final void generateXML(final PageState state, final Element parent) {
|
||||
if (isVisible(state)) {
|
||||
final Element layout = parent.newChildElement
|
||||
("bebop:actionGroup", BEBOP_XML_NS);
|
||||
|
||||
final Element subject = layout.newChildElement
|
||||
("bebop:subject", BEBOP_XML_NS);
|
||||
|
||||
if (m_subject != null) {
|
||||
m_subject.generateXML(state, subject);
|
||||
}
|
||||
|
||||
for (Iterator iter = m_actions.iterator(); iter.hasNext(); ) {
|
||||
final Object[] spec = (Object[]) iter.next();
|
||||
final Component component = (Component) spec[0];
|
||||
final String clacc = (String) spec[1];
|
||||
|
||||
if (component.isVisible(state)) {
|
||||
final Element action = layout.newChildElement
|
||||
("bebop:action", BEBOP_XML_NS);
|
||||
|
||||
if (clacc != null) {
|
||||
action.addAttribute("class", clacc);
|
||||
}
|
||||
|
||||
component.generateXML(state, action);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright (C) 2003-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.toolbox.ui;
|
||||
|
||||
import com.arsdigita.bebop.Component;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.Resettable;
|
||||
import com.arsdigita.bebop.SimpleComponent;
|
||||
import com.arsdigita.util.Assert;
|
||||
import com.arsdigita.xml.Element;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @version $Id$
|
||||
*/
|
||||
public class ComponentSet extends SimpleComponent
|
||||
implements Resettable {
|
||||
|
||||
private static final Logger s_log = Logger.getLogger(ComponentSet.class);
|
||||
|
||||
private final ArrayList m_components;
|
||||
|
||||
public ComponentSet() {
|
||||
m_components = new ArrayList();
|
||||
}
|
||||
|
||||
public void reset(final PageState state) {
|
||||
s_log.debug("Resetting children");
|
||||
|
||||
final Iterator iter = children();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
final Object component = iter.next();
|
||||
|
||||
if (component instanceof Resettable) {
|
||||
((Resettable) component).reset(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final Iterator children() {
|
||||
return m_components.iterator();
|
||||
}
|
||||
|
||||
public final void add(final Component component) {
|
||||
Assert.exists(component, "Component component");
|
||||
|
||||
synchronized (m_components) {
|
||||
final int index = m_components.indexOf(component);
|
||||
|
||||
if (index == -1) {
|
||||
m_components.add(component);
|
||||
} else {
|
||||
m_components.set(index, component);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final Component get(final int index) {
|
||||
return (Component) m_components.get(index);
|
||||
}
|
||||
|
||||
public final int indexOf(final Component component) {
|
||||
return m_components.indexOf(component);
|
||||
}
|
||||
|
||||
public final boolean contains(final Component component) {
|
||||
return m_components.contains(component);
|
||||
}
|
||||
|
||||
public void generateXML(final PageState state, final Element parent) {
|
||||
if (isVisible(state)) {
|
||||
final Iterator iter = children();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
((Component) iter.next()).generateXML(state, parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright (C) 2002-2004 Red Hat Inc. All Rights Reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
package com.arsdigita.toolbox.ui;
|
||||
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.RequestLocal;
|
||||
import com.arsdigita.globalization.Globalized;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.l10n.GlobalizationHelper;
|
||||
|
||||
/**
|
||||
*
|
||||
* This class holds methods to support consistent formatting across the system.
|
||||
*
|
||||
* @version $Revision$ $Date$
|
||||
* @version $Id$
|
||||
*/
|
||||
public class FormatStandards implements Globalized {
|
||||
|
||||
private static RequestLocal s_dateFormat = new RequestLocal();
|
||||
private static RequestLocal s_dateTimeFormat = new RequestLocal();
|
||||
|
||||
private static void initialize(PageState ps) {
|
||||
Locale l = CdiUtil.createCdiUtil().findBean(GlobalizationHelper.class).
|
||||
getNegotiatedLocale();
|
||||
s_dateFormat.set(ps, DateFormat.getDateInstance(DATE_DISPLAY_FORMAT, l));
|
||||
s_dateTimeFormat.set(ps, DateFormat.getDateTimeInstance(
|
||||
DATE_DISPLAY_FORMAT, TIME_DISPLAY_FORMAT, l));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A globalized DateFormat instance for formatting the date only.
|
||||
* @see #getDateTimeFormat()
|
||||
*/
|
||||
public static DateFormat getDateFormat() {
|
||||
PageState ps = PageState.getPageState();
|
||||
Object obj = s_dateFormat.get(ps);
|
||||
|
||||
if (obj == null) {
|
||||
initialize(ps);
|
||||
obj = s_dateFormat.get(ps);
|
||||
}
|
||||
|
||||
return (DateFormat) obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A globalized DateFormat instance for formatting the date and
|
||||
* time.
|
||||
* @see #getDateFormat()
|
||||
*/
|
||||
public static DateFormat getDateTimeFormat() {
|
||||
PageState ps = PageState.getPageState();
|
||||
Object obj = s_dateTimeFormat.get(ps);
|
||||
|
||||
if (obj == null) {
|
||||
initialize(ps);
|
||||
obj = s_dateTimeFormat.get(ps);
|
||||
}
|
||||
|
||||
return (DateFormat) obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a date value according to formatting standards and localization.
|
||||
* In English This will show the date as "Mmm DD, YYYY" or "Jan 23, 2002."
|
||||
* This method discards the clock time.
|
||||
*
|
||||
* @param d The date to format.
|
||||
* @return A properly formatted date.
|
||||
* @see #formatDateTime(Date)
|
||||
*/
|
||||
public static String formatDate(Date d) {
|
||||
return (d == null) ? null : getDateFormat().format(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a date and time value according to formatting standards and
|
||||
* localization. This method includes the date and the time. In English, it
|
||||
* will appear as "Mmm DD, YYYY HH:MM AM" or "Jan 23, 2002, 5:44 PM.
|
||||
*
|
||||
* @param d The date to format.
|
||||
* @return A properly formatted date and time.
|
||||
*/
|
||||
public static String formatDateTime(Date d) {
|
||||
return (d == null) ? null : getDateTimeFormat().format(d);
|
||||
}
|
||||
}
|
||||
|
|
@ -65,20 +65,38 @@ public abstract class AbstractAuditedEntityRepository<K, T>
|
|||
/**
|
||||
* Retrieves the number of revisions for a given entity.
|
||||
*
|
||||
* @param entity The entity
|
||||
* @param entity The entity
|
||||
* @param objectId The primary key
|
||||
*
|
||||
* @return A list of revision numbers, at which the entity was modified,
|
||||
* sorted in ascending order (so older revisions come first).
|
||||
*
|
||||
* @throws NotAuditedException When entities of the given class are not
|
||||
* audited.
|
||||
* @throws NotAuditedException When entities of the given class are not
|
||||
* audited.
|
||||
* @throws IllegalArgumentException If cls or primaryKey is null.
|
||||
* @throws IllegalStateException If the associated entity manager is closed.
|
||||
* @throws IllegalStateException If the associated entity manager is
|
||||
* closed.
|
||||
*/
|
||||
public List<Number> retrieveRevisionNumbersOfEntity(final T entity,
|
||||
final Long objectId) {
|
||||
return auditReader.getRevisions(entity.getClass(), objectId);
|
||||
}
|
||||
|
||||
public CcmRevision retrieveFirstRevision(final T entity,
|
||||
final Long objectId) {
|
||||
final List<Number> revisions = retrieveRevisionNumbersOfEntity(
|
||||
entity, objectId);
|
||||
|
||||
return auditReader.findRevision(CcmRevision.class, revisions.get(0));
|
||||
}
|
||||
|
||||
public CcmRevision retrieveCurrentRevision(final T entity,
|
||||
final Long objectId) {
|
||||
final List<Number> revisions = retrieveRevisionNumbersOfEntity(
|
||||
entity, objectId);
|
||||
final Number lastRevision = revisions.get(revisions.size() - 1);
|
||||
|
||||
return auditReader.findRevision(CcmRevision.class, lastRevision);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,10 +48,23 @@ import javax.persistence.Table;
|
|||
@Entity
|
||||
@Table(name = "CATEGORIZATIONS", schema = DB_SCHEMA)
|
||||
@NamedQueries({
|
||||
@NamedQuery(name = "Categorization.find",
|
||||
query = "SELECT c FROM Categorization c "
|
||||
+ "WHERE c.category = :category "
|
||||
+ "AND c.categorizedObject = :object")
|
||||
@NamedQuery(
|
||||
name = "Categorization.find",
|
||||
query = "SELECT c FROM Categorization c "
|
||||
+ "WHERE c.category = :category "
|
||||
+ "AND c.categorizedObject = :object"),
|
||||
@NamedQuery(
|
||||
name = "Categorization.findIndexObject",
|
||||
query = "SELECT c.categorizedObject FROM Categorization c "
|
||||
+ "WHERE c.category = :category "
|
||||
+ "AND c.index = TRUE"),
|
||||
@NamedQuery(
|
||||
name = "Categorization.hasIndexObject",
|
||||
query = "SELECT (CASE WHEN COUNT(c.categorizedObject) > 0 THEN true "
|
||||
+ "ELSE false END) "
|
||||
+ "FROM Categorization c "
|
||||
+ "WHERE c.category = :category "
|
||||
+ "AND c.index = TRUE")
|
||||
})
|
||||
public class Categorization implements Serializable {
|
||||
|
||||
|
|
|
|||
|
|
@ -25,11 +25,15 @@ import org.apache.logging.log4j.Logger;
|
|||
import org.libreccm.core.CcmObject;
|
||||
import org.libreccm.core.CcmObjectRepository;
|
||||
import org.libreccm.security.AuthorizationRequired;
|
||||
import org.libreccm.security.PermissionChecker;
|
||||
import org.libreccm.security.RequiresPrivilege;
|
||||
import org.libreccm.security.Shiro;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
import javax.enterprise.context.RequestScoped;
|
||||
import javax.inject.Inject;
|
||||
|
|
@ -65,6 +69,9 @@ public class CategoryManager {
|
|||
@Inject
|
||||
private Shiro shiro;
|
||||
|
||||
@Inject
|
||||
private PermissionChecker permissionChecker;
|
||||
|
||||
/**
|
||||
* Assigns an category to an object.
|
||||
*
|
||||
|
|
@ -89,6 +96,35 @@ public class CategoryManager {
|
|||
@RequiresPrivilege(MANAGE_CATEGORY_OBJECTS_PRIVILEGE)
|
||||
final Category category) {
|
||||
|
||||
addObjectToCategory(object, category, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns an category to an object.
|
||||
*
|
||||
* Please note: Because the association between {@link Category} and {@code
|
||||
* CcmObject} is a many-to-many association we use an association object to
|
||||
* store the additional attributes of the association. The
|
||||
* {@link Categorization} entity is completely managed by this class.
|
||||
*
|
||||
* If either {@code object} or the {@code category} parameter are
|
||||
* {@code null} an {@link IllegalArgumentException} is thrown because
|
||||
* passing {@code null} to this method indicates a programming error.
|
||||
*
|
||||
* @param object The object to assign to the category. Can never be
|
||||
* {@code null}.
|
||||
* @param category The category to which the object should be assigned. Can
|
||||
* never be {@code null}.
|
||||
* @param type Type of the categorisation.
|
||||
*/
|
||||
@AuthorizationRequired
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public void addObjectToCategory(
|
||||
final CcmObject object,
|
||||
@RequiresPrivilege(MANAGE_CATEGORY_OBJECTS_PRIVILEGE)
|
||||
final Category category,
|
||||
final String type) {
|
||||
|
||||
if (object == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Null can't be added to a category.");
|
||||
|
|
@ -104,11 +140,12 @@ public class CategoryManager {
|
|||
categorization.setCategory(category);
|
||||
categorization.setCategoryOrder(object.getCategories().size() + 1);
|
||||
categorization.setObjectOrder(category.getObjects().size() + 1);
|
||||
categorization.setType(type);
|
||||
|
||||
object.addCategory(categorization);
|
||||
category.addObject(categorization);
|
||||
|
||||
// To saving a category requires the manage_category privilege which
|
||||
// Saving a category requires the manage_category privilege which
|
||||
// may has not been granted to a user which is allowed to assign objects
|
||||
// to a category. Therefore we bypass the this authorisation check here
|
||||
// by executing CategoryRepository#save(Category) as the system user.
|
||||
|
|
@ -595,4 +632,65 @@ public class CategoryManager {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path of a category as string. The path of a category are the
|
||||
* names of all its parent categories and the category joined together,
|
||||
* separated by a slash.
|
||||
*
|
||||
* @param category The category whose path is generated.
|
||||
*
|
||||
* @return The path of the category.
|
||||
*/
|
||||
public String getCategoryPath(final Category category) {
|
||||
final List<String> tokens = new ArrayList<>();
|
||||
|
||||
Category current = category;
|
||||
while (current.getParentCategory() != null) {
|
||||
tokens.add(current.getDisplayName());
|
||||
current = current.getParentCategory();
|
||||
}
|
||||
|
||||
Collections.reverse(tokens);
|
||||
final StringJoiner joiner = new StringJoiner("/", "/", "");
|
||||
tokens.forEach(joiner::add);
|
||||
|
||||
return joiner.toString();
|
||||
}
|
||||
|
||||
public boolean hasIndexObject(final Category category) {
|
||||
// final TypedQuery<Long> hasIndexItemQuery = entityManager
|
||||
// .createNamedQuery("Categorization.hasIndexObject", Long.class);
|
||||
// hasIndexItemQuery.setParameter("category", category);
|
||||
// final long indexItems = hasIndexItemQuery.getSingleResult();
|
||||
// return indexItems > 0;
|
||||
final TypedQuery<Boolean> query = entityManager
|
||||
.createNamedQuery("Categorization.hasIndexObject", Boolean.class);
|
||||
query.setParameter("category", category);
|
||||
|
||||
return query.getSingleResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves to index object of a category. The caller is responsible for
|
||||
* checking if the current user has sufficient privileges to read the index
|
||||
* object!
|
||||
*
|
||||
* @param category The category of which the index object should be
|
||||
* retrieved.
|
||||
*
|
||||
* @return An {@link Optional} containing the index object of the provided
|
||||
* category if the category has an index object.
|
||||
*/
|
||||
public Optional<CcmObject> getIndexObject(final Category category) {
|
||||
if (hasIndexObject(category)) {
|
||||
final TypedQuery<CcmObject> query = entityManager.createNamedQuery(
|
||||
"Categorization.findIndexObject", CcmObject.class);
|
||||
query.setParameter("category", category);
|
||||
|
||||
return Optional.of(query.getSingleResult());
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,11 +87,11 @@ public class PermissionChecker {
|
|||
return result;
|
||||
} else if (object instanceof InheritsPermissions) {
|
||||
if (((InheritsPermissions) object).getParent().isPresent()) {
|
||||
return result;
|
||||
} else {
|
||||
return isPermitted(
|
||||
privilege,
|
||||
((InheritsPermissions) object).getParent().get());
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
return result;
|
||||
|
|
@ -141,17 +141,15 @@ public class PermissionChecker {
|
|||
|
||||
if (!result) {
|
||||
if (((InheritsPermissions) object).getParent().isPresent()) {
|
||||
if (subject.isAuthenticated()) {
|
||||
subject.checkPermission(generatePermissionString(
|
||||
privilege, object));
|
||||
} else {
|
||||
shiro.getPublicUser().checkPermission(
|
||||
generatePermissionString(privilege, object));
|
||||
}
|
||||
} else {
|
||||
checkPermission(
|
||||
privilege,
|
||||
((InheritsPermissions) object).getParent().get());
|
||||
} else if (subject.isAuthenticated()) {
|
||||
subject.checkPermission(generatePermissionString(
|
||||
privilege, object));
|
||||
} else {
|
||||
shiro.getPublicUser().checkPermission(
|
||||
generatePermissionString(privilege, object));
|
||||
}
|
||||
}
|
||||
} else if (subject.isAuthenticated()) {
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ import org.libreccm.security.Shiro;
|
|||
import org.libreccm.tests.categories.IntegrationTest;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.persistence.EntityManager;
|
||||
|
|
@ -582,5 +582,34 @@ public class CategoryManagerTest {
|
|||
categoryManager.addSubCategoryToCategory(test, categories);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@UsingDataSet(
|
||||
"datasets/org/libreccm/categorization/CategoryManagerTest/data.yml")
|
||||
@InSequence(6000)
|
||||
public void hasIndexObject() {
|
||||
final Category category1 = categoryRepo.findById(-2100L);
|
||||
final Category category2 = categoryRepo.findById(-2200L);
|
||||
|
||||
assertThat(categoryManager.hasIndexObject(category1), is(false));
|
||||
assertThat(categoryManager.hasIndexObject(category2), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
@UsingDataSet(
|
||||
"datasets/org/libreccm/categorization/CategoryManagerTest/data.yml")
|
||||
@InSequence(6500)
|
||||
public void getIndexObject() {
|
||||
final Category category1 = categoryRepo.findById(-2100L);
|
||||
final Category category2 = categoryRepo.findById(-2200L);
|
||||
|
||||
assertThat(categoryManager.getIndexObject(category1).isPresent(),
|
||||
is(false));
|
||||
|
||||
final Optional<CcmObject> index2 = categoryManager.getIndexObject(
|
||||
category2);
|
||||
assertThat(index2.isPresent(), is(true));
|
||||
assertThat(index2.get().getDisplayName(), is(equalTo("object3")));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ CREATE SCHEMA ccm_core;
|
|||
CATEGORY_ORDER bigint,
|
||||
CATEGORY_INDEX boolean,
|
||||
OBJECT_ORDER bigint,
|
||||
TYPE varchar(255),
|
||||
OBJECT_ID bigint,
|
||||
CATEGORY_ID bigint,
|
||||
primary key (CATEGORIZATION_ID)
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ CREATE SCHEMA ccm_core;
|
|||
CATEGORY_ORDER int8,
|
||||
CATEGORY_INDEX boolean,
|
||||
OBJECT_ORDER int8,
|
||||
TYPE varchar(255),
|
||||
OBJECT_ID int8,
|
||||
CATEGORY_ID int8,
|
||||
primary key (CATEGORIZATION_ID)
|
||||
|
|
|
|||
|
|
@ -71,4 +71,4 @@ ccm_core.categorizations:
|
|||
category_id: -2100
|
||||
category_order: 1
|
||||
object_order: 2
|
||||
category_index: false
|
||||
category_index: true
|
||||
|
|
@ -76,4 +76,4 @@ ccm_core.categorizations:
|
|||
object_id: -3300
|
||||
category_order: 1
|
||||
object_order: 1
|
||||
category_index: false
|
||||
category_index: true
|
||||
|
|
@ -109,4 +109,4 @@ ccm_core.categorizations:
|
|||
object_id: -3300
|
||||
category_order: 1
|
||||
object_order: 1
|
||||
category_index: false
|
||||
category_index: true
|
||||
|
|
@ -59,4 +59,4 @@ ccm_core.categorizations:
|
|||
object_id: -3300
|
||||
category_order: 1
|
||||
object_order: 1
|
||||
category_index: false
|
||||
category_index: true
|
||||
|
|
|
|||
|
|
@ -64,4 +64,4 @@ ccm_core.categorizations:
|
|||
object_id: -3300
|
||||
category_order: 1
|
||||
object_order: 1
|
||||
category_index: false
|
||||
category_index: true
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ ccm_core.categorizations:
|
|||
object_id: -3300
|
||||
category_order: 1
|
||||
object_order: 1
|
||||
category_index: false
|
||||
category_index: true
|
||||
|
||||
ccm_core.parties:
|
||||
- party_id: -3000
|
||||
|
|
|
|||
Loading…
Reference in New Issue