Skip to content

Commit e122a90

Browse files
author
Jens Vannerum
committed
Implement a SEOHealthIndicator which verifies all relevant parameters for SEO are ok
(cherry picked from commit 4bd8a24)
1 parent ac7eee6 commit e122a90

File tree

2 files changed

+84
-0
lines changed

2 files changed

+84
-0
lines changed

dspace-server-webapp/src/main/java/org/dspace/app/rest/configuration/ActuatorConfiguration.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import org.apache.solr.client.solrj.SolrServerException;
1515
import org.dspace.app.rest.DiscoverableEndpointsService;
1616
import org.dspace.app.rest.health.GeoIpHealthIndicator;
17+
import org.dspace.app.rest.health.SEOHealthIndicator;
1718
import org.dspace.authority.AuthoritySolrServiceImpl;
1819
import org.dspace.discovery.SolrSearchCore;
1920
import org.dspace.statistics.SolrStatisticsCore;
@@ -82,6 +83,12 @@ public SolrHealthIndicator solrOaiCoreHealthIndicator(SolrServerResolver solrSer
8283
return new SolrHealthIndicator(solrServerResolver.getServer());
8384
}
8485

86+
@Bean
87+
@ConditionalOnEnabledHealthIndicator("seo")
88+
public SEOHealthIndicator seoHealthIndicator() {
89+
return new SEOHealthIndicator();
90+
}
91+
8592
@Bean
8693
@ConditionalOnEnabledHealthIndicator("geoIp")
8794
public GeoIpHealthIndicator geoIpHealthIndicator() {
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/**
2+
* The contents of this file are subject to the license and copyright
3+
* detailed in the LICENSE and NOTICE files at the root of the source
4+
* tree and available online at
5+
*
6+
* http://www.dspace.org/license/
7+
*/
8+
package org.dspace.app.rest.health;
9+
10+
import org.apache.commons.lang3.StringUtils;
11+
import org.dspace.services.ConfigurationService;
12+
import org.dspace.services.factory.DSpaceServicesFactory;
13+
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
14+
import org.springframework.boot.actuate.health.Health;
15+
import org.springframework.web.client.RestTemplate;
16+
17+
/**
18+
* Implementation of {@link org.springframework.boot.actuate.health.HealthIndicator} that verifies if the SEO of the
19+
* DSpace instance is configured correctly.
20+
*
21+
* This is only relevant in a production environment, where the DSpace instance is exposed to the public.
22+
*/
23+
public class SEOHealthIndicator extends AbstractHealthIndicator {
24+
25+
ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
26+
27+
private final RestTemplate restTemplate = new RestTemplate();
28+
29+
@Override
30+
protected void doHealthCheck(Health.Builder builder) {
31+
String baseUrl = configurationService.getProperty("dspace.ui.url");
32+
33+
boolean sitemapOk = checkUrl(baseUrl + "/sitemap_index.xml") || checkUrl(baseUrl + "/sitemap_index.html");
34+
boolean robotsTxtOk = checkRobotsTxt(baseUrl + "/robots.txt");
35+
boolean ssrOk = checkSSR(baseUrl);
36+
37+
if (sitemapOk && robotsTxtOk && ssrOk) {
38+
builder.up()
39+
.withDetail("sitemap", "OK")
40+
.withDetail("robots.txt", "OK")
41+
.withDetail("ssr", "OK");
42+
} else {
43+
builder.down()
44+
.withDetail("sitemap", sitemapOk ? "OK" : "Missing or inaccessible")
45+
.withDetail("robots.txt", robotsTxtOk ? "OK" : "Empty or contains local URLs")
46+
.withDetail("ssr", ssrOk ? "OK" : "Server-side rendering might be disabled");
47+
}
48+
}
49+
50+
private boolean checkUrl(String url) {
51+
try {
52+
restTemplate.getForEntity(url, String.class);
53+
return true;
54+
} catch (Exception e) {
55+
return false;
56+
}
57+
}
58+
59+
private boolean checkRobotsTxt(String url) {
60+
try {
61+
String content = restTemplate.getForObject(url, String.class);
62+
return StringUtils.isNotBlank(content) && !content.contains("localhost");
63+
} catch (Exception e) {
64+
return false;
65+
}
66+
}
67+
68+
private boolean checkSSR(String url) {
69+
try {
70+
String content = restTemplate.getForObject(url, String.class);
71+
return content != null && !content.contains("<ds-app></ds-app>");
72+
} catch (Exception e) {
73+
return false;
74+
}
75+
}
76+
}
77+

0 commit comments

Comments
 (0)