Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions cms-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,16 @@
<artifactId>handlebars</artifactId>
</dependency>

<!-- Groovy -->
<dependency>
<groupId>org.apache.groovy</groupId>
<artifactId>groovy</artifactId>
</dependency>
<dependency>
<groupId>org.apache.groovy</groupId>
<artifactId>groovy-json</artifactId>
</dependency>

<!-- Test dependencies -->
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
Expand Down
40 changes: 40 additions & 0 deletions cms-core/src/main/java/com/gentics/api/ChannelScope.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.gentics.api;

import com.gentics.api.lib.exception.NodeException;
import com.gentics.contentnode.factory.ChannelTrx;
import com.gentics.contentnode.factory.NoMcTrx;
import com.gentics.contentnode.object.Node;
import com.gentics.contentnode.object.parttype.NodePartType;
import com.gentics.contentnode.render.RenderUtils;

import groovy.lang.Closure;

/**
* Channel Scope helper which should be used in Groovy Scripts to load objects in the scope of channels
*/
public class ChannelScope {
/**
* Private constructor
*/
private ChannelScope() {
}

/**
* Run the closure body in a {@link ChannelTrx}
* @param <T> type of the return value
* @param scope scope (channel)
* @param body closure body
* @return return value
* @throws NodeException
*/
public static <T> T withChannel(Object scope, Closure<T> body) throws NodeException {
Node node = null;
try (final NoMcTrx nMcTrx = new NoMcTrx()) {
node = RenderUtils.getObject(scope, Node.class, NodePartType.class, NodePartType::getNode);
}

try (ChannelTrx cTrx = new ChannelTrx(node)) {
return body.call(cTrx);
}
}
}
220 changes: 220 additions & 0 deletions cms-core/src/main/java/com/gentics/api/Loader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
package com.gentics.api;

import static com.gentics.contentnode.render.RenderUtils.wrap;

import java.util.Map;

import com.gentics.api.lib.exception.NodeException;
import com.gentics.api.lib.resolving.Resolvable;
import com.gentics.contentnode.factory.Transaction;
import com.gentics.contentnode.factory.TransactionManager;
import com.gentics.contentnode.object.File;
import com.gentics.contentnode.object.Folder;
import com.gentics.contentnode.object.ImageFile;
import com.gentics.contentnode.object.Node;
import com.gentics.contentnode.object.NodeObject;
import com.gentics.contentnode.object.Page;
import com.gentics.lib.log.NodeLogger;

