From 0f5f728ffedf388cac3db61620adcbbb97f7829d Mon Sep 17 00:00:00 2001 From: jensp Date: Wed, 22 Feb 2017 12:37:17 +0000 Subject: [PATCH] CCM NG/ccm-cms: Deleting items from FolderBrowser git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@4591 8810af33-2d31-482b-a856-94f89814c4df --- .../cms/ui/folder/FolderBrowser.java | 271 ++---------------- .../ui/folder/FolderBrowserController.java | 42 ++- .../ui/folder/FolderBrowserTableModel.java | 14 +- .../contentsection/ContentItemRepository.java | 46 +++ .../h2/V7_0_0_11__fix_item_aud_item_uuid.sql | 2 + .../V7_0_0_11__fix_item_aud_item_uuid.sql | 2 + .../scripts/create_ccm_cms_schema.sql | 1 - .../categorization/CategoryManager.java | 40 +-- .../core/AbstractEntityRepository.java | 9 +- .../libreccm/core/CcmObjectRepository.java | 7 + 10 files changed, 148 insertions(+), 286 deletions(-) create mode 100644 ccm-cms/src/main/resources/db/migrations/org/librecms/ccm_cms/h2/V7_0_0_11__fix_item_aud_item_uuid.sql create mode 100644 ccm-cms/src/main/resources/db/migrations/org/librecms/ccm_cms/pgsql/V7_0_0_11__fix_item_aud_item_uuid.sql diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderBrowser.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderBrowser.java index 718faddbb..f9b00dd22 100755 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderBrowser.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderBrowser.java @@ -246,11 +246,11 @@ public class FolderBrowser extends Table { protected String getSortType(final PageState state) { return (String) state.getValue(sortTypeParameter); } - + protected String getSortDirection(final PageState state) { return (String) state.getValue(sortDirectionParameter); } - + private class HeaderCellRenderer extends com.arsdigita.cms.ui.util.DefaultTableCellRenderer { @@ -349,6 +349,7 @@ public class FolderBrowser extends Table { final boolean isFolder = ((FolderBrowserTableModel) table .getTableModel(state)).isFolder(); + final long objectId = getObjectId(key); if (isFolder) { //return new ControlLink(new Text(name)); @@ -356,13 +357,13 @@ public class FolderBrowser extends Table { state, value, isSelected, - key, + objectId, row, column); } else { return new Link(new Text(name), itemResolver.generateItemURL(state, - (long) key, + objectId, name, section, "DRAFT")); @@ -392,48 +393,21 @@ public class FolderBrowser extends Table { final int row, final int column) { -// final ContentItem item = (ContentItem) value; -// final 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().stream() -// .map((locale) -> locale.toString()) -// .map((lang) -> { -// 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()); -// return langLabel; -// }) -// .forEach((langLabel) -> { -// container.add(new Link( -// langLabel, -// itemResolver.generateItemURL(state, -// item.getObjectId(), -// name, -// section, -// item.getVersion().name()))); -// }); @SuppressWarnings("unchecked") final List availableLocales = (List) value; availableLocales.forEach(locale -> container.add(new Link( new Text(locale.toString()), itemResolver.generateItemURL( state, - (long) key, + getObjectId(key), locale.toString(), section, "DRAFT")))); @@ -516,188 +490,17 @@ public class FolderBrowser extends Table { } final PageState state = event.getPageState(); - final long itemId = Long.parseLong(event.getRowKey().toString()); final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); final FolderBrowserController controller = cdiUtil.findBean( FolderBrowserController.class); - controller.deleteObject(itemId); + controller.deleteObject((String) event.getRowKey()); ((Table) event.getSource()).clearSelection(state); } } -// /** -// * 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 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 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 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 (LOGGER.isDebugEnabled()) { -// LOGGER.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 (LOGGER.isDebugEnabled()) { -// LOGGER.debug( -// "This item has a live instance; it cannot be deleted"); -// } -// return false; -// } -// -// if (LOGGER.isDebugEnabled()) { -// LOGGER.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 @@ -708,54 +511,14 @@ public class FolderBrowser extends Table { if (nameColumn != getColumn(col)) { return; } - final String key = (String) event.getRowKey(); clearSelection(state); - getFolderSelectionModel().setSelectedKey(state, Long.parseLong(key)); - + getFolderSelectionModel().setSelectedKey( + state, + getObjectId(event.getRowKey())); } } - -// 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. * @@ -766,4 +529,18 @@ public class FolderBrowser extends Table { } + private long getObjectId(final Object key) { + + final String keyStr = (String) key; + + if (keyStr.startsWith("folder-")) { + return Long.parseLong(keyStr.substring("folder-".length())); + } else if (keyStr.startsWith("item-")) { + return Long.parseLong(keyStr.substring("item-".length())); + } else { + return Long.parseLong(keyStr); + } + + } + } diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderBrowserController.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderBrowserController.java index 3eb992f54..d1d717fb9 100644 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderBrowserController.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderBrowserController.java @@ -30,9 +30,11 @@ import org.librecms.CmsConstants; import org.librecms.contentsection.ContentItem; import org.librecms.contentsection.ContentItemL10NManager; import org.librecms.contentsection.ContentItemManager; +import org.librecms.contentsection.ContentItemRepository; import org.librecms.contentsection.ContentItemVersion; import org.librecms.contentsection.ContentType; import org.librecms.contentsection.Folder; +import org.librecms.contentsection.FolderRepository; import org.librecms.contenttypes.ContentTypeInfo; import org.librecms.contenttypes.ContentTypesManager; @@ -75,7 +77,7 @@ public class FolderBrowserController { @Inject private CategoryManager categoryManager; - + @Inject private CcmObjectRepository objectRepo; @@ -90,8 +92,14 @@ public class FolderBrowserController { @Inject private ContentTypesManager typesManager; - - @Inject + + @Inject + private FolderRepository folderRepo; + + @Inject + private ContentItemRepository itemRepo; + + @Inject private ContentItemManager itemManager; private Locale defaultLocale; @@ -335,7 +343,7 @@ public class FolderBrowserController { } row.setFolder(true); row.setDeletable(!categoryManager.hasSubCategories(folder) - && !categoryManager.hasObjects(folder)); + && !categoryManager.hasObjects(folder)); return row; } @@ -374,7 +382,7 @@ public class FolderBrowserController { type); row.setTypeLabelBundle(typeInfo.getLabelBundle()); row.setTypeLabelKey(typeInfo.getLabelKey()); - + row.setDeletable(!itemManager.isLive(item)); row.setCreated(item.getCreationDate()); @@ -391,11 +399,27 @@ public class FolderBrowserController { * @param objectId */ @Transactional(Transactional.TxType.REQUIRED) - protected void deleteObject(final long objectId) { - final Optional object = objectRepo.findById(objectId); + protected void deleteObject(final String objectId) { - if (object.isPresent()) { - objectRepo.delete(object.get()); + Objects.requireNonNull(objectId); + + if (objectId.startsWith("folder-")) { + final long folderId = Long.parseLong( + objectId.substring("folder-".length())); + + folderRepo + .findById(folderId) + .ifPresent(folderRepo::delete); + } else if (objectId.startsWith("item-")) { + final long itemId = Long.parseLong( + objectId.substring("item-".length())); + + itemRepo + .findById(itemId) + .ifPresent(itemRepo::delete); + } else { + throw new IllegalArgumentException( + "The objectId is expected to start with 'folder-' or 'item.'."); } } diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderBrowserTableModel.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderBrowserTableModel.java index 3e3693ad1..7e00bdf62 100644 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderBrowserTableModel.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/folder/FolderBrowserTableModel.java @@ -98,12 +98,14 @@ class FolderBrowserTableModel implements TableModel { @Override public Object getKeyAt(final int columnIndex) { -// if (currentRow.isFolder()) { -// return String.format("folder-%d", currentRow.getObjectId()); -// } else { -// return String.format("item-%d", currentRow.getObjectId()); -// } - return currentRow.getObjectId(); + if (currentRow.isFolder()) { + return String.format("folder-%d", currentRow.getObjectId()); + } else { + return String.format("item-%d", currentRow.getObjectId()); + } + + +// return currentRow.getObjectId(); } public boolean isFolder() { diff --git a/ccm-cms/src/main/java/org/librecms/contentsection/ContentItemRepository.java b/ccm-cms/src/main/java/org/librecms/contentsection/ContentItemRepository.java index 75b55817e..f278d2432 100644 --- a/ccm-cms/src/main/java/org/librecms/contentsection/ContentItemRepository.java +++ b/ccm-cms/src/main/java/org/librecms/contentsection/ContentItemRepository.java @@ -23,9 +23,13 @@ import org.apache.shiro.subject.Subject; import java.util.Date; import org.libreccm.auditing.AbstractAuditedEntityRepository; +import org.libreccm.categorization.Categorization; import org.libreccm.categorization.Category; +import org.libreccm.categorization.CategoryManager; +import org.libreccm.categorization.ObjectNotAssignedToCategoryException; import org.libreccm.core.CcmObject; import org.libreccm.core.CcmObjectRepository; +import org.libreccm.core.UnexpectedErrorException; import java.util.List; import java.util.Optional; @@ -39,6 +43,8 @@ import javax.persistence.TypedQuery; import org.libreccm.security.Shiro; import org.libreccm.workflow.Workflow; +import javax.transaction.Transactional; + /** * Repository for content items. * @@ -53,6 +59,12 @@ public class ContentItemRepository @Inject private FolderRepository folderRepo; + + @Inject + private ContentItemManager itemManager; + + @Inject + private CategoryManager categoryManager; @Inject private Shiro shiro; @@ -371,5 +383,39 @@ public class ContentItemRepository super.save(item); } + + @Transactional(Transactional.TxType.REQUIRED) + @Override + public void delete(final ContentItem item) { + if (itemManager.isLive(item)) { + throw new IllegalArgumentException(String.format( + "The provided content item %s can't be deleted because it " + + "is live.", + item.getItemUuid())); + } + + final ContentItem draft = itemManager.getDraftVersion(item, + ContentItem.class); +// draft.getCategories().stream() +// .map(categorization -> categorization.getCategory()) +// .forEach(category -> removeCategoryFromItem(item, category)); + for(final Categorization categorization : draft.getCategories()) { + final Category category = categorization.getCategory(); + + removeCategoryFromItem(item, category); + } + + + super.delete(draft); + } + + private void removeCategoryFromItem(final ContentItem item, + final Category category) { + try { + categoryManager.removeObjectFromCategory(item, category); + } catch(ObjectNotAssignedToCategoryException ex) { + throw new UnexpectedErrorException(ex); + } + } } diff --git a/ccm-cms/src/main/resources/db/migrations/org/librecms/ccm_cms/h2/V7_0_0_11__fix_item_aud_item_uuid.sql b/ccm-cms/src/main/resources/db/migrations/org/librecms/ccm_cms/h2/V7_0_0_11__fix_item_aud_item_uuid.sql new file mode 100644 index 000000000..1ee1f08c8 --- /dev/null +++ b/ccm-cms/src/main/resources/db/migrations/org/librecms/ccm_cms/h2/V7_0_0_11__fix_item_aud_item_uuid.sql @@ -0,0 +1,2 @@ +ALTER TABLE ccm_cms.content_items_aud + ALTER COLUMN item_uuid set null; diff --git a/ccm-cms/src/main/resources/db/migrations/org/librecms/ccm_cms/pgsql/V7_0_0_11__fix_item_aud_item_uuid.sql b/ccm-cms/src/main/resources/db/migrations/org/librecms/ccm_cms/pgsql/V7_0_0_11__fix_item_aud_item_uuid.sql new file mode 100644 index 000000000..a7a0158f8 --- /dev/null +++ b/ccm-cms/src/main/resources/db/migrations/org/librecms/ccm_cms/pgsql/V7_0_0_11__fix_item_aud_item_uuid.sql @@ -0,0 +1,2 @@ +ALTER TABLE ccm_cms.content_items_aud + ALTER COLUMN item_uuid drop not null; diff --git a/ccm-cms/src/test/resources-wildfly-remote-h2-mem/scripts/create_ccm_cms_schema.sql b/ccm-cms/src/test/resources-wildfly-remote-h2-mem/scripts/create_ccm_cms_schema.sql index 44734c60c..f1d70351c 100644 --- a/ccm-cms/src/test/resources-wildfly-remote-h2-mem/scripts/create_ccm_cms_schema.sql +++ b/ccm-cms/src/test/resources-wildfly-remote-h2-mem/scripts/create_ccm_cms_schema.sql @@ -296,7 +296,6 @@ create schema CCM_CORE; WORKFLOW_ID bigint, primary key (OBJECT_ID, REV) ); - create table CCM_CMS.CONTENT_SECTION_LIFECYCLE_DEFINITIONS ( CONTENT_SECTION_ID bigint not null, LIFECYCLE_DEFINITION_ID bigint not null diff --git a/ccm-core/src/main/java/org/libreccm/categorization/CategoryManager.java b/ccm-core/src/main/java/org/libreccm/categorization/CategoryManager.java index 507f68d22..c64191594 100644 --- a/ccm-core/src/main/java/org/libreccm/categorization/CategoryManager.java +++ b/ccm-core/src/main/java/org/libreccm/categorization/CategoryManager.java @@ -289,26 +289,28 @@ public class CategoryManager { ex); return; } + + entityManager.remove(categorization); - shiro.getSystemUser().execute(() -> { - object.removeCategory(categorization); - category.removeObject(categorization); - entityManager.remove(categorization); - categoryRepo.save(category); - ccmObjectRepo.save(object); - - final List categories = object.getCategories(); - for (int i = 0; i < categories.size(); i++) { - categories.get(i).setCategoryOrder(i); - entityManager.merge(categories.get(i)); - } - - final List objects = category.getObjects(); - for (int i = 0; i < objects.size(); i++) { - objects.get(i).setObjectOrder(i); - entityManager.merge(objects.get(i)); - } - }); +// shiro.getSystemUser().execute(() -> { +// object.removeCategory(categorization); +// category.removeObject(categorization); +// entityManager.remove(categorization); +// categoryRepo.save(category); +// ccmObjectRepo.save(object); +// +// final List categories = object.getCategories(); +// for (int i = 0; i < categories.size(); i++) { +// categories.get(i).setCategoryOrder(i); +// entityManager.merge(categories.get(i)); +// } +// +// final List objects = category.getObjects(); +// for (int i = 0; i < objects.size(); i++) { +// objects.get(i).setObjectOrder(i); +// entityManager.merge(objects.get(i)); +// } +// }); } /** diff --git a/ccm-core/src/main/java/org/libreccm/core/AbstractEntityRepository.java b/ccm-core/src/main/java/org/libreccm/core/AbstractEntityRepository.java index 60c0810f2..920c61839 100644 --- a/ccm-core/src/main/java/org/libreccm/core/AbstractEntityRepository.java +++ b/ccm-core/src/main/java/org/libreccm/core/AbstractEntityRepository.java @@ -24,6 +24,7 @@ import org.apache.logging.log4j.Logger; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import javax.inject.Inject; @@ -266,10 +267,10 @@ public abstract class AbstractEntityRepository { */ @Transactional(Transactional.TxType.REQUIRED) public void delete(final E entity) { - if (entity == null) { - throw new IllegalArgumentException("Can't delete a null entity."); - } - + + Objects.requireNonNull(entity, + "Can't delete a null entity."); + //We need to make sure we use a none detached entity, therefore the merge entityManager.remove(entityManager.merge(entity)); } diff --git a/ccm-core/src/main/java/org/libreccm/core/CcmObjectRepository.java b/ccm-core/src/main/java/org/libreccm/core/CcmObjectRepository.java index b41b99e6c..b77d0735c 100644 --- a/ccm-core/src/main/java/org/libreccm/core/CcmObjectRepository.java +++ b/ccm-core/src/main/java/org/libreccm/core/CcmObjectRepository.java @@ -27,6 +27,7 @@ import java.util.UUID; import javax.enterprise.context.RequestScoped; import javax.persistence.NoResultException; import javax.persistence.TypedQuery; +import javax.transaction.Transactional; /** * A repository class for {@link CcmObject}. @@ -89,5 +90,11 @@ public class CcmObjectRepository extends AbstractEntityRepository