diff --git a/src/main/java/ubc/pavlab/rdp/Application.java b/src/main/java/ubc/pavlab/rdp/Application.java index 9f48a2fb..321e52ae 100644 --- a/src/main/java/ubc/pavlab/rdp/Application.java +++ b/src/main/java/ubc/pavlab/rdp/Application.java @@ -4,7 +4,6 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCaching; -import org.springframework.data.jpa.repository.config.EnableJpaAuditing; import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication diff --git a/src/main/java/ubc/pavlab/rdp/ResourceLoaderConfig.java b/src/main/java/ubc/pavlab/rdp/ResourceLoaderConfig.java index 505c2b00..0057c867 100644 --- a/src/main/java/ubc/pavlab/rdp/ResourceLoaderConfig.java +++ b/src/main/java/ubc/pavlab/rdp/ResourceLoaderConfig.java @@ -1,12 +1,8 @@ package ubc.pavlab.rdp; import lombok.extern.apachecommons.CommonsLog; -import org.springframework.beans.BeansException; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; import org.springframework.context.ResourceLoaderAware; import org.springframework.context.annotation.Configuration; -import org.springframework.context.support.GenericApplicationContext; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.ResourceLoader; import ubc.pavlab.rdp.util.PurlResolver; diff --git a/src/main/java/ubc/pavlab/rdp/ValidationConfig.java b/src/main/java/ubc/pavlab/rdp/ValidationConfig.java index 034cfdd1..4fedb6b4 100644 --- a/src/main/java/ubc/pavlab/rdp/ValidationConfig.java +++ b/src/main/java/ubc/pavlab/rdp/ValidationConfig.java @@ -8,6 +8,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.core.io.Resource; import org.springframework.http.converter.FormHttpMessageConverter; +import org.springframework.lang.Nullable; import org.springframework.web.client.RestTemplate; import ubc.pavlab.rdp.validation.*; @@ -27,8 +28,8 @@ public class ValidationConfig { @Bean public EmailValidator emailValidator( - @Value("${rdp.settings.allowed-email-domains}") List allowedEmailDomains, - @Value("${rdp.settings.allowed-email-domains-file}") Resource allowedEmailDomainsFile, + @Value("${rdp.settings.allowed-email-domains}") @Nullable List allowedEmailDomains, + @Value("${rdp.settings.allowed-email-domains-file}") @Nullable Resource allowedEmailDomainsFile, @Value("${rdp.settings.allowed-email-domains-file-refresh-delay}") @DurationUnit(ChronoUnit.SECONDS) Duration refreshDelay, @Value("${rdp.settings.allow-internationalized-email-domains}") boolean allowIdn ) throws IOException { List strategies = new ArrayList<>(); diff --git a/src/main/java/ubc/pavlab/rdp/WebSecurityConfig.java b/src/main/java/ubc/pavlab/rdp/WebSecurityConfig.java index b0e1a44b..e140cba2 100644 --- a/src/main/java/ubc/pavlab/rdp/WebSecurityConfig.java +++ b/src/main/java/ubc/pavlab/rdp/WebSecurityConfig.java @@ -25,7 +25,6 @@ import ubc.pavlab.rdp.security.authentication.TokenBasedAuthenticationManager; import ubc.pavlab.rdp.services.UserService; import ubc.pavlab.rdp.settings.ApplicationSettings; -import ubc.pavlab.rdp.settings.SiteSettings; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; @@ -63,9 +62,6 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserService userService; - @Autowired - private SiteSettings siteSettings; - @Override protected void configure( AuthenticationManagerBuilder auth ) throws Exception { auth.userDetailsService( userDetailsService ).passwordEncoder( bCryptPasswordEncoder ); diff --git a/src/main/java/ubc/pavlab/rdp/controllers/AdminController.java b/src/main/java/ubc/pavlab/rdp/controllers/AdminController.java index 377d95d2..5c8a35d5 100644 --- a/src/main/java/ubc/pavlab/rdp/controllers/AdminController.java +++ b/src/main/java/ubc/pavlab/rdp/controllers/AdminController.java @@ -148,7 +148,7 @@ public Object createServiceAccount( @Validated(User.ValidationServiceAccount.cla } @PostMapping(value = "/admin/users/{user}/roles") - public Object updateRoles( @PathVariable User user, @RequestParam(required = false) Set roles, RedirectAttributes redirectAttributes, Locale locale ) { + public Object updateRoles( @PathVariable User user, @RequestParam(required = false) @Nullable Set roles, RedirectAttributes redirectAttributes, Locale locale ) { if ( roles == null ) { roles = Collections.emptySet(); } @@ -176,7 +176,7 @@ public Object updateRoles( @PathVariable User user, @RequestParam(required = fal * Retrieve a user's details. */ @GetMapping(value = "/admin/users/{user}") - public Object getUser( @PathVariable(required = false) User user, @SuppressWarnings("unused") ConfirmEmailForm confirmEmailForm, Locale locale ) { + public Object getUser( @PathVariable(required = false) @Nullable User user, @SuppressWarnings("unused") ConfirmEmailForm confirmEmailForm, Locale locale ) { if ( user == null ) { return new ModelAndView( "error/404", HttpStatus.NOT_FOUND ) .addObject( "message", messageSource.getMessage( "AdminController.userNotFoundById", null, locale ) ); @@ -185,7 +185,7 @@ public Object getUser( @PathVariable(required = false) User user, @SuppressWarni } @PostMapping(value = "/admin/users/{user}/create-access-token") - public Object createAccessTokenForUser( @PathVariable(required = false) User user, RedirectAttributes redirectAttributes, Locale locale ) { + public Object createAccessTokenForUser( @PathVariable(required = false) @Nullable User user, RedirectAttributes redirectAttributes, Locale locale ) { if ( user == null ) { return new ModelAndView( "error/404", HttpStatus.NOT_FOUND ) .addObject( "message", messageSource.getMessage( "AdminController.userNotFoundById", null, locale ) ); @@ -196,7 +196,7 @@ public Object createAccessTokenForUser( @PathVariable(required = false) User use } @PostMapping(value = "/admin/users/{user}/revoke-access-token/{accessToken}") - public Object revokeAccessTn( @PathVariable(required = false) User user, @PathVariable(required = false) AccessToken accessToken, RedirectAttributes redirectAttributes, Locale locale ) { + public Object revokeAccessTn( @PathVariable(required = false) @Nullable User user, @PathVariable(required = false) @Nullable AccessToken accessToken, RedirectAttributes redirectAttributes, Locale locale ) { if ( user == null ) { return new ModelAndView( "error/404", HttpStatus.NOT_FOUND ) .addObject( "message", messageSource.getMessage( "AdminController.userNotFoundById", null, locale ) ); @@ -218,7 +218,7 @@ public static class ConfirmEmailForm { * Delete a given user. */ @DeleteMapping(value = "/admin/users/{user}") - public Object deleteUser( @PathVariable(required = false) User user, + public Object deleteUser( @PathVariable(required = false) @Nullable User user, @Valid ConfirmEmailForm confirmEmailForm, BindingResult bindingResult, Locale locale ) { if ( user == null ) { @@ -245,7 +245,7 @@ public ModelAndView getOntologies( @SuppressWarnings("unused") ImportOntologyFor } @GetMapping("/admin/ontologies/{ontology}") - public ModelAndView getOntology( @PathVariable(required = false) Ontology ontology, Locale locale ) { + public ModelAndView getOntology( @PathVariable(required = false) @Nullable Ontology ontology, Locale locale ) { if ( ontology == null ) { return new ModelAndView( "error/404", HttpStatus.NOT_FOUND ) .addObject( "message", messageSource.getMessage( "AdminController.ontologyNotFoundById", null, locale ) ); @@ -293,15 +293,17 @@ public static UpdateOntologyForm fromOntology( Ontology ontology ) { @Size(min = 1, max = Ontology.MAX_NAME_LENGTH) private String name; + @Nullable private String definition; + @Nullable private URL ontologyUrl; private boolean availableForGeneSearch; } @PostMapping("/admin/ontologies/{ontology}") - public ModelAndView updateOntology( @PathVariable(required = false) Ontology ontology, + public ModelAndView updateOntology( @PathVariable(required = false) @Nullable Ontology ontology, @Valid UpdateOntologyForm updateOntologyForm, BindingResult bindingResult, Locale locale ) { if ( ontology == null ) { @@ -337,7 +339,7 @@ public ModelAndView updateOntology( @PathVariable(required = false) Ontology ont } @DeleteMapping("/admin/ontologies/{ontology}") - public Object deleteOntology( @PathVariable(required = false) Ontology ontology, + public Object deleteOntology( @PathVariable(required = false) @Nullable Ontology ontology, @Valid DeleteOntologyForm deleteOntologyForm, BindingResult bindingResult, RedirectAttributes redirectAttributes, Locale locale ) { @@ -395,7 +397,7 @@ public Object createSimpleOntology( @SuppressWarnings("unused") ImportOntologyFo } @PostMapping("/admin/ontologies/{ontology}/update-simple-ontology") - public Object updateSimpleOntology( @PathVariable(required = false) Ontology ontology, + public Object updateSimpleOntology( @PathVariable(required = false) @Nullable Ontology ontology, @Valid SimpleOntologyForm simpleOntologyForm, BindingResult bindingResult, RedirectAttributes redirectAttributes, Locale locale ) { if ( ontology == null ) { @@ -483,6 +485,7 @@ public static SimpleOntologyTermForm emptyRow() { /** * Auto-generated if null or empty, which is why we allow zero as a size. */ + @Nullable @Size(max = OntologyTermInfo.MAX_TERM_ID_LENGTH, groups = RowNotEmpty.class) private String termId; @NotNull(groups = RowNotEmpty.class) @@ -631,7 +634,7 @@ public void initBinding2( WebDataBinder webDataBinder ) { } @PostMapping("/admin/ontologies/{ontology}/update") - public Object updateOntology( @PathVariable(required = false) Ontology ontology, + public Object updateOntology( @PathVariable(required = false) @Nullable Ontology ontology, RedirectAttributes redirectAttributes, Locale locale ) { if ( ontology == null ) { @@ -716,7 +719,12 @@ public Object importReactomePathways( RedirectAttributes redirectAttributes ) { @PostMapping("/admin/ontologies/{ontology}/update-reactome-pathways") public Object updateReactomePathways( @PathVariable(required = false) @Nullable Ontology ontology, RedirectAttributes redirectAttributes, Locale locale ) { // null-check is not necessary, but can save a database call - if ( ontology == null || !ontology.equals( reactomeService.findPathwaysOntology() ) ) { + if ( ontology == null ) { + return new ModelAndView( "error/404", HttpStatus.NOT_FOUND ) + .addObject( "message", messageSource.getMessage( "AdminController.ontologyNotFoundById", null, locale ) ); + } + Ontology reactome = reactomeService.findPathwaysOntology(); + if ( reactome == null || !reactome.equals( ontology ) ) { return new ModelAndView( "error/404", HttpStatus.NOT_FOUND ) .addObject( "message", messageSource.getMessage( "AdminController.ontologyNotFoundById", null, locale ) ); } @@ -821,7 +829,7 @@ public static class DeactivateOntologyForm extends ActivateOrDeactivateOntologyF } @PostMapping("/admin/ontologies/{ontology}/activate") - public Object activateOntology( @PathVariable(required = false) Ontology ontology, ActivateOntologyForm activateOntologyForm, RedirectAttributes redirectAttributes, Locale locale ) { + public Object activateOntology( @PathVariable(required = false) @Nullable Ontology ontology, ActivateOntologyForm activateOntologyForm, RedirectAttributes redirectAttributes, Locale locale ) { if ( ontology == null ) { return new ModelAndView( "error/404", HttpStatus.NOT_FOUND ) .addObject( "message", messageSource.getMessage( "AdminController.ontologyNotFoundById", null, locale ) ); @@ -833,7 +841,7 @@ public Object activateOntology( @PathVariable(required = false) Ontology ontolog } @PostMapping("/admin/ontologies/{ontology}/deactivate") - public Object deactivateOntology( @PathVariable(required = false) Ontology ontology, DeactivateOntologyForm deactivateOntologyForm, RedirectAttributes redirectAttributes, Locale locale ) { + public Object deactivateOntology( @PathVariable(required = false) @Nullable Ontology ontology, DeactivateOntologyForm deactivateOntologyForm, RedirectAttributes redirectAttributes, Locale locale ) { if ( ontology == null ) { return new ModelAndView( "error/404", HttpStatus.NOT_FOUND ) .addObject( "message", messageSource.getMessage( "AdminController.ontologyNotFoundById", null, locale ) ); @@ -890,7 +898,7 @@ public Object deactivateTerm( @PathVariable(required = false) Ontology ontology, return activateOrDeactivateTerm( ontology, deactivateTermForm, bindingResult, redirectAttributes, locale ); } - private Object activateOrDeactivateTerm( Ontology ontology, + private Object activateOrDeactivateTerm( @Nullable Ontology ontology, ActivateOrDeactivateTermForm activateOrDeactivateTermForm, BindingResult bindingResult, RedirectAttributes redirectAttributes, Locale locale ) { @@ -901,7 +909,7 @@ private Object activateOrDeactivateTerm( Ontology ontology, OntologyTermInfo ontologyTermInfo = null; if ( !bindingResult.hasFieldErrors( "ontologyTermInfoId" ) ) { - ontologyTermInfo = ontologyService.findTermByTermIdAndOntology( activateOrDeactivateTermForm.ontologyTermInfoId, ontology ); + ontologyTermInfo = ontologyService.findTermByTermIdAndOntology( activateOrDeactivateTermForm.ontologyTermInfoId, ontology ).orElse( null ); if ( ontologyTermInfo == null ) { bindingResult.rejectValue( "ontologyTermInfoId", "AdminController.ActivateOrDeactivateTermForm.unknownTermInOntology", new String[]{ activateOrDeactivateTermForm.getOntologyTermInfoId(), messageSource.getMessage( ontology.getResolvableTitle(), locale ) }, null ); @@ -953,7 +961,7 @@ private Object activateOrDeactivateTerm( Ontology ontology, * Provides the ontology in OBO format. */ @GetMapping(value = "/admin/ontologies/{ontology}/download", produces = "text/plain") - public ResponseEntity downloadOntology( @PathVariable(required = false) Ontology ontology, TimeZone timeZone ) { + public ResponseEntity downloadOntology( @PathVariable(required = false) @Nullable Ontology ontology, TimeZone timeZone ) { if ( ontology == null ) { return ResponseEntity.notFound().build(); } @@ -969,7 +977,7 @@ public ResponseEntity downloadOntology( @PathVariable(req @ResponseBody @GetMapping("/admin/ontologies/{ontology}/autocomplete-terms") - public Object autocompleteOntologyTerms( @PathVariable(required = false) Ontology ontology, @RequestParam String query, Locale locale ) { + public Object autocompleteOntologyTerms( @PathVariable(required = false) @Nullable Ontology ontology, @RequestParam String query, Locale locale ) { if ( ontology == null ) { return ResponseEntity.status( HttpStatus.NOT_FOUND ) .body( messageSource.getMessage( "AdminController.ontologyNotFoundById", null, locale ) ); @@ -993,7 +1001,7 @@ public ResponseEntity refreshMessages() { } @PostMapping("/admin/ontologies/{ontology}/move") - public Object move( @PathVariable(required = false) Ontology ontology, @RequestParam String direction, + public Object move( @PathVariable(required = false) @Nullable Ontology ontology, @RequestParam String direction, @SuppressWarnings("unused") ImportOntologyForm importOntologyForm, Locale locale ) { if ( ontology == null ) { diff --git a/src/main/java/ubc/pavlab/rdp/controllers/LoginController.java b/src/main/java/ubc/pavlab/rdp/controllers/LoginController.java index 7cb7cc22..89e8bb04 100644 --- a/src/main/java/ubc/pavlab/rdp/controllers/LoginController.java +++ b/src/main/java/ubc/pavlab/rdp/controllers/LoginController.java @@ -26,6 +26,7 @@ import ubc.pavlab.rdp.validation.Recaptcha; import ubc.pavlab.rdp.validation.RecaptchaValidator; +import javax.annotation.Nullable; import javax.servlet.http.HttpServletRequest; import java.util.List; import java.util.Locale; @@ -110,8 +111,8 @@ public ModelAndView registration() { @PostMapping("/registration") public ModelAndView createNewUser( @Validated(User.ValidationUserAccount.class) User user, BindingResult bindingResult, - @RequestParam(name = "g-recaptcha-response", required = false) String recaptchaResponse, - @RequestHeader(name = "X-Forwarded-For", required = false) List clientIp, + @RequestParam(name = "g-recaptcha-response", required = false) @Nullable String recaptchaResponse, + @RequestHeader(name = "X-Forwarded-For", required = false) @Nullable List clientIp, RedirectAttributes redirectAttributes, Locale locale ) { ModelAndView modelAndView = new ModelAndView( "registration" ); @@ -129,19 +130,10 @@ public ModelAndView createNewUser( @Validated(User.ValidationUserAccount.class) } User existingUser = userService.findUserByEmailNoAuth( user.getEmail() ); - - // profile can be missing of no profile.* fields have been set - if ( user.getProfile() == null ) { - user.setProfile( new Profile() ); - } - user.setEnabled( false ); // initialize a basic user profile Profile userProfile = user.getProfile(); - if ( userProfile == null ) { - userProfile = new Profile(); - } userProfile.setPrivacyLevel( privacyService.getDefaultPrivacyLevel() ); userProfile.setShared( applicationSettings.getPrivacy().isDefaultSharing() ); userProfile.setHideGenelist( false ); diff --git a/src/main/java/ubc/pavlab/rdp/controllers/PasswordController.java b/src/main/java/ubc/pavlab/rdp/controllers/PasswordController.java index a7c918a0..d6451548 100644 --- a/src/main/java/ubc/pavlab/rdp/controllers/PasswordController.java +++ b/src/main/java/ubc/pavlab/rdp/controllers/PasswordController.java @@ -22,6 +22,8 @@ import javax.validation.Valid; import java.util.Locale; +import static java.util.Objects.requireNonNull; + /** * Created by mjacobson on 23/01/18. */ @@ -103,7 +105,7 @@ public ModelAndView showChangePasswordPage( @RequestParam("id") int id, @Request } // Log in - User user = userService.findUserByIdNoAuth( id ); + User user = requireNonNull( userService.findUserByIdNoAuth( id ) ); UserPrinciple principle = new UserPrinciple( user ); Authentication auth = new UsernamePasswordAuthenticationToken( principle, null, principle.getAuthorities() ); SecurityContextHolder.getContext().setAuthentication( auth ); diff --git a/src/main/java/ubc/pavlab/rdp/controllers/SearchViewController.java b/src/main/java/ubc/pavlab/rdp/controllers/SearchViewController.java index 33dd4885..4b3f1259 100644 --- a/src/main/java/ubc/pavlab/rdp/controllers/SearchViewController.java +++ b/src/main/java/ubc/pavlab/rdp/controllers/SearchViewController.java @@ -264,8 +264,8 @@ public ModelAndView searchUsersByGeneView( @RequestParam String symbol, @GetMapping(value = "/search/view/orthologs") public ModelAndView searchOrthologsForGene( @RequestParam String symbol, @RequestParam Integer taxonId, - @RequestParam(required = false) Set tiers, - @RequestParam(required = false) Integer orthologTaxonId, + @RequestParam(required = false) @Nullable Set tiers, + @RequestParam(required = false) @Nullable Integer orthologTaxonId, Locale locale ) { // Only look for orthologs when taxon is human if ( taxonId != 9606 ) { @@ -324,7 +324,7 @@ public ModelAndView searchOrthologsForGene( @RequestParam String symbol, */ @PreAuthorize("hasPermission(null, 'international-search')") @GetMapping("/search/view/international/available-terms-by-partner") - public ModelAndView getAvailableTermsByPartner( @RequestParam(required = false) List ontologyTermIds ) { + public ModelAndView getAvailableTermsByPartner( @RequestParam(required = false) @Nullable List ontologyTermIds ) { if ( ontologyTermIds == null || ontologyTermIds.isEmpty() ) { return new ModelAndView( "fragments/error::message", HttpStatus.BAD_REQUEST ) .addObject( "errorMessage", "There must be at least one specified ontology term ID via 'ontologyTermIds'." ); diff --git a/src/main/java/ubc/pavlab/rdp/controllers/TermController.java b/src/main/java/ubc/pavlab/rdp/controllers/TermController.java index accf24cf..ee4e7ca7 100644 --- a/src/main/java/ubc/pavlab/rdp/controllers/TermController.java +++ b/src/main/java/ubc/pavlab/rdp/controllers/TermController.java @@ -3,21 +3,13 @@ import lombok.extern.apachecommons.CommonsLog; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; -import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; -import ubc.pavlab.rdp.model.GeneInfo; import ubc.pavlab.rdp.model.GeneOntologyTerm; import ubc.pavlab.rdp.model.GeneOntologyTermInfo; import ubc.pavlab.rdp.model.Taxon; import ubc.pavlab.rdp.services.GOService; import ubc.pavlab.rdp.services.TaxonService; -import ubc.pavlab.rdp.util.SearchResult; - -import java.util.Collection; -import java.util.Comparator; -import java.util.List; -import java.util.stream.Collectors; /** * Created by mjacobson on 18/01/18. diff --git a/src/main/java/ubc/pavlab/rdp/controllers/UserController.java b/src/main/java/ubc/pavlab/rdp/controllers/UserController.java index a92f278a..cab4d0d3 100644 --- a/src/main/java/ubc/pavlab/rdp/controllers/UserController.java +++ b/src/main/java/ubc/pavlab/rdp/controllers/UserController.java @@ -171,6 +171,7 @@ public static class SupportForm { @NotNull(message = "The message must be provided.") @Size(min = 1, message = "The message must not be empty.") private String message; + @Nullable private MultipartFile attachment; } @@ -359,7 +360,9 @@ static class ProfileSavedModel { @Data static class FieldErrorModel { private final String field; + @Nullable private final String message; + @Nullable private final Object rejectedValue; public static FieldErrorModel fromFieldError( FieldError fieldError ) { diff --git a/src/main/java/ubc/pavlab/rdp/events/OnRegistrationCompleteEvent.java b/src/main/java/ubc/pavlab/rdp/events/OnRegistrationCompleteEvent.java index b9e10ac9..e6fc04ae 100644 --- a/src/main/java/ubc/pavlab/rdp/events/OnRegistrationCompleteEvent.java +++ b/src/main/java/ubc/pavlab/rdp/events/OnRegistrationCompleteEvent.java @@ -2,7 +2,6 @@ import lombok.EqualsAndHashCode; import lombok.Getter; -import lombok.Setter; import org.springframework.context.ApplicationEvent; import ubc.pavlab.rdp.model.User; import ubc.pavlab.rdp.model.VerificationToken; diff --git a/src/main/java/ubc/pavlab/rdp/events/OnRequestAccessEvent.java b/src/main/java/ubc/pavlab/rdp/events/OnRequestAccessEvent.java index b804a5e0..a837298d 100644 --- a/src/main/java/ubc/pavlab/rdp/events/OnRequestAccessEvent.java +++ b/src/main/java/ubc/pavlab/rdp/events/OnRequestAccessEvent.java @@ -11,9 +11,9 @@ @EqualsAndHashCode(callSuper = false) public class OnRequestAccessEvent extends ApplicationEvent { - private User user; - private T object; - private String reason; + private final User user; + private final T object; + private final String reason; public OnRequestAccessEvent( User user, T object, String reason ) { super( user ); diff --git a/src/main/java/ubc/pavlab/rdp/listeners/UserListener.java b/src/main/java/ubc/pavlab/rdp/listeners/UserListener.java index 05d2e9f5..837994b6 100644 --- a/src/main/java/ubc/pavlab/rdp/listeners/UserListener.java +++ b/src/main/java/ubc/pavlab/rdp/listeners/UserListener.java @@ -2,9 +2,7 @@ import lombok.extern.apachecommons.CommonsLog; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; -import org.springframework.transaction.event.TransactionPhase; import org.springframework.transaction.event.TransactionalEventListener; import ubc.pavlab.rdp.events.OnContactEmailUpdateEvent; import ubc.pavlab.rdp.events.OnRegistrationCompleteEvent; diff --git a/src/main/java/ubc/pavlab/rdp/model/Gene.java b/src/main/java/ubc/pavlab/rdp/model/Gene.java index cad98756..e5e18f2b 100644 --- a/src/main/java/ubc/pavlab/rdp/model/Gene.java +++ b/src/main/java/ubc/pavlab/rdp/model/Gene.java @@ -6,6 +6,7 @@ import lombok.Setter; import lombok.ToString; import org.hibernate.annotations.NaturalId; +import org.springframework.lang.Nullable; import javax.persistence.*; import java.io.Serializable; @@ -42,5 +43,6 @@ public abstract class Gene implements Serializable { @JsonIgnore @Column(name = "modification_date") + @Nullable private LocalDate modificationDate; } diff --git a/src/main/java/ubc/pavlab/rdp/model/GeneInfo.java b/src/main/java/ubc/pavlab/rdp/model/GeneInfo.java index 0363ca0e..1a12aea0 100644 --- a/src/main/java/ubc/pavlab/rdp/model/GeneInfo.java +++ b/src/main/java/ubc/pavlab/rdp/model/GeneInfo.java @@ -4,7 +4,6 @@ import lombok.Getter; import javax.persistence.*; -import java.io.Serializable; import java.util.Comparator; import java.util.HashSet; import java.util.Set; diff --git a/src/main/java/ubc/pavlab/rdp/model/GeneOntologyTermInfo.java b/src/main/java/ubc/pavlab/rdp/model/GeneOntologyTermInfo.java index 0b8fffe0..a7321c24 100644 --- a/src/main/java/ubc/pavlab/rdp/model/GeneOntologyTermInfo.java +++ b/src/main/java/ubc/pavlab/rdp/model/GeneOntologyTermInfo.java @@ -1,17 +1,14 @@ package ubc.pavlab.rdp.model; import com.fasterxml.jackson.annotation.JsonIgnore; -import lombok.Data; import lombok.Getter; import lombok.Setter; import lombok.ToString; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; -import ubc.pavlab.rdp.model.enums.RelationshipType; import ubc.pavlab.rdp.services.GOService; import java.util.*; -import java.util.stream.Collectors; @Getter @Setter diff --git a/src/main/java/ubc/pavlab/rdp/model/Profile.java b/src/main/java/ubc/pavlab/rdp/model/Profile.java index cafcc688..33b07f90 100644 --- a/src/main/java/ubc/pavlab/rdp/model/Profile.java +++ b/src/main/java/ubc/pavlab/rdp/model/Profile.java @@ -9,6 +9,7 @@ import lombok.NoArgsConstructor; import org.hibernate.validator.constraints.Email; import org.hibernate.validator.constraints.URL; +import org.springframework.lang.Nullable; import ubc.pavlab.rdp.model.enums.PrivacyLevelType; import ubc.pavlab.rdp.model.enums.ResearcherCategory; import ubc.pavlab.rdp.model.enums.ResearcherPosition; @@ -55,6 +56,7 @@ public String getFullName() { @Lob @Column(name = "description", columnDefinition = "TEXT") + @Nullable private String description; @Column(name = "organization") @@ -66,6 +68,7 @@ public String getFullName() { @Column(name = "phone") private String phone; + @Nullable @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) @Email(message = "Your email address is not valid.") @Column(name = "contact_email") @@ -76,6 +79,7 @@ public String getFullName() { private boolean contactEmailVerified; @JsonIgnore + @Nullable @Column(name = "contact_email_verified_at") private Instant contactEmailVerifiedAt; @@ -83,6 +87,7 @@ public String getFullName() { @URL private String website; + @Nullable @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) @Enumerated(EnumType.ORDINAL) @Column(name = "privacy_level") @@ -102,6 +107,7 @@ public String getFullName() { @JoinColumn(name = "user_id") private final Set publications = new HashSet<>(); + @Nullable @Enumerated(EnumType.STRING) @Column(name = "researcher_position") private ResearcherPosition researcherPosition; diff --git a/src/main/java/ubc/pavlab/rdp/model/Taxon.java b/src/main/java/ubc/pavlab/rdp/model/Taxon.java index 4d54b9ea..555cb1a4 100644 --- a/src/main/java/ubc/pavlab/rdp/model/Taxon.java +++ b/src/main/java/ubc/pavlab/rdp/model/Taxon.java @@ -7,6 +7,7 @@ import org.hibernate.annotations.Immutable; import org.springframework.context.MessageSourceResolvable; import org.springframework.context.support.DefaultMessageSourceResolvable; +import org.springframework.lang.Nullable; import javax.persistence.*; import java.io.Serializable; @@ -43,6 +44,7 @@ public static Comparator getComparator() { private String commonName; + @Nullable @JsonIgnore private URL geneUrl; diff --git a/src/main/java/ubc/pavlab/rdp/model/User.java b/src/main/java/ubc/pavlab/rdp/model/User.java index 7639a7b4..2311f931 100644 --- a/src/main/java/ubc/pavlab/rdp/model/User.java +++ b/src/main/java/ubc/pavlab/rdp/model/User.java @@ -63,7 +63,7 @@ public static UserBuilder builder( Profile profile ) { public static Comparator getComparator() { return Comparator - .comparing( ( User u ) -> u.getProfile().getFullName() ) + .comparing( ( User u ) -> u.getProfile().getFullName(), Comparator.nullsLast( Comparator.naturalOrder() ) ) .thenComparing( User::getOriginUrl, Comparator.nullsLast( Comparator.naturalOrder() ) ) // at least one of the two must be non-null .thenComparing( User::getId, Comparator.nullsLast( Comparator.naturalOrder() ) ) @@ -140,15 +140,15 @@ public static Comparator getComparator() { private final Set passwordResetTokens = new HashSet<>(); @Valid - @NotNull @Embedded @JsonUnwrapped - private Profile profile; + private Profile profile = new Profile(); @Transient private String origin; @Transient + @Nullable private URI originUrl; /* Research related information */ @@ -258,7 +258,7 @@ public String getVerifiedContactEmailJsonValue() { @JsonIgnore @Transient public Optional getVerifiedAtContactEmail() { - if ( profile.isContactEmailVerified() ) { + if ( profile != null && profile.isContactEmailVerified() ) { return Optional.ofNullable( profile.getContactEmailVerifiedAt() ); } else if ( enabled ) { return Optional.ofNullable( enabledAt ); @@ -276,11 +276,13 @@ public Optional getOwner() { @Override @JsonProperty(value = "privacyLevel") public PrivacyLevelType getEffectivePrivacyLevel() { + // profile can be null when deserialized by Jackson + PrivacyLevelType privacyLevel = profile != null ? profile.getPrivacyLevel() : PrivacyLevelType.PRIVATE; // this is a fallback - if ( getProfile() == null || getProfile().getPrivacyLevel() == null ) { - log.warn( MessageFormat.format( "User {0} has no profile or a null privacy level defined in its profile.", this ) ); + if ( privacyLevel == null ) { + log.warn( MessageFormat.format( this + " has a null privacy level defined in its profile, defaulting to PRIVATE.", this ) ); return PrivacyLevelType.PRIVATE; } - return getProfile().getPrivacyLevel(); + return privacyLevel; } } diff --git a/src/main/java/ubc/pavlab/rdp/model/UserContent.java b/src/main/java/ubc/pavlab/rdp/model/UserContent.java index 0a22ec57..d0e79272 100644 --- a/src/main/java/ubc/pavlab/rdp/model/UserContent.java +++ b/src/main/java/ubc/pavlab/rdp/model/UserContent.java @@ -1,6 +1,5 @@ package ubc.pavlab.rdp.model; -import org.springframework.lang.NonNull; import ubc.pavlab.rdp.model.enums.PrivacyLevelType; import java.time.Instant; diff --git a/src/main/java/ubc/pavlab/rdp/model/UserGene.java b/src/main/java/ubc/pavlab/rdp/model/UserGene.java index a5290d1c..0dc51de5 100644 --- a/src/main/java/ubc/pavlab/rdp/model/UserGene.java +++ b/src/main/java/ubc/pavlab/rdp/model/UserGene.java @@ -142,12 +142,16 @@ public Optional getOwner() { @Override @JsonProperty("privacyLevel") public PrivacyLevelType getEffectivePrivacyLevel() { - PrivacyLevelType privacyLevel = getPrivacyLevel() != null ? getPrivacyLevel() : getUser().getProfile().getPrivacyLevel(); + PrivacyLevelType privacyLevel = getPrivacyLevel(); // the user can be null if it was deserialized by Jackson (see @JsonIgnore on user above) - if ( getUser() != null && privacyLevel.ordinal() > getUser().getEffectivePrivacyLevel().ordinal() ) { + PrivacyLevelType userPrivacyLevel = user != null ? getUser().getEffectivePrivacyLevel() : PrivacyLevelType.PRIVATE; + if ( privacyLevel == null ) { + privacyLevel = userPrivacyLevel; + } + if ( privacyLevel.ordinal() > userPrivacyLevel.ordinal() ) { log.warn( MessageFormat.format( "Gene privacy level {0} of {1} is looser than that of the user profile {2}, and will be capped to {3}.", - privacyLevel, this, getUser(), getUser().getEffectivePrivacyLevel() ) ); - return getUser().getEffectivePrivacyLevel(); + privacyLevel, this, user, userPrivacyLevel ) ); + privacyLevel = userPrivacyLevel; } return privacyLevel; } diff --git a/src/main/java/ubc/pavlab/rdp/model/enums/TierType.java b/src/main/java/ubc/pavlab/rdp/model/enums/TierType.java index e088fbe5..f4b38a1e 100644 --- a/src/main/java/ubc/pavlab/rdp/model/enums/TierType.java +++ b/src/main/java/ubc/pavlab/rdp/model/enums/TierType.java @@ -4,7 +4,6 @@ import lombok.Getter; import java.util.EnumSet; -import java.util.Set; /** * Created by mjacobson on 28/01/18. diff --git a/src/main/java/ubc/pavlab/rdp/model/enums/package-info.java b/src/main/java/ubc/pavlab/rdp/model/enums/package-info.java new file mode 100644 index 00000000..440e2a9b --- /dev/null +++ b/src/main/java/ubc/pavlab/rdp/model/enums/package-info.java @@ -0,0 +1,7 @@ +/** + * + */ +@NonNullApi +package ubc.pavlab.rdp.model.enums; + +import org.springframework.lang.NonNullApi; \ No newline at end of file diff --git a/src/main/java/ubc/pavlab/rdp/model/ontology/Ontology.java b/src/main/java/ubc/pavlab/rdp/model/ontology/Ontology.java index a769898f..2bb40352 100644 --- a/src/main/java/ubc/pavlab/rdp/model/ontology/Ontology.java +++ b/src/main/java/ubc/pavlab/rdp/model/ontology/Ontology.java @@ -7,6 +7,7 @@ import org.hibernate.annotations.LazyCollectionOption; import org.springframework.context.MessageSourceResolvable; import org.springframework.context.support.DefaultMessageSourceResolvable; +import org.springframework.lang.Nullable; import javax.persistence.*; import java.net.URL; @@ -65,6 +66,7 @@ public static Comparator getComparator() { @Lob @Column(columnDefinition = "TEXT") + @Nullable private String definition; /** @@ -101,6 +103,7 @@ public static Comparator getComparator() { * The only supported format for now is OBO. */ @JsonIgnore + @Nullable private URL ontologyUrl; /** @@ -155,6 +158,6 @@ public DefaultMessageSourceResolvable getResolvableTitle() { @JsonIgnore public DefaultMessageSourceResolvable getResolvableDefinition() { - return new DefaultMessageSourceResolvable( new String[]{ "rdp.ontologies." + name + ".definition" }, definition ); + return new DefaultMessageSourceResolvable( new String[]{ "rdp.ontologies." + name + ".definition" }, null, definition ); } } diff --git a/src/main/java/ubc/pavlab/rdp/model/ontology/OntologyTermInfo.java b/src/main/java/ubc/pavlab/rdp/model/ontology/OntologyTermInfo.java index 73ae4f81..c260dff4 100644 --- a/src/main/java/ubc/pavlab/rdp/model/ontology/OntologyTermInfo.java +++ b/src/main/java/ubc/pavlab/rdp/model/ontology/OntologyTermInfo.java @@ -9,6 +9,7 @@ import org.hibernate.annotations.SortComparator; import org.springframework.context.MessageSourceResolvable; import org.springframework.context.support.DefaultMessageSourceResolvable; +import org.springframework.lang.Nullable; import javax.persistence.*; import java.text.Collator; @@ -103,6 +104,7 @@ public int compare( String a, String b ) { @Lob @Column(columnDefinition = "TEXT") + @Nullable private String definition; /** @@ -138,6 +140,7 @@ public int compare( String a, String b ) { */ @JsonIgnore @Column + @Nullable private Integer ordering; /** @@ -214,6 +217,6 @@ public int compareTo( OntologyTermInfo ontologyTermInfo ) { @Override @JsonIgnore public DefaultMessageSourceResolvable getResolvableDefinition() { - return new DefaultMessageSourceResolvable( new String[]{ "rdp.ontologies." + getOntology().getName() + ".terms." + getName() + ".definition" }, definition ); + return new DefaultMessageSourceResolvable( new String[]{ "rdp.ontologies." + getOntology().getName() + ".terms." + getName() + ".definition" }, null, definition ); } } diff --git a/src/main/java/ubc/pavlab/rdp/model/ontology/package-info.java b/src/main/java/ubc/pavlab/rdp/model/ontology/package-info.java new file mode 100644 index 00000000..9d99120c --- /dev/null +++ b/src/main/java/ubc/pavlab/rdp/model/ontology/package-info.java @@ -0,0 +1,7 @@ +/** + * + */ +@NonNullApi +package ubc.pavlab.rdp.model.ontology; + +import org.springframework.lang.NonNullApi; \ No newline at end of file diff --git a/src/main/java/ubc/pavlab/rdp/ontology/resolvers/OntobeeResolver.java b/src/main/java/ubc/pavlab/rdp/ontology/resolvers/OntobeeResolver.java index 62ab1af1..04b5531f 100644 --- a/src/main/java/ubc/pavlab/rdp/ontology/resolvers/OntobeeResolver.java +++ b/src/main/java/ubc/pavlab/rdp/ontology/resolvers/OntobeeResolver.java @@ -21,7 +21,7 @@ public class OntobeeResolver implements OntologyResolver { @Override public boolean accepts( Ontology ontology ) { - return ontology.getOntologyUrl().toExternalForm().startsWith( DEFAULT_IRI_PREFIX ); + return ontology.getOntologyUrl() != null && ontology.getOntologyUrl().toExternalForm().startsWith( DEFAULT_IRI_PREFIX ); } @Override diff --git a/src/main/java/ubc/pavlab/rdp/ontology/resolvers/ReactomeResolver.java b/src/main/java/ubc/pavlab/rdp/ontology/resolvers/ReactomeResolver.java index fd7fd7a1..eaf27026 100644 --- a/src/main/java/ubc/pavlab/rdp/ontology/resolvers/ReactomeResolver.java +++ b/src/main/java/ubc/pavlab/rdp/ontology/resolvers/ReactomeResolver.java @@ -23,7 +23,8 @@ public class ReactomeResolver implements OntologyResolver { @Override public boolean accepts( Ontology ontology ) { - return ontology.equals( reactomeService.findPathwaysOntology() ); + Ontology reactome = reactomeService.findPathwaysOntology(); + return reactome != null && reactome.equals( ontology ); } @Override diff --git a/src/main/java/ubc/pavlab/rdp/repositories/AccessTokenRepository.java b/src/main/java/ubc/pavlab/rdp/repositories/AccessTokenRepository.java index 77045999..ec0e7302 100644 --- a/src/main/java/ubc/pavlab/rdp/repositories/AccessTokenRepository.java +++ b/src/main/java/ubc/pavlab/rdp/repositories/AccessTokenRepository.java @@ -4,8 +4,10 @@ import org.springframework.stereotype.Repository; import ubc.pavlab.rdp.model.AccessToken; +import java.util.Optional; + @Repository public interface AccessTokenRepository extends JpaRepository { - AccessToken findByToken( String token ); + Optional findByToken( String token ); } diff --git a/src/main/java/ubc/pavlab/rdp/repositories/GeneInfoRepository.java b/src/main/java/ubc/pavlab/rdp/repositories/GeneInfoRepository.java index cff84890..cedcfa8a 100644 --- a/src/main/java/ubc/pavlab/rdp/repositories/GeneInfoRepository.java +++ b/src/main/java/ubc/pavlab/rdp/repositories/GeneInfoRepository.java @@ -3,29 +3,26 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import org.springframework.lang.Nullable; import org.springframework.stereotype.Repository; import ubc.pavlab.rdp.model.GeneInfo; import ubc.pavlab.rdp.model.Taxon; import java.util.Collection; +import java.util.Optional; @Repository public interface GeneInfoRepository extends JpaRepository { - @Nullable - GeneInfo findByGeneId( Integer geneId ); + Optional findByGeneId( Integer geneId ); Collection findAllByGeneIdIn( Collection geneIds ); @Query("select gene from GeneInfo gene left join fetch gene.orthologs where gene.geneId in :geneIds") Collection findAllByGeneIdWithOrthologs( @Param("geneIds") Collection geneIds ); - @Nullable - GeneInfo findByGeneIdAndTaxon( Integer geneId, Taxon taxon ); + Optional findByGeneIdAndTaxon( Integer geneId, Taxon taxon ); - @Nullable - GeneInfo findBySymbolAndTaxon( String symbol, Taxon taxon ); + Optional findBySymbolAndTaxon( String symbol, Taxon taxon ); Collection findBySymbolInAndTaxon( Collection symbols, Taxon taxon ); @@ -37,7 +34,5 @@ public interface GeneInfoRepository extends JpaRepository { Collection findAllByAliasesContainingIgnoreCaseAndTaxon( String query, Taxon taxon ); - Collection findAllByTaxonActiveTrue(); - long countByTaxon( Taxon taxon ); } diff --git a/src/main/java/ubc/pavlab/rdp/repositories/OrganInfoRepository.java b/src/main/java/ubc/pavlab/rdp/repositories/OrganInfoRepository.java index 219bc795..d713e812 100644 --- a/src/main/java/ubc/pavlab/rdp/repositories/OrganInfoRepository.java +++ b/src/main/java/ubc/pavlab/rdp/repositories/OrganInfoRepository.java @@ -5,11 +5,12 @@ import ubc.pavlab.rdp.model.OrganInfo; import java.util.Collection; +import java.util.Optional; @Repository public interface OrganInfoRepository extends JpaRepository { - OrganInfo findByUberonId( String id ); + Optional findByUberonId( String id ); Collection findByActiveTrueOrderByOrdering(); diff --git a/src/main/java/ubc/pavlab/rdp/repositories/PasswordResetTokenRepository.java b/src/main/java/ubc/pavlab/rdp/repositories/PasswordResetTokenRepository.java index 87c2320b..269b4e80 100644 --- a/src/main/java/ubc/pavlab/rdp/repositories/PasswordResetTokenRepository.java +++ b/src/main/java/ubc/pavlab/rdp/repositories/PasswordResetTokenRepository.java @@ -3,16 +3,16 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; -import org.springframework.lang.Nullable; import org.springframework.stereotype.Repository; import ubc.pavlab.rdp.model.PasswordResetToken; import java.time.Instant; +import java.util.Optional; @Repository public interface PasswordResetTokenRepository extends JpaRepository { - @Nullable - PasswordResetToken findByToken( String token ); + + Optional findByToken( String token ); @Modifying @Query("delete from PasswordResetToken t where t.expiryDate <= :since") diff --git a/src/main/java/ubc/pavlab/rdp/repositories/RoleRepository.java b/src/main/java/ubc/pavlab/rdp/repositories/RoleRepository.java index 751a6094..678b5c8a 100644 --- a/src/main/java/ubc/pavlab/rdp/repositories/RoleRepository.java +++ b/src/main/java/ubc/pavlab/rdp/repositories/RoleRepository.java @@ -1,16 +1,16 @@ package ubc.pavlab.rdp.repositories; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.lang.Nullable; import org.springframework.stereotype.Repository; import ubc.pavlab.rdp.model.Role; +import java.util.Optional; + /** * Created by mjacobson on 16/01/18. */ @Repository public interface RoleRepository extends JpaRepository { - @Nullable - Role findByRole( String role ); + Optional findByRole( String role ); } \ No newline at end of file diff --git a/src/main/java/ubc/pavlab/rdp/repositories/TaxonRepository.java b/src/main/java/ubc/pavlab/rdp/repositories/TaxonRepository.java index 45daa0c3..5cb3d08b 100644 --- a/src/main/java/ubc/pavlab/rdp/repositories/TaxonRepository.java +++ b/src/main/java/ubc/pavlab/rdp/repositories/TaxonRepository.java @@ -13,6 +13,7 @@ public interface TaxonRepository extends JpaRepository { @QueryHints(@QueryHint(name = "org.hibernate.cacheable", value = "true")) List findByActiveTrue(); + @QueryHints(@QueryHint(name = "org.hibernate.cacheable", value = "true")) List findByActiveTrueOrderByOrdering(); } diff --git a/src/main/java/ubc/pavlab/rdp/repositories/UserGeneRepository.java b/src/main/java/ubc/pavlab/rdp/repositories/UserGeneRepository.java index f1b6e5e2..fbbba932 100644 --- a/src/main/java/ubc/pavlab/rdp/repositories/UserGeneRepository.java +++ b/src/main/java/ubc/pavlab/rdp/repositories/UserGeneRepository.java @@ -15,6 +15,7 @@ import javax.persistence.QueryHint; import java.util.Collection; +import java.util.Optional; import java.util.Set; @Repository @@ -55,7 +56,7 @@ public interface UserGeneRepository extends JpaRepository { Page findByPrivacyLevelAndUserEnabledTrueAndUserProfilePrivacyLevel( @Param("privacyLevel") PrivacyLevelType privacyLevel, @Nullable Pageable pageable ); @QueryHints(@QueryHint(name = "org.hibernate.cacheable", value = "true")) - UserGene findById( int id ); + Optional findById( int id ); @QueryHints(@QueryHint(name = "org.hibernate.cacheable", value = "true")) Collection findByGeneId( int geneId ); @@ -75,7 +76,7 @@ public interface UserGeneRepository extends JpaRepository { @QueryHints(@QueryHint(name = "org.hibernate.cacheable", value = "true")) Collection findBySymbolContainingIgnoreCaseAndTaxonAndTierIn( String symbolContaining, Taxon taxon, Set tiers ); - UserGene findBySymbolAndTaxon( String symbol, Taxon taxon ); + Optional findBySymbolAndTaxon( String symbol, Taxon taxon ); /** * Find all user genes ortholog to a given gene. diff --git a/src/main/java/ubc/pavlab/rdp/repositories/UserRepository.java b/src/main/java/ubc/pavlab/rdp/repositories/UserRepository.java index bdf3180b..8db2b504 100644 --- a/src/main/java/ubc/pavlab/rdp/repositories/UserRepository.java +++ b/src/main/java/ubc/pavlab/rdp/repositories/UserRepository.java @@ -13,8 +13,8 @@ import javax.persistence.QueryHint; import java.util.Collection; -import java.util.Optional; import java.util.List; +import java.util.Optional; @Repository public interface UserRepository extends JpaRepository { @@ -39,7 +39,7 @@ public interface UserRepository extends JpaRepository { Page findByEnabledTrueAndProfilePrivacyLevel( PrivacyLevelType privacyLevel, Pageable pageable ); @Query("select user from User user left join fetch user.roles where lower(user.email) = lower(:email)") - User findByEmailIgnoreCase( @Param("email") String email ); + Optional findByEmailIgnoreCase( @Param("email") String email ); @QueryHints(@QueryHint(name = "org.hibernate.cacheable", value = "true")) @Query("select u from User u where u.profile.lastName is not NULL and u.profile.lastName <> '' and u.profile.privacyLevel >= :privacyLevel") diff --git a/src/main/java/ubc/pavlab/rdp/repositories/VerificationTokenRepository.java b/src/main/java/ubc/pavlab/rdp/repositories/VerificationTokenRepository.java index be0210e9..035d863a 100644 --- a/src/main/java/ubc/pavlab/rdp/repositories/VerificationTokenRepository.java +++ b/src/main/java/ubc/pavlab/rdp/repositories/VerificationTokenRepository.java @@ -3,16 +3,16 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; -import org.springframework.lang.Nullable; import org.springframework.stereotype.Repository; import ubc.pavlab.rdp.model.VerificationToken; import java.time.Instant; +import java.util.Optional; @Repository public interface VerificationTokenRepository extends JpaRepository { - @Nullable - VerificationToken findByToken( String token ); + + Optional findByToken( String token ); @Modifying @Query("delete from VerificationToken t where t.expiryDate <= :since") diff --git a/src/main/java/ubc/pavlab/rdp/repositories/ontology/OntologyRepository.java b/src/main/java/ubc/pavlab/rdp/repositories/ontology/OntologyRepository.java index e9f56f8a..9632e927 100644 --- a/src/main/java/ubc/pavlab/rdp/repositories/ontology/OntologyRepository.java +++ b/src/main/java/ubc/pavlab/rdp/repositories/ontology/OntologyRepository.java @@ -8,6 +8,7 @@ import ubc.pavlab.rdp.model.ontology.Ontology; import java.util.List; +import java.util.Optional; /** * @author poirigui @@ -21,9 +22,9 @@ public interface OntologyRepository extends JpaRepository { List findAllByNameIn( List asList ); - Ontology findByName( String name ); + Optional findByName( String name ); - Ontology findByNameAndActiveTrue( String name ); + Optional findByNameAndActiveTrue( String name ); boolean existsByName( String name ); diff --git a/src/main/java/ubc/pavlab/rdp/repositories/ontology/OntologyTermInfoRepository.java b/src/main/java/ubc/pavlab/rdp/repositories/ontology/OntologyTermInfoRepository.java index 8580a350..c5405bc0 100644 --- a/src/main/java/ubc/pavlab/rdp/repositories/ontology/OntologyTermInfoRepository.java +++ b/src/main/java/ubc/pavlab/rdp/repositories/ontology/OntologyTermInfoRepository.java @@ -15,6 +15,7 @@ import java.io.Reader; import java.util.Collection; import java.util.List; +import java.util.Optional; import java.util.Set; /** @@ -25,7 +26,7 @@ @Repository public interface OntologyTermInfoRepository extends JpaRepository { - OntologyTermInfo findByTermIdAndOntology( String ontologyTermInfoId, Ontology ontology ); + Optional findByTermIdAndOntology( String ontologyTermInfoId, Ontology ontology ); List findAllByActiveTrueAndIdIn( Collection ids ); @@ -178,14 +179,14 @@ public interface OntologyTermInfoRepository extends JpaRepository findSubTermsIdsByTermIdIn( @Param("termIds") Set termIds ); - OntologyTermInfo findByTermIdAndOntologyName( String termId, String ontologyName ); + Optional findByTermIdAndOntologyName( String termId, String ontologyName ); /** * Retrieve the definition of an ontology. */ @QueryHints(@QueryHint(name = "org.hibernate.cacheable", value = "true")) @Query("select o.definition from Ontology o where o.name = :ontologyName") - String findDefinitionByOntologyName( @Param("ontologyName") String ontologyName ); + Optional findDefinitionByOntologyName( @Param("ontologyName") String ontologyName ); /** * Retrieve all the definitions matching an term name and its corresponding ontology name. diff --git a/src/main/java/ubc/pavlab/rdp/repositories/ontology/package-info.java b/src/main/java/ubc/pavlab/rdp/repositories/ontology/package-info.java new file mode 100644 index 00000000..0790a608 --- /dev/null +++ b/src/main/java/ubc/pavlab/rdp/repositories/ontology/package-info.java @@ -0,0 +1,7 @@ +/** + * + */ +@NonNullApi +package ubc.pavlab.rdp.repositories.ontology; + +import org.springframework.lang.NonNullApi; \ No newline at end of file diff --git a/src/main/java/ubc/pavlab/rdp/security/PermissionEvaluatorImpl.java b/src/main/java/ubc/pavlab/rdp/security/PermissionEvaluatorImpl.java index d041d5cc..52baa9f8 100644 --- a/src/main/java/ubc/pavlab/rdp/security/PermissionEvaluatorImpl.java +++ b/src/main/java/ubc/pavlab/rdp/security/PermissionEvaluatorImpl.java @@ -2,6 +2,7 @@ import lombok.extern.apachecommons.CommonsLog; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.lang.Nullable; import org.springframework.security.access.PermissionEvaluator; import org.springframework.security.authentication.AnonymousAuthenticationToken; import org.springframework.security.core.Authentication; @@ -25,7 +26,7 @@ public class PermissionEvaluatorImpl implements PermissionEvaluator { private UserPrivacyService privacyService; @Override - public boolean hasPermission( Authentication authentication, Object targetDomainObject, Object permission ) { + public boolean hasPermission( Authentication authentication, @Nullable Object targetDomainObject, Object permission ) { User user = authentication instanceof AnonymousAuthenticationToken ? null : userService.findUserByIdNoAuth( ( (UserPrinciple) authentication.getPrincipal() ).getId() ); if ( permission.equals( Permissions.SEARCH ) ) { return privacyService.checkUserCanSearch( user, false ); diff --git a/src/main/java/ubc/pavlab/rdp/security/SecureTokenChallenge.java b/src/main/java/ubc/pavlab/rdp/security/SecureTokenChallenge.java index d45f1527..e46b627b 100644 --- a/src/main/java/ubc/pavlab/rdp/security/SecureTokenChallenge.java +++ b/src/main/java/ubc/pavlab/rdp/security/SecureTokenChallenge.java @@ -7,7 +7,7 @@ public interface SecureTokenChallenge { /** * @param token the token being challenged - * @throws TokenException + * @throws TokenException if the challenge fails */ void challenge( Token token, T object ) throws TokenException; diff --git a/src/main/java/ubc/pavlab/rdp/services/EmailServiceImpl.java b/src/main/java/ubc/pavlab/rdp/services/EmailServiceImpl.java index 4ea4ae4d..80986220 100644 --- a/src/main/java/ubc/pavlab/rdp/services/EmailServiceImpl.java +++ b/src/main/java/ubc/pavlab/rdp/services/EmailServiceImpl.java @@ -10,6 +10,7 @@ import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.stereotype.Service; +import org.springframework.util.Assert; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.util.UriComponentsBuilder; import ubc.pavlab.rdp.model.PasswordResetToken; @@ -155,6 +156,7 @@ public Future sendRegistrationMessage( User user, VerificationToken token, Lo @Override public Future sendContactEmailVerificationMessage( User user, VerificationToken token, Locale locale ) throws MessagingException { + Assert.notNull( user.getProfile().getContactEmail(), "User must have a contact email." ); InternetAddress recipientAddress = new InternetAddress( user.getProfile().getContactEmail() ); String subject = messageSource.getMessage( "EmailService.sendContactEmailVerificationMessage.subject", new Object[]{ Messages.SHORTNAME }, locale ); URI confirmationUrl = UriComponentsBuilder.fromUri( siteSettings.getHostUrl() ) diff --git a/src/main/java/ubc/pavlab/rdp/services/GOServiceImpl.java b/src/main/java/ubc/pavlab/rdp/services/GOServiceImpl.java index 7352a58d..f153b8ab 100644 --- a/src/main/java/ubc/pavlab/rdp/services/GOServiceImpl.java +++ b/src/main/java/ubc/pavlab/rdp/services/GOServiceImpl.java @@ -226,7 +226,7 @@ private SearchResult queryTerm( String queryString, GeneOn } List splitPatterns = Arrays.stream( queryString.split( " " ) ) - .filter( s -> !s.equals( "" ) ) + .filter( s -> !s.isEmpty() ) .map( s -> "(?i:.*" + Pattern.quote( s ) + ".*)" ).collect( Collectors.toList() ); for ( String splitPattern : splitPatterns ) { diff --git a/src/main/java/ubc/pavlab/rdp/services/GeneInfoServiceImpl.java b/src/main/java/ubc/pavlab/rdp/services/GeneInfoServiceImpl.java index 8dc3188d..22208889 100644 --- a/src/main/java/ubc/pavlab/rdp/services/GeneInfoServiceImpl.java +++ b/src/main/java/ubc/pavlab/rdp/services/GeneInfoServiceImpl.java @@ -7,7 +7,6 @@ import org.springframework.core.io.UrlResource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import ubc.pavlab.rdp.model.Gene; import ubc.pavlab.rdp.model.GeneInfo; import ubc.pavlab.rdp.model.Taxon; import ubc.pavlab.rdp.model.enums.GeneMatchType; @@ -50,7 +49,7 @@ public class GeneInfoServiceImpl implements GeneInfoService { @Override public GeneInfo load( Integer id ) { - return geneInfoRepository.findByGeneId( id ); + return geneInfoRepository.findByGeneId( id ).orElse( null ); } @Override @@ -60,7 +59,7 @@ public Collection load( Collection ids ) { @Override public GeneInfo findBySymbolAndTaxon( String symbol, Taxon taxon ) { - return geneInfoRepository.findBySymbolAndTaxon( symbol, taxon ); + return geneInfoRepository.findBySymbolAndTaxon( symbol, taxon ).orElse( null ); } @Override diff --git a/src/main/java/ubc/pavlab/rdp/services/LoggingEmailServiceImpl.java b/src/main/java/ubc/pavlab/rdp/services/LoggingEmailServiceImpl.java index 7819ed1e..206d3ae2 100644 --- a/src/main/java/ubc/pavlab/rdp/services/LoggingEmailServiceImpl.java +++ b/src/main/java/ubc/pavlab/rdp/services/LoggingEmailServiceImpl.java @@ -3,6 +3,7 @@ import lombok.extern.apachecommons.CommonsLog; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Profile; +import org.springframework.lang.Nullable; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.util.UriComponentsBuilder; @@ -32,7 +33,7 @@ public class LoggingEmailServiceImpl implements EmailService { private SiteSettings siteSettings; @Override - public Future sendSupportMessage( String message, String name, User user, String userAgent, MultipartFile attachment, Locale locale ) { + public Future sendSupportMessage( String message, String name, User user, String userAgent, @Nullable MultipartFile attachment, Locale locale ) { log.info( MessageFormat.format( "Support message for {0}:\n{1}", user, message ) ); return CompletableFuture.completedFuture( null ); } diff --git a/src/main/java/ubc/pavlab/rdp/services/OntologyService.java b/src/main/java/ubc/pavlab/rdp/services/OntologyService.java index 9e6558ec..12a1441e 100644 --- a/src/main/java/ubc/pavlab/rdp/services/OntologyService.java +++ b/src/main/java/ubc/pavlab/rdp/services/OntologyService.java @@ -114,12 +114,12 @@ public Ontology findById( Integer id ) { @Nullable public Ontology findByName( String name ) { - return ontologyRepository.findByName( name ); + return ontologyRepository.findByName( name ).orElse( null ); } @Nullable public Ontology findByNameAndActiveTrue( String name ) { - return ontologyRepository.findByNameAndActiveTrue( name ); + return ontologyRepository.findByNameAndActiveTrue( name ).orElse( null ); } @Transactional(readOnly = true) @@ -489,10 +489,7 @@ public List findTermByTermIdsAndOntologyNames( List te } LinkedHashSet results = new LinkedHashSet<>( termIds.size() ); for ( int i = 0; i < ontologyNames.size(); i++ ) { - OntologyTermInfo term = ontologyTermInfoRepository.findByTermIdAndOntologyName( termIds.get( i ), ontologyNames.get( i ) ); - if ( term != null ) { - results.add( term ); - } + ontologyTermInfoRepository.findByTermIdAndOntologyName( termIds.get( i ), ontologyNames.get( i ) ).ifPresent( results::add ); } return new ArrayList<>( results ); } @@ -634,7 +631,7 @@ public void saveTermsNoAuth( Iterable terms ) { @Nullable @Transactional(readOnly = true) public OntologyTermInfo findTermByTermIdAndOntologyName( String termId, String ontologyName ) { - return ontologyTermInfoRepository.findByTermIdAndOntologyName( termId, ontologyName ); + return ontologyTermInfoRepository.findByTermIdAndOntologyName( termId, ontologyName ).orElse( null ); } @Transactional @@ -655,7 +652,7 @@ public Ontology updateNoAuth( Ontology ontology ) { } @Transactional(readOnly = true) - public String findDefinitionByOntologyName( String ontologyName ) { + public Optional findDefinitionByOntologyName( String ontologyName ) { return ontologyTermInfoRepository.findDefinitionByOntologyName( ontologyName ); } @@ -746,7 +743,7 @@ private List> autocompleteTerms( String query, Se .collect( Collectors.joining( " " ) ); // make last term, if available a prefix match - if ( fullTextQuery.length() > 0 ) { + if ( !fullTextQuery.isEmpty() ) { fullTextQuery += "*"; } @@ -1066,7 +1063,7 @@ private Comparator getTopologicalComparator( Set findTermByTermIdAndOntology( String ontologyTermInfoId, Ontology ontology ) { return ontologyTermInfoRepository.findByTermIdAndOntology( ontologyTermInfoId, ontology ); } diff --git a/src/main/java/ubc/pavlab/rdp/services/PrivacyServiceImpl.java b/src/main/java/ubc/pavlab/rdp/services/PrivacyServiceImpl.java index 87cc55e2..bfa4fd9c 100644 --- a/src/main/java/ubc/pavlab/rdp/services/PrivacyServiceImpl.java +++ b/src/main/java/ubc/pavlab/rdp/services/PrivacyServiceImpl.java @@ -2,18 +2,10 @@ import lombok.extern.apachecommons.CommonsLog; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; -import ubc.pavlab.rdp.model.Profile; -import ubc.pavlab.rdp.model.Role; -import ubc.pavlab.rdp.model.User; -import ubc.pavlab.rdp.model.UserContent; import ubc.pavlab.rdp.model.enums.PrivacyLevelType; -import ubc.pavlab.rdp.repositories.RoleRepository; import ubc.pavlab.rdp.settings.ApplicationSettings; -import java.text.MessageFormat; - /** * Logic regarding privacy */ diff --git a/src/main/java/ubc/pavlab/rdp/services/ReactomeService.java b/src/main/java/ubc/pavlab/rdp/services/ReactomeService.java index 7e7b29df..b062688a 100644 --- a/src/main/java/ubc/pavlab/rdp/services/ReactomeService.java +++ b/src/main/java/ubc/pavlab/rdp/services/ReactomeService.java @@ -52,9 +52,6 @@ public ReactomeService( OntologyService ontologyService, ApplicationSettings app this.restTemplate = restTemplate; } - /** - * @return - */ @Nullable public Ontology findPathwaysOntology() { return ontologyService.findByName( applicationSettings.getOntology().getReactomePathwaysOntologyName() ); @@ -199,7 +196,7 @@ public void updatePathwaySummations( @Nullable ProgressCallback progressCallback ProgressUtils.emitProgress( progressCallback, ( i * 20L ) + page.getNumberOfElements(), page.getTotalElements(), timer.getTime( TimeUnit.MILLISECONDS ) ); if ( entity.getStatusCode().is2xxSuccessful() && entity.getBody() != null ) { Map results = Arrays.stream( entity.getBody() ) - .filter( e -> e.getSummation() != null && e.getSummation().size() > 0 ) + .filter( e -> e.getSummation() != null && !e.getSummation().isEmpty() ) .collect( Collectors.toMap( ReactomeEntity::getStId, e -> e.getSummation().get( 0 ).getText() ) ); for ( OntologyTermInfo term : page ) { if ( results.containsKey( term.getTermId() ) ) { @@ -220,6 +217,7 @@ public void updatePathwaySummations( @Nullable ProgressCallback progressCallback @Data public static class ReactomeEntity { private String stId; + @Nullable private List summation; } diff --git a/src/main/java/ubc/pavlab/rdp/services/RemoteResourceServiceImpl.java b/src/main/java/ubc/pavlab/rdp/services/RemoteResourceServiceImpl.java index daf49e53..1accef9f 100644 --- a/src/main/java/ubc/pavlab/rdp/services/RemoteResourceServiceImpl.java +++ b/src/main/java/ubc/pavlab/rdp/services/RemoteResourceServiceImpl.java @@ -27,10 +27,7 @@ import org.springframework.web.util.UriComponentsBuilder; import ubc.pavlab.rdp.exception.RemoteException; import ubc.pavlab.rdp.exception.UnknownRemoteApiException; -import ubc.pavlab.rdp.model.RemoteResource; -import ubc.pavlab.rdp.model.Taxon; -import ubc.pavlab.rdp.model.User; -import ubc.pavlab.rdp.model.UserGene; +import ubc.pavlab.rdp.model.*; import ubc.pavlab.rdp.model.enums.ResearcherCategory; import ubc.pavlab.rdp.model.enums.ResearcherPosition; import ubc.pavlab.rdp.model.enums.TierType; @@ -199,12 +196,13 @@ public static class Server { private URI url; } + @Nullable private Info info; private List servers; } @Override - public List findUsersByLikeName( String nameLike, Boolean prefix, Set researcherPositions, Collection researcherCategories, Collection organUberonIds, Map> ontologyTermInfos ) { + public List findUsersByLikeName( String nameLike, Boolean prefix, @Nullable Set researcherPositions, @Nullable Collection researcherCategories, @Nullable Collection organUberonIds, @Nullable Map> ontologyTermInfos ) { MultiValueMap params = new LinkedMultiValueMap<>(); params.add( "nameLike", nameLike ); params.add( "prefix", prefix.toString() ); @@ -227,7 +225,7 @@ public List findUsersByLikeName( String nameLike, Boolean prefix, Set findUsersByDescription( String descriptionLike, Set researcherPositions, Collection researcherCategories, Collection organUberonIds, Map> ontologyTermInfos ) { + public List findUsersByDescription( String descriptionLike, @Nullable Set researcherPositions, @Nullable Collection researcherCategories, @Nullable Collection organUberonIds, @Nullable Map> ontologyTermInfos ) { MultiValueMap params = new LinkedMultiValueMap<>(); params.add( "descriptionLike", descriptionLike ); params.putAll( UserSearchParams.builder() @@ -533,7 +531,8 @@ private URI prepareApiUri( URI apiUri, boolean authenticate ) { .replaceQueryParam( "noauth" ); if ( authenticate ) { User user = userService.findCurrentUser(); - if ( user != null && user.getRoles().contains( roleRepository.findByRole( "ROLE_ADMIN" ) ) ) { + Role adminRole = roleRepository.findByRole( "ROLE_ADMIN" ).orElseThrow( NullPointerException::new ); + if ( user != null && user.getRoles().contains( adminRole ) ) { UriComponents apiUriComponents = UriComponentsBuilder.fromUri( apiUri ).build(); //noinspection StatementWithEmptyBody if ( apiUriComponents.getQueryParams().containsKey( "noauth" ) ) { @@ -605,9 +604,13 @@ private RequestFilter satisfiesVersion( String minimumVersion ) { @SuperBuilder private static class UserSearchParams { + @Nullable private Collection researcherPositions; + @Nullable private Collection researcherCategories; + @Nullable private Collection organUberonIds; + @Nullable private Map> ontologyTermInfos; public MultiValueMap toMultiValueMap() { @@ -646,6 +649,7 @@ private static class UserGeneSearchParams extends UserSearchParams { private Integer taxonId; private TierType tier; + @Nullable private Integer orthologTaxonId; @Override diff --git a/src/main/java/ubc/pavlab/rdp/services/TaxonService.java b/src/main/java/ubc/pavlab/rdp/services/TaxonService.java index 647b0452..04f87581 100644 --- a/src/main/java/ubc/pavlab/rdp/services/TaxonService.java +++ b/src/main/java/ubc/pavlab/rdp/services/TaxonService.java @@ -14,7 +14,4 @@ public interface TaxonService { Taxon findById( final Integer id ); Collection findByActiveTrue(); - - Collection loadAll(); - } diff --git a/src/main/java/ubc/pavlab/rdp/services/TaxonServiceImpl.java b/src/main/java/ubc/pavlab/rdp/services/TaxonServiceImpl.java index 86397d47..f346bcab 100644 --- a/src/main/java/ubc/pavlab/rdp/services/TaxonServiceImpl.java +++ b/src/main/java/ubc/pavlab/rdp/services/TaxonServiceImpl.java @@ -26,9 +26,4 @@ public Collection findByActiveTrue() { return taxonRepository.findByActiveTrueOrderByOrdering(); } - @Override - public Collection loadAll() { - return taxonRepository.findAll(); - } - } diff --git a/src/main/java/ubc/pavlab/rdp/services/UserDetailsServiceImpl.java b/src/main/java/ubc/pavlab/rdp/services/UserDetailsServiceImpl.java index b933a5c3..268c2bb3 100644 --- a/src/main/java/ubc/pavlab/rdp/services/UserDetailsServiceImpl.java +++ b/src/main/java/ubc/pavlab/rdp/services/UserDetailsServiceImpl.java @@ -5,7 +5,6 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import ubc.pavlab.rdp.model.User; import ubc.pavlab.rdp.model.UserPrinciple; import ubc.pavlab.rdp.repositories.UserRepository; @@ -21,11 +20,9 @@ public class UserDetailsServiceImpl implements UserDetailsService { @Override @Transactional(readOnly = true) public UserPrinciple loadUserByUsername( String email ) { - User user = userRepository.findByEmailIgnoreCase( email ); - if ( user == null ) { - throw new UsernameNotFoundException( email ); - } - return new UserPrinciple( user ); + return userRepository.findByEmailIgnoreCase( email ) + .map( UserPrinciple::new ) + .orElseThrow( () -> new UsernameNotFoundException( email ) ); } } diff --git a/src/main/java/ubc/pavlab/rdp/services/UserGeneService.java b/src/main/java/ubc/pavlab/rdp/services/UserGeneService.java index 65fcea46..c52f48e4 100644 --- a/src/main/java/ubc/pavlab/rdp/services/UserGeneService.java +++ b/src/main/java/ubc/pavlab/rdp/services/UserGeneService.java @@ -67,12 +67,14 @@ public interface UserGeneService { * * @param tiers only retain results in the given {@link TierType}, or any if null * @param orthologTaxon only retain results in the given ortholog {@link Taxon}, or any if null - * @param researcherPositions only retain results where the corresponding {@link User} holds any given {@link ResearcherPosition}, - * or any if null - * @param researcherTypes only retain results where the corresponding {@link User} has any of the given {@link ResearcherCategory} - * or any if null - * @param organs only retain results where the corresponding {@link User} tracks any of the given {@link OrganInfo} - * @param ontologyTermInfos + * @param researcherPositions only retain results where the corresponding {@link User} holds any given + * {@link ResearcherPosition}, or any if null + * @param researcherTypes only retain results where the corresponding {@link User} has any of the given + * {@link ResearcherCategory}, or any if null + * @param organs only retain results where the corresponding {@link User} tracks any of the given + * {@link OrganInfo}, or any if null + * @param ontologyTermInfos only retain results where the corresponding {@link User} tracks any of the given + * {@link OntologyTermInfo}, or any if null */ List handleGeneSearch( Gene gene, @Nullable Set tiers, @Nullable Taxon orthologTaxon, @Nullable Set researcherPositions, @Nullable Collection researcherTypes, @Nullable Collection organs, @Nullable Map> ontologyTermInfos ); diff --git a/src/main/java/ubc/pavlab/rdp/services/UserGeneServiceImpl.java b/src/main/java/ubc/pavlab/rdp/services/UserGeneServiceImpl.java index ae9e4229..89fbcc23 100644 --- a/src/main/java/ubc/pavlab/rdp/services/UserGeneServiceImpl.java +++ b/src/main/java/ubc/pavlab/rdp/services/UserGeneServiceImpl.java @@ -24,6 +24,7 @@ import org.springframework.cache.annotation.Cacheable; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.lang.Nullable; import org.springframework.security.access.PermissionEvaluator; import org.springframework.security.access.prepost.PostFilter; import org.springframework.security.core.Authentication; @@ -144,7 +145,7 @@ public long countUniqueAssociationsToHumanAllTiers() { @Override @PostFilter("hasPermission(filterObject, 'read')") - public List handleGeneSearch( Gene gene, Set tiers, Taxon orthologTaxon, Set researcherPositions, Collection researcherCategories, Collection organs, Map> ontologyTermInfos ) { + public List handleGeneSearch( Gene gene, @Nullable Set tiers, @Nullable Taxon orthologTaxon, @Nullable Set researcherPositions, @Nullable Collection researcherCategories, @Nullable Collection organs, @Nullable Map> ontologyTermInfos ) { Stream results = handleGeneSearchInternal( gene, tiers, orthologTaxon, researcherPositions, researcherCategories, organs, ontologyTermInfos ).stream(); if ( applicationSettings.getPrivacy().isEnableAnonymizedSearchResults() ) { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); @@ -160,7 +161,7 @@ public List handleGeneSearch( Gene gene, Set tiers, Taxon or .collect( Collectors.toList() ); // we need to preserve the search order } - private Set handleGeneSearchInternal( Gene gene, Set tiers, Taxon orthologTaxon, Set researcherPositions, Collection researcherCategories, Collection organs, Map> ontologyTermInfos ) { + private Set handleGeneSearchInternal( Gene gene, @Nullable Set tiers, @Nullable Taxon orthologTaxon, @Nullable Set researcherPositions, @Nullable Collection researcherCategories, @Nullable Collection organs, @Nullable Map> ontologyTermInfos ) { Set uGenes = new LinkedHashSet<>(); // do this once to save time in the inner loop @@ -183,7 +184,7 @@ private Set handleGeneSearchInternal( Gene gene, Set tiers, // ortholog relationship is not reflexive (i.e. a gene is not its own ortholog), but we still want to display // that gene first when ortholog search is performed in the same MO if ( orthologTaxon == null || gene.getTaxon().equals( orthologTaxon ) ) { - uGenes.addAll( userGeneRepository.findByGeneIdAndTierIn( gene.getGeneId(), tiers ).stream() + uGenes.addAll( tiers == null ? userGeneRepository.findByGeneId( gene.getGeneId() ) : userGeneRepository.findByGeneIdAndTierIn( gene.getGeneId(), tiers ).stream() .filter( ug -> researcherPositions == null || researcherPositions.contains( ug.getUser().getProfile().getResearcherPosition() ) ) .filter( ug -> nullOrContainsAtLeastOne( researcherCategories, () -> ug.getUser().getProfile().getResearcherCategories() ) ) .filter( ortholog -> nullOrContainsAtLeastOne( organUberonIds, () -> ortholog.getUser().getUserOrgans().values().stream().map( UserOrgan::getUberonId ).collect( Collectors.toSet() ) ) ) @@ -196,9 +197,9 @@ private Set handleGeneSearchInternal( Gene gene, Set tiers, return uGenes; } - private Set handleOrthologSearchInternal( Gene gene, Set tiers, Taxon orthologTaxon, Set researcherPositions, Collection researcherCategories, Collection organUberonIds, Map> ontologyTermInfoIds ) { + private Set handleOrthologSearchInternal( Gene gene, @Nullable Set tiers, @Nullable Taxon orthologTaxon, @Nullable Set researcherPositions, @Nullable Collection researcherCategories, @Nullable Collection organUberonIds, @Nullable Map> ontologyTermInfoIds ) { return ( orthologTaxon == null ? userGeneRepository.findOrthologsByGeneId( gene.getGeneId() ) : userGeneRepository.findOrthologsByGeneIdAndTaxon( gene.getGeneId(), orthologTaxon ) ).stream() - .filter( ortholog -> tiers.contains( ortholog.getTier() ) ) + .filter( ortholog -> tiers == null || tiers.contains( ortholog.getTier() ) ) .filter( ug -> researcherPositions == null || researcherPositions.contains( ug.getUser().getProfile().getResearcherPosition() ) ) .filter( ug -> nullOrContainsAtLeastOne( researcherCategories, () -> ug.getUser().getProfile().getResearcherCategories() ) ) .filter( ortholog -> nullOrContainsAtLeastOne( organUberonIds, () -> ortholog.getUser().getUserOrgans().values().stream().map( UserOrgan::getUberonId ).collect( Collectors.toSet() ) ) ) diff --git a/src/main/java/ubc/pavlab/rdp/services/UserOrganServiceImpl.java b/src/main/java/ubc/pavlab/rdp/services/UserOrganServiceImpl.java index a574dea7..80ed8cec 100644 --- a/src/main/java/ubc/pavlab/rdp/services/UserOrganServiceImpl.java +++ b/src/main/java/ubc/pavlab/rdp/services/UserOrganServiceImpl.java @@ -4,7 +4,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import ubc.pavlab.rdp.model.OrganInfo; import ubc.pavlab.rdp.model.UserOrgan; import ubc.pavlab.rdp.repositories.OrganInfoRepository; import ubc.pavlab.rdp.repositories.UserOrganRepository; @@ -24,11 +23,10 @@ public class UserOrganServiceImpl implements UserOrganService { public void updateUserOrgans() { log.info( "Updating user organs..." ); for ( UserOrgan userOrgan : userOrganRepository.findAll() ) { - OrganInfo organInfo = organInfoRepository.findByUberonId( userOrgan.getUberonId() ); - if ( organInfo != null ) { + organInfoRepository.findByUberonId( userOrgan.getUberonId() ).ifPresent( organInfo -> { userOrgan.updateOrgan( organInfo ); userOrganRepository.save( userOrgan ); - } + } ); } log.info( "Done updating user organs." ); } diff --git a/src/main/java/ubc/pavlab/rdp/services/UserPrivacyService.java b/src/main/java/ubc/pavlab/rdp/services/UserPrivacyService.java index ee0ff87c..a0a21845 100644 --- a/src/main/java/ubc/pavlab/rdp/services/UserPrivacyService.java +++ b/src/main/java/ubc/pavlab/rdp/services/UserPrivacyService.java @@ -2,7 +2,6 @@ import lombok.extern.apachecommons.CommonsLog; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cache.annotation.Cacheable; import org.springframework.lang.Nullable; import org.springframework.stereotype.Service; import ubc.pavlab.rdp.model.Profile; @@ -15,8 +14,6 @@ import java.text.MessageFormat; -import static java.util.Objects.requireNonNull; - @Service @CommonsLog public class UserPrivacyService { @@ -56,7 +53,7 @@ public boolean checkUserCanUpdate( @Nullable User user, UserContent userContent private boolean checkUserCanSeeOtherUserContentWithPrivacyLevel( @Nullable User currentUser, @Nullable User otherUser, PrivacyLevelType privacyLevel ) { // Never show the remote admin profile (or accidental null users) - if ( otherUser == null || ( applicationSettings.getIsearch() != null && isRemoteSearchUser( otherUser ) ) ) { + if ( otherUser == null || isRemoteSearchUser( otherUser ) ) { return false; } @@ -67,7 +64,7 @@ private boolean checkUserCanSeeOtherUserContentWithPrivacyLevel( @Nullable User Profile profile = otherUser.getProfile(); - if ( profile == null || profile.getPrivacyLevel() == null ) { + if ( profile.getPrivacyLevel() == null ) { log.error( MessageFormat.format( "User without a profile, privacy levels or sharing set: {0}", otherUser ) ); return false; } @@ -75,7 +72,7 @@ private boolean checkUserCanSeeOtherUserContentWithPrivacyLevel( @Nullable User // Either the user is looking at himself, or the user is public, or shared with registered users - check for any logged-in user, or private - check for admin; If logged-in user is admin, we have to // check whether this user is the designated actor for the authenticated remote search, in which case we have to check for remote search privileges on the user. - return otherUser.equals( currentUser ) // User is looking at himself + return ( currentUser != null && currentUser.equals( otherUser ) ) // User is looking at himself || ( privacyLevel == PrivacyLevelType.PUBLIC ) // Data is public || ( privacyLevel == PrivacyLevelType.SHARED && currentUser != null && !isRemoteSearchUser( currentUser ) )// data is accessible for registerd users and there is a user logged in who is not the remote admin || ( privacyLevel == PrivacyLevelType.PRIVATE && currentUser != null && isAdminOrServiceAccount( currentUser ) && !isRemoteSearchUser( currentUser ) ) // data is private and there is an admin (or service account) logged in who is not the remote search user @@ -97,14 +94,12 @@ public boolean checkCurrentUserCanSeeGeneList( User otherUser ) { || ( currentUser != null && currentUser.getRoles().contains( getAdminRole() ) ) ); } - @Cacheable(value = "ubc.pavlab.rdp.model.Role.byRole", key = "'ROLE_ADMIN'") - public Role getAdminRole() { - return requireNonNull( roleRepository.findByRole( "ROLE_ADMIN" ) ); + private Role getAdminRole() { + return roleRepository.findByRole( "ROLE_ADMIN" ).orElseThrow( NullPointerException::new ); } - @Cacheable(value = "ubc.pavlab.rdp.model.Role.byRole", key = "'ROLE_SERVICE_ACCOUNT'") - public Role getServiceAccountRole() { - return requireNonNull( roleRepository.findByRole( "ROLE_SERVICE_ACCOUNT" ) ); + private Role getServiceAccountRole() { + return roleRepository.findByRole( "ROLE_SERVICE_ACCOUNT" ).orElseThrow( NullPointerException::new ); } private boolean isRemoteSearchUser( User user ) { diff --git a/src/main/java/ubc/pavlab/rdp/services/UserService.java b/src/main/java/ubc/pavlab/rdp/services/UserService.java index 79eca75d..d7877137 100644 --- a/src/main/java/ubc/pavlab/rdp/services/UserService.java +++ b/src/main/java/ubc/pavlab/rdp/services/UserService.java @@ -69,6 +69,7 @@ public interface UserService { @Nullable User findUserByEmailNoAuth( String email ); + @Nullable User findUserByAccessTokenNoAuth( String accessToken ) throws TokenException; /** @@ -83,7 +84,7 @@ public interface UserService { * Note: when using this, ensure that the user is enabled as per {@link User#isEnabled()}, otherwise a * {@link org.springframework.security.access.AccessDeniedException} will be raised. That is because a non-enabled * user will not satisfy the 'read' permission for any user as defined in {@link ubc.pavlab.rdp.security.PermissionEvaluatorImpl} - * and {@link PrivacyService#checkUserCanSee(User, UserContent)}. + * and {@link UserPrivacyService#checkUserCanSee(User, UserContent)}. * * @throws org.springframework.security.access.AccessDeniedException if the user is not enabled */ @@ -219,15 +220,12 @@ User updateUserProfileAndPublicationsAndOrgansAndOntologyTerms( User user, * inference from {@link OntologyService#inferTermIds(Collection)}. * * @param ontologyTermInfoIdsByOntology the term IDs grouped by ontology - * @return true if all the ontologies possess at least one match - or zero if empty, false otherwise + * @return a predicate that indicates if all the ontologies possess at least one match - or zero if empty, false otherwise */ - Predicate hasOntologyTermIn( Map> ontologyTermInfoIdsByOntology ); + Predicate hasOntologyTermIn( @Nullable Map> ontologyTermInfoIdsByOntology ); /** * Indicate if there are users with terms in the given ontology. - * - * @param ontology - * @return */ boolean existsByOntology( Ontology ontology ); } diff --git a/src/main/java/ubc/pavlab/rdp/services/UserServiceImpl.java b/src/main/java/ubc/pavlab/rdp/services/UserServiceImpl.java index dd6ece3e..71d9ea08 100644 --- a/src/main/java/ubc/pavlab/rdp/services/UserServiceImpl.java +++ b/src/main/java/ubc/pavlab/rdp/services/UserServiceImpl.java @@ -128,7 +128,7 @@ public void afterPropertiesSet() { @Override public User create( User user ) { user.setPassword( bCryptPasswordEncoder.encode( user.getPassword() ) ); - Role userRole = roleRepository.findByRole( "ROLE_USER" ); + Role userRole = roleRepository.findByRole( "ROLE_USER" ).orElseThrow( NullPointerException::new ); user.getRoles().add( userRole ); return userRepository.save( user ); } @@ -138,7 +138,7 @@ public User create( User user ) { @Override public User createAdmin( User admin ) { admin.setPassword( bCryptPasswordEncoder.encode( admin.getPassword() ) ); - Role adminRole = roleRepository.findByRole( "ROLE_ADMIN" ); + Role adminRole = roleRepository.findByRole( "ROLE_ADMIN" ).orElseThrow( NullPointerException::new ); admin.getRoles().add( adminRole ); return userRepository.save( admin ); } @@ -148,7 +148,7 @@ public User createAdmin( User admin ) { @Transactional public User createServiceAccount( User user ) { user.setPassword( bCryptPasswordEncoder.encode( createSecureRandomToken() ) ); - Role serviceAccountRole = roleRepository.findByRole( "ROLE_SERVICE_ACCOUNT" ); + Role serviceAccountRole = roleRepository.findByRole( "ROLE_SERVICE_ACCOUNT" ).orElseThrow( NullPointerException::new ); user.getRoles().add( serviceAccountRole ); user = userRepository.save( user ); createAccessTokenForUser( user ); @@ -165,7 +165,7 @@ public List findAllRoles() { @Secured("ROLE_ADMIN") @Transactional(rollbackFor = RoleException.class) public void updateRoles( User user, Set roles ) throws RoleException { - Role adminRole = roleRepository.findByRole( "ROLE_ADMIN" ); + Role adminRole = roleRepository.findByRole( "ROLE_ADMIN" ).orElseThrow( NullPointerException::new ); if ( isCurrentUser( user ) && !roles.containsAll( user.getRoles() ) ) { throw new CannotRevokeOwnRolesException( "You cannot revoke your own roles." ); } else if ( user.getRoles().contains( adminRole ) && !roles.containsAll( user.getRoles() ) ) { @@ -178,18 +178,13 @@ public void updateRoles( User user, Set roles ) throws RoleException { @Override @PreAuthorize("hasPermission(#user, 'update')") public User update( User user ) { - if ( applicationSettings.getPrivacy() == null ) { - // FIXME: this should not be possible... - log.warn( MessageFormat.format( "{0} attempted to update, but applicationSettings.privacy is null.", user.getEmail() ) ); - } else { - PrivacyLevelType defaultPrivacyLevel = PrivacyLevelType.values()[applicationSettings.getPrivacy().getDefaultLevel()]; - boolean defaultSharing = applicationSettings.getPrivacy().isDefaultSharing(); - boolean defaultGenelist = applicationSettings.getPrivacy().isAllowHideGenelist(); + PrivacyLevelType defaultPrivacyLevel = PrivacyLevelType.values()[applicationSettings.getPrivacy().getDefaultLevel()]; + boolean defaultSharing = applicationSettings.getPrivacy().isDefaultSharing(); + boolean defaultGenelist = applicationSettings.getPrivacy().isAllowHideGenelist(); - if ( user.getProfile().getPrivacyLevel() == null ) { - log.warn( "Received a null 'privacyLevel' value in profile." ); - user.getProfile().setPrivacyLevel( defaultPrivacyLevel ); - } + if ( user.getProfile().getPrivacyLevel() == null ) { + log.warn( "Received a null 'privacyLevel' value in profile." ); + user.getProfile().setPrivacyLevel( defaultPrivacyLevel ); } PrivacyLevelType userPrivacyLevel = user.getProfile().getPrivacyLevel(); @@ -220,14 +215,12 @@ public void delete( User user ) { @Transactional @Override - public User changePassword( String oldPassword, String newPassword ) - throws BadCredentialsException, ValidationException { + public User changePassword( String oldPassword, String newPassword ) throws BadCredentialsException, ValidationException { User user = requireNonNull( findCurrentUser() ); if ( bCryptPasswordEncoder.matches( oldPassword, user.getPassword() ) ) { if ( newPassword.length() >= 6 ) { //TODO: Tie in with hibernate constraint on User or not necessary? - user.setPassword( bCryptPasswordEncoder.encode( newPassword ) ); - return update( user ); + return userRepository.save( user ); } else { throw new ValidationException( "Password must be a minimum of 6 characters" ); } @@ -317,12 +310,12 @@ public User findUserByIdNoAuth( int id ) { @Override public User findUserByEmailNoAuth( String email ) { - return userRepository.findByEmailIgnoreCase( email ); + return userRepository.findByEmailIgnoreCase( email ).orElse( null ); } @Override public User findUserByAccessTokenNoAuth( String accessToken ) throws TokenException { - AccessToken token = accessTokenRepository.findByToken( accessToken ); + AccessToken token = accessTokenRepository.findByToken( accessToken ).orElse( null ); if ( token == null ) { return null; } @@ -420,7 +413,7 @@ public Page findByEnabledTrueAndPrivacyLevelNoAuth( PrivacyLevelType priva @Override @PostFilter("hasPermission(filterObject, 'read')") - public List findByLikeName( String nameLike, Set researcherPositions, Set researcherTypes, Collection organs, Map> ontologyTermInfos ) { + public List findByLikeName( String nameLike, @Nullable Set researcherPositions, @Nullable Set researcherTypes, @Nullable Collection organs, @Nullable Map> ontologyTermInfos ) { final Set organUberonIds = organUberonIdsFromOrgans( organs ); Map> ontologyTermInfoIds = ontologyTermInfoIdsFromOntologyTermInfo( ontologyTermInfos ); return userRepository.findByProfileNameContainingIgnoreCaseOrProfileLastNameContainingIgnoreCase( nameLike, nameLike ).stream() @@ -434,7 +427,7 @@ public List findByLikeName( String nameLike, Set resea @Override @PostFilter("hasPermission(filterObject, 'read')") - public List findByStartsName( String startsName, Set researcherPositions, Set researcherTypes, Collection organs, Map> ontologyTermInfos ) { + public List findByStartsName( String startsName, @Nullable Set researcherPositions, @Nullable Set researcherTypes, @Nullable Collection organs, @Nullable Map> ontologyTermInfos ) { final Set organUberonIds = organUberonIdsFromOrgans( organs ); Map> ontologyTermInfoIds = ontologyTermInfoIdsFromOntologyTermInfo( ontologyTermInfos ); return userRepository.findByProfileLastNameStartsWithIgnoreCase( startsName ).stream() @@ -448,7 +441,7 @@ public List findByStartsName( String startsName, Set r @Override @PostFilter("hasPermission(filterObject, 'read')") - public List findByDescription( String descriptionLike, Set researcherPositions, Collection researcherTypes, Collection organs, Map> ontologyTermInfos ) { + public List findByDescription( String descriptionLike, @Nullable Set researcherPositions, @Nullable Collection researcherTypes, @Nullable Collection organs, @Nullable Map> ontologyTermInfos ) { final Set organUberonIds = organUberonIdsFromOrgans( organs ); Map> ontologyTermInfoIds = ontologyTermInfoIdsFromOntologyTermInfo( ontologyTermInfos ); return userRepository.findDistinctByProfileDescriptionLikeIgnoreCaseOrTaxonDescriptionsLikeIgnoreCaseOrUserOntologyTermsNameLikeIgnoreCase( "%" + descriptionLike + "%" ).stream() @@ -462,7 +455,7 @@ public List findByDescription( String descriptionLike, Set findByNameAndDescription( String nameLike, boolean prefix, String descriptionLike, Set researcherPositions, Set researcherCategories, Collection organs, Map> ontologyTermInfos ) { + public List findByNameAndDescription( String nameLike, boolean prefix, String descriptionLike, @Nullable Set researcherPositions, @Nullable Set researcherCategories, @Nullable Collection organs, @Nullable Map> ontologyTermInfos ) { final Set organUberonIds = organUberonIdsFromOrgans( organs ); String namePattern = prefix ? nameLike + "%" : "%" + nameLike + "%"; String descriptionPattern = "%" + descriptionLike + "%"; @@ -482,7 +475,8 @@ public List findByNameAndDescription( String nameLike, boolean prefix, Str .collect( Collectors.toList() ); } - private Set organUberonIdsFromOrgans( Collection organs ) { + @Nullable + private Set organUberonIdsFromOrgans( @Nullable Collection organs ) { if ( organs != null ) { return organs.stream().map( Organ::getUberonId ).collect( Collectors.toSet() ); } else { @@ -490,7 +484,8 @@ private Set organUberonIdsFromOrgans( Collection organs ) { } } - private Map> ontologyTermInfoIdsFromOntologyTermInfo( Map> ontologyTermInfos ) { + @Nullable + private Map> ontologyTermInfoIdsFromOntologyTermInfo( @Nullable Map> ontologyTermInfos ) { if ( ontologyTermInfos != null ) { return ontologyTermInfos.entrySet().stream() .collect( Collectors.toMap( Map.Entry::getKey, e -> ontologyService.inferTermIds( e.getValue() ) ) ); @@ -500,7 +495,7 @@ private Map> ontologyTermInfoIdsFromOntologyTermInfo( Map } @Override - public Predicate hasOntologyTermIn( Map> ontologyTermInfoIdsByOntology ) { + public Predicate hasOntologyTermIn( @Nullable Map> ontologyTermInfoIdsByOntology ) { return u -> ontologyTermInfoIdsByOntology == null || ontologyTermInfoIdsByOntology.values().stream() .allMatch( entry -> containsAtLeastOne( entry, () -> getUserTermInfoIds( u ) ) ); } @@ -767,14 +762,12 @@ public User updateUserProfileAndPublicationsAndOrgansAndOntologyTerms( User user user.getProfile().setResearcherPosition( profile.getResearcherPosition() ); user.getProfile().setOrganization( profile.getOrganization() ); - if ( profile.getResearcherCategories() != null ) { - if ( applicationSettings.getProfile().getEnabledResearcherCategories().containsAll( profile.getResearcherCategories() ) ) { - user.getProfile().getResearcherCategories().retainAll( profile.getResearcherCategories() ); - user.getProfile().getResearcherCategories().addAll( profile.getResearcherCategories() ); - } else { - log.warn( MessageFormat.format( "User {0} attempted to set user {1} researcher type to an unknown value {2}.", - findCurrentUser(), user, profile.getResearcherCategories() ) ); - } + if ( applicationSettings.getProfile().getEnabledResearcherCategories().containsAll( profile.getResearcherCategories() ) ) { + user.getProfile().getResearcherCategories().retainAll( profile.getResearcherCategories() ); + user.getProfile().getResearcherCategories().addAll( profile.getResearcherCategories() ); + } else { + log.warn( MessageFormat.format( "User {0} attempted to set user {1} researcher type to an unknown value {2}.", + findCurrentUser(), user, profile.getResearcherCategories() ) ); } if ( user.getProfile().getContactEmail() == null || @@ -802,7 +795,7 @@ public User updateUserProfileAndPublicationsAndOrgansAndOntologyTerms( User user // privacy settings if ( applicationSettings.getPrivacy().isCustomizableLevel() ) { - if ( privacyService.isPrivacyLevelEnabled( profile.getPrivacyLevel() ) ) { + if ( profile.getPrivacyLevel() == null || privacyService.isPrivacyLevelEnabled( profile.getPrivacyLevel() ) ) { // reset gene privacy levels if the profile value is changed if ( applicationSettings.getPrivacy().isCustomizableGeneLevel() && user.getProfile().getPrivacyLevel() != profile.getPrivacyLevel() ) { @@ -864,7 +857,7 @@ public PasswordResetToken createPasswordResetTokenForUser( User user, Locale loc @Override public PasswordResetToken verifyPasswordResetToken( int userId, String token, HttpServletRequest request ) throws TokenException { - PasswordResetToken passToken = passwordResetTokenRepository.findByToken( token ); + PasswordResetToken passToken = passwordResetTokenRepository.findByToken( token ).orElse( null ); if ( passToken == null ) { throw new TokenException( "Password reset token is invalid." ); @@ -914,6 +907,7 @@ public VerificationToken createVerificationTokenForUser( User user, Locale local @Transactional @Override public VerificationToken createContactEmailVerificationTokenForUser( User user, Locale locale ) { + Assert.notNull( user.getProfile().getContactEmail(), "User does not have a contact email." ); VerificationToken userToken = new VerificationToken(); userToken.setUser( user ); userToken.setEmail( user.getProfile().getContactEmail() ); @@ -926,7 +920,7 @@ public VerificationToken createContactEmailVerificationTokenForUser( User user, @Override @Transactional(rollbackFor = { TokenException.class }) public User confirmVerificationToken( String token, HttpServletRequest request ) throws TokenException { - VerificationToken verificationToken = tokenRepository.findByToken( token ); + VerificationToken verificationToken = tokenRepository.findByToken( token ).orElse( null ); if ( verificationToken == null ) { throw new TokenNotFoundException( "Verification token is invalid." ); diff --git a/src/main/java/ubc/pavlab/rdp/settings/ApplicationSettings.java b/src/main/java/ubc/pavlab/rdp/settings/ApplicationSettings.java index b2254bcf..0a5fa36f 100644 --- a/src/main/java/ubc/pavlab/rdp/settings/ApplicationSettings.java +++ b/src/main/java/ubc/pavlab/rdp/settings/ApplicationSettings.java @@ -5,6 +5,7 @@ import org.springframework.boot.convert.DurationUnit; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.Resource; +import org.springframework.lang.Nullable; import org.springframework.validation.annotation.Validated; import ubc.pavlab.rdp.model.GeneInfo; import ubc.pavlab.rdp.model.enums.PrivacyLevelType; @@ -55,22 +56,24 @@ public static class CacheSettings { /** * Location of GO terms. */ + @Nullable private String termFile; /** * Location of gene2go annotations. - *

- * FIXME: use a {@link Resource}, but resolving is not supported at the config-level (see #192) */ + @Nullable private Resource annotationFile; /** * Location of gene orthologs. */ + @Nullable private Resource orthologFile; /** * Location of organ system terms. *

* FIXME: use a {@link Resource}, but resolving is not supported at the config-level (see #192) */ + @Nullable private String organFile; } @@ -197,6 +200,7 @@ public static class InternationalSearchSettings { *

* If set, the user must exist at startup and there must be at least one {@link #authTokens} specified. */ + @Nullable private Integer userId; /** * List of partner APIs endpoints. @@ -210,6 +214,7 @@ public static class InternationalSearchSettings { /** * Token used to query other partner registries. */ + @Nullable private String searchToken; /** * Request timeout when querying partner registries, or null to disable. @@ -221,16 +226,19 @@ public static class InternationalSearchSettings { * defining the timeout. */ @Deprecated + @Nullable @DurationUnit(value = ChronoUnit.SECONDS) private Duration requestTimeout; /** * Connection timeout in milliseconds, or null to disable. */ + @Nullable @DurationUnit(value = ChronoUnit.MILLIS) private Duration connectTimeout; /** * Read timeout in milliseconds, or null to disable. */ + @Nullable @DurationUnit(value = ChronoUnit.MILLIS) private Duration readTimeout; } @@ -261,6 +269,7 @@ public static class OntologySettings { private OrganSettings organs; private OntologySettings ontology; + @Nullable private Resource faqFile; private boolean sendEmailOnRegistration; /** diff --git a/src/main/java/ubc/pavlab/rdp/settings/SiteSettings.java b/src/main/java/ubc/pavlab/rdp/settings/SiteSettings.java index 403fafcc..8e7e9121 100644 --- a/src/main/java/ubc/pavlab/rdp/settings/SiteSettings.java +++ b/src/main/java/ubc/pavlab/rdp/settings/SiteSettings.java @@ -3,8 +3,8 @@ import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; +import org.springframework.lang.Nullable; import org.springframework.validation.annotation.Validated; -import org.springframework.web.util.UriComponentsBuilder; import javax.validation.constraints.Email; import javax.validation.constraints.NotEmpty; @@ -34,6 +34,7 @@ public URI getHostUrl() { * If configured, CORS policies will be setup so that scripts running on the main site can freely access the * '/stats' and '/api/**' endpoints. */ + @Nullable private URI mainsite; @Pattern(regexp = "#[a-fA-F\\d]{6}", message = "The theme color must be a valid hex color (i.e. '#FFFFFF').") diff --git a/src/main/java/ubc/pavlab/rdp/util/CacheUtils.java b/src/main/java/ubc/pavlab/rdp/util/CacheUtils.java index 266eb362..81caa9fc 100644 --- a/src/main/java/ubc/pavlab/rdp/util/CacheUtils.java +++ b/src/main/java/ubc/pavlab/rdp/util/CacheUtils.java @@ -5,7 +5,6 @@ import org.springframework.cache.CacheManager; import java.util.Collection; -import java.util.Map; /** * Utilities for working with {@link CacheManager} and {@link Cache}. diff --git a/src/main/java/ubc/pavlab/rdp/util/CollectionUtils.java b/src/main/java/ubc/pavlab/rdp/util/CollectionUtils.java index 405367cb..30c34dc1 100644 --- a/src/main/java/ubc/pavlab/rdp/util/CollectionUtils.java +++ b/src/main/java/ubc/pavlab/rdp/util/CollectionUtils.java @@ -1,6 +1,6 @@ package ubc.pavlab.rdp.util; -import org.springframework.lang.NonNull; +import org.springframework.lang.Nullable; import java.util.Collection; import java.util.HashMap; @@ -88,11 +88,11 @@ public static Predicate by( Function s * will return false regardless of the supplied candidates * @see org.springframework.util.CollectionUtils#containsAny(Collection, Collection) */ - public static boolean nullOrContainsAtLeastOne( Collection source, Supplier> candidates ) { + public static boolean nullOrContainsAtLeastOne( @Nullable Collection source, Supplier> candidates ) { return source == null || containsAtLeastOne( source, candidates ); } - public static boolean containsAtLeastOne( @NonNull Collection source, Supplier> candidates ) { + public static boolean containsAtLeastOne( Collection source, Supplier> candidates ) { return ( !source.isEmpty() && containsAny( source, candidates.get() ) ); } } diff --git a/src/main/java/ubc/pavlab/rdp/util/GeneInfoParser.java b/src/main/java/ubc/pavlab/rdp/util/GeneInfoParser.java index d596594d..514ffc5c 100644 --- a/src/main/java/ubc/pavlab/rdp/util/GeneInfoParser.java +++ b/src/main/java/ubc/pavlab/rdp/util/GeneInfoParser.java @@ -4,6 +4,7 @@ import lombok.Data; import lombok.extern.apachecommons.CommonsLog; import org.apache.commons.lang3.ArrayUtils; +import org.springframework.lang.Nullable; import org.springframework.stereotype.Component; import java.io.*; @@ -67,6 +68,7 @@ public static class Record { private String symbol; private String synonyms; private String description; + @Nullable private LocalDate modificationDate; public static Record parseLine( String line, String[] header, int lineNumber ) throws UncheckedParseException { diff --git a/src/main/java/ubc/pavlab/rdp/util/GeneOrthologsParser.java b/src/main/java/ubc/pavlab/rdp/util/GeneOrthologsParser.java index 84876f0b..32d419d6 100644 --- a/src/main/java/ubc/pavlab/rdp/util/GeneOrthologsParser.java +++ b/src/main/java/ubc/pavlab/rdp/util/GeneOrthologsParser.java @@ -8,7 +8,6 @@ import java.io.*; import java.util.List; -import java.util.Objects; import java.util.stream.Collectors; /** @@ -64,7 +63,6 @@ public List parse( InputStream is ) throws ParseException, IOException { } return br.lines() .map( line -> Record.parseLine( line, header, br.getLineNumber() ) ) - .filter( Objects::nonNull ) .collect( Collectors.toList() ); } catch ( UncheckedIOException ioe ) { throw ioe.getCause(); diff --git a/src/main/java/ubc/pavlab/rdp/util/OBOParser.java b/src/main/java/ubc/pavlab/rdp/util/OBOParser.java index 4e8c7c5d..e48615ef 100644 --- a/src/main/java/ubc/pavlab/rdp/util/OBOParser.java +++ b/src/main/java/ubc/pavlab/rdp/util/OBOParser.java @@ -2,6 +2,7 @@ import lombok.*; import lombok.extern.apachecommons.CommonsLog; +import org.springframework.lang.Nullable; import org.springframework.stereotype.Component; import java.io.IOException; @@ -30,6 +31,7 @@ public static class Ontology { private String formatVersion; private String dataVersion; private String defaultNamespace; + @Nullable private String name; } @@ -77,6 +79,7 @@ public static class Relationship { private String name; private String definition; private List synonyms = new ArrayList<>(); + @Nullable private Boolean obsolete; /* we map both directions of a relationship */ diff --git a/src/main/java/ubc/pavlab/rdp/util/OntologyMessageSource.java b/src/main/java/ubc/pavlab/rdp/util/OntologyMessageSource.java index 2c01e0b9..5119542a 100644 --- a/src/main/java/ubc/pavlab/rdp/util/OntologyMessageSource.java +++ b/src/main/java/ubc/pavlab/rdp/util/OntologyMessageSource.java @@ -1,16 +1,10 @@ package ubc.pavlab.rdp.util; -import lombok.SneakyThrows; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.support.AbstractMessageSource; import org.springframework.stereotype.Component; -import org.springframework.web.util.UriComponentsBuilder; -import ubc.pavlab.rdp.model.ontology.OntologyTermInfo; -import ubc.pavlab.rdp.repositories.ontology.OntologyTermInfoRepository; import ubc.pavlab.rdp.services.OntologyService; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; import java.text.MessageFormat; import java.util.Locale; import java.util.regex.Matcher; @@ -50,7 +44,7 @@ protected String resolveCodeWithoutArguments( String code, Locale locale ) { return ontologyService.findDefinitionByTermNameAndOntologyName( termName, ontologyName ).orElse( null ); } else if ( ( matcher = ONTOLOGY_DEFINITION.matcher( code ) ).matches() ) { String ontologyName = matcher.group( 1 ); - return ontologyService.findDefinitionByOntologyName( ontologyName ); + return ontologyService.findDefinitionByOntologyName( ontologyName ).orElse( null ); } else { return super.resolveCodeWithoutArguments( code, locale ); } diff --git a/src/main/java/ubc/pavlab/rdp/util/ParseException.java b/src/main/java/ubc/pavlab/rdp/util/ParseException.java index 80ac309a..7e6c02fc 100644 --- a/src/main/java/ubc/pavlab/rdp/util/ParseException.java +++ b/src/main/java/ubc/pavlab/rdp/util/ParseException.java @@ -7,10 +7,10 @@ /** * Exception raised when a parsing error occurs for biological data. */ +@Getter public class ParseException extends Exception { - @Getter - private int lineNumber; + private final int lineNumber; public ParseException( String message, int lineNumber ) { super( MessageFormat.format( "{0}: {1}", lineNumber, message ) ); diff --git a/src/main/java/ubc/pavlab/rdp/util/PurlResolver.java b/src/main/java/ubc/pavlab/rdp/util/PurlResolver.java index 4251b5e6..90c289a3 100644 --- a/src/main/java/ubc/pavlab/rdp/util/PurlResolver.java +++ b/src/main/java/ubc/pavlab/rdp/util/PurlResolver.java @@ -5,13 +5,6 @@ import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.UrlResource; -import org.springframework.beans.BeansException; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.context.ResourceLoaderAware; -import org.springframework.context.support.GenericApplicationContext; -import org.springframework.core.io.*; -import org.springframework.stereotype.Component; import java.io.IOException; import java.net.HttpURLConnection; @@ -54,6 +47,7 @@ public Resource resolve( String location, ResourceLoader resourceLoader ) { log.warn( String.format( "Invalid 'Location' header for PURL %s.", url ) ); } catch ( IOException e ) { log.error( String.format( "Failed to resolve PURL %s.", url ), e ); + } finally { if ( con != null ) { con.disconnect(); } diff --git a/src/main/java/ubc/pavlab/rdp/util/SearchResult.java b/src/main/java/ubc/pavlab/rdp/util/SearchResult.java index aa84e14e..d991f84f 100644 --- a/src/main/java/ubc/pavlab/rdp/util/SearchResult.java +++ b/src/main/java/ubc/pavlab/rdp/util/SearchResult.java @@ -19,10 +19,12 @@ @EqualsAndHashCode(of = { "match" }) public class SearchResult> implements Comparable> { + @Nullable private final MatchType matchType; /** * A unique, internal ID that disambiguate results with the same {@link #label}. This is not being displayed. */ + @Nullable private final Integer id; /** * A label to identify the result. @@ -31,6 +33,7 @@ public class SearchResult> implements Comparable FACTORS.length ) { throw new VersionException( "Version must have at most " + FACTORS.length + " components." ); } diff --git a/src/main/java/ubc/pavlab/rdp/validation/Recaptcha.java b/src/main/java/ubc/pavlab/rdp/validation/Recaptcha.java index 32695818..79ef5c0f 100644 --- a/src/main/java/ubc/pavlab/rdp/validation/Recaptcha.java +++ b/src/main/java/ubc/pavlab/rdp/validation/Recaptcha.java @@ -2,11 +2,10 @@ import lombok.Value; import org.springframework.lang.Nullable; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.RequestParam; @Value public class Recaptcha { + @Nullable String response; @Nullable String remoteIp; diff --git a/src/main/resources/ehcache.xml b/src/main/resources/ehcache.xml index 44e47f08..aada3763 100644 --- a/src/main/resources/ehcache.xml +++ b/src/main/resources/ehcache.xml @@ -26,10 +26,6 @@ maxElementsInMemory="10" eternal="true"/> - - diff --git a/src/test/java/ubc/pavlab/rdp/controllers/AdminControllerTest.java b/src/test/java/ubc/pavlab/rdp/controllers/AdminControllerTest.java index bca4cea6..4187d5c5 100644 --- a/src/test/java/ubc/pavlab/rdp/controllers/AdminControllerTest.java +++ b/src/test/java/ubc/pavlab/rdp/controllers/AdminControllerTest.java @@ -27,7 +27,6 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; import org.springframework.util.LinkedMultiValueMap; @@ -202,7 +201,7 @@ public void givenLoggedIn_whenCreateAccessToken_thenRedirect3xx() throws Excepti AccessToken accessToken = TestUtils.createAccessToken( 1, user, "1234" ); when( userService.findUserById( 1 ) ).thenReturn( user ); when( userService.createAccessTokenForUser( user ) ).thenReturn( accessToken ); - when( roleRepository.findByRole( "ROLE_USER" ) ).thenReturn( createRole( 1, "ROLE_USER" ) ); + when( roleRepository.findByRole( "ROLE_USER" ) ).thenReturn( Optional.of( createRole( 1, "ROLE_USER" ) ) ); mvc.perform( post( "/admin/users/{user}/create-access-token", user.getId() ) ) .andExpect( status().is3xxRedirection() ) .andExpect( redirectedUrl( "/admin/users/1" ) ); @@ -718,7 +717,7 @@ public void activateOntologyTermInfo() throws Exception { Ontology ontology = Ontology.builder( "mondo" ).id( 1 ).build(); OntologyTermInfo term = OntologyTermInfo.builder( ontology, "test" ).build(); when( ontologyService.findById( 1 ) ).thenReturn( ontology ); - when( ontologyService.findTermByTermIdAndOntology( "test", ontology ) ).thenReturn( term ); + when( ontologyService.findTermByTermIdAndOntology( "test", ontology ) ).thenReturn( Optional.of( term ) ); mvc.perform( post( "/admin/ontologies/{ontologyId}/activate-term", ontology.getId() ) .param( "ontologyTermInfoId", "test" ) ) .andExpect( status().is3xxRedirection() ) @@ -734,7 +733,7 @@ public void activateOntologyTermInfo_whenIncludeSubtree() throws Exception { Ontology ontology = Ontology.builder( "mondo" ).id( 1 ).build(); OntologyTermInfo term = OntologyTermInfo.builder( ontology, "test" ).build(); when( ontologyService.findById( 1 ) ).thenReturn( ontology ); - when( ontologyService.findTermByTermIdAndOntology( "test", ontology ) ).thenReturn( term ); + when( ontologyService.findTermByTermIdAndOntology( "test", ontology ) ).thenReturn( Optional.of( term ) ); mvc.perform( post( "/admin/ontologies/{ontologyId}/activate-term", ontology.getId() ) .param( "ontologyTermInfoId", "test" ) .param( "includeSubtree", "true" ) ) @@ -751,7 +750,7 @@ public void activateOntologyTermInfo_whenTermFieldIsEmpty() throws Exception { Ontology ontology = Ontology.builder( "mondo" ).id( 1 ).build(); OntologyTermInfo term = OntologyTermInfo.builder( ontology, "test" ).build(); when( ontologyService.findById( 1 ) ).thenReturn( ontology ); - when( ontologyService.findTermByTermIdAndOntology( "test", ontology ) ).thenReturn( term ); + when( ontologyService.findTermByTermIdAndOntology( "test", ontology ) ).thenReturn( Optional.of( term ) ); mvc.perform( post( "/admin/ontologies/{ontologyId}/activate-term", ontology.getId() ) .param( "ontologyTermInfoId", "" ) .param( "includeSubtree", "true" ) ) @@ -770,7 +769,7 @@ public void activateOntologyTermInfo_whenTermFieldIsEmpty() throws Exception { public void activateOntologyTermInfo_whenTermIsNotInOntology() throws Exception { Ontology ontology = Ontology.builder( "mondo" ).id( 1 ).build(); when( ontologyService.findById( 1 ) ).thenReturn( ontology ); - when( ontologyService.findTermByTermIdAndOntology( "test", ontology ) ).thenReturn( null ); + when( ontologyService.findTermByTermIdAndOntology( "test", ontology ) ).thenReturn( Optional.empty() ); mvc.perform( post( "/admin/ontologies/{ontologyId}/activate-term", ontology.getId() ) .param( "ontologyTermInfoId", "test" ) ) .andExpect( status().isBadRequest() ) diff --git a/src/test/java/ubc/pavlab/rdp/repositories/PasswordResetTokenRepositoryTest.java b/src/test/java/ubc/pavlab/rdp/repositories/PasswordResetTokenRepositoryTest.java index 535d5532..dc78358b 100644 --- a/src/test/java/ubc/pavlab/rdp/repositories/PasswordResetTokenRepositoryTest.java +++ b/src/test/java/ubc/pavlab/rdp/repositories/PasswordResetTokenRepositoryTest.java @@ -60,23 +60,17 @@ public void setUp() { @Test public void findByToken_whenValidToken_thenReturnToken() { - - PasswordResetToken found = passwordResetTokenRepository.findByToken( "validtoken" ); - assertThat( found ).isEqualTo( validToken ); + assertThat( passwordResetTokenRepository.findByToken( "validtoken" ) ).hasValue( validToken ); } @Test public void findByToken_whenExpredToken_thenReturnToken() { - - PasswordResetToken found = passwordResetTokenRepository.findByToken( "expiredtoken" ); - assertThat( found ).isEqualTo( expiredToken ); + assertThat( passwordResetTokenRepository.findByToken( "expiredtoken" ) ).hasValue( expiredToken ); } @Test public void findByToken_whenInvalidToken_thenReturnNull() { - - PasswordResetToken found = passwordResetTokenRepository.findByToken( "invalidtoken" ); - assertThat( found ).isNull(); + assertThat( passwordResetTokenRepository.findByToken( "invalidtoken" ) ).isEmpty(); } @Test diff --git a/src/test/java/ubc/pavlab/rdp/repositories/RoleRepositoryTest.java b/src/test/java/ubc/pavlab/rdp/repositories/RoleRepositoryTest.java index 2e08a70a..5c7154bf 100644 --- a/src/test/java/ubc/pavlab/rdp/repositories/RoleRepositoryTest.java +++ b/src/test/java/ubc/pavlab/rdp/repositories/RoleRepositoryTest.java @@ -47,7 +47,7 @@ public void findByRole_whenValidRole_thenReturnRole() { entityManager.persist( role ); entityManager.flush(); - Role found = roleRepository.findByRole( "TEST_ROLE" ); + Role found = roleRepository.findByRole( "TEST_ROLE" ).orElse( null ); assertThat( found ).isEqualTo( role ); @@ -57,7 +57,7 @@ public void findByRole_whenValidRole_thenReturnRole() { @Test public void findByRole_whenInvalidRole_thenReturnNull() { - Role found = roleRepository.findByRole( "XXX" ); + Role found = roleRepository.findByRole( "XXX" ).orElse( null ); assertThat( found ).isNull(); diff --git a/src/test/java/ubc/pavlab/rdp/repositories/UserRepositoryTest.java b/src/test/java/ubc/pavlab/rdp/repositories/UserRepositoryTest.java index 2069c806..80a17e30 100644 --- a/src/test/java/ubc/pavlab/rdp/repositories/UserRepositoryTest.java +++ b/src/test/java/ubc/pavlab/rdp/repositories/UserRepositoryTest.java @@ -48,11 +48,11 @@ public void findByEmail_whenMatch_thenReturnUser() { entityManager.flush(); // when - User found = userRepository.findByEmailIgnoreCase( user.getEmail() ); - - // then - assertThat( found.getEmail() ) - .isEqualTo( user.getEmail() ); + assertThat( userRepository.findByEmailIgnoreCase( user.getEmail() ) ).hasValueSatisfying( found -> { + // then + assertThat( found.getEmail() ) + .isEqualTo( user.getEmail() ); + } ); } @Test @@ -65,10 +65,10 @@ public void findByEmail_whenCaseInsensitiveMatch_thenReturnUser() { entityManager.flush(); // when - User found = userRepository.findByEmailIgnoreCase( user.getEmail().toUpperCase() ); - - // then - assertThat( found ).isEqualTo( user ); + assertThat( userRepository.findByEmailIgnoreCase( user.getEmail().toUpperCase() ) ).hasValueSatisfying( found -> { + // then + assertThat( found ).isEqualTo( user ); + } ); } @Test @@ -326,6 +326,7 @@ public void findByDescriptionLike_whenCaseInsensitiveMatch_thenReturnUser() { entityManager.flush(); // when + assertThat( user.getProfile().getDescription() ).isNotNull(); String search = user.getProfile().getDescription().toUpperCase(); Collection found = userRepository.findDistinctByProfileDescriptionLikeIgnoreCaseOrTaxonDescriptionsLikeIgnoreCaseOrUserOntologyTermsNameLikeIgnoreCase( "%" + search + "%" ); @@ -344,6 +345,7 @@ public void findByDescriptionLike_whenDescriptionStartsWithMatch_thenReturnUser( entityManager.flush(); // when + assertThat( user.getProfile().getDescription() ).isNotNull(); String search = user.getProfile().getDescription().substring( 0, 3 ); Collection found = userRepository.findDistinctByProfileDescriptionLikeIgnoreCaseOrTaxonDescriptionsLikeIgnoreCaseOrUserOntologyTermsNameLikeIgnoreCase( "%" + search + "%" ); @@ -362,6 +364,7 @@ public void findByDescriptionLike_whenDescriptionEndsWithMatch_thenReturnUser() entityManager.flush(); // when + assertThat( user.getProfile().getDescription() ).isNotNull(); String search = user.getProfile().getDescription().substring( 3 ); Collection found = userRepository.findDistinctByProfileDescriptionLikeIgnoreCaseOrTaxonDescriptionsLikeIgnoreCaseOrUserOntologyTermsNameLikeIgnoreCase( "%" + search + "%" ); @@ -380,6 +383,7 @@ public void findByDescriptionLike_whenDescriptionContainsMatch_thenReturnUser() entityManager.flush(); // when + assertThat( user.getProfile().getDescription() ).isNotNull(); String search = user.getProfile().getDescription().substring( 1, 3 ); Collection found = userRepository.findDistinctByProfileDescriptionLikeIgnoreCaseOrTaxonDescriptionsLikeIgnoreCaseOrUserOntologyTermsNameLikeIgnoreCase( "%" + search + "%" ); @@ -551,7 +555,7 @@ public void delete_whenUserHasMultipleAssociations_thenSucceed() { UserOrgan userOrgan = entityManager.persistAndFlush( createUserOrgan( user, organInfo ) ); user.getVerificationTokens().add( token ); - user.getRoles().add( roleRepository.findByRole( "ROLE_USER" ) ); + user.getRoles().add( roleRepository.findByRole( "ROLE_USER" ).orElseThrow( NullPointerException::new ) ); user.getProfile().getResearcherCategories().add( ResearcherCategory.IN_SILICO ); user.getUserOrgans().put( userOrgan.getUberonId(), userOrgan ); user.getTaxonDescriptions().put( humanTaxon, "I'm a human researcher." ); diff --git a/src/test/java/ubc/pavlab/rdp/repositories/VerificationTokenRepositoryTest.java b/src/test/java/ubc/pavlab/rdp/repositories/VerificationTokenRepositoryTest.java index 0e224c4b..3a9f745d 100644 --- a/src/test/java/ubc/pavlab/rdp/repositories/VerificationTokenRepositoryTest.java +++ b/src/test/java/ubc/pavlab/rdp/repositories/VerificationTokenRepositoryTest.java @@ -1,6 +1,5 @@ package ubc.pavlab.rdp.repositories; -import org.assertj.core.data.TemporalUnitOffset; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -63,23 +62,17 @@ public void setUp() { @Test public void findByToken_whenValidToken_thenReturnToken() { - - VerificationToken found = verificationTokenRepository.findByToken( "validtoken" ); - assertThat( found ).isEqualTo( validToken ); + assertThat( verificationTokenRepository.findByToken( "validtoken" ) ).hasValue( validToken ); } @Test public void findByToken_whenExpredToken_thenReturnToken() { - - VerificationToken found = verificationTokenRepository.findByToken( "expiredtoken" ); - assertThat( found ).isEqualTo( expiredToken ); + assertThat( verificationTokenRepository.findByToken( "expiredtoken" ) ).hasValue( expiredToken ); } @Test public void findByToken_whenInvalidToken_thenReturnNull() { - - VerificationToken found = verificationTokenRepository.findByToken( "invalidtoken" ); - assertThat( found ).isNull(); + assertThat( verificationTokenRepository.findByToken( "invalidtoken" ) ).isEmpty(); } @Test diff --git a/src/test/java/ubc/pavlab/rdp/security/PrivacyServiceImplTest.java b/src/test/java/ubc/pavlab/rdp/security/PrivacyServiceImplTest.java index fe19ab93..638c7220 100644 --- a/src/test/java/ubc/pavlab/rdp/security/PrivacyServiceImplTest.java +++ b/src/test/java/ubc/pavlab/rdp/security/PrivacyServiceImplTest.java @@ -77,8 +77,8 @@ public void setUp() { otherUser.setEnabledAt( Instant.now() ); adminUser = createUserWithRoles( 3, roleAdmin ); serviceAccountUser = createUserWithRoles( 4, roleServiceAccount ); - when( roleRepository.findByRole( "ROLE_ADMIN" ) ).thenReturn( roleAdmin ); - when( roleRepository.findByRole( "ROLE_SERVICE_ACCOUNT" ) ).thenReturn( roleServiceAccount ); + when( roleRepository.findByRole( "ROLE_ADMIN" ) ).thenReturn( Optional.of( roleAdmin ) ); + when( roleRepository.findByRole( "ROLE_SERVICE_ACCOUNT" ) ).thenReturn( Optional.of( roleServiceAccount ) ); when( applicationSettings.getPrivacy() ).thenReturn( privacySettings ); when( applicationSettings.getIsearch() ).thenReturn( iSearchSettings ); when( privacySettings.isRegisteredSearch() ).thenReturn( true ); diff --git a/src/test/java/ubc/pavlab/rdp/services/GeneInfoServiceImplTest.java b/src/test/java/ubc/pavlab/rdp/services/GeneInfoServiceImplTest.java index 6f53b81c..3cd2d1a0 100644 --- a/src/test/java/ubc/pavlab/rdp/services/GeneInfoServiceImplTest.java +++ b/src/test/java/ubc/pavlab/rdp/services/GeneInfoServiceImplTest.java @@ -27,7 +27,6 @@ import java.io.IOException; import java.net.URL; -import java.time.Instant; import java.time.LocalDate; import java.util.Collection; import java.util.Collections; @@ -37,10 +36,7 @@ import java.util.stream.IntStream; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; import static ubc.pavlab.rdp.util.TestUtils.createGene; import static ubc.pavlab.rdp.util.TestUtils.createTaxon; @@ -303,7 +299,7 @@ public void updateGenes_thenSucceed() throws ParseException, IOException { verify( taxonService ).findByActiveTrue(); verify( geneInfoParser ).parse( any(), eq( humanTaxon.getId() ) ); assertThat( geneInfoRepository.findByGeneId( 4 ) ) - .isNotNull() + .get() .hasFieldOrPropertyWithValue( "symbol", "FOO" ) .hasFieldOrPropertyWithValue( "name", "BAR" ) .hasFieldOrPropertyWithValue( "taxon", humanTaxon ); @@ -318,7 +314,7 @@ public void updateGenes_whenTaxonDiffers_thenIgnoreGeneRecord() throws ParseExce geneService.updateGenes(); verify( taxonService ).findByActiveTrue(); verify( geneInfoParser ).parse( any(), eq( 9606 ) ); - assertThat( geneInfoRepository.findByGeneId( 4 ) ).isNull(); + assertThat( geneInfoRepository.findByGeneId( 4 ) ).isEmpty(); } @Test @@ -332,7 +328,7 @@ public void updateGenes_whenTaxonIsChanged_thenUpdateGene() throws ParseExceptio geneService.updateGenes(); verify( taxonService ).findByActiveTrue(); assertThat( geneInfoRepository.findByGeneId( 4 ) ) - .isNotNull() + .get() .hasFieldOrPropertyWithValue( "symbol", "FOO" ) .hasFieldOrPropertyWithValue( "name", "BAR" ) .hasFieldOrPropertyWithValue( "taxon", humanTaxon ); @@ -350,7 +346,7 @@ public void updateGenes_whenGeneInfoContainsMultipleTaxon_thenIgnoreUnrelatedTax verify( taxonService ).findByActiveTrue(); verify( geneInfoParser ).parse( any(), eq( fissionYeastTaxon.getId() ) ); assertThat( geneInfoRepository.findByGeneId( 4 ) ) - .isNotNull() + .get() .hasFieldOrPropertyWithValue( "symbol", "FOO" ) .hasFieldOrPropertyWithValue( "name", "BAR" ) .hasFieldOrPropertyWithValue( "taxon", fissionYeastTaxon ); diff --git a/src/test/java/ubc/pavlab/rdp/services/OntologyServiceTest.java b/src/test/java/ubc/pavlab/rdp/services/OntologyServiceTest.java index 789ffeac..4c0ef93c 100644 --- a/src/test/java/ubc/pavlab/rdp/services/OntologyServiceTest.java +++ b/src/test/java/ubc/pavlab/rdp/services/OntologyServiceTest.java @@ -111,7 +111,7 @@ public static class OntologyTestSetupService { public Ontology setupOntology( String ont, boolean activateTerms ) throws IOException, OntologyNameAlreadyUsedException, ParseException { if ( ontologyRepository.existsByName( ont ) ) { log.info( String.format( "%s ontology already setup, skipping...", ont ) ); - return ontologyRepository.findByName( ont ); + return ontologyRepository.findByName( ont ).orElseThrow( NullPointerException::new ); } Resource resource = new ClassPathResource( "cache/" + ont + ".obo" ); try ( Reader reader = new InputStreamReader( resource.getInputStream() ) ) { @@ -137,11 +137,11 @@ public void createFromObo() throws IOException, ParseException, OntologyNameAlre assertThat( term.getSynonyms() ) .hasSize( 9 ) .contains( "canalis cervicis uteri" ); - term = ontologyService.findTermByTermIdAndOntology( "UBERON:0000044", ontology ); + term = ontologyService.findTermByTermIdAndOntology( "UBERON:0000044", ontology ).orElse( null ); assertThat( term ).isNotNull(); assertThat( term.getAltTermIds() ) .containsExactly( "UBERON:0026602" ); - OntologyTermInfo termWithMixedCaseSynonym = ontologyService.findTermByTermIdAndOntology( "UBERON:8000005", ontology ); + OntologyTermInfo termWithMixedCaseSynonym = ontologyService.findTermByTermIdAndOntology( "UBERON:8000005", ontology ).orElse( null ); assertThat( termWithMixedCaseSynonym ).isNotNull(); assertThat( termWithMixedCaseSynonym.getSynonyms() ) .contains( "nerve fiber layer of Henle".toLowerCase() ); @@ -169,7 +169,7 @@ public void updateFromObo_whenSynonymChangeCase_thenIgnoreNewValue() throws Onto Ontology ontology = ontologySetupService.setupOntology( "mondo", false ); // need to rehash because the sorted set is case insensitive - synonyms = new HashSet<>( ontologyService.findTermByTermIdAndOntology( "MONDO:0005296", ontology ).getSynonyms() ); + synonyms = new HashSet<>( ontologyService.findTermByTermIdAndOntology( "MONDO:0005296", ontology ).get().getSynonyms() ); assertThat( synonyms ).contains( "sleep Apneas, mixed" ); // the casing has changed to "sleep apneas, mixed" in mondo2 @@ -177,7 +177,7 @@ public void updateFromObo_whenSynonymChangeCase_thenIgnoreNewValue() throws Onto try ( Reader reader = new InputStreamReader( resource.getInputStream() ) ) { ontologyService.updateFromObo( ontology, reader ); } - synonyms = new HashSet<>( ontologyService.findTermByTermIdAndOntology( "MONDO:0005296", ontology ).getSynonyms() ); + synonyms = new HashSet<>( ontologyService.findTermByTermIdAndOntology( "MONDO:0005296", ontology ).get().getSynonyms() ); assertThat( synonyms ).contains( "sleep Apneas, mixed" ); } @@ -330,7 +330,7 @@ public void writeObo_whenFedBackToOboParser_thenProduceExactlyTheSameStructure() @Test public void activateTerm() throws OntologyNameAlreadyUsedException, IOException, ParseException { Ontology mondo = ontologySetupService.setupOntology( "mondo", true ); - OntologyTermInfo term = ontologyService.findTermByTermIdAndOntology( "MONDO:0000001", mondo ); + OntologyTermInfo term = ontologyService.findTermByTermIdAndOntology( "MONDO:0000001", mondo ).orElse( null ); ontologyService.activateTerm( term ); entityManager.refresh( term ); assertThat( term.isActive() ).isTrue(); @@ -342,7 +342,7 @@ public void activateTerm() throws OntologyNameAlreadyUsedException, IOException, @Test public void activateTermSubtree() throws OntologyNameAlreadyUsedException, IOException, ParseException { Ontology mondo = ontologySetupService.setupOntology( "mondo", false ); - OntologyTermInfo term = ontologyService.findTermByTermIdAndOntology( "MONDO:0000001", mondo ); + OntologyTermInfo term = ontologyService.findTermByTermIdAndOntology( "MONDO:0000001", mondo ).orElse( null ); int activatedTerms = ontologyService.activateTermSubtree( term ); assertThat( activatedTerms ).isEqualTo( 22027 ); } @@ -361,7 +361,7 @@ public void inferTermIds() throws OntologyNameAlreadyUsedException, IOException, public void inferTermIds_whenTopTermIsUsed() throws OntologyNameAlreadyUsedException, IOException, ParseException { Ontology uberon = ontologySetupService.setupOntology( "uberon", true ); StopWatch stopWatch = StopWatch.createStarted(); - OntologyTermInfo brainTerm = ontologyService.findTermByTermIdAndOntology( "UBERON:0001062", uberon ); + OntologyTermInfo brainTerm = ontologyService.findTermByTermIdAndOntology( "UBERON:0001062", uberon ).orElse( null ); stopWatch.stop(); Set inferredTerms = ontologyService.inferTermIds( Collections.singleton( brainTerm ) ); assertThat( inferredTerms ).hasSize( 13848 ); diff --git a/src/test/java/ubc/pavlab/rdp/services/ReactomeServiceTest.java b/src/test/java/ubc/pavlab/rdp/services/ReactomeServiceTest.java index 7bf01b64..41eb948f 100644 --- a/src/test/java/ubc/pavlab/rdp/services/ReactomeServiceTest.java +++ b/src/test/java/ubc/pavlab/rdp/services/ReactomeServiceTest.java @@ -134,8 +134,9 @@ public void updateSummations() throws ReactomeException { reactomeService.updatePathwaySummations( null ); assertThat( ontologyService.findTermByTermIdAndOntology( "R-HSA-164843", reactome ) ) - .isNotNull() - .hasFieldOrPropertyWithValue( "definition", "the new summation" ); + .hasValueSatisfying( term -> { + assertThat( term ).hasFieldOrPropertyWithValue( "definition", "the new summation" ); + } ); mockServer.verify(); } diff --git a/src/test/java/ubc/pavlab/rdp/services/RemoteResourceServiceTest.java b/src/test/java/ubc/pavlab/rdp/services/RemoteResourceServiceTest.java index c780a859..b62cd1ed 100644 --- a/src/test/java/ubc/pavlab/rdp/services/RemoteResourceServiceTest.java +++ b/src/test/java/ubc/pavlab/rdp/services/RemoteResourceServiceTest.java @@ -34,10 +34,7 @@ import java.net.URI; import java.net.URISyntaxException; -import java.util.Arrays; -import java.util.Collections; -import java.util.EnumSet; -import java.util.UUID; +import java.util.*; import java.util.concurrent.TimeUnit; import static org.assertj.core.api.Assertions.assertThat; @@ -126,7 +123,7 @@ public void setUp() { adminRole.setId( 1 ); adminRole.setRole( "ADMIN" ); adminUser.getRoles().add( adminRole ); - when( roleRepository.findByRole( "ROLE_ADMIN" ) ).thenReturn( adminRole ); + when( roleRepository.findByRole( "ROLE_ADMIN" ) ).thenReturn( Optional.ofNullable( adminRole ) ); } @After diff --git a/src/test/java/ubc/pavlab/rdp/services/UserGeneServiceImplTest.java b/src/test/java/ubc/pavlab/rdp/services/UserGeneServiceImplTest.java index 218c21bb..6d1442ac 100644 --- a/src/test/java/ubc/pavlab/rdp/services/UserGeneServiceImplTest.java +++ b/src/test/java/ubc/pavlab/rdp/services/UserGeneServiceImplTest.java @@ -20,6 +20,8 @@ import ubc.pavlab.rdp.repositories.UserGeneRepository; import ubc.pavlab.rdp.settings.ApplicationSettings; +import java.util.Optional; + import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static ubc.pavlab.rdp.util.TestUtils.*; @@ -69,7 +71,7 @@ public void updateUserGenes_withExistingUser_thenUserGeneAreUpdated() { UserGene userGene = createUserGene( 1, gene, user, TierType.TIER1, PrivacyLevelType.PRIVATE ); userGene.setGeneInfo( gene ); when( userGeneRepository.findAllWithGeneInfo() ).thenReturn( Lists.newArrayList( userGene ) ); - when( geneInfoRepository.findByGeneIdAndTaxon( gene.getGeneId(), gene.getTaxon() ) ).thenReturn( gene ); + when( geneInfoRepository.findByGeneIdAndTaxon( gene.getGeneId(), gene.getTaxon() ) ).thenReturn( Optional.of( gene ) ); userGeneService.updateUserGenes(); verify( userGeneRepository ).save( userGene ); } diff --git a/src/test/java/ubc/pavlab/rdp/services/UserServiceImplTest.java b/src/test/java/ubc/pavlab/rdp/services/UserServiceImplTest.java index 3c2c5799..58300c01 100644 --- a/src/test/java/ubc/pavlab/rdp/services/UserServiceImplTest.java +++ b/src/test/java/ubc/pavlab/rdp/services/UserServiceImplTest.java @@ -190,7 +190,7 @@ public void setUp() { } private void setUpRoleMocks() { - when( roleRepository.findByRole( "ROLE_USER" ) ).thenReturn( createRole( 2, "ROLE_USER" ) ); + when( roleRepository.findByRole( "ROLE_USER" ) ).thenReturn( Optional.of( createRole( 2, "ROLE_USER" ) ) ); } private void setUpPasswordResetTokenMocks() { @@ -199,20 +199,20 @@ private void setUpPasswordResetTokenMocks() { PasswordResetToken token = new PasswordResetToken(); token.setUser( user ); token.updateToken( "token1" ); - when( passwordResetTokenRepository.findByToken( token.getToken() ) ).thenReturn( token ); + when( passwordResetTokenRepository.findByToken( token.getToken() ) ).thenReturn( Optional.of( token ) ); token = new PasswordResetToken(); token.setUser( user ); token.setToken( "token1Expired" ); token.setExpiryDate( Instant.now().minusSeconds( 1 ) ); - when( passwordResetTokenRepository.findByToken( token.getToken() ) ).thenReturn( token ); + when( passwordResetTokenRepository.findByToken( token.getToken() ) ).thenReturn( Optional.of( token ) ); token = new PasswordResetToken(); token.setUser( otherUser ); token.updateToken( "token2" ); - when( passwordResetTokenRepository.findByToken( token.getToken() ) ).thenReturn( token ); + when( passwordResetTokenRepository.findByToken( token.getToken() ) ).thenReturn( Optional.of( token ) ); - when( passwordResetTokenRepository.findByToken( "tokenBad" ) ).thenReturn( null ); + when( passwordResetTokenRepository.findByToken( "tokenBad" ) ).thenReturn( Optional.empty() ); } private void setUpVerificationTokenMocks() { @@ -221,16 +221,16 @@ private void setUpVerificationTokenMocks() { token.setUser( user ); token.setEmail( user.getEmail() ); token.updateToken( "token1" ); - when( tokenRepository.findByToken( token.getToken() ) ).thenReturn( token ); + when( tokenRepository.findByToken( token.getToken() ) ).thenReturn( Optional.of( token ) ); token = new VerificationToken(); token.setUser( user ); token.setEmail( user.getEmail() ); token.setToken( "token1Expired" ); token.setExpiryDate( Instant.now().minus( 1, ChronoUnit.SECONDS ) ); - when( tokenRepository.findByToken( token.getToken() ) ).thenReturn( token ); + when( tokenRepository.findByToken( token.getToken() ) ).thenReturn( Optional.of( token ) ); - when( tokenRepository.findByToken( "tokenBad" ) ).thenReturn( null ); + when( tokenRepository.findByToken( "tokenBad" ) ).thenReturn( Optional.empty() ); } private void setUpRecommendTermsMocks() { @@ -408,7 +408,7 @@ public void findUserByIdNoAuth_whenInvalidId_thenReturnNull() { @Test public void findUserByEmail_whenValidEmail_thenUserShouldBeFound() { User user = createUser( 1 ); - when( userRepository.findByEmailIgnoreCase( user.getEmail() ) ).thenReturn( user ); + when( userRepository.findByEmailIgnoreCase( user.getEmail() ) ).thenReturn( Optional.of( user ) ); User found = userService.findUserByEmailNoAuth( user.getEmail() ); assertThat( found ).isNotNull(); @@ -807,7 +807,7 @@ public void confirmVerificationToken_whenTokenEmailDoesNotMatch_thenThrowTokenEx token.setUser( user ); token.setEmail( "foo@example.com" ); token.updateToken( "token1" ); - when( tokenRepository.findByToken( token.getToken() ) ).thenReturn( token ); + when( tokenRepository.findByToken( token.getToken() ) ).thenReturn( Optional.of( token ) ); userService.confirmVerificationToken( "token1", new MockHttpServletRequest() ); } diff --git a/src/test/java/ubc/pavlab/rdp/util/OntologyMessageSourceTest.java b/src/test/java/ubc/pavlab/rdp/util/OntologyMessageSourceTest.java index 67aac661..573f87b5 100644 --- a/src/test/java/ubc/pavlab/rdp/util/OntologyMessageSourceTest.java +++ b/src/test/java/ubc/pavlab/rdp/util/OntologyMessageSourceTest.java @@ -69,7 +69,7 @@ public void resolveCode_whenCodeIsReactome_thenUseDefaults() { @Test public void resolveCode_whenCodeIsAnOntologyDefinition() { - when( ontologyService.findDefinitionByOntologyName( "mondo" ) ).thenReturn( "A diseases ontology." ); + when( ontologyService.findDefinitionByOntologyName( "mondo" ) ).thenReturn( Optional.of( "A diseases ontology." ) ); assertThat( messageSource.getMessage( "rdp.ontologies.mondo.definition", null, Locale.getDefault() ) ) .isEqualTo( "A diseases ontology." ); verify( ontologyService ).findDefinitionByOntologyName( "mondo" ); @@ -78,7 +78,7 @@ public void resolveCode_whenCodeIsAnOntologyDefinition() { @Test public void resolveCode_whenCodeIsAnOntologyDefinitionMessageSourceResolvable_thenResolveItCorrectly() { Ontology ontology = Ontology.builder( "mondo" ).build(); - when( ontologyService.findDefinitionByOntologyName( "mondo" ) ).thenReturn( "A disease ontology." ); + when( ontologyService.findDefinitionByOntologyName( "mondo" ) ).thenReturn( Optional.of( "A disease ontology." ) ); assertThat( messageSource.getMessage( ontology.getResolvableDefinition(), Locale.getDefault() ) ) .isEqualTo( "A disease ontology." ); verify( ontologyService ).findDefinitionByOntologyName( "mondo" );