Skip to content

Commit

Permalink
Download important files xwikisas#8
Browse files Browse the repository at this point in the history
- Removed the download logs endpoint
- Added an endpoint for downloading a multiple files archive
- Added function for data providers to return info json
- Added script function to retrieve the context path
ChiuchiuSorin committed Sep 6, 2023
1 parent a2a79ba commit 1d56ff4
Showing 9 changed files with 219 additions and 54 deletions.
Original file line number Diff line number Diff line change
@@ -19,6 +19,8 @@
*/
package com.xwiki.admintools;

import java.util.Map;

import org.xwiki.component.annotation.Role;

/**
@@ -37,6 +39,13 @@ public interface DataProvider
*/
String provideData();

/**
* Provides the info structured in a json.
*
* @return Map containing the generated info.
*/
Map<String, String> generateJson();

/**
* Extract the hint of a component.
*
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@
package com.xwiki.admintools.rest;

import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
@@ -48,15 +49,27 @@ public interface AdminToolsResources extends XWikiRestComponent
@Path("/configs/{fileType}")
Response getConfigs(@PathParam("fileType") String type) throws XWikiRestException;

// /**
// * REST endpoint for accessing the logs archive download.
// *
// * @param from filter date, starting from.
// * @param to filter date, until.
// * @return Response with a configured header for zip download.
// * @throws XWikiRestException
// */
// @GET
// @Path("/logs")
// Response getLogs(@QueryParam("from") String from, @QueryParam("to") String to) throws XWikiRestException;

/**
* REST endpoint for accessing the logs archive download.
* Rest endpoint to download all selected files.
*
* @param from filter date, starting from.
* @param to filter date, until.
* @param from filter date, starting from given value.
* @param to filter date, until given value.
* @return Response with a configured header for zip download.
* @throws XWikiRestException
*/
@GET
@Path("/logs")
Response getLogs(@QueryParam("from") String from, @QueryParam("to") String to) throws XWikiRestException;
@POST
@Path("/all")
Response getFiles(@QueryParam("from") String from, @QueryParam("to") String to) throws XWikiRestException;
}
Original file line number Diff line number Diff line change
@@ -27,6 +27,8 @@

import org.xwiki.component.annotation.Component;

import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.web.XWikiRequest;
import com.xwiki.admintools.DataProvider;

/**
@@ -45,6 +47,9 @@ public class AdminToolsManager
@Inject
private Provider<List<DataProvider>> dataProviderProvider;

@Inject
private Provider<XWikiContext> xcontextProvider;

/**
* Merges all templates generated by the data providers.
*
@@ -79,4 +84,17 @@ public String generateData(String hint)
}
return null;
}

/**
* Get the context path for the current XWiki request.
*
* @return a String representing the xwiki context path.
*/
public String getContextPath()
{
XWikiContext xWikiContext = this.xcontextProvider.get();
XWikiRequest xWikiRequest = xWikiContext.getRequest();

return xWikiRequest.getContextPath();
}
}
Original file line number Diff line number Diff line change
@@ -57,6 +57,17 @@ public String getIdentifier()

@Override
public String provideData()
{
return getRenderedTemplate("data/configurationTemplate.vm", generateJson(), HINT);
}

/**
* Provides the info structured in a json.
*
* @return Map containing the generated info.
*/
@Override
public Map<String, String> generateJson()
{
usedServer.updatePaths();
Map<String, String> systemInfo = new HashMap<>();
@@ -65,7 +76,7 @@ public String provideData()
systemInfo.put("javaVersion", this.getJavaVersion());
systemInfo.put("osInfo", this.getOSInfo());

return getRenderedTemplate("data/configurationTemplate.vm", systemInfo, HINT);
return systemInfo;
}

/**
Original file line number Diff line number Diff line change
@@ -69,25 +69,18 @@ public class SecurityDataProvider extends AbstractDataProvider
@Override
public String provideData()
{
Map<String, String> securityDetails = this.getXwikiSecurityInfo();

securityDetails.putAll(getEnvironmentInfo());
Map<String, String> securityDetails = this.generateJson();

return getRenderedTemplate("data/securityTemplate.vm", securityDetails, HINT);
}

@Override
public String getIdentifier()
{
return HINT;
}

/**
* Get the security info of the current wiki.
* Provides the info structured in a json.
*
* @return xwiki security info.
* @return Map containing the generated info.
*/
private Map<String, String> getXwikiSecurityInfo()
@Override
public Map<String, String> generateJson()
{
Map<String, String> results = new HashMap<>();

@@ -98,10 +91,17 @@ private Map<String, String> getXwikiSecurityInfo()
results.put("activeEncoding", wiki.getEncoding());
results.put("configurationEncoding", configurationSource.getProperty("xwiki.encoding", String.class));
results.put("fileEncoding", System.getProperty("file.encoding"));
results.putAll(getEnvironmentInfo());

return results;
}

@Override
public String getIdentifier()
{
return HINT;
}

