From db9e9b9cfd521d9710760f9ed35090861126f5fe Mon Sep 17 00:00:00 2001 From: jensp Date: Fri, 14 Sep 2018 18:01:57 +0000 Subject: [PATCH] CCM NG: Second part of api for theme manager app git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@5692 8810af33-2d31-482b-a856-94f89814c4df --- .../libreccm/files/NIOFileSystemAdapter.java | 21 ++--- .../theming/FileSystemThemeProvider.java | 72 ++++++++++++----- .../libreccm/theming/StaticThemeProvider.java | 5 ++ .../org/libreccm/theming/ThemeProvider.java | 9 +++ .../theming/db/DatabaseThemeProvider.java | 8 ++ .../org/libreccm/theming/manager/Themes.java | 80 +++++++++++++++---- 6 files changed, 153 insertions(+), 42 deletions(-) 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 c89741fd3..7c6b6c806 100644 --- a/ccm-core/src/main/java/org/libreccm/files/NIOFileSystemAdapter.java +++ b/ccm-core/src/main/java/org/libreccm/files/NIOFileSystemAdapter.java @@ -44,7 +44,6 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.nio.file.attribute.BasicFileAttributes; -import java.rmi.UnexpectedException; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -234,14 +233,16 @@ public class NIOFileSystemAdapter implements FileSystemAdapter { final String targetPath, boolean recursive) throws FileAccessException { - final Path nioSourcePath = Paths.get(sourcePath); - final Path nioTargetPath = Paths.get(targetPath); + final Path nioSourcePath = Paths + .get(String.join("/", dataPath, sourcePath)); + final Path nioTargetPath = Paths + .get(String.join("/", dataPath, targetPath)); if (recursive) { try { Files.walkFileTree( - nioTargetPath, + nioSourcePath, new FileVisitor() { @Override @@ -262,7 +263,7 @@ public class NIOFileSystemAdapter implements FileSystemAdapter { file, nioTargetPath .resolve(nioSourcePath.relativize(file)), - StandardCopyOption.ATOMIC_MOVE, +// StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING, LinkOption.NOFOLLOW_LINKS); @@ -311,7 +312,7 @@ public class NIOFileSystemAdapter implements FileSystemAdapter { try { Files.copy(nioSourcePath, nioTargetPath, - StandardCopyOption.ATOMIC_MOVE, +// StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING, LinkOption.NOFOLLOW_LINKS); @@ -325,14 +326,16 @@ public class NIOFileSystemAdapter implements FileSystemAdapter { public void move(final String sourcePath, final String targetPath) throws FileAccessException { - final Path nioSourcePath = Paths.get(sourcePath); - final Path nioTargetPath = Paths.get(targetPath); + final Path nioSourcePath = Paths.get( + String.join("/", dataPath, sourcePath)); + final Path nioTargetPath = Paths.get( + String.join("/", dataPath, targetPath)); try { Files.move(nioSourcePath, nioTargetPath, StandardCopyOption.ATOMIC_MOVE, - StandardCopyOption.COPY_ATTRIBUTES, +// StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING, LinkOption.NOFOLLOW_LINKS); } catch(IOException ex) { 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 a19e6d17c..63f85e747 100644 --- a/ccm-core/src/main/java/org/libreccm/theming/FileSystemThemeProvider.java +++ b/ccm-core/src/main/java/org/libreccm/theming/FileSystemThemeProvider.java @@ -54,8 +54,8 @@ public class FileSystemThemeProvider implements ThemeProvider { private static final long serialVersionUID = 1L; private static final String BASE_PATH = "/themes"; - private static final String DRAFT_THEMES_PATH = "/themes" + "/draft"; - private static final String LIVE_THEMES_PATH = "/themes" + "/live"; + private static final String DRAFT_THEMES_PATH = BASE_PATH + "/draft"; + private static final String LIVE_THEMES_PATH = BASE_PATH + "/live"; private static final String THEME_JSON = "%s/theme.json"; private static final String THEME_XML = "%s/theme.xml"; @@ -175,7 +175,7 @@ public class FileSystemThemeProvider implements ThemeProvider { throw new UnexpectedErrorException(ex); } - try(final OutputStreamWriter writer = new OutputStreamWriter( + try (final OutputStreamWriter writer = new OutputStreamWriter( outputStream, StandardCharsets.UTF_8)) { writer .append(manifestUtil @@ -203,21 +203,21 @@ public class FileSystemThemeProvider implements ThemeProvider { .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", + ccmFiles.deleteFile(String.format(DRAFT_THEMES_PATH + "/%s", themeName), true); - } catch (FileAccessException - | FileDoesNotExistException - | DirectoryNotEmptyException - | InsufficientPermissionsException ex) { + } catch (FileAccessException + | FileDoesNotExistException + | DirectoryNotEmptyException + | InsufficientPermissionsException ex) { throw new UnexpectedErrorException(ex); } } @@ -320,20 +320,50 @@ public class FileSystemThemeProvider implements ThemeProvider { ThemeVersion.DRAFT); final String liveThemePath = createThemePath(theme, ThemeVersion.LIVE); - final String liveThemePathTmp = String.format("%_tmp", liveThemePath); + final String liveThemePathTmp = String.format("%s_tmp", liveThemePath); try { + if (!ccmFiles.existsFile(LIVE_THEMES_PATH)) { + ccmFiles.createDirectory(LIVE_THEMES_PATH); + } + } catch (FileAccessException + | InsufficientPermissionsException + | FileAlreadyExistsException ex) { + throw new UnexpectedErrorException(ex); + } + + try { + + ccmFiles.createDirectory(liveThemePathTmp); + ccmFiles.copyFile(draftThemePath, liveThemePathTmp, true); if (ccmFiles.existsFile(liveThemePath)) { ccmFiles.deleteFile(liveThemePath, true); } ccmFiles.moveFile(liveThemePathTmp, liveThemePath); + + } catch (DirectoryNotEmptyException + | FileAccessException + | FileAlreadyExistsException + | FileDoesNotExistException + | InsufficientPermissionsException ex) { + throw new UnexpectedErrorException(ex); + } + } + + @Override + public void unpublishTheme(final String theme) { + + final String liveThemePath = createThemePath(theme, + ThemeVersion.LIVE); + try { + ccmFiles.deleteFile(liveThemePath, true); } catch (DirectoryNotEmptyException | FileAccessException | FileDoesNotExistException | InsufficientPermissionsException ex) { - throw new UnexpectedErrorException(); + throw new UnexpectedErrorException(ex); } } @@ -357,15 +387,19 @@ public class FileSystemThemeProvider implements ThemeProvider { final ThemeManifest manifest; try { - final InputStream inputStream = ccmFiles - .createInputStream(String.format(THEME_JSON, - themePath)); - if (ccmFiles.existsFile(String.format(THEME_JSON, - themePath))) { + final String jsonPath = String.format( + DRAFT_THEMES_PATH + "/" + THEME_JSON, themePath); + final String xmlPath = String.format( + DRAFT_THEMES_PATH + "/" + THEME_XML, themePath); + + if (ccmFiles.existsFile(jsonPath)) { + final InputStream inputStream = ccmFiles + .createInputStream(jsonPath); manifest = manifestUtil.loadManifest(inputStream, "theme.json"); - } else if (ccmFiles.existsFile(String.format(THEME_XML, - themePath))) { + } else if (ccmFiles.existsFile(xmlPath)) { + final InputStream inputStream = ccmFiles + .createInputStream(xmlPath); manifest = manifestUtil.loadManifest(inputStream, "theme.xml"); } else { return Optional.empty(); 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 63697aa72..b15353cbb 100644 --- a/ccm-core/src/main/java/org/libreccm/theming/StaticThemeProvider.java +++ b/ccm-core/src/main/java/org/libreccm/theming/StaticThemeProvider.java @@ -390,6 +390,11 @@ public class StaticThemeProvider implements ThemeProvider { public void publishTheme(final String theme) { //No op in this implementation. } + + @Override + public void unpublishTheme(final String theme) { + //No op in this implementation. + } private URI getJarUri() { 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 a94ebfd02..dbf920f3b 100644 --- a/ccm-core/src/main/java/org/libreccm/theming/ThemeProvider.java +++ b/ccm-core/src/main/java/org/libreccm/theming/ThemeProvider.java @@ -208,5 +208,14 @@ public interface ThemeProvider extends Serializable { * @param theme The theme to publish. */ void publishTheme(String theme); + + /** + * Unpublishes (deletes) the live version of a theme. For + * implementations which do not support draft/live themes the implementation + * of this method should be a noop, but not throw an exception. + * + * @param theme The theme to publish. + */ + void unpublishTheme(String theme); } 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 826670f25..00d455bf7 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 @@ -325,6 +325,14 @@ public class DatabaseThemeProvider implements ThemeProvider { .findThemeByName(themeName, ThemeVersion.DRAFT) .ifPresent(themeManager::publishTheme); } + + @Override + public void unpublishTheme(final String themeName) { + + themeRepository + .findThemeByName(themeName, ThemeVersion.LIVE) + .ifPresent(themeManager::unpublishTheme); + } private ThemeInfo createThemeInfo(final Theme theme) { 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 index c7aff21fd..bb3e88576 100644 --- a/ccm-core/src/main/java/org/libreccm/theming/manager/Themes.java +++ b/ccm-core/src/main/java/org/libreccm/theming/manager/Themes.java @@ -20,9 +20,11 @@ package org.libreccm.theming.manager; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.libreccm.security.RequiresPrivilege; import org.libreccm.theming.ThemeInfo; import org.libreccm.theming.ThemeProvider; import org.libreccm.theming.ThemeVersion; +import org.libreccm.theming.ThemingPrivileges; import java.io.Serializable; import java.io.StringWriter; @@ -40,6 +42,7 @@ import javax.json.JsonArrayBuilder; import javax.json.JsonWriter; import javax.ws.rs.DELETE; import javax.ws.rs.GET; +import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; @@ -49,8 +52,6 @@ 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.*; /** * @@ -74,6 +75,8 @@ public class Themes implements Serializable { @GET @Path("/providers") @Produces(MediaType.APPLICATION_JSON) + //@AuthorizationRequired + @RequiresPrivilege(ThemingPrivileges.ADMINISTER_THEMES) public String getThemeProviders() { final List providersList = new ArrayList<>(); @@ -100,6 +103,8 @@ public class Themes implements Serializable { @GET @Path("/themes") @Produces(MediaType.APPLICATION_JSON) + //@AuthorizationRequired + @RequiresPrivilege(ThemingPrivileges.ADMINISTER_THEMES) public List getAvailableThemes() { final List availableThemes = new ArrayList<>(); @@ -115,6 +120,8 @@ public class Themes implements Serializable { @GET @Path("/themes/{theme}") @Produces(MediaType.APPLICATION_JSON) + //@AuthorizationRequired + @RequiresPrivilege(ThemingPrivileges.EDIT_THEME) public ThemeInfo getTheme(@PathParam("theme") final String themeName) { for (final ThemeProvider provider : providers) { @@ -133,6 +140,8 @@ public class Themes implements Serializable { @Path("/themes/{theme}") @Produces(MediaType.APPLICATION_JSON) @SuppressWarnings("unchecked") + //@AuthorizationRequired + @RequiresPrivilege(ThemingPrivileges.ADMINISTER_THEMES) public ThemeInfo createTheme( @PathParam("theme") final String themeName, @QueryParam("provider") final String providerName) { @@ -167,29 +176,59 @@ public class Themes implements Serializable { @DELETE @Path("/themes/{theme}") + //@AuthorizationRequired + @RequiresPrivilege(ThemingPrivileges.ADMINISTER_THEMES) 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(); - + final Optional provider = findProvider(themeName); + if (provider.isPresent()) { - + provider.get().deleteTheme(themeName); - + } else { throw new WebApplicationException(Response.Status.NOT_FOUND); } } + @POST + @Path("/themes/{theme}/live") + //@AuthorizationRequired + @RequiresPrivilege(ThemingPrivileges.ADMINISTER_THEMES) + public void publishTheme(@PathParam("theme") final String themeName) { + + final Optional provider = findProvider(themeName); + + if (provider.isPresent()) { + + provider.get().publishTheme(themeName); + + } else { + throw new WebApplicationException(Response.Status.NOT_FOUND); + } + + } + + @DELETE + @Path("/themes/{theme}/live") + //@AuthorizationRequired + @RequiresPrivilege(ThemingPrivileges.ADMINISTER_THEMES) + public void unPublishTheme(@PathParam("theme") final String themeName) { + + final Optional provider = findProvider(themeName); + + if (provider.isPresent()) { + + provider.get().unpublishTheme(themeName); + + } else { + throw new WebApplicationException(Response.Status.NOT_FOUND); + } + + } + private String getProviderName(final ThemeProvider provider) { if (provider @@ -207,4 +246,17 @@ public class Themes implements Serializable { } + private Optional findProvider(final String forTheme) { + + final List providersList = new ArrayList<>(); + providers + .forEach(provider -> providersList.add(provider)); + + return providersList + .stream() + .filter(current -> current.providesTheme(forTheme, + ThemeVersion.DRAFT)) + .findAny(); + } + }