/**
* Loader helper, which should be used in Groovy Scripts to load objects
*/
public class Loader {
private static NodeLogger logger = NodeLogger.getNodeLogger(Loader.class);

/**
* Map of types to type ids
*/
private final static Map<String, Integer> TYPES = Map.of(
"page", Page.TYPE_PAGE,
"folder", Folder.TYPE_FOLDER,
"file", File.TYPE_FILE,
"image", ImageFile.TYPE_IMAGE,
"node", Node.TYPE_NODE);

/**
* Private constructor
*/
private Loader() {
}

/**
* Load object with given type and id
* @param type object type
* @param id object id (as integer)
* @return loaded object or null, if not found
* @throws NodeException
*/
public static Resolvable object(int type, int id) throws NodeException {
Transaction t = TransactionManager.getCurrentTransaction();

Class<? extends NodeObject> clazz = t.getClass(type);
if (clazz == null) {
logger.warn("Unable to load object of unknown type ID %d".formatted(type));
return null;
}

NodeObject object = t.getObject(clazz, id);
if (object == null && type == File.TYPE_FILE) {
return object(ImageFile.TYPE_IMAGE, id);
}

return wrap(object);
}

/**
* Load object with given type and id
* @param type object type
* @param id object id (as string)
* @return loaded object or null, if not found
* @throws NodeException
*/
public static Resolvable object(int type, String id) throws NodeException {
Transaction t = TransactionManager.getCurrentTransaction();

Class<? extends NodeObject> clazz = t.getClass(type);
if (clazz == null) {
logger.warn("Unable to load object of unknown type ID %d".formatted(type));
return null;
}

NodeObject object = t.getObject(clazz, id);
if (object == null && type == File.TYPE_FILE) {
return object(ImageFile.TYPE_IMAGE, id);
}

return wrap(object);
}

/**
* Load object with given type and id
* @param type type
* @param id id (as integer)
* @return loaded object or null, if not found
* @throws NodeException
*/
public static Resolvable object(String type, int id) throws NodeException {
if (TYPES.containsKey(type)) {
return object(TYPES.get(type), id);
} else {
logger.warn("Unable to load object of unknown type %s".formatted(type));
return null;
}
}

/**
* Load object with given type and id
* @param type type
* @param id id (as string)
* @return loaded object or null, if not found
* @throws NodeException
*/
public static Resolvable object(String type, String id) throws NodeException {
if (TYPES.containsKey(type)) {
return object(TYPES.get(type), id);
} else {
logger.warn("Unable to load object of unknown type %s".formatted(type));
return null;
}
}

/**
* Load page
* @param id page id
* @return wrapped page
* @throws NodeException
*/
public static Resolvable page(int id) throws NodeException {
return object(Page.TYPE_PAGE, id);
}

/**
* Load page
* @param id page id
* @return wrapped page
* @throws NodeException
*/
public static Resolvable page(String id) throws NodeException {
return object(Page.TYPE_PAGE, id);
}

/**
* Load folder
* @param id folder id
* @return wrapped folder
* @throws NodeException
*/
public static Resolvable folder(int id) throws NodeException {
return object(Folder.TYPE_FOLDER, id);
}

/**
* Load folder
* @param id folder id
* @return wrapped folder
* @throws NodeException
*/
public static Resolvable folder(String id) throws NodeException {
return object(Folder.TYPE_FOLDER, id);
}

/**
* Load file
* @param id file id
* @return wrapped file
* @throws NodeException
*/
public static Resolvable file(int id) throws NodeException {
return object(File.TYPE_FILE, id);
}

/**
* Load file
* @param id file id
* @return wrapped file
* @throws NodeException
*/
public static Resolvable file(String id) throws NodeException {
return object(File.TYPE_FILE, id);
}

/**
* Load image
* @param id image id
* @return wrapped image
* @throws NodeException
*/
public static Resolvable image(int id) throws NodeException {
return object(ImageFile.TYPE_IMAGE, id);
}

/**
* Load image
* @param id image id
* @return wrapped image
* @throws NodeException
*/
public static Resolvable image(String id) throws NodeException {
return object(ImageFile.TYPE_IMAGE, id);
}

/**
* Load node
* @param id node id
* @return wrapped node
* @throws NodeException
*/
public static Resolvable node(int id) throws NodeException {
return object(Node.TYPE_NODE, id);
}

/**
* Load node
* @param id node id
* @return wrapped node
* @throws NodeException
*/
public static Resolvable node(String id) throws NodeException {
return object(Node.TYPE_NODE, id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.output.NullOutputStream;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Strings;

import com.gentics.api.lib.etc.ObjectTransformer;
import com.gentics.api.lib.exception.NodeException;
Expand Down Expand Up @@ -559,8 +560,10 @@ protected void jsonToFile(Object object, File file) throws NodeException {
*/
protected String getProposedFilename(Part part) {
// special case for HandlebarsPartType
if (part.getPartTypeId() == 43) {
if (part.getPartTypeId() == Part.HANDLEBARS) {
return "part." + part.getKeyname() + ".hbs";
} else if (part.getPartTypeId() == Part.GROOVY) {
return "part." + part.getKeyname() + ".groovy";
}
switch (Property.Type.get(part.getPartTypeId())) {
case STRING:
Expand Down Expand Up @@ -593,7 +596,7 @@ protected boolean isJsonFile(Part part) {
* @return true iff the filename belongs to a part value
*/
protected boolean isPartFilename(String filename) {
return filename.startsWith("part.") && (filename.endsWith(".txt") || filename.endsWith(".html") || filename.endsWith(".json") || filename.endsWith(".hbs"));
return Strings.CI.startsWith(filename, "part.") && Strings.CI.endsWithAny(filename, ".txt", ".html", ".json", ".hbs", ".groovy");
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public class MainPackageSynchronizer extends PackageSynchronizer {
* List containing invalid subpackage directory names
*/
public final static List<String> INVALID_SUBPACKAGE_NAMES = Arrays.asList(CONSTRUCTS_DIR, DATASOURCES_DIR, OBJECTPROPERTIES_DIR, TEMPLATES_DIR, FILES_DIR,
CR_FRAGMENTS_DIR, CONTENTREPOSITORIES_DIR, HANDLEBARS_DIR);
CR_FRAGMENTS_DIR, CONTENTREPOSITORIES_DIR, HANDLEBARS_DIR, SCRIPTS_DIR);

/**
* Lambda that generates the rest model for a package
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import java.io.IOException;
import java.io.Reader;
import java.io.StringWriter;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
Expand All @@ -27,7 +26,7 @@
import java.util.function.Consumer;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Strings;
import org.tautua.markdownpapers.Markdown;

import com.gentics.api.lib.exception.NodeException;
Expand Down Expand Up @@ -97,6 +96,11 @@ public abstract class PackageSynchronizer {
*/
public final static String HANDLEBARS_DIR = "handlebars";

/**
* Name of the subdirectory containing (groovy) scripts
*/
public final static String SCRIPTS_DIR = "scripts";

/**
* Directory map for object class
*/
Expand Down Expand Up @@ -186,6 +190,16 @@ public PackageSynchronizer(Path packagePath, boolean registerWatchers) throws No
// clean the cached handlebars helpers
handlebarsHelpers = null;
});
// add a handler for changes in the scripts directory
pathHandlers.put(new File(packagePath.toFile(), SCRIPTS_DIR).toPath(), changedPath -> {
try {
for (Node node : getNodes()) {
Synchronizer.invalidateGroovyClassLoader(node);
}
} catch (NodeException e) {
Synchronizer.invalidateGroovyClassLoader();
}
});
if (registerWatchers) {
try {
Synchronizer.registerAll(packagePath);
Expand Down Expand Up @@ -516,11 +530,11 @@ public String getHandlebarsHelpers() throws IOException {

if (helpersDirectory.isDirectory()) {
StringBuilder registerHelpers = new StringBuilder();
File[] files = helpersDirectory.listFiles((dir, name) -> StringUtils.endsWith(name, ".js"));
File[] files = helpersDirectory.listFiles((dir, name) -> Strings.CI.endsWith(name, ".js"));

if (files != null) {
for (File helperFile : files) {
String helperNameShort = StringUtils.removeEnd(helperFile.getName(), ".js");
String helperNameShort = Strings.CI.removeEnd(helperFile.getName(), ".js");
String helperName = String.format("%s.%s", packageName, helperNameShort);
String helperFileContents = FileUtils.readFileToString(helperFile, StandardCharsets.UTF_8);
String register = String.format("Handlebars.registerHelper('%s', %s)", helperName, helperFileContents);
Expand All @@ -547,6 +561,20 @@ public File getHandlebarsPartialsDirectory() {
return new File(handlebarsDirectory, "partials");
}

/**
* Get the script files of the package
* @return script files
*/
public File[] getScriptFiles() {
File scriptsDirectory = new File(this.packagePath.toFile(), SCRIPTS_DIR);

if (scriptsDirectory.isDirectory()) {
return scriptsDirectory.listFiles((dir, name) -> Strings.CI.endsWith(name, ".groovy"));
}

return new File[0];
}

/**
* Add a synchronizer implementation
* @param path base path
Expand Down
Loading