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();
- }
-
-}