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;
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>The <tt>ItemResolver</tt> is responsible for mapping a URL in a
|
* <p>
|
||||||
* particular content section to a content item.</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>
|
* <tt>http://yourserver/cms/cheese</tt>:</p>
|
||||||
*
|
*
|
||||||
* <p>The item resolver would be asked to map the URL stub <tt>/cheese</tt>
|
* <p>
|
||||||
* in the content section mounted at <tt>/cms</tt> to a content item. To
|
* The item resolver would be asked to map the URL stub <tt>/cheese</tt>
|
||||||
* this end, the dispatcher calls the <tt>getItem</tt> method, passing in
|
* in the content section mounted at <tt>/cms</tt> to a content item. To this
|
||||||
* the {@link com.arsdigita.cms.ContentSection} and the URL stub for the
|
* end, the dispatcher calls the <tt>getItem</tt> method, passing in the
|
||||||
* item within the section, <tt>/cheese</tt> in our example. As a final
|
* {@link com.arsdigita.cms.ContentSection} and the URL stub for the item within
|
||||||
* argument, the dispatcher passes either <tt>ContentItem.DRAFT</tt> or
|
* the section, <tt>/cheese</tt> in our example. As a final argument, the
|
||||||
* <tt>ContentItem.LIVE</tt> to the <tt>ItemResolver</tt>, depending on
|
* dispatcher passes either <tt>ContentItem.DRAFT</tt> or
|
||||||
* whether the returned item should be the live version (for public pages)
|
* <tt>ContentItem.LIVE</tt> to the <tt>ItemResolver</tt>, depending on whether
|
||||||
* or the draft version (for previewing).</p>
|
* 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 Michael Pih (pihman@arsdigita.com)
|
||||||
* @author Stanislav Freidin (sfreidin@arsdigita.com)
|
* @author Stanislav Freidin (sfreidin@arsdigita.com)
|
||||||
|
|
@ -60,7 +63,8 @@ public interface ItemResolver {
|
||||||
* @param context The use context
|
* @param context The use context
|
||||||
* @return The content item, or null if no such item exists
|
* @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);
|
String context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -82,10 +86,11 @@ public interface ItemResolver {
|
||||||
* @return The URL of the item
|
* @return The URL of the item
|
||||||
* @see #getCurrentContext
|
* @see #getCurrentContext
|
||||||
*/
|
*/
|
||||||
public String generateItemURL (
|
public String generateItemURL(PageState state,
|
||||||
PageState state, BigDecimal itemId, String name,
|
Long itemId,
|
||||||
ContentSection section, String context
|
String name,
|
||||||
);
|
ContentSection section,
|
||||||
|
String context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a URL for a content item.
|
* Generates a URL for a content item.
|
||||||
|
|
@ -99,9 +104,12 @@ public interface ItemResolver {
|
||||||
* @return The URL of the item
|
* @return The URL of the item
|
||||||
* @see #getCurrentContext
|
* @see #getCurrentContext
|
||||||
*/
|
*/
|
||||||
public String generateItemURL (
|
public String generateItemURL(PageState state,
|
||||||
PageState state, BigDecimal itemId, String name,
|
Long itemId,
|
||||||
ContentSection section, String context, String templateContext
|
String name,
|
||||||
|
ContentSection section,
|
||||||
|
String context,
|
||||||
|
String templateContext
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -114,9 +122,10 @@ public interface ItemResolver {
|
||||||
* @return The URL of the item
|
* @return The URL of the item
|
||||||
* @see #getCurrentContext
|
* @see #getCurrentContext
|
||||||
*/
|
*/
|
||||||
public String generateItemURL (
|
public String generateItemURL(PageState state,
|
||||||
PageState state, ContentItem item, ContentSection section, String context
|
ContentItem item,
|
||||||
);
|
ContentSection section,
|
||||||
|
String context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a URL for a content item.
|
* Generates a URL for a content item.
|
||||||
|
|
@ -129,10 +138,11 @@ public interface ItemResolver {
|
||||||
* @return The URL of the item
|
* @return The URL of the item
|
||||||
* @see #getCurrentContext
|
* @see #getCurrentContext
|
||||||
*/
|
*/
|
||||||
public String generateItemURL (
|
public String generateItemURL(PageState state,
|
||||||
PageState state, ContentItem item, ContentSection section, String context,
|
ContentItem item,
|
||||||
String templateContext
|
ContentSection section,
|
||||||
);
|
String context,
|
||||||
|
String templateContext);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a master page based on page state (and content section).
|
* Return a master page based on page state (and content section).
|
||||||
|
|
@ -153,10 +163,10 @@ public interface ItemResolver {
|
||||||
* template contexts, and TemplateResolver sets the actual template contexts
|
* template contexts, and TemplateResolver sets the actual template contexts
|
||||||
* in the request.
|
* in the request.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the template context from the URL and returns it, if it is there.
|
* Finds the template context from the URL and returns it, if it is there.
|
||||||
* Otherwise, returns null.
|
* Otherwise, returns null.
|
||||||
|
*
|
||||||
* @param inUrl the URL from which to get the template context
|
* @param inUrl the URL from which to get the template context
|
||||||
* @return the template context, or null if there is no template context
|
* @return the template context, or null if there is no template context
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -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.table.TableColumn;
|
||||||
import com.arsdigita.bebop.tree.TreeCellRenderer;
|
import com.arsdigita.bebop.tree.TreeCellRenderer;
|
||||||
import com.arsdigita.cms.CMS;
|
import com.arsdigita.cms.CMS;
|
||||||
import com.arsdigita.cms.CMSConfig;
|
import com.arsdigita.globalization.GlobalizedMessage;
|
||||||
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.toolbox.ui.ActionGroup;
|
import com.arsdigita.toolbox.ui.ActionGroup;
|
||||||
import com.arsdigita.util.Assert;
|
import com.arsdigita.util.Assert;
|
||||||
import com.arsdigita.util.UncheckedWrapperException;
|
import com.arsdigita.util.UncheckedWrapperException;
|
||||||
import com.arsdigita.web.Web;
|
import com.arsdigita.web.Web;
|
||||||
import com.arsdigita.workflow.simple.TaskException;
|
|
||||||
import com.arsdigita.workflow.simple.Workflow;
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
|
|
@ -99,12 +74,26 @@ import org.apache.log4j.Logger;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
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).
|
* Browse folders and manipulate them with various actions (move/copy/delete).
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:lutter@arsdigita.com">David Lutterkort</a>
|
* @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")
|
@SuppressWarnings("PMD.BeanMembersShouldSerialize")
|
||||||
public class FolderManipulator extends SimpleContainer implements
|
public class FolderManipulator extends SimpleContainer implements
|
||||||
|
|
@ -114,9 +103,8 @@ public class FolderManipulator extends SimpleContainer implements
|
||||||
Resettable {
|
Resettable {
|
||||||
|
|
||||||
//public static final String RESOURCE_BUNDLE = "com.arsdigita.cms.ui.folder.CMSFolderResources";
|
//public static final String RESOURCE_BUNDLE = "com.arsdigita.cms.ui.folder.CMSFolderResources";
|
||||||
private final GlobalisationUtil globalizationUtil = new com.arsdigita.toolbox.GlobalisationUtil(
|
private static final Logger LOGGER = Logger.getLogger(
|
||||||
"com.arsdigita.cms.ui.folder.CMSFolderResources");
|
FolderManipulator.class);
|
||||||
private static final Logger LOGGER = Logger.getLogger(FolderManipulator.class);
|
|
||||||
private static final String ATOZ_FILTER_PARAM = "aToZfilter";
|
private static final String ATOZ_FILTER_PARAM = "aToZfilter";
|
||||||
private static final String ACTION_PARAM = "act";
|
private static final String ACTION_PARAM = "act";
|
||||||
private static final String FILTER_PARAM = "filter";
|
private static final String FILTER_PARAM = "filter";
|
||||||
|
|
@ -140,7 +128,8 @@ public class FolderManipulator extends SimpleContainer implements
|
||||||
//private final PublishDialog publishDialog = new PublishDialog();
|
//private final PublishDialog publishDialog = new PublishDialog();
|
||||||
|
|
||||||
private FilterForm filterForm;
|
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);
|
private final StringParameter filterParam = new StringParameter(FILTER_PARAM);
|
||||||
|
|
||||||
public FolderManipulator(final FolderSelectionModel folderModel) {
|
public FolderManipulator(final FolderSelectionModel folderModel) {
|
||||||
|
|
@ -154,12 +143,13 @@ public class FolderManipulator extends SimpleContainer implements
|
||||||
add(itemView);
|
add(itemView);
|
||||||
|
|
||||||
targetSelector.addProcessListener(new TargetSelectorProcessListener());
|
targetSelector.addProcessListener(new TargetSelectorProcessListener());
|
||||||
targetSelector.addValidationListener(new TargetSelectorValidationListener());
|
targetSelector.addValidationListener(
|
||||||
targetSelector.addSubmissionListener(new TargetSelectorSubmissionListener());
|
new TargetSelectorValidationListener());
|
||||||
|
targetSelector.addSubmissionListener(
|
||||||
|
new TargetSelectorSubmissionListener());
|
||||||
add(targetSelector);
|
add(targetSelector);
|
||||||
|
|
||||||
//publishDialog.addProcessListener(new PublishDialogProcessListener());
|
//publishDialog.addProcessListener(new PublishDialogProcessListener());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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.
|
//Return empty array instead of null.
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
return new BigDecimal[0];
|
return new Long[0];
|
||||||
} else {
|
} else {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -191,7 +181,7 @@ public class FolderManipulator extends SimpleContainer implements
|
||||||
return sourceFolderModel;
|
return sourceFolderModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final Folder getTarget(final PageState state) {
|
public final Category getTarget(final PageState state) {
|
||||||
return targetSelector.getTarget(state);
|
return targetSelector.getTarget(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -210,61 +200,58 @@ public class FolderManipulator extends SimpleContainer implements
|
||||||
// protected final boolean isUnPublish(final PageState state) {
|
// protected final boolean isUnPublish(final PageState state) {
|
||||||
// return UNPUBLISH.equals(getAction(state));
|
// return UNPUBLISH.equals(getAction(state));
|
||||||
// }
|
// }
|
||||||
|
|
||||||
private String getAction(final PageState state) {
|
private String getAction(final PageState state) {
|
||||||
return (String) state.getValue(actionParam);
|
return (String) state.getValue(actionParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void moveItems(final Folder target, final BigDecimal[] itemIds) {
|
protected void moveItems(final Category target,
|
||||||
|
final Long[] itemIds) {
|
||||||
|
|
||||||
|
for (Long itemId : itemIds) {
|
||||||
|
|
||||||
for (BigDecimal itemId : itemIds) {
|
|
||||||
try {
|
|
||||||
changeItemParent(itemId, target);
|
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()));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void changeItemParent(final BigDecimal itemId, final Folder newParent)
|
private void changeItemParent(final Long itemId, final Category newParent) {
|
||||||
throws DataObjectNotFoundException {
|
|
||||||
|
|
||||||
final ContentItem item = new ContentItem(itemId);
|
//ToDo
|
||||||
item.setParent(newParent);
|
throw new UnsupportedOperationException();
|
||||||
item.save();
|
|
||||||
|
|
||||||
|
// 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,
|
protected void copyItems(final Category target,
|
||||||
final BigDecimal[] itemIds) {
|
final Long[] itemIds) {
|
||||||
|
|
||||||
if (LOGGER.isDebugEnabled()) {
|
//ToDo
|
||||||
LOGGER.debug("Copying items " + Arrays.asList(itemIds) + " to " + target);
|
throw new UnsupportedOperationException();
|
||||||
}
|
|
||||||
for (BigDecimal itemId : itemIds) {
|
|
||||||
|
|
||||||
// ContentItem source = (ContentItem) DomainObjectFactory.newInstance(
|
|
||||||
// new OID(ContentItem.BASE_DATA_OBJECT_TYPE, itemId));
|
|
||||||
// Assert.exists(source, ContentItem.class);
|
|
||||||
//
|
|
||||||
// final ACSObject parent = source.getParent();
|
|
||||||
// if (parent instanceof ContentBundle) {
|
|
||||||
// source = (ContentBundle) parent;
|
|
||||||
// }
|
|
||||||
//
|
//
|
||||||
// if (LOGGER.isDebugEnabled()) {
|
// if (LOGGER.isDebugEnabled()) {
|
||||||
// LOGGER.debug("Copying item " + source);
|
// LOGGER.debug("Copying items " + Arrays.asList(itemIds) + " to "
|
||||||
|
// + target);
|
||||||
|
// }
|
||||||
|
// for (BigDecimal itemId : itemIds) {
|
||||||
|
//
|
||||||
|
// 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) {
|
// protected void publishItems(final BigDecimal[] itemIds) {
|
||||||
|
|
@ -291,7 +278,6 @@ public class FolderManipulator extends SimpleContainer implements
|
||||||
//
|
//
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// private void publish(final BigDecimal itemId) {
|
// private void publish(final BigDecimal itemId) {
|
||||||
//
|
//
|
||||||
// }
|
// }
|
||||||
|
|
@ -385,27 +371,26 @@ public class FolderManipulator extends SimpleContainer implements
|
||||||
//
|
//
|
||||||
// thread.start();
|
// thread.start();
|
||||||
// }
|
// }
|
||||||
|
// private ContentItem retrieveSourceItem(final BigDecimal itemToCopyId) {
|
||||||
private ContentItem retrieveSourceItem(final BigDecimal itemToCopyId) {
|
//
|
||||||
|
// ContentItem source = (ContentItem) DomainObjectFactory.newInstance(
|
||||||
ContentItem source = (ContentItem) DomainObjectFactory.newInstance(
|
// new OID(ContentItem.BASE_DATA_OBJECT_TYPE, itemToCopyId));
|
||||||
new OID(ContentItem.BASE_DATA_OBJECT_TYPE, itemToCopyId));
|
// Assert.exists(source, ContentItem.class);
|
||||||
Assert.exists(source, ContentItem.class);
|
//
|
||||||
|
// final ACSObject parent = source.getParent();
|
||||||
final ACSObject parent = source.getParent();
|
// if (parent instanceof ContentBundle) {
|
||||||
if (parent instanceof ContentBundle) {
|
// source = (ContentBundle) parent;
|
||||||
source = (ContentBundle) parent;
|
// }
|
||||||
}
|
//
|
||||||
|
// if (LOGGER.isDebugEnabled()) {
|
||||||
if (LOGGER.isDebugEnabled()) {
|
// LOGGER.debug("Copying item " + source);
|
||||||
LOGGER.debug("Copying item " + source);
|
// }
|
||||||
}
|
//
|
||||||
|
// return 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
|
* @return The form containing the folder browser and dropdown menu
|
||||||
*/
|
*/
|
||||||
|
|
@ -438,7 +423,8 @@ public class FolderManipulator extends SimpleContainer implements
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(final FormSectionEvent event) throws FormProcessException {
|
public void process(final FormSectionEvent event) throws
|
||||||
|
FormProcessException {
|
||||||
final PageState state = event.getPageState();
|
final PageState state = event.getPageState();
|
||||||
|
|
||||||
itemView.setVisible(state, false);
|
itemView.setVisible(state, false);
|
||||||
|
|
@ -455,15 +441,16 @@ public class FolderManipulator extends SimpleContainer implements
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(final FormSectionEvent event) throws FormProcessException {
|
public void process(final FormSectionEvent event) throws
|
||||||
|
FormProcessException {
|
||||||
|
|
||||||
final PageState state = event.getPageState();
|
final PageState state = event.getPageState();
|
||||||
|
|
||||||
itemView.setVisible(state, true);
|
itemView.setVisible(state, true);
|
||||||
targetSelector.setVisible(state, false);
|
targetSelector.setVisible(state, false);
|
||||||
|
|
||||||
final Folder folder = targetSelector.getTarget(state);
|
final Category folder = targetSelector.getTarget(state);
|
||||||
final BigDecimal[] itemIds = getSources(state);
|
final Long[] itemIds = getSources(state);
|
||||||
|
|
||||||
if (isCopy(state)) {
|
if (isCopy(state)) {
|
||||||
copyItems(folder, itemIds);
|
copyItems(folder, itemIds);
|
||||||
|
|
@ -503,7 +490,6 @@ public class FolderManipulator extends SimpleContainer implements
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// }
|
// }
|
||||||
|
|
||||||
private class ItemViewValidationListener implements FormValidationListener {
|
private class ItemViewValidationListener implements FormValidationListener {
|
||||||
|
|
||||||
public ItemViewValidationListener() {
|
public ItemViewValidationListener() {
|
||||||
|
|
@ -511,26 +497,30 @@ public class FolderManipulator extends SimpleContainer implements
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validate(final FormSectionEvent event) throws FormProcessException {
|
public void validate(final FormSectionEvent event) throws
|
||||||
|
FormProcessException {
|
||||||
|
|
||||||
final PageState state = event.getPageState();
|
final PageState state = event.getPageState();
|
||||||
final FormData data = event.getFormData();
|
final FormData data = event.getFormData();
|
||||||
|
|
||||||
if (getSources(state).length <= 0) {
|
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() {
|
public TargetSelectorValidationListener() {
|
||||||
//Nothing
|
//Nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validate(final FormSectionEvent event) throws FormProcessException {
|
public void validate(final FormSectionEvent event) throws
|
||||||
|
FormProcessException {
|
||||||
|
|
||||||
final PageState state = event.getPageState();
|
final PageState state = event.getPageState();
|
||||||
|
|
||||||
|
|
@ -538,70 +528,82 @@ public class FolderManipulator extends SimpleContainer implements
|
||||||
throw new IllegalStateException("No source items specified");
|
throw new IllegalStateException("No source items specified");
|
||||||
}
|
}
|
||||||
|
|
||||||
final Folder target = targetSelector.getTarget(state);
|
final Category target = targetSelector.getTarget(state);
|
||||||
final FormData data = event.getFormData();
|
final FormData data = event.getFormData();
|
||||||
if (target == null) {
|
if (target == null) {
|
||||||
data.addError(globalizationUtil.globalize(
|
data.addError(new GlobalizedMessage(
|
||||||
"cms.ui.folder.need_select_target_folder"));
|
"cms.ui.folder.need_select_target_folder",
|
||||||
|
CmsConstants.CMS_FOLDER_BUNDLE));
|
||||||
//If the target is null, we can skip the rest of the checks
|
//If the target is null, we can skip the rest of the checks
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target.equals(sourceFolderModel.getSelectedObject(state))) {
|
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
|
// check create item permission
|
||||||
final User user = Web.getWebContext().getUser();
|
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||||
final SecurityManager securityManager = CMS.getSecurityManager(state);
|
final Shiro shiro = cdiUtil.findBean(Shiro.class);
|
||||||
if (!securityManager.canAccess(user, SecurityManager.NEW_ITEM, target)) {
|
final PermissionChecker permissionChecker = cdiUtil.findBean(
|
||||||
data.addError(globalizationUtil.globalize("cms.ui.folder.no_permission_for_item"));
|
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)) {
|
for (Long source : getSources(state)) {
|
||||||
try {
|
|
||||||
validateItem(source, target, state, data);
|
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()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateItem(final BigDecimal itemId,
|
private void validateItem(final Long itemId,
|
||||||
final Folder target,
|
final Category target,
|
||||||
final PageState state,
|
final PageState state,
|
||||||
final FormData data) {
|
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 ContentItem item = itemRepo.findById(itemId);
|
||||||
final String name = item.getName();
|
final String name = item.getDisplayName();
|
||||||
|
|
||||||
final ItemCollection items = target.getItems();
|
final long count = itemRepo.countByNameInFolder(target, name);
|
||||||
items.addNameFilter(name);
|
if (count > 0) {
|
||||||
if (items.next()) {
|
|
||||||
// there is an item in the target folder that already has this name
|
// there is an item in the target folder that already has this name
|
||||||
addErrorMessage(data, "cms.ui.folder.item_already_exists", 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);
|
addErrorMessage(data, "cms.ui.folder.item_is_live", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
final SecurityManager securityManager = CMS.getSecurityManager(state);
|
if (!(permissionChecker.isPermitted(
|
||||||
final User user = Web.getWebContext().getUser();
|
CmsConstants.PRIVILEGE_ITEMS_DELETE, item))
|
||||||
if ((!securityManager.canAccess(user, SecurityManager.DELETE_ITEM, item))
|
|
||||||
&& isMove(state)) {
|
&& isMove(state)) {
|
||||||
addErrorMessage(data, "cms.ui.folder.no_permission_for_item", name);
|
addErrorMessage(data, "cms.ui.folder.no_permission_for_item",
|
||||||
|
name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addErrorMessage(final FormData data, final String message, final String itemName) {
|
private void addErrorMessage(final FormData data,
|
||||||
data.addError(globalizationUtil.globalize(message, new Object[]{itemName}));
|
final String message,
|
||||||
|
final String itemName) {
|
||||||
|
data.addError(new GlobalizedMessage(message,
|
||||||
|
CmsConstants.CMS_FOLDER_BUNDLE,
|
||||||
|
new Object[]{itemName}));
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Override
|
// @Override
|
||||||
|
|
@ -615,20 +617,24 @@ public class FolderManipulator extends SimpleContainer implements
|
||||||
//
|
//
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
private class TargetSelectorSubmissionListener implements FormSubmissionListener {
|
private class TargetSelectorSubmissionListener implements
|
||||||
|
FormSubmissionListener {
|
||||||
|
|
||||||
public TargetSelectorSubmissionListener() {
|
public TargetSelectorSubmissionListener() {
|
||||||
//Nothing
|
//Nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void submitted(final FormSectionEvent event) throws FormProcessException {
|
public void submitted(final FormSectionEvent event) throws
|
||||||
|
FormProcessException {
|
||||||
|
|
||||||
final PageState state = event.getPageState();
|
final PageState state = event.getPageState();
|
||||||
|
|
||||||
if (targetSelector.isCancelled(state)) {
|
if (targetSelector.isCancelled(state)) {
|
||||||
reset(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 PageState state = event.getPageState();
|
||||||
final Label label = (Label) event.getTarget();
|
final Label label = (Label) event.getTarget();
|
||||||
final int numberOfItems = getSources(state).length;
|
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)) {
|
if (isMove(state)) {
|
||||||
label.setLabel(globalizationUtil.globalize(
|
|
||||||
"cms.ui.folder.move", new Object[]{numberOfItems,
|
label.setLabel(new GlobalizedMessage(
|
||||||
folder.getPathNoJsp()}));
|
"cms.ui.folder.move",
|
||||||
|
CmsConstants.CMS_FOLDER_BUNDLE,
|
||||||
|
new Object[]{numberOfItems,
|
||||||
|
categoryManager.getCategoryPath(
|
||||||
|
folder)}));
|
||||||
} else if (isCopy(state)) {
|
} else if (isCopy(state)) {
|
||||||
label.setLabel(globalizationUtil.globalize(
|
label.setLabel(new GlobalizedMessage(
|
||||||
"cms.ui.folder.copy", new Object[]{numberOfItems,
|
"cms.ui.folder.copy",
|
||||||
folder.getPathNoJsp()}));
|
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
|
// Set things up the first time the selector gets visible
|
||||||
public void expose(final PageState state) {
|
public void expose(final PageState state) {
|
||||||
final Folder folder = (Folder) sourceFolderModel.getSelectedObject(state);
|
final Category folder = (Category) sourceFolderModel.
|
||||||
|
getSelectedObject(
|
||||||
|
state);
|
||||||
targetModel.clearSelection(state);
|
targetModel.clearSelection(state);
|
||||||
if (folder != null) {
|
if (folder != null) {
|
||||||
final ItemCollection items = folder.getPathInfo(true);
|
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||||
while (items.next()) {
|
final ContentItemManager itemManager = cdiUtil.findBean(
|
||||||
folderTree.expand(items.getID().toString(), state);
|
ContentItemManager.class);
|
||||||
}
|
|
||||||
items.close();
|
//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);
|
folderTree.clearSelection(state);
|
||||||
// FIXME: add a reset method to Tree and call that instead of this
|
// FIXME: add a reset method to Tree and call that instead of this
|
||||||
// hack
|
// hack
|
||||||
state.setValue(folderTree.getSelectionModel().getStateParameter(), null);
|
state.setValue(folderTree.getSelectionModel().getStateParameter(),
|
||||||
|
null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Folder getTarget(final PageState state) {
|
public Category getTarget(final PageState state) {
|
||||||
return (Folder) targetModel.getSelectedObject(state);
|
return (Category) targetModel.getSelectedObject(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isCancelled(final PageState 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
|
// The form containing the browser and the drop down for selecting an
|
||||||
// action
|
// action
|
||||||
private class ItemView extends Form implements Resettable {
|
private class ItemView extends Form implements Resettable {
|
||||||
|
|
@ -797,13 +821,15 @@ public class FolderManipulator extends SimpleContainer implements
|
||||||
folderBrowser.setAtoZfilterParameter(atozFilterParam);
|
folderBrowser.setAtoZfilterParameter(atozFilterParam);
|
||||||
folderBrowser.setFilterParameter(filterParam);
|
folderBrowser.setFilterParameter(filterParam);
|
||||||
folderBrowser.setFilterForm(filterForm);
|
folderBrowser.setFilterForm(filterForm);
|
||||||
paginator = new Paginator((PaginationModelBuilder) folderBrowser.getModelBuilder(),
|
paginator = new Paginator(
|
||||||
ContentSection.getConfig().getFolderBrowseListSize());
|
(PaginationModelBuilder) folderBrowser.getModelBuilder(),
|
||||||
|
CMSConfig.getConfig().getFolderBrowseListSize());
|
||||||
panel.add(paginator);
|
panel.add(paginator);
|
||||||
panel.add(folderBrowser);
|
panel.add(folderBrowser);
|
||||||
|
|
||||||
LOGGER.debug("Adding filter form...");
|
LOGGER.debug("Adding filter form...");
|
||||||
filterForm = new FilterForm((FilterFormModelBuilder) folderBrowser.getModelBuilder());
|
filterForm = new FilterForm((FilterFormModelBuilder) folderBrowser.
|
||||||
|
getModelBuilder());
|
||||||
FolderManipulator.this.add(filterForm);
|
FolderManipulator.this.add(filterForm);
|
||||||
|
|
||||||
checkboxGroup = new CheckboxGroup(sourcesParam);
|
checkboxGroup = new CheckboxGroup(sourcesParam);
|
||||||
|
|
@ -814,14 +840,20 @@ public class FolderManipulator extends SimpleContainer implements
|
||||||
final Container container = new SimpleContainer();
|
final Container container = new SimpleContainer();
|
||||||
group.addAction(container);
|
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 = new SingleSelect(actionParam);
|
||||||
actionSelect.addOption(new Option(COPY,
|
actionSelect.addOption(
|
||||||
new Label(globalizationUtil.globalize(
|
new Option(COPY,
|
||||||
"cms.ui.folder.copy.action"))));
|
new Label(new GlobalizedMessage(
|
||||||
actionSelect.addOption(new Option(MOVE,
|
"cms.ui.folder.copy.action",
|
||||||
new Label(globalizationUtil.globalize(
|
CmsConstants.CMS_FOLDER_BUNDLE))));
|
||||||
"cms.ui.folder.move.action"))));
|
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
|
//Publishing in the folder browser only works if threaded publishing is active
|
||||||
// if (CMSConfig.getInstanceOf().getThreadedPublishing()) {
|
// if (CMSConfig.getInstanceOf().getThreadedPublishing()) {
|
||||||
// actionSelect.addOption(new Option(PUBLISH,
|
// actionSelect.addOption(new Option(PUBLISH,
|
||||||
|
|
@ -832,7 +864,10 @@ public class FolderManipulator extends SimpleContainer implements
|
||||||
// "cms.ui.folder.unpublish.action"))));
|
// "cms.ui.folder.unpublish.action"))));
|
||||||
// }
|
// }
|
||||||
container.add(actionSelect);
|
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);
|
container.add(submit);
|
||||||
|
|
||||||
// Add a new first column to the table
|
// Add a new first column to the table
|
||||||
|
|
@ -872,7 +907,8 @@ public class FolderManipulator extends SimpleContainer implements
|
||||||
final int row,
|
final int row,
|
||||||
final int column) {
|
final int column) {
|
||||||
final BigDecimal n = (BigDecimal) key;
|
final BigDecimal n = (BigDecimal) key;
|
||||||
Option result = new Option(sourcesParam.marshalElement(n.abs()), "");
|
Option result = new Option(sourcesParam.marshalElement(n.abs()),
|
||||||
|
"");
|
||||||
result.setGroup(checkboxGroup);
|
result.setGroup(checkboxGroup);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -904,7 +940,8 @@ public class FolderManipulator extends SimpleContainer implements
|
||||||
panel = new BoxPanel(BoxPanel.HORIZONTAL);
|
panel = new BoxPanel(BoxPanel.HORIZONTAL);
|
||||||
|
|
||||||
final ActionLink allLink = new ActionLink(
|
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() {
|
allLink.addActionListener(new ActionListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -929,11 +966,15 @@ public class FolderManipulator extends SimpleContainer implements
|
||||||
// });
|
// });
|
||||||
// panel.add(link);
|
// 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);
|
filterField = new TextField(filterParam);
|
||||||
panel.add(filterField);
|
panel.add(filterField);
|
||||||
panel.add(new Submit("filterFolderSubmit",
|
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);
|
add(panel);
|
||||||
|
|
||||||
|
|
@ -944,25 +985,29 @@ public class FolderManipulator extends SimpleContainer implements
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(final FormSectionEvent event) throws FormProcessException {
|
public void process(final FormSectionEvent event) throws
|
||||||
|
FormProcessException {
|
||||||
//Nothing
|
//Nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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);
|
//fse.getPageState().setValue(FolderManipulator.this.m_filter, null);
|
||||||
//filterField.setValue(fse.getPageState(), null);
|
//filterField.setValue(fse.getPageState(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void submitted(final FormSectionEvent event) throws FormProcessException {
|
public void submitted(final FormSectionEvent event) throws
|
||||||
|
FormProcessException {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isVisible(PageState state) {
|
public boolean isVisible(PageState state) {
|
||||||
if (super.isVisible(state)
|
if (super.isVisible(state)
|
||||||
&& (modelBuilder.getFolderSize(state)
|
&& (modelBuilder.getFolderSize(state)
|
||||||
>= CMSConfig.getInstanceOf().getFolderAtoZShowLimit())) {
|
>= CMSConfig.getConfig().
|
||||||
|
getFolderAtoZShowLimit())) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -996,9 +1041,10 @@ public class FolderManipulator extends SimpleContainer implements
|
||||||
private RequestLocal m_invalidFolders = new RequestLocal();
|
private RequestLocal m_invalidFolders = new RequestLocal();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the folders appropriately. The selected folder is a bold label. Invalid folders
|
* Render the folders appropriately. The selected folder is a bold
|
||||||
* are plain labels. Unselected, valid folders are control links. Invalid folders are: the
|
* label. Invalid folders are plain labels. Unselected, valid folders
|
||||||
* parent folder of the sources, any of the sources, and any subfolders of the sources.
|
* are control links. Invalid folders are: the parent folder of the
|
||||||
|
* sources, any of the sources, and any subfolders of the sources.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Component getComponent(final Tree tree,
|
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.
|
// Get the list of invalid folders once per request.
|
||||||
ArrayList invalidFolders = (ArrayList) m_invalidFolders.get(state);
|
ArrayList invalidFolders = (ArrayList) m_invalidFolders.get(state);
|
||||||
|
|
||||||
if (invalidFolders == null) {
|
// if (invalidFolders == null) {
|
||||||
// The list of invalid folders has not been set for this
|
// // The list of invalid folders has not been set for this
|
||||||
// request. Setting now.
|
// // request. Setting now.
|
||||||
invalidFolders = new ArrayList();
|
// invalidFolders = new ArrayList();
|
||||||
|
//
|
||||||
final DataCollection collection = SessionManager.getSession().retrieve(
|
// final DataCollection collection = SessionManager.getSession().
|
||||||
ContentItem.BASE_DATA_OBJECT_TYPE);
|
// retrieve(
|
||||||
CompoundFilter filter = collection.getFilterFactory().or();
|
// ContentItem.BASE_DATA_OBJECT_TYPE);
|
||||||
// The sources themselves are not valid.
|
// CompoundFilter filter = collection.getFilterFactory().or();
|
||||||
final BigDecimal[] sources = getSources(state);
|
// // The sources themselves are not valid.
|
||||||
|
// final Long[] sources = getSources(state);
|
||||||
for (int i = 0; i < sources.length; i++) {
|
//
|
||||||
invalidFolders.add(sources[i].toString());
|
// 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]);
|
// final Filter temp = filter.addFilter("id = :id" + i);
|
||||||
}
|
// temp.set("id" + i, sources[i]);
|
||||||
collection.addFilter(filter);
|
// }
|
||||||
|
// collection.addFilter(filter);
|
||||||
final DataCollection folders = SessionManager.getSession().retrieve(
|
//
|
||||||
Folder.BASE_DATA_OBJECT_TYPE);
|
// final DataCollection folders = SessionManager.getSession().
|
||||||
folders.addEqualsFilter(Folder.IS_DELETED, Boolean.FALSE);
|
// retrieve(
|
||||||
|
// Folder.BASE_DATA_OBJECT_TYPE);
|
||||||
filter = collection.getFilterFactory().or();
|
// folders.addEqualsFilter(Folder.IS_DELETED, Boolean.FALSE);
|
||||||
int count = 0;
|
//
|
||||||
while (collection.next()) {
|
// filter = collection.getFilterFactory().or();
|
||||||
filter.addFilter(Folder.ANCESTORS + " like :ancestors"
|
// int count = 0;
|
||||||
+ count + " || '%'");
|
// while (collection.next()) {
|
||||||
filter.set("ancestors" + count,
|
// filter.addFilter(Folder.ANCESTORS + " like :ancestors"
|
||||||
collection.get(ContentItem.ANCESTORS));
|
// + count + " || '%'");
|
||||||
count++;
|
// filter.set("ancestors" + count,
|
||||||
}
|
// collection.get(ContentItem.ANCESTORS));
|
||||||
folders.addFilter(filter);
|
// count++;
|
||||||
|
// }
|
||||||
while (folders.next()) {
|
// folders.addFilter(filter);
|
||||||
invalidFolders.add(folders.get(Folder.ID).toString());
|
//
|
||||||
}
|
// 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");
|
// invalidFolders.add(sourceFolderModel.getSelectedKey(state).
|
||||||
dq.setParameter("item_list", invalidFolders);
|
// toString());
|
||||||
|
//
|
||||||
while (dq.next()) {
|
// // Save the invalid folder list
|
||||||
invalidFolders.add (dq.get("folder_id").toString());
|
// m_invalidFolders.set(state, invalidFolders);
|
||||||
}
|
// }
|
||||||
*/
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
final Label label = new Label(value.toString());
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -71,7 +71,46 @@ import static org.librecms.CmsConstants.*;
|
||||||
name = "ContentItem.findByFolder",
|
name = "ContentItem.findByFolder",
|
||||||
query = "SELECT c.categorizedObject FROM Categorization c "
|
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,
|
public class ContentItem extends CcmObject implements Serializable,
|
||||||
InheritsPermissions {
|
InheritsPermissions {
|
||||||
|
|
@ -258,7 +297,8 @@ public class ContentItem extends CcmObject implements Serializable,
|
||||||
@Override
|
@Override
|
||||||
public Optional<CcmObject> getParent() {
|
public Optional<CcmObject> getParent() {
|
||||||
final List<Categorization> result = getCategories().stream().filter(
|
final List<Categorization> result = getCategories().stream().filter(
|
||||||
categorization -> CmsConstants.CATEGORIZATION_TYPE_FOLDER.equals(
|
categorization -> CmsConstants.CATEGORIZATION_TYPE_FOLDER.
|
||||||
|
equals(
|
||||||
categorization.getType()))
|
categorization.getType()))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,14 @@
|
||||||
*/
|
*/
|
||||||
package org.librecms.contentsection;
|
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.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
import org.libreccm.categorization.Category;
|
import org.libreccm.categorization.Category;
|
||||||
import org.libreccm.workflow.WorkflowTemplate;
|
import org.libreccm.workflow.WorkflowTemplate;
|
||||||
import org.librecms.lifecycle.LifecycleDefinition;
|
import org.librecms.lifecycle.LifecycleDefinition;
|
||||||
|
|
@ -30,8 +36,31 @@ import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.enterprise.context.RequestScoped;
|
import javax.enterprise.context.RequestScoped;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import org.libreccm.categorization.Categorization;
|
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.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
|
@RequestScoped
|
||||||
public class ContentItemManager {
|
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
|
@Inject
|
||||||
private ContentItemRepository contentItemRepo;
|
private ContentItemRepository contentItemRepo;
|
||||||
|
|
||||||
|
|
@ -49,6 +90,12 @@ public class ContentItemManager {
|
||||||
@Inject
|
@Inject
|
||||||
private ContentSectionManager sectionManager;
|
private ContentSectionManager sectionManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private LifecycleManager lifecycleManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private WorkflowManager workflowManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new content item in the provided content section and folder
|
* Creates a new content item in the provided content section and folder
|
||||||
* with the default lifecycle and workflow.
|
* with the default lifecycle and workflow.
|
||||||
|
|
@ -65,6 +112,7 @@ public class ContentItemManager {
|
||||||
*
|
*
|
||||||
* @return The new content item.
|
* @return The new content item.
|
||||||
*/
|
*/
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public <T extends ContentItem> T createContentItem(
|
public <T extends ContentItem> T createContentItem(
|
||||||
final String name,
|
final String name,
|
||||||
final ContentSection section,
|
final ContentSection section,
|
||||||
|
|
@ -112,6 +160,7 @@ public class ContentItemManager {
|
||||||
*
|
*
|
||||||
* @return The new content item.
|
* @return The new content item.
|
||||||
*/
|
*/
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public <T extends ContentItem> T createContentItem(
|
public <T extends ContentItem> T createContentItem(
|
||||||
final String name,
|
final String name,
|
||||||
final ContentSection section,
|
final ContentSection section,
|
||||||
|
|
@ -119,7 +168,47 @@ public class ContentItemManager {
|
||||||
final WorkflowTemplate workflowTemplate,
|
final WorkflowTemplate workflowTemplate,
|
||||||
final LifecycleDefinition lifecycleDefinition,
|
final LifecycleDefinition lifecycleDefinition,
|
||||||
final Class<T> type) {
|
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 item The item to move.
|
||||||
* @param targetFolder The folder to which the item is moved.
|
* @param targetFolder The folder to which the item is moved.
|
||||||
*/
|
*/
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public void move(final ContentItem item, final Category targetFolder) {
|
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
|
* original item an index is appended to the name of the
|
||||||
* item.
|
* item.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public void copy(final ContentItem item, final Category targetFolder) {
|
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();
|
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
|
* Creates a live version of content item or updates the live version of a
|
||||||
* content item if there already a live version.
|
* content item if there already a live version.
|
||||||
|
|
@ -156,8 +439,151 @@ public class ContentItemManager {
|
||||||
*
|
*
|
||||||
* @return The published content item.
|
* @return The published content item.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public ContentItem publish(final ContentItem item) {
|
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
|
* @param item
|
||||||
*/
|
*/
|
||||||
public void unpublish(final ContentItem item) {
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
throw new UnsupportedOperationException();
|
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.
|
* {@code false} if not.
|
||||||
*/
|
*/
|
||||||
public boolean isLive(final ContentItem item) {
|
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(
|
public <T extends ContentItem> Optional<T> getLiveVersion(
|
||||||
final ContentItem item,
|
final ContentItem item,
|
||||||
final Class<T> type) {
|
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,
|
public <T extends ContentItem> T getDraftVersion(final ContentItem item,
|
||||||
final Class<T> type) {
|
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}.
|
* {@code /research/computer-science/artificial-intelligence/neural-nets}.
|
||||||
* If the parameter {@code withContentSection} is set to {@code true} the
|
* If the parameter {@code withContentSection} is set to {@code true} the
|
||||||
* the path will be prefixed with the name of the content section. For
|
* 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
|
* {@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
|
* @param withContentSection Wether to include the content section into the
|
||||||
* path.
|
* path.
|
||||||
*
|
*
|
||||||
|
|
@ -339,4 +790,26 @@ public class ContentItemManager {
|
||||||
return folders;
|
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.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.enterprise.context.RequestScoped;
|
import javax.enterprise.context.RequestScoped;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.persistence.TypedQuery;
|
import javax.persistence.TypedQuery;
|
||||||
|
import jdk.nashorn.internal.objects.NativeArray;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Repository for content items.
|
* Repository for content items.
|
||||||
|
|
@ -163,16 +165,51 @@ public class ContentItemRepository
|
||||||
* @return A list of all items in the provided folder.
|
* @return A list of all items in the provided folder.
|
||||||
*/
|
*/
|
||||||
public List<ContentItem> findByFolder(final Category folder) {
|
public List<ContentItem> findByFolder(final Category folder) {
|
||||||
final TypedQuery<CcmObject> query = getEntityManager()
|
final TypedQuery<ContentItem> query = getEntityManager()
|
||||||
.createNamedQuery("ContentItem.findByFolder", CcmObject.class);
|
.createNamedQuery("ContentItem.findByFolder",
|
||||||
|
ContentItem.class);
|
||||||
query.setParameter("folder", folder);
|
query.setParameter("folder", folder);
|
||||||
|
|
||||||
final List<ContentItem> result = new ArrayList<>();
|
return query.getResultList();
|
||||||
query.getResultList().stream()
|
}
|
||||||
.filter(obj -> (obj instanceof ContentItem))
|
|
||||||
.forEach(obj -> result.add((ContentItem) obj));
|
|
||||||
|
|
||||||
return result;
|
public long countItemsInFolder(final Category folder) {
|
||||||
|
final TypedQuery<Long> query = getEntityManager()
|
||||||
|
.createNamedQuery("ContentItem.countItemsInFolder", Long.class);
|
||||||
|
query.setParameter("folder", folder);
|
||||||
|
|
||||||
|
return query.getSingleResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
*/
|
*/
|
||||||
package org.librecms.contentsection;
|
package org.librecms.contentsection;
|
||||||
|
|
||||||
|
import com.arsdigita.cms.dispatcher.ItemResolver;
|
||||||
import com.arsdigita.kernel.KernelConfig;
|
import com.arsdigita.kernel.KernelConfig;
|
||||||
|
|
||||||
import org.libreccm.categorization.Category;
|
import org.libreccm.categorization.Category;
|
||||||
|
|
@ -34,7 +35,6 @@ import org.libreccm.security.RoleRepository;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import javax.enterprise.context.RequestScoped;
|
import javax.enterprise.context.RequestScoped;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
@ -275,4 +275,16 @@ public class ContentSectionManager {
|
||||||
throw new UnsupportedOperationException();
|
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>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
<configuration>
|
<configuration>
|
||||||
<groups>org.libreccm.tests.categories.UnitTest</groups>
|
<groups>org.libreccm.tests.categories.UnitTest</groups>
|
||||||
|
<trimStackTrace>false</trimStackTrace>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
|
|
@ -425,6 +426,9 @@
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-surefire-report-plugin</artifactId>
|
<artifactId>maven-surefire-report-plugin</artifactId>
|
||||||
<version>2.19.1</version>
|
<version>2.19.1</version>
|
||||||
|
<configuration>
|
||||||
|
<trimStackTrace>false</trimStackTrace>
|
||||||
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.jacoco</groupId>
|
<groupId>org.jacoco</groupId>
|
||||||
|
|
@ -708,6 +712,7 @@
|
||||||
<additionalClasspathElements>
|
<additionalClasspathElements>
|
||||||
<additionalClasspathElement>${project.build.directory}/generated-resources</additionalClasspathElement>
|
<additionalClasspathElement>${project.build.directory}/generated-resources</additionalClasspathElement>
|
||||||
</additionalClasspathElements>
|
</additionalClasspathElements>
|
||||||
|
<trimStackTrace>false</trimStackTrace>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
|
|
@ -784,6 +789,7 @@
|
||||||
org.libreccm.tests.categories.UnitTest,
|
org.libreccm.tests.categories.UnitTest,
|
||||||
org.libreccm.tests.categories.IntegrationTest
|
org.libreccm.tests.categories.IntegrationTest
|
||||||
</groups>
|
</groups>
|
||||||
|
<trimStackTrace>false</trimStackTrace>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
|
|
@ -1083,6 +1089,7 @@
|
||||||
org.libreccm.tests.categories.UnitTest,
|
org.libreccm.tests.categories.UnitTest,
|
||||||
org.libreccm.tests.categories.IntegrationTest
|
org.libreccm.tests.categories.IntegrationTest
|
||||||
</groups>
|
</groups>
|
||||||
|
<trimStackTrace>false</trimStackTrace>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
|
|
@ -1169,6 +1176,7 @@
|
||||||
org.libreccm.tests.categories.UnitTest,
|
org.libreccm.tests.categories.UnitTest,
|
||||||
org.libreccm.tests.categories.IntegrationTest
|
org.libreccm.tests.categories.IntegrationTest
|
||||||
</groups>
|
</groups>
|
||||||
|
<trimStackTrace>false</trimStackTrace>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -74,11 +74,29 @@ public abstract class AbstractAuditedEntityRepository<K, T>
|
||||||
* @throws NotAuditedException When entities of the given class are not
|
* @throws NotAuditedException When entities of the given class are not
|
||||||
* audited.
|
* audited.
|
||||||
* @throws IllegalArgumentException If cls or primaryKey is null.
|
* @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,
|
public List<Number> retrieveRevisionNumbersOfEntity(final T entity,
|
||||||
final Long objectId) {
|
final Long objectId) {
|
||||||
return auditReader.getRevisions(entity.getClass(), 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
|
@Entity
|
||||||
@Table(name = "CATEGORIZATIONS", schema = DB_SCHEMA)
|
@Table(name = "CATEGORIZATIONS", schema = DB_SCHEMA)
|
||||||
@NamedQueries({
|
@NamedQueries({
|
||||||
@NamedQuery(name = "Categorization.find",
|
@NamedQuery(
|
||||||
|
name = "Categorization.find",
|
||||||
query = "SELECT c FROM Categorization c "
|
query = "SELECT c FROM Categorization c "
|
||||||
+ "WHERE c.category = :category "
|
+ "WHERE c.category = :category "
|
||||||
+ "AND c.categorizedObject = :object")
|
+ "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 {
|
public class Categorization implements Serializable {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,15 @@ import org.apache.logging.log4j.Logger;
|
||||||
import org.libreccm.core.CcmObject;
|
import org.libreccm.core.CcmObject;
|
||||||
import org.libreccm.core.CcmObjectRepository;
|
import org.libreccm.core.CcmObjectRepository;
|
||||||
import org.libreccm.security.AuthorizationRequired;
|
import org.libreccm.security.AuthorizationRequired;
|
||||||
|
import org.libreccm.security.PermissionChecker;
|
||||||
import org.libreccm.security.RequiresPrivilege;
|
import org.libreccm.security.RequiresPrivilege;
|
||||||
import org.libreccm.security.Shiro;
|
import org.libreccm.security.Shiro;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.StringJoiner;
|
||||||
|
|
||||||
import javax.enterprise.context.RequestScoped;
|
import javax.enterprise.context.RequestScoped;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
@ -65,6 +69,9 @@ public class CategoryManager {
|
||||||
@Inject
|
@Inject
|
||||||
private Shiro shiro;
|
private Shiro shiro;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private PermissionChecker permissionChecker;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assigns an category to an object.
|
* Assigns an category to an object.
|
||||||
*
|
*
|
||||||
|
|
@ -89,6 +96,35 @@ public class CategoryManager {
|
||||||
@RequiresPrivilege(MANAGE_CATEGORY_OBJECTS_PRIVILEGE)
|
@RequiresPrivilege(MANAGE_CATEGORY_OBJECTS_PRIVILEGE)
|
||||||
final Category category) {
|
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) {
|
if (object == null) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Null can't be added to a category.");
|
"Null can't be added to a category.");
|
||||||
|
|
@ -104,11 +140,12 @@ public class CategoryManager {
|
||||||
categorization.setCategory(category);
|
categorization.setCategory(category);
|
||||||
categorization.setCategoryOrder(object.getCategories().size() + 1);
|
categorization.setCategoryOrder(object.getCategories().size() + 1);
|
||||||
categorization.setObjectOrder(category.getObjects().size() + 1);
|
categorization.setObjectOrder(category.getObjects().size() + 1);
|
||||||
|
categorization.setType(type);
|
||||||
|
|
||||||
object.addCategory(categorization);
|
object.addCategory(categorization);
|
||||||
category.addObject(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
|
// 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
|
// to a category. Therefore we bypass the this authorisation check here
|
||||||
// by executing CategoryRepository#save(Category) as the system user.
|
// 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;
|
return result;
|
||||||
} else if (object instanceof InheritsPermissions) {
|
} else if (object instanceof InheritsPermissions) {
|
||||||
if (((InheritsPermissions) object).getParent().isPresent()) {
|
if (((InheritsPermissions) object).getParent().isPresent()) {
|
||||||
return result;
|
|
||||||
} else {
|
|
||||||
return isPermitted(
|
return isPermitted(
|
||||||
privilege,
|
privilege,
|
||||||
((InheritsPermissions) object).getParent().get());
|
((InheritsPermissions) object).getParent().get());
|
||||||
|
} else {
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -141,18 +141,16 @@ public class PermissionChecker {
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
if (((InheritsPermissions) object).getParent().isPresent()) {
|
if (((InheritsPermissions) object).getParent().isPresent()) {
|
||||||
if (subject.isAuthenticated()) {
|
checkPermission(
|
||||||
|
privilege,
|
||||||
|
((InheritsPermissions) object).getParent().get());
|
||||||
|
} else if (subject.isAuthenticated()) {
|
||||||
subject.checkPermission(generatePermissionString(
|
subject.checkPermission(generatePermissionString(
|
||||||
privilege, object));
|
privilege, object));
|
||||||
} else {
|
} else {
|
||||||
shiro.getPublicUser().checkPermission(
|
shiro.getPublicUser().checkPermission(
|
||||||
generatePermissionString(privilege, object));
|
generatePermissionString(privilege, object));
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
checkPermission(
|
|
||||||
privilege,
|
|
||||||
((InheritsPermissions) object).getParent().get());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (subject.isAuthenticated()) {
|
} else if (subject.isAuthenticated()) {
|
||||||
subject.checkPermission(generatePermissionString(privilege, object));
|
subject.checkPermission(generatePermissionString(privilege, object));
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ import org.libreccm.security.Shiro;
|
||||||
import org.libreccm.tests.categories.IntegrationTest;
|
import org.libreccm.tests.categories.IntegrationTest;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.Optional;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
|
|
@ -583,4 +583,33 @@ public class CategoryManagerTest {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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_ORDER bigint,
|
||||||
CATEGORY_INDEX boolean,
|
CATEGORY_INDEX boolean,
|
||||||
OBJECT_ORDER bigint,
|
OBJECT_ORDER bigint,
|
||||||
|
TYPE varchar(255),
|
||||||
OBJECT_ID bigint,
|
OBJECT_ID bigint,
|
||||||
CATEGORY_ID bigint,
|
CATEGORY_ID bigint,
|
||||||
primary key (CATEGORIZATION_ID)
|
primary key (CATEGORIZATION_ID)
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ CREATE SCHEMA ccm_core;
|
||||||
CATEGORY_ORDER int8,
|
CATEGORY_ORDER int8,
|
||||||
CATEGORY_INDEX boolean,
|
CATEGORY_INDEX boolean,
|
||||||
OBJECT_ORDER int8,
|
OBJECT_ORDER int8,
|
||||||
|
TYPE varchar(255),
|
||||||
OBJECT_ID int8,
|
OBJECT_ID int8,
|
||||||
CATEGORY_ID int8,
|
CATEGORY_ID int8,
|
||||||
primary key (CATEGORIZATION_ID)
|
primary key (CATEGORIZATION_ID)
|
||||||
|
|
|
||||||
|
|
@ -71,4 +71,4 @@ ccm_core.categorizations:
|
||||||
category_id: -2100
|
category_id: -2100
|
||||||
category_order: 1
|
category_order: 1
|
||||||
object_order: 2
|
object_order: 2
|
||||||
category_index: false
|
category_index: true
|
||||||
|
|
@ -76,4 +76,4 @@ ccm_core.categorizations:
|
||||||
object_id: -3300
|
object_id: -3300
|
||||||
category_order: 1
|
category_order: 1
|
||||||
object_order: 1
|
object_order: 1
|
||||||
category_index: false
|
category_index: true
|
||||||
|
|
@ -109,4 +109,4 @@ ccm_core.categorizations:
|
||||||
object_id: -3300
|
object_id: -3300
|
||||||
category_order: 1
|
category_order: 1
|
||||||
object_order: 1
|
object_order: 1
|
||||||
category_index: false
|
category_index: true
|
||||||
|
|
@ -59,4 +59,4 @@ ccm_core.categorizations:
|
||||||
object_id: -3300
|
object_id: -3300
|
||||||
category_order: 1
|
category_order: 1
|
||||||
object_order: 1
|
object_order: 1
|
||||||
category_index: false
|
category_index: true
|
||||||
|
|
|
||||||
|
|
@ -64,4 +64,4 @@ ccm_core.categorizations:
|
||||||
object_id: -3300
|
object_id: -3300
|
||||||
category_order: 1
|
category_order: 1
|
||||||
object_order: 1
|
object_order: 1
|
||||||
category_index: false
|
category_index: true
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ ccm_core.categorizations:
|
||||||
object_id: -3300
|
object_id: -3300
|
||||||
category_order: 1
|
category_order: 1
|
||||||
object_order: 1
|
object_order: 1
|
||||||
category_index: false
|
category_index: true
|
||||||
|
|
||||||
ccm_core.parties:
|
ccm_core.parties:
|
||||||
- party_id: -3000
|
- party_id: -3000
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue