Skip to content
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package gov.healthit.chpl.web.controller;

Check warning on line 1 in chpl/chpl-api/src/main/java/gov/healthit/chpl/web/controller/QuestionableActivityReportController.java

View workflow job for this annotation

GitHub Actions / Checkstyle job

[reviewdog] reported by reviewdog 🐶 File does not end with a newline 'lf'. Raw Output: /github/workspace/./chpl/chpl-api/src/main/java/gov/healthit/chpl/web/controller/QuestionableActivityReportController.java:1:0: warning: File does not end with a newline 'lf'. (com.puppycrawl.tools.checkstyle.checks.NewlineAtEndOfFileCheck)

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import gov.healthit.chpl.report.ReportDataManager;
import gov.healthit.chpl.report.questionableActivity.QuestionableActivityReport;
import gov.healthit.chpl.util.LogMethodUsage;
import gov.healthit.chpl.util.SwaggerSecurityRequirement;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.log4j.Log4j2;

@Log4j2
@Tag(name = "report-data/questionable-activity", description = "Allows retrieval of data used by Questionable Activity Report.")
@RestController
@RequestMapping("/report-data/questionable-activity")
public class QuestionableActivityReportController {
private ReportDataManager reportDataManager;

@Autowired
public QuestionableActivityReportController(ReportDataManager reportDataManager) {
this.reportDataManager = reportDataManager;
}

@Operation(summary = "Retrieves the data used to generate the Questionable Activity Report.",
security = {
@SecurityRequirement(name = SwaggerSecurityRequirement.API_KEY)
})
@LogMethodUsage
@RequestMapping(value = "", method = RequestMethod.GET, produces = "application/json; charset=utf-8")
public @ResponseBody List<QuestionableActivityReport> getQuestionableActivityReports() {
return reportDataManager.getQuestionableActivityService().getQuestionableActivityReports();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ public enum QuestionableActivityTriggerConcept implements Serializable {
CURES_UPDATE_REMOVED("Cures Update Designation Removed"),
GAP_EDITED("GAP Status Edited");

public static final String LEVEL_LISTING = "Listing";
public static final String LEVEL_CRITERIA = "Certification Criteria";
public static final String LEVEL_DEVELOPER = "Developer";
public static final String LEVEL_PRODUCT = "Product";
public static final String LEVEL_VERSION = "Version";

private final String name;

QuestionableActivityTriggerConcept(String input) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@
import java.util.Date;
import java.util.UUID;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

import org.hibernate.annotations.Immutable;

import gov.healthit.chpl.questionableactivity.search.QuestionableActivitySearchResult;
import gov.healthit.chpl.util.DateUtil;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
Expand Down Expand Up @@ -52,9 +51,6 @@ public class QuestionableActivitySearchResultEntity {
@Column(name = "activity_sso_user_id")
private UUID ssoUserId;

//@Column(name = "user_contact_info")
//private String username;

@Column(name = "certification_status_change_reason")
private String certificationStatusChangeReason;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,25 @@
import org.apache.commons.lang3.StringUtils;

import com.fasterxml.jackson.annotation.JsonIgnore;
import tools.jackson.databind.annotation.JsonDeserialize;
import tools.jackson.databind.annotation.JsonSerialize;

import gov.healthit.chpl.domain.auth.User;
import gov.healthit.chpl.questionableactivity.QuestionableActivityTriggerConcept;
import gov.healthit.chpl.util.DateUtil;
import gov.healthit.chpl.util.EasternToSystemLocalDateTimeDeserializer;
import gov.healthit.chpl.util.SystemToEasternLocalDateTimeSerializer;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import tools.jackson.databind.annotation.JsonDeserialize;
import tools.jackson.databind.annotation.JsonSerialize;

@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
public class QuestionableActivitySearchResult implements Serializable {
private static final long serialVersionUID = -8153861360218726537L;
private static final String LEVEL_LISTING = "Listing";
private static final String LEVEL_CRITERIA = "Certification Criteria";
private static final String ADDED_PREFIX = "Added";
private static final String REMOVED_PREFIX = "Removed";

Expand Down Expand Up @@ -96,7 +95,8 @@ public List<String> toListOfStringsForCsv(String listingsReportUrlPartBegin) {
csvFields.add(chplProductNumber);
csvFields.add(certificationStatusName);
csvFields.add(DateUtil.formatInEasternTime(DateUtil.fromSystemToEastern(activityDate)));
if (LEVEL_LISTING.equals(triggerLevel) || LEVEL_CRITERIA.equals(triggerLevel)) {
if (QuestionableActivityTriggerConcept.LEVEL_LISTING.equals(triggerLevel)
|| QuestionableActivityTriggerConcept.LEVEL_CRITERIA.equals(triggerLevel)) {
csvFields.add(listingsReportUrlPartBegin + "/" + listingId);
} else {
csvFields.add("");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import gov.healthit.chpl.report.product.ProductByAcb;
import gov.healthit.chpl.report.product.ProductReportsService;
import gov.healthit.chpl.report.product.UniqueProductCount;
import gov.healthit.chpl.report.questionableActivity.QuestionableActivityReportService;
import gov.healthit.chpl.report.questionableurl.QuestionableUrlReportService;
import gov.healthit.chpl.report.realworldtesting.RealWorldTestingReportDataService;
import gov.healthit.chpl.report.servicebaseurllistreport.ServiceBaseUrlListReportService;
Expand Down Expand Up @@ -58,6 +59,7 @@ public class ReportDataManager {
private CriteriaUpToDateReportService criteriaUpToDateReportService;
private ListingAttributeReportService listingAttributeReportService;
private QuestionableUrlReportService questionableUrlReportService;
private QuestionableActivityReportService questionableActivityReportService;
private ServiceBaseUrlListReportService serviceBaseUrlListReportService;
private SvapReportService svapReportService;
private RealWorldTestingReportDataService realWorldTestingReportDataService;
Expand All @@ -77,6 +79,7 @@ public ReportDataManager(CriteriaMigrationReportService criteriaMigrationReportS
CriteriaUpToDateReportService criteriaUpToDateReportService,
ListingAttributeReportService listingAttributeReportService,
QuestionableUrlReportService questionableUrlReportService,
QuestionableActivityReportService questionableActivityReportService,
ServiceBaseUrlListReportService serviceBaseUrlListReportService,
SvapReportService svapReportService,
RealWorldTestingReportDataService realWorldTestingReportDataService,
Expand All @@ -96,6 +99,7 @@ public ReportDataManager(CriteriaMigrationReportService criteriaMigrationReportS
this.criteriaUpToDateReportService = criteriaUpToDateReportService;
this.listingAttributeReportService = listingAttributeReportService;
this.questionableUrlReportService = questionableUrlReportService;
this.questionableActivityReportService = questionableActivityReportService;
this.serviceBaseUrlListReportService = serviceBaseUrlListReportService;
this.svapReportService = svapReportService;
this.realWorldTestingReportDataService = realWorldTestingReportDataService;
Expand Down Expand Up @@ -299,6 +303,11 @@ public QuestionableUrlReportService getQuestionableUrlService() {
return questionableUrlReportService;
}

@Synchronized("lock")
public QuestionableActivityReportService getQuestionableActivityService() {
return questionableActivityReportService;
}

@Synchronized("lock")
public CriteriaUpToDateReportService getCriteriaAttributeUpToDateService() {
return criteriaUpToDateReportService;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package gov.healthit.chpl.report.questionableActivity;

import java.time.LocalDate;

import gov.healthit.chpl.util.LocalDateDeserializer;
import gov.healthit.chpl.util.LocalDateSerializer;
import lombok.Builder;
import lombok.Data;
import tools.jackson.databind.annotation.JsonDeserialize;
import tools.jackson.databind.annotation.JsonSerialize;

@Data
@Builder
public class QuestionableActivityReport {
private String activityType;
private String developer;

@JsonDeserialize(using = LocalDateDeserializer.class)
@JsonSerialize(using = LocalDateSerializer.class)
private LocalDate activityDate;

/**
* The CHPL Product Number, developer name, product name, ONC-ACB name, etc depending on the "type" of the activity
*/
private String relatedItem;
private Long relatedItemId;
private String relatedItemUrl;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package gov.healthit.chpl.report.questionableActivity;

import java.util.List;
import java.util.stream.Collectors;

import org.ff4j.FF4j;
import org.joda.time.LocalDateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;

import gov.healthit.chpl.dao.impl.BaseDAOImpl;
import gov.healthit.chpl.questionableactivity.QuestionableActivityTriggerConcept;
import gov.healthit.chpl.questionableactivity.entity.QuestionableActivitySearchResultEntity;
import gov.healthit.chpl.questionableactivity.search.QuestionableActivitySearchResult;
import jakarta.persistence.Query;

@Repository
public class QuestionableActivityReportDao extends BaseDAOImpl {
private static final int REPORT_MONTHS = 6;

private String unformattedListingDetailsUrl;
private String unformattedDeveloperDetailsUrl;
private FF4j ff4j;

@Autowired
public QuestionableActivityReportDao(@Value("${chplUrlBegin}") String chplUrlBegin,
@Value("${listingDetailsUrlPart}") String listingDetailsUrlPart,
@Value("${developerUrlPart}") String developerUrlPart) {
this.unformattedListingDetailsUrl = chplUrlBegin + listingDetailsUrlPart;
this.unformattedDeveloperDetailsUrl = chplUrlBegin + developerUrlPart;
}

public List<QuestionableActivityReport> getQuestionableActivityReports() {
Query query = entityManager.createQuery("SELECT qa "
+ "FROM QuestionableActivitySearchResultEntity qa "
+ "WHERE qa.activityDate >= :activityDate ",
QuestionableActivitySearchResultEntity.class);
query.setParameter("activityDate", LocalDateTime.now().minusMonths(REPORT_MONTHS).toDate());

List<QuestionableActivitySearchResultEntity> queryResults = query.getResultList();
List<QuestionableActivityReport> results = queryResults.stream()
.map(entity -> entity.toDomain())
.map(activity -> QuestionableActivityReport.builder()
.activityType(activity.getTriggerName())
.activityDate(activity.getActivityDate().toLocalDate())
.developer(activity.getDeveloperName())
.relatedItem(getRelatedItemName(activity))
.relatedItemId(getRelatedItemId(activity))
.relatedItemUrl(getRelatedItemUrl(activity))
.build())
.collect(Collectors.toList());
return results;
}

private String getRelatedItemName(QuestionableActivitySearchResult activity) {
if (activity.getTriggerLevel().equals(QuestionableActivityTriggerConcept.LEVEL_LISTING)
|| activity.getTriggerLevel().equals(QuestionableActivityTriggerConcept.LEVEL_CRITERIA)) {
return activity.getChplProductNumber();
} else if (activity.getTriggerLevel().equals(QuestionableActivityTriggerConcept.LEVEL_DEVELOPER)) {
return activity.getDeveloperName();
} else if (activity.getTriggerLevel().equals(QuestionableActivityTriggerConcept.LEVEL_PRODUCT)) {
return activity.getProductName();
} else if (activity.getTriggerLevel().equals(QuestionableActivityTriggerConcept.LEVEL_VERSION)) {
return activity.getVersionName();
}
return activity.getDescription();
}

private Long getRelatedItemId(QuestionableActivitySearchResult activity) {
if (activity.getTriggerLevel().equals(QuestionableActivityTriggerConcept.LEVEL_LISTING)
|| activity.getTriggerLevel().equals(QuestionableActivityTriggerConcept.LEVEL_CRITERIA)) {
return activity.getListingId();
} else if (activity.getTriggerLevel().equals(QuestionableActivityTriggerConcept.LEVEL_DEVELOPER)) {
return activity.getDeveloperId();
} else if (activity.getTriggerLevel().equals(QuestionableActivityTriggerConcept.LEVEL_PRODUCT)) {
return activity.getProductId();
} else if (activity.getTriggerLevel().equals(QuestionableActivityTriggerConcept.LEVEL_VERSION)) {
return activity.getVersionId();
}
return null;
}

private String getRelatedItemUrl(QuestionableActivitySearchResult activity) {
if (activity.getTriggerLevel().equals(QuestionableActivityTriggerConcept.LEVEL_LISTING)
|| activity.getTriggerLevel().equals(QuestionableActivityTriggerConcept.LEVEL_CRITERIA)) {
return String.format(unformattedListingDetailsUrl, activity.getListingId());
} else if (activity.getTriggerLevel().equals(QuestionableActivityTriggerConcept.LEVEL_DEVELOPER)) {
return String.format(unformattedDeveloperDetailsUrl, activity.getDeveloperId());
}
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package gov.healthit.chpl.report.questionableActivity;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import lombok.extern.log4j.Log4j2;

@Log4j2
@Component
public class QuestionableActivityReportService {
private QuestionableActivityReportDao questionableActivityReportDao;

@Autowired
public QuestionableActivityReportService(QuestionableActivityReportDao questionableActivityReportDao) {
this.questionableActivityReportDao = questionableActivityReportDao;
}

@Transactional
public List<QuestionableActivityReport> getQuestionableActivityReports() {
return questionableActivityReportDao.getQuestionableActivityReports();
}
}
Loading