Extended RESTful API for theme management

Former-commit-id: 3ef46aaf51
restapi
Jens Pelzetter 2020-08-07 17:33:41 +02:00
parent 30cd9bae25
commit de29bb6a3a
3 changed files with 608 additions and 400 deletions

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@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<ThemeProvider> providers;
@GET
@Path("/providers")
@Produces(MediaType.APPLICATION_JSON)
@AuthorizationRequired
@RequiresPrivilege(ThemingPrivileges.ADMINISTER_THEMES)
public List<String> 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<ThemeInfo> 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<ThemeProvider> providerClass;
try {
providerClass = (Class<ThemeProvider>) 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<ThemeFileInfo> 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<ThemeFileInfo> 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<ThemeProvider> findProvider(final String forTheme) {
final List<ThemeProvider> 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<ThemeFileInfo> 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
)
)
);
}
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@ApplicationPath("/thememanager")
public class ThemeManager extends Application {
@ApplicationPath("/api/themes")
public class ThemesApi extends Application {
@Override
public Set<Class<?>> getClasses() {
final Set<Class<?>> classes = new HashSet<>();
classes.add(CorsFilter.class);
classes.add(DefaultResponseHeaders.class);
classes.add(PreflightRequestFilter.class);
classes.add(Themes.class);
return classes;
}
}

View File

@ -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 <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
*/
@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<ThemeProvider> providers;
@Inject
private Themes themes;
@GET
@Path("/providers")
@Produces(MediaType.APPLICATION_JSON)
@AuthorizationRequired
@RequiresPrivilege(ThemingPrivileges.ADMINISTER_THEMES)
public String getThemeProviders() {
final List<ThemeProvider> 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<ThemeInfo> getAvailableThemes() {
final List<ThemeInfo> 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<ThemeProvider> providerClass;
try {
providerClass = (Class<ThemeProvider>) 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<ThemeProvider> 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<ThemeProvider> 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<ThemeProvider> 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<ThemeProvider> provider = findProvider(themeName);
if (provider.isPresent()) {
final Optional<ThemeFileInfo> fileInfo = provider
.get()
.getThemeFileInfo(themeName, ThemeVersion.DRAFT, "/");
if (fileInfo.isPresent()) {
if (fileInfo.get().isDirectory()) {
final List<ThemeFileInfo> 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<ThemeProvider> provider = findProvider(themeName);
if (provider.isPresent()) {
final Optional<ThemeFileInfo> fileInfo = provider
.get()
.getThemeFileInfo(themeName, ThemeVersion.DRAFT, path);
if (fileInfo.isPresent()) {
final ThemeFileInfo themeFileInfo = fileInfo.get();
if (themeFileInfo.isDirectory()) {
final List<ThemeFileInfo> fileInfos = provider
.get()
.listThemeFiles(themeName, ThemeVersion.DRAFT, path);
return Response
.ok(fileInfos)
.type(MediaType.APPLICATION_JSON)
.build();
} else {
final Optional<InputStream> 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<ThemeProvider> findProvider(final String forTheme) {
final List<ThemeProvider> providersList = new ArrayList<>();
providers
.forEach(provider -> providersList.add(provider));
return providersList
.stream()
.filter(current -> current.providesTheme(forTheme,
ThemeVersion.DRAFT))
.findAny();
}
}