diff --git a/ccm-core/src/main/java/org/libreccm/api/themes/Themes.java b/ccm-core/src/main/java/org/libreccm/api/themes/Themes.java new file mode 100644 index 000000000..9bac3c015 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/api/themes/Themes.java @@ -0,0 +1,595 @@ +/* + * 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.api.themes; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.libreccm.security.AuthorizationRequired; +import org.libreccm.security.RequiresPrivilege; +import org.libreccm.theming.ThemeFileInfo; +import org.libreccm.theming.ThemeInfo; +import org.libreccm.theming.ThemeProvider; +import org.libreccm.theming.ThemeVersion; +import org.libreccm.theming.ThemingPrivileges; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import javax.enterprise.context.RequestScoped; +import javax.enterprise.inject.Any; +import javax.enterprise.inject.Instance; +import javax.inject.Inject; +import javax.ws.rs.BadRequestException; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.NotFoundException; +import javax.ws.rs.POST; +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; + +/** + * + * @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; + + @GET + @Path("/providers") + @Produces(MediaType.APPLICATION_JSON) + @AuthorizationRequired + @RequiresPrivilege(ThemingPrivileges.ADMINISTER_THEMES) + public List getThemeProviders() { + + return providers + .stream() + .filter( + provider -> provider.supportsChanges() + && provider.supportsDraftThemes() + ) + .map(this::getProviderName) + .collect(Collectors.toList()); + } + + @GET + @Path("/themes") + @Produces(MediaType.APPLICATION_JSON) + @AuthorizationRequired + @RequiresPrivilege(ThemingPrivileges.ADMINISTER_THEMES) + public List getAvailableThemes() { + return providers + .stream() + .filter(provider -> provider.supportsChanges() + && provider.supportsDraftThemes() + ) + .map(ThemeProvider::getThemes) + .flatMap(themes -> themes.stream()) + .collect(Collectors.toList()); + } + + @GET + @Path("/themes/{theme}") + @Produces(MediaType.APPLICATION_JSON) + @AuthorizationRequired + @RequiresPrivilege(ThemingPrivileges.EDIT_THEME) + public ThemeInfo getTheme(@PathParam("theme") final String themeName) { + return providers + .stream() + .filter( + provider -> provider.providesTheme( + themeName, ThemeVersion.DRAFT + ) + ) + .findAny() + .map( + provider -> provider.getThemeInfo( + themeName, ThemeVersion.DRAFT + ) + ) + .orElseThrow( + () -> new NotFoundException( + String.format( + "Theme %s not found.", themeName + ) + ) + ) + .orElseThrow( + () -> new NotFoundException( + String.format( + "Theme %s not found.", themeName + ) + ) + ); + } + + @PUT + @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 + ) { + Objects.requireNonNull(themeName); + Objects.requireNonNull(providerName); + + if (themeName.isEmpty() || themeName.matches("\\s*")) { + throw new BadRequestException("No name for new theme provided."); + } + + if (providerName.isEmpty() || providerName.matches("\\s*")) { + throw new BadRequestException( + "No provider for new theme provided." + ); + } + + 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}") + @AuthorizationRequired + @RequiresPrivilege(ThemingPrivileges.ADMINISTER_THEMES) + public Response deleteTheme(@PathParam("theme") final String themeName) { + Objects.requireNonNull(themeName); + + final ThemeProvider provider = findProvider(themeName) + .orElseThrow( + () -> new NotFoundException( + String.format( + "Theme %s not found", themeName + ) + ) + ); + + provider.deleteTheme(themeName); + + return Response.ok().build(); + } + + @POST + @Path("/themes/{theme}/live") + @AuthorizationRequired + @RequiresPrivilege(ThemingPrivileges.ADMINISTER_THEMES) + public Response publishTheme(@PathParam("theme") final String themeName) { + final ThemeProvider provider = findProvider(themeName) + .orElseThrow( + () -> new NotFoundException( + String.format( + "Theme %s not found", themeName + ) + ) + ); + + provider.publishTheme(themeName); + + return Response.ok().build(); + } + + @DELETE + @Path("/themes/{theme}/live") + @AuthorizationRequired + @RequiresPrivilege(ThemingPrivileges.ADMINISTER_THEMES) + public Response unPublishTheme(@PathParam("theme") final String themeName) { + final ThemeProvider provider = findProvider(themeName) + .orElseThrow( + () -> new NotFoundException( + String.format( + "Theme %s not found", themeName + ) + ) + ); + + provider.unpublishTheme(themeName); + + return Response.ok().build(); + } + + @GET + @Path("/themes/{theme}/files/") + @AuthorizationRequired + @RequiresPrivilege(ThemingPrivileges.EDIT_THEME) + public Response getThemeRootDir(@PathParam("theme") final String themeName) { + final ThemeProvider provider = findProvider(themeName) + .orElseThrow( + () -> new NotFoundException( + String.format( + "Theme %s not found", themeName + ) + ) + ); + + final ThemeFileInfo fileInfo = provider + .getThemeFileInfo(themeName, ThemeVersion.DRAFT, "/") + .orElseThrow( + () -> new WebApplicationException( + String.format( + "File \"/\" in theme %s is not a directory.", + themeName), + Response.Status.INTERNAL_SERVER_ERROR + ) + ); + + if (fileInfo.isDirectory()) { + return Response + .ok( + provider.listThemeFiles( + themeName, ThemeVersion.DRAFT, "/") + ) + .type(MediaType.APPLICATION_JSON) + .build(); + } else { + throw new WebApplicationException( + String.format( + "File \"/\" in theme %s is not a directory.", + themeName), + Response.Status.INTERNAL_SERVER_ERROR); + } + } + + @GET + @Path("/themes/{theme}/files/{path:.+}") + @AuthorizationRequired + @RequiresPrivilege(ThemingPrivileges.EDIT_THEME) + public Response getThemeFile( + @PathParam("theme") final String themeName, + @PathParam("path") final String path + ) { + final ThemeProvider provider = findProvider(themeName) + .orElseThrow( + () -> new NotFoundException( + String.format( + "Theme \"%s\" does not exist.", themeName + ) + ) + ); + + final ThemeFileInfo fileInfo = provider + .getThemeFileInfo(themeName, ThemeVersion.DRAFT, path) + .orElseThrow( + () -> new NotFoundException( + String.format( + "File \"%s\" does not exist in theme %s.", + path, + themeName + ) + ) + ); + + if (fileInfo.isDirectory()) { + return Response + .ok( + provider.listThemeFiles(themeName, ThemeVersion.DRAFT, path) + ) + .type(MediaType.APPLICATION_JSON) + .build(); + } else { + final InputStream inputStream = provider + .getThemeFileAsStream(themeName, ThemeVersion.DRAFT, path) + .orElseThrow( + () -> new NotFoundException( + String.format( + "File \"%s\" does not exist in theme %s.", + path, + themeName + ) + ) + ); + + return Response + .ok(inputStream) + .type(fileInfo.getMimeType()) + .build(); + } + } + + @PUT + @Path("/themes/{theme}/files/{path:.+}") + @AuthorizationRequired + @RequiresPrivilege(ThemingPrivileges.EDIT_THEME) + public Response createOrUpdateThemeFile( + @PathParam("theme") final String themeName, + @PathParam("path") final String path, + final byte[] data + ) { + final ThemeProvider provider = findProvider(themeName) + .orElseThrow( + () -> new NotFoundException( + String.format( + "Theme %s not found", themeName + ) + ) + ); + + final Optional fileInfo = provider + .getThemeFileInfo(themeName, ThemeVersion.DRAFT, "/"); + + if (fileInfo.isPresent() && fileInfo.get().isDirectory()) { + throw new BadRequestException( + String.format( + "File %s already exists in theme %s and is a directory.", + path, + themeName + ) + ); + } + + final OutputStream outputStream = provider.getOutputStreamForThemeFile( + themeName, path + ); + + try { + outputStream.write(data); + } catch (IOException ex) { + throw new WebApplicationException( + String.format( + "Failed to create/update file %s in theme %s.", + path, + themeName + ), + Response.Status.INTERNAL_SERVER_ERROR + ); + } + + return Response.ok().build(); + } + + @DELETE + @Path("/themes/{theme}/files/{path:.+}") + @AuthorizationRequired + @RequiresPrivilege(ThemingPrivileges.EDIT_THEME) + public Response deleteThemeFile( + @PathParam("theme") final String themeName, + @PathParam("path") final String path, + @QueryParam("recursive") final boolean recursive + ) { + final ThemeProvider provider = findProvider(themeName) + .orElseThrow(() -> new NotFoundException( + String.format( + "Theme \"%s\" does not exist.", themeName + ) + )); + + final ThemeFileInfo fileInfo = provider + .getThemeFileInfo(themeName, ThemeVersion.DRAFT, path) + .orElseThrow( + () -> new NotFoundException( + String.format( + "File \"%s\" does not exist in theme %s.", + path, + themeName + ) + ) + ); + + if (fileInfo.isDirectory()) { + final List files = provider + .listThemeFiles(themeName, ThemeVersion.DRAFT, path); + if (files.isEmpty()) { + provider.deleteThemeFile(themeName, path); + return Response.ok().build(); + } else if (recursive) { + for (final ThemeFileInfo file : files) { + provider.deleteThemeFile( + themeName, String.format("%s/%s", path, file.getName()) + ); + } + provider.deleteThemeFile(themeName, path); + return Response.ok().build(); + } else { + throw new BadRequestException( + String.format( + "Directory %s of theme %s is not empty.", + path, themeName + ) + ); + } + } else { + provider.deleteThemeFile(themeName, path); + return Response.ok().build(); + } + } + + @GET + @Path("/themes/{theme}/@download") + @Produces("application/zip") + @AuthorizationRequired + @RequiresPrivilege(ThemingPrivileges.EDIT_THEME) + public Response downloadTheme(final String themeName) { + final ThemeProvider provider = findProvider(themeName) + .orElseThrow( + () -> new NotFoundException( + String.format( + "Theme %s not found", themeName + ) + ) + ); + + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ZipOutputStream zos = new ZipOutputStream(baos)) { + addFilesInDirectoryToZip(provider, themeName, "/", zos); + + final byte[] result = baos.toByteArray(); + + return Response + .ok(result) + .build(); + } catch (IOException ex) { + throw new WebApplicationException( + String.format( + "Error zipping theme %s.", themeName + ), + ex, + Response.Status.INTERNAL_SERVER_ERROR + ); + } + } + + @POST + @Path("/themes/{theme}/@update") + @Consumes("application/zip") + @AuthorizationRequired + @RequiresPrivilege(ThemingPrivileges.EDIT_THEME) + public Response updateTheme( + final String themeName, final byte[] updatedTheme + ) { + final ThemeProvider provider = findProvider(themeName) + .orElseThrow( + () -> new NotFoundException( + String.format( + "Theme %s not found", themeName + ) + ) + ); + + // Read every file from ZIP + // Try to find file in theme + // Create or update file in theme + // remove files not in ZIP from theme + + throw new UnsupportedOperationException(); + } + + 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(); + } + + } + + 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(); + } + + private void addFilesInDirectoryToZip( + final ThemeProvider provider, + final String themeName, + final String directoryPath, + final ZipOutputStream zipOutputStream + ) throws IOException { + final List files = provider + .listThemeFiles(themeName, ThemeVersion.DRAFT, directoryPath + ); + for (ThemeFileInfo file : files) { + if (file.isDirectory()) { + final String dirPath = String.format( + "%s/%s", directoryPath, file.getName() + ); + final ZipEntry entry = new ZipEntry(dirPath); + zipOutputStream.putNextEntry(entry); + addFilesInDirectoryToZip( + provider, themeName, dirPath, zipOutputStream + ); + } else { + final String filePath = String.format( + "%s/%s", directoryPath, file.getName() + ); + final ZipEntry entry = new ZipEntry(filePath); + zipOutputStream.putNextEntry(entry); + + try (InputStream inputStream = getFileInputStream( + provider, themeName, filePath + )) { + byte[] buffer = new byte[1024]; + int length = inputStream.read(buffer); + while (length != -1) { + zipOutputStream.write(buffer); + length = inputStream.read(buffer); + } + } + zipOutputStream.closeEntry(); + } + } + } + + private InputStream getFileInputStream( + final ThemeProvider provider, final String themeName, + final String filePath + ) { + return provider + .getThemeFileAsStream(themeName, ThemeVersion.DRAFT, filePath) + .orElseThrow( + () -> new NotFoundException( + String.format( + "File %s not found in theme %s.", + filePath, + themeName + ) + ) + ); + } + +} diff --git a/ccm-core/src/main/java/org/libreccm/theming/manager/ThemeManager.java b/ccm-core/src/main/java/org/libreccm/api/themes/ThemesApi.java similarity index 75% rename from ccm-core/src/main/java/org/libreccm/theming/manager/ThemeManager.java rename to ccm-core/src/main/java/org/libreccm/api/themes/ThemesApi.java index a3d06ba1b..3ce7d7951 100644 --- a/ccm-core/src/main/java/org/libreccm/theming/manager/ThemeManager.java +++ b/ccm-core/src/main/java/org/libreccm/api/themes/ThemesApi.java @@ -16,7 +16,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ -package org.libreccm.theming.manager; +package org.libreccm.api.themes; + +import org.libreccm.api.CorsFilter; +import org.libreccm.api.DefaultResponseHeaders; +import org.libreccm.api.PreflightRequestFilter; import java.util.HashSet; import java.util.Set; @@ -26,19 +30,20 @@ import javax.ws.rs.core.Application; /** * JAX-RS application for managing themes. - * + * * @author Jens Pelzetter */ -@ApplicationPath("/thememanager") -public class ThemeManager extends Application { - +@ApplicationPath("/api/themes") +public class ThemesApi extends Application { + @Override public Set> getClasses() { - final Set> classes = new HashSet<>(); + classes.add(CorsFilter.class); + classes.add(DefaultResponseHeaders.class); + classes.add(PreflightRequestFilter.class); 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 deleted file mode 100644 index f5a948871..000000000 --- a/ccm-core/src/main/java/org/libreccm/theming/manager/Themes.java +++ /dev/null @@ -1,392 +0,0 @@ -/* - * 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.security.AuthorizationRequired; -import org.libreccm.security.RequiresPrivilege; -import org.libreccm.theming.ThemeFileInfo; -import org.libreccm.theming.ThemeInfo; -import org.libreccm.theming.ThemeProvider; -import org.libreccm.theming.ThemeVersion; -import org.libreccm.theming.ThemingPrivileges; - -import java.io.InputStream; -import java.io.InputStreamReader; -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.POST; -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; - -/** - * - * @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) - @AuthorizationRequired - @RequiresPrivilege(ThemingPrivileges.ADMINISTER_THEMES) - 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) - @AuthorizationRequired - @RequiresPrivilege(ThemingPrivileges.ADMINISTER_THEMES) - 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) - @AuthorizationRequired - @RequiresPrivilege(ThemingPrivileges.EDIT_THEME) - 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") - @AuthorizationRequired - @RequiresPrivilege(ThemingPrivileges.ADMINISTER_THEMES) - 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}") - @AuthorizationRequired - @RequiresPrivilege(ThemingPrivileges.ADMINISTER_THEMES) - public void deleteTheme(@PathParam("theme") final String themeName) { - - Objects.requireNonNull(themeName); - - 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); - } - } - - @GET - @Path("/themes/{theme}/files/") - @AuthorizationRequired - @RequiresPrivilege(ThemingPrivileges.ADMINISTER_THEMES) - public Response getThemeRootDir(@PathParam("theme") final String themeName) { - - final Optional provider = findProvider(themeName); - - if (provider.isPresent()) { - - final Optional fileInfo = provider - .get() - .getThemeFileInfo(themeName, ThemeVersion.DRAFT, "/"); - - if (fileInfo.isPresent()) { - - if (fileInfo.get().isDirectory()) { - - final List fileInfos = provider - .get() - .listThemeFiles(themeName, ThemeVersion.DRAFT, "/"); - - return Response - .ok(fileInfos) - .type(MediaType.APPLICATION_JSON) - .build(); - - } else { - - throw new WebApplicationException( - String.format( - "File \"/\" in theme %s is not a directory.", - themeName), - Response.Status.INTERNAL_SERVER_ERROR); - } - - } else { - return Response - .status(Response.Status.NOT_FOUND) - .entity(String.format( - "File \"/\" does not exist in theme %s.", - themeName)) - .build(); - } - - } else { - return Response - .status(Response.Status.NOT_FOUND) - .entity(String.format("Theme \"%s\" does not exist.", - themeName)) - .build(); - } - - } - - @GET - @Path("/themes/{theme}/files/{path:.+}") - @AuthorizationRequired - @RequiresPrivilege(ThemingPrivileges.ADMINISTER_THEMES) - public Response getThemeFile(@PathParam("theme") final String themeName, - @PathParam("path") final String path) { - - final Optional provider = findProvider(themeName); - - if (provider.isPresent()) { - - final Optional fileInfo = provider - .get() - .getThemeFileInfo(themeName, ThemeVersion.DRAFT, path); - - if (fileInfo.isPresent()) { - - final ThemeFileInfo themeFileInfo = fileInfo.get(); - - if (themeFileInfo.isDirectory()) { - - final List fileInfos = provider - .get() - .listThemeFiles(themeName, ThemeVersion.DRAFT, path); - - return Response - .ok(fileInfos) - .type(MediaType.APPLICATION_JSON) - .build(); - - } else { - final Optional inputStream = provider - .get() - .getThemeFileAsStream(themeName, - ThemeVersion.DRAFT, - path); - - if (inputStream.isPresent()) { - - final InputStream inStream = inputStream.get(); - return Response - .ok(inStream) - .type(themeFileInfo.getMimeType()) - .build(); - } else { - return Response - .status(Response.Status.NOT_FOUND) - .entity(String.format( - "File \"%s\" does not exist in theme %s.", - path, - themeName)) - .build(); - } - } - } else { - return Response - .status(Response.Status.NOT_FOUND) - .entity(String.format( - "File \"%s\" does not exist in theme %s.", - path, - themeName)) - .build(); - } - - } else { - return Response - .status(Response.Status.NOT_FOUND) - .entity(String.format("Theme \"%s\" does not exist.", - themeName)) - .build(); - } - } - - 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(); - } - - } - - 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(); - } - -}