diff --git a/ccm-bundle-devel-wildfly-web/src/main/resources/shiro.ini b/ccm-bundle-devel-wildfly-web/src/main/resources/shiro.ini index f313a39e8..968eec0b8 100644 --- a/ccm-bundle-devel-wildfly-web/src/main/resources/shiro.ini +++ b/ccm-bundle-devel-wildfly-web/src/main/resources/shiro.ini @@ -7,4 +7,4 @@ passwordMatcher.passwordService = $passwordService ccmRealm = org.libreccm.security.CcmShiroRealm ccmRealm.credentialsMatcher = $passwordMatcher -securityManager.realms = $ccmRealm \ No newline at end of file +securityManager.realms = $ccmRealm diff --git a/ccm-bundle-devel-wildfly-web/src/main/webapp/WEB-INF/classes/META-INF/persistence.xml b/ccm-bundle-devel-wildfly-web/src/main/webapp/WEB-INF/classes/META-INF/persistence.xml index f6d8bf07f..ede5653a7 100644 --- a/ccm-bundle-devel-wildfly-web/src/main/webapp/WEB-INF/classes/META-INF/persistence.xml +++ b/ccm-bundle-devel-wildfly-web/src/main/webapp/WEB-INF/classes/META-INF/persistence.xml @@ -22,6 +22,7 @@ java:/comp/env/jdbc/libreccm/db lib/ccm-core-7.0.0-SNAPSHOT.jar + lib/ccm-shortcuts-7.0.0-SNAPSHOT.jar diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/ApplicationsTab.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/ApplicationsTab.java index e9e7f6553..1e5f6f0c5 100644 --- a/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/ApplicationsTab.java +++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/ApplicationsTab.java @@ -20,7 +20,6 @@ package com.arsdigita.ui.admin.applications; import com.arsdigita.bebop.ActionLink; import com.arsdigita.bebop.BoxPanel; -import com.arsdigita.bebop.Form; import com.arsdigita.bebop.Label; import com.arsdigita.bebop.Page; import com.arsdigita.bebop.PageState; @@ -40,8 +39,6 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; import static com.arsdigita.ui.admin.AdminUiConstants.*; @@ -102,7 +99,14 @@ public class ApplicationsTab extends LayoutPanel { final ApplicationType appType = appManager.getApplicationTypes() .get(appTypeKey); - if (appType.singleton()) { + if (appType == null) { + hideAllInstanceForms(state); + hideAllSettingsPanes(state); + hideAppInfo(state); + hideInstances(state); + hideManagementLinks(state); + hideSingletonAppSettings(state); + } else if (appType.singleton()) { showSingletonAppSettings(state); } else { showInstances(state); @@ -219,6 +223,14 @@ public class ApplicationsTab extends LayoutPanel { page.setVisibleDefault(placeholderSingletonSettings, false); page.setVisibleDefault(appInfo, false); + settingsPanes.forEach((k, v) -> { + page.setVisibleDefault(v, false); + }); + + instanceForms.forEach((k, v) -> { + page.setVisibleDefault(v, false); + }); + } protected void showManagementLinks(final PageState state) { @@ -251,7 +263,13 @@ public class ApplicationsTab extends LayoutPanel { hideAllInstanceForms(state); hideAllSettingsPanes(state); placeholderInstances.setVisible(state, false); - placeholderSingletonSettings.setVisible(state, true); + //placeholderSingletonSettings.setVisible(state, true); + + final String appType = selectedAppType.getSelectedKey(state); + if (settingsPanes.containsKey(appType)) { + settingsPanes.get(appType).setVisible(state, true); + } + appInfo.setVisible(state, false); } diff --git a/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/DefaultApplicationSettingsPane.java b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/DefaultApplicationSettingsPane.java index 6bc63ccff..791acd5b4 100644 --- a/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/DefaultApplicationSettingsPane.java +++ b/ccm-core/src/main/java/com/arsdigita/ui/admin/applications/DefaultApplicationSettingsPane.java @@ -18,14 +18,20 @@ */ package com.arsdigita.ui.admin.applications; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.PageState; import com.arsdigita.bebop.ParameterSingleSelectionModel; -import com.arsdigita.bebop.Text; +import com.arsdigita.globalization.GlobalizedMessage; + +import org.libreccm.web.ApplicationType; + +import static com.arsdigita.ui.admin.AdminUiConstants.*; /** * * @author Jens Pelzetter */ -public class DefaultApplicationSettingsPane +public class DefaultApplicationSettingsPane extends AbstractAppSettingsPane { public DefaultApplicationSettingsPane( @@ -33,13 +39,59 @@ public class DefaultApplicationSettingsPane final ParameterSingleSelectionModel selectedAppInstance) { super(selectedAppType, selectedAppInstance); + + final Label label = new Label(); + label.addPrintListener(e -> { + final PageState state = e.getPageState(); + final ApplicationType appType = getSelectedAppType(state); + + final GlobalizedMessage message; + if (appType.singleton()) { + message = new GlobalizedMessage( + "ui.admin.applications.settings.singleton.no_setting_for", + ADMIN_BUNDLE, + new String[]{appType.name()}); + } else { + message = new GlobalizedMessage( + "ui.admin.applications.settings.instance.no_setting_for", + ADMIN_BUNDLE, + new String[]{appType.name()}); + } + + final Label target = (Label) e.getTarget(); + target.setLabel(message); + }); + + add(label); } @Override protected void createWidgets() { - add(new Text("")); + +// final Label label = new Label(); +// label.addPrintListener(e -> { +// final PageState state = e.getPageState(); +// final ApplicationType appType = getSelectedAppType(state); +// +// final GlobalizedMessage message; +// if (appType.singleton()) { +// message = new GlobalizedMessage( +// "ui.admin.applications.settings.singleton.no_setting_for", +// ADMIN_BUNDLE, +// new String[]{appType.name()}); +// } else { +// message = new GlobalizedMessage( +// "ui.admin.applications.settings.instance.no_setting_for", +// ADMIN_BUNDLE, +// new String[]{appType.name()}); +// } +// +// final Label target = (Label) e.getTarget(); +// target.setLabel(message); +// }); +// +// add(label); + } - - } diff --git a/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources.properties b/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources.properties index 6cb97f0d0..b3243fa8f 100644 --- a/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources.properties +++ b/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources.properties @@ -538,3 +538,5 @@ ui.admin.applications.type.property_sheet.singleton=Singleton? ui.admin.applications.type.property_sheet.servlet_class=Servlet ui.admin.applications.type.property_sheet.servlet_path=Servlet path ui.admin.applications.info.heading=About the application type +ui.admin.applications.settings.singleton.no_setting_for=No settings for application {0} available. +ui.admin.applications.settings.instance.no_setting_for=No settings for instance of application type {0} available. diff --git a/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_de.properties b/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_de.properties index cae914f2f..788b1faa1 100644 --- a/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_de.properties +++ b/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_de.properties @@ -541,3 +541,5 @@ ui.admin.applications.type.property_sheet.singleton=Singleton? ui.admin.applications.type.property_sheet.servlet_class=Servlet ui.admin.applications.type.property_sheet.servlet_path=Servlet-Pfad ui.admin.applications.info.heading=\u00dcber den Applikationstyp +ui.admin.applications.settings.singleton.no_setting_for=Keine Einstellungen f\u00fcr Applikation {0} verf\u00fcbar. +ui.admin.applications.settings.instance.no_setting_for=Keine Einstellungen f\u00fcr Instanzen des Typs {0} verf\u00fcgbar. diff --git a/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_en.properties b/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_en.properties index a330375c2..6336854f4 100755 --- a/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_en.properties +++ b/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_en.properties @@ -534,3 +534,5 @@ ui.admin.applications.type.property_sheet.singleton=Singleton? ui.admin.applications.type.property_sheet.servlet_class=Servlet ui.admin.applications.type.property_sheet.servlet_path=Servlet path ui.admin.applications.info.heading=About the application type +ui.admin.applications.settings.singleton.no_setting_for=No settings for application {0} available. +ui.admin.applications.settings.instance.no_setting_for=No settings for instance of application type {0} available. diff --git a/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_fr.properties b/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_fr.properties index f116fc351..4763e7663 100755 --- a/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_fr.properties +++ b/ccm-core/src/main/resources/com/arsdigita/ui/admin/AdminResources_fr.properties @@ -525,3 +525,5 @@ ui.admin.applications.type.property_sheet.singleton=Singleton? ui.admin.applications.type.property_sheet.servlet_class=Servlet ui.admin.applications.type.property_sheet.servlet_path=Servlet path ui.admin.applications.info.heading=About the application type +ui.admin.applications.settings.singleton.no_setting_for=No settings for application {0} available. +ui.admin.applications.settings.instance.no_setting_for=No settings for instance of application type {0} available. diff --git a/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/ShortcutManager.java b/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/ShortcutManager.java index 61174ca93..c7d55571d 100644 --- a/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/ShortcutManager.java +++ b/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/ShortcutManager.java @@ -23,6 +23,7 @@ import org.libreccm.security.RequiresPrivilege; import javax.enterprise.context.RequestScoped; import javax.inject.Inject; +import javax.transaction.Transactional; /** * This class provides complex operations on {@link Shortcut} objects like @@ -50,6 +51,7 @@ public class ShortcutManager { */ @AuthorizationRequired @RequiresPrivilege(ShortcutsConstants.SHORTSCUT_MANAGE_PRIVILEGE) + @Transactional(Transactional.TxType.REQUIRED) public Shortcut createShortcut(final String url, final String redirect) { if (url == null || url.trim().isEmpty()) { throw new IllegalArgumentException( diff --git a/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/ShortcutRepository.java b/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/ShortcutRepository.java index dad6a40b2..cd39adb5a 100644 --- a/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/ShortcutRepository.java +++ b/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/ShortcutRepository.java @@ -30,6 +30,7 @@ import java.util.Optional; import javax.enterprise.context.RequestScoped; import javax.persistence.NoResultException; import javax.persistence.TypedQuery; +import javax.transaction.Transactional; /** * @@ -91,6 +92,7 @@ public class ShortcutRepository extends AbstractEntityRepository @Override @AuthorizationRequired @RequiresPrivilege(ShortcutsConstants.SHORTSCUT_MANAGE_PRIVILEGE) + @Transactional(Transactional.TxType.REQUIRED) public void save(final Shortcut shortcut) { //Cleanup the URL key shortcut.setUrlKey(cleanUrlKey(shortcut.getUrlKey())); @@ -101,6 +103,7 @@ public class ShortcutRepository extends AbstractEntityRepository @Override @AuthorizationRequired @RequiresPrivilege(ShortcutsConstants.SHORTSCUT_MANAGE_PRIVILEGE) + @Transactional(Transactional.TxType.REQUIRED) public void delete(final Shortcut shortcut) { super.delete(shortcut); } diff --git a/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/Shortcuts.java b/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/Shortcuts.java index 3433156d9..b197d3a2b 100644 --- a/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/Shortcuts.java +++ b/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/Shortcuts.java @@ -26,6 +26,7 @@ import org.libreccm.modules.Module; import org.libreccm.modules.RequiredModule; import org.libreccm.modules.ShutdownEvent; import org.libreccm.modules.UnInstallEvent; +import org.libreccm.shortcuts.ui.ShortcutsSettingsPane; import org.libreccm.web.ApplicationType; /** @@ -38,8 +39,9 @@ import org.libreccm.web.ApplicationType; }, applicationTypes = { @ApplicationType(name = ShortcutsConstants.SHORTCUTS_APP_TYPE, - descBundle = "org.libreccm.shortcuts.ShortcutsResources", + descBundle = ShortcutsConstants.SHORTCUTS_BUNDLE, singleton = true, + settingsPane = ShortcutsSettingsPane.class, creator = ShortcutsApplicationCreator.class)}) public class Shortcuts implements CcmModule { diff --git a/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/ShortcutsConstants.java b/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/ShortcutsConstants.java index 5c2e36182..e02d1771d 100644 --- a/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/ShortcutsConstants.java +++ b/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/ShortcutsConstants.java @@ -23,18 +23,25 @@ package org.libreccm.shortcuts; * @author Jens Pelzetter */ public final class ShortcutsConstants { - + /** * Name of the shortcuts application type */ public static final String SHORTCUTS_APP_TYPE - = "org.libreccm.shortcuts.Shortcuts"; - + = "org.libreccm.shortcuts.Shortcuts"; + + public static final String SHORTCUTS_BUNDLE + = "org.libreccm.shortcuts.ShortcutsResources"; + /** * Primary URL of the singleton Shortcuts application instance. */ public static final String SHORTCUTS_PRIMARY_URL = "/shortcuts/"; - + public static final String SHORTSCUT_MANAGE_PRIVILEGE = "manage_shortcuts"; - + + private ShortcutsConstants() { + //Nothing + } + } diff --git a/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/ui/AdminPanel.java.tmpOff b/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/ui/AdminPanel.java.tmpOff deleted file mode 100644 index 3d3a97a5e..000000000 --- a/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/ui/AdminPanel.java.tmpOff +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2015 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 org.libreccm.shortcuts.ui; - - -import org.apache.log4j.Category; - -import com.arsdigita.bebop.Page; -import com.arsdigita.bebop.ParameterSingleSelectionModel; -import com.arsdigita.bebop.SimpleContainer; -import com.arsdigita.bebop.parameters.LongParameter; - -public class AdminPanel extends SimpleContainer { - - final private ParameterSingleSelectionModel m_shortcut = new ParameterSingleSelectionModel(new LongParameter("ShortcutID")); - - private static final Category log = Category.getInstance(AdminPanel.class - .getName()); - - public AdminPanel() { - add(new ShortcutForm(m_shortcut)); - add(new ShortcutsTable(m_shortcut)); - } - - @Override - public void register(Page p) { - super.register(p); - - p.addGlobalStateParam(m_shortcut.getStateParameter()); - } - -} - diff --git a/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/ui/ShortcutForm.java b/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/ui/ShortcutForm.java new file mode 100644 index 000000000..682fad94e --- /dev/null +++ b/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/ui/ShortcutForm.java @@ -0,0 +1,159 @@ +/* + * 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 org.libreccm.shortcuts.ui; + +import com.arsdigita.bebop.Form; +import com.arsdigita.bebop.FormData; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.ParameterSingleSelectionModel; +import com.arsdigita.bebop.SaveCancelSection; +import com.arsdigita.bebop.form.TextField; +import com.arsdigita.globalization.GlobalizedMessage; + +import org.libreccm.cdi.utils.CdiUtil; +import org.libreccm.shortcuts.Shortcut; +import org.libreccm.shortcuts.ShortcutManager; +import org.libreccm.shortcuts.ShortcutRepository; +import org.libreccm.shortcuts.ShortcutsConstants; + +import java.util.Locale; +import java.util.regex.Pattern; + +/** + * + * @author Jens Pelzetter + */ +public class ShortcutForm extends Form { + + + + private static final String URL_KEY = "urlKey"; + private static final String REDIRECT = "redirect"; + + private final TextField urlKeyField; + private final TextField redirectField; + + private final SaveCancelSection saveCancelSection; + + public ShortcutForm( + final ShortcutsSettingsPane shortcutsPane, + final ParameterSingleSelectionModel selectedShortcut) { + + super("shortcutForm"); + + urlKeyField = new TextField(URL_KEY); + urlKeyField.setLabel(new GlobalizedMessage( + "shortcuts.ui.admin.url_key.label", + ShortcutsConstants.SHORTCUTS_BUNDLE)); + add(urlKeyField); + + redirectField = new TextField(REDIRECT); + redirectField.setLabel(new GlobalizedMessage( + "shortcuts.ui.admin.redirect.label", + ShortcutsConstants.SHORTCUTS_BUNDLE)); + add(redirectField); + + saveCancelSection = new SaveCancelSection(); + add(saveCancelSection); + + addValidationListener(e -> { + final PageState state = e.getPageState(); + final FormData data = e.getFormData(); + + final String urlKey = data.getString(URL_KEY); + if (urlKey == null || urlKey.trim().isEmpty()) { + data.addError(URL_KEY, new GlobalizedMessage( + "shortcuts.ui.admin.url_key.error.not_empty", + ShortcutsConstants.SHORTCUTS_BUNDLE)); + return; + } + + // The URL to redirect must start with a '/' and end with a '/'. + // Between the starting and the ending '/' only the characters + // 'a' to 'z', 'A' to 'Z', '0' to '9', '_', '-' and '.' may appear. + if (!Pattern.matches("^/[-a-zA-Z0-9_./]+/$", urlKey)) { + data.addError(URL_KEY, new GlobalizedMessage( + "shortcuts.ui.admin.url_key.error.invalid", + ShortcutsConstants.SHORTCUTS_BUNDLE)); + return; + } + + if (data.getString(REDIRECT) == null + || data.getString(REDIRECT).trim().isEmpty()) { + data.addError(URL_KEY, new GlobalizedMessage( + "shortcuts.ui.admin.redirect.not_empty", + ShortcutsConstants.SHORTCUTS_BUNDLE)); + return; + } + final String redirect = data.getString(REDIRECT).toLowerCase( + Locale.ROOT); + if (!redirect.startsWith("http://") + && !redirect.startsWith("https://") + && !redirect.startsWith("/")) { + data.addError(URL_KEY, new GlobalizedMessage( + "shortcuts.ui.admin.redirect.error.invalid", + ShortcutsConstants.SHORTCUTS_BUNDLE)); + } + }); + + addInitListener(e -> { + final PageState state = e.getPageState(); + final FormData data = e.getFormData(); + + if (selectedShortcut.isSelected(state)) { + final ShortcutRepository repo = CdiUtil.createCdiUtil() + .findBean(ShortcutRepository.class); + final Shortcut shortcut = repo.findById(Long.parseLong( + selectedShortcut.getSelectedKey(state))); + urlKeyField.setValue(state, shortcut.getUrlKey()); + redirectField.setValue(state, shortcut.getRedirect()); + } + }); + + addProcessListener(e -> { + final PageState state = e.getPageState(); + final FormData data = e.getFormData(); + + if (saveCancelSection.getSaveButton().isSelected(state)) { + + final Shortcut shortcut; + if (selectedShortcut.isSelected(state)) { + final ShortcutRepository repo = CdiUtil.createCdiUtil() + .findBean(ShortcutRepository.class); + shortcut = repo.findById(Long.parseLong(selectedShortcut + .getSelectedKey(state))); + + shortcut.setUrlKey(data.getString(URL_KEY)); + shortcut.setRedirect(data.getString(REDIRECT)); + + repo.save(shortcut); + } else { + final ShortcutManager shortcutManager = CdiUtil + .createCdiUtil().findBean(ShortcutManager.class); + shortcutManager.createShortcut(data.getString(URL_KEY), + data.getString(REDIRECT)); + } + } + + selectedShortcut.clearSelection(state); + shortcutsPane.showShortcutsTable(state); + }); + } + +} diff --git a/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/ui/ShortcutForm.java.tmpOff b/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/ui/ShortcutForm.java.tmpOff deleted file mode 100644 index 3b1486e6e..000000000 --- a/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/ui/ShortcutForm.java.tmpOff +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright (C) 2015 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 org.libreccm.shortcuts.ui; - -import java.math.BigDecimal; - -import com.arsdigita.bebop.FormProcessException; -import com.arsdigita.bebop.event.FormProcessListener; -import com.arsdigita.bebop.PageState; -import com.arsdigita.bebop.event.FormValidationListener; -import com.arsdigita.bebop.Label; -import com.arsdigita.bebop.Form; -import com.arsdigita.bebop.event.FormInitListener; -import com.arsdigita.bebop.event.FormSectionEvent; -import com.arsdigita.bebop.event.ParameterListener; -import com.arsdigita.bebop.event.ParameterEvent; -import com.arsdigita.bebop.form.Submit; -import com.arsdigita.bebop.form.TextField; -import com.arsdigita.bebop.parameters.ParameterData; -import com.arsdigita.bebop.parameters.TrimmedStringParameter; -import com.arsdigita.bebop.parameters.NotEmptyValidationListener; -import com.arsdigita.bebop.util.GlobalizationUtil; -import org.libreccm.shortcuts.ShortcutManager; -import com.arsdigita.bebop.ParameterSingleSelectionModel; -import org.libreccm.shortcuts.Shortcut; -import org.libreccm.shortcuts.ShortcutRepository; -import com.arsdigita.util.UncheckedWrapperException; - -import org.apache.log4j.Category; -import org.apache.oro.text.perl.Perl5Util; -import org.apache.oro.text.perl.MalformedPerl5PatternException; -import org.libreccm.cdi.utils.CdiUtil; - -public class ShortcutForm extends Form { - - private static final Category log = Category.getInstance(ShortcutForm.class - .getName()); - - private ParameterSingleSelectionModel m_selected_shortcut; - - private TextField m_url; - - private TextField m_redirect; - - private final Submit m_submit; - - public ShortcutForm(ParameterSingleSelectionModel selected_shortcut) { - super("ShortcutForm"); - m_selected_shortcut = selected_shortcut; - - TrimmedStringParameter urlKeyParameter = new TrimmedStringParameter( - "url"); - urlKeyParameter.addParameterListener(new NotEmptyValidationListener()); - m_url = new TextField(urlKeyParameter); - - TrimmedStringParameter redirectParameter = new TrimmedStringParameter( - "redirect"); - redirectParameter - .addParameterListener(new NotEmptyValidationListener()); - - m_redirect = new TextField(redirectParameter); - - urlKeyParameter.addParameterListener(new ParameterListener() { - - @Override - public void validate(ParameterEvent e) throws FormProcessException { - ParameterData data = e.getParameterData(); - - String key = (String) data.getValue(); - if (key == null) { - return; // Something else will handle this - } - - Perl5Util perl = new Perl5Util(); - try { - if (!perl.match("/^(\\/[-a-zA-Z0-9_.]+)+\\/?$/", key)) { - data.addError(GlobalizationUtil.globalize( - "shortcuts.ui.invalid_key_descr")); - throw new FormProcessException( - "Invalid key", - GlobalizationUtil.globalize( - "shortcuts.ui.invalid_key") - ); - } - } catch (MalformedPerl5PatternException ex) { - throw new UncheckedWrapperException("bad regex", ex); - } - } - - }); - - redirectParameter.addParameterListener(new ParameterListener() { - - @Override - public void validate(ParameterEvent e) throws FormProcessException { - ParameterData data = e.getParameterData(); - - String url = (String) data.getValue(); - if (url == null) { - return; // Something else will handle this - } - - url = url.toLowerCase(); - - // Absolute local url is ok - if (url.startsWith("/")) { - return; - } - - // Fully qualified url is ok - if (url.startsWith("http://")) { - return; - } - - // And secure ones too - if (url.startsWith("https://")) { - return; - } - - data - .addError("You must enter an absolute path " - + "(starting with '/') or a fully " - + "qualified URL (starting with 'http://' or 'https://')"); - throw new FormProcessException(GlobalizationUtil.globalize( - "shortcuts.ui.invalid_key")); - } - - }); - - add(new Label("URL Key:")); - add(m_url); - add(new Label("Redirect:")); - add(m_redirect); - - m_submit = new Submit("Save Shortcut"); - add(m_submit); - - addInitListener(new ShortcutInitListener()); - addProcessListener(new ShortcutFormProcessListener()); - addValidationListener(new ShortcutFormValidationListener()); - } - - private class ShortcutInitListener implements FormInitListener { - - @Override - public void init(FormSectionEvent ev) throws FormProcessException { - final PageState state = ev.getPageState(); - final ShortcutRepository shortcutsRepo = CdiUtil.createCdiUtil() - .findBean(ShortcutRepository.class); - - Long shortcutKey = (Long) m_selected_shortcut - .getSelectedKey(state); - if (shortcutKey == null) { - log.debug("init form for empty shortcut"); - m_url.setValue(state, null); - m_redirect.setValue(state, null); - } else { - log.debug("init form for shortcut " + shortcutKey); -// Shortcut shortcut = new Shortcut(shortcutKey); - Shortcut shortcut = shortcutsRepo.findById(shortcutKey); - m_url.setValue(state, shortcut.getUrlKey()); - m_redirect.setValue(state, shortcut.getRedirect()); - } - } - - } - - private class ShortcutFormValidationListener implements - FormValidationListener { - - @Override - public void validate(FormSectionEvent e) throws FormProcessException { - PageState state = e.getPageState(); - ShortcutManager shortcutMgr = new ShortcutManager(); - - // get currently edited shortcut - Long shortcutKey = (Long) m_selected_shortcut - .getSelectedKey(state); - -//TODO: maybe adjust url. see com-arsdigita.shortcuts.ShortcutUtil.cleanURLKey() - String key = (String) m_url.getValue(state); - - if (shortcutKey == null) { - String target = shortcutMgr.findByUrlKey(key).getUrlKey(); - - if (target != null) { - m_url.addError(GlobalizationUtil.globalize( - "shortcuts.ui.key_already_exists")); - throw new FormProcessException( - "duplicate key", - GlobalizationUtil - .globalize("shortcuts.ui.duplicate_key") - ); - } - } - - int index = key.indexOf("/", 2); - String base = key.substring(0, index + 1); - } - - } - - private class ShortcutFormProcessListener implements FormProcessListener { - - @Override - public void process(FormSectionEvent e) throws FormProcessException { - ShortcutManager shortcutMgr = new ShortcutManager(); - PageState state = e.getPageState(); - final ShortcutRepository shortcutsRepo = CdiUtil.createCdiUtil() - .findBean(ShortcutRepository.class); - - Long shortcutKey = (Long) m_selected_shortcut.getSelectedKey(state); - -// String url = ShortcutUtil.cleanURLKey((String) m_url.getValue(state)); - String url = (String) m_url.getValue(state); - String redirect = (String) m_redirect.getValue(state); - - if (shortcutKey == null) { - log.info("save new shortcut " + url); - - Shortcut shortcut = shortcutMgr.createShortcut(url, redirect); - shortcutsRepo.save(shortcut); - } else { - log.info("save updated shortcut " + shortcutKey + " " + url); - - Shortcut shortcut = shortcutsRepo.findById(shortcutKey); - shortcut.setUrlKey(url); - shortcut.setRedirect(redirect); - shortcutsRepo.save(shortcut); - } - -// ShortcutUtil.repopulateShortcuts(); - m_redirect.setValue(state, ""); - m_url.setValue(state, ""); - m_selected_shortcut.clearSelection(state); - } - - } - -} diff --git a/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/ui/ShortcutsSettingsPane.java b/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/ui/ShortcutsSettingsPane.java new file mode 100644 index 000000000..f1c2f2edb --- /dev/null +++ b/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/ui/ShortcutsSettingsPane.java @@ -0,0 +1,107 @@ +/* + * 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 org.libreccm.shortcuts.ui; + +import com.arsdigita.bebop.ActionLink; +import com.arsdigita.bebop.BoxPanel; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.Page; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.ParameterSingleSelectionModel; +import com.arsdigita.bebop.parameters.StringParameter; +import com.arsdigita.globalization.GlobalizedMessage; +import com.arsdigita.ui.admin.applications.AbstractAppSettingsPane; + +import org.libreccm.shortcuts.ShortcutsConstants; + +/** + * + * @author Jens Pelzetter + */ +public class ShortcutsSettingsPane extends AbstractAppSettingsPane { + + private final StringParameter selectedShortcutParam; + private final ParameterSingleSelectionModel selectedShortcut; + private final ShortcutsTable shortcutsTable; + private final ActionLink addShortcutLink; + private final ShortcutForm shortcutForm; + + public ShortcutsSettingsPane( + final ParameterSingleSelectionModel selectedAppType, + final ParameterSingleSelectionModel selectedAppInstance) { + + super(selectedAppType, selectedAppInstance); + + selectedShortcutParam = new StringParameter("selectedShortcut"); + selectedShortcut = new ParameterSingleSelectionModel<>( + selectedShortcutParam); + + final BoxPanel panel = new BoxPanel(BoxPanel.VERTICAL); + final Label heading = new Label(new GlobalizedMessage( + "shortcuts.ui.admin.heading", ShortcutsConstants.SHORTCUTS_BUNDLE)); + heading.setClassAttr("heading"); + panel.add(heading); + + shortcutsTable = new ShortcutsTable(this, selectedShortcut); + panel.add(shortcutsTable); + + shortcutForm = new ShortcutForm(this, selectedShortcut); + panel.add(shortcutForm); + + addShortcutLink = new ActionLink(new GlobalizedMessage( + "shortcuts.ui.admin.add_shortcut", + ShortcutsConstants.SHORTCUTS_BUNDLE)); + addShortcutLink.addActionListener(e -> { + showShortcutForm(e.getPageState()); + }); + panel.add(addShortcutLink); + + add(panel); + } + + @Override + protected void createWidgets() { + + } + + @Override + public void register(final Page page) { + super.register(page); + + page.addGlobalStateParam(selectedShortcutParam); + + page.setVisibleDefault(shortcutsTable, true); + page.setVisibleDefault(shortcutForm, false); + page.setVisibleDefault(addShortcutLink, true); + + } + + void showShortcutForm(final PageState state) { + shortcutsTable.setVisible(state, false); + shortcutForm.setVisible(state, true); + addShortcutLink.setVisible(state, false); + } + + void showShortcutsTable(final PageState state) { + shortcutsTable.setVisible(state, true); + shortcutForm.setVisible(state, false); + addShortcutLink.setVisible(state, true); + } + +} diff --git a/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/ui/ShortcutsTable.java b/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/ui/ShortcutsTable.java new file mode 100644 index 000000000..0cdc2689b --- /dev/null +++ b/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/ui/ShortcutsTable.java @@ -0,0 +1,224 @@ +/* + * 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 org.libreccm.shortcuts.ui; + +import com.arsdigita.bebop.Component; +import com.arsdigita.bebop.ControlLink; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.ParameterSingleSelectionModel; +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.bebop.table.TableModel; +import com.arsdigita.bebop.table.TableModelBuilder; +import com.arsdigita.globalization.GlobalizedMessage; +import com.arsdigita.util.LockableImpl; + +import org.libreccm.cdi.utils.CdiUtil; +import org.libreccm.shortcuts.Shortcut; +import org.libreccm.shortcuts.ShortcutRepository; +import org.libreccm.shortcuts.ShortcutsConstants; + +import java.util.List; + +/** + * + * @author Jens Pelzetter + */ +public class ShortcutsTable extends Table { + + private static final int COL_URL_KEY = 0; + private static final int COL_REDIRECT = 1; + private static final int COL_EDIT = 2; + private static final int COL_DELETE = 3; + + private final ShortcutsSettingsPane shortcutsPane; + + public ShortcutsTable( + final ShortcutsSettingsPane shortcutsPane, + final ParameterSingleSelectionModel selectedShortcut) { + + super(); + + this.shortcutsPane = shortcutsPane; + + final TableColumnModel columnModel = getColumnModel(); + columnModel.add(new TableColumn( + COL_URL_KEY, + new Label(new GlobalizedMessage( + "shortcuts.ui.admin.shortcuts_table.col_url_key.header", + ShortcutsConstants.SHORTCUTS_BUNDLE)) + )); + columnModel.add(new TableColumn( + COL_REDIRECT, + new Label(new GlobalizedMessage( + "shortcuts.ui.admin.shortcuts_table.col_redirect.header", + ShortcutsConstants.SHORTCUTS_BUNDLE)) + )); + columnModel.add(new TableColumn( + COL_EDIT, + new Label(new GlobalizedMessage( + "shortcuts.ui.admin.shortcuts_table.col_edit.header", + ShortcutsConstants.SHORTCUTS_BUNDLE)) + )); + columnModel.add(new TableColumn( + COL_DELETE, + new Label(new GlobalizedMessage( + "shortcuts.ui.admin.shortcuts_table.col_delete.header", + ShortcutsConstants.SHORTCUTS_BUNDLE)) + )); + + columnModel.get(COL_EDIT).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) { + return new ControlLink((Component) value); + } + + }); + + 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) { + return new ControlLink((Component) value); + } + + }); + + addTableActionListener(new TableActionListener() { + + @Override + public void cellSelected(final TableActionEvent event) { + final PageState state = event.getPageState(); + + switch (event.getColumn()) { + case COL_EDIT: + selectedShortcut.setSelectedKey(state, + event.getRowKey()); + shortcutsPane.showShortcutForm(state); + break; + case COL_DELETE: { + final ShortcutRepository repo = CdiUtil.createCdiUtil() + .findBean(ShortcutRepository.class); + final Shortcut shortcut = repo.findById(Long.parseLong( + (String) event.getRowKey())); + repo.delete(shortcut); + break; + } + } + } + + @Override + public void headSelected(final TableActionEvent event) { + //nothing + } + + }); + + setModelBuilder(new ShortcutsTableModelBuilder()); + + setEmptyView(new Label(new GlobalizedMessage( + "shortcuts.ui.admin.table.empty", + ShortcutsConstants.SHORTCUTS_BUNDLE))); + + } + + private class ShortcutsTableModelBuilder extends LockableImpl implements + TableModelBuilder { + + @Override + public TableModel makeModel(final Table table, final PageState state) { + return new ShortcutsTableModel(); + } + + } + + private class ShortcutsTableModel implements TableModel { + + private final List shortcuts; + private int index = -1; + + public ShortcutsTableModel() { + final ShortcutRepository repo = CdiUtil.createCdiUtil().findBean( + ShortcutRepository.class); + shortcuts = repo.findAll(); + shortcuts.sort((s1, s2) -> { + return s1.getUrlKey().compareTo(s2.getUrlKey()); + }); + } + + @Override + public int getColumnCount() { + return 4; + } + + @Override + public boolean nextRow() { + index++; + return index < shortcuts.size(); + } + + @Override + public Object getElementAt(final int columnIndex) { + final Shortcut shortcut = shortcuts.get(index); + + switch (columnIndex) { + case COL_URL_KEY: + return shortcut.getUrlKey(); + case COL_REDIRECT: + return shortcut.getRedirect(); + case COL_EDIT: + return new Label(new GlobalizedMessage( + "shortcuts.ui.admin.shortcuts_table.edit", + ShortcutsConstants.SHORTCUTS_BUNDLE)); + case COL_DELETE: + return new Label(new GlobalizedMessage( + "shortcuts.ui.admin.shortcuts_table.delete", + ShortcutsConstants.SHORTCUTS_BUNDLE)); + default: + throw new IllegalArgumentException( + "Not a valid column index"); + } + } + + @Override + public Object getKeyAt(final int columnIndex) { + return Long.toString(shortcuts.get(index).getShortcutId()); + } + + } + +} diff --git a/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/ui/ShortcutsTable.java.tmpOff b/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/ui/ShortcutsTable.java.tmpOff deleted file mode 100644 index 1c06adce5..000000000 --- a/ccm-shortcuts/src/main/java/org/libreccm/shortcuts/ui/ShortcutsTable.java.tmpOff +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (C) 2015 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 org.libreccm.shortcuts.ui; - -import com.arsdigita.bebop.Table; -import com.arsdigita.bebop.table.TableModelBuilder; -import com.arsdigita.util.LockableImpl; -import com.arsdigita.bebop.table.TableModel; -import com.arsdigita.bebop.PageState; - -import com.arsdigita.bebop.ParameterSingleSelectionModel; -import org.libreccm.shortcuts.Shortcut; -//import com.arsdigita.shortcuts.ShortcutCollection; -import java.math.BigDecimal; - -import org.apache.log4j.Category; - -import com.arsdigita.bebop.event.TableActionListener; -import com.arsdigita.bebop.table.TableCellRenderer; -import com.arsdigita.bebop.event.TableActionEvent; -import com.arsdigita.bebop.ControlLink; -import com.arsdigita.util.UncheckedWrapperException; -import com.arsdigita.bebop.Component; -import java.util.List; -import org.libreccm.cdi.utils.CdiUtil; -import org.libreccm.shortcuts.ShortcutRepository; - -/** - * - * - */ -public class ShortcutsTable extends Table { - - private static final Category log - = Category.getInstance( - ShortcutsTable.class.getName()); - - public static final String headers[] = {"URL Key", "Redirect", "", ""}; - - public ShortcutsTable(final ParameterSingleSelectionModel selected_shortcut) { - super(new ShortcutsModelBuilder(), headers); - setDefaultCellRenderer(new ShortcutsCellRenderer()); - final ShortcutRepository shortcutsRepo = CdiUtil.createCdiUtil() - .findBean(ShortcutRepository.class); - - addTableActionListener(new TableActionListener() { - - public void cellSelected(TableActionEvent e) { - selected_shortcut.clearSelection(e.getPageState()); - String row = (String) e.getRowKey(); - if (e.getColumn().intValue() == 2) { - // edit selected - log.debug("selected edit shortcut " + row); - selected_shortcut.setSelectedKey(e.getPageState(), - new BigDecimal(row)); - - } else if (e.getColumn().intValue() == 3) { - // delete selected - log.fatal("selected delete shortcut " + row); - - Shortcut shortcut = shortcutsRepo.findById( - (Long) selected_shortcut - .getSelectedKey(e.getPageState())); - - if (shortcut != null) { - log.info("delete shortcut " + shortcut.getUrlKey()); - shortcutsRepo.delete(shortcut); - } - } - } - - public void headSelected(TableActionEvent e) { - } - - }); - } - - protected static class ShortcutsModelBuilder extends LockableImpl implements - TableModelBuilder { - - public TableModel makeModel(Table table, PageState ps) { - return new ShortcutsModel(); - } - - protected class ShortcutsModel implements TableModel { - - private ShortcutRepository shortcutRepo = new ShortcutRepository(); - private List m_shortcuts = null; - private int index = 0; - private Shortcut m_shortcut; - - public ShortcutsModel() { -// m_shortcuts = Shortcut.retrieveAll(); - m_shortcuts = shortcutRepo.findAll(); - } - - public int getColumnCount() { - return headers.length; - } - - public boolean nextRow() { - if (index < m_shortcuts.size()) { - index++; - m_shortcut = m_shortcuts.get(index); - return true; - } else { - return false; - } - } - - public Object getElementAt(int col) { - return m_shortcut; - } - - public Long getKeyAt(int col) { - Long id = m_shortcut.getShortcutId(); - return id; - } - - } - - } - - protected static class ShortcutsCellRenderer implements TableCellRenderer { - - public Component getComponent(Table table, PageState state, - Object value, boolean isSelected, - Object key, int row, - int column) { - Shortcut shortcut = (Shortcut) value; - - switch (column) { -// case 0: -// return new ExternalLink(shortcut.getUrlKey(), shortcut -// .getUrlKey()); -// case 1: -// return new ExternalLink(shortcut.getRedirect(), shortcut -// .getRedirect()); - case 2: - return new ControlLink(" edit "); - case 3: - return new ControlLink(" delete "); - default: - throw new UncheckedWrapperException("Column out of bounds"); - } - } - - } - -} diff --git a/ccm-shortcuts/src/main/resources/org/libreccm/shortcuts/ShortcutsResources.properties b/ccm-shortcuts/src/main/resources/org/libreccm/shortcuts/ShortcutsResources.properties index 5844878b0..38469b544 100644 --- a/ccm-shortcuts/src/main/resources/org/libreccm/shortcuts/ShortcutsResources.properties +++ b/ccm-shortcuts/src/main/resources/org/libreccm/shortcuts/ShortcutsResources.properties @@ -17,3 +17,18 @@ application_title=Shortcuts application_desc=Manage short URLs for internal and external redirects. +shortcuts.ui.admin.shortcuts_table.col_url_key.header=URL +shortcuts.ui.admin.shortcuts_table.col_redirect.header=Redirect +shortcuts.ui.admin.shortcuts_table.col_edit.header=Edit +shortcuts.ui.admin.shortcuts_table.col_delete.header=Delete +shortcuts.ui.admin.shortcuts_table.edit=Edit +shortcuts.ui.admin.shortcuts_table.delete=Delete +shortcuts.ui.admin.url_key.label=URL +shortcuts.ui.admin.redirect.label=Redirect +shortcuts.ui.admin.url_key.error.not_empty=The URL to redirect can't be empty. +shortcuts.ui.admin.url_key.error.invalid=The URL to redirect is not a valid URL. +shortcuts.ui.admin.redirect.not_empty=The target of the redirect can't be empty. +shortcuts.ui.admin.redirect.error.invalid=The target of the redirect must be a absolute URL. +shortcuts.ui.admin.heading=Manage shortcuts +shortcuts.ui.admin.table.empty=No shortcuts definied yet +shortcuts.ui.admin.add_shortcut=Add shortcut diff --git a/ccm-shortcuts/src/main/resources/org/libreccm/shortcuts/ShortcutsResources_de.properties b/ccm-shortcuts/src/main/resources/org/libreccm/shortcuts/ShortcutsResources_de.properties index 5844878b0..1fefabf78 100644 --- a/ccm-shortcuts/src/main/resources/org/libreccm/shortcuts/ShortcutsResources_de.properties +++ b/ccm-shortcuts/src/main/resources/org/libreccm/shortcuts/ShortcutsResources_de.properties @@ -17,3 +17,18 @@ application_title=Shortcuts application_desc=Manage short URLs for internal and external redirects. +shortcuts.ui.admin.shortcuts_table.col_url_key.header=URL +shortcuts.ui.admin.shortcuts_table.col_redirect.header=Weiterleitung +shortcuts.ui.admin.shortcuts_table.col_edit.header=Bearbeiten +shortcuts.ui.admin.shortcuts_table.col_delete.header=L\u00f6schen +shortcuts.ui.admin.shortcuts_table.edit=Bearbeiten +shortcuts.ui.admin.shortcuts_table.delete=L\u00f6schen +shortcuts.ui.admin.url_key.label=URL +shortcuts.ui.admin.redirect.label=Weiterleitung +shortcuts.ui.admin.url_key.error.not_empty=Die weiterzuleitende URL darf nicht leer sein. +shortcuts.ui.admin.url_key.error.invalid=Die weiterzuleitende URL ist keine valide URL. +shortcuts.ui.admin.redirect.not_empty=Das Ziel der Weiterleitung darf nicht leer sein. +shortcuts.ui.admin.redirect.error.invalid=Das Ziel der Weiterleitung muss eine absolute URL sein. +shortcuts.ui.admin.heading=Shortcuts verwalten +shortcuts.ui.admin.table.empty=Es wurden noch keine Shortcuts angelegt. +shortcuts.ui.admin.add_shortcut=Shortcut hinzuf\u00fcgen