Skip to content

Commit a45b701

Browse files
committed
Merge branch 'hotfix-1.4.9'
2 parents f1716bd + eb930ff commit a45b701

24 files changed

+239
-126
lines changed

pom.xml

+2-6
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
<groupId>ubc.pavlab</groupId>
77
<artifactId>rdp</artifactId>
8-
<version>1.4.8</version>
8+
<version>1.4.9</version>
99

1010
<developers>
1111
<developer>
@@ -52,7 +52,6 @@
5252
<dependency>
5353
<groupId>org.springframework.boot</groupId>
5454
<artifactId>spring-boot-configuration-processor</artifactId>
55-
<optional>true</optional>
5655
</dependency>
5756

5857
<!-- Spring Framework Caching Support -->
@@ -69,13 +68,11 @@
6968
<dependency>
7069
<groupId>org.springframework.boot</groupId>
7170
<artifactId>spring-boot-starter-actuator</artifactId>
72-
<optional>true</optional>
7371
</dependency>
7472

7573
<dependency>
7674
<groupId>org.springframework.boot</groupId>
7775
<artifactId>spring-boot-actuator-docs</artifactId>
78-
<optional>true</optional>
7976
</dependency>
8077

8178
<!-- JPA Data (We are going to use Repositories, Entities, Hibernate, etc...) -->
@@ -122,7 +119,6 @@
122119
<dependency>
123120
<groupId>org.springframework.boot</groupId>
124121
<artifactId>spring-boot-devtools</artifactId>
125-
<optional>true</optional>
126122
</dependency>
127123

128124
<dependency>
@@ -135,7 +131,7 @@
135131
<dependency>
136132
<groupId>commons-io</groupId>
137133
<artifactId>commons-io</artifactId>
138-
<version>2.8.0</version>
134+
<version>2.11.0</version>
139135
</dependency>
140136

141137
<!-- Testing Support -->

src/main/java/ubc/pavlab/rdp/controllers/ApiController.java

+10-11
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import ubc.pavlab.rdp.settings.SiteSettings;
2929

3030
import javax.servlet.http.HttpServletRequest;
31-
import java.text.MessageFormat;
3231
import java.util.*;
3332
import java.util.stream.Collectors;
3433