/**
* Get the security info regarding the environment.
*
Original file line number Diff line number Diff line change
@@ -107,16 +107,17 @@ private boolean checkFilters(Map<String, String> filters, Pattern pattern, File
String toDateFilterKey = "to";
String fileDateString = matcher.group();
LocalDate fileDate = LocalDate.parse(fileDateString);

if (filters.get(fromDateFilterKey) != null && filters.get(toDateFilterKey) != null) {
LocalDate fromDate = LocalDate.parse(filters.get(fromDateFilterKey));
LocalDate toDate = LocalDate.parse(filters.get(toDateFilterKey));
return fileDate.isAfter(fromDate) && fileDate.isBefore(toDate);
return fileDate.isAfter(fromDate.minusDays(1)) && fileDate.isBefore(toDate.plusDays(1));
} else if (filters.get(fromDateFilterKey) != null) {
LocalDate fromDate = LocalDate.parse(filters.get(fromDateFilterKey));
return fileDate.isAfter(fromDate);
return fileDate.isAfter(fromDate.minusDays(1));
} else if (filters.get(toDateFilterKey) != null) {
LocalDate toDate = LocalDate.parse(filters.get(toDateFilterKey));
return fileDate.isBefore(toDate);
return fileDate.isBefore(toDate.plusDays(1));
} else {
return true;
}
Original file line number Diff line number Diff line change
@@ -20,19 +20,26 @@
package com.xwiki.admintools.internal.downloads;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;

import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.xwiki.component.annotation.Component;
import org.xwiki.component.phase.Initializable;
import org.xwiki.component.phase.InitializationException;
@@ -42,7 +49,10 @@
import org.xwiki.security.authorization.Right;

import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.web.XWikiRequest;
import com.xwiki.admintools.DataProvider;
import com.xwiki.admintools.LogsDownloader;
import com.xwiki.admintools.internal.data.ConfigurationDataProvider;
import com.xwiki.admintools.internal.data.identifiers.CurrentServer;

/**
@@ -55,8 +65,12 @@
@Singleton
public class DownloadsManager implements Initializable
{
private final String config = "config";

private final String properties = "properties";

@Inject
protected Provider<XWikiContext> xcontextProvider;
private Provider<XWikiContext> xcontextProvider;

@Inject
private CurrentServer currentServer;
@@ -70,10 +84,17 @@ public class DownloadsManager implements Initializable
@Inject
private Provider<List<LogsDownloader>> filesDownloader;

@Inject
@Named(ConfigurationDataProvider.HINT)
private DataProvider configurationDataProvider;

private String serverPath;

private String serverType;

@Inject
private Logger logger;

/**
* Initializes variables with the server type and the path to the server.
*
@@ -94,7 +115,7 @@ public void initialize() throws InitializationException
* @return filtered file content as a byte array
* @throws IOException
*/
public byte[] downloadXWikiFile(String fileType) throws IOException
public byte[] getXWikiFile(String fileType) throws IOException
{
return prepareFile(fileType);
}
@@ -112,14 +133,84 @@ public boolean isAdmin()
return this.authorizationManager.hasAccess(Right.ADMIN, user, wikiReference);
}

/**
* Retrieve the selected files from the request and create an archive containing them.
*
* @return byte array representing the files archive.
*/
public byte[] downloadMultipleFiles()
{
XWikiContext wikiContext = xcontextProvider.get();
XWikiRequest xWikiRequest = wikiContext.getRequest();
Map<String, String[]> files = xWikiRequest.getParameterMap();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

try (ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream)) {
createArchiveEntries(files, zipOutputStream);
zipOutputStream.flush();
byteArrayOutputStream.flush();
zipOutputStream.close();
byteArrayOutputStream.close();
return byteArrayOutputStream.toByteArray();
} catch (Exception e) {
logger.warn("Failed to download logs. Root cause is: [{}]", ExceptionUtils.getRootCauseMessage(e));
return null;
}
}

private void createArchiveEntries(Map<String, String[]> files, ZipOutputStream zipOutputStream) throws IOException
{
ZipEntry zipEntry;
byte[] buffer;
for (String fileType : files.get("files")) {
switch (fileType) {
case "cfg_file":
zipEntry = new ZipEntry("xwiki.cfg");
zipOutputStream.putNextEntry(zipEntry);
buffer = prepareFile(config);
zipOutputStream.write(buffer, 0, buffer.length);
zipOutputStream.closeEntry();
break;
case "properties_file":
zipEntry = new ZipEntry("xwiki.properties");
zipOutputStream.putNextEntry(zipEntry);
buffer = prepareFile(properties);
zipOutputStream.write(buffer, 0, buffer.length);
zipOutputStream.closeEntry();
break;
case "logs":
zipEntry = new ZipEntry("logs.zip");
zipOutputStream.putNextEntry(zipEntry);
Map<String, String> filters = new HashMap<>();
String from = "from";
String to = "to";
filters.put(from, !Objects.equals(files.get(from)[0], "") ? files.get(from)[0] : null);
filters.put(to, !Objects.equals(files.get(to)[0], "") ? files.get(to)[0] : null);
buffer = getLogs(filters);
zipOutputStream.write(buffer, 0, buffer.length);
zipOutputStream.closeEntry();
break;
case "configuration_info":
zipEntry = new ZipEntry("configuration_json.txt");
zipOutputStream.putNextEntry(zipEntry);
buffer = configurationDataProvider.generateJson().toString().getBytes();
zipOutputStream.write(buffer, 0, buffer.length);
zipOutputStream.closeEntry();
break;
default:
break;
}
}
}

/**
* Initiates the download process for the server logs. Taking into consideration the used server, it identifies the
* right downloader. It returns null if none is corresponding.
*
* @param filters Map that can contain the start and end date of the search. It can also be empty.
* @return byte array representing the logs archive.
*/
public byte[] downloadLogs(Map<String, String> filters)
private byte[] getLogs(Map<String, String> filters)
{
return callLogsDownloader(serverType + "Logs", filters);
}
@@ -136,9 +227,9 @@ public byte[] downloadLogs(Map<String, String> filters)
private byte[] prepareFile(String type) throws IOException
{
String filePath = serverPath;
if (Objects.equals(type, "properties")) {
if (Objects.equals(type, properties)) {
filePath += "/webapps/xwiki/WEB-INF/xwiki.properties";
} else {
} else if (Objects.equals(type, config)) {
filePath += "/webapps/xwiki/WEB-INF/xwiki.cfg";
}
File inputFile = new File(filePath);
Loading

0 comments on commit 1d56ff4

Please sign in to comment.