Skip to content

Commit dd3734c

Browse files
committed
Merge branch 'release-1.1.1'
2 parents 11a99e2 + 34b2369 commit dd3734c

File tree

5 files changed

+236
-18
lines changed

5 files changed

+236
-18
lines changed

README.md

+173
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
# Rare Disease Project
2+
Registry for model organism researchers, developed for the Canadian Rare Disease Models & Mechanisms Network
3+
4+
## Setup Instructions
5+
6+
### Requirements
7+
* Java 8+
8+
* MySQL 5.5+ or equivalent
9+
10+
### Obtain Distribution
11+
Download the latest jar distribution [here](https://github.com/PavlidisLab/modinvreg/releases/latest).
12+
13+
The jar contains the core application, including an embedded webserver (Tomcat 8.5.x).
14+
15+
### Set up database
16+
Create database and associated user that the application will use to connect.
17+
18+
Ex.
19+
```SQL
20+
CREATE DATABASE afg CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
21+
CREATE USER 'rdpuser'@'%' identified by 'rdppassword';
22+
grant all on rdp.* to 'rdpuser'@'%';
23+
```
24+
25+
### Customize Settings
26+
The only thing that's left is customization and connection with your database.
27+
This is done by creating the following properties files
28+
29+
* application-prod.properties
30+
- Location: Working directory of running jar
31+
- Defaults: https://github.com/PavlidisLab/modinvreg/blob/master/src/main/resources/application.properties
32+
- Contents: Majority of the properties related to the running of the application (including database connection information) and message customisation.
33+
- Example:
34+
```Ini
35+
# ===============================
36+
# = DATA SOURCE
37+
# ===============================
38+
39+
### Database Connection ###
40+
spring.datasource.url = jdbc:mysql://<Host Here>:3306/<Database Name Here>
41+
spring.datasource.username = DB_USER
42+
spring.datasource.password = DB_PASS
43+
44+
# ==============================================================
45+
# = Spring Email
46+
# ==============================================================
47+
48+
### Email Server Setup ##
49+
spring.mail.host=smtp.gmail.com
50+
spring.mail.username[email protected]
51+
spring.mail.password=example_password
52+
spring.mail.port=587
53+
54+
# ==============================================================
55+
# = Application Specific Defaults
56+
# ==============================================================
57+
58+
# Default user will be ROLE_MANAGER instead of ROLE_USER
59+
# Set to true if you want the default newly created user
60+
# to be able to search and view other users' profile.
61+
rdp.settings.send-email-on-registration=true
62+
63+
### Host of your production website (No Trailing Slash) ###
64+
rdp.site.host=http://register.rare-diseases-catalyst-network.ca
65+
66+
## Context Root Path of production website (leave blank if none) ###
67+
rdp.site.context=
68+
69+
### Emails (these can be the same) ###
70+
71+
### Contact Email is the one displayed in the website ###
72+
rdp.site.contact-email[email protected]
73+
74+
### Admin Email is the one used by the system to send and receive email ###
75+
rdp.site.admin-email[email protected]
76+
77+
# ==============================================================
78+
# = Custom Messages
79+
# ==============================================================
80+
81+
### Customisable HTML Embeddings ###
82+
rdp.site.fullname=Rare Diseases: Models & Mechanisms Network
83+
rdp.site.shortname=RDMMN
84+
85+
rdp.site.logohtml=<h2 class="navbar-text m-0">${rdp.site.fullname}</h2>
86+
87+
rdp.site.welcome=<p>The ${rdp.site.fullname} Registry collects information on model organism researchers \
88+
and the specific genes they study. The Registry is the mechanism by which researchers can find potential \
89+
matches of model organism researchers to human rare disease or cancer researchers.</p>
90+
91+
rdp.site.email.registration-welcome=Thank you for registering with ${rdp.site.fullname}. (${rdp.site.host}${rdp.site.context}).
92+
93+
rdp.site.email.registration-ending=You will then be able to log in using the password you provided, and \
94+
start filling in your profile.\r\n\r\n If you have questions or difficulties with registration please \
95+
feel free to contact us: ${rdp.site.contact-email}
96+
```
97+
* faq.properties
98+
- Location: Specified using `-Dspring.config.location=file:<location>`
99+
- Defaults: Empty
100+
- Contents: All of the question and answer style items that will display in the frequently asked questions page. Each entry requires two parts: `rdp.faq.questions.<q_key>` and `rdp.faq.answers.<q_key>` which hold the question and the corresponding answer, respectively.
101+
- Example: https://github.com/PavlidisLab/modinvreg/blob/master/faq.properties
102+
* login.properties
103+
- Location: Working directory of running jar
104+
- Defaults: https://github.com/PavlidisLab/modinvreg/blob/master/src/main/resources/application.properties
105+
- Contents: Create this file if you would like to customise spring specific messages such as incorrect username/password.
106+
107+
### Running Application
108+
To start the application the simplest command is: java -jar rdp-x.x.x.jar
109+
110+
That being said, there a few options you will likely want to specify
111+
112+
* `-Dserver.port=<port>`: Port for the webserver to listen on.
113+
* `-Dspring.config.location=file:<faq location>`: Location to find the FAQ question & answers
114+
* `-Djava.security.egd=file:/dev/./urandom`: Specify this if you receive logs such as: _"Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [235,853] milliseconds."_ The secure random calls may be blocking as there is not enough entropy to feed them in /dev/random.
115+
116+
The webserver will start initialising, create any missing required tables in the connected database and shortly be serving content at the provided port.
117+
118+
#### Notes
119+
* The organisms table is prepopulated on creation however all but human are turned off. Set the active column to 1 in the database to turn on an organism (Example (this will activate mouse): `update taxon set active=1 where taxon_id=10090`)
120+
* If a required table is not found in the database upon application startup it will create it, it will NOT delete existing data.
121+
122+
## Building From Source
123+
124+
* Clone the repo or download the source distribution.
125+
- `git clone https://github.com/PavlidisLab/modinvreg.git`
126+
* Package
127+
- `cd modinvreg/`
128+
- `./mvnw package`
129+
130+
The jar will be create in the target directory.
131+
132+
For custom deployments see: https://docs.spring.io/spring-boot/docs/current/reference/html/cloud-deployment.html
133+
To install as a system service see: https://docs.spring.io/spring-boot/docs/current/reference/html/deployment-install.html
134+
135+
## Example Setup for Centos 7 With Mysql 5.5+ & Apache
136+
137+
### Database
138+
* mysql -uroot -p
139+
* CREATE DATABASE rdp CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
140+
* CREATE USER 'rdpuser'@'%' identified by 'rdppassword';
141+
* grant all on rdp.* to 'rdpuser'@'%';
142+
143+
### Application
144+
* `cd /project/directory`
145+
* `wget https://github.com/PavlidisLab/modinvreg/releases/download/vx.x/rdp-x.x.x.jar`
146+
* create application-prod.properties, faq.properties and optionally login.properties
147+
* test run the jar: java -Dserver.port=8080 -Dspring.config.location=file:faq.properties -Djava.security.egd=file:/dev/./urandom -jar rdp-x.x.x.jar
148+
* (Optional) Log into the database and activate other organisms.
149+
* Set up jar as systemd service:
150+
- create file /etc/systemd/system/rdp.service containing similar to the following:
151+
152+
```Ini
153+
[Unit]
154+
Description=rdp
155+
After=syslog.target
156+
157+
[Service]
158+
User=tomcat
159+
Group=tomcat
160+
WorkingDirectory=/project/directory
161+
ExecStart=/bin/java -Dserver.port=8083 -Dspring.config.location=file:faq.properties -Djava.security.egd=file:/dev/./urandom -jar rdp-x.x.x.jar
162+
SuccessExitStatus=143
163+
164+
[Install]
165+
WantedBy=multi-user.target
166+
```
167+
* Start service: `systemctl start rdp.service`
168+
* View logs: `journalctl -f -u rdp.service`
169+
170+
### Apache
171+
* Create a standard virtualhost with the following proxies:
172+
- `ProxyPass / http://localhost:<port>/`
173+
- `ProxyPassReverse / http://localhost:<port>/`

pom.xml

+1-1
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.1.0</version>
8+
<version>1.1.1</version>
99

1010
<parent>
1111
<groupId>org.springframework.boot</groupId>

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ public void updateTermsAndGenesInTaxon( User user, Taxon taxon, Map<Gene, TierTy
297297
Map<String, Integer> goIdToHibernateId = user.getUserTerms().stream()
298298
.filter( t -> t.getTaxon().equals( taxon ) )
299299
.collect( Collectors.toMap( GeneOntologyTerm::getGoId, UserTerm::getId ) );
300-
Collection<UserTerm> updatedTerms = convertTerms( user, taxon, goTerms );
300+
Collection<UserTerm> updatedTerms = convertTermTypes( goTerms, taxon, genesToTierMap.keySet() );
301301
updatedTerms.forEach( t -> t.setId( goIdToHibernateId.get( t.getGoId() ) ) );
302302

303303
removeTermsFromUserByTaxon( user, taxon );

src/test/java/ubc/pavlab/rdp/services/UserServiceImplTest.java

+49-13
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22

33
import org.apache.commons.logging.Log;
44
import org.apache.commons.logging.LogFactory;
5+
import org.assertj.core.util.Maps;
56
import org.junit.Before;
67
import org.junit.Test;
78
import org.junit.runner.RunWith;
89
import org.mockito.Mockito;
10+
import org.mockito.internal.util.collections.Sets;
911
import org.springframework.beans.factory.annotation.Autowired;
1012
import org.springframework.boot.test.context.TestConfiguration;
1113
import org.springframework.boot.test.mock.mockito.MockBean;
@@ -160,7 +162,7 @@ private void setUpRecomendTermsMocks() {
160162

161163
expected.forEach( ( key, value ) -> key.getSizesByTaxon().put( taxon, value + 10 ) );
162164

163-
Mockito.when( goService.termFrequencyMap( Mockito.anyCollectionOf(Gene.class) ) ).thenReturn( expected );
165+
Mockito.when( goService.termFrequencyMap( Mockito.anyCollectionOf( Gene.class ) ) ).thenReturn( expected );
164166
}
165167

166168

@@ -701,7 +703,7 @@ public void updateTermsAndGenesInTaxon_whenUserHasNoGeneOrTerms() {
701703
Collection<Gene> calculatedGenes = IntStream.range( 101, 110 ).boxed().map(
702704
nbr -> createGene( nbr, taxon )
703705
).collect( Collectors.toList() );
704-
Mockito.when( goService.getGenes( Mockito.anyCollectionOf(GeneOntologyTerm.class), Mockito.any() ) ).thenReturn( calculatedGenes );
706+
Mockito.when( goService.getGenes( Mockito.anyCollectionOf( GeneOntologyTerm.class ), Mockito.any() ) ).thenReturn( calculatedGenes );
705707

706708
Collection<GeneOntologyTerm> terms = IntStream.range( 1, 10 ).boxed().map(
707709
nbr -> createTermWithGene( toGOId( nbr ), createGene( nbr, taxon ) )
@@ -743,7 +745,7 @@ public void updateTermsAndGenesInTaxon_whenUserHasGenesAndTerms() {
743745
Collection<Gene> calculatedGenes = IntStream.range( 101, 110 ).boxed().map(
744746
nbr -> createGene( nbr, taxon )
745747
).collect( Collectors.toList() );
746-
Mockito.when( goService.getGenes( Mockito.anyCollectionOf(GeneOntologyTerm.class), Mockito.any() ) ).thenReturn( calculatedGenes );
748+
Mockito.when( goService.getGenes( Mockito.anyCollectionOf( GeneOntologyTerm.class ), Mockito.any() ) ).thenReturn( calculatedGenes );
747749

748750
Collection<GeneOntologyTerm> terms = IntStream.range( 1, 10 ).boxed().map(
749751
nbr -> createTermWithGene( toGOId( nbr ), createGene( nbr, taxon ) )
@@ -774,7 +776,7 @@ public void updateTermsAndGenesInTaxon_whenManualAndCalculatedGenesOverlap_thenK
774776
Collection<Gene> calculatedGenes = IntStream.range( 5, 14 ).boxed().map(
775777
nbr -> createGene( nbr, taxon )
776778
).collect( Collectors.toList() );
777-
Mockito.when( goService.getGenes( Mockito.anyCollectionOf(GeneOntologyTerm.class), Mockito.any() ) ).thenReturn( calculatedGenes );
779+
Mockito.when( goService.getGenes( Mockito.anyCollectionOf( GeneOntologyTerm.class ), Mockito.any() ) ).thenReturn( calculatedGenes );
778780

779781
Collection<GeneOntologyTerm> terms = IntStream.range( 1, 10 ).boxed().map(
780782
nbr -> createTermWithGene( toGOId( nbr ), createGene( nbr, taxon ) )
@@ -814,7 +816,7 @@ public void updateTermsAndGenesInTaxon_whenOldAndNewOverlap_thenRetainIds() {
814816

815817
// Mock goService.getRelatedGenes
816818
Collection<Gene> calculatedGenes = Collections.singleton( createGene( 105, taxon ) );
817-
Mockito.when( goService.getGenes( Mockito.anyCollectionOf(GeneOntologyTerm.class), Mockito.any() ) ).thenReturn( calculatedGenes );
819+
Mockito.when( goService.getGenes( Mockito.anyCollectionOf( GeneOntologyTerm.class ), Mockito.any() ) ).thenReturn( calculatedGenes );
818820

819821
Collection<GeneOntologyTerm> terms = Collections.singleton( createTermWithGene( toGOId( 5 ), createGene( 5, taxon ) ) );
820822

@@ -837,13 +839,47 @@ public void updateTermsAndGenesInTaxon_whenOldAndNewOverlap_thenRetainIds() {
837839
assertThat( user.getUserGenes().values().iterator().next().getId() ).isEqualTo( 1 );
838840
}
839841

842+
@Test
843+
public void updateTermsAndGenesInTaxon_whenUserHasGenesAndTerms_thenUpdateFrequency() {
844+
User user = createUser( 1 );
845+
Taxon taxon = createTaxon( 1 );
846+
847+
Gene geneWillBeRemoved = createGene( 999, taxon );
848+
GeneOntologyTerm termWillBeRemoved = createTermWithGene( toGOId( geneWillBeRemoved.getGeneId() ), geneWillBeRemoved );
849+
user.getUserTerms().add( createUserTerm( 1, termWillBeRemoved, taxon ) );
850+
user.getUserGenes().put( geneWillBeRemoved.getGeneId(), createUserGene( 1, geneWillBeRemoved, user, TierType.TIER1 ) );
851+
852+
Gene geneWillChangeTier = createGene( 5, taxon );
853+
user.getUserGenes().put( geneWillChangeTier.getGeneId(), createUserGene( 2, geneWillChangeTier, user, TierType.TIER2 ) );
854+
855+
UserTerm termWillUpdateFrequency = createUserTerm( 3,
856+
createTermWithGene( toGOId( geneWillChangeTier.getGeneId() ), geneWillBeRemoved, geneWillChangeTier ),
857+
taxon );
858+
// Should have frequency of 2
859+
termWillUpdateFrequency.setFrequency( 2 );
860+
user.getUserTerms().add( termWillUpdateFrequency );
861+
862+
becomeUser( user );
863+
864+
Mockito.when( goService.getGenes( Mockito.anyCollectionOf( GeneOntologyTerm.class ), Mockito.any() ) ).thenReturn( Collections.emptySet() );
865+
866+
Map<Gene, TierType> geneTierMap = Maps.newHashMap( geneWillChangeTier, TierType.TIER1 );
867+
868+
userService.updateTermsAndGenesInTaxon( user, taxon, geneTierMap, Sets.newSet( termWillUpdateFrequency) );
869+
870+
assertThat( user.getUserTerms() ).hasSize( 1 );
871+
assertThat( user.getUserTerms().iterator().next() ).isEqualTo( termWillUpdateFrequency );
872+
assertThat( user.getUserTerms().iterator().next().getFrequency() ).isEqualTo( 1 );
873+
874+
}
875+
840876
private void assertThatUserTermsAreEqualTo( User user, Collection<GeneOntologyTerm> terms ) {
841877
assertThat( user.getUserTerms() ).hasSize( terms.size() );
842878
assertThat( user.getUserTerms().stream().map( GeneOntologyTerm::getGoId ).collect( Collectors.toSet() ) )
843879
.isEqualTo( terms.stream().map( GeneOntologyTerm::getGoId ).collect( Collectors.toSet() ) );
844880
}
845881

846-
private void assertThatUserGenesAreEqualTo( User user, Map<Gene, TierType> expectedGenes ) {
882+
private void assertThatUserGenesAreEqualTo( User user, Map<Gene, TierType> expectedGenes ) {
847883
assertThat( user.getUserGenes().keySet() )
848884
.containsExactlyElementsOf( expectedGenes.keySet().stream().map( Gene::getGeneId )
849885
.collect( Collectors.toSet() ) );
@@ -893,7 +929,7 @@ public void recommendTerms_whenFrequencyLimited_thenReturnBestLimitedResultsOnly
893929

894930
User user = createUser( 1 );
895931
Taxon taxon = createTaxon( 1 );
896-
Collection<UserTerm> found = userService.recommendTerms( user, taxon, -1, -1, 3);
932+
Collection<UserTerm> found = userService.recommendTerms( user, taxon, -1, -1, 3 );
897933
assertThat( found.stream().map( GeneOntologyTerm::getGoId ).collect( Collectors.toList() ) ).containsExactlyInAnyOrder( toGOId( 1 ), toGOId( 7 ), toGOId( 8 ) );
898934

899935
found = userService.recommendTerms( user, taxon, -1, -1, 4 );
@@ -906,7 +942,7 @@ public void recommendTerms_whenFrequencyLimitedAndSizeLimited_thenReturnBestLimi
906942

907943
User user = createUser( 1 );
908944
Taxon taxon = createTaxon( 1 );
909-
Collection<UserTerm> found = userService.recommendTerms( user, taxon, 11, 12, 2);
945+
Collection<UserTerm> found = userService.recommendTerms( user, taxon, 11, 12, 2 );
910946
assertThat( found.stream().map( GeneOntologyTerm::getGoId ).collect( Collectors.toList() ) ).containsExactlyInAnyOrder( toGOId( 0 ), toGOId( 4 ), toGOId( 6 ) );
911947

912948
found = userService.recommendTerms( user, taxon, 1, 11, 2 );
@@ -919,7 +955,7 @@ public void recommendTerms_whenRedundantTerms_thenReturnOnlyMostSpecific() {
919955

920956
User user = createUser( 1 );
921957
Taxon taxon = createTaxon( 1 );
922-
Collection<UserTerm> found = userService.recommendTerms( user, taxon, 11, 11, 1);
958+
Collection<UserTerm> found = userService.recommendTerms( user, taxon, 11, 11, 1 );
923959
assertThat( found.stream().map( GeneOntologyTerm::getGoId ).collect( Collectors.toList() ) ).containsExactlyInAnyOrder( toGOId( 2 ), toGOId( 3 ), toGOId( 5 ), toGOId( 99 ) );
924960

925961
found = userService.recommendTerms( user, taxon, 1, 11, 2 );
@@ -929,11 +965,11 @@ public void recommendTerms_whenRedundantTerms_thenReturnOnlyMostSpecific() {
929965
@Test
930966
public void recommendTerms_whenUserHasNoGenes_thenReturnEmpty() {
931967
Map<GeneOntologyTerm, Long> empyFMap = new HashMap<>();
932-
Mockito.when( goService.termFrequencyMap( Mockito.anyCollectionOf(Gene.class) ) ).thenReturn( empyFMap );
968+
Mockito.when( goService.termFrequencyMap( Mockito.anyCollectionOf( Gene.class ) ) ).thenReturn( empyFMap );
933969

934970
User user = createUser( 1 );
935971
Taxon taxon = createTaxon( 1 );
936-
Collection<UserTerm> found = userService.recommendTerms( user, taxon, -1, -1, -1);
972+
Collection<UserTerm> found = userService.recommendTerms( user, taxon, -1, -1, -1 );
937973
assertThat( found ).isEmpty();
938974
}
939975

@@ -942,7 +978,7 @@ public void recommendTerms_whenUserNull_thenReturnNull() {
942978
setUpRecomendTermsMocks();
943979

944980
Taxon taxon = createTaxon( 1 );
945-
Collection<UserTerm> found = userService.recommendTerms( null, taxon, -1, -1, -1);
981+
Collection<UserTerm> found = userService.recommendTerms( null, taxon, -1, -1, -1 );
946982
assertThat( found ).isNull();
947983
}
948984

@@ -951,7 +987,7 @@ public void recommendTerms_whenTaxonNull_thenReturnNull() {
951987
setUpRecomendTermsMocks();
952988

953989
User user = createUser( 1 );
954-
Collection<UserTerm> found = userService.recommendTerms( user, null, -1, -1, -1);
990+
Collection<UserTerm> found = userService.recommendTerms( user, null, -1, -1, -1 );
955991
assertThat( found ).isNull();
956992
}
957993

src/test/java/ubc/pavlab/rdp/util/BaseTest.java

+12-3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import ubc.pavlab.rdp.model.enums.TierType;
88

99
import java.util.Arrays;
10+
import java.util.Set;
1011
import java.util.stream.Collectors;
1112

1213
import static org.mockito.Mockito.mock;
@@ -92,13 +93,15 @@ protected GeneOntologyTerm createTerm( String id ) {
9293
return term;
9394
}
9495

95-
protected GeneOntologyTerm createTermWithGene( String id, Gene gene ) {
96+
protected GeneOntologyTerm createTermWithGene( String id, Gene... genes ) {
9697
GeneOntologyTerm term = new GeneOntologyTerm();
9798
term.setGoId( id );
9899
term.setObsolete( false );
99100

100-
term.getDirectGenes().add( gene );
101-
gene.getTerms().add( term );
101+
Arrays.stream(genes).forEach( g -> {
102+
term.getDirectGenes().add( g );
103+
g.getTerms().add( term );
104+
} );
102105

103106
return term;
104107
}
@@ -117,6 +120,12 @@ protected UserTerm createUserTerm( int id, GeneOntologyTerm term, Taxon taxon )
117120
return ut;
118121
}
119122

123+
protected UserTerm createUserTerm( int id, GeneOntologyTerm term, Taxon taxon, Set<Gene> genes ) {
124+
UserTerm ut = new UserTerm(term, taxon, genes );
125+
ut.setId( id );
126+
return ut;
127+
}
128+
120129
protected UserGene createUserGene( int id, Gene gene, User user, TierType tier ) {
121130
UserGene ug = new UserGene( gene, user, tier );
122131
ug.setId( id );

0 commit comments

Comments
 (0)