@@ -116,12 +115,12 @@ public Object getUsers( @RequestHeader(value = HttpHeaders.AUTHORIZATION, requir
116115
checkAuth( authorizationHeader, auth );
117116
if ( applicationSettings.getPrivacy().isEnableAnonymizedSearchResults() ) {
118117
final Authentication auth2 = SecurityContextHolder.getContext().getAuthentication();
119-
return userService.findAllByIsEnabledNoAuth( pageable )
118+
return userService.findByEnabledTrueNoAuth( pageable )
120119
.map( user -> permissionEvaluator.hasPermission( auth2, user, "read" ) ? user : userService.anonymizeUser( user ) )
121120
.map( user -> initUser( user, locale ) );
122121

123122
} else {
124-
return userService.findAllByPrivacyLevel( PrivacyLevelType.PUBLIC, pageable ).map( user -> initUser( user, locale ) );
123+
return userService.findByEnabledTrueAndPrivacyLevelNoAuth( PrivacyLevelType.PUBLIC, pageable ).map( user -> initUser( user, locale ) );
125124
}
126125
}
127126

@@ -138,11 +137,11 @@ public Object getGenes( @RequestHeader(value = HttpHeaders.AUTHORIZATION, requir
138137
checkAuth( authorizationHeader, auth );
139138
if ( applicationSettings.getPrivacy().isEnableAnonymizedSearchResults() ) {
140139
final Authentication auth2 = SecurityContextHolder.getContext().getAuthentication();
141-
return userGeneService.findAllNoAuth( pageable )
140+
return userGeneService.findByUserEnabledTrueNoAuth( pageable )
142141
.map( userGene -> permissionEvaluator.hasPermission( auth2, userGene, "read" ) ? userGene : userService.anonymizeUserGene( userGene ) )
143142
.map( userGene -> initUserGene( userGene, locale ) );
144143
} else {
145-
return userGeneService.findAllByPrivacyLevel( PrivacyLevelType.PUBLIC, pageable ).map( userGene -> initUserGene( userGene, locale ) );
144+
return userGeneService.findByUserEnabledTrueAndPrivacyLevelNoAuth( PrivacyLevelType.PUBLIC, pageable ).map( userGene -> initUserGene( userGene, locale ) );
146145
}
147146
}
148147

@@ -197,13 +196,13 @@ public Object searchUsersByGeneSymbol( @RequestParam String symbol,
197196
Taxon taxon = taxonService.findById( taxonId );
198197

199198
if ( taxon == null ) {
200-
return ResponseEntity.notFound().build();
199+
throw new ApiException( HttpStatus.NOT_FOUND, String.format( locale, "Unknown taxon ID: %s.", taxonId ) );
201200
}
202201

203202
GeneInfo gene = geneService.findBySymbolAndTaxon( symbol, taxon );
204203

205204
if ( gene == null ) {
206-
return ResponseEntity.notFound().build();
205+
throw new ApiException( HttpStatus.NOT_FOUND, String.format( locale, "Unknown gene with symbol: %s.", symbol ) );
207206
}
208207

209208
if ( tiers == null ) {
@@ -217,7 +216,7 @@ public Object searchUsersByGeneSymbol( @RequestParam String symbol,
217216

218217
// Check if there is an ortholog request for a different taxon than the original gene
219218
if ( orthologTaxon != null && !orthologTaxon.equals( gene.getTaxon() ) && orthologs.isEmpty() ) {
220-
return new ResponseEntity<>( messageSource.getMessage( "ApiController.noOrthologsWithGivenParameters", null, locale ), null, HttpStatus.NOT_FOUND );
219+
throw new ApiException( HttpStatus.NOT_FOUND, messageSource.getMessage( "ApiController.noOrthologsWithGivenParameters", null, locale ) );
221220
}
222221

223222
return initUserGenes( userGeneService.handleGeneSearch( gene, restrictTiers( tiers ), orthologTaxon, researcherPositions, researcherCategories, organsFromUberonIds( organUberonIds ) ), locale );
@@ -251,7 +250,7 @@ public Object searchUsersByGeneSymbol( @RequestParam String symbol,
251250
tiers = EnumSet.of( TierType.valueOf( tier ) );
252251
} catch ( IllegalArgumentException e ) {
253252
log.error( "Could not parse tier type.", e );
254-
return ResponseEntity.badRequest().body( MessageFormat.format( "Unknown tier {0}.", tier ) );
253+
throw new ApiException( HttpStatus.BAD_REQUEST, String.format( locale, "Unknown tier: %s.", tier ), e );
255254
}
256255
}
257256

@@ -267,7 +266,7 @@ public Object getUserById( @PathVariable Integer userId,
267266
checkAuth( authorizationHeader, auth );
268267
User user = userService.findUserById( userId );
269268
if ( user == null ) {
270-
return ResponseEntity.notFound().build();
269+
throw new ApiException( HttpStatus.NOT_FOUND, String.format( locale, "Unknown user with ID: %d.", userId ) );
271270
}
272271
return initUser( user, locale );
273272
}
@@ -282,7 +281,7 @@ public Object getUserByAnonymousId( @PathVariable UUID anonymousId,
282281
checkAuth( authorizationHeader, auth );
283282
User user = userService.findUserByAnonymousIdNoAuth( anonymousId );
284283
if ( user == null ) {
285-
return ResponseEntity.notFound().build();
284+
throw new ApiException( HttpStatus.NOT_FOUND, String.format( "Unknown user with anonymous ID: %s.", anonymousId ) );
286285
}
287286
if ( permissionEvaluator.hasPermission( SecurityContextHolder.getContext().getAuthentication(), user, "read" ) ) {
288287
return initUser( user, locale );

src/main/java/ubc/pavlab/rdp/controllers/SearchViewController.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -233,8 +233,9 @@ public ModelAndView searchOrthologsForGene( @RequestParam String symbol,
233233
return modelAndView;
234234
}
235235

236-
SortedMap<Taxon, Set<GeneInfo>> orthologMap = orthologs.stream()
237-
.collect( Collectors.groupingBy( GeneInfo::getTaxon, TreeMap::new, Collectors.toSet() ) );
236+
Map<Taxon, Set<GeneInfo>> orthologMap = orthologs.stream()
237+
.sorted( Comparator.comparing( GeneInfo::getTaxon, Taxon.getComparator() ) )
238+
.collect( Collectors.groupingBy( GeneInfo::getTaxon, LinkedHashMap::new, Collectors.toSet() ) );
238239

239240
modelAndView.addObject( "orthologs", orthologMap );
240241

src/main/java/ubc/pavlab/rdp/exception/ApiException.java

+5
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,9 @@ public ApiException( HttpStatus status, String message ) {
1212
super( message );
1313
this.status = status;
1414
}
15+
16+
public ApiException( HttpStatus status, String message, Throwable cause ) {
17+
super( message, cause );
18+
this.status = status;
19+
}
1520
}

src/main/java/ubc/pavlab/rdp/model/Taxon.java

+8
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import javax.persistence.*;
99
import java.io.Serializable;
1010
import java.net.URL;
11+
import java.util.Comparator;
1112

1213
/**
1314
* Created by mjacobson on 17/01/18.
@@ -24,6 +25,13 @@
2425
@ToString(of = { "id", "scientificName" })
2526
public class Taxon implements Serializable {
2627

28+
public static Comparator<Taxon> getComparator() {
29+
// taxon are ordered by the ordering field, however the ordering field is not set for remote users
30+
// because it is ignored in JSON serialization
31+
return Comparator.comparing( Taxon::getOrdering, Comparator.nullsLast( Comparator.naturalOrder() ) )
32+
.thenComparing( Taxon::getCommonName );
33+
}
34+
2735
@Id
2836
@Column(name = "taxon_id")
2937
private Integer id;

src/main/java/ubc/pavlab/rdp/model/User.java

+5-4
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ public interface ValidationUserAccount {
4747
public interface ValidationServiceAccount {
4848
}
4949

50+
public static Comparator<User> getComparator() {
51+
return Comparator.comparing( u -> u.getProfile().getFullName() );
52+
}
53+
5054
@Id
5155
@GeneratedValue(strategy = GenerationType.AUTO)
5256
@Column(name = "user_id")
@@ -162,10 +166,7 @@ public boolean hasTaxon( @NonNull Taxon taxon ) {
162166
public Set<Taxon> getTaxons() {
163167
return this.getUserGenes().values().stream()
164168
.map( UserGene::getTaxon )
165-
// taxon are ordered by the ordering field, however the ordering field is not set for remote users
166-
// because it is ignored in JSON serialization
167-
.sorted( Comparator.comparing( Taxon::getOrdering, Comparator.nullsLast( Comparator.naturalOrder() ) )
168-
.thenComparing( Taxon::getCommonName ) )
169+
.sorted( Taxon.getComparator() )
169170
.collect( Collectors.toCollection( LinkedHashSet::new ) );
170171
}
171172

src/main/java/ubc/pavlab/rdp/model/UserGene.java

+20
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,13 @@
1010

1111
import javax.persistence.*;
1212
import java.text.MessageFormat;
13+
import java.util.Comparator;
1314
import java.util.Optional;
1415
import java.util.UUID;
1516

17+
import static java.util.Comparator.*;
18+
import static java.util.Comparator.naturalOrder;
19+
1620
/**
1721
* Created by mjacobson on 17/01/18.
1822
*/
@@ -36,6 +40,22 @@
3640
@ToString(of = { "user", "tier", "privacyLevel" }, callSuper = true)
3741
public class UserGene extends Gene implements UserContent {
3842

43+
/**
44+
* Obtain a comparator for comparing {@link UserGene}.
45+
*
46+
* <ul>
47+
* <li>by anonymity, anonymous users are displayed after</li>
48+
* <li>by taxon, see {@link Taxon#getComparator()}</li>
49+
* <li>by tier</li>
50+
* <li>by user, see {@link User#getComparator()}</li>
51+
* </ul>
52+
*/
53+
public static Comparator<UserGene> getComparator() {
54+
return Comparator.comparing( UserGene::getTaxon, Taxon.getComparator() )
55+
.thenComparing( UserGene::getTier )
56+
.thenComparing( UserGene::getUser, User.getComparator() );
57+
}
58+
3959
@Id
4060
@GeneratedValue(strategy = GenerationType.AUTO)
4161
@Column

src/main/java/ubc/pavlab/rdp/repositories/UserGeneRepository.java

+4-8
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,15 @@ public interface UserGeneRepository extends JpaRepository<UserGene, Integer> {
3535
/**
3636
* Find all genes from enabled users.
3737
*/
38-
Page<UserGene> findAllByUserEnabled( Pageable pageable );
38+
Page<UserGene> findByUserEnabledTrue( Pageable pageable );
3939

4040
/**
41-
* Select all user genes that fall within a given privacy level.
41+
* Find all user genes that fall within a given privacy level amonng enabled users.
4242
* <p>
4343
* If the user gene privacy level is less strict than the profile value or null, then the profile value is taken.
44-
*
45-
* @param privacyLevel
46-
* @param pageable
47-
* @return
4844
*/
49-
@Query("select ug from UserGene as ug join ug.user where (case when ug.privacyLevel is null or ug.privacyLevel > ug.user.profile.privacyLevel then ug.user.profile.privacyLevel else ug.privacyLevel end) = :privacyLevel")
50-
Page<UserGene> findAllByPrivacyLevelAndUserProfilePrivacyLevel( @Param("privacyLevel") PrivacyLevelType privacyLevel, Pageable pageable );
45+
@Query("select ug from UserGene as ug join ug.user where ug.user.enabled is true and (case when ug.privacyLevel is null or ug.privacyLevel > ug.user.profile.privacyLevel then ug.user.profile.privacyLevel else ug.privacyLevel end) = :privacyLevel")
46+
Page<UserGene> findByPrivacyLevelAndUserEnabledTrueAndUserProfilePrivacyLevel( @Param("privacyLevel") PrivacyLevelType privacyLevel, Pageable pageable );
5147

5248
@QueryHints(@QueryHint(name = "org.hibernate.cacheable", value = "true"))
5349
UserGene findById( int id );

src/main/java/ubc/pavlab/rdp/repositories/UserRepository.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ public interface UserRepository extends JpaRepository<User, Integer> {
3131
/**
3232
* Find all enabled users.
3333
*/
34-
Page<User> findAllByEnabled( Pageable pageable );
34+
Page<User> findByEnabledTrue( Pageable pageable );
3535

36-
Page<User> findAllByProfilePrivacyLevel( PrivacyLevelType privacyLevel, Pageable pageable );
36+
Page<User> findByEnabledTrueAndProfilePrivacyLevel( PrivacyLevelType privacyLevel, Pageable pageable );
3737

3838
@Query("select user from User user left join fetch user.roles where lower(user.email) = lower(:email)")
3939
User findByEmailIgnoreCase( @Param("email") String email );

src/main/java/ubc/pavlab/rdp/security/PermissionEvaluatorImpl.java

+9-7
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,17 @@ public boolean hasPermission( Authentication authentication, Object targetDomain
3030
return privacyService.checkUserCanSearch( user, false );
3131
} else if ( permission.equals( "international-search" ) ) {
3232
return privacyService.checkUserCanSearch( user, true );
33-
} else if ( targetDomainObject instanceof UserContent ) {
34-
if ( permission.equals( "read" ) ) {
35-
return privacyService.checkUserCanSee( user, (UserContent) targetDomainObject );
36-
} else if ( permission.equals( "update" ) ) {
37-
return privacyService.checkUserCanUpdate( user, (UserContent) targetDomainObject );
38-
}
33+
} else if ( permission.equals( "read" ) && targetDomainObject == null ) {
34+
// null objects must be let through, so they can be handled as a 404 if necessary
35+
return true;
36+
} else if ( permission.equals( "read" ) && targetDomainObject instanceof UserContent ) {
37+
return privacyService.checkUserCanSee( user, (UserContent) targetDomainObject );
38+
} else if ( permission.equals( "update" ) && targetDomainObject instanceof UserContent ) {
39+
return privacyService.checkUserCanUpdate( user, (UserContent) targetDomainObject );
40+
} else {
41+
throw new UnsupportedOperationException( "Permission " + permission + " is not supported." );
3942
}
4043

41-
throw new UnsupportedOperationException( "Permission " + permission + " is not supported." );
4244
}
4345

4446
@Override

src/main/java/ubc/pavlab/rdp/services/RemoteResourceService.java

+7-7
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,7 @@
1010
import ubc.pavlab.rdp.model.enums.TierType;
1111

1212
import java.net.URI;
13-
import java.util.Collection;
14-
import java.util.Locale;
15-
import java.util.Set;
16-
import java.util.UUID;
13+
import java.util.*;
1714

1815
/**
1916
* Interface for remote resource methods. These mirror methods from UserService and UserGeneService, but the implementation
@@ -33,23 +30,26 @@ public interface RemoteResourceService {
3330
/**
3431
* Find users by name among all partner registries.
3532
*
33+
* @return matching users sorted according to {@link UserService#getUserComparator()}.
3634
* @see ApiController#searchUsersByName(String, Boolean, Set, Set, Set, String, String, Locale)
3735
*/
38-
Collection<User> findUsersByLikeName( String nameLike, Boolean prefix, Set<ResearcherPosition> researcherPositions, Collection<ResearcherCategory> researcherTypes, Collection<String> organUberonIds );
36+
List<User> findUsersByLikeName( String nameLike, Boolean prefix, Set<ResearcherPosition> researcherPositions, Collection<ResearcherCategory> researcherTypes, Collection<String> organUberonIds );
3937

4038
/**
4139
* Find users by description among all partner registries.
4240
*
41+
* @return matching users sorted according to {@link UserService#getUserComparator()}.
4342
* @see ApiController#searchUsersByDescription(String, Set, Set, Set, String, String, Locale)
4443
*/
45-
Collection<User> findUsersByDescription( String descriptionLike, Set<ResearcherPosition> researcherPositions, Collection<ResearcherCategory> researcherTypes, Collection<String> organUberonIds );
44+
List<User> findUsersByDescription( String descriptionLike, Set<ResearcherPosition> researcherPositions, Collection<ResearcherCategory> researcherTypes, Collection<String> organUberonIds );
4645

4746
/**
4847
* Find genes by symbol among all partner registries.
4948
*
49+
* @return matching genes sorted according to {@link UserGeneService#getUserGeneComparator()}.
5050
* @see ApiController#searchUsersByGeneSymbol(String, Integer, Set, Integer, Set, Set, Set, String, String, Locale)
5151
*/
52-
Collection<UserGene> findGenesBySymbol( String symbol, Taxon taxon, Set<TierType> tier, Integer orthologTaxonId, Set<ResearcherPosition> researcherPositions, Set<ResearcherCategory> researcherTypes, Set<String> organUberonIds );
52+
List<UserGene> findGenesBySymbol( String symbol, Taxon taxon, Set<TierType> tier, Integer orthologTaxonId, Set<ResearcherPosition> researcherPositions, Set<ResearcherCategory> researcherTypes, Set<String> organUberonIds );
5353

5454
/**
5555
* Retrieve a user from a specific registry.

0 commit comments

Comments
 (0)