Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[POC] Integrate the Datahub application in GeoNetwork web app #8192

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,7 @@ web/src/main/webapp/data/
web/src/main/webapp/doc/en
web/src/main/webapp/doc/fr
web/src/main/webapp/WEB-INF/data/data/resources/schemapublication

# geonetwork-ui git project
web/src/main/geonetwork-ui/
web/node/
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@ public class Settings {

public static final String MICROSERVICES_ENABLED = "microservices/enabled";

public static final String GEONETWORK_UI_DATAHUB_CONFIGURATION = "geonetwork-ui/datahub/configuration";
public static final String GEONETWORK_UI_DATAHUB_ENABLED = "geonetwork-ui/datahub/enabled";

public static class GNSetting {
private String name;
private boolean nullable;
Expand Down
159 changes: 159 additions & 0 deletions core/src/main/java/org/fao/geonet/web/DatahubFilter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
package org.fao.geonet.web;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpHeaders;
import org.apache.log4j.Logger;
import org.fao.geonet.ApplicationContextHolder;
import org.fao.geonet.NodeInfo;
import org.fao.geonet.domain.Source;
import org.fao.geonet.domain.SourceType;
import org.fao.geonet.kernel.setting.SettingManager;
import org.fao.geonet.kernel.setting.Settings;
import org.fao.geonet.repository.SourceRepository;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.zip.GZIPOutputStream;

public class DatahubFilter implements Filter {
private static final Logger log = Logger.getLogger(DatahubFilter.class);

@Override
public void init(FilterConfig config) {
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
ServletContext context = req.getServletContext();

String reqPath = req.getPathInfo();
if (reqPath == null || !reqPath.matches("^/[a-zA-Z0-9_\\-]+/datahub.*")) {
chain.doFilter(request, res);
return;
}

String isDatahubEnabled = getSettingManager().getValue(Settings.GEONETWORK_UI_DATAHUB_ENABLED);
if (!isDatahubEnabled.equals("true")) {
res.setStatus(404);
return;
}

// a req path will be "/srv/datahub/bla/bla"
String[] parts = reqPath.split("/");
String portalName = parts[1]; // element at i=0 is empty

SourceRepository sourceRepository = getSourceRepository();
Boolean datahubEnabled = false;
if (NodeInfo.DEFAULT_NODE.equals(portalName)) {
datahubEnabled = getSettingManager().getValue(Settings.GEONETWORK_UI_DATAHUB_ENABLED).equals("true");
} else if (sourceRepository.existsByUuidAndType(portalName, SourceType.subportal)) {
datahubEnabled = sourceRepository.findOneByUuid(portalName).getDatahubEnabled();
}

if (!datahubEnabled) {
res.setStatus(404);
return;
}

String filePath = Stream.of(parts).skip(2).collect(Collectors.joining("/"));
File actualFile = new File(context.getRealPath("/" + filePath));

// fallback to index.html if the file doesn't exist
if (!actualFile.exists()) {
actualFile = new File(context.getRealPath("/datahub/index.html"));

// disable cache only for index.html
res.setHeader(HttpHeaders.CACHE_CONTROL, "no-cache");
res.setHeader(HttpHeaders.PRAGMA, "no-cache");
res.setHeader(HttpHeaders.EXPIRES, "0");
}

res.setStatus(200);
String extension = FilenameUtils.getExtension(actualFile.getName()).toLowerCase();
String contentType;
if (extension.equals("js")) {
contentType = "text/javascript; charset=UTF-8";
} else {
contentType = Files.probeContentType(actualFile.toPath());
}
res.setContentType(contentType);

InputStream inStream;

// the config is read from the settings
if (actualFile.getName().equals("default.toml")) {
inStream = readConfiguration(portalName);
} else {
inStream = new FileInputStream(actualFile);
}
OutputStream outStream = res.getOutputStream();

// handle gzip compression
if(req.getHeader(HttpHeaders.ACCEPT_ENCODING).contains("gzip")) {
res.setHeader(HttpHeaders.CONTENT_ENCODING, "gzip");
outStream = new GZIPOutputStream(outStream);
}

IOUtils.copy(inStream, outStream);
outStream.close();
}

private InputStream readConfiguration(String portalName) {
String configuration = getSettingManager().getValue(Settings.GEONETWORK_UI_DATAHUB_CONFIGURATION);

if (!portalName.equals(NodeInfo.DEFAULT_NODE)) {
Source portal = getSourceRepository().findOneByUuid(portalName);
if (portal != null && !portal.getDatahubConfiguration().isEmpty()) {
configuration = portal.getDatahubConfiguration();
}
}

/*TomlParseResult toml = Toml.parse(configuration);
Map<String, Object> tomlMap = toml.toMap();

// Force the "gn4_api_url" field to a value including the portal name
if (!tomlMap.containsKey("global")) {
tomlMap.put("global", Map.of());
}
Map<String, String> globalSection = (Map<String, String>) tomlMap.get("global");
globalSection.put("geonetwork4_api_url", "/geonetwork/" + portalName + "/api");

TomlWriter tomlWriter = new TomlWriter();
configuration = tomlWriter.write(tomlMap);*/

// remove url & add new one
configuration = configuration.replaceAll("\ngeonetwork4_api_url\\s?=.+", "\n")
.replace("[global]", "[global]\ngeonetwork4_api_url = \"/geonetwork/" + portalName + "/api\"");
return new ByteArrayInputStream(configuration.getBytes());
}

@Override
public void destroy() {
}

private SettingManager getSettingManager() {
return ApplicationContextHolder.get().getBean(SettingManager.class);
}
private SourceRepository getSourceRepository() {
return ApplicationContextHolder.get().getBean(SourceRepository.class);
}
}
27 changes: 27 additions & 0 deletions domain/src/main/java/org/fao/geonet/domain/Source.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.fao.geonet.domain.converter.BooleanToYNConverter;
import org.fao.geonet.entitylistener.SourceEntityListenerManager;
import org.fao.geonet.repository.LanguageRepository;
import org.hibernate.annotations.Type;

import javax.annotation.Nonnull;
import javax.persistence.*;
Expand Down Expand Up @@ -64,6 +65,9 @@ public class Source extends Localized {
private Integer groupOwner;
private Boolean listableInHeaderSelector = true;

private Boolean datahubEnabled = false;
private String datahubConfiguration = ""; // will use the main conf if empty

/**
* Default constructor. Required by framework.
*/
Expand Down Expand Up @@ -224,6 +228,29 @@ public Source setUiConfig(String uiConfig) {
return this;
}

/**
* Only applies to subportal.
*
* @return
*/
public Boolean getDatahubEnabled() {
return datahubEnabled;
}
public Source setDatahubEnabled(Boolean datahubEnabled) {
this.datahubEnabled = datahubEnabled;
return this;
}

@Lob
@Type(type = "org.hibernate.type.TextType")
public String getDatahubConfiguration() {
return datahubConfiguration;
}
public Source setDatahubConfiguration(String datahubConfiguration) {
this.datahubConfiguration = datahubConfiguration;
return this;
}


/**
* Get the date that the source was created.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,8 @@ private void updateSource(String sourceIdentifier,
entity.setGroupOwner(source.getGroupOwner());
entity.setServiceRecord(source.getServiceRecord());
entity.setUiConfig(source.getUiConfig());
entity.setDatahubEnabled(source.getDatahubEnabled());
entity.setDatahubConfiguration(source.getDatahubConfiguration());
entity.setLogo(source.getLogo());
entity.setListableInHeaderSelector(source.isListableInHeaderSelector());
Map<String, String> labelTranslations = source.getLabelTranslations();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,9 @@
filter: "",
serviceRecord: null,
groupOwner: null,
listableInHeaderSelector: true
listableInHeaderSelector: true,
datahubEnabled: false,
datahubConfiguration: ""
};
// TODO: init labels
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,28 @@
<span data-translate="">displayInHeaderSwitcher</span>
</label>
<p class="help-block" data-translate="">displayInHeaderSwitcher-help</p>

<label data-translate="">datahubEnabled</label>
<input
type="checkbox"
name="datahubEnabled"
id="datahubEnabled"
data-ng-model="source.datahubEnabled"
/>
<p class="help-block" data-translate="">sourceDatahubEnabled-help</p>

<label data-translate="">datahubConfiguration</label>
<textarea
data-gn-autogrow=""
type="text"
name="datahubConfiguration"
class="form-control"
id="datahubConfiguration"
data-ng-model="source.datahubConfiguration"
>
{{source.datahubConfiguration}}</textarea
>
<p class="help-block" data-translate="">sourceDatahubConfiguration-help</p>
</form>

<div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,24 @@ <h4 class="modal-title" data-translate="">
data-ng-disabled="!isTranslationProviderSelected"
/>

<input
data-ng-switch-when="geonetwork-ui/datahub/enabled"
type="checkbox"
id="{{s['name']}}"
name="{{s.name}}"
data-ng-model="s.value"
/>
<textarea
data-gn-autogrow=""
data-ng-switch-when="geonetwork-ui/datahub/configuration"
type="text"
class="form-control"
id="{{s['name']}}"
name="{{s.name}}"
>
{{s.value}}</textarea
>

<!-- Default -->
<input
data-ng-switch-default=""
Expand Down
Loading