Update a theme by uploading a ZIP file

Jens Pelzetter 2020-08-09 12:33:58 +02:00
parent 589ca1a2c6
commit 413a6ab150
1 changed files with 138 additions and 7 deletions

View File

@ -20,6 +20,8 @@ package org.libreccm.api.themes;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.hibernate.engine.jdbc.internal.BinaryStreamImpl;
import org.libreccm.core.UnexpectedErrorException;
import org.libreccm.security.AuthorizationRequired;
import org.libreccm.security.RequiresPrivilege;
import org.libreccm.theming.ThemeFileInfo;
@ -28,17 +30,27 @@ import org.libreccm.theming.ThemeProvider;
import org.libreccm.theming.ThemeVersion;
import org.libreccm.theming.ThemingPrivileges;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.rmi.UnexpectedException;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import javax.enterprise.context.RequestScoped;
@ -497,12 +509,85 @@ public class Themes implements Serializable {
)
);
// Read every file from ZIP
// Try to find file in theme
// Create or update file in theme
// remove files not in ZIP from theme
final Set<String> pathsInTheme = createThemeFilesSet(
provider, themeName
);
throw new UnsupportedOperationException();
try (
ByteArrayInputStream bais = new ByteArrayInputStream(updatedTheme);
ZipInputStream zis = new ZipInputStream(bais)) {
ZipEntry entry = zis.getNextEntry();
while (entry != null) {
final String path = entry.getName();
entry = zis.getNextEntry();
if (pathsInTheme.contains(path)) {
final ByteArrayOutputStream zipBaos
= new ByteArrayOutputStream();
byte[] zipBuffer = new byte[1024];
int zipRead = zis.read(zipBuffer, 0, 1024);
while (zipRead != -1) {
zipBaos.writeBytes(zipBuffer);
zipRead = zis.read(zipBuffer, 0, 1024);
}
final byte[] bytesFromZip = zipBaos.toByteArray();
final InputStream inputStream = provider
.getThemeFileAsStream(
themeName, ThemeVersion.DRAFT, path
)
.orElseThrow(() -> new UnexpectedErrorException());
final ByteArrayOutputStream themeBaos
= new ByteArrayOutputStream();
byte[] themeBuffer = new byte[1024];
int themeRead = inputStream.read(themeBuffer);
while (themeRead != -1) {
themeBaos.writeBytes(zipBuffer);
themeRead = inputStream.read(themeBuffer);
}
final byte[] bytesFromTheme = themeBaos.toByteArray();
final byte[] fromZipChecksum = MessageDigest
.getInstance("SHA-256")
.digest(bytesFromZip);
final byte[] fromThemeChecksum = MessageDigest
.getInstance("SHA-256")
.digest(bytesFromTheme);
if (!MessageDigest.isEqual(
fromZipChecksum, fromThemeChecksum
)) {
try(OutputStream outputStream = provider
.getOutputStreamForThemeFile(themeName, path)) {
outputStream.write(bytesFromZip);
}
}
} else {
copyFileFromZipToTheme(
zis,
provider,
themeName,
path
);
}
}
for (final String path : pathsInTheme) {
provider.deleteThemeFile(themeName, path);
}
} catch (IOException ex) {
throw new UnexpectedErrorException(
String.format("Failed to update theme %s", themeName),
ex
);
} catch (NoSuchAlgorithmException ex) {
throw new UnexpectedErrorException(
"Message digest SHA-256 is not available.", ex
);
}
return Response.ok().build();
}
private String getProviderName(final ThemeProvider provider) {
@ -592,4 +677,50 @@ public class Themes implements Serializable {
);
}
private SortedSet<String> createThemeFilesSet(
final ThemeProvider provider, final String themeName
) {
return createThemeFilesSet(provider, themeName, "/");
}
private SortedSet<String> createThemeFilesSet(
final ThemeProvider provider,
final String themeName,
final String currentPath
) {
final SortedSet<String> files = new TreeSet<>();
final List<ThemeFileInfo> filesInfo = provider
.listThemeFiles(themeName, ThemeVersion.DRAFT, currentPath);
for (final ThemeFileInfo fileInfo : filesInfo) {
final String filePath = String.format(
"%s/%s", currentPath, fileInfo.getName()
);
files.add(filePath);
if (fileInfo.isDirectory()) {
final Set<String> subFiles = createThemeFilesSet(
provider, themeName, filePath);
files.addAll(subFiles);
}
}
return files;
}
private void copyFileFromZipToTheme(
final ZipInputStream zis,
final ThemeProvider themeProvider,
final String themeName,
final String path
) throws IOException {
try (OutputStream outputStream = themeProvider
.getOutputStreamForThemeFile(themeName, path)) {
final byte[] buffer = new byte[1024];
int read = zis.read(buffer, 0, 1024);
while (read != -1) {
outputStream.write(buffer);
read = zis.read(buffer, 0, 1024);
}
}
}
}