diff --git a/ccm-core/src/main/java/org/libreccm/files/NIOFileSystemAdapter.java b/ccm-core/src/main/java/org/libreccm/files/NIOFileSystemAdapter.java index a54a4f2e6..c89741fd3 100644 --- a/ccm-core/src/main/java/org/libreccm/files/NIOFileSystemAdapter.java +++ b/ccm-core/src/main/java/org/libreccm/files/NIOFileSystemAdapter.java @@ -434,14 +434,6 @@ public class NIOFileSystemAdapter implements FileSystemAdapter { throw new InsufficientPermissionsException(path); } - try { - if (Files.isDirectory(nioPath) && Files.list(nioPath).count() > 0) { - throw new DirectoryNotEmptyException(path); - } - } catch (IOException ex) { - throw new FileAccessException(path, ex); - } - if (recursively && Files.isDirectory(nioPath)) { final List files; try { @@ -455,7 +447,11 @@ public class NIOFileSystemAdapter implements FileSystemAdapter { for (final String file : files) { deleteFile(file, recursively); } + + deleteFile(path); } else { + + deleteFile(path); } } diff --git a/ccm-core/src/main/java/org/libreccm/theming/FileSystemThemeProvider.java b/ccm-core/src/main/java/org/libreccm/theming/FileSystemThemeProvider.java index 062936fda..a19e6d17c 100644 --- a/ccm-core/src/main/java/org/libreccm/theming/FileSystemThemeProvider.java +++ b/ccm-core/src/main/java/org/libreccm/theming/FileSystemThemeProvider.java @@ -22,15 +22,20 @@ import org.libreccm.core.UnexpectedErrorException; import org.libreccm.files.CcmFiles; import org.libreccm.files.DirectoryNotEmptyException; import org.libreccm.files.FileAccessException; +import org.libreccm.files.FileAlreadyExistsException; import org.libreccm.files.FileDoesNotExistException; import org.libreccm.files.InsufficientPermissionsException; import org.libreccm.theming.manifest.ThemeManifest; import org.libreccm.theming.manifest.ThemeManifestUtil; +import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.logging.Level; import java.util.logging.Logger; @@ -84,8 +89,8 @@ public class FileSystemThemeProvider implements ThemeProvider { .collect(Collectors.toList()); } catch (FileAccessException - | FileDoesNotExistException - | InsufficientPermissionsException ex) { + | FileDoesNotExistException + | InsufficientPermissionsException ex) { throw new UnexpectedErrorException(ex); } @@ -96,7 +101,7 @@ public class FileSystemThemeProvider implements ThemeProvider { try { if (!ccmFiles.isDirectory(BASE_PATH) - || !ccmFiles.isDirectory(DRAFT_THEMES_PATH)) { + || !ccmFiles.isDirectory(LIVE_THEMES_PATH)) { return Collections.emptyList(); } @@ -109,8 +114,8 @@ public class FileSystemThemeProvider implements ThemeProvider { .map(info -> info.get()) .collect(Collectors.toList()); } catch (FileAccessException - | FileDoesNotExistException - | InsufficientPermissionsException ex) { + | FileDoesNotExistException + | InsufficientPermissionsException ex) { throw new UnexpectedErrorException(ex); } @@ -137,6 +142,86 @@ public class FileSystemThemeProvider implements ThemeProvider { } } + @Override + public ThemeInfo createTheme(final String themeName) { + + Objects.requireNonNull(themeName); + + if (themeName.isEmpty() || themeName.matches("\\s*")) { + throw new IllegalArgumentException( + "The name of a theme can't be empty."); + } + + try { + ccmFiles.createDirectory(String.format(DRAFT_THEMES_PATH + "/%s", + themeName)); + } catch (FileAccessException + | FileAlreadyExistsException + | InsufficientPermissionsException ex) { + throw new UnexpectedErrorException(ex); + } + + final ThemeManifest manifest = new ThemeManifest(); + manifest.setName(themeName); + + final OutputStream outputStream; + try { + outputStream = ccmFiles.createOutputStream( + String.format(DRAFT_THEMES_PATH + "/%s/" + + ThemeConstants.THEME_MANIFEST_JSON, + themeName)); + } catch (FileAccessException + | InsufficientPermissionsException ex) { + throw new UnexpectedErrorException(ex); + } + + try(final OutputStreamWriter writer = new OutputStreamWriter( + outputStream, StandardCharsets.UTF_8)) { + writer + .append(manifestUtil + .serializeManifest(manifest, + ThemeConstants.THEME_MANIFEST_JSON)); + writer.flush(); + } catch (IOException ex) { + throw new UnexpectedErrorException(ex); + } + + return getThemeInfo(themeName, ThemeVersion.DRAFT).get(); + } + + @Override + public void deleteTheme(final String themeName) { + + Objects.requireNonNull(themeName); + + if (themeName.isEmpty() || themeName.matches("\\s*")) { + throw new IllegalArgumentException( + "The name of a theme can't be empty."); + } + + final Optional liveTheme = getLiveThemes() + .stream() + .filter(theme -> theme.getName().equals(themeName)) + .findAny(); + + if (liveTheme.isPresent()) { + throw new IllegalArgumentException(String + .format("The theme \"%s\" is live and can't be deleted.", + themeName)); + } + + try { + ccmFiles.deleteFile(String.format(DRAFT_THEMES_PATH + "/%s", + themeName), + true); + } catch (FileAccessException + | FileDoesNotExistException + | DirectoryNotEmptyException + | InsufficientPermissionsException ex) { + throw new UnexpectedErrorException(ex); + } + } + @Override public List listThemeFiles(final String theme, final ThemeVersion version, @@ -154,8 +239,8 @@ public class FileSystemThemeProvider implements ThemeProvider { .collect(Collectors.toList()); } catch (FileAccessException - | FileDoesNotExistException - | InsufficientPermissionsException ex) { + | FileDoesNotExistException + | InsufficientPermissionsException ex) { throw new UnexpectedErrorException(ex); } @@ -166,7 +251,7 @@ public class FileSystemThemeProvider implements ThemeProvider { final String theme, final ThemeVersion version, final String path) { final String themePath = createThemePath(theme, version); - final String filePath = String.join(theme, path, "/"); + final String filePath = String.join(themePath, path, "/"); try { if (ccmFiles.existsFile(path)) { @@ -175,8 +260,8 @@ public class FileSystemThemeProvider implements ThemeProvider { return Optional.of(ccmFiles.createInputStream(filePath)); } } catch (FileAccessException - | FileDoesNotExistException - | InsufficientPermissionsException ex) { + | FileDoesNotExistException + | InsufficientPermissionsException ex) { throw new UnexpectedErrorException(ex); } @@ -194,7 +279,7 @@ public class FileSystemThemeProvider implements ThemeProvider { return ccmFiles.createOutputStream(filePath); } catch (FileAccessException - | InsufficientPermissionsException ex) { + | InsufficientPermissionsException ex) { throw new UnexpectedErrorException(ex); } @@ -209,9 +294,9 @@ public class FileSystemThemeProvider implements ThemeProvider { try { ccmFiles.deleteFile(filePath, true); } catch (FileAccessException - | FileDoesNotExistException - | DirectoryNotEmptyException - | InsufficientPermissionsException ex) { + | FileDoesNotExistException + | DirectoryNotEmptyException + | InsufficientPermissionsException ex) { throw new UnexpectedErrorException(ex); } @@ -242,14 +327,14 @@ public class FileSystemThemeProvider implements ThemeProvider { if (ccmFiles.existsFile(liveThemePath)) { ccmFiles.deleteFile(liveThemePath, true); } - + ccmFiles.moveFile(liveThemePathTmp, liveThemePath); } catch (DirectoryNotEmptyException - | FileAccessException + | FileAccessException | FileDoesNotExistException | InsufficientPermissionsException ex) { throw new UnexpectedErrorException(); - } + } } private String createThemePath(final String theme, @@ -258,9 +343,9 @@ public class FileSystemThemeProvider implements ThemeProvider { switch (version) { case DRAFT: - return String.format(DRAFT_THEMES_PATH, theme); + return String.format(DRAFT_THEMES_PATH + "/%s", theme); case LIVE: - return String.format(LIVE_THEMES_PATH, theme); + return String.format(LIVE_THEMES_PATH + "/%s", theme); default: throw new IllegalArgumentException(String .format("Illegal argument for ThemeVersion \"%s\".", @@ -286,8 +371,8 @@ public class FileSystemThemeProvider implements ThemeProvider { return Optional.empty(); } } catch (FileAccessException - | FileDoesNotExistException - | InsufficientPermissionsException ex) { + | FileDoesNotExistException + | InsufficientPermissionsException ex) { throw new UnexpectedErrorException(ex); } @@ -310,8 +395,8 @@ public class FileSystemThemeProvider implements ThemeProvider { return fileInfo; } catch (FileAccessException - | FileDoesNotExistException - | InsufficientPermissionsException ex) { + | FileDoesNotExistException + | InsufficientPermissionsException ex) { throw new UnexpectedErrorException(ex); } diff --git a/ccm-core/src/main/java/org/libreccm/theming/StaticThemeProvider.java b/ccm-core/src/main/java/org/libreccm/theming/StaticThemeProvider.java index 20abbf3fb..63697aa72 100644 --- a/ccm-core/src/main/java/org/libreccm/theming/StaticThemeProvider.java +++ b/ccm-core/src/main/java/org/libreccm/theming/StaticThemeProvider.java @@ -254,6 +254,22 @@ public class StaticThemeProvider implements ThemeProvider { return manifestJsonUrl != null || manifestXmlUrl != null; } + @Override + public ThemeInfo createTheme(final String theme) { + + throw new UnsupportedOperationException(String.format( + "The ThemeProvider %s does support the creation of new themes.", + getClass().getName())); + } + + @Override + public void deleteTheme(final String theme) { + + throw new UnsupportedOperationException(String.format( + "The ThemeProvider %s does support the deltion of themes.", + getClass().getName())); + } + @Override public List listThemeFiles(final String theme, final ThemeVersion version, diff --git a/ccm-core/src/main/java/org/libreccm/theming/ThemeProvider.java b/ccm-core/src/main/java/org/libreccm/theming/ThemeProvider.java index 5ba60ce8c..a94ebfd02 100644 --- a/ccm-core/src/main/java/org/libreccm/theming/ThemeProvider.java +++ b/ccm-core/src/main/java/org/libreccm/theming/ThemeProvider.java @@ -79,6 +79,36 @@ public interface ThemeProvider extends Serializable { */ boolean providesTheme(String theme, ThemeVersion version); + /** + * Creates a new theme. + * + * The theme should be empty besides the manifest file. If a theme with the + * provided name already exists implementations should throw an + * {@link IllegalArgumentException}. + * + * {@code ThemeProvider} implementations which do not support the the + * creation of new themes the implementation of the method should throw a + * {@link UnsupportedOperationException}. + * + * @param themeName The name of the new theme. + * + * @return The {@link ThemeInfo} about the new theme. + */ + ThemeInfo createTheme(String themeName); + + /** + * Deletes a theme and all its content. + * + * If the is live implementations should throw an exception. + * + * {@code ThemeProvider} implementations which do not support the the + * deletion of themes the implementation of the method should throw a + * {@link UnsupportedOperationException}. + * + * @param themeName The theme to delete. + */ + void deleteTheme(String themeName); + /** * List all files in a theme at the specified path. * @@ -154,7 +184,7 @@ public interface ThemeProvider extends Serializable { OutputStream getOutputStreamForThemeFile(String theme, String path); void deleteThemeFile(String theme, String path); - + /** * Determines if the implementation supports changes to the files of the * themes. diff --git a/ccm-core/src/main/java/org/libreccm/theming/Themes.java b/ccm-core/src/main/java/org/libreccm/theming/Themes.java index af820d717..c9fb4313b 100644 --- a/ccm-core/src/main/java/org/libreccm/theming/Themes.java +++ b/ccm-core/src/main/java/org/libreccm/theming/Themes.java @@ -184,9 +184,9 @@ public class Themes implements Serializable { return Optional.empty(); } else { final Optional masterTheme = getTheme( - theme.getManifest().getMasterTheme(), + theme.getManifest().getMasterTheme(), theme.getVersion()); - + if (masterTheme.isPresent()) { return getFileFromTheme(masterTheme.get(), path); } else { @@ -194,21 +194,22 @@ public class Themes implements Serializable { } } } - + /** * List all files in a theme at the specified path - * + * * @param theme The theme from which the file is retrieved. - * @param path The path of the file relative to the root directory of the + * @param path The path of the file relative to the root directory of the * theme. + * * @return A list of all files in the provided directory. If there is no * such path in the theme the list is empty. If the path is the path * of a file and not a directory the list should have one element, * the data about the file itself. */ - public List listThemesFiles(final ThemeInfo theme, - final String path) { - + public List listThemeFiles(final ThemeInfo theme, + final String path) { + final Instance forTheme = providers.select( theme.getProvider()); @@ -221,17 +222,17 @@ public class Themes implements Serializable { } final ThemeProvider provider = forTheme.get(); - return provider.listThemeFiles(theme.getName(), - theme.getVersion(), + return provider.listThemeFiles(theme.getName(), + theme.getVersion(), path); } - - public void deleteThemeFile(final ThemeInfo theme, + + public void deleteThemeFile(final ThemeInfo theme, final String path) { - - final Instance forTheme = providers.select( - theme.getProvider()); - + + final Instance forTheme = providers + .select(theme.getProvider()); + if (forTheme.isUnsatisfied()) { LOGGER.error("ThemeProvider \"{}\" not found.", theme.getProvider().getName()); @@ -242,7 +243,7 @@ public class Themes implements Serializable { final ThemeProvider provider = forTheme.get(); provider.deleteThemeFile(theme.getName(), path); - + } } diff --git a/ccm-core/src/main/java/org/libreccm/theming/db/DatabaseThemeProvider.java b/ccm-core/src/main/java/org/libreccm/theming/db/DatabaseThemeProvider.java index f1d73fe3a..826670f25 100644 --- a/ccm-core/src/main/java/org/libreccm/theming/db/DatabaseThemeProvider.java +++ b/ccm-core/src/main/java/org/libreccm/theming/db/DatabaseThemeProvider.java @@ -112,6 +112,39 @@ public class DatabaseThemeProvider implements ThemeProvider { .isPresent(); } + @Override + public ThemeInfo createTheme(final String themeName) { + + Objects.requireNonNull(themeName); + + if (themeName.isEmpty() || themeName.matches("\\s*")) { + throw new IllegalArgumentException( + "The name of a theme can't be empty."); + } + + final Theme theme = themeManager.createTheme(themeName); + + return createThemeInfo(theme); + } + + @Override + public void deleteTheme(final String themeName) { + + Objects.requireNonNull(themeName); + + if (themeName.isEmpty() || themeName.matches("\\s*")) { + throw new IllegalArgumentException( + "The name of a theme can't be empty."); + } + + final Theme theme = themeRepository + .findThemeByName(themeName, ThemeVersion.DRAFT) + .orElseThrow(() -> new IllegalArgumentException(String.format( + "No theme with name \"%s\" is managed by this provider.", + themeName))); + themeManager.deleteTheme(theme); + } + @Override public List listThemeFiles(final String themeName, final ThemeVersion version, @@ -247,7 +280,7 @@ public class DatabaseThemeProvider implements ThemeProvider { @Override public void deleteThemeFile(final String themeName, final String path) { - + Objects.requireNonNull(themeName); Objects.requireNonNull(path); @@ -267,10 +300,10 @@ public class DatabaseThemeProvider implements ThemeProvider { final ThemeFile file = fileRepository .findByPath(theme, path, ThemeVersion.DRAFT) .orElse(createDataFile(theme, path)); - + if (file instanceof DataFile) { fileManager.delete(file); - } else if(file instanceof Directory) { + } else if (file instanceof Directory) { fileManager.deleteRecursive(file); } } diff --git a/ccm-core/src/main/java/org/libreccm/theming/manager/ThemeManager.java b/ccm-core/src/main/java/org/libreccm/theming/manager/ThemeManager.java new file mode 100644 index 000000000..a3d06ba1b --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/theming/manager/ThemeManager.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2018 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.theming.manager; + +import java.util.HashSet; +import java.util.Set; + +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.core.Application; + +/** + * JAX-RS application for managing themes. + * + * @author Jens Pelzetter + */ +@ApplicationPath("/thememanager") +public class ThemeManager extends Application { + + @Override + public Set> getClasses() { + + final Set> classes = new HashSet<>(); + classes.add(Themes.class); + return classes; + } + + +} diff --git a/ccm-core/src/main/java/org/libreccm/theming/manager/Themes.java b/ccm-core/src/main/java/org/libreccm/theming/manager/Themes.java new file mode 100644 index 000000000..c7aff21fd --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/theming/manager/Themes.java @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2018 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.theming.manager; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.libreccm.theming.ThemeInfo; +import org.libreccm.theming.ThemeProvider; +import org.libreccm.theming.ThemeVersion; + +import java.io.Serializable; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +import javax.enterprise.context.RequestScoped; +import javax.enterprise.inject.Any; +import javax.enterprise.inject.Instance; +import javax.inject.Inject; +import javax.json.Json; +import javax.json.JsonArrayBuilder; +import javax.json.JsonWriter; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import static javassist.CtClass.*; +import static org.reflections.util.Utils.*; + +/** + * + * @author Jens Pelzetter + */ +@RequestScoped +@Path("/") +public class Themes implements Serializable { + + private static final long serialVersionUID = 1L; + + private static final Logger LOGGER = LogManager.getLogger(Themes.class); + + @Inject + @Any + private Instance providers; + + @Inject + private Themes themes; + + @GET + @Path("/providers") + @Produces(MediaType.APPLICATION_JSON) + public String getThemeProviders() { + + final List providersList = new ArrayList<>(); + providers + .forEach(provider -> providersList.add(provider)); + + final JsonArrayBuilder jsonArrayBuilder = Json.createArrayBuilder(); + + providersList + .stream() + .filter(provider -> provider.supportsChanges() + && provider.supportsDraftThemes()) + .map(this::getProviderName) + .forEach(jsonArrayBuilder::add); + + final StringWriter writer = new StringWriter(); + final JsonWriter jsonWriter = Json.createWriter(writer); + + jsonWriter.writeArray(jsonArrayBuilder.build()); + + return writer.toString(); + } + + @GET + @Path("/themes") + @Produces(MediaType.APPLICATION_JSON) + public List getAvailableThemes() { + + final List availableThemes = new ArrayList<>(); + for (final ThemeProvider provider : providers) { + if (provider.supportsChanges() && provider.supportsDraftThemes()) { + availableThemes.addAll(provider.getThemes()); + } + } + + return availableThemes; + } + + @GET + @Path("/themes/{theme}") + @Produces(MediaType.APPLICATION_JSON) + public ThemeInfo getTheme(@PathParam("theme") final String themeName) { + + for (final ThemeProvider provider : providers) { + if (provider.providesTheme(themeName, ThemeVersion.DRAFT)) { + return provider + .getThemeInfo(themeName, ThemeVersion.DRAFT) + .orElseThrow(() -> new WebApplicationException( + Response.Status.NOT_FOUND)); + } + } + + throw new WebApplicationException(Response.Status.NOT_FOUND); + } + + @PUT + @Path("/themes/{theme}") + @Produces(MediaType.APPLICATION_JSON) + @SuppressWarnings("unchecked") + public ThemeInfo createTheme( + @PathParam("theme") final String themeName, + @QueryParam("provider") final String providerName) { + + Objects.requireNonNull(themeName); + Objects.requireNonNull(providerName); + + if (themeName.isEmpty() || themeName.matches("\\s*")) { + throw new WebApplicationException("No name for new theme provided.", + Response.Status.BAD_REQUEST); + } + + if (providerName.isEmpty() || providerName.matches("\\s*")) { + throw new WebApplicationException( + "No provider for new theme provided.", + Response.Status.BAD_REQUEST); + } + + final Class providerClass; + try { + providerClass = (Class) Class.forName(providerName); + } catch (ClassNotFoundException ex) { + throw new WebApplicationException( + String.format("No provider with name \"%s\" available.", + providerName), + Response.Status.INTERNAL_SERVER_ERROR); + } + final ThemeProvider provider = providers.select(providerClass).get(); + + return provider.createTheme(themeName); + } + + @DELETE + @Path("/themes/{theme}") + public void deleteTheme(@PathParam("theme") final String themeName) { + + Objects.requireNonNull(themeName); + + final List providersList = new ArrayList<>(); + providers + .forEach(provider -> providersList.add(provider)); + + final Optional provider = providersList + .stream() + .filter(current -> current.providesTheme(themeName, + ThemeVersion.DRAFT)) + .findAny(); + + if (provider.isPresent()) { + + provider.get().deleteTheme(themeName); + + } else { + throw new WebApplicationException(Response.Status.NOT_FOUND); + } + } + + private String getProviderName(final ThemeProvider provider) { + + if (provider + .getClass() + .getCanonicalName() + .toLowerCase() + .contains("$proxy")) { + + final String name = provider.getClass().getCanonicalName(); + return name.substring(0, name.toLowerCase().indexOf("$proxy")); + + } else { + return provider.getClass().getName(); + } + + } + +} diff --git a/ccm-core/src/main/java/org/libreccm/theming/manifest/ThemeManifestUtil.java b/ccm-core/src/main/java/org/libreccm/theming/manifest/ThemeManifestUtil.java index 0814d4ed2..9a3ef5c2a 100644 --- a/ccm-core/src/main/java/org/libreccm/theming/manifest/ThemeManifestUtil.java +++ b/ccm-core/src/main/java/org/libreccm/theming/manifest/ThemeManifestUtil.java @@ -21,6 +21,7 @@ package org.libreccm.theming.manifest; import static org.libreccm.theming.ThemeConstants.*; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.dataformat.xml.JacksonXmlModule; import com.fasterxml.jackson.dataformat.xml.XmlMapper; import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule; @@ -149,6 +150,7 @@ public class ThemeManifestUtil implements Serializable { } mapper.registerModule(new JaxbAnnotationModule()); + mapper.configure(SerializationFeature.INDENT_OUTPUT, true); final StringWriter writer = new StringWriter(); try { diff --git a/ccm-core/src/main/java/org/libreccm/theming/webdav/ThemeFiles.java b/ccm-core/src/main/java/org/libreccm/theming/webdav/ThemeFiles.java index 4edb80bcb..b8128062c 100644 --- a/ccm-core/src/main/java/org/libreccm/theming/webdav/ThemeFiles.java +++ b/ccm-core/src/main/java/org/libreccm/theming/webdav/ThemeFiles.java @@ -202,7 +202,7 @@ public class ThemeFiles { "No theme with name \"%s\" exists.", theme))); - final List fileInfos = themes.listThemesFiles(themeInfo, + final List fileInfos = themes.listThemeFiles(themeInfo, path); final MultiStatus result; if (fileInfos.isEmpty()) {