diff --git a/cms-api/src/main/java/com/condation/cms/api/ui/extensions/UIActionsExtensionPoint.java b/cms-api/src/main/java/com/condation/cms/api/ui/extensions/UIActionsExtensionPoint.java index 1b88e4e58..d422eb48f 100644 --- a/cms-api/src/main/java/com/condation/cms/api/ui/extensions/UIActionsExtensionPoint.java +++ b/cms-api/src/main/java/com/condation/cms/api/ui/extensions/UIActionsExtensionPoint.java @@ -22,16 +22,13 @@ * #L% */ -import com.condation.cms.api.module.SiteModuleContext; -import com.condation.cms.api.module.SiteRequestContext; import com.condation.cms.api.ui.elements.Menu; -import com.condation.modules.api.ExtensionPoint; /** * * @author t.marx */ -public interface UIActionsExtensionPoint extends ExtensionPoint { +public interface UIActionsExtensionPoint extends UIExtensionPoint { public default void addMenuItems (Menu menu) {}; } diff --git a/cms-api/src/main/java/com/condation/cms/api/ui/extensions/UIExtensionPoint.java b/cms-api/src/main/java/com/condation/cms/api/ui/extensions/UIExtensionPoint.java new file mode 100644 index 000000000..6d4754117 --- /dev/null +++ b/cms-api/src/main/java/com/condation/cms/api/ui/extensions/UIExtensionPoint.java @@ -0,0 +1,35 @@ +package com.condation.cms.api.ui.extensions; + +/*- + * #%L + * cms-api + * %% + * Copyright (C) 2023 - 2025 CondationCMS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ + +import com.condation.cms.api.module.SiteModuleContext; +import com.condation.cms.api.module.SiteRequestContext; +import com.condation.modules.api.ExtensionPoint; + +/** + * + * @author thmar + */ +public interface UIExtensionPoint extends ExtensionPoint { + +} diff --git a/cms-api/src/main/java/com/condation/cms/api/ui/extensions/UILocalizationExtensionPoint.java b/cms-api/src/main/java/com/condation/cms/api/ui/extensions/UILocalizationExtensionPoint.java index 61873a3e0..d4152570b 100644 --- a/cms-api/src/main/java/com/condation/cms/api/ui/extensions/UILocalizationExtensionPoint.java +++ b/cms-api/src/main/java/com/condation/cms/api/ui/extensions/UILocalizationExtensionPoint.java @@ -22,16 +22,13 @@ * #L% */ -import com.condation.cms.api.module.SiteModuleContext; -import com.condation.cms.api.module.SiteRequestContext; -import com.condation.modules.api.ExtensionPoint; import java.util.Map; /** * * @author t.marx */ -public interface UILocalizationExtensionPoint extends ExtensionPoint { +public interface UILocalizationExtensionPoint extends UIExtensionPoint { public Map> getLocalizations (); } diff --git a/cms-api/src/main/java/com/condation/cms/api/ui/extensions/UIRemoteMethodExtensionPoint.java b/cms-api/src/main/java/com/condation/cms/api/ui/extensions/UIRemoteMethodExtensionPoint.java index 896a8a8b2..f23383532 100644 --- a/cms-api/src/main/java/com/condation/cms/api/ui/extensions/UIRemoteMethodExtensionPoint.java +++ b/cms-api/src/main/java/com/condation/cms/api/ui/extensions/UIRemoteMethodExtensionPoint.java @@ -22,12 +22,10 @@ * #L% */ -import com.condation.cms.api.extensions.AbstractExtensionPoint; - /** * * @author t.marx */ -public abstract class UIRemoteMethodExtensionPoint extends AbstractExtensionPoint { +public interface UIRemoteMethodExtensionPoint extends UIExtensionPoint{ } diff --git a/cms-api/src/main/java/com/condation/cms/api/ui/extensions/UIScriptActionSourceExtension.java b/cms-api/src/main/java/com/condation/cms/api/ui/extensions/UIScriptActionSourceExtension.java new file mode 100644 index 000000000..0287194bf --- /dev/null +++ b/cms-api/src/main/java/com/condation/cms/api/ui/extensions/UIScriptActionSourceExtension.java @@ -0,0 +1,34 @@ +package com.condation.cms.api.ui.extensions; + +/*- + * #%L + * cms-api + * %% + * Copyright (C) 2023 - 2025 CondationCMS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ + +import java.util.Map; + +/** + * + * @author thmar + */ +public interface UIScriptActionSourceExtension extends UIExtensionPoint { + + public Map getActionSources (); +} diff --git a/cms-api/src/main/java/com/condation/cms/api/utils/AnnotationsUtil.java b/cms-api/src/main/java/com/condation/cms/api/utils/AnnotationsUtil.java index 17eaa95fa..5c4a03358 100644 --- a/cms-api/src/main/java/com/condation/cms/api/utils/AnnotationsUtil.java +++ b/cms-api/src/main/java/com/condation/cms/api/utils/AnnotationsUtil.java @@ -51,7 +51,7 @@ public static List> process(Object List> result = new ArrayList(); Class clazz = target.getClass(); - for (Method method : clazz.getDeclaredMethods()) { + for (Method method : clazz.getMethods()) { if (!method.isAnnotationPresent(annotationClass)) { continue; } diff --git a/modules/example-module/src/main/java/com/condation/cms/modules/example/ui/ExampleUiScriptActionSourceExtension.java b/modules/example-module/src/main/java/com/condation/cms/modules/example/ui/ExampleUiScriptActionSourceExtension.java new file mode 100644 index 000000000..f47c8c772 --- /dev/null +++ b/modules/example-module/src/main/java/com/condation/cms/modules/example/ui/ExampleUiScriptActionSourceExtension.java @@ -0,0 +1,77 @@ +package com.condation.cms.modules.example.ui; + +/*- + * #%L + * example-module + * %% + * Copyright (C) 2023 - 2025 CondationCMS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ +import com.condation.cms.api.auth.Permissions; +import com.condation.cms.api.extensions.AbstractExtensionPoint; +import com.condation.cms.api.ui.annotations.MenuEntry; +import com.condation.cms.api.ui.annotations.ShortCut; +import com.condation.cms.api.ui.extensions.UIActionsExtensionPoint; +import com.condation.cms.api.ui.extensions.UIScriptActionSourceExtension; +import com.condation.modules.api.annotation.Extension; +import com.condation.modules.api.annotation.Extensions; +import java.util.Map; + +/** + * + * @author thmar + */ +@Extensions({ + @Extension(UIActionsExtensionPoint.class), + @Extension(UIScriptActionSourceExtension.class) +}) +public class ExampleUiScriptActionSourceExtension extends AbstractExtensionPoint implements UIScriptActionSourceExtension, UIActionsExtensionPoint { + + @Override + public Map getActionSources() { + return Map.of("example/source", "// this is an example script source"); + } + + @MenuEntry( + id = "exampleMenu", + name = "Example", + permissions = {Permissions.CONTENT_EDIT}, + position = 10 + ) + public void exampleMenu() { + + } + + @MenuEntry( + parent = "exampleMenu", + id = "example-action", + name = "Example action", + permissions = {Permissions.CONTENT_EDIT}, + position = 1, + scriptAction = @com.condation.cms.api.ui.annotations.ScriptAction(module = "/manager/actions/example/source") + ) + @ShortCut( + id = "example-action", + title = "Example Action", + permissions = {Permissions.CONTENT_EDIT}, + section = "Example", + scriptAction = @com.condation.cms.api.ui.annotations.ScriptAction(module = "/manager/actions/example/source") + ) + public void example_action() { + + } +} diff --git a/modules/ui-module/src/main/java/com/condation/cms/modules/ui/extensionpoints/remotemethods/AbstractRemoteMethodeExtension.java b/modules/ui-module/src/main/java/com/condation/cms/modules/ui/extensionpoints/remotemethods/AbstractRemoteMethodeExtension.java index 066be7d45..1d16e2129 100644 --- a/modules/ui-module/src/main/java/com/condation/cms/modules/ui/extensionpoints/remotemethods/AbstractRemoteMethodeExtension.java +++ b/modules/ui-module/src/main/java/com/condation/cms/modules/ui/extensionpoints/remotemethods/AbstractRemoteMethodeExtension.java @@ -23,6 +23,7 @@ */ import com.condation.cms.api.db.DB; +import com.condation.cms.api.extensions.AbstractExtensionPoint; import com.condation.cms.api.feature.features.AuthFeature; import com.condation.cms.api.feature.features.DBFeature; import com.condation.cms.api.feature.features.HookSystemFeature; @@ -36,7 +37,7 @@ * * @author thorstenmarx */ -public abstract class AbstractRemoteMethodeExtension extends UIRemoteMethodExtensionPoint { +public abstract class AbstractRemoteMethodeExtension extends AbstractExtensionPoint implements UIRemoteMethodExtensionPoint { protected String getUserName() { if (getRequestContext().has(AuthFeature.class)) { return getRequestContext().get(AuthFeature.class).username(); diff --git a/modules/ui-module/src/main/java/com/condation/cms/modules/ui/extensionpoints/remotemethods/LocalizationEnpoints.java b/modules/ui-module/src/main/java/com/condation/cms/modules/ui/extensionpoints/remotemethods/LocalizationEnpoints.java index 197e21b93..fbf3ca8f3 100644 --- a/modules/ui-module/src/main/java/com/condation/cms/modules/ui/extensionpoints/remotemethods/LocalizationEnpoints.java +++ b/modules/ui-module/src/main/java/com/condation/cms/modules/ui/extensionpoints/remotemethods/LocalizationEnpoints.java @@ -23,6 +23,7 @@ */ import com.condation.cms.api.auth.Permissions; +import com.condation.cms.api.extensions.AbstractExtensionPoint; import com.condation.cms.api.feature.features.HookSystemFeature; import com.condation.cms.api.feature.features.ModuleManagerFeature; import com.condation.cms.api.ui.extensions.UILocalizationExtensionPoint; @@ -41,7 +42,7 @@ */ @Slf4j @Extension(UIRemoteMethodExtensionPoint.class) -public class LocalizationEnpoints extends UIRemoteMethodExtensionPoint { +public class LocalizationEnpoints extends AbstractExtensionPoint implements UIRemoteMethodExtensionPoint { diff --git a/modules/ui-module/src/main/java/com/condation/cms/modules/ui/extensionpoints/remotemethods/RemoteContentEndpointsExtension.java b/modules/ui-module/src/main/java/com/condation/cms/modules/ui/extensionpoints/remotemethods/RemoteContentEndpointsExtension.java index 275dcc988..1611f6788 100644 --- a/modules/ui-module/src/main/java/com/condation/cms/modules/ui/extensionpoints/remotemethods/RemoteContentEndpointsExtension.java +++ b/modules/ui-module/src/main/java/com/condation/cms/modules/ui/extensionpoints/remotemethods/RemoteContentEndpointsExtension.java @@ -27,6 +27,7 @@ import com.condation.cms.api.db.cms.ReadOnlyFile; import com.condation.cms.api.eventbus.events.InvalidateContentCacheEvent; import com.condation.cms.api.eventbus.events.ReIndexContentMetaDataEvent; +import com.condation.cms.api.extensions.AbstractExtensionPoint; import com.condation.cms.api.feature.features.DBFeature; import com.condation.cms.api.feature.features.EventBusFeature; import com.condation.cms.api.feature.features.RequestFeature; @@ -58,7 +59,7 @@ */ @Slf4j @Extension(UIRemoteMethodExtensionPoint.class) -public class RemoteContentEndpointsExtension extends UIRemoteMethodExtensionPoint { +public class RemoteContentEndpointsExtension extends AbstractExtensionPoint implements UIRemoteMethodExtensionPoint { @RemoteMethod(name = "content.get", permissions = {Permissions.CONTENT_EDIT}) public Object getContent(Map parameters) { diff --git a/modules/ui-module/src/main/java/com/condation/cms/modules/ui/extensionpoints/remotemethods/RemoteMediaEnpoints.java b/modules/ui-module/src/main/java/com/condation/cms/modules/ui/extensionpoints/remotemethods/RemoteMediaEnpoints.java index ca306d4b5..cdde69274 100644 --- a/modules/ui-module/src/main/java/com/condation/cms/modules/ui/extensionpoints/remotemethods/RemoteMediaEnpoints.java +++ b/modules/ui-module/src/main/java/com/condation/cms/modules/ui/extensionpoints/remotemethods/RemoteMediaEnpoints.java @@ -24,6 +24,7 @@ import com.condation.cms.api.Constants; import com.condation.cms.api.auth.Permissions; import com.condation.cms.api.eventbus.events.InvalidateMediaCache; +import com.condation.cms.api.extensions.AbstractExtensionPoint; import com.condation.cms.api.feature.features.DBFeature; import com.condation.cms.api.feature.features.EventBusFeature; import com.condation.cms.api.feature.features.SiteMediaServiceFeature; @@ -46,7 +47,7 @@ */ @Slf4j @Extension(UIRemoteMethodExtensionPoint.class) -public class RemoteMediaEnpoints extends UIRemoteMethodExtensionPoint { +public class RemoteMediaEnpoints extends AbstractExtensionPoint implements UIRemoteMethodExtensionPoint { @RemoteMethod(name = "media.meta.get", permissions = {Permissions.CONTENT_EDIT}) public Object getMediaMeta(Map parameters) throws RPCException { diff --git a/modules/ui-module/src/main/java/com/condation/cms/modules/ui/http/JSActionHandler.java b/modules/ui-module/src/main/java/com/condation/cms/modules/ui/http/JSActionHandler.java index ed65ddd7d..df07fefa8 100644 --- a/modules/ui-module/src/main/java/com/condation/cms/modules/ui/http/JSActionHandler.java +++ b/modules/ui-module/src/main/java/com/condation/cms/modules/ui/http/JSActionHandler.java @@ -21,11 +21,15 @@ * . * #L% */ +import com.condation.cms.api.feature.features.ModuleManagerFeature; import com.condation.cms.api.module.SiteModuleContext; +import com.condation.cms.api.ui.extensions.UIScriptActionSourceExtension; import com.condation.cms.api.utils.HTTPUtil; +import com.google.common.base.Strings; import java.nio.charset.StandardCharsets; import java.nio.file.FileSystem; import java.nio.file.Files; +import java.util.Optional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.eclipse.jetty.http.HttpHeader; @@ -48,24 +52,45 @@ public class JSActionHandler extends JettyHandler { @Override public boolean handle(Request request, Response response, Callback callback) throws Exception { - var resource = request.getHttpURI().getPath().replace( - managerURL("/manager/actions/", context), "") + ".js"; - - var files = fileSystem.getPath(base); - - if (resource.startsWith("/")) { - resource = resource.substring(1); + var resourceName = request.getHttpURI().getPath().replace( + managerURL("/manager/actions/", context), ""); + + if (resourceName.startsWith("/")) { + resourceName = resourceName.substring(1); } - - var path = files.resolve(resource); - if (Files.exists(path)) { - response.getHeaders().put(HttpHeader.CONTENT_TYPE, "%s; charset=UTF-8".formatted(Files.probeContentType(path))); - Content.Sink.write(response, true, Files.readString(path, StandardCharsets.UTF_8), callback); + + String scriptContent = ""; + + var moduleContent = getScriptContentFromModules(resourceName); + if (moduleContent.isPresent()) { + scriptContent = moduleContent.get(); + } else { + var resourceFile = resourceName + ".js"; + var files = fileSystem.getPath(base); + var path = files.resolve(resourceFile); + if (Files.exists(path)) { + scriptContent = Files.readString(path); + } + } + + + if (!Strings.isNullOrEmpty(scriptContent)) { + response.getHeaders().put(HttpHeader.CONTENT_TYPE, "application/javascript; charset=UTF-8"); + Content.Sink.write(response, true, scriptContent, callback); } else { callback.succeeded(); } return true; } + + private Optional getScriptContentFromModules (String filename) { + return context.get(ModuleManagerFeature.class).moduleManager().extensions(UIScriptActionSourceExtension.class) + .stream() + .map(UIScriptActionSourceExtension::getActionSources) + .filter(source -> source.containsKey(filename)) + .map(source -> source.get(filename)) + .findFirst(); + } } diff --git a/modules/ui-module/src/main/java/com/condation/cms/modules/ui/utils/ActionFactory.java b/modules/ui-module/src/main/java/com/condation/cms/modules/ui/utils/ActionFactory.java index c6245df5e..ece6937bc 100644 --- a/modules/ui-module/src/main/java/com/condation/cms/modules/ui/utils/ActionFactory.java +++ b/modules/ui-module/src/main/java/com/condation/cms/modules/ui/utils/ActionFactory.java @@ -102,7 +102,7 @@ public Menu createMenu() { private List scanShortCuts(Object moduleInstance) { List shortCuts = new ArrayList<>(); - for (Method method : moduleInstance.getClass().getDeclaredMethods()) { + for (Method method : moduleInstance.getClass().getMethods()) { var shortcutAnnotation = method.getAnnotation(com.condation.cms.api.ui.annotations.ShortCut.class); if (shortcutAnnotation == null) { continue; @@ -156,7 +156,7 @@ private List scanMenuEntries(Object moduleInstance) { List entries = new ArrayList<>(); - for (Method method : moduleInstance.getClass().getDeclaredMethods()) { + for (Method method : moduleInstance.getClass().getMethods()) { var menuAnn = method.getAnnotation(com.condation.cms.api.ui.annotations.MenuEntry.class); if (menuAnn == null) { continue; diff --git a/test-server/hosts/demo/modules_data/example-module/configuration.properties b/test-server/hosts/demo/modules_data/example-module/configuration.properties new file mode 100644 index 000000000..e69de29bb diff --git a/test-server/hosts/demo/site.toml b/test-server/hosts/demo/site.toml index 1cc7a435b..15716870b 100644 --- a/test-server/hosts/demo/site.toml +++ b/test-server/hosts/demo/site.toml @@ -27,6 +27,9 @@ target = "/Users/thorstenmarx/entwicklung/backups" [cache] content = true +[modules] +active = ["example-module"] + [translation] enabled = true languages = ["de", "en"] diff --git a/test-server/modules/example-module/libs/example-module-8.0.0.jar b/test-server/modules/example-module/libs/example-module-8.0.0.jar new file mode 100644 index 000000000..41c483960 Binary files /dev/null and b/test-server/modules/example-module/libs/example-module-8.0.0.jar differ diff --git a/test-server/modules/example-module/module.properties b/test-server/modules/example-module/module.properties new file mode 100644 index 000000000..93dd4e37c --- /dev/null +++ b/test-server/modules/example-module/module.properties @@ -0,0 +1,4 @@ +id=example-module +name=example module +version=8.0.0 +priority=HIGH \ No newline at end of file