diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/ApplyWorkflowFormSection.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/ApplyWorkflowFormSection.java new file mode 100755 index 000000000..456382509 --- /dev/null +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/ApplyWorkflowFormSection.java @@ -0,0 +1,282 @@ +/* + * 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.cms.ui.authoring; + +import com.arsdigita.bebop.ColumnPanel; +import com.arsdigita.bebop.Container; +import com.arsdigita.bebop.FormProcessException; +import com.arsdigita.bebop.FormSection; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.event.FormInitListener; +import com.arsdigita.bebop.event.FormSectionEvent; +import com.arsdigita.bebop.event.ParameterEvent; +import com.arsdigita.bebop.form.RadioGroup; +import com.arsdigita.bebop.parameters.LongParameter; +import com.arsdigita.bebop.parameters.NotNullValidationListener; + +import org.librecms.contentsection.ContentItem; +import org.librecms.contentsection.ContentSection; +import org.librecms.contentsection.ContentType; +import org.librecms.contentsection.Folder; + +import com.arsdigita.cms.ui.workflow.WorkflowsOptionPrintListener; +import com.arsdigita.globalization.GlobalizedMessage; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.libreccm.cdi.utils.CdiUtil; +import org.libreccm.security.PermissionChecker; +import org.libreccm.workflow.AssignableTask; +import org.libreccm.workflow.AssignableTaskManager; +import org.libreccm.workflow.Workflow; +import org.libreccm.workflow.WorkflowManager; +import org.libreccm.workflow.WorkflowTemplate; +import org.libreccm.workflow.WorkflowTemplateRepository; +import org.librecms.CmsConstants; +import org.librecms.contentsection.privileges.ItemPrivileges; + +import java.util.List; +import java.util.TooManyListenersException; + +/** + * A FormSection which will allow users with + * SecrityConstants.APPLY_ALTERNATE_WORFLOWS permission to choose a different + * workflow to apply to a new item. + * + * @author Stanislav Freidin (stas@arsdigita.com) + * @author Jens Pelzetter + */ +public class ApplyWorkflowFormSection + extends FormSection + implements FormInitListener { + + private static final Logger LOGGER = LogManager + .getLogger(ApplyWorkflowFormSection.class); + + private RadioGroup radioGroup; + private CreationSelector creationSelector; + private ContentType contentType; + private ApplyWorkflowPrintListener printListener; + + /** + * Construct a new ApplyWorkflowFormSection + */ + public ApplyWorkflowFormSection() { + this(null); + } + + /** + * Construct a new ApplyWorkflowFormSection + * + * @param type + */ + public ApplyWorkflowFormSection(final ContentType type) { + this(type, new ColumnPanel(2, true)); + } + + /** + * Construct a new ApplyWorkflowFormSection + * + * @param type + * @param panel Container to use for this FormSection + */ + public ApplyWorkflowFormSection(final ContentType type, + final Container panel) { + super(panel); + + radioGroup = new RadioGroup(new LongParameter("workflowSelect")); + radioGroup.setClassAttr("vertical"); + contentType = type; + printListener = new ApplyWorkflowPrintListener(); + + try { + // should we filter on WorkflowDefinitions where this user + // is assigned to at least one initial task, or should we + // assume that users with "alternate workflow" permission + // are advanced enough to know what they're doing? + radioGroup.addPrintListener(printListener); + } catch (TooManyListenersException ex) { + LOGGER.error("Too many listeners", ex); + } + + add(new Label(new GlobalizedMessage("cms.ui.authoring.workflow", + CmsConstants.CMS_BUNDLE))); + radioGroup.addValidationListener(new NotNullValidationListener() { + + @Override + public void validate(final ParameterEvent event) { + final PageState state = event.getPageState(); + if (!ApplyWorkflowFormSection.this.isVisible(state)) { + return; + } + super.validate(event); + } + + }); + add(radioGroup); + addInitListener(this); + } + + /** + * Initialises the workflow selection widget to the default workflow for the + * content type. + * + * @param event + * + * @throws com.arsdigita.bebop.FormProcessException + */ + @Override + public void init(final FormSectionEvent event) throws FormProcessException { + + final PageState state = event.getPageState(); + final ContentSection section = creationSelector.getContentSection( + state); + final WorkflowTemplate template = contentType.getDefaultWorkflow(); + if (template != null) { + radioGroup.setValue(state, template.getWorkflowId()); + } + } + + /** + * Sets the CreationSelector which should be the same as that of the + * creation component. This cannot be set in the constructor since for most + * creation components, addWidgets() is called via the superclass + * constructor, so this member will not yet be set. + * + * @param creationSelector CreationSelector to use for this FormSection + */ + public void setCreationSelector(final CreationSelector creationSelector) { + this.creationSelector = creationSelector; + } + + /** + * Sets the ContentType for the creation component. + * + * @param contentType ContentType to use for this FormSection + */ + public void setContentType(final ContentType contentType) { + this.contentType = contentType; + } + + /** + * Whether or not this component is visible. The additional visibility + * requirement is that the user must have the + * SecurityConstants.APPLY_ALTERNATE_WORKFLOWS privilege on the parent + * folder. + * + * @param state The PageState + * + * @return + */ + @Override + public boolean isVisible(final PageState state) { + boolean result = false; + + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final PermissionChecker permissionChecker = cdiUtil + .findBean(PermissionChecker.class); + ; + + if (super.isVisible(state) + && permissionChecker + .isPermitted(ItemPrivileges.APPLY_ALTERNATE_WORKFLOW, + creationSelector.getFolder(state))) { + + return !printListener.getCollection(state).isEmpty(); + } + return result; + } + + /** + * Apply the proper initial workflow to the item. If the user has + * SecurityConstants.APPLY_ALTERNATE_WORKFLOWS permission on the parent + * folder and a workflow has been chosen, use this workflow. + * Otherwise use the default workflow for the content type. + * + * @param state The PageState + * @param item The new ContentItem + */ + public void applyWorkflow(final PageState state, final ContentItem item) { + + final Long flowId = (Long) radioGroup.getValue(state); + final ContentSection section = creationSelector.getContentSection( + state); + final Folder folder = creationSelector.getFolder(state); + final WorkflowTemplate template; + + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final PermissionChecker permissionChecker = cdiUtil + .findBean(PermissionChecker.class); + final WorkflowTemplateRepository templateRepo = cdiUtil + .findBean(WorkflowTemplateRepository.class); + + if (flowId != null + && permissionChecker.isPermitted( + ItemPrivileges.APPLY_ALTERNATE_WORKFLOW, folder)) { + template = templateRepo + .findById(flowId) + .orElseThrow(() -> new IllegalArgumentException(String.format( + "No WorkflowTemplate with ID %d in database. " + + "Where did that ID come from?"))); + } else { + template = item.getContentType().getDefaultWorkflow(); + } + + if (template != null) { + + final WorkflowManager workflowManager = cdiUtil + .findBean(WorkflowManager.class); + + final Workflow workflow = workflowManager.createWorkflow(template, + item); + workflowManager.start(workflow); + + if (!workflow.getTasks().isEmpty()) { + + if (workflow.getTasks().get(0) instanceof AssignableTask) { + + final AssignableTaskManager taskManager = cdiUtil + .findBean(AssignableTaskManager.class); + final AssignableTask task = (AssignableTask) workflow + .getTasks() + .get(0); + taskManager.lockTask(task); + } + } + } + + } + + private class ApplyWorkflowPrintListener + extends WorkflowsOptionPrintListener { + + @Override + protected ContentSection getContentSection(final PageState state) { + return creationSelector.getContentSection(state); + } + + @Override + protected List getCollection(final PageState state) { + return super.getCollection(state); + } + + } + +} diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/BasicItemForm.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/BasicItemForm.java index f04ba2bb8..93eec9f44 100755 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/BasicItemForm.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/BasicItemForm.java @@ -20,6 +20,7 @@ package com.arsdigita.cms.ui.authoring; import com.arsdigita.bebop.ColumnPanel; import com.arsdigita.bebop.Component; +import com.arsdigita.bebop.FormData; import com.arsdigita.bebop.FormProcessException; import com.arsdigita.bebop.FormSection; import com.arsdigita.bebop.Label; @@ -39,7 +40,12 @@ import com.arsdigita.globalization.GlobalizedMessage; import com.arsdigita.web.Web; import com.arsdigita.xml.Element; +import org.libreccm.categorization.Category; +import org.libreccm.categorization.CategoryRepository; +import org.libreccm.cdi.utils.CdiUtil; import org.librecms.CmsConstants; +import org.librecms.contentsection.ContentItem; +import org.librecms.contentsection.ContentItemRepository; /** * A form for editing subclasses of ContentItem. This is just a convenience @@ -222,7 +228,7 @@ public abstract class BasicItemForm extends FormSection } /** - * Perform form initialization. Children should override this this method to + * Perform form initialisation. Children should override this this method to * pre-fill the widgets with data, instantiate the content item, etc. * * @param e @@ -343,140 +349,64 @@ public abstract class BasicItemForm extends FormSection * @param event the {@link FormSectionEvent} which was passed to the * validation listener */ -// public void validateNameUniqueness(Category parent, FormSectionEvent event) { -// -// FormData data = event.getFormData(); -// String newName = (String) data.get(NAME); -// -// validateNameUniqueness(parent, event, newName); -// } + public void validateNameUniqueness(final Category parent, + final FormSectionEvent event) { + + final FormData data = event.getFormData(); + final String newName = (String) data.get(NAME); + + validateNameUniqueness(parent, event, newName); + } + /** * * @param parent * @param event * @param newName */ -// public void validateNameUniqueness(Category parent, -// FormSectionEvent event, -// String newName) { -// -// final String ERR_MSG = "cms.ui.authoring.an_item_with_this_name_exists"; -// -// if (newName != null) { -// final String query = "com.arsdigita.cms.validateUniqueItemName"; -// DataQuery dq = SessionManager.getSession().retrieveQuery(query); -// dq.setParameter("parentId", parent.getID()); -// dq.setParameter("name", newName.toUpperCase()); -// FormData data = event.getFormData(); -// ParameterData name = data.getParameter(NAME); -// -// if (dq.size() > 0) { -// // Try to get a currently selected content item -// ContentItem item = null; -// if (getItemSelectionModel() != null) { -// item = (ContentItem) getItemSelectionModel() -// .getSelectedObject(event.getPageState()); -// } -// if (item == null) { // The content item being null -// // means it is a creation form. -// // Therefore finding any item of the same name is a fault. -// data.addError(globalize(ERR_MSG)); -// return; -// } else { -// // means we are in a edit form. -// // We need to add all of the items that are different -// // versions of this item to the list so that we do not mark -// // an error if those are the only problems. -// BigDecimal itemID = null; -// Collection list = getAllVersionIDs(item); -// while (dq.next()) { -// itemID = (BigDecimal) dq.get("itemID"); -// if (!list.contains(itemID)) { -// String[] itemObj = new String[1]; -// itemObj[0] = itemID.toString(); -// dq.close(); -// data.addError(globalize(ERR_MSG, itemObj)); -// return; -// } -// } -// } -// } -// } -// } - /** - * NOT USED ANYMORE. - * - * Ensure that the name of an item is unique within a category. This should - * only be called from the validation listener of an "edit" form. - * - * @param event the {@link FormSectionEvent} which was passed to the - * validation listener - * @param id The id of the item that is being checked. This must no be - * null. - * - * @return - * - * @throws FormProcessException if the folder already contains an item with - * the name the user provided on the input - * form. / public void - * validateNameUniquenessWithinCategory(FormSectionEvent - * event, BigDecimal id) throws - * FormProcessException { if (id == null) { - * s_log.warn("Trying to validation the name - * uniqueness without " + " a valid item is - * invalid. This method should only " + " be - * called in \"edit\" forms. The passed in id " - * + " was null."); return; } // now we check - * to make sure that the new name is valid // - * within every category that the item is - * mapped to // this is only necessary for - * category browsing FormData data = - * event.getFormData(); String url = (String) - * data.get(NAME); if (url == null) { return; } - * DataQuery query = - * SessionManager.getSession().retrieveQuery( - * "com.arsdigita.categorization.getAllItemURLsForCategoryFromItem"); - * query.setParameter("itemID", id); - * query.addEqualsFilter("lower(url)", - * url.toLowerCase()); if (query.size() > 0) { - * // we need to make sure that the conflicting - * item is not a // pending or live version of - * the same item BigDecimal itemID = null; - * - * ContentItem item = (ContentItem)getItemSelectionModel() - * .getSelectedObject(event.getPageState()); Collection list = - * getAllVersionIDs(item); try { while (query.next()) { itemID = - * (BigDecimal) query.get("itemID"); if (!list.contains(itemID)) { // - * StringBuffer buffer = new StringBuffer((String) GlobalizationUtil // - * .globalize("cms.ui.authoring.error_conflicts_with_this_url") // - * .localize()); // buffer.append(url); String[] urlObj=new String[1]; - * urlObj[0]=url; throw new FormProcessException( "Error: Conflict with url: - * "+url, globalize( "cms.ui.authoring.error_conflicts_with_this_url", - * urlObj) ); } } - * - * } finally { query.close(); } } } - */ - /** - * Helper Method for name uniqueness validation. - * - * @param item - * - * @return - */ -// public static Collection getAllVersionIDs(ContentItem item) { -// // we need to add all of the items that are different versions -// // of this item to the list so that we do not throw an error -// // if those are the only problems -// ArrayList list = new ArrayList(); -// list.add(item.getID()); -// ContentItem live = item.getLiveVersion(); -// if (live != null) { -// list.add(live.getID()); -// } -// ItemCollection collection = item.getPendingVersions(); -// while (collection.next()) { -// list.add(collection.getID()); -// } -// return list; -// } + public void validateNameUniqueness(final Category parent, + final FormSectionEvent event, + final String newName) { + + final String ERR_MSG = "cms.ui.authoring.an_item_with_this_name_exists"; + + if (newName != null) { + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final CategoryRepository categoryRepo = cdiUtil + .findBean(CategoryRepository.class); + final ContentItemRepository itemRepo = cdiUtil + .findBean(ContentItemRepository.class); + + final long result = itemRepo.countByNameInFolder(parent, newName); + + if (result > 0) { + // Try to get a currently selected content item + final ContentItem item; + if (getItemSelectionModel() == null) { + item = null; + } else { + item = getItemSelectionModel() + .getSelectedObject(event.getPageState()); + } + if (item == null) { // The content item being null + // means it is a creation form. + // Therefore finding any item of the same name is a fault. + event.getFormData() + .addError(new GlobalizedMessage(ERR_MSG, + CmsConstants.CMS_BUNDLE)); + } else { + // means we are in a edit form. + // We need to add all of the items that are different + // versions of this item to the list so that we do not mark + // an error if those are the only problems. + event.getFormData() + .addError(new GlobalizedMessage( + ERR_MSG, + CmsConstants.CMS_BUNDLE, + new Object[]{item.getUuid()})); + } + } + } + } + } diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/BasicPageForm.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/BasicPageForm.java new file mode 100755 index 000000000..83397384e --- /dev/null +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/BasicPageForm.java @@ -0,0 +1,310 @@ +/* + * 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.authoring; + +import com.arsdigita.bebop.ColumnPanel; +import com.arsdigita.bebop.FormData; +import com.arsdigita.bebop.FormProcessException; +import com.arsdigita.bebop.FormSection; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.event.FormSectionEvent; +import com.arsdigita.bebop.event.ParameterEvent; +import com.arsdigita.bebop.event.ParameterListener; +import com.arsdigita.bebop.parameters.DateParameter; +import com.arsdigita.bebop.parameters.ParameterData; +import com.arsdigita.bebop.parameters.ParameterModel; + +import org.librecms.contentsection.ContentItem; +import org.librecms.contentsection.ContentSection; +import org.librecms.contentsection.Folder; + +import com.arsdigita.cms.ItemSelectionModel; +import com.arsdigita.globalization.GlobalizedMessage; +import com.arsdigita.kernel.KernelConfig; +import com.arsdigita.util.Assert; + +import org.arsdigita.cms.CMSConfig; +import org.libreccm.cdi.utils.CdiUtil; +import org.librecms.CmsConstants; +import org.librecms.contentsection.ContentItemManager; +import org.librecms.contentsection.ContentType; +import org.librecms.contentsection.FolderManager; + +import javax.servlet.ServletException; + +import java.util.Date; +import java.util.Locale; +import java.util.Optional; + +/** + * A form for editing basic properties of documents (that is subclasses of class + * ContentPage). + * + * Document specific classes inherit from this class which provides the basic + * widgets for title, name launch date to use by those classes. + * + * This is just a convenience class. It uses parent class to construct the form + * including basic widgets (i.e. title and name/URL as well as save/cancel + * buttons) and adds optional launch date. + * + * Note: It is for editing existing content (specifically due to its validation + * method). + * + * @author Stanislav Freidin (stas@arsdigita.com) + * @author Jens Pelzetter + */ +public abstract class BasicPageForm extends BasicItemForm { + + private static final String LAUNCH_DATE = "launch_date"; + + private FormSection widgetSection; + + /** + * Construct a new BasicPageForm + * + * @param formName the name of this form + * @param itemModel The {@link ItemSelectionModel} which will be responsible + * for loading the current item + */ + public BasicPageForm(final String formName, + final ItemSelectionModel itemModel) { + + super(formName, itemModel); + } + + /** + * Construct a new BasicPageForm with nothing on it + * + * @param formName the name of this form + * @param columnPanel the column panel of the form + * @param itemModel The {@link ItemSelectionModel} which will be + * responsible for loading the current item + */ + public BasicPageForm(final String formName, + final ColumnPanel columnPanel, + final ItemSelectionModel itemModel) { + + super(formName, columnPanel, itemModel); + } + + /** + * Add various widgets to the form. Child classes should override this + * method to perform all their widget-adding needs + */ + @Override + protected void addWidgets() { + + /* Add basic widgets title/name which are part of any content item */ + super.addWidgets(); + + final CMSConfig cmsConfig = CMSConfig.getConfig(); + + /* Optionally add Lunchdate */ + if (!cmsConfig.isHideLaunchDate()) { + add(new Label(new GlobalizedMessage( + "cms.ui.authoring.page_launch_date", + CmsConstants.CMS_BUNDLE))); + final ParameterModel launchDateParam + = new DateParameter(LAUNCH_DATE); + com.arsdigita.bebop.form.Date launchDate + = new com.arsdigita.bebop.form.Date( + launchDateParam); + if (CMSConfig.getConfig().isRequireLaunchDate()) { + launchDate.addValidationListener( + new LaunchDateValidationListener()); + // if launch date is required, help user by suggesting today's date + launchDateParam.setDefaultValue(new Date()); + } + add(launchDate); + } + } + + /** + * Utility method to initialise the name/title widgets. Child classes may + * call this method from the init listener + * + * @param event the {@link FormSectionEvent} which was passed to the init + * listener + * + * @return the ContentPage instance which was extracted from the + * ItemSelectionModel + */ + public ContentItem initBasicWidgets(final FormSectionEvent event) { + Assert.exists(getItemSelectionModel()); + + final FormData data = event.getFormData(); + final PageState state = event.getPageState(); + final ContentItem item = getItemSelectionModel() + .getSelectedObject(state); + + if (item != null) { + // Preset fields + data.put(CONTENT_ITEM_ID, Long.toString(item.getObjectId())); + data.put(NAME, item.getName()); + data.put(TITLE, item.getTitle()); + final CMSConfig cmsConfig = CMSConfig.getConfig(); + if (!cmsConfig.isHideLaunchDate()) { + data.put(LAUNCH_DATE, item.getLaunchDate()); + // if launch date is required, help user by suggesting today's date + if (cmsConfig.isRequireLaunchDate() + && item.getLaunchDate() == null) { + data.put(LAUNCH_DATE, new Date()); + } + } + } + + return item; + } + + /** + * Class specific implementation of FormValidationListener interface + * (inherited from BasicItemForm). + * + * @param fse + * + * @throws FormProcessException + */ + @Override + public void validate(final FormSectionEvent fse) throws FormProcessException { + + super.validate(fse); //noop, BasicItemForm#validate does nothing + + final ContentItem item = getItemSelectionModel() + .getSelectedItem(fse.getPageState()); + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final ContentItemManager itemManager = cdiUtil + .findBean(ContentItemManager.class); + + final Optional folder = itemManager.getItemFolder(item); + if (folder.isPresent()) { + final FormData data = fse.getFormData(); + final String name = fse.getFormData().getString(NAME); + if (!item.getName() + .getValue(KernelConfig.getConfig().getDefaultLocale()) + .equals(name)) { + validateNameUniqueness(folder.get(), fse); + } + } + } + + /** + * Utility method to process the name/title widgets. Child classes may call + * this method from the process listener. + * + * @param event the {@link FormSectionEvent} which was passed to the process + * listener + * + * @return + */ + public ContentItem processBasicWidgets(final FormSectionEvent event) { + Assert.exists(getItemSelectionModel()); + + final FormData data = event.getFormData(); + final PageState state = event.getPageState(); + final ContentItem item = getItemSelectionModel() + .getSelectedObject(state); + + if (item != null) { + // Update attributes + final KernelConfig kernelConfig = KernelConfig.getConfig(); + final Locale defaultLocale = kernelConfig.getDefaultLocale(); + item.getName().addValue(defaultLocale, (String) data.get(NAME)); + item.getTitle().addValue(defaultLocale, (String) data.get(TITLE)); + if (!CMSConfig.getConfig().isHideLaunchDate()) { + item.setLaunchDate((Date) data.get(LAUNCH_DATE)); + } + } + + return item; + } + + /** + * A utility method that will create a new item and tell the selection model + * to select the new item. + * + * Creation components may call this method in the process listener of their + * form. See {@link PageCreate} for an example. + * + * @param state + * @param name + * @param section + * @param folder + * + * @return the new content item (or a proper subclass thereof) + * + * @throws com.arsdigita.bebop.FormProcessException + */ + public ContentItem createContentPage(final PageState state, + final String name, + final ContentSection section, + final Folder folder) + throws FormProcessException { + + final ItemSelectionModel selectionModel = getItemSelectionModel(); + final ContentType contentType = selectionModel.getContentType(); + + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final ContentItemManager itemManager = cdiUtil + .findBean(ContentItemManager.class); + + // Create new item + final ContentItem item; + try { + @SuppressWarnings("unchecked") + final Class clazz + = (Class) Class + .forName(contentType.getContentItemClass()); + item = itemManager.createContentItem(name, section, folder, clazz); + } catch (ClassNotFoundException ex) { + throw new FormProcessException( + "Couldn't create contentpage", + new GlobalizedMessage( + "cms.ui.authoring.couldnt_create_contentpage", + CmsConstants.CMS_BUNDLE), + ex); + } + + // Create new item + + // Make sure the item will be remembered across requests + selectionModel.setSelectedKey(state, item.getObjectId()); + + return item; + } + + /** + * Constructs a new LaunchDateValidationListener. + */ + private class LaunchDateValidationListener implements ParameterListener { + + @Override + public void validate(final ParameterEvent event) { + + final ParameterData data = event.getParameterData(); + final Object value = data.getValue(); + + if (value == null) { + data.addError("launch date is required"); + } + } + + } + +} diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/CreationComponent.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/CreationComponent.java new file mode 100755 index 000000000..b636a5d88 --- /dev/null +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/CreationComponent.java @@ -0,0 +1,64 @@ +/* + * 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.cms.ui.authoring; + +import com.arsdigita.bebop.Container; +import com.arsdigita.bebop.SaveCancelSection; +import com.arsdigita.bebop.event.FormProcessListener; + +/** + * Interface which item creation components should implement. It's + * currently an optional interface, but user defined content types + * will not work unless they inherit from a type whose creation + * component implements this. This interface currently only defines + * methods which are essential to the operation of UDCT creation + * components. + * + * @author Scott Seago (sseago@redhat.com) + */ +public interface CreationComponent extends Container, FormProcessListener { + + /** + * Instantiate and add the save/cancel section for this CreationComponent. + */ + void addSaveCancelSection(); + + /** + * Return the save/cancel section for this CreationComponent. + * + * @return the save/cancel section for this CreationComponent. + */ + SaveCancelSection getSaveCancelSection(); + + /** + * Removes the specified process listener from the + * list of process listeners (if it had previously been added). + * + * @param listener the process listener to remove + */ + void removeProcessListener(FormProcessListener listener); + + /** + * Return the ApplyWorkflowFormSection associated with this CreationComponent. + * + * @return the ApplyWorkflowFormSection associated with this CreationComponent. + */ + ApplyWorkflowFormSection getWorkflowSection(); + +} diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/CreationSelector.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/CreationSelector.java index 632483511..8d6266389 100755 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/CreationSelector.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/CreationSelector.java @@ -26,7 +26,6 @@ import com.arsdigita.bebop.Page; import com.arsdigita.bebop.PageState; import com.arsdigita.bebop.SingleSelectionModel; import com.arsdigita.bebop.form.FormErrorDisplay; -import com.arsdigita.bebop.parameters.BigDecimalParameter; import com.arsdigita.bebop.parameters.LongParameter; import com.arsdigita.cms.ItemSelectionModel; import com.arsdigita.cms.ui.ContentItemPage; @@ -45,14 +44,12 @@ import org.librecms.contentsection.ContentType; import org.librecms.contentsection.ContentTypeManager; import org.librecms.contentsection.ContentTypeRepository; import org.librecms.contentsection.Folder; -import org.librecms.contenttypes.AuthoringKit; import org.librecms.contenttypes.AuthoringKitInfo; import org.librecms.contenttypes.ContentTypeInfo; import org.librecms.contenttypes.ContentTypesManager; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; -import java.math.BigDecimal; import java.util.Optional; /** diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/NewItemForm.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/NewItemForm.java index 10dba3735..026da0a76 100755 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/NewItemForm.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/NewItemForm.java @@ -22,36 +22,28 @@ import com.arsdigita.bebop.BoxPanel; import com.arsdigita.bebop.Form; import com.arsdigita.bebop.Label; import com.arsdigita.bebop.PageState; -import com.arsdigita.bebop.Text; import com.arsdigita.bebop.event.PrintEvent; import com.arsdigita.bebop.event.PrintListener; import com.arsdigita.bebop.form.Option; import com.arsdigita.bebop.form.OptionGroup; import com.arsdigita.bebop.form.SingleSelect; import com.arsdigita.bebop.form.Submit; -import com.arsdigita.bebop.parameters.BigDecimalParameter; import com.arsdigita.bebop.parameters.LongParameter; import com.arsdigita.cms.ui.ItemSearch; import com.arsdigita.globalization.GlobalizedMessage; import com.arsdigita.util.UncheckedWrapperException; import com.arsdigita.xml.Element; -import java.math.BigDecimal; - import org.libreccm.cdi.utils.CdiUtil; import org.libreccm.security.PermissionChecker; import org.librecms.CmsConstants; import org.librecms.contentsection.ContentSection; import org.librecms.contentsection.ContentType; import org.librecms.contentsection.ContentTypeRepository; -import org.librecms.contentsection.privileges.TypePrivileges; import java.util.List; import java.util.TooManyListenersException; -import java.util.stream.Collectors; -import org.libreccm.l10n.GlobalizationHelper; -import org.librecms.contentsection.ContentTypeManager; import org.librecms.contenttypes.ContentTypeInfo; import org.librecms.contenttypes.ContentTypesManager; @@ -107,7 +99,7 @@ public abstract class NewItemForm extends Form { createLabel.setIdAttr("create_label"); panel.add(createLabel); - typeSelect = new SingleSelect(new BigDecimalParameter(TYPE_ID), + typeSelect = new SingleSelect(new LongParameter(TYPE_ID), OptionGroup.SortMode.ALPHABETICAL_ASCENDING); try { typeSelect.addPrintListener(new PrintListener() { diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/PageCreate.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/PageCreate.java new file mode 100755 index 000000000..a5a6247dc --- /dev/null +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/PageCreate.java @@ -0,0 +1,222 @@ +/* + * 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.authoring; + +import com.arsdigita.bebop.ColumnPanel; +import com.arsdigita.bebop.FormData; +import com.arsdigita.bebop.FormProcessException; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.event.FormSectionEvent; +import com.arsdigita.bebop.event.FormSubmissionListener; + +import org.librecms.contentsection.ContentSection; +import org.librecms.contentsection.ContentType; +import org.librecms.contentsection.Folder; + +import com.arsdigita.cms.ItemSelectionModel; +import com.arsdigita.globalization.GlobalizedMessage; +import com.arsdigita.kernel.KernelConfig; +import com.arsdigita.util.Assert; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.arsdigita.cms.CMSConfig; +import org.librecms.CmsConstants; +import org.librecms.contentsection.ContentItem; + +import java.util.Date; +import java.util.Locale; + +/** + * A form which will create a new document (that is subclasses of class + * ContentPage). + * + * Used to create a new document / content item. Creates widgets to select the + * workflow, and language. It displays the type of document as well. Super class + * adds additional widgets (title and name/URL) to complete the form. + * + * It's a pane which is part of a more complex page, additionally containing + * folder structure, content items in the folder, permissions, etc. + * + * @author Stanislav Freidin (stas@arsdigita.com) + * @author Jens Pelzetter + */ +public class PageCreate + extends BasicPageForm + implements FormSubmissionListener, CreationComponent { + + private final CreationSelector creationSelector; + private final ApplyWorkflowFormSection workflowSection; + + /** + * The state parameter which specifies the content section + */ + public static final String SECTION_ID = "sid"; + + /** + * Construct a new PageCreationForm + * + * @param itemModel The {@link ItemSelectionModel} which will be + * responsible for loading the current item + * @param creationSelector The {@link CreationSelector} parent. This class + * should call either the {@link + * CreationSelector#redirectBack(PageState)} or {@link + * CreationSelector#editItem(PageState, ContentItem)} methods on the parent + * eventually + */ + public PageCreate(final ItemSelectionModel itemModel, + final CreationSelector creationSelector) { + + super("PageCreate", itemModel); + + this.creationSelector = creationSelector; + + /* Retrieve Content Type */ + final ContentType type = getItemSelectionModel().getContentType(); + /* Add workflow selection based on configured Content Type */ + workflowSection = new ApplyWorkflowFormSection(type); + + workflowSection.setCreationSelector(creationSelector); + addSubmissionListener(this); + + getSaveCancelSection().getSaveButton() + .setButtonLabel(new GlobalizedMessage("cms.ui.create", + CmsConstants.CMS_BUNDLE)); + } + + /** + * Add various widgets to the form. Child classes should override this + * method to perform all their widget-adding needs. + */ + @Override + protected void addWidgets() { + + add(workflowSection, ColumnPanel.INSERT); + /* content type */ + add(new Label(new GlobalizedMessage("cms.ui.authoring.content_type", + CmsConstants.CMS_BUNDLE))); + /* Retrieve Content Type */ + final ContentType type = getItemSelectionModel().getContentType(); + add(new Label(type.getLabel().getValue(KernelConfig + .getConfig() + .getDefaultLocale()))); + /* language selection */ + add(new Label(new GlobalizedMessage("cms.ui.language.field", + CmsConstants.CMS_BUNDLE))); + add(new LanguageWidget(LANGUAGE)); + + /* Additional widgets from super type: title and name (url) */ + super.addWidgets(); + } + + /** + * Return the ApplyWorkflowFormSection associated with this + * CreationComponent. + * + * @return the ApplyWorkflowFormSection associated with this + * CreationComponent. + */ + @Override + public ApplyWorkflowFormSection getWorkflowSection() { + return workflowSection; + } + + /** + * Create a new item id. + * + * @throws com.arsdigita.bebop.FormProcessException + */ + @Override + public void init(final FormSectionEvent event) throws FormProcessException { + // this is currently a no-op + } + + /** + * If the Cancel button was pressed, hide self and show the display + * component. + * + * @throws com.arsdigita.bebop.FormProcessException + */ + @Override + public void submitted(final FormSectionEvent event) + throws FormProcessException { + + final PageState state = event.getPageState(); + + if (getSaveCancelSection().getCancelButton().isSelected(state)) { + creationSelector.redirectBack(state); + + throw new FormProcessException( + new GlobalizedMessage("cms.ui.authoring.submission_cancelled", + CmsConstants.CMS_BUNDLE)); + } + } + + /** + * Validate inputs to ensure name uniqueness. Note: We can't call + * {@code super.validate(FormSectionEvent)} here because the super method + * {@link BasicPageForm#validate(com.arsdigita.bebop.event.FormSectionEvent)} + * tries to access things which on existing yet. + * + * @param event + * + * @throws com.arsdigita.bebop.FormProcessException + */ + @Override + public void validate(final FormSectionEvent event) + throws FormProcessException { + + final Folder folder = creationSelector.getFolder(event.getPageState()); + validateNameUniqueness(folder, event); + } + + /** + * Class specific implementation if FormProcessListener (as inherited from + * BasicItemForm), saves fields to the database. + * + * @param event + * + * @throws FormProcessException + */ + @Override + public void process(final FormSectionEvent event) + throws FormProcessException { + + final FormData data = event.getFormData(); + final PageState state = event.getPageState(); + final ContentSection section = creationSelector.getContentSection(state); + final Folder folder = creationSelector.getFolder(state); + + Assert.exists(section, ContentSection.class); + + final ContentItem item = createContentPage(state, + (String) data.get(NAME), + section, + folder); + final Locale locale = new Locale((String) data.get(LANGUAGE)); + item.getName().addValue(locale, (String) data.get(NAME)); + item.getTitle().addValue(locale, (String) data.get(TITLE)); + + workflowSection.applyWorkflow(state, item); + + creationSelector.editItem(state, item); + } + +}