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
Former-commit-id: db9e9b9cfd
pull/2/head
parent
69d3f449e2
commit
d4e9a5f27f
|
|
@ -44,7 +44,6 @@ import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.nio.file.StandardCopyOption;
|
import java.nio.file.StandardCopyOption;
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.rmi.UnexpectedException;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
@ -234,14 +233,16 @@ public class NIOFileSystemAdapter implements FileSystemAdapter {
|
||||||
final String targetPath,
|
final String targetPath,
|
||||||
boolean recursive) throws FileAccessException {
|
boolean recursive) throws FileAccessException {
|
||||||
|
|
||||||
final Path nioSourcePath = Paths.get(sourcePath);
|
final Path nioSourcePath = Paths
|
||||||
final Path nioTargetPath = Paths.get(targetPath);
|
.get(String.join("/", dataPath, sourcePath));
|
||||||
|
final Path nioTargetPath = Paths
|
||||||
|
.get(String.join("/", dataPath, targetPath));
|
||||||
|
|
||||||
if (recursive) {
|
if (recursive) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Files.walkFileTree(
|
Files.walkFileTree(
|
||||||
nioTargetPath,
|
nioSourcePath,
|
||||||
new FileVisitor<Path>() {
|
new FileVisitor<Path>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -262,7 +263,7 @@ public class NIOFileSystemAdapter implements FileSystemAdapter {
|
||||||
file,
|
file,
|
||||||
nioTargetPath
|
nioTargetPath
|
||||||
.resolve(nioSourcePath.relativize(file)),
|
.resolve(nioSourcePath.relativize(file)),
|
||||||
StandardCopyOption.ATOMIC_MOVE,
|
// StandardCopyOption.ATOMIC_MOVE,
|
||||||
StandardCopyOption.COPY_ATTRIBUTES,
|
StandardCopyOption.COPY_ATTRIBUTES,
|
||||||
StandardCopyOption.REPLACE_EXISTING,
|
StandardCopyOption.REPLACE_EXISTING,
|
||||||
LinkOption.NOFOLLOW_LINKS);
|
LinkOption.NOFOLLOW_LINKS);
|
||||||
|
|
@ -311,7 +312,7 @@ public class NIOFileSystemAdapter implements FileSystemAdapter {
|
||||||
try {
|
try {
|
||||||
Files.copy(nioSourcePath,
|
Files.copy(nioSourcePath,
|
||||||
nioTargetPath,
|
nioTargetPath,
|
||||||
StandardCopyOption.ATOMIC_MOVE,
|
// StandardCopyOption.ATOMIC_MOVE,
|
||||||
StandardCopyOption.COPY_ATTRIBUTES,
|
StandardCopyOption.COPY_ATTRIBUTES,
|
||||||
StandardCopyOption.REPLACE_EXISTING,
|
StandardCopyOption.REPLACE_EXISTING,
|
||||||
LinkOption.NOFOLLOW_LINKS);
|
LinkOption.NOFOLLOW_LINKS);
|
||||||
|
|
@ -325,14 +326,16 @@ public class NIOFileSystemAdapter implements FileSystemAdapter {
|
||||||
public void move(final String sourcePath, final String targetPath)
|
public void move(final String sourcePath, final String targetPath)
|
||||||
throws FileAccessException {
|
throws FileAccessException {
|
||||||
|
|
||||||
final Path nioSourcePath = Paths.get(sourcePath);
|
final Path nioSourcePath = Paths.get(
|
||||||
final Path nioTargetPath = Paths.get(targetPath);
|
String.join("/", dataPath, sourcePath));
|
||||||
|
final Path nioTargetPath = Paths.get(
|
||||||
|
String.join("/", dataPath, targetPath));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Files.move(nioSourcePath,
|
Files.move(nioSourcePath,
|
||||||
nioTargetPath,
|
nioTargetPath,
|
||||||
StandardCopyOption.ATOMIC_MOVE,
|
StandardCopyOption.ATOMIC_MOVE,
|
||||||
StandardCopyOption.COPY_ATTRIBUTES,
|
// StandardCopyOption.COPY_ATTRIBUTES,
|
||||||
StandardCopyOption.REPLACE_EXISTING,
|
StandardCopyOption.REPLACE_EXISTING,
|
||||||
LinkOption.NOFOLLOW_LINKS);
|
LinkOption.NOFOLLOW_LINKS);
|
||||||
} catch(IOException ex) {
|
} catch(IOException ex) {
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,8 @@ public class FileSystemThemeProvider implements ThemeProvider {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private static final String BASE_PATH = "/themes";
|
private static final String BASE_PATH = "/themes";
|
||||||
private static final String DRAFT_THEMES_PATH = "/themes" + "/draft";
|
private static final String DRAFT_THEMES_PATH = BASE_PATH + "/draft";
|
||||||
private static final String LIVE_THEMES_PATH = "/themes" + "/live";
|
private static final String LIVE_THEMES_PATH = BASE_PATH + "/live";
|
||||||
|
|
||||||
private static final String THEME_JSON = "%s/theme.json";
|
private static final String THEME_JSON = "%s/theme.json";
|
||||||
private static final String THEME_XML = "%s/theme.xml";
|
private static final String THEME_XML = "%s/theme.xml";
|
||||||
|
|
@ -320,20 +320,50 @@ public class FileSystemThemeProvider implements ThemeProvider {
|
||||||
ThemeVersion.DRAFT);
|
ThemeVersion.DRAFT);
|
||||||
final String liveThemePath = createThemePath(theme,
|
final String liveThemePath = createThemePath(theme,
|
||||||
ThemeVersion.LIVE);
|
ThemeVersion.LIVE);
|
||||||
final String liveThemePathTmp = String.format("%_tmp", liveThemePath);
|
final String liveThemePathTmp = String.format("%s_tmp", liveThemePath);
|
||||||
|
|
||||||
try {
|
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);
|
ccmFiles.copyFile(draftThemePath, liveThemePathTmp, true);
|
||||||
if (ccmFiles.existsFile(liveThemePath)) {
|
if (ccmFiles.existsFile(liveThemePath)) {
|
||||||
ccmFiles.deleteFile(liveThemePath, true);
|
ccmFiles.deleteFile(liveThemePath, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
ccmFiles.moveFile(liveThemePathTmp, liveThemePath);
|
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
|
} catch (DirectoryNotEmptyException
|
||||||
| FileAccessException
|
| FileAccessException
|
||||||
| FileDoesNotExistException
|
| FileDoesNotExistException
|
||||||
| InsufficientPermissionsException ex) {
|
| InsufficientPermissionsException ex) {
|
||||||
throw new UnexpectedErrorException();
|
throw new UnexpectedErrorException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -357,15 +387,19 @@ public class FileSystemThemeProvider implements ThemeProvider {
|
||||||
|
|
||||||
final ThemeManifest manifest;
|
final ThemeManifest manifest;
|
||||||
try {
|
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");
|
manifest = manifestUtil.loadManifest(inputStream, "theme.json");
|
||||||
} else if (ccmFiles.existsFile(String.format(THEME_XML,
|
} else if (ccmFiles.existsFile(xmlPath)) {
|
||||||
themePath))) {
|
final InputStream inputStream = ccmFiles
|
||||||
|
.createInputStream(xmlPath);
|
||||||
manifest = manifestUtil.loadManifest(inputStream, "theme.xml");
|
manifest = manifestUtil.loadManifest(inputStream, "theme.xml");
|
||||||
} else {
|
} else {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
|
|
|
||||||
|
|
@ -391,6 +391,11 @@ public class StaticThemeProvider implements ThemeProvider {
|
||||||
//No op in this implementation.
|
//No op in this implementation.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unpublishTheme(final String theme) {
|
||||||
|
//No op in this implementation.
|
||||||
|
}
|
||||||
|
|
||||||
private URI getJarUri() {
|
private URI getJarUri() {
|
||||||
|
|
||||||
LOGGER.debug("Getting URI of JAR...");
|
LOGGER.debug("Getting URI of JAR...");
|
||||||
|
|
|
||||||
|
|
@ -209,4 +209,13 @@ public interface ThemeProvider extends Serializable {
|
||||||
*/
|
*/
|
||||||
void publishTheme(String theme);
|
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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -326,6 +326,14 @@ public class DatabaseThemeProvider implements ThemeProvider {
|
||||||
.ifPresent(themeManager::publishTheme);
|
.ifPresent(themeManager::publishTheme);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unpublishTheme(final String themeName) {
|
||||||
|
|
||||||
|
themeRepository
|
||||||
|
.findThemeByName(themeName, ThemeVersion.LIVE)
|
||||||
|
.ifPresent(themeManager::unpublishTheme);
|
||||||
|
}
|
||||||
|
|
||||||
private ThemeInfo createThemeInfo(final Theme theme) {
|
private ThemeInfo createThemeInfo(final Theme theme) {
|
||||||
|
|
||||||
Objects.requireNonNull(theme);
|
Objects.requireNonNull(theme);
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,11 @@ package org.libreccm.theming.manager;
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.libreccm.security.RequiresPrivilege;
|
||||||
import org.libreccm.theming.ThemeInfo;
|
import org.libreccm.theming.ThemeInfo;
|
||||||
import org.libreccm.theming.ThemeProvider;
|
import org.libreccm.theming.ThemeProvider;
|
||||||
import org.libreccm.theming.ThemeVersion;
|
import org.libreccm.theming.ThemeVersion;
|
||||||
|
import org.libreccm.theming.ThemingPrivileges;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
|
|
@ -40,6 +42,7 @@ import javax.json.JsonArrayBuilder;
|
||||||
import javax.json.JsonWriter;
|
import javax.json.JsonWriter;
|
||||||
import javax.ws.rs.DELETE;
|
import javax.ws.rs.DELETE;
|
||||||
import javax.ws.rs.GET;
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.POST;
|
||||||
import javax.ws.rs.PUT;
|
import javax.ws.rs.PUT;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.PathParam;
|
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.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
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
|
@GET
|
||||||
@Path("/providers")
|
@Path("/providers")
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
//@AuthorizationRequired
|
||||||
|
@RequiresPrivilege(ThemingPrivileges.ADMINISTER_THEMES)
|
||||||
public String getThemeProviders() {
|
public String getThemeProviders() {
|
||||||
|
|
||||||
final List<ThemeProvider> providersList = new ArrayList<>();
|
final List<ThemeProvider> providersList = new ArrayList<>();
|
||||||
|
|
@ -100,6 +103,8 @@ public class Themes implements Serializable {
|
||||||
@GET
|
@GET
|
||||||
@Path("/themes")
|
@Path("/themes")
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
//@AuthorizationRequired
|
||||||
|
@RequiresPrivilege(ThemingPrivileges.ADMINISTER_THEMES)
|
||||||
public List<ThemeInfo> getAvailableThemes() {
|
public List<ThemeInfo> getAvailableThemes() {
|
||||||
|
|
||||||
final List<ThemeInfo> availableThemes = new ArrayList<>();
|
final List<ThemeInfo> availableThemes = new ArrayList<>();
|
||||||
|
|
@ -115,6 +120,8 @@ public class Themes implements Serializable {
|
||||||
@GET
|
@GET
|
||||||
@Path("/themes/{theme}")
|
@Path("/themes/{theme}")
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
//@AuthorizationRequired
|
||||||
|
@RequiresPrivilege(ThemingPrivileges.EDIT_THEME)
|
||||||
public ThemeInfo getTheme(@PathParam("theme") final String themeName) {
|
public ThemeInfo getTheme(@PathParam("theme") final String themeName) {
|
||||||
|
|
||||||
for (final ThemeProvider provider : providers) {
|
for (final ThemeProvider provider : providers) {
|
||||||
|
|
@ -133,6 +140,8 @@ public class Themes implements Serializable {
|
||||||
@Path("/themes/{theme}")
|
@Path("/themes/{theme}")
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
//@AuthorizationRequired
|
||||||
|
@RequiresPrivilege(ThemingPrivileges.ADMINISTER_THEMES)
|
||||||
public ThemeInfo createTheme(
|
public ThemeInfo createTheme(
|
||||||
@PathParam("theme") final String themeName,
|
@PathParam("theme") final String themeName,
|
||||||
@QueryParam("provider") final String providerName) {
|
@QueryParam("provider") final String providerName) {
|
||||||
|
|
@ -167,19 +176,13 @@ public class Themes implements Serializable {
|
||||||
|
|
||||||
@DELETE
|
@DELETE
|
||||||
@Path("/themes/{theme}")
|
@Path("/themes/{theme}")
|
||||||
|
//@AuthorizationRequired
|
||||||
|
@RequiresPrivilege(ThemingPrivileges.ADMINISTER_THEMES)
|
||||||
public void deleteTheme(@PathParam("theme") final String themeName) {
|
public void deleteTheme(@PathParam("theme") final String themeName) {
|
||||||
|
|
||||||
Objects.requireNonNull(themeName);
|
Objects.requireNonNull(themeName);
|
||||||
|
|
||||||
final List<ThemeProvider> providersList = new ArrayList<>();
|
final Optional<ThemeProvider> provider = findProvider(themeName);
|
||||||
providers
|
|
||||||
.forEach(provider -> providersList.add(provider));
|
|
||||||
|
|
||||||
final Optional<ThemeProvider> provider = providersList
|
|
||||||
.stream()
|
|
||||||
.filter(current -> current.providesTheme(themeName,
|
|
||||||
ThemeVersion.DRAFT))
|
|
||||||
.findAny();
|
|
||||||
|
|
||||||
if (provider.isPresent()) {
|
if (provider.isPresent()) {
|
||||||
|
|
||||||
|
|
@ -190,6 +193,42 @@ public class Themes implements Serializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private String getProviderName(final ThemeProvider provider) {
|
private String getProviderName(final ThemeProvider provider) {
|
||||||
|
|
||||||
if (provider
|
if (provider
|
||||||
|
|
@ -207,4 +246,17 @@ public class Themes implements Serializable {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue