package ca.intelliware.ihtsdo.mlds.web.rest; import java.util.Collection; import java.util.List; import javax.annotation.Resource; import javax.annotation.security.RolesAllowed; import javax.transaction.Transactional; import org.apache.commons.lang.Validate; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import ca.intelliware.ihtsdo.mlds.domain.Affiliate; import ca.intelliware.ihtsdo.mlds.domain.AffiliateType; import ca.intelliware.ihtsdo.mlds.domain.ApprovalState; import ca.intelliware.ihtsdo.mlds.domain.CommercialUsage; import ca.intelliware.ihtsdo.mlds.domain.CommercialUsageCountry; import ca.intelliware.ihtsdo.mlds.domain.CommercialUsageEntry; import ca.intelliware.ihtsdo.mlds.domain.CommercialUsagePeriod; import ca.intelliware.ihtsdo.mlds.domain.UsageContext; import ca.intelliware.ihtsdo.mlds.domain.UsageReportState; import ca.intelliware.ihtsdo.mlds.repository.AffiliateRepository; import ca.intelliware.ihtsdo.mlds.repository.CommercialUsageCountryRepository; import ca.intelliware.ihtsdo.mlds.repository.CommercialUsageEntryRepository; import ca.intelliware.ihtsdo.mlds.repository.CommercialUsageRepository; import ca.intelliware.ihtsdo.mlds.security.AuthoritiesConstants; import ca.intelliware.ihtsdo.mlds.service.ApprovalTransition; import ca.intelliware.ihtsdo.mlds.service.CommercialUsageAuditEvents; import ca.intelliware.ihtsdo.mlds.service.CommercialUsageAuthorizationChecker; import ca.intelliware.ihtsdo.mlds.service.CommercialUsageResetter; import ca.intelliware.ihtsdo.mlds.service.CommercialUsageService; import ca.intelliware.ihtsdo.mlds.service.UsageReportTransition; import com.codahale.metrics.annotation.Timed; import com.google.common.base.Objects; import com.google.common.collect.Lists; @RestController public class CommercialUsageResource { private static final String FILTER_STATE_SUBMITTED = "approvalState/not submitted eq false"; @Resource CommercialUsageRepository commercialUsageRepository; @Resource CommercialUsageEntryRepository commercialUsageEntryRepository; @Resource CommercialUsageCountryRepository commercialUsageCountryRepository; @Resource AffiliateRepository affiliateRepository; @Resource CommercialUsageAuthorizationChecker authorizationChecker; @Resource CommercialUsageResetter commercialUsageResetter; @Resource CommercialUsageAuditEvents commercialUsageAuditEvents; @Resource CommercialUsageService commercialUsageService; @RequestMapping(value = Routes.USAGE_REPORTS, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) @RolesAllowed({ AuthoritiesConstants.USER, AuthoritiesConstants.STAFF, AuthoritiesConstants.ADMIN }) @Timed public @ResponseBody ResponseEntity<Collection<CommercialUsage>> getUsageReports(@PathVariable long affiliateId) { Affiliate affiliate = affiliateRepository.findOne(affiliateId); authorizationChecker.checkCanAccessAffiliate(affiliate); if (affiliate == null) { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } return new ResponseEntity<Collection<CommercialUsage>>(affiliate.getCommercialUsages(), HttpStatus.OK); } @RequestMapping(value = Routes.USAGE_REPORTS_ALL, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) @RolesAllowed({AuthoritiesConstants.STAFF, AuthoritiesConstants.ADMIN }) @Timed public @ResponseBody ResponseEntity<Collection<CommercialUsage>> getAllUsageReports(@RequestParam(value="$filter") String filter) { Collection<CommercialUsage> usageReports = null; if (filter == null) { usageReports = commercialUsageRepository.findAll(); } else { if (Objects.equal(filter, FILTER_STATE_SUBMITTED)) { usageReports = commercialUsageRepository.findByNotStateAndEffectiveToIsNull(UsageReportState.NOT_SUBMITTED); } else { return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } } return new ResponseEntity<Collection<CommercialUsage>>(usageReports, HttpStatus.OK); } public static class CommercialUsageTransitionMessage { UsageReportTransition transition; public UsageReportTransition getTransition() { return transition; } public void setTransition(UsageReportTransition transition) { this.transition = transition; } } /** * Start a new submission * @param affiliateId * @param submissionPeriod * @return the new CommercialUsage or an existing CommercialUsage with matching date period */ @Transactional @RequestMapping(value = Routes.USAGE_REPORTS, method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) @RolesAllowed({ AuthoritiesConstants.USER, AuthoritiesConstants.ADMIN }) @Timed public @ResponseBody ResponseEntity<CommercialUsage> createNewSubmission(@PathVariable long affiliateId, @RequestBody CommercialUsagePeriod submissionPeriod) { Affiliate affiliate = affiliateRepository.findOne(affiliateId); authorizationChecker.checkCanAccessAffiliate(affiliate); if (affiliate == null) { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } CommercialUsage commercialUsage = null; List<CommercialUsage> commercialUsages = commercialUsageRepository.findActiveBySamePeriod(affiliate, submissionPeriod.getStartDate(), submissionPeriod.getEndDate()); if (commercialUsages.size() > 0) { // Return the existing commercial usage unmodified commercialUsage = commercialUsages.get(0); return new ResponseEntity<CommercialUsage>(commercialUsage, HttpStatus.OK); } else { commercialUsages = commercialUsageRepository.findActiveByMostRecentPeriod(affiliate); if (commercialUsages.size() > 0) { commercialUsage = commercialUsages.get(0); } } if (commercialUsage == null) { commercialUsage = new CommercialUsage(); commercialUsage.setType(affiliate.getType()); } commercialUsageResetter.detachAndReset(commercialUsage, submissionPeriod.getStartDate(), submissionPeriod.getEndDate()); commercialUsage = commercialUsageRepository.save(commercialUsage); affiliate.addCommercialUsage(commercialUsage); commercialUsageAuditEvents.logCreationOf(commercialUsage); ResponseEntity<CommercialUsage> responseEntity = new ResponseEntity<CommercialUsage>(commercialUsage, HttpStatus.OK); return responseEntity; } @RequestMapping(value = Routes.USAGE_REPORT, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) @RolesAllowed({ AuthoritiesConstants.USER, AuthoritiesConstants.STAFF, AuthoritiesConstants.ADMIN }) @Timed public @ResponseBody ResponseEntity<CommercialUsage> getCommercialUsageReport(@PathVariable long commercialUsageId) { authorizationChecker.checkCanAccessUsageReport(commercialUsageId); CommercialUsage commercialUsage = commercialUsageRepository.findOne(commercialUsageId); if (commercialUsage == null) { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } return new ResponseEntity<CommercialUsage>(commercialUsage, HttpStatus.OK); } @RequestMapping(value = Routes.USAGE_REPORT_CONTEXT, method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_VALUE) @RolesAllowed({ AuthoritiesConstants.USER, AuthoritiesConstants.ADMIN }) @Timed public @ResponseBody ResponseEntity<UsageContext> updateCommercialUsageContext(@PathVariable long commercialUsageId, @RequestBody UsageContext context) { authorizationChecker.checkCanAccessUsageReport(commercialUsageId); CommercialUsage commercialUsage = commercialUsageRepository.findOne(commercialUsageId); if (commercialUsage == null) { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } commercialUsage.setContext(context); commercialUsage = commercialUsageRepository.save(commercialUsage); return new ResponseEntity<UsageContext>(commercialUsage.getContext(), HttpStatus.OK); } @RequestMapping(value = Routes.USAGE_REPORT_TYPE, method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_VALUE) @RolesAllowed({ AuthoritiesConstants.USER, AuthoritiesConstants.ADMIN }) @Timed public @ResponseBody ResponseEntity<UsageContext> updateCommercialUsageType(@PathVariable long commercialUsageId, @PathVariable AffiliateType type) { authorizationChecker.checkCanAccessUsageReport(commercialUsageId); CommercialUsage commercialUsage = commercialUsageRepository.findOne(commercialUsageId); if (commercialUsage == null) { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } commercialUsage.setType(type); commercialUsage = commercialUsageRepository.save(commercialUsage); return new ResponseEntity<UsageContext>(commercialUsage.getContext(), HttpStatus.OK); } @Transactional @RequestMapping(value = Routes.USAGE_REPORT_APPROVAL, method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) @RolesAllowed({ AuthoritiesConstants.USER, AuthoritiesConstants.STAFF, AuthoritiesConstants.ADMIN}) @Timed public @ResponseBody ResponseEntity<CommercialUsage> transitionCommercialUsageApproval(@PathVariable("commercialUsageId") long commercialUsageId, @RequestBody CommercialUsageTransitionMessage applyTransition) { authorizationChecker.checkCanAccessUsageReport(commercialUsageId); CommercialUsage commercialUsage = commercialUsageRepository.findOne(commercialUsageId); if (commercialUsage == null) { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } commercialUsage = commercialUsageService.transitionCommercialUsageApproval(commercialUsage, applyTransition.getTransition()); return new ResponseEntity<CommercialUsage>(commercialUsage, HttpStatus.OK); } @Transactional @RequestMapping(value = Routes.USAGE_REPORT, method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) @RolesAllowed({ AuthoritiesConstants.USER, AuthoritiesConstants.ADMIN }) @Timed public @ResponseBody ResponseEntity<CommercialUsageEntry> addCommercialUsageEntry(@PathVariable("commercialUsageId") long commercialUsageId, @RequestBody CommercialUsageEntry newEntryValue) { authorizationChecker.checkCanAccessUsageReport(commercialUsageId); commercialUsageEntryRepository.save(newEntryValue); CommercialUsage commercialUsage = commercialUsageRepository.findOne(commercialUsageId); if (commercialUsage == null) { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } commercialUsage.addEntry(newEntryValue); HttpHeaders headers = new HttpHeaders(); // FIXME flush and get ids back //headers.setLocation(ServletUriComponentsBuilder.fromPath(Routes.USAGE_REPORT_ENTRY).build().expand(newEntry.getCommercialUsageEntryId()).toUri()); ResponseEntity<CommercialUsageEntry> responseEntity = new ResponseEntity<CommercialUsageEntry>(newEntryValue, headers, HttpStatus.CREATED); return responseEntity; } @RequestMapping(value = Routes.USAGE_REPORT_ENTRY, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) @RolesAllowed({ AuthoritiesConstants.USER, AuthoritiesConstants.STAFF, AuthoritiesConstants.ADMIN }) @Timed public @ResponseBody ResponseEntity<CommercialUsageEntry> getCommercialUsageEntry(@PathVariable("commercialUsageId") long commercialUsageId, @PathVariable("commercialUsageEntryId") long commercialUsageEntryId) { authorizationChecker.checkCanAccessCommercialUsageEntry(commercialUsageId, commercialUsageEntryId); CommercialUsageEntry commercialUserEntity = commercialUsageEntryRepository.findOne(commercialUsageEntryId); if (commercialUserEntity == null) { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } //FIXME should validate entry is part of usage report return new ResponseEntity<CommercialUsageEntry>(commercialUserEntity, HttpStatus.OK); } @Transactional @RequestMapping(value = Routes.USAGE_REPORT_ENTRY, method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_VALUE) @RolesAllowed({ AuthoritiesConstants.USER, AuthoritiesConstants.ADMIN }) @Timed public @ResponseBody ResponseEntity<CommercialUsageEntry> updateCommercialUsageEntry(@PathVariable("commercialUsageId") long commercialUsageId, @PathVariable("commercialUsageEntryId") long commercialUsageEntryId, @RequestBody CommercialUsageEntry newEntryValue) { authorizationChecker.checkCanAccessCommercialUsageEntry(commercialUsageId, commercialUsageEntryId); Validate.isTrue(newEntryValue.getCommercialUsageEntryId() != null && newEntryValue.getCommercialUsageEntryId() == commercialUsageEntryId,"Must include commercialUsageEntryId in message"); CommercialUsageEntry entry = commercialUsageEntryRepository.save(newEntryValue); CommercialUsage commercialUsage = commercialUsageRepository.findOne(commercialUsageId); if (commercialUsage == null) { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } commercialUsage.addEntry(entry); ResponseEntity<CommercialUsageEntry> responseEntity = new ResponseEntity<CommercialUsageEntry>(entry, HttpStatus.OK); return responseEntity; } @RequestMapping(value = Routes.USAGE_REPORT_ENTRY, method = RequestMethod.DELETE, produces = MediaType.APPLICATION_JSON_VALUE) @RolesAllowed({ AuthoritiesConstants.USER, AuthoritiesConstants.ADMIN }) @Timed public @ResponseBody ResponseEntity<?> deleteCommercialUsageEntry(@PathVariable("commercialUsageId") long commercialUsageId, @PathVariable("commercialUsageEntryId") long commercialUsageEntryId) { authorizationChecker.checkCanAccessCommercialUsageEntry(commercialUsageId, commercialUsageEntryId); commercialUsageEntryRepository.delete(commercialUsageEntryId); return new ResponseEntity<>(HttpStatus.OK); } /** * Delete a country record and in addition all entries associated with the same country * * @param commercialUsageId * @param commercialUsageCountId * @return */ @Transactional @RequestMapping(value = Routes.USAGE_REPORT_COUNTRY, method = RequestMethod.DELETE, produces = MediaType.APPLICATION_JSON_VALUE) @RolesAllowed({ AuthoritiesConstants.USER, AuthoritiesConstants.ADMIN }) @Timed public @ResponseBody ResponseEntity<?> deleteCommercialUsageCountry(@PathVariable("commercialUsageId") long commercialUsageId, @PathVariable("commercialUsageCountId") long commercialUsageCountId) { authorizationChecker.checkCanAccessCommercialUsageCount(commercialUsageId, commercialUsageCountId); CommercialUsageCountry commercialUsageCountry = commercialUsageCountryRepository.findOne(commercialUsageCountId); if (commercialUsageCountry == null) { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } CommercialUsage commercialUsage = commercialUsageRepository.findOne(commercialUsageId); if (commercialUsageCountry == null) { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } commercialUsageCountryRepository.delete(commercialUsageCountId); // Yes delete usage from this country, but only for the current usage report! List<CommercialUsageEntry> entries = commercialUsageEntryRepository.findByCountryAndCommercialUsage( commercialUsageCountry.getCountry(), commercialUsage); for (CommercialUsageEntry commercialUsageEntry : entries) { commercialUsageEntryRepository.delete(commercialUsageEntry); } return new ResponseEntity<>(HttpStatus.OK); } @Transactional @RequestMapping(value = Routes.USAGE_REPORT_COUNTRIES, method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) @RolesAllowed({ AuthoritiesConstants.USER, AuthoritiesConstants.ADMIN }) @Timed public @ResponseBody ResponseEntity<?> addCommercialUsageCountry(@PathVariable("commercialUsageId") long commercialUsageId, @RequestBody CommercialUsageCountry newCountValue) { authorizationChecker.checkCanAccessUsageReport(commercialUsageId); CommercialUsage commercialUsage = commercialUsageRepository.findOne(commercialUsageId); if (commercialUsage == null) { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } // MLDS-889 We're seeing duplicate country counts being created which I'm guessing happens when they come in without a primary key // but already exist in the database. I'll also sync this block, in case we're looking at double clicking. synchronized (commercialUsage) { // If this new Value is not known as already being in the database, check if we have anything for the same country if (newCountValue.getCommercialUsageCountId() == null && commercialUsage.exists(newCountValue)) { return new ResponseEntity<String>("Country already exists for this usage report.", HttpStatus.CONFLICT); } commercialUsageCountryRepository.save(newCountValue); commercialUsage.addCount(newCountValue); } HttpHeaders headers = new HttpHeaders(); // FIXME flush and get ids back //headers.setLocation(ServletUriComponentsBuilder.fromPath(Routes.USAGE_REPORT_ENTRY).build().expand(newEntry.getCommercialUsageEntryId()).toUri()); ResponseEntity<CommercialUsageCountry> responseEntity = new ResponseEntity<CommercialUsageCountry>(newCountValue, headers, HttpStatus.CREATED); return responseEntity; } private void synchronize() { // TODO Auto-generated method stub } @RequestMapping(value = Routes.USAGE_REPORT_COUNTRY, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) @RolesAllowed({ AuthoritiesConstants.USER, AuthoritiesConstants.STAFF, AuthoritiesConstants.ADMIN }) @Timed public @ResponseBody ResponseEntity<CommercialUsageCountry> getCommercialUsageCountry(@PathVariable("commercialUsageId") long commercialUsageId, @PathVariable("commercialUsageCountId") long commercialUsageCountId) { authorizationChecker.checkCanAccessCommercialUsageCount(commercialUsageId, commercialUsageCountId); CommercialUsageCountry commercialUsageCount = commercialUsageCountryRepository.findOne(commercialUsageCountId); if (commercialUsageCount == null) { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } return new ResponseEntity<CommercialUsageCountry>(commercialUsageCount, HttpStatus.OK); } @Transactional @RequestMapping(value = Routes.USAGE_REPORT_COUNTRY, method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_VALUE) @RolesAllowed({ AuthoritiesConstants.USER, AuthoritiesConstants.ADMIN }) @Timed public @ResponseBody ResponseEntity<CommercialUsageCountry> updateCommercialUsageCountry(@PathVariable("commercialUsageId") long commercialUsageId, @PathVariable("commercialUsageCountId") long commercialUsageCountId, @RequestBody CommercialUsageCountry newCountValue) { authorizationChecker.checkCanAccessCommercialUsageCount(commercialUsageId, commercialUsageCountId); Validate.isTrue(newCountValue.getCommercialUsageCountId() != null && newCountValue.getCommercialUsageCountId() == commercialUsageCountId, "Must include commercialUsageCountId in message"); // validate id not null? CommercialUsageCountry count = commercialUsageCountryRepository.save(newCountValue); CommercialUsage commercialUsage = commercialUsageRepository.findOne(commercialUsageId); if (commercialUsage == null) { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } commercialUsage.addCount(count); ResponseEntity<CommercialUsageCountry> responseEntity = new ResponseEntity<CommercialUsageCountry>(count, HttpStatus.OK); return responseEntity; } }