filteredAffiliateIds = applications.stream()
+ .map(this::evaluateApplication)
+ .filter(Objects::nonNull)
+ .toList();
+
+ logger.info("Total applications meeting the criteria: {}", filteredAffiliateIds.size());
+
+ if (!filteredAffiliateIds.isEmpty()) {
+ applicationRepository.updateLastProcessed(filteredAffiliateIds, Instant.now());
+ deactivateAffiliates(filteredAffiliateIds);
+ }
+ }
+
+ private Long evaluateApplication(Application application) {
+ Logger logger = LoggerFactory.getLogger(getClass());
+
+ Member member = getMemberById(application.getMember().getMemberId());
+ if (member == null) {
+ logger.warn("Member not found for application ID: {}", application.getApplicationId());
+ return null;
+ }
+
+ int pendingApplication = member.getPendingApplication();
+ if (pendingApplication == 0) {
+ logger.info("Skipping application ID {}: PendingApplication is 0", application.getApplicationId());
+ return null;
+ }
+
+ LocalDate cutoffDate = getCutoffDate(pendingApplication);
+ LocalDate submittedAt = getLocalDate(application.getSubmittedAt());
+ LocalDate completedAt = getLocalDate(application.getCompletedAt());
+
+ if (application.getAffiliate() == null) {
+ logger.warn("Affiliate is null for application ID: {}", application.getApplicationId());
+ return null;
+ }
+
+ boolean isOldCompleted = completedAt != null && completedAt.isBefore(cutoffDate);
+ boolean isOldSubmitted = submittedAt != null && submittedAt.isBefore(cutoffDate);
+
+ return (isOldCompleted || isOldSubmitted) ? application.getAffiliate().getAffiliateId() : null;
+ }
+
+ private LocalDate getLocalDate(Instant dateTime) {
+ return dateTime != null ? dateTime.atZone(ZoneId.systemDefault()).toLocalDate() : null;
+ }
+
+ /**
+ * Scheduled process to deactivate affiliates whose invoices are in a pending state
+ * beyond the defined period for their respective member country.
+ *
+ * - Fetches all affiliates with pending invoices.
+ * - Retrieves the defined invoice pending period for the member.
+ * - Identifies affiliates whose invoice pending period has exceeded the cutoff date.
+ * - Performs a bulk deactivation for the identified affiliates.
+ *
+ * This ensures that affiliates who have not cleared their invoices within the allowed timeframe
+ * are deactivated automatically, maintaining compliance with membership policies.
+ */
+ @Scheduled(cron = "${scheduler.remove-invoices-pending.cron}")
+ public void removeInvoicesPending() {
+ Logger logger = LoggerFactory.getLogger(getClass());
+
+ Member member = getMemberById(1L);
+ if (member.getInvoicesPending() == 0) {
+ logger.info("Skipping processing: PendingApplication is 0 for Member ID 1");
+ return;
+ }
+
+ LocalDate cutoffDate = getCutoffDate(member.getInvoicesPending());
+ List affiliateIds = getFilteredAffiliateIds(cutoffDate);
+ updateLastProcessedForAffiliates(affiliateIds);
+ deactivateAffiliates(affiliateIds);
+ }
+
+ private void updateLastProcessedForAffiliates(List affiliateIds) {
+ if (!affiliateIds.isEmpty()) {
+ affiliateRepository.updateLastProcessed(affiliateIds, Instant.now());
+ }
+ }
+
+ /*Get filtered affiliate IDs for Pending Incoices State For IHTSDO members*/
+ private List getFilteredAffiliateIds(LocalDate cutoffDate) {
+ List affiliates = affiliateRepository.getIHTSDOPendingInvoices();
+
+ return affiliates.stream()
+ .filter(affiliate -> affiliate.getStandingState() == StandingState.PENDING_INVOICE
+ && affiliate.getCreated().atZone(ZoneId.systemDefault()).toLocalDate().isBefore(cutoffDate))
+ .map(Affiliate::getAffiliateId)
+ .toList();
+
+ }
+
+ /*Fetch member details using the Member Id*/
+ private Member getMemberById(Long memberId) {
+ return memberRepository.findMemberById(memberId);
+ }
+
+ /*Reusable Method to Compute cutoff date based on Standing State , Approval State, Usage Reports*/
+ public LocalDate getCutoffDate(int invoicesPending) {
+ return LocalDate.now().minus(invoicesPending, ChronoUnit.DAYS);
+ }
+
+ /* Reusable method for Bulk Deactivate the Affiliates if applicable */
+ private void deactivateAffiliates(List affiliateid) {
+ Logger logger = LoggerFactory.getLogger(getClass());
+
+ if (!affiliateid.isEmpty()) {
+ // Fetch only active affiliates from the provided IDs
+ List activeAffiliateIds = affiliateRepository.findActiveAffiliateIds(new ArrayList<>(affiliateid));
+
+ if (!activeAffiliateIds.isEmpty()) {
+ int updatedCount = 0;
+ for (Long affiliateId : activeAffiliateIds) {
+ updatedCount = affiliateRepository.updateAffiliateStandingStateAndDeactivationReason(affiliateId, StandingState.DEREGISTERED, ReasonForDeactivation.AUTODEACTIVATION);
+
+ }
+ logger.info("Total affiliates deactivated: {}", updatedCount);
+ } else {
+ logger.info("No active affiliates found for deactivation.");
+ }
+ } else {
+ logger.info("No affiliates provided for deactivation.");
+ }
+ }
+
+ @Scheduled(cron = "${scheduler.remove-usage-reports.cron}")
+ public void removeUsageReports() {
+ Logger logger = LoggerFactory.getLogger(getClass());
+
+ List commercialUsages = commercialUsageRepository.findByState();
+
+ if (commercialUsages.isEmpty()) {
+ logger.info("No CommercialUsage records found with state 'NOT_SUBMITTED'.");
+ return;
+ }
+
+ List affiliateIdsForDeactivation = commercialUsages.stream()
+ .map(this::processUsage)
+ .filter(Objects::nonNull)
+ .toList();
+
+ if (!affiliateIdsForDeactivation.isEmpty()) {
+ deactivateAffiliates(affiliateIdsForDeactivation);
+ logger.info("Deactivated {} affiliates", affiliateIdsForDeactivation.size());
+ } else {
+ logger.info("No affiliates found for deactivation.");
+ }
+ }
+
+ private Long processUsage(CommercialUsage usage) {
+ Logger logger = LoggerFactory.getLogger(getClass());
+
+ if (usage.getAffiliate() == null || usage.getAffiliate().getAffiliateId() == null) {
+ logger.warn("CommercialUsage ID {} has no valid affiliate.", usage.getCommercialUsageId());
+ return null;
+ }
+
+ Long affiliateId = usage.getAffiliate().getAffiliateId();
+ Affiliate affiliate = affiliateRepository.findById(affiliateId).orElse(null);
+
+ if (affiliate == null || affiliate.getHomeMember() == null) {
+ logger.warn("Affiliate or HomeMember is null for Affiliate ID {}", affiliateId);
+ return null;
+ }
+
+ Member member = getMemberById(affiliate.getHomeMember().getMemberId());
+ if (member == null) {
+ logger.warn("Member not found for ID: {}", affiliate.getHomeMember().getMemberId());
+ return null;
+ }
+
+ if (member.getUsageReports() == 0) {
+ logger.info("Skipping processing: Usage Reports is 0 for Member ID {}", member.getMemberId());
+ return null;
+ }
+
+ if (usage.getCreated() == null) {
+ logger.warn("Skipping CommercialUsage ID {}: Created date is null.", usage.getCommercialUsageId());
+ return null;
+ }
+
+ LocalDate createdDate = usage.getCreated().atZone(ZoneId.systemDefault()).toLocalDate();
+ LocalDate cutoffDate = getCutoffDate(member.getUsageReports());
+
+ if (createdDate.isBefore(cutoffDate)) {
+ usage.setLastProcessed(Instant.now());
+ commercialUsageRepository.save(usage);
+ return affiliateId;
+ }
+
+ return null;
+ }
+
+
}
+
+
+
+
+
+
+
diff --git a/src/main/java/ca/intelliware/ihtsdo/mlds/service/mail/ClientLinkBuilder.java b/src/main/java/ca/intelliware/ihtsdo/mlds/service/mail/ClientLinkBuilder.java
index 9206ba062..3266bcd77 100644
--- a/src/main/java/ca/intelliware/ihtsdo/mlds/service/mail/ClientLinkBuilder.java
+++ b/src/main/java/ca/intelliware/ihtsdo/mlds/service/mail/ClientLinkBuilder.java
@@ -27,5 +27,10 @@ public String buildViewApplication(long applicationId) {
public String buildViewReleasePackageLink(long releasePackageId) {
return templateEvaluator.getUrlBase() + "#/viewReleases/viewRelease/"+releasePackageId;
}
+ public String buildUnsubscribeLink(long affiliateId, String unsubscribeKey) {
+ // Build and return the unsubscribe URL
+ return templateEvaluator.getUrlBase() + "#/unsubscribenotification/" + affiliateId + "/" + unsubscribeKey;
+ }
+
}
diff --git a/src/main/java/ca/intelliware/ihtsdo/mlds/service/mail/EmailVariables.java b/src/main/java/ca/intelliware/ihtsdo/mlds/service/mail/EmailVariables.java
index e3cc3687f..ec309ff0b 100644
--- a/src/main/java/ca/intelliware/ihtsdo/mlds/service/mail/EmailVariables.java
+++ b/src/main/java/ca/intelliware/ihtsdo/mlds/service/mail/EmailVariables.java
@@ -16,4 +16,5 @@ public class EmailVariables {
static final String APPLICATION_MEMBER = "applicationMember";
static final String BLANK_TITLE = "blankTitle";
static final String BLANK_BODY = "blankBody";
-}
\ No newline at end of file
+ static final String UNSUBSCRIBE_URL = "unsubscribeUrl";
+}
diff --git a/src/main/java/ca/intelliware/ihtsdo/mlds/service/mail/ReleasePackageUpdatedEmailSender.java b/src/main/java/ca/intelliware/ihtsdo/mlds/service/mail/ReleasePackageUpdatedEmailSender.java
index 6ce9ff425..4f9c3076d 100644
--- a/src/main/java/ca/intelliware/ihtsdo/mlds/service/mail/ReleasePackageUpdatedEmailSender.java
+++ b/src/main/java/ca/intelliware/ihtsdo/mlds/service/mail/ReleasePackageUpdatedEmailSender.java
@@ -1,14 +1,16 @@
package ca.intelliware.ihtsdo.mlds.service.mail;
+import ca.intelliware.ihtsdo.mlds.domain.Affiliate;
import ca.intelliware.ihtsdo.mlds.domain.ReleasePackage;
import ca.intelliware.ihtsdo.mlds.domain.ReleaseVersion;
import ca.intelliware.ihtsdo.mlds.domain.User;
+import ca.intelliware.ihtsdo.mlds.repository.AffiliateRepository;
+import ca.intelliware.ihtsdo.mlds.repository.UserRepository;
import com.google.common.collect.Maps;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
-import java.util.Locale;
-import java.util.Map;
+import java.util.*;
@Service
public class ReleasePackageUpdatedEmailSender {
@@ -16,19 +18,65 @@ public class ReleasePackageUpdatedEmailSender {
@Resource TemplateEvaluator templateEvaluator;
@Resource ClientLinkBuilder clientLinkBuilder;
- public void sendRelasePackageUpdatedEmail(User user, ReleasePackage releasePackage, ReleaseVersion releaseVersion) {
- final Locale locale = Locale.forLanguageTag(user.getLangKey());
- Map variables = Maps.newHashMap();
- variables.put(EmailVariables.RELEASE_PACKAGE, releasePackage);
- variables.put(EmailVariables.RELEASE_VERSION, releaseVersion);
- variables.put(EmailVariables.USER, user);
- variables.put(EmailVariables.MEMBERKEY, releasePackage.getMember().getKey());
- variables.put(EmailVariables.VIEW_RELEASE_PACKAGE_URL, clientLinkBuilder.buildViewReleasePackageLink(releasePackage.getReleasePackageId()));
- variables.put(EmailVariables.VIEW_PACKAGES_URL, clientLinkBuilder.buildViewReleasesLink());
- String content = templateEvaluator.evaluateTemplate("releasePackageUpdatedEmail", locale, variables);
- String subject = templateEvaluator.getTitleFor("releasePackageUpdated", locale);
-
- mailService.sendEmail(user.getEmail(), subject, content, false, true);
- }
+ AffiliateRepository affiliateRepository;
+ UserRepository userRepository;
+
+ public ReleasePackageUpdatedEmailSender(UserRepository userRepository, AffiliateRepository affiliateRepository) {
+ this.userRepository = userRepository;
+ this.affiliateRepository = affiliateRepository;
+ }
+
+ public void sendRelasePackageUpdatedEmail(User user, ReleasePackage releasePackage, ReleaseVersion releaseVersion) {
+ final Locale locale = Locale.forLanguageTag(user.getLangKey());
+ Map variables = Maps.newHashMap();
+
+ // Add existing variables
+ variables.put(EmailVariables.RELEASE_PACKAGE, releasePackage);
+ variables.put(EmailVariables.RELEASE_VERSION, releaseVersion);
+ variables.put(EmailVariables.USER, user);
+ variables.put(EmailVariables.MEMBERKEY, releasePackage.getMember().getKey());
+ variables.put(EmailVariables.VIEW_RELEASE_PACKAGE_URL, clientLinkBuilder.buildViewReleasePackageLink(releasePackage.getReleasePackageId()));
+ variables.put(EmailVariables.VIEW_PACKAGES_URL, clientLinkBuilder.buildViewReleasesLink());
+
+ // Generate unsubscribe URL with affiliateId and unsubscribeKey
+ String unsubscribeUrl = generateUnsubscribeData(user);
+ variables.put(EmailVariables.UNSUBSCRIBE_URL, unsubscribeUrl); // Add unsubscribe URL to the variables
+
+ // Generate the content using the template
+ String content = templateEvaluator.evaluateTemplate("releasePackageUpdatedEmail", locale, variables);
+
+ // Get the subject for the email
+ String subject = templateEvaluator.getTitleFor("releasePackageUpdated", locale);
+
+ // Send the email
+ mailService.sendEmail(user.getEmail(), subject, content, false, true);
+ }
+
+
+ // New method to generate unsubscribe key and fetch affiliateId
+ public String generateUnsubscribeData(User user) {
+ // Fetch affiliate using creator from Affiliate table (returns Affiliate, not Optional)
+ List affiliateList = affiliateRepository.findByCreatorIgnoreCase(user.getLogin());
+
+ // Check if affiliate exists and is not empty
+ if (affiliateList != null && !affiliateList.isEmpty()) {
+ Affiliate affiliate = affiliateList.get(0); // Get the first affiliate
+
+ long affiliateId = affiliate.getAffiliateId(); // Get affiliateId
+
+ // Generate unsubscribe key if it does not exist already
+ if (user.getUnsubscribeKey() == null || user.getUnsubscribeKey().isEmpty()) {
+ user.setUnsubscribeKey(UUID.randomUUID().toString()); // Generate new unsubscribe key
+ userRepository.save(user); // Save the user with the new unsubscribe key
+ }
+
+ // Return the unsubscribe URL with affiliateId and unsubscribeKey
+ return clientLinkBuilder.buildUnsubscribeLink(affiliateId, user.getUnsubscribeKey());
+ } else {
+ // Handle case where affiliate is not found
+ throw new IllegalArgumentException("Affiliate not found for the user.");
+ }
+ }
+
}
diff --git a/src/main/java/ca/intelliware/ihtsdo/mlds/web/rest/AffiliateResource.java b/src/main/java/ca/intelliware/ihtsdo/mlds/web/rest/AffiliateResource.java
index a886513aa..579761ab4 100644
--- a/src/main/java/ca/intelliware/ihtsdo/mlds/web/rest/AffiliateResource.java
+++ b/src/main/java/ca/intelliware/ihtsdo/mlds/web/rest/AffiliateResource.java
@@ -130,12 +130,12 @@ public class AffiliateResource {
} else {
if (member == null) {
if (standingState == null) {
- affiliates = affiliateRepository.findAll(pageRequest);
+ affiliates = affiliateRepository.findAllByDeactivatedFalse(pageRequest);
} else {
if (standingStateNot) {
- affiliates = affiliateRepository.findByStandingStateNot(standingState, pageRequest);
+ affiliates = affiliateRepository.findByStandingStateNotAndDeactivatedFalse(standingState, pageRequest);
} else {
- affiliates = affiliateRepository.findByStandingState(standingState, pageRequest);
+ affiliates = affiliateRepository.findByStandingStateAndDeactivatedFalse(standingState, pageRequest);
}
}
} else {
@@ -143,14 +143,16 @@ public class AffiliateResource {
affiliates = affiliateRepository.findByHomeMember(member, pageRequest);
} else {
if (standingStateNot) {
- affiliates = affiliateRepository.findByHomeMemberAndStandingStateNot(member, standingState, pageRequest);
+ affiliates = affiliateRepository.findByHomeMemberAndStandingStateNotAndDeactivatedFalse(member, standingState, pageRequest);
} else {
- affiliates = affiliateRepository.findByHomeMemberAndStandingState(member, standingState, pageRequest);
+ affiliates = affiliateRepository.findByHomeMemberAndStandingStateAndDeactivatedFalse(member, standingState, pageRequest);
}
}
}
}
+
AffiliateSearchResult result = new AffiliateSearchResult();
+
result.setAffiliates(affiliates.getContent());
result.setTotalResults(affiliates.getTotalElements());
result.setTotalPages(affiliates.getTotalPages());
diff --git a/src/main/java/ca/intelliware/ihtsdo/mlds/web/rest/ApplicationResource.java b/src/main/java/ca/intelliware/ihtsdo/mlds/web/rest/ApplicationResource.java
index 52f0be7ff..fafdc9e2b 100644
--- a/src/main/java/ca/intelliware/ihtsdo/mlds/web/rest/ApplicationResource.java
+++ b/src/main/java/ca/intelliware/ihtsdo/mlds/web/rest/ApplicationResource.java
@@ -40,7 +40,6 @@
import java.util.regex.Pattern;
-
@RestController
public class ApplicationResource {
@Resource
@@ -213,7 +212,11 @@ private Affiliate findAffiliateByUsername(String username) {
applications = applicationRepository.findByApprovalStateIn(approvalStates, pageRequest);
}
}
- return new ResponseEntity(new ApplicationCollection(applications), HttpStatus.OK);
+ List activeApplications = applications.stream()
+ .filter(a -> !a.getAffiliate().isDeactivated()) // Filtering out deactivated affiliates
+ .toList();
+
+ return new ResponseEntity<>(new ApplicationCollection(activeApplications), HttpStatus.OK);
}
private static final Map> ORDER_BY_FIELD_MAPPINGS = new HashMap>();
diff --git a/src/main/java/ca/intelliware/ihtsdo/mlds/web/rest/AuditResource.java b/src/main/java/ca/intelliware/ihtsdo/mlds/web/rest/AuditResource.java
index 7e77a8b4f..d77edb6b1 100644
--- a/src/main/java/ca/intelliware/ihtsdo/mlds/web/rest/AuditResource.java
+++ b/src/main/java/ca/intelliware/ihtsdo/mlds/web/rest/AuditResource.java
@@ -91,7 +91,9 @@ public List findReleaseFileDownloadAuditData(@RequestBody A
Map countMap = new HashMap<>();
for (PersistentAuditEvent event : result) {
Map data = event.getData();
- String key = data.get("releaseFile.label");
+ String key = data.get("releaseFile.label") + "|" +
+ data.get("releaseVersion.name") + "|" +
+ data.get("releasePackage.name");
countMap.computeIfAbsent(key, k -> {
ReleaseFileCountDTO countDTO = new ReleaseFileCountDTO();
diff --git a/src/main/java/ca/intelliware/ihtsdo/mlds/web/rest/CommercialUsageResource.java b/src/main/java/ca/intelliware/ihtsdo/mlds/web/rest/CommercialUsageResource.java
index 996d0ee20..58de78978 100644
--- a/src/main/java/ca/intelliware/ihtsdo/mlds/web/rest/CommercialUsageResource.java
+++ b/src/main/java/ca/intelliware/ihtsdo/mlds/web/rest/CommercialUsageResource.java
@@ -97,7 +97,9 @@ public ResponseEntity getAllUsageReports(
usageReports = commercialUsageRepository.searchUsageReports(searchText,UsageReportState.NOT_SUBMITTED, pageRequest);
}
- return new ResponseEntity<>(new CommercialUsageCollection(usageReports), HttpStatus.OK);
+ return new ResponseEntity<>(new CommercialUsageCollection(usageReports.stream()
+ .filter(a -> !a.getAffiliate().isDeactivated()) // Filtering out deactivated affiliates
+ .toList() ), HttpStatus.OK);
}
private Sort createUsageReportsSort(String orderby) {
diff --git a/src/main/java/ca/intelliware/ihtsdo/mlds/web/rest/DomainBlacklistResource.java b/src/main/java/ca/intelliware/ihtsdo/mlds/web/rest/DomainBlacklistResource.java
index bddcaa67b..c49725bda 100644
--- a/src/main/java/ca/intelliware/ihtsdo/mlds/web/rest/DomainBlacklistResource.java
+++ b/src/main/java/ca/intelliware/ihtsdo/mlds/web/rest/DomainBlacklistResource.java
@@ -41,7 +41,7 @@ public Object addDomainToBlacklist(@RequestParam String domain) {
DomainBlacklist newDomain = new DomainBlacklist();
- newDomain.setDomainname(domain);
+ newDomain.setDomainName(domain);
domainBlacklistRespository.save(newDomain);
@@ -52,7 +52,7 @@ public Object addDomainToBlacklist(@RequestParam String domain) {
@RequestMapping(value="api/domain-blacklist/remove", method=RequestMethod.POST)
@Timed
public Object removeDomainFromBlacklist(@RequestParam String domain) {
- domainBlacklistRespository.deleteAll(domainBlacklistRespository.findByDomainname(domain));
+ domainBlacklistRespository.deleteAll(domainBlacklistRespository.findByDomainName(domain));
return new ResponseEntity<>(HttpStatus.OK);
}
}
diff --git a/src/main/java/ca/intelliware/ihtsdo/mlds/web/rest/MemberResource.java b/src/main/java/ca/intelliware/ihtsdo/mlds/web/rest/MemberResource.java
index 80e04abcb..fd524180f 100644
--- a/src/main/java/ca/intelliware/ihtsdo/mlds/web/rest/MemberResource.java
+++ b/src/main/java/ca/intelliware/ihtsdo/mlds/web/rest/MemberResource.java
@@ -7,6 +7,7 @@
import ca.intelliware.ihtsdo.mlds.repository.MemberRepository;
import ca.intelliware.ihtsdo.mlds.security.AuthoritiesConstants;
import ca.intelliware.ihtsdo.mlds.web.SessionService;
+import ca.intelliware.ihtsdo.mlds.web.rest.dto.AutoDeactivationMemberDTO;
import ca.intelliware.ihtsdo.mlds.web.rest.dto.MemberDTO;
import com.codahale.metrics.annotation.Timed;
import jakarta.annotation.Resource;
@@ -32,6 +33,7 @@
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
@RestController
@@ -204,7 +206,8 @@ public ResponseEntity> updateMember(@PathVariable String memberKey, @RequestBo
member.setPromotePackages(body.getPromotePackages());
member.setStaffNotificationEmail(body.getStaffNotificationEmail());
-
+ member.setLanguage(body.getLanguage());
+ member.setFooterActive(body.getFooterActive());
memberRepository.save(member);
return new ResponseEntity(new MemberDTO(member), HttpStatus.OK);
@@ -216,11 +219,71 @@ public ResponseEntity> updateMember(@PathVariable String memberKey, @RequestBo
@Timed
public ResponseEntity> updateMemberFeedURL(@PathVariable String memberKey, @RequestBody MemberDTO body) throws IOException {
Member member = memberRepository.findOneByKey(memberKey);
+
+ if (member == null) {
+ return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Member not found for key: " + memberKey);
+ }
+
member.setContactEmail(body.getContactEmail());
member.setMemberOrgURL(body.getMemberOrgURL());
member.setMemberOrgName(body.getMemberOrgName());
memberRepository.save(member);
return new ResponseEntity(new MemberDTO(member), HttpStatus.OK);
}
+ @GetMapping(value = Routes.MEMBER_AUTO_DEACTIVATION, produces = "application/json")
+ @RolesAllowed({AuthoritiesConstants.STAFF, AuthoritiesConstants.ADMIN})
+ @Transactional
+ @Timed
+ public ResponseEntity getAutoDeactivationMemberDeatils(@PathVariable String memberKey){
+ Member member=memberRepository.findOneByKey(memberKey);
+ if (member == null) {
+ return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
+ }
+ AutoDeactivationMemberDTO deactivationMemberDTO=new AutoDeactivationMemberDTO();
+ deactivationMemberDTO.setUsageReports(member.getUsageReports());
+ deactivationMemberDTO.setPendingApplications(member.getPendingApplication());
+ deactivationMemberDTO.setInvoicesPending(member.getInvoicesPending());
+ return new ResponseEntity<>((deactivationMemberDTO), HttpStatus.OK);
+ }
+
+ @PutMapping(value = Routes.POST_MEMBER_AUTO_DEACTIVATION,produces = "application/json")
+ @RolesAllowed({AuthoritiesConstants.STAFF, AuthoritiesConstants.ADMIN})
+ @Transactional
+ @Timed
+ public ResponseEntity postAutoDeactivationMemberDetails(
+ @PathVariable String memberKey,
+ @RequestBody AutoDeactivationMemberDTO autoDeactivationDTO) {
+
+ Member member = memberRepository.findOneByKey(memberKey);
+ if (member == null) {
+ return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Member not found");
+ }
+
+ member.setInvoicesPending(autoDeactivationDTO.getInvoicesPending());
+ member.setUsageReports(autoDeactivationDTO.getUsageReports());
+ member.setPendingApplication(autoDeactivationDTO.getPendingApplications());
+
+ memberRepository.save(member);
+ return ResponseEntity.ok(Map.of("message", "Data Saved Successfully").toString());
+
+ }
+
+ @PutMapping(value = Routes.MEMBERLANGUAGEANDFOOTER,
+ produces = "application/json")
+ @RolesAllowed({AuthoritiesConstants.STAFF, AuthoritiesConstants.ADMIN})
+ @Transactional
+ @Timed
+ public ResponseEntity updateMemberLanguageAndFooter(@PathVariable String memberKey, @RequestBody MemberDTO body) {
+ Member member = memberRepository.findOneByKey(memberKey);
+ if (member == null) {
+ return new ResponseEntity<>(HttpStatus.NOT_FOUND);
+ }
+
+ member.setLanguage(body.getLanguage());
+ member.setFooterActive(body.getFooterActive());
+ memberRepository.save(member);
+
+ return new ResponseEntity<>(new MemberDTO(member), HttpStatus.OK);
+ }
}
diff --git a/src/main/java/ca/intelliware/ihtsdo/mlds/web/rest/ReleasePackagesResource.java b/src/main/java/ca/intelliware/ihtsdo/mlds/web/rest/ReleasePackagesResource.java
index 7aeadde7d..2c860689f 100644
--- a/src/main/java/ca/intelliware/ihtsdo/mlds/web/rest/ReleasePackagesResource.java
+++ b/src/main/java/ca/intelliware/ihtsdo/mlds/web/rest/ReleasePackagesResource.java
@@ -1,18 +1,20 @@
package ca.intelliware.ihtsdo.mlds.web.rest;
-import ca.intelliware.ihtsdo.mlds.domain.File;
-import ca.intelliware.ihtsdo.mlds.domain.ReleasePackage;
-import ca.intelliware.ihtsdo.mlds.domain.ReleaseVersion;
-import ca.intelliware.ihtsdo.mlds.repository.BlobHelper;
-import ca.intelliware.ihtsdo.mlds.repository.FileRepository;
-import ca.intelliware.ihtsdo.mlds.repository.ReleasePackageRepository;
+import ca.intelliware.ihtsdo.mlds.domain.*;
+import ca.intelliware.ihtsdo.mlds.repository.*;
import ca.intelliware.ihtsdo.mlds.security.AuthoritiesConstants;
import ca.intelliware.ihtsdo.mlds.security.ihtsdo.CurrentSecurityContext;
+import ca.intelliware.ihtsdo.mlds.service.ReleasePackageAccessService;
import ca.intelliware.ihtsdo.mlds.service.ReleasePackagePrioritizer;
+import ca.intelliware.ihtsdo.mlds.service.ReleasePackageService;
import ca.intelliware.ihtsdo.mlds.service.UserMembershipAccessor;
import ca.intelliware.ihtsdo.mlds.web.SessionService;
+import ca.intelliware.ihtsdo.mlds.web.rest.dto.ReleasePermissionRequestDTO;
import com.codahale.metrics.annotation.Timed;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import jakarta.annotation.security.PermitAll;
import jakarta.annotation.security.RolesAllowed;
@@ -45,7 +47,6 @@ public class ReleasePackagesResource {
BlobHelper blobHelper;
@Autowired
FileRepository fileRepository;
- @Autowired
SessionService sessionService;
@Autowired
@@ -68,6 +69,34 @@ public class ReleasePackagesResource {
@Autowired
ReleasePackagePrioritizer releasePackagePrioritizer;
+
+
+ @Autowired
+ ReleasePackageAccessRepository releasePackageAccessRepository;
+
+
+ ReleasePackageConfigRepository releasePackageConfigRepository;
+
+
+ UserRepository userRepository;
+
+
+ ReleasePackageService releasePackageService;
+
+
+ public ReleasePackagesResource(ReleasePackageAccessService releasePackageAccessService, UserRepository userRepository, ReleasePackageConfigRepository releasePackageConfigRepository, ReleasePackageService releasePackageService, SessionService sessionService) {
+ this.releasePackageAccessService = releasePackageAccessService;
+ this.userRepository = userRepository;
+ this.releasePackageConfigRepository = releasePackageConfigRepository;
+ this.releasePackageService = releasePackageService;
+ this.sessionService = sessionService;
+ }
+
+ ReleasePackageAccessService releasePackageAccessService;
+
+ private static final String NOT_SELECTED = "NOT_SELECTED";
+
+
//
// ////////////////////////////////////////////////////////////////////////////////////////////////////////
// // Release Packages
@@ -78,17 +107,94 @@ public class ReleasePackagesResource {
@Timed
public ResponseEntity> getReleasePackages() {
- Collection releasePackages = releasePackageRepository.findAll();
+ Collection releasePackages = releasePackageRepository.findAll();
- releasePackages = filterReleasePackagesByOnline(releasePackages);
+ //admin role checks - no restriction to admin role returns all the packages
+ if(currentSecurityContext.isAdmin()){
+ return new ResponseEntity<>(releasePackages, HttpStatus.OK);
+ }
+
+ // split online alphabeta offline package logic
+ List onlinePackages = new ArrayList<>();
+ List alphaBetaPackages = new ArrayList<>();
+ List offlinePackages = new ArrayList<>();
+ List finalMasterResult = new ArrayList<>();
+
+ for (ReleasePackage eachReleasePackage : releasePackages) {
+ releasePackageService.classifyPackage(eachReleasePackage, onlinePackages, alphaBetaPackages, offlinePackages);
+ }
+
+ if (currentSecurityContext.isStaff() || currentSecurityContext.isMember()) {
+ Collection staffAccessiblePackages = releasePackageAccessService.getAccessiblePackagesForStaff(
+ releasePackages,
+ onlinePackages,
+ alphaBetaPackages,
+ offlinePackages,
+ currentSecurityContext.getStaffMemberKey()
+ );
+ return ResponseEntity.ok(staffAccessiblePackages);
+ }
+
+ if (currentSecurityContext.isUser()) {
+ Collection userAccessiblePackages =
+ releasePackageAccessService.getAccessiblePackagesForUser(
+ releasePackages,
+ onlinePackages,
+ alphaBetaPackages,
+ offlinePackages,
+ currentSecurityContext.getCurrentUserName()
+ );
+
+ return new ResponseEntity<>(userAccessiblePackages, HttpStatus.OK);
+ }
+
+ if (!currentSecurityContext.isUser()
+ && !currentSecurityContext.isAdmin()
+ && !currentSecurityContext.isStaff()) {
+
+ Collection result = releasePackageAccessService
+ .getAccessiblePackagesForUnauthenticatedUser(
+ releasePackages,
+ onlinePackages,
+ alphaBetaPackages,
+ offlinePackages
+ );
+
+ return new ResponseEntity<>(result, HttpStatus.OK);
+ }
+
+ return new ResponseEntity<>(finalMasterResult, HttpStatus.OK);
+ }
+
+ @GetMapping(value = Routes.ARCHIVE_RELEASE_PACKAGES,
+ produces = MediaType.APPLICATION_JSON_VALUE)
+ @RolesAllowed(AuthoritiesConstants.ADMIN)
+ @Timed
+ public ResponseEntity> getArchiveReleasePackages() {
- return new ResponseEntity<>(releasePackages, HttpStatus.OK);
+ List releasePackages = releasePackageRepository.findAll();
+
+ releasePackages = filterReleasePackagesByOnline(releasePackages);
+ List response = releasePackages.stream()
+ .map(releasePackage -> {
+ Set archivedVersions = releasePackage.getReleaseVersions().stream()
+ .filter(ReleaseVersion::isArchive)
+ .collect(Collectors.toSet());
+ if (!archivedVersions.isEmpty()) {
+ releasePackage.setReleaseVersions(archivedVersions); // Keep only archived versions
+ return releasePackage; // Include this package
+ }
+ return null; // Skip this package
+ })
+ .filter(Objects::nonNull) // Exclude null packages
+ .toList();
+ return new ResponseEntity<>(response, HttpStatus.OK);
}
- private Collection filterReleasePackagesByOnline(
- Collection releasePackages) {
+ private List filterReleasePackagesByOnline(
+ List releasePackages) {
- Collection result = releasePackages;
+ List result = releasePackages;
if (!authorizationChecker.shouldSeeOfflinePackages()) {
result = new ArrayList<>();
@@ -120,6 +226,7 @@ private boolean isPackagePublished(ReleasePackage releasePackage) {
authorizationChecker.checkCanCreateReleasePackages();
releasePackage.setCreatedBy(currentSecurityContext.getCurrentUserName());
+ releasePackage.setPermissionType(ReleasePermissionType.NOT_SELECTED);
// MLDS-740 - Allow Admin to specify the member
if (releasePackage.getMember() == null || !currentSecurityContext.isAdmin()) {
@@ -136,20 +243,34 @@ private boolean isPackagePublished(ReleasePackage releasePackage) {
return result;
}
- @GetMapping(value = Routes.RELEASE_PACKAGE,
- produces = MediaType.APPLICATION_JSON_VALUE)
+
+ @GetMapping(value = Routes.RELEASE_PACKAGE, produces = MediaType.APPLICATION_JSON_VALUE)
@RolesAllowed({AuthoritiesConstants.ANONYMOUS, AuthoritiesConstants.USER, AuthoritiesConstants.MEMBER, AuthoritiesConstants.STAFF, AuthoritiesConstants.ADMIN})
@Timed
public ResponseEntity getReleasePackage(@PathVariable long releasePackageId) {
Optional optionalReleasePackage = releasePackageRepository.findById(releasePackageId);
+ if (optionalReleasePackage.isEmpty()) return new ResponseEntity<>(HttpStatus.NOT_FOUND);
- if (optionalReleasePackage.isEmpty()) {
- return new ResponseEntity<>(HttpStatus.NOT_FOUND);
+ ReleasePackage releasePackage = optionalReleasePackage.get();
+ String releaseType = releasePackageService.categorizePackage(releasePackage.getReleaseVersions());
+ ReleasePackageConfig config = releasePackageConfigRepository.findByReleaseType(releaseType.toUpperCase());
+ ReleasePackageConfig masterConfig = releasePackageConfigRepository.findByReleaseType("ALL");
+
+ if (currentSecurityContext.isAdmin()) {
+ return ResponseEntity.ok(releasePackage);
}
- ReleasePackage releasePackage = filterReleasePackageByAuthority(optionalReleasePackage.get());
+ if (currentSecurityContext.isStaff() || currentSecurityContext.isMember()) {
+ if (releasePackageAccessService.isStaffOwner(releasePackage)) return ResponseEntity.ok(releasePackage);
+ if (releasePackageAccessService.isAdminOnly(releasePackage, config, masterConfig)) return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
+ return ResponseEntity.ok(releasePackage);
+ }
- return new ResponseEntity<>(releasePackage, HttpStatus.OK);
+ if (currentSecurityContext.isUser()) {
+ return releasePackageAccessService.handleUserAccess(releasePackage, config, masterConfig, releasePackageId);
+ }
+
+ return releasePackageAccessService.handlePublicAccess(releasePackage, config, masterConfig);
}
private ReleasePackage filterReleasePackageByAuthority(ReleasePackage releasePackage) {
@@ -318,4 +439,250 @@ private File updateFile(MultipartFile multipartFile, File existingFile) throws I
fileRepository.save(newFile);
return newFile;
}
+
+ @PutMapping(value = Routes.RELEASE_PACKAGE_PERMISSION, produces = MediaType.APPLICATION_JSON_VALUE)
+ @RolesAllowed(AuthoritiesConstants.ADMIN)
+ @Timed
+ public ResponseEntity updateReleasePackageType(@PathVariable long releasePackageId, @RequestBody Map request) {
+
+ Optional optionalReleasePackage = releasePackageRepository.findById(releasePackageId);
+ if (optionalReleasePackage.isEmpty()) {
+ return new ResponseEntity<>(HttpStatus.NOT_FOUND);
+ }
+ ReleasePackage releasePackage = optionalReleasePackage.get();
+ authorizationChecker.checkCanEditReleasePackage(releasePackage);
+ String releasePackageType = (String) request.get("releasePackageType");
+ if (releasePackageType != null) {
+ releasePackage.setPermissionType(ReleasePermissionType.valueOf(releasePackageType));
+ }
+
+ if(releasePackage.getPermissionType() == ReleasePermissionType.ADMIN_STAFF_SELECTED_USERS) {
+ List users = (List) request.get("users");
+ if (users != null && !users.isEmpty()) {
+ users.forEach(user ->{
+ ReleasePackageAccess access = new ReleasePackageAccess();
+ access.setReleasePackageId(releasePackage.getReleasePackageId());
+ access.setUserId(Long.parseLong(user));
+ releasePackageAccessRepository.save(access);
+ });
+ }
+ }
+
+ releasePackageRepository.save(releasePackage);
+ return new ResponseEntity<>(releasePackage, HttpStatus.OK);
+ }
+
+ @PutMapping(value = Routes.RELEASE_PACKAGES_PERMISSION, produces = MediaType.APPLICATION_JSON_VALUE)
+ @RolesAllowed(AuthoritiesConstants.ADMIN)
+ @Timed
+ public ResponseEntity updateReleasePackagesType(@RequestBody Map request) {
+ releasePackageService.updateReleasePackagesPermission(request);
+ return new ResponseEntity<>(HttpStatus.OK);
+ }
+
+ @PostMapping(value = Routes.RELEASE_PACKAGES_MASTER_PERMISSION, produces = MediaType.APPLICATION_JSON_VALUE)
+ @RolesAllowed(AuthoritiesConstants.ADMIN)
+ @Timed
+ public ResponseEntity updateReleaseMasterConfig(@RequestBody Map request) {
+ try {
+ releasePackageService.updateReleaseMasterConfig(request);
+ return new ResponseEntity<>(HttpStatus.OK);
+ } catch (RuntimeException e) {
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
+ }
+ }
+
+
+ @GetMapping(value = "/api/releasePermission", produces = MediaType.APPLICATION_JSON_VALUE)
+ @RolesAllowed(AuthoritiesConstants.ADMIN)
+ public ResponseEntity> getReleasePermissions() {
+ List permissionDTOList = releasePackageRepository.findAll().stream()
+ .filter(releasePackage -> releasePackage.getPermissionType() != ReleasePermissionType.NOT_SELECTED)
+ .map(releasePackage -> new ReleasePermissionRequestDTO(
+ releasePackage.getReleasePackageId(),
+ releasePackage.getName(),
+ releasePackage.getPermissionType())
+ )
+ .toList();
+
+ return ResponseEntity.ok(permissionDTOList);
+ }
+
+
+ @GetMapping(value = "/api/masterReleasePermission", produces = MediaType.APPLICATION_JSON_VALUE)
+ @RolesAllowed(AuthoritiesConstants.ADMIN)
+ public ResponseEntity> getMasterReleasePermissions() {
+ List