Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
d96ba59
Created `report_result` table in the database.
milanmajchrak Jun 5, 2025
2044d2a
Created Java mapping for the ReportResult object with the CRUD operat…
milanmajchrak Jun 5, 2025
ea0358b
JSONified the InfoCheck and the result is stored to the ReportResult …
milanmajchrak Jun 5, 2025
356d3e7
Fetch the ReportResultService from the ContentServiceFactory
milanmajchrak Jun 5, 2025
6f294e3
Marked the report_result_id as PRIMARY KEY in the sql file.
milanmajchrak Jun 6, 2025
46256f3
Use CURRENT_TIMESTAMP as a default value for the last_modified
milanmajchrak Jun 6, 2025
52b85fe
h2 should have the defaut value for the `report_result_id`
milanmajchrak Jun 6, 2025
e65a9ac
Added doc to the report result service
milanmajchrak Jun 6, 2025
ada63d5
Updated doc in the report result service
milanmajchrak Jun 6, 2025
28a15ec
Make sure the current date is used in the timestamp when updating the…
milanmajchrak Jun 6, 2025
b7d0f83
Removed redundant `getID` method from the ReportResult
milanmajchrak Jun 6, 2025
f461963
Do not add the `URL: ` value to the url property in the InfoCheck
milanmajchrak Jun 6, 2025
74939b1
Format the date for the InfoCheck date time stamp
milanmajchrak Jun 6, 2025
e977a9c
Added HealthReport functionality to the Try Finally block to be sure …
milanmajchrak Jun 6, 2025
48c6fd3
Created sequence in the h2 database for the report result object.
milanmajchrak Jun 6, 2025
e900051
Fixed documentation in the psql for the report result.
milanmajchrak Jun 6, 2025
50c781a
Do not append string with `Url: ` two times..
milanmajchrak Jun 6, 2025
9d5a6ce
Fixed checkstyle
milanmajchrak Jun 6, 2025
d05bf5d
Fixed h2 sql definition - missing comma
milanmajchrak Jun 6, 2025
4454544
Added raw process for creating diff between two last result reports.
milanmajchrak Jun 6, 2025
fc2c62f
Working somehow, refactoring needed.
milanmajchrak Jun 10, 2025
b5e2872
Added Integration tests and fixed bugs.
milanmajchrak Jun 10, 2025
16c8d34
Refactored the code and fixed checkstyle issues
milanmajchrak Jun 11, 2025
cbbfaea
Use consistent DateFormat
milanmajchrak Jun 11, 2025
ac24df9
Updated description for the srcipt definition
milanmajchrak Jun 12, 2025
f1e6a8e
The test failed because not all scripts were returned because of pagi…
milanmajchrak Jun 12, 2025
4e42a99
UFAL/JSONificate Item Summary health reports (#986)
jr-rk Jul 9, 2025
fa0dfc7
UFAL/JSONificate User Summary health reports (#987)
jr-rk Jul 9, 2025
346e87f
UFAL/JSONificate License Summary health reports (#988)
jr-rk Jul 9, 2025
3a63fce
Use last two reports from DB when 'from' and 'to' are empty, add test
Paurikova2 Aug 6, 2025
ba10d17
Send an email about the report differences
Paurikova2 Aug 6, 2025
0f980fb
refactoring based on copilot and coderabbitai
Paurikova2 Aug 6, 2025
ba6eb2e
added limit for dates list
Paurikova2 Aug 6, 2025
551a270
review copilot
Paurikova2 Aug 6, 2025
bf3583e
fix incorrect limit specification
Paurikova2 Aug 12, 2025
380640f
fix log msgs
Paurikova2 Aug 12, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,21 @@
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.mail.MessagingException;

import org.apache.commons.cli.Option;
import org.apache.commons.cli.ParseException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.content.ReportResult;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.ReportResultService;
import org.dspace.core.Context;
import org.dspace.core.Email;
import org.dspace.core.I18nUtil;
Expand All @@ -34,6 +40,8 @@
import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.dspace.utils.DSpace;
import org.json.JSONArray;
import org.json.JSONObject;

/**
* This class is used to generate a health report of the DSpace instance.
Expand All @@ -44,6 +52,7 @@ public class HealthReport extends DSpaceRunnable<HealthReportScriptConfiguration
private static final Logger log = LogManager.getLogger(HealthReport.class);

private ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
private ReportResultService reportResultService = ContentServiceFactory.getInstance().getReportResultService();
private EPersonService ePersonService;

/**
Expand Down Expand Up @@ -136,12 +145,18 @@ public void internalRun() throws Exception {
return;
}

Context context = new Context();
context.setCurrentUser(ePersonService.find(context, this.getEpersonIdentifier()));

ReportInfo ri = new ReportInfo(this.forLastNDays);

StringBuilder sbReport = new StringBuilder();
sbReport.append("\n\nHEALTH REPORT:\n");

int position = -1;
JSONObject root = new JSONObject();
// Create the array
JSONArray checksArray = new JSONArray();
for (Map.Entry<String, Check> check_entry : Report.checks().entrySet()) {
++position;
if (specificCheck != -1 && specificCheck != position) {
Expand All @@ -157,13 +172,32 @@ public void internalRun() throws Exception {
sbReport.append("\n######################\n\n").append(name).append(":\n");
check.report(ri);
sbReport.append(check.getReport());

// JSON:
// Check name: {Report}
JSONObject report = check.getReportJson(); // assume check is already defined

JSONObject checkJson = new JSONObject();
checkJson.put("name", name);
checkJson.put("report", report);
// Add items to array
checksArray.put(checkJson);
}

// Add array to root object under a key "checks"
root.put("checks", checksArray);

// Add health report summary to the ReportResult object
ReportResult reportResult = reportResultService.create(context);
reportResult.setArgs(printCommandlineOptions());
reportResult.setExecutor(context.getCurrentUser());
reportResult.setType("healthcheck");
reportResult.setValue(root.toString());
reportResultService.update(context, reportResult);
context.commit();

// save output to file
if (fileName != null) {
Context context = new Context();
context.setCurrentUser(ePersonService.find(context, this.getEpersonIdentifier()));

InputStream inputStream = toInputStream(sbReport.toString(), StandardCharsets.UTF_8);
handler.writeFilestream(context, fileName, inputStream, "export");

Expand Down Expand Up @@ -201,6 +235,21 @@ public void printHelp() {
);
}

/**
* Print command line options in a readable format.
* This method is used to print the options used for the report.
*/
private String printCommandlineOptions() {
// Return key-value pairs of options
StringBuilder options = new StringBuilder();
for (Option option : commandLine.getOptions()) {
String key = option.getOpt();
String value = commandLine.getOptionValue(key);
options.append(String.format(" -%s: %s\n", key, value));
}
return options.toString();
}

Comment thread
milanmajchrak marked this conversation as resolved.
/**
* Convert checks names to string.
*/
Expand Down
116 changes: 116 additions & 0 deletions dspace-api/src/main/java/org/dspace/content/ReportResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.content;

import org.dspace.core.ReloadableEntity;
import org.dspace.eperson.EPerson;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import java.util.Date;

/**
* ReportResult is an entity that stores the results of a Health Report execution.
* It includes the type of report, the value of the result, the executor,
* arguments used for the report, and the last modified date.
*
* @author Milan Majchrak (milan.majchrak at dataquest.sk)
*/
@Entity
@Table(name = "report_result")
public class ReportResult implements ReloadableEntity<Integer> {
@Id
@Column(name = "report_result_id")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "report_result_id_seq")
@SequenceGenerator(name = "report_result_id_seq", sequenceName = "report_result_id_seq",
allocationSize = 1)
private Integer id;

@Column(name = "type")
private String type;

@Column(name = "value")
private String value;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "executor_id")
private EPerson executor;

@Column(name = "args")
private String args;

@Column(name = "last_modified", columnDefinition = "timestamp with time zone")
Comment thread
Paurikova2 marked this conversation as resolved.
Outdated
@Temporal(TemporalType.TIMESTAMP)
private Date lastModified = new Date();

@Override
public Integer getID() {
return id;
}

public ReportResult() {
}

public Integer getId() {
return id;
}
Comment thread
milanmajchrak marked this conversation as resolved.
Outdated

public void setId(Integer id) {
this.id = id;
}

public String getType() {
return type;
}

public void setType(String type) {
this.type = type;
}

public String getValue() {
return value;
}

public void setValue(String value) {
this.value = value;
}

public EPerson getExecutor() {
return executor;
}

public void setExecutor(EPerson executor) {
this.executor = executor;
}

public String getArgs() {
return args;
}

public void setArgs(String args) {
this.args = args;
}

public Date getLastModified() {
return lastModified;
}

public void setLastModified(Date lastModified) {
this.lastModified = lastModified;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.content;

import java.sql.SQLException;

import org.dspace.content.dao.ReportResultDAO;
import org.dspace.content.service.ReportResultService;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;

/**
* Service implementation for managing ReportResult objects.
* This class provides methods for creating, finding, deleting, and updating ReportResult instances.
* @see ReportResultService
*
* @author Milan Majchrak (milan.majchrak at dataquest.sk)
*/
public class ReportResultServiceImpl implements ReportResultService {
@Autowired
private ReportResultDAO reportResultDAO;

@Override
public ReportResult create(Context context) throws SQLException {
return reportResultDAO.create(context, new ReportResult());
}

@Override
public ReportResult create(Context context, ReportResult reportResult) throws SQLException {
return reportResultDAO.create(context, reportResult);
}

@Override
public ReportResult find(Context context, int id) throws SQLException {
return reportResultDAO.findByID(context, ReportResult.class, id);
}

@Override
public void delete(Context context, ReportResult reportResult) throws SQLException {
reportResultDAO.delete(context, reportResult);
}

@Override
public void update(Context context, ReportResult reportResult) throws SQLException {
reportResultDAO.save(context, reportResult);
}
Comment thread
milanmajchrak marked this conversation as resolved.
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.content.dao;

import org.dspace.content.ReportResult;
import org.dspace.core.GenericDAO;

/**
* Database Access Object interface class for the ReportResult object.
* The implementation of this class is responsible for all database calls for the ReportResult object
*
* @author Milan Majchrak (milan.majchrak at dataquest.sk)
*/
public interface ReportResultDAO extends GenericDAO<ReportResult> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.content.dao.impl;

import org.dspace.content.ReportResult;
import org.dspace.content.dao.ReportResultDAO;
import org.dspace.core.AbstractHibernateDAO;

/**
* Database Access Object implementation class for the ReportResult object.
* This class is responsible for all database calls for the ReportResult object
* and is autowired by Spring. It extends AbstractHibernateDAO to provide basic CRUD operations.
*
* @author Milan Majchrak (milan.majchrak at dataquest.sk)
*/
public class ReportResultDAOImpl extends AbstractHibernateDAO<ReportResult> implements ReportResultDAO {

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.dspace.content.service.PreviewContentService;
import org.dspace.content.service.RelationshipService;
import org.dspace.content.service.RelationshipTypeService;
import org.dspace.content.service.ReportResultService;
import org.dspace.content.service.SiteService;
import org.dspace.content.service.WorkspaceItemService;
import org.dspace.core.ProvenanceService;
Expand Down Expand Up @@ -132,6 +133,8 @@ public abstract class ContentServiceFactory {
*/
public abstract ProvenanceService getProvenanceService();

public abstract ReportResultService getReportResultService();

public InProgressSubmissionService getInProgressSubmissionService(InProgressSubmission inProgressSubmission) {
if (inProgressSubmission instanceof WorkspaceItem) {
return getWorkspaceItemService();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.dspace.content.service.PreviewContentService;
import org.dspace.content.service.RelationshipService;
import org.dspace.content.service.RelationshipTypeService;
import org.dspace.content.service.ReportResultService;
import org.dspace.content.service.SiteService;
import org.dspace.content.service.WorkspaceItemService;
import org.dspace.core.ProvenanceService;
Expand Down Expand Up @@ -97,6 +98,9 @@ public class ContentServiceFactoryImpl extends ContentServiceFactory {
@Autowired(required = true)
private ProvenanceService provenanceService;

@Autowired(required = true)
private ReportResultService reportResultService;

@Override
public List<DSpaceObjectService<? extends DSpaceObject>> getDSpaceObjectServices() {
return dSpaceObjectServices;
Expand Down Expand Up @@ -182,6 +186,11 @@ public ProvenanceService getProvenanceService() {
return provenanceService;
}

@Override
public ReportResultService getReportResultService() {
return reportResultService;
}

@Override
public RelationshipTypeService getRelationshipTypeService() {
return relationshipTypeService;
Expand Down
Loading