diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ItemSelectionModel.java b/ccm-cms/src/main/java/com/arsdigita/cms/ItemSelectionModel.java index 5b50a0a01..6fd29c125 100755 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ItemSelectionModel.java +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ItemSelectionModel.java @@ -53,9 +53,6 @@ public class ItemSelectionModel extends CcmObjectSelectionModel { private Long typeId; - private static final Logger LOGGER = Logger.getLogger( - ItemSelectionModel.class); - /** * Construct a new ItemSelectionModel * diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/BrowsePane.java.off b/ccm-cms/src/main/java/com/arsdigita/cms/ui/BrowsePane.java.todo similarity index 100% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/BrowsePane.java.off rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/BrowsePane.java.todo diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/FlatItemList.java.off b/ccm-cms/src/main/java/com/arsdigita/cms/ui/FlatItemList.java.todo similarity index 100% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/FlatItemList.java.off rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/FlatItemList.java.todo diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/ImagesPane.java.off b/ccm-cms/src/main/java/com/arsdigita/cms/ui/ImagesPane.java.todo similarity index 100% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/ImagesPane.java.off rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/ImagesPane.java.todo diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearch.java.off b/ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearch.java.todo similarity index 100% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearch.java.off rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearch.java.todo diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearchPage.java.off b/ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearchPage.java.todo similarity index 100% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearchPage.java.off rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/ItemSearchPage.java.todo diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/ReportPane.java.off b/ccm-cms/src/main/java/com/arsdigita/cms/ui/ReportPane.java.todo similarity index 100% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/ReportPane.java.off rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/ReportPane.java.todo diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/NewItemForm.java.off b/ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/NewItemForm.java.todo similarity index 100% rename from ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/NewItemForm.java.off rename to ccm-cms/src/main/java/com/arsdigita/cms/ui/authoring/NewItemForm.java.todo diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/item/ItemLanguages.java.todo b/ccm-cms/src/main/java/com/arsdigita/cms/ui/item/ItemLanguages.java.todo index 2052edb7e..04c0e8151 100755 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/item/ItemLanguages.java.todo +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/item/ItemLanguages.java.todo @@ -23,6 +23,7 @@ import com.arsdigita.bebop.Form; import com.arsdigita.bebop.FormProcessException; import com.arsdigita.bebop.Label; import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.SingleSelectionModel; import com.arsdigita.bebop.event.FormProcessListener; import com.arsdigita.bebop.event.FormSectionEvent; import com.arsdigita.bebop.event.PrintEvent; @@ -30,13 +31,17 @@ import com.arsdigita.bebop.event.PrintListener; import com.arsdigita.bebop.form.Option; import com.arsdigita.bebop.form.OptionGroup; import com.arsdigita.bebop.form.Submit; + import org.librecms.contentsection.ContentItem; import org.librecms.contentsection.ContentSection; import org.librecms.contentsection.ContentType; + import com.arsdigita.cms.ItemSelectionModel; import com.arsdigita.cms.ui.ContentItemPage; import com.arsdigita.cms.ui.authoring.LanguageWidget; + import org.librecms.util.LanguageUtil; + import com.arsdigita.globalization.GlobalizedMessage; import com.arsdigita.toolbox.ui.ActionGroup; import com.arsdigita.toolbox.ui.LayoutPanel; @@ -46,12 +51,17 @@ import com.arsdigita.util.Pair; import com.arsdigita.util.UncheckedWrapperException; import com.arsdigita.web.RedirectSignal; import com.arsdigita.web.URL; + +import org.libreccm.cdi.utils.CdiUtil; import org.libreccm.workflow.Workflow; import org.libreccm.workflow.WorkflowTemplate; +import org.librecms.contentsection.ContentItemL10NManager; import java.util.Collection; import java.util.Iterator; +import java.util.List; import java.util.TooManyListenersException; +import java.util.stream.Collectors; /** * Displays the "Language instances" pane, with all the language instances in @@ -63,6 +73,7 @@ import java.util.TooManyListenersException; public class ItemLanguages extends LayoutPanel { private final ItemSelectionModel selectionModel; + private final SingleSelectionModel selectedLanguage; private final LanguageWidget languageWidget; private final Submit changeSubmit; private final Submit createSubmit; @@ -70,11 +81,15 @@ public class ItemLanguages extends LayoutPanel { /** * Constructs a new ItemLanguages. * - * @param selectionModel the {@link ItemSelectionModel} which will supply - * the current item + * @param selectionModel the {@link ItemSelectionModel} which will supply + * the current item + * @param selectedLanguage {@link SingleSelectionModel} for the selected + * language. */ - public ItemLanguages(final ItemSelectionModel selectionModel) { + public ItemLanguages(final ItemSelectionModel selectionModel, + final SingleSelectionModel selectedLanguage) { this.selectionModel = selectionModel; + this.selectedLanguage = selectedLanguage; final Section section = new Section(gz("cms.ui.item.languages")); setBody(section); @@ -82,15 +97,17 @@ public class ItemLanguages extends LayoutPanel { final ActionGroup group = new ActionGroup(); section.setBody(group); - group.setSubject(new ItemLanguagesTable(selectionModel)); + group.setSubject(new ItemLanguagesTable(selectionModel, + selectedLanguage)); final Form form = new Form("newLanguage", new BoxPanel( BoxPanel.HORIZONTAL)); group.addAction(form); form.setRedirecting(true); - languageWidget = new LanguageWidget(ContentItem.LANGUAGE) { + languageWidget = new LanguageWidget("language_widget") { + @Override protected void setupOptions() { // Don't do anything. } @@ -99,8 +116,8 @@ public class ItemLanguages extends LayoutPanel { try { languageWidget.addPrintListener(new OptionPrinter()); - } catch (TooManyListenersException tmle) { - new UncheckedWrapperException(tmle); + } catch (TooManyListenersException ex) { + throw new UncheckedWrapperException(ex); } form.add(languageWidget); @@ -116,16 +133,26 @@ public class ItemLanguages extends LayoutPanel { */ private class OptionPrinter implements PrintListener { - public final void prepare(final PrintEvent e) { - final PageState state = e.getPageState(); - final OptionGroup optionGroup = (OptionGroup) e.getTarget(); - final ContentPage item = (ContentPage) selectionModel. - getSelectedItem(state); - final Collection languages = LanguageUtil.convertToG11N( - LanguageUtil.getCreatableLanguages(item)); + @Override + public final void prepare(final PrintEvent event) { + final PageState state = event.getPageState(); + final OptionGroup optionGroup = (OptionGroup) event.getTarget(); + final ContentItem item = selectionModel.getSelectedItem(state); - for (Iterator iter = languages.iterator(); iter.hasNext();) { - final Pair pair = (Pair) iter.next(); + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final LanguageUtil languageUtil = cdiUtil.findBean( + LanguageUtil.class); + final ContentItemL10NManager l10NManager = cdiUtil.findBean( + ContentItemL10NManager.class); + + final List creatableLangs = l10NManager.creatableLocales( + item).stream() + .map(locale -> locale.toString()) + .collect(Collectors.toList()); + final List languages = languageUtil.convertToG11N( + creatableLangs); + + for(final Pair pair : languages) { final String langCode = (String) pair.getKey(); final GlobalizedMessage langName = (GlobalizedMessage) pair @@ -141,9 +168,10 @@ public class ItemLanguages extends LayoutPanel { */ private class ProcessListener implements FormProcessListener { - public final void process(final FormSectionEvent e) + @Override + public final void process(final FormSectionEvent event) throws FormProcessException { - PageState state = e.getPageState(); + PageState state = event.getPageState(); String lang = (String) languageWidget.getValue(state); ContentPage item = (ContentPage) selectionModel.getSelectedItem( state); diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/item/ItemLanguagesController.java b/ccm-cms/src/main/java/com/arsdigita/cms/ui/item/ItemLanguagesController.java new file mode 100644 index 000000000..58817e0f7 --- /dev/null +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/item/ItemLanguagesController.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2016 LibreCCM Foundation. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package com.arsdigita.cms.ui.item; + +import com.arsdigita.bebop.table.RowData; + +import org.libreccm.l10n.GlobalizationHelper; +import org.librecms.contentsection.ContentItem; +import org.librecms.contentsection.ContentItemL10NManager; +import org.librecms.contentsection.ContentItemRepository; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +import javax.transaction.Transactional; + +/** + * + * @author Jens Pelzetter + */ +@RequestScoped +public class ItemLanguagesController { + + @Inject + private ContentItemRepository itemRepo; + + @Inject + private ContentItemL10NManager itemL10NManager; + + @Inject + private GlobalizationHelper globalizationHelper; + + public List> retrieveLanguageVariants(final ContentItem item) { + return retrieveLanguageVariants(item.getObjectId()); + } + + @Transactional(Transactional.TxType.REQUIRED) + public List> retrieveLanguageVariants(final long itemId) { + final Optional item = itemRepo.findById(itemId); + + if (!item.isPresent()) { + throw new IllegalArgumentException(String.format( + "No content item with id %d found.", itemId)); + } + + final List availableLangs = new ArrayList<>(itemL10NManager + .availableLanguages(item.get())); + availableLangs.sort((locale1, locale2) -> { + return locale1.toString().compareTo(locale2.toString()); + }); + + return availableLangs.stream() + .map(lang -> createRow(item.get(), lang)) + .collect(Collectors.toList()); + } + + private RowData createRow(final ContentItem item, + final Locale lang) { + final RowData row = new RowData<>(2); + row.setRowKey(lang.toString()); + row.setColData(0, lang.getDisplayName(globalizationHelper.getNegotiatedLocale())); + row.setColData(1, item.getTitle().getValue(lang)); + + return row; + } + +} diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/item/ItemLanguagesTable.java.todo b/ccm-cms/src/main/java/com/arsdigita/cms/ui/item/ItemLanguagesTable.java.todo index 3f8007e09..5c05baf98 100755 --- a/ccm-cms/src/main/java/com/arsdigita/cms/ui/item/ItemLanguagesTable.java.todo +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/item/ItemLanguagesTable.java.todo @@ -18,237 +18,162 @@ */ package com.arsdigita.cms.ui.item; -import com.arsdigita.bebop.event.TableActionAdapter; +import com.arsdigita.bebop.Component; +import com.arsdigita.bebop.ControlLink; +import com.arsdigita.bebop.FormProcessException; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.Link; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.SingleSelectionModel; +import com.arsdigita.bebop.Table; import com.arsdigita.bebop.event.TableActionEvent; +import com.arsdigita.bebop.event.TableActionListener; import com.arsdigita.bebop.table.TableCellRenderer; import com.arsdigita.bebop.table.TableColumn; +import com.arsdigita.bebop.table.TableColumnModel; import com.arsdigita.cms.ItemSelectionModel; -import com.arsdigita.cms.dispatcher.MultilingualItemResolver; import com.arsdigita.cms.ui.ContentItemPage; +import com.arsdigita.globalization.GlobalizedMessage; + +import org.libreccm.cdi.utils.CdiUtil; +import org.librecms.CmsConstants; +import org.librecms.contentsection.ContentItem; +import org.librecms.contentsection.ContentItemL10NManager; import org.librecms.util.LanguageUtil; -import com.arsdigita.toolbox.ui.DataTable; -import com.arsdigita.util.LockableImpl; -import com.arsdigita.web.RedirectSignal; -import com.arsdigita.web.URL; -import java.math.BigDecimal; -import org.apache.log4j.Logger; + +import java.util.Locale; + /** - * Displays a list of all language instances of an item. + * Displays a list of all language instances of an item. * */ -public class ItemLanguagesTable extends DataTable { +public class ItemLanguagesTable extends Table { - private static final Logger LOGGER = Logger.getLogger(ItemLanguagesTable.class); - private final ItemSelectionModel m_model; - private final TableColumn m_deleteColumn; + public static final int COL_LANGUAGE = 0; + public static final int COL_TITLE = 1; + public static final int COL_DELETE = 2; + + private final ItemSelectionModel itemSelectionModel; + private final SingleSelectionModel langSelectionModel; +// private final TableColumn deleteColumn; /** - * Construct a new - * ItemHistoryTable + * Construct a new {@code ItemLanguagesTable} which shows all language + * variants of an item. * - * @param model the ItemSelectionModel that supplies the current item + * @param itemSelectionModel the ItemSelectionModel that supplies the + * current item + * @param langSelectionModel the single selection model which stores the + * selected language. */ - public ItemLanguagesTable(ItemSelectionModel model) { - super(new LanguagesBuilder(model)); - m_model = model; + public ItemLanguagesTable(final ItemSelectionModel itemSelectionModel, + final SingleSelectionModel langSelectionModel) { + super(); + setIdAttr("item_languages_table"); - addColumn("cms.ui.language.header", - ContentPage.LANGUAGE, - false, - new LanguageCellRenderer(m_model)); - addColumn("cms.ui.title", - ContentPage.TITLE); - m_deleteColumn = addColumn("cms.ui.action", new ActionCellRenderer( - m_model)); - setResourceBundle(GlobalizationUtil.getBundleName()); - addTableActionListener(new InstanceDeleter(m_model)); - } + this.itemSelectionModel = itemSelectionModel; + this.langSelectionModel = langSelectionModel; + setModelBuilder(new ItemLanguagesTableModelBuilder(itemSelectionModel)); - /** - * Builds the query for all the language instances in the current Bundle - */ - private static class LanguagesBuilder extends LockableImpl - implements DataQueryBuilder { + final TableColumnModel columnModel = getColumnModel(); + columnModel.add(new TableColumn(COL_LANGUAGE, + new Label(new GlobalizedMessage( + "cms.ui.language.header", + CmsConstants.CMS_BUNDLE)))); + columnModel.add(new TableColumn(COL_TITLE, + new Label(new GlobalizedMessage( + "cms.ui.language.title", + CmsConstants.CMS_BUNDLE)))); + columnModel.add(new TableColumn(COL_DELETE, + new Label(new GlobalizedMessage( + "cms.ui.action", + CmsConstants.CMS_BUNDLE)))); - ItemSelectionModel m_model; + columnModel.get(COL_LANGUAGE).setCellRenderer(new TableCellRenderer() { - public LanguagesBuilder(ItemSelectionModel model) { - super(); - m_model = model; - } + @Override + public Component getComponent(final Table table, + final PageState state, + final Object value, + final boolean isSelected, + final Object key, + final int row, + final int column) { - public DataQuery makeDataQuery(DataTable t, PageState s) { - ContentPage multiLingual = - (ContentPage) m_model.getSelectedObject(s); - DataQuery q = SessionManager.getSession().retrieveQuery( - "com.arsdigita.cms.getBundledItems"); - q.setParameter("bundleID", multiLingual.getContentBundle().getID()); - return q; - } + final Locale locale = new Locale((String) value); - public String getKeyColumn() { - return ContentPage.ID; - } - } + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final LanguageUtil langUtil = cdiUtil.findBean( + LanguageUtil.class); - /** - * Renders the full language name. - */ - private static class LanguageCellRenderer implements TableCellRenderer { + final Label label = new Label(langUtil.getLangFull(locale)); - private ItemSelectionModel m_model; - - public LanguageCellRenderer(ItemSelectionModel model) { - m_model = model; - } - - public Component getComponent(Table table, PageState state, Object value, - boolean isSelected, Object key, - int row, int column) { - - BigDecimal id = (BigDecimal) key; - ContentPage cp; - - try { - cp = new ContentPage(id); - } catch (DataObjectNotFoundException ex) { - // Content item was not found, return nothing - return new Label(); - } - - ContentBundle bundle = cp.getContentBundle(); - - if (bundle != null - && !(cp instanceof LanguageInvariantContentItem - && ((LanguageInvariantContentItem) cp).isLanguageInvariant())) { - - StringBuilder fontWeight = new StringBuilder(2); - StringBuilder classes = new StringBuilder(20); - - if (cp.isLive()) { - fontWeight.append(Label.BOLD); - classes.append("live "); - } - if (bundle.getPrimaryInstance().equals(cp)) { - fontWeight.append(Label.ITALIC); - classes.append("primaryInstance"); - } - - String target = ContentItemPage.getItemURL(cp, ContentItemPage.AUTHORING_TAB); - Label langLabel = new Label(LanguageUtil.getLangFull((String) value)); - - langLabel.setFontWeight(fontWeight.toString().trim()); - langLabel.setClassAttr(classes.toString().trim()); - - if (m_model.getSelectedKey(state).equals(key)) { - // Current instance: no link - return langLabel; + if (langSelectionModel.getSelectedKey(state).equals(key)) { + // Current variant, no link + return label; } else { - return new Link(langLabel, target); + final String target = ContentItemPage.getItemURL( + itemSelectionModel.getSelectedItem(state), + ContentItemPage.AUTHORING_TAB); + return new Link(label, target); } } - return new Label(); } + ); + columnModel.get(COL_DELETE).setCellRenderer(new TableCellRenderer() { + + @Override + public Component getComponent(final Table table, + final PageState state, + final Object value, + final boolean isSelected, + final Object key, + final int row, + final int column) { + + final ControlLink link = new ControlLink(new Label( + new GlobalizedMessage("cms.ui.delete", + CmsConstants.CMS_BUNDLE))); + link.setConfirmation(new GlobalizedMessage( + "cms.ui.delete.confirmation", CmsConstants.CMS_BUNDLE)); + + return link; + } + + }); + + addTableActionListener(new TableActionListener() { + + @Override + public void cellSelected(final TableActionEvent event) + throws FormProcessException { + + if (event.getColumn() != COL_DELETE) { + //Nothing to do + return; + } + + final PageState state = event.getPageState(); + final ContentItem item = itemSelectionModel + .getSelectedItem(state); + final String selectedLang = (String) event.getRowKey(); + + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final ContentItemL10NManager l10nManager = cdiUtil.findBean( + ContentItemL10NManager.class); + + l10nManager.removeLangauge(item, new Locale(selectedLang)); + } + + @Override + public void headSelected(final TableActionEvent event) { + //Nothing + } + + }); + } - /** - * Delete language instance action link. - */ - private static class ActionCellRenderer implements TableCellRenderer { - - private static final Logger logger = - Logger.getLogger(ActionCellRenderer.class); - private static final Label s_noAction; - private static final Label s_primary; - private static final ControlLink s_link; - - static { - logger.debug("Static initializer is starting..."); - s_noAction = new Label(" ", false); - s_noAction.lock(); - s_primary = new Label(GlobalizationUtil.globalize( - "cms.ui.primary_instance"), false); - s_primary.lock(); - s_link = new ControlLink(new Label(GlobalizationUtil.globalize( - "cms.ui.delete"))); - s_link.setConfirmation(GlobalizationUtil.globalize( - "cms.ui.delete_confirmation")); - logger.debug("Static initalizer finished."); - } - private ItemSelectionModel m_model; - - public ActionCellRenderer(ItemSelectionModel model) { - m_model = model; - } - - public Component getComponent(Table table, PageState state, Object value, - boolean isSelected, Object key, - int row, int column) { - // check if primary instance - BigDecimal id = new BigDecimal(key.toString()); - OID oid = new OID(ContentPage.BASE_DATA_OBJECT_TYPE, id); - try { - ContentPage item = (ContentPage) DomainObjectFactory.newInstance(oid); - if (item.getLanguage().equals( - item.getContentBundle().getDefaultLanguage())) { - return s_primary; - } else if (item.isLive()) { - return s_noAction; - } - } catch (DataObjectNotFoundException ex) { - if (logger.isDebugEnabled()) { - logger.debug("Could not get item with id " + id); - } - return s_noAction; - } - return s_link; - } - } - - // delete one language instance - private class InstanceDeleter extends TableActionAdapter { - - private ItemSelectionModel m_model; - - public InstanceDeleter(ItemSelectionModel model) { - m_model = model; - } - - @Override - public void cellSelected(TableActionEvent e) { - int col = e.getColumn().intValue(); - - if (m_deleteColumn != getColumn(col)) { - return; - } - - PageState s = e.getPageState(); - BigDecimal id = new BigDecimal(e.getRowKey().toString()); - - OID oid = new OID(ContentPage.BASE_DATA_OBJECT_TYPE, id); - try { - ContentPage item = - (ContentPage) DomainObjectFactory.newInstance(oid); - ContentBundle bundle = item.getContentBundle(); - bundle.removeInstance(item); - item.delete(); - - if (m_model.getSelectedKey(s).equals(id)) { - throw new RedirectSignal( - URL.there((new MultilingualItemResolver() - .generateItemURL(s, - bundle.getPrimaryInstance(), - bundle.getContentSection(), - ContentItem.DRAFT)), - null), - true); - } - } catch (com.arsdigita.domain.DataObjectNotFoundException ex) { - // Object not found is ok, it has probably been deleted already - } - ((Table) e.getSource()).clearSelection(s); - } - } } diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/item/ItemLanguagesTableModel.java.todo b/ccm-cms/src/main/java/com/arsdigita/cms/ui/item/ItemLanguagesTableModel.java.todo new file mode 100644 index 000000000..8ba74ad03 --- /dev/null +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/item/ItemLanguagesTableModel.java.todo @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2016 LibreCCM Foundation. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package com.arsdigita.cms.ui.item; + +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.table.RowData; +import com.arsdigita.bebop.table.TableModel; +import com.arsdigita.globalization.GlobalizedMessage; + +import org.librecms.CmsConstants; + +import java.util.Iterator; +import java.util.List; + +/** + * + * @author Jens Pelzetter + */ +class ItemLanguagesTableModel implements TableModel { + + private final Iterator> iterator; + private RowData curentRow; + + protected ItemLanguagesTableModel(final List> rows) { + iterator = rows.iterator(); + } + + @Override + public int getColumnCount() { + return 3; + } + + @Override + public boolean nextRow() { + if (iterator.hasNext()) { + curentRow = iterator.next(); + return true; + } else { + return false; + } + } + + @Override + public Object getElementAt(final int columnIndex) { + switch (columnIndex) { + case ItemLanguagesTable.COL_LANGUAGE: + return curentRow.getColData(0); + case ItemLanguagesTable.COL_TITLE: + return curentRow.getColData(1); + case ItemLanguagesTable.COL_DELETE: + return new Label(new GlobalizedMessage("cms.ui.delete", + CmsConstants.CMS_BUNDLE)); + default: + throw new IllegalArgumentException("Invalid column index."); + } + } + + @Override + public Object getKeyAt(final int columnIndex) { + return curentRow.getRowKey(); + } + +} diff --git a/ccm-cms/src/main/java/com/arsdigita/cms/ui/item/ItemLanguagesTableModelBuilder.java.todo b/ccm-cms/src/main/java/com/arsdigita/cms/ui/item/ItemLanguagesTableModelBuilder.java.todo new file mode 100644 index 000000000..599700e33 --- /dev/null +++ b/ccm-cms/src/main/java/com/arsdigita/cms/ui/item/ItemLanguagesTableModelBuilder.java.todo @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2016 LibreCCM Foundation. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package com.arsdigita.cms.ui.item; + +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.Table; +import com.arsdigita.bebop.table.RowData; +import com.arsdigita.bebop.table.TableModel; +import com.arsdigita.bebop.table.TableModelBuilder; +import com.arsdigita.cms.ItemSelectionModel; +import com.arsdigita.util.LockableImpl; + +import org.libreccm.cdi.utils.CdiUtil; +import org.librecms.contentsection.ContentItem; + +import java.util.List; + +/** + * + * @author Jens Pelzetter + */ +class ItemLanguagesTableModelBuilder + extends LockableImpl + implements TableModelBuilder { + + private final ItemSelectionModel itemSelectionModel; + + protected ItemLanguagesTableModelBuilder( + final ItemSelectionModel itemSelectionModel) { + this.itemSelectionModel = itemSelectionModel; + } + + @Override + public TableModel makeModel(final Table table, final PageState state) { + final ContentItem item = itemSelectionModel.getSelectedItem(state); + + final CdiUtil cdiUtil = CdiUtil.createCdiUtil(); + final ItemLanguagesController controller = cdiUtil.findBean(ItemLanguagesController.class); + final List> rows = controller.retrieveLanguageVariants( + item); + + return new ItemLanguagesTableModel(rows); + } + +} diff --git a/ccm-cms/src/main/java/org/librecms/contentsection/ContentItemL10NManager.java b/ccm-cms/src/main/java/org/librecms/contentsection/ContentItemL10NManager.java index 400880964..25e17367b 100644 --- a/ccm-cms/src/main/java/org/librecms/contentsection/ContentItemL10NManager.java +++ b/ccm-cms/src/main/java/org/librecms/contentsection/ContentItemL10NManager.java @@ -24,6 +24,7 @@ import com.arsdigita.util.UncheckedWrapperException; import org.libreccm.configuration.ConfigurationManager; import org.libreccm.l10n.LocalizedString; import org.libreccm.security.AuthorizationRequired; +import org.libreccm.security.PermissionChecker; import org.libreccm.security.RequiresPrivilege; import org.librecms.CmsConstants; import org.librecms.contentsection.privileges.ItemPrivileges; @@ -34,9 +35,11 @@ import java.beans.PropertyDescriptor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Locale; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -60,6 +63,9 @@ public class ContentItemL10NManager { @Inject private ContentItemRepository itemRepo; + @Inject + private PermissionChecker permissionChecker; + private Locale defaultLocale; private List supportedLocales; @@ -112,6 +118,50 @@ public class ContentItemL10NManager { return locales; } + /** + * Helper method for reading methods in this class for verifying that the + * current user is permitted to read the item. + * + * If the provided {@code item} is a live item + * ({@link ContentItem#getVersion()} returns + * {@link ContentItemVersion#LIVE}) the current user needs the a permission + * which grants the {@link ItemPrivileges#VIEW_PUBLISHED} privilege for the + * provided {@code item}. If the item is a draft item + * ({@link ContentItem#getVersion()} returns + * {@link ContentItemVersion#DRAFT}, {@link ContentItemVersion#PENDING} or + * {@link ContentItemVersion#PUBLISHING} the user needs a permission which + * grants the {@link ItemPrivileges#PREVIEW} privilege for the provided + * {@code item}. + * + * @param item The item for which the read permission is verified. + */ + private void checkReadPermission(final ContentItem item) { + final String requiredPrivilege; + if (ContentItemVersion.LIVE == item.getVersion()) { + requiredPrivilege = ItemPrivileges.VIEW_PUBLISHED; + } else { + requiredPrivilege = ItemPrivileges.PREVIEW; + } + + permissionChecker.checkPermission(requiredPrivilege, item); + } + + /** + * Retrieves all languages in which content item is available. + * + * @param item The item. + * + * @return A (unmodifiable) {@link Set} containing all languages in which + * the item is available. + */ + @Transactional(Transactional.TxType.REQUIRED) + public Set availableLanguages( + final ContentItem item) { + + checkReadPermission(item); + return Collections.unmodifiableSet(collectLanguages(item)); + } + /** * Checks if an content item has data for particular language. * @@ -121,8 +171,13 @@ public class ContentItemL10NManager { * @return {@link true} if the item has data for the language, {@code false} * if not. */ + @AuthorizationRequired @Transactional(Transactional.TxType.REQUIRED) - public boolean hasLanguage(final ContentItem item, final Locale locale) { + public boolean hasLanguage( + @RequiresPrivilege(ItemPrivileges.VIEW_PUBLISHED) + final ContentItem item, + final Locale locale) { + if (item == null) { throw new IllegalArgumentException("Can't check if item null has a" + "specific locale."); @@ -132,14 +187,27 @@ public class ContentItemL10NManager { throw new IllegalArgumentException("Can't check for locale null."); } + checkReadPermission(item); + return collectLanguages(item).contains(locale); } - + + /** + * Returns a {@link Set} containing the locales for which the item does not + * yet have a variant. + * + * @param item The item. + * + * @return A {@link Set} with the locales for which the item does not have a + * variant. + */ @Transactional(Transactional.TxType.REQUIRED) public Set creatableLocales(final ContentItem item) { + checkReadPermission(item); + return supportedLocales.stream() - .filter(locale -> hasLanguage(item, locale)) - .collect(Collectors.toSet()); + .filter(locale -> hasLanguage(item, locale)) + .collect(Collectors.toSet()); } /** @@ -149,7 +217,11 @@ public class ContentItemL10NManager { * configured in {@link KernelConfig}. If a field does not have an entry for * the default language the first value found is used. * - * @param item The item to which the language variant is added. + * @param item The item to which the language variant is added. The item + * must be the draft version + * of the item! If a live version or a + * pending version is provided the method will throw an + * {@link IllegalArgumentException}! * @param locale The locale of the language variant to add. */ @AuthorizationRequired @@ -160,7 +232,14 @@ public class ContentItemL10NManager { final Locale locale) { if (item == null) { - throw new IllegalArgumentException("Can't add language to item null."); + throw new IllegalArgumentException( + "Can't add language to item null."); + } + + if (ContentItemVersion.DRAFT != item.getVersion()) { + throw new IllegalArgumentException(String.format( + "The provided item %s is not the draft version of an item.", + Objects.toString(item))); } if (locale == null) { @@ -220,7 +299,11 @@ public class ContentItemL10NManager { * the entry for the provided locale if the field has an entry for that * locale. * - * @param item The item from which the language variant is removed. + * @param item The item from which the language variant is removed. The + * item must be the draft + * version of the item! If a live version or + * a pending version is provided the method will + * throw an {@link IllegalArgumentException}! * @param locale The locale of the language variant to remove. */ @AuthorizationRequired @@ -235,6 +318,12 @@ public class ContentItemL10NManager { "Can't remove language from item null."); } + if (ContentItemVersion.DRAFT != item.getVersion()) { + throw new IllegalArgumentException(String.format( + "The provided item %s is not the draft version of an item.", + Objects.toString(item))); + } + if (locale == null) { throw new IllegalArgumentException( "Can't remove language null from an item."); @@ -268,7 +357,10 @@ public class ContentItemL10NManager { * {@link LocalizedString} has an entry for every language in the set. If * not an entry for the language is added. * - * @param item The item to normalise. + * @param item The item to normalise. The item must be the + * draft version of the item! If a live + * version or a pending version is provided the + * method will throw an {@link IllegalArgumentException}! */ @AuthorizationRequired @Transactional(Transactional.TxType.REQUIRED) @@ -280,6 +372,12 @@ public class ContentItemL10NManager { throw new IllegalArgumentException("Can't normalise item null."); } + if (ContentItemVersion.DRAFT != item.getVersion()) { + throw new IllegalArgumentException(String.format( + "The provided item %s is not the draft version of an item.", + Objects.toString(item))); + } + final Set languages = collectLanguages(item); findLocalizedStringProperties(item)