Merge "Introduced preliminary support for meta data field retrieval"
diff --git a/README.md b/README.md
index a744b66..634aae8 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,7 @@
# Setup
-Prerequisites: Jdk 1.7, Git, Maven 3, MySQL (optional).
+Prerequisites: Jdk 1.8, Git, Maven 3, MySQL (optional), Postfix (optional).
Clone the latest version of Kustvakt
<pre>
@@ -147,6 +147,92 @@
```full/src/main/resources/db/new-mysql``` and other paths specified in
```jdbc.schemaPath```.
+## Enabling Mail
+
+Kustvakt supports email notification, for instance of a invitation to a user-group.
+The mail setting is by default configured for a mail server at localhost post 25.
+You can setup a mail server for example by using [Postfix](http://www.postfix.org/).
+
+In kustvakt.conf or kustvakt-test.conf, set
+
+ mail.enabled = true
+ mail.receiver = test@localhost
+ mail.sender = noreply@ids-mannheim.de
+
+
+You can change ```mail.sender``` value to any email address.
+```mail.receiver``` is only used for testing purpose. Change
+```test``` to any username available in your system, or create an alias for
+```test@localhost```.
+
+To view the mailbox, you can use ```mailx```
+
+ $ mailx -u test
+ s-nail version v14.8.6. Type ? for help.
+ "/var/mail/test": 1 messages 0 unread
+ O 1 noreply@ids-mannhe Wed Feb 21 18:07 30/1227 Invitation to join
+
+
+### Creating email aliases
+
+ sudo vi /etc/postfix/main.cf
+
+In main.cf, set
+
+ "virtual_alias_maps = hash:/etc/postfix/alias"
+
+Create alias file:
+
+ sudo vi /etc/postfix/alias
+
+In the alias file, create an alias for ```test@localhost``` to a user in your system
+
+ test@localhost username
+
+Create alias database
+
+ sudo postmap /etc/postfix/alias
+
+Restart postfix
+
+ sudo /etc/init.d/postfix restart
+
+
+By default, any emails sent to ```test@localhost``` will be available at
+```/var/mail/username```.
+
+### Customizing SMTP configuration
+
+To connect to an external/remote mail server instead of using local Postfix,
+copy ```full/src/main/resources/properties/mail.properties``` to
+the ```full/``` folder. Customize the properties in the file according to
+the mail server setup.
+
+ mail.host = smtp.host.address
+ mail.port = 123
+ mail.connectiontimeout = 3000
+ mail.auth = true
+ mail.starttls.enable = true
+ mail.username = username
+ mail.password = password
+
+### Customizing Mail template
+
+Kustvakt uses [Apache Velocity](http://velocity.apache.org/) as the email template engine and searches for templates located at:
+
+```full/src/main/resources/templates```.
+
+For instance, the template for email notification of user-group invitation is
+
+```full/src/main/resources/templates/notification.vm```
+
+You can change the template according to Velocity Template Language.
+
+In ```kustvakt.conf``` or ```kustvakt-test.conf```, specify which template should be used.
+
+ template.group.invitation = notification.vm
+
+
# Known issues
Tests are verbose - they do not necessarily imply system errors.
diff --git a/core/Changes b/core/Changes
index d1d629e..3b341f8 100644
--- a/core/Changes
+++ b/core/Changes
@@ -1,14 +1,22 @@
-0.59.10 2018-02-01
+version 0.59.10
+20/02/2018
- updated hibernate and reflection versions (margaretha)
- added Changes file (margaretha)
- merged BeanConfigBaseTest to BeanConfigTest in /full (margaretha)
- added status code for already deleted entry (margaretha)
- - updated library versions and java environment (margaretha)
-0.59.9 2017-11-08
+ - updated library versions and java environment (margaretha)
+ - added status codes (margaretha)
+ - moved validation.properties (margaretha)
+ - fixed unrecognize media-type application/json (margaretha)
+
+version 0.59.9
+08/11/2017
- fixed missing exception in JsonUtils (margaretha)
- fixed and restructured KustvaktResponseHandler (margaretha)
- updated status code in ParameterChecker (margaretha)
-0.59.8 2017-10-24
+
+version 0.59.8
+24/10/2017
- restructured Kustvakt and created core project (margaretha)
- marked loader classes as deprecated (margaretha)
- updated Spring version (margaretha)
diff --git a/core/pom.xml b/core/pom.xml
index 2e8728d..ee9b4b0 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -10,7 +10,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-framework.version>5.0.3.RELEASE</spring-framework.version>
<jersey.version>1.19.4</jersey.version>
- <jetty.version>8.2.0.v20160908</jetty.version>
+ <jetty.version>9.4.8.v20171121</jetty.version>
<hibernate.version>5.1.11.Final</hibernate.version>
</properties>
<build>
@@ -108,7 +108,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
- <version>2.19.1</version>
+ <version>2.20.1</version>
<configuration>
<reuseForks>false</reuseForks>
@@ -358,6 +358,8 @@
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
+
+ <!-- jetty -->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
@@ -369,6 +371,12 @@
<version>${jetty.version}</version>
</dependency>
<dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-webapp</artifactId>
+ <version>${jetty.version}</version>
+ </dependency>
+
+ <dependency>
<groupId>asm</groupId>
<artifactId>asm</artifactId>
<version>3.3.1</version>
diff --git a/core/src/main/java/de/ids_mannheim/korap/exceptions/StatusCodes.java b/core/src/main/java/de/ids_mannheim/korap/exceptions/StatusCodes.java
index 5b57438..941b5af 100644
--- a/core/src/main/java/de/ids_mannheim/korap/exceptions/StatusCodes.java
+++ b/core/src/main/java/de/ids_mannheim/korap/exceptions/StatusCodes.java
@@ -79,9 +79,16 @@
public static final int DB_INSERT_SUCCESSFUL = 505;
public static final int DB_DELETE_SUCCESSFUL = 506;
public static final int DB_UPDATE_SUCCESSFUL = 507;
-
public static final int DB_ENTRY_EXISTS = 508;
- public static final int DB_ENTRY_DELETED = 509;
+
+
+ // User group and member
+ public static final int GROUP_MEMBER_EXISTS = 601;
+ public static final int GROUP_MEMBER_DELETED = 602;
+ public static final int GROUP_MEMBER_NOT_FOUND = 603;
+ public static final int INVITATION_EXPIRED = 604;
+ public static final int GROUP_NOT_FOUND = 605;
+
// public static final int ARGUMENT_VALIDATION_FAILURE = 700;
// public static final int ARGUMENT_VALIDATION_FAILURE = 701;
diff --git a/core/src/main/java/de/ids_mannheim/korap/user/User.java b/core/src/main/java/de/ids_mannheim/korap/user/User.java
index 8732a21..3cba4a2 100644
--- a/core/src/main/java/de/ids_mannheim/korap/user/User.java
+++ b/core/src/main/java/de/ids_mannheim/korap/user/User.java
@@ -24,9 +24,10 @@
@Data
public abstract class User implements Serializable {
-// public static final int ADMINISTRATOR_ID = 34349733;
-// public static final String ADMINISTRATOR_NAME = "admin";
-
+ //EM: add
+ private String email;
+ //EM: finish
+
private Integer id;
// in local its username, in shib it's edupersonPrincipalName
private String username;
diff --git a/core/src/main/java/de/ids_mannheim/korap/web/KustvaktBaseServer.java b/core/src/main/java/de/ids_mannheim/korap/web/KustvaktBaseServer.java
index 7ad0500..8496d04 100644
--- a/core/src/main/java/de/ids_mannheim/korap/web/KustvaktBaseServer.java
+++ b/core/src/main/java/de/ids_mannheim/korap/web/KustvaktBaseServer.java
@@ -4,14 +4,14 @@
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.bio.SocketConnector;
+import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
+import org.springframework.stereotype.Component;
import org.springframework.web.context.ContextLoaderListener;
import com.sun.jersey.spi.spring.container.servlet.SpringServlet;
-import de.ids_mannheim.korap.config.BeansFactory;
import de.ids_mannheim.korap.config.KustvaktConfiguration;
import lombok.Getter;
import lombok.Setter;
@@ -20,11 +20,14 @@
* @author hanl
* @date 01/06/2015
*/
+@Component
public abstract class KustvaktBaseServer {
-
+
+ protected static KustvaktConfiguration config;
+
protected static String rootPackages;
protected static KustvaktArgs kargs;
-
+
public KustvaktBaseServer () {
KustvaktConfiguration.loadLogger();
}
@@ -59,38 +62,37 @@
return kargs;
}
- protected abstract void setup ();
+ protected void start () {
- protected void start(){
- KustvaktConfiguration config = BeansFactory.getKustvaktContext().getConfiguration();
-
- if (kargs.init){
- setup();
- }
- if (kargs.port == -1){
+ if (kargs.port == -1) {
kargs.setPort(config.getPort());
}
-
+
Server server = new Server();
- ServletContextHandler contextHandler = new ServletContextHandler(
- ServletContextHandler.NO_SESSIONS);
+
+ ServletContextHandler contextHandler =
+ new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
contextHandler.setContextPath("/");
- contextHandler.setInitParameter("contextConfigLocation", "classpath:"+kargs.getConfig());
-
+ contextHandler.setInitParameter("contextConfigLocation",
+ "classpath:" + kargs.getConfig());
+
ServletContextListener listener = new ContextLoaderListener();
contextHandler.addEventListener(listener);
ServletHolder servletHolder = new ServletHolder(new SpringServlet());
- servletHolder.setInitParameter("com.sun.jersey.config.property.packages",
- rootPackages);
+ servletHolder.setInitParameter(
+ "com.sun.jersey.config.property.packages", rootPackages);
+ servletHolder.setInitParameter(
+ "com.sun.jersey.api.json.POJOMappingFeature", "true");
servletHolder.setInitOrder(1);
contextHandler.addServlet(servletHolder, config.getBaseURL());
-
- SocketConnector connector = new SocketConnector();
+
+ ServerConnector connector = new ServerConnector(server);
connector.setPort(kargs.port);
- connector.setMaxIdleTime(60000);
-
+ connector.setIdleTimeout(60000);
+
server.setHandler(contextHandler);
+
server.setConnectors(new Connector[] { connector });
try {
server.start();
@@ -99,11 +101,11 @@
catch (Exception e) {
System.out.println("Server could not be started!");
System.out.println(e.getMessage());
+ e.printStackTrace();
System.exit(-1);
-// e.printStackTrace();
}
}
-
+
@Setter
public static class KustvaktArgs {
diff --git a/full/src/main/resources/validation.properties b/core/src/main/resources/validation.properties
similarity index 100%
rename from full/src/main/resources/validation.properties
rename to core/src/main/resources/validation.properties
diff --git a/full/Changes b/full/Changes
index b147983..7d83752 100644
--- a/full/Changes
+++ b/full/Changes
@@ -1,17 +1,35 @@
-0.59.10 2018-02-01
+version 0.60 release
+21/02/2018
+ - set up mail settings using localhost port 25 (margaretha)
+ - added mail template in kustvakt configuration (margaretha)
+ - added mail settings to readme (margaretha)
+ - disabled email notification for auto group (margaretha)
+
+version 0.59.10
+20/02/2018
- added sort VC by id (margaretha)
- added test cases regarding VC sharing (margaretha)
- implemented withdraw VC from publication (margaretha)
- added Changes file (margaretha)
- - implemented add users to group (margaretha)
+ - implemented add/invite users to group (margaretha)
- implemented delete user-group and member tasks (margaretha)
- added userMemberStatus in group lists (margaretha)
- updated and added SQL test data (margaretha)
- added user group related tests (margaretha)
- implemented custom configuration for deleting user groups and members (margaretha)
- updated library versions and java environment (margaretha)
+ - added expiration time check for member invitation (margaretha)
+ - moved .properties files (margaretha)
+ - merged changelog file to Changes (margaretha)
+ - updated status codes and error messages to be more detailed (margaretha)
+ - testing mail implementation using embedded jetty jndi (margaretha)
+ - fixed collection rewrite regarding OR operation with other fields (margaretha)
+ - implemented sending mail using spring injection and removed jetty jndi (margaretha)
+ - fixed unrecognized application/json (margaretha)
+ - fixed and updated velocity template (margaretha)
-0.59.9 2018-01-19
+version 0.59.9
+19/01/2018
- restructured basic authentication (margaretha)
- fixed AuthenticationException to include authentication scheme (margaretha)
- fixed rewrite redundancy in collection rewrite (margaretha)
@@ -21,7 +39,7 @@
- fixed foundry rewrite for korap span without wrap node (margaretha)
- implemented list user group (margaretha)
- implemented delete VC task (margaretha)
- - implemented create user-group, subscribe to usergroup, unsubscribe to user group tasks(margaretha)
+ - implemented create user-group, subscribe to user-groups, unsubscribe to user-groups tasks(margaretha)
- fixed handling JSON mapping exception for missing enums (margaretha)
- implemented list VC task (margaretha)
- added KoralQuery in VC lists (margaretha)
@@ -37,8 +55,8 @@
- removed PredefinedUserGroup.ALL and related codes (margaretha)
- implemented search for published VC (margaretha)
-
-0.59.8 2017-09-21
+version 0.59.8
+21/09/2017
- restructured statistics service (margaretha)
- removed deprecated loader codes and tests (margaretha)
- removed old Spring java configurations (margaretha)
@@ -54,5 +72,14 @@
- fixed missing exceptions in JsonUtils (margaretha)
- restructured web filters and authentication codes (margaretha)
- implemented create/store VC (margaretha)
- - fixed collection rewrite bug regarding availability with operation or (margaretha)
-
\ No newline at end of file
+ - fixed collection rewrite bug regarding availability with operation or (margaretha)
+
+version 0.59.7
+13/10/2016
+ - MOD: updated search to use new siglen (diewald)
+ - MOD: fixed matchinfo retrieval in light service (diewald)
+
+05/05/2015
+ - ADD: rest test suite for user service (hanl)
+ - MOD: setup parameter modification (hanl)
+ - ADD: oauth2 client unique constraint (hanl)
diff --git a/full/pom.xml b/full/pom.xml
index bccc9bf..b1b92c8 100644
--- a/full/pom.xml
+++ b/full/pom.xml
@@ -3,12 +3,13 @@
<modelVersion>4.0.0</modelVersion>
<groupId>de.ids_mannheim.korap</groupId>
<artifactId>Kustvakt-full</artifactId>
- <version>0.59.10</version>
+ <version>0.60</version>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-framework.version>5.0.3.RELEASE</spring-framework.version>
<spring-security.version>4.2.3.RELEASE</spring-security.version>
+ <jetty.version>9.4.8.v20171121</jetty.version>
<jersey.version>1.19.4</jersey.version>
<hibernate.version>5.1.11.Final</hibernate.version>
</properties>
@@ -24,6 +25,7 @@
<include>**/*.kustvakt</include>
<include>**/*.properties</include>
<include>**/*.sql</include>
+ <include>**/*.vm</include>
</includes>
</resource>
</resources>
@@ -72,10 +74,9 @@
<compilerVersion>${java.version}</compilerVersion>
<source>${java.version}</source>
<target>${java.version}</target>
- <!-- <compilerArguments>
- <processor>lombok.launch.AnnotationProcessorHider$AnnotationProcessor</processor>
- <processor>org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</processor>
- </compilerArguments> -->
+ <!-- <compilerArguments> <processor>lombok.launch.AnnotationProcessorHider$AnnotationProcessor</processor>
+ <processor>org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</processor>
+ </compilerArguments> -->
<processors>
<processor>lombok.launch.AnnotationProcessorHider$AnnotationProcessor</processor>
<processor>org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</processor>
@@ -85,12 +86,12 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
- <version>2.19.1</version>
+ <version>2.20.1</version>
<configuration>
<reuseForks>false</reuseForks>
<forkCount>2</forkCount>
<threadCount>10</threadCount>
-
+ <argLine>-Xmx1024m -XX:MaxPermSize=256m</argLine>
<excludes>
<!-- <exclude>de/ids_mannheim/korap/suites/*.java</exclude> -->
<!-- <exclude>de/ids_mannheim/korap/dao/*.java</exclude> -->
@@ -183,7 +184,7 @@
<exclusions>
<exclusion>
<groupId>org.javassist</groupId>
- <artifactId>javassist</artifactId>
+ <artifactId>javassist</artifactId>
</exclusion>
</exclusions>
</dependency>
@@ -194,9 +195,14 @@
<scope>provided</scope>
</dependency>
<dependency>
- <groupId>org.javassist</groupId>
- <artifactId>javassist</artifactId>
- <version>3.22.0-GA</version>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-java8</artifactId>
+ <version>${hibernate.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.javassist</groupId>
+ <artifactId>javassist</artifactId>
+ <version>3.22.0-GA</version>
</dependency>
<!-- MySql -->
@@ -219,6 +225,11 @@
<version>${jersey.version}</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>com.sun.jersey</groupId>
+ <artifactId>jersey-json</artifactId>
+ <version>${jersey.version}</version>
+ </dependency>
<!-- Spring -->
<dependency>
@@ -232,14 +243,55 @@
<version>${spring-framework.version}</version>
</dependency>
<dependency>
- <groupId>org.springframework.security</groupId>
- <artifactId>spring-security-core</artifactId>
- <version>${spring-security.version}</version>
+ <groupId>org.springframework.security</groupId>
+ <artifactId>spring-security-core</artifactId>
+ <version>${spring-security.version}</version>
</dependency>
<dependency>
- <groupId>org.springframework.security</groupId>
- <artifactId>spring-security-web</artifactId>
- <version>${spring-security.version}</version>
+ <groupId>org.springframework.security</groupId>
+ <artifactId>spring-security-web</artifactId>
+ <version>${spring-security.version}</version>
+ </dependency>
+
+ <!-- jetty -->
+ <!-- <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-jndi</artifactId>
+ <version>${jetty.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-plus</artifactId>
+ <version>${jetty.version}</version>
+ </dependency> -->
+
+ <!-- velocity -->
+ <dependency>
+ <groupId>org.apache.velocity</groupId>
+ <artifactId>velocity-engine-core</artifactId>
+ <version>2.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.velocity</groupId>
+ <artifactId>velocity-tools</artifactId>
+ <version>2.0</version>
+ </dependency>
+ <!-- mail -->
+ <dependency>
+ <groupId>com.sun.mail</groupId>
+ <artifactId>javax.mail</artifactId>
+ <version>1.6.0</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.activation</groupId>
+ <artifactId>activation</artifactId>
+ <version>1.1.1</version>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>javax.servlet-api</artifactId>
+ <version>4.0.0</version>
</dependency>
<!-- Flyway -->
@@ -249,4 +301,5 @@
<version>4.0</version>
</dependency>
</dependencies>
+
</project>
\ No newline at end of file
diff --git a/full/src/main/java/de/ids_mannheim/korap/authentication/KustvaktAuthenticationManager.java b/full/src/main/java/de/ids_mannheim/korap/authentication/KustvaktAuthenticationManager.java
index 46649eb..0015e89 100644
--- a/full/src/main/java/de/ids_mannheim/korap/authentication/KustvaktAuthenticationManager.java
+++ b/full/src/main/java/de/ids_mannheim/korap/authentication/KustvaktAuthenticationManager.java
@@ -139,6 +139,8 @@
//EM:copied from EntityDao
KorAPUser user = new KorAPUser(); // oder eigentlich new DemoUser oder new DefaultUser.
user.setUsername(username);
+ // get user data
+ user.setEmail(config.getTestEmail());
return user;
// return entHandler.getAccount(username);
}
@@ -201,7 +203,6 @@
@Override
public void setAccessAndLocation(User user, HttpHeaders headers) {
- Boolean DEBUG_LOG = true;
MultivaluedMap<String, String> headerMap = headers.getRequestHeaders();
Location location = Location.EXTERN;
CorpusAccess corpusAccess = CorpusAccess.FREE;
@@ -210,14 +211,13 @@
{
// to be absolutely sure:
user.setCorpusAccess(User.CorpusAccess.FREE);
- if( DEBUG_LOG == true )
- System.out.printf("setAccessAndLocation: DemoUser: location=%s, access=%s.\n", user.locationtoString(), user.accesstoString());
+ jlog.debug("setAccessAndLocation: DemoUser: location=%s, access=%s.\n", user.locationtoString(), user.accesstoString());
return;
}
- if (headerMap != null && headerMap.containsKey(org.eclipse.jetty.http.HttpHeaders.X_FORWARDED_FOR)) {
+ if (headerMap != null && headerMap.containsKey(com.google.common.net.HttpHeaders.X_FORWARDED_FOR)) {
- String[] vals = headerMap.getFirst(org.eclipse.jetty.http.HttpHeaders.X_FORWARDED_FOR).split(",");
+ String[] vals = headerMap.getFirst(com.google.common.net.HttpHeaders.X_FORWARDED_FOR).split(",");
String clientAddress = vals[0];
try {
@@ -243,8 +243,8 @@
user.setLocation(location);
user.setCorpusAccess(corpusAccess);
- if( DEBUG_LOG == true )
- System.out.printf("setAccessAndLocation: KorAPUser: location=%s, access=%s.\n", user.locationtoString(), user.accesstoString());
+
+ jlog.debug("setAccessAndLocation: KorAPUser: location=%s, access=%s.\n", user.locationtoString(), user.accesstoString());
}
} // getAccess
diff --git a/full/src/main/java/de/ids_mannheim/korap/config/FullConfiguration.java b/full/src/main/java/de/ids_mannheim/korap/config/FullConfiguration.java
index 7b9c48c..201fc4b 100644
--- a/full/src/main/java/de/ids_mannheim/korap/config/FullConfiguration.java
+++ b/full/src/main/java/de/ids_mannheim/korap/config/FullConfiguration.java
@@ -14,7 +14,13 @@
*/
public class FullConfiguration extends KustvaktConfiguration {
+ // mail configuration
+ private boolean isMailEnabled;
+ private String testEmail;
+ private String noReply;
+ private String groupInvitationTemplate;
+
private String ldapConfig;
private String freeOnlyRegex;
@@ -49,12 +55,26 @@
// EM: pattern for matching availability in Krill matches
setLicensePatterns(properties);
setDeleteConfiguration(properties);
+ setMailConfiguration(properties);
ldapConfig = properties.getProperty("ldap.config");
+
+ }
+
+ private void setMailConfiguration (Properties properties) {
+ setMailEnabled(Boolean.valueOf(properties.getProperty("mail.enabled", "false")));
+ if (isMailEnabled){
+ // other properties must be set in the kustvakt.conf
+ setTestEmail(properties.getProperty("mail.receiver"));
+ setNoReply(properties.getProperty("mail.sender"));
+ setGroupInvitationTemplate(properties.getProperty("template.group.invitation"));
+ }
}
private void setDeleteConfiguration (Properties properties) {
- setSoftDeleteGroup(parseDeleteConfig(properties.getProperty("delete.group", "")));
- setSoftDeleteAutoGroup(parseDeleteConfig(properties.getProperty("delete.auto.group", "")));
+ setSoftDeleteGroup(
+ parseDeleteConfig(properties.getProperty("delete.group", "")));
+ setSoftDeleteAutoGroup(parseDeleteConfig(
+ properties.getProperty("delete.auto.group", "")));
setSoftDeleteGroupMember(parseDeleteConfig(
properties.getProperty("delete.group.member", "")));
}
@@ -217,4 +237,36 @@
this.isSoftDeleteAutoGroup = isSoftDeleteAutoGroup;
}
+ public String getTestEmail () {
+ return testEmail;
+ }
+
+ public void setTestEmail (String testEmail) {
+ this.testEmail = testEmail;
+ }
+
+ public boolean isMailEnabled () {
+ return isMailEnabled;
+ }
+
+ public void setMailEnabled (boolean isMailEnabled) {
+ this.isMailEnabled = isMailEnabled;
+ }
+
+ public String getNoReply () {
+ return noReply;
+ }
+
+ public void setNoReply (String noReply) {
+ this.noReply = noReply;
+ }
+
+ public String getGroupInvitationTemplate () {
+ return groupInvitationTemplate;
+ }
+
+ public void setGroupInvitationTemplate (String groupInvitationTemplate) {
+ this.groupInvitationTemplate = groupInvitationTemplate;
+ }
+
}
diff --git a/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupDao.java b/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupDao.java
index 6885f3d..e960ee1 100644
--- a/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupDao.java
+++ b/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupDao.java
@@ -94,7 +94,7 @@
entityManager.merge(group);
}
else {
- if (!entityManager.contains(group)){
+ if (!entityManager.contains(group)) {
group = entityManager.merge(group);
}
entityManager.remove(group);
@@ -141,9 +141,8 @@
return (UserGroup) q.getSingleResult();
}
catch (NoResultException e) {
- throw new KustvaktException(StatusCodes.NO_RESULT_FOUND,
- "No result found for query: retrieve group by id "
- + groupId,
+ throw new KustvaktException(StatusCodes.GROUP_NOT_FOUND,
+ "Group with id " + groupId + " is not found",
String.valueOf(groupId), e);
}
}
@@ -174,8 +173,8 @@
userId),
criteriaBuilder.notEqual(members.get(UserGroupMember_.status),
GroupMemberStatus.DELETED));
-// criteriaBuilder.equal(members.get(UserGroupMember_.status),
-// GroupMemberStatus.ACTIVE));
+ // criteriaBuilder.equal(members.get(UserGroupMember_.status),
+ // GroupMemberStatus.ACTIVE));
query.select(root);
@@ -220,7 +219,8 @@
}
}
- public UserGroup retrieveHiddenGroupByVC (int vcId) throws KustvaktException {
+ public UserGroup retrieveHiddenGroupByVC (int vcId)
+ throws KustvaktException {
ParameterChecker.checkIntegerValue(vcId, "vcId");
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
@@ -237,7 +237,7 @@
criteriaBuilder.equal(root.get(UserGroup_.status),
UserGroupStatus.HIDDEN),
criteriaBuilder.equal(vc.get(VirtualCorpus_.id), vcId));
-
+
query.select(root);
query.where(p);
Query q = entityManager.createQuery(query);
diff --git a/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupMemberDao.java b/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupMemberDao.java
index 9803461..d2ffe28 100644
--- a/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupMemberDao.java
+++ b/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupMemberDao.java
@@ -36,45 +36,33 @@
entityManager.persist(member);
}
- public void addMembers (List<UserGroupMember> members)
- throws KustvaktException {
- ParameterChecker.checkObjectValue(members, "List<UserGroupMember>");
+ // @Deprecated
+ // public void addMembers (List<UserGroupMember> members)
+ // throws KustvaktException {
+ // ParameterChecker.checkObjectValue(members, "List<UserGroupMember>");
+ //
+ // for (UserGroupMember member : members) {
+ // addMember(member);
+ // }
+ // }
- for (UserGroupMember member : members) {
- addMember(member);
- }
+ public void updateMember (UserGroupMember member) throws KustvaktException {
+ ParameterChecker.checkObjectValue(member, "UserGroupMember");
+ entityManager.merge(member);
}
- public void approveMember (String userId, int groupId)
- throws KustvaktException {
- ParameterChecker.checkStringValue(userId, "userId");
- ParameterChecker.checkIntegerValue(groupId, "groupId");
-
- UserGroupMember member = retrieveMemberById(userId, groupId);
- if (member.getStatus().equals(GroupMemberStatus.DELETED)) {
- throw new KustvaktException(StatusCodes.NOTHING_CHANGED, "Username "
- + userId + " had been deleted in group " + groupId, userId);
- }
-
- member.setStatus(GroupMemberStatus.ACTIVE);
- entityManager.persist(member);
- }
-
- public void deleteMember (String userId, int groupId, String deletedBy,
+ public void deleteMember (UserGroupMember member, String deletedBy,
boolean isSoftDelete) throws KustvaktException {
- ParameterChecker.checkStringValue(userId, "userId");
- ParameterChecker.checkIntegerValue(groupId, "groupId");
+ ParameterChecker.checkObjectValue(member, "UserGroupMember");
+ ParameterChecker.checkStringValue(deletedBy, "deletedBy");
- UserGroupMember member = retrieveMemberById(userId, groupId);
- GroupMemberStatus status = member.getStatus();
- if (isSoftDelete && status.equals(GroupMemberStatus.DELETED)) {
- throw new KustvaktException(StatusCodes.DB_ENTRY_DELETED,
- userId + " has already been deleted from the group.",
- userId);
+ if (!entityManager.contains(member)) {
+ member = entityManager.merge(member);
}
if (isSoftDelete) {
member.setStatus(GroupMemberStatus.DELETED);
+ member.setDeletedBy(deletedBy);
entityManager.persist(member);
}
else {
@@ -107,9 +95,8 @@
return (UserGroupMember) q.getSingleResult();
}
catch (NoResultException e) {
- throw new KustvaktException(StatusCodes.NO_RESULT_FOUND,
- "Username " + userId + " is not found in group " + groupId,
- userId);
+ throw new KustvaktException(StatusCodes.GROUP_MEMBER_NOT_FOUND,
+ userId + " is not found in the group", userId);
}
}
diff --git a/full/src/main/java/de/ids_mannheim/korap/entity/UserGroupMember.java b/full/src/main/java/de/ids_mannheim/korap/entity/UserGroupMember.java
index 6e7f874..f148959 100644
--- a/full/src/main/java/de/ids_mannheim/korap/entity/UserGroupMember.java
+++ b/full/src/main/java/de/ids_mannheim/korap/entity/UserGroupMember.java
@@ -1,5 +1,7 @@
package de.ids_mannheim.korap.entity;
+import java.time.ZonedDateTime;
+import java.util.Date;
import java.util.List;
import javax.persistence.Column;
@@ -47,6 +49,10 @@
private String createdBy;
@Column(name = "deleted_by")
private String deletedBy;
+
+ // auto update in the database
+ @Column(name = "status_date")
+ private ZonedDateTime statusDate;
@Enumerated(EnumType.STRING)
private GroupMemberStatus status;
diff --git a/full/src/main/java/de/ids_mannheim/korap/rewrite/CollectionRewrite.java b/full/src/main/java/de/ids_mannheim/korap/rewrite/CollectionRewrite.java
index 7f7370a..1ab70a3 100644
--- a/full/src/main/java/de/ids_mannheim/korap/rewrite/CollectionRewrite.java
+++ b/full/src/main/java/de/ids_mannheim/korap/rewrite/CollectionRewrite.java
@@ -81,9 +81,20 @@
}
else {
for (int i = 0; i < operands.size(); i++) {
- updatedAvailabilities = checkAvailability(operands.get(i),
- originalAvailabilities, updatedAvailabilities,
- true);
+ node = operands.get(i);
+ if (node.has("key") && !node.at("/key").asText()
+ .equals("availability")) {
+ jlog.debug("RESET availabilities 1, key="
+ + node.at("/key").asText());
+ updatedAvailabilities.clear();
+ updatedAvailabilities.addAll(originalAvailabilities);
+ break;
+ }
+ else {
+ updatedAvailabilities = checkAvailability(
+ operands.get(i), originalAvailabilities,
+ updatedAvailabilities, true);
+ }
}
}
}
@@ -91,13 +102,14 @@
&& node.at("/key").asText().equals("availability")) {
String queryAvailability = node.at("/value").asText();
String matchOp = node.at("/match").asText();
+
if (originalAvailabilities.contains(queryAvailability)
&& matchOp.equals(KoralMatchOperator.EQUALS.toString())) {
jlog.debug("REMOVE " + queryAvailability);
updatedAvailabilities.remove(queryAvailability);
}
else if (isOperationOr) {
- jlog.debug("RESET availabilities");
+ jlog.debug("RESET availabilities 2");
updatedAvailabilities.clear();
updatedAvailabilities.addAll(originalAvailabilities);
return updatedAvailabilities;
@@ -110,7 +122,7 @@
public JsonNode rewriteQuery (KoralNode node, KustvaktConfiguration config,
User user) throws KustvaktException {
JsonNode jsonNode = node.rawNode();
-
+
FullConfiguration fullConfig = (FullConfiguration) config;
List<String> userAvailabilities = new ArrayList<String>();
@@ -145,7 +157,7 @@
avalabilityCopy, userAvailabilities, false);
if (!userAvailabilities.isEmpty()) {
builder.with(buildAvailability(avalabilityCopy));
- jlog.debug("corpus query: " +builder.toString());
+ jlog.debug("corpus query: " + builder.toString());
builder.setBaseQuery(builder.toJSON());
rewrittesNode = builder.mergeWith(jsonNode).at("/collection");
node.set("collection", rewrittesNode, identifier);
@@ -153,7 +165,7 @@
}
else {
builder.with(buildAvailability(userAvailabilities));
- jlog.debug("corpus query: " +builder.toString());
+ jlog.debug("corpus query: " + builder.toString());
rewrittesNode =
JsonUtils.readTree(builder.toJSON()).at("/collection");
node.set("collection", rewrittesNode, identifier);
@@ -169,27 +181,28 @@
for (int i = 0; i < userAvailabilities.size(); i++) {
parseAvailability(sb, userAvailabilities.get(i), "|");
}
- String availabilities = sb.toString();
- return availabilities.substring(0, availabilities.length()-3);
+ String availabilities = sb.toString();
+ return availabilities.substring(0, availabilities.length() - 3);
}
-
- private void parseAvailability (StringBuilder sb, String availability, String operator) {
+
+ private void parseAvailability (StringBuilder sb, String availability,
+ String operator) {
String uaArr[] = null;
- if (availability.contains("|")){
+ if (availability.contains("|")) {
uaArr = availability.split("\\|");
- for (int j=0; j < uaArr.length; j++){
+ for (int j = 0; j < uaArr.length; j++) {
parseAvailability(sb, uaArr[j].trim(), "|");
}
}
// EM: not supported
-// else if (availability.contains("&")){
-// uaArr = availability.split("&");
-// for (int j=0; j < uaArr.length -1; j++){
-// parseAvailability(sb, uaArr[j], "&");
-// }
-// parseAvailability(sb, uaArr[uaArr.length-1], "|");
-// }
- else{
+ // else if (availability.contains("&")){
+ // uaArr = availability.split("&");
+ // for (int j=0; j < uaArr.length -1; j++){
+ // parseAvailability(sb, uaArr[j], "&");
+ // }
+ // parseAvailability(sb, uaArr[uaArr.length-1], "|");
+ // }
+ else {
sb.append("availability=/");
sb.append(availability);
sb.append("/ ");
@@ -198,6 +211,6 @@
}
}
-
+
}
diff --git a/full/src/main/java/de/ids_mannheim/korap/server/KustvaktServer.java b/full/src/main/java/de/ids_mannheim/korap/server/KustvaktServer.java
index 4b3a6d6..b938904 100644
--- a/full/src/main/java/de/ids_mannheim/korap/server/KustvaktServer.java
+++ b/full/src/main/java/de/ids_mannheim/korap/server/KustvaktServer.java
@@ -1,6 +1,11 @@
package de.ids_mannheim.korap.server;
-import de.ids_mannheim.korap.config.BeansFactory;
+import java.io.File;
+import java.io.FileInputStream;
+import java.net.URL;
+import java.util.Properties;
+
+import de.ids_mannheim.korap.config.FullConfiguration;
import de.ids_mannheim.korap.web.KustvaktBaseServer;
/**
@@ -11,17 +16,35 @@
*/
public class KustvaktServer extends KustvaktBaseServer {
+ private static FullConfiguration fullConfig;
+
public static final String API_VERSION = "v0.1";
public static void main (String[] args) throws Exception {
KustvaktServer server = new KustvaktServer();
kargs = server.readAttributes(args);
+
+ File f = new File("kustvakt.conf");
+ if (!f.exists()){
+ URL url = KustvaktServer.class.getResource("kustvakt.conf");
+ if (url!=null){
+ f = new File(url.toURI());
+ }
+ }
+
+ Properties properties = new Properties();
+ FileInputStream in = new FileInputStream(f);
+ properties.load(in);
+ in.close();
+ fullConfig = new FullConfiguration(properties);
+ config = fullConfig;
- if (kargs.getConfig() != null)
- BeansFactory.loadFileContext(kargs.getConfig());
- else{
+ if (kargs.getConfig() == null){
+// BeansFactory.loadFileContext(kargs.getConfig());
+// }
+// else {
kargs.setConfig("default-config.xml");
- BeansFactory.loadClasspathContext("default-config.xml");
+// BeansFactory.loadClasspathContext("default-config.xml");
}
kargs.setRootPackages(new String[] { "de.ids_mannheim.korap.web.utils",
"de.ids_mannheim.korap.web.service.full" });
@@ -29,54 +52,4 @@
+ "de.ids_mannheim.korap.web.service.full";
server.start();
}
-
- @Override
- protected void setup () {
-// Set<Class<? extends BootableBeanInterface>> set = KustvaktClassLoader
-// .loadSubTypes(BootableBeanInterface.class);
-//
-// ContextHolder context = BeansFactory.getKustvaktContext();
-// if (context == null)
-// throw new RuntimeException("Beans could not be loaded!");
-//
-// List<BootableBeanInterface> list = new ArrayList<>(set.size());
-// for (Class cl : set) {
-// BootableBeanInterface iface;
-//
-// try {
-// iface = (BootableBeanInterface) cl.newInstance();
-// if (iface instanceof CollectionLoader){
-// continue;
-// }
-// list.add(iface);
-// }
-// catch (InstantiationException | IllegalAccessException e) {
-// continue;
-// }
-// }
-// System.out.println("Found boot loading interfaces: " + list);
-//
-// while (!list.isEmpty()) {
-// loop: for (BootableBeanInterface iface : new ArrayList<>(list)) {
-// try {
-// for (Class dep : iface.getDependencies()) {
-// if (set.contains(dep))
-// continue loop;
-// }
-// iface.load(context);
-// list.remove(iface);
-// set.remove(iface.getClass());
-// System.out.println("Done with interface "
-// + iface.getClass().getSimpleName());
-// }
-// catch (KustvaktException e) {
-// // don't do anything!
-// System.out.println("An error occurred in class "
-// + iface.getClass().getSimpleName() + "!\n");
-// e.printStackTrace();
-// System.exit(-1);
-// }
-// }
-// }
- }
}
diff --git a/full/src/main/java/de/ids_mannheim/korap/service/MailAuthenticator.java b/full/src/main/java/de/ids_mannheim/korap/service/MailAuthenticator.java
new file mode 100644
index 0000000..28e7660
--- /dev/null
+++ b/full/src/main/java/de/ids_mannheim/korap/service/MailAuthenticator.java
@@ -0,0 +1,20 @@
+package de.ids_mannheim.korap.service;
+
+import javax.mail.Authenticator;
+import javax.mail.PasswordAuthentication;
+
+public class MailAuthenticator extends Authenticator {
+
+ private PasswordAuthentication passwordAuthentication;
+
+ public MailAuthenticator (String username, String password) {
+ passwordAuthentication = new PasswordAuthentication(username, password);
+
+ }
+
+ @Override
+ protected PasswordAuthentication getPasswordAuthentication () {
+ return passwordAuthentication;
+ }
+
+}
diff --git a/full/src/main/java/de/ids_mannheim/korap/service/MailService.java b/full/src/main/java/de/ids_mannheim/korap/service/MailService.java
new file mode 100644
index 0000000..866a0a9
--- /dev/null
+++ b/full/src/main/java/de/ids_mannheim/korap/service/MailService.java
@@ -0,0 +1,76 @@
+package de.ids_mannheim.korap.service;
+
+import java.io.StringWriter;
+import java.nio.charset.StandardCharsets;
+
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeMessage;
+
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.context.Context;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.mail.javamail.MimeMessageHelper;
+import org.springframework.mail.javamail.MimeMessagePreparator;
+import org.springframework.stereotype.Service;
+
+import de.ids_mannheim.korap.config.FullConfiguration;
+import de.ids_mannheim.korap.interfaces.AuthenticationManagerIface;
+import de.ids_mannheim.korap.user.User;
+
+@Service
+public class MailService {
+
+ private static Logger jlog = LoggerFactory.getLogger(MailService.class);
+
+ @Autowired
+ private AuthenticationManagerIface authManager;
+ @Autowired
+ private JavaMailSender mailSender;
+ @Autowired
+ private VelocityEngine velocityEngine;
+ @Autowired
+ private FullConfiguration config;
+
+ public void sendMemberInvitationNotification (String inviteeName,
+ String groupName, String inviter) {
+
+ MimeMessagePreparator preparator = new MimeMessagePreparator() {
+
+ public void prepare (MimeMessage mimeMessage) throws Exception {
+
+ User invitee = authManager.getUser(inviteeName);
+
+ MimeMessageHelper message = new MimeMessageHelper(mimeMessage);
+ message.setTo(new InternetAddress(invitee.getEmail()));
+ message.setFrom(config.getNoReply());
+ message.setSubject("Invitation to join " + groupName);
+ message.setText(prepareGroupInvitationText(inviteeName,
+ groupName, inviter), true);
+ }
+
+ };
+ mailSender.send(preparator);
+ }
+
+ private String prepareGroupInvitationText (String username,
+ String groupName, String inviter) {
+ Context context = new VelocityContext();
+ context.put("username", username);
+ context.put("group", groupName);
+ context.put("inviter", inviter);
+
+ StringWriter stringWriter = new StringWriter();
+
+ velocityEngine.mergeTemplate(
+ "templates/" + config.getGroupInvitationTemplate(),
+ StandardCharsets.UTF_8.name(), context, stringWriter);
+
+ String message = stringWriter.toString();
+ jlog.debug(message);
+ return message;
+ }
+}
diff --git a/full/src/main/java/de/ids_mannheim/korap/service/UserGroupService.java b/full/src/main/java/de/ids_mannheim/korap/service/UserGroupService.java
index 15f6052..9c3e245 100644
--- a/full/src/main/java/de/ids_mannheim/korap/service/UserGroupService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/service/UserGroupService.java
@@ -1,9 +1,12 @@
package de.ids_mannheim.korap.service;
+import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -37,6 +40,8 @@
@Service
public class UserGroupService {
+ private static Logger jlog =
+ LoggerFactory.getLogger(UserGroupService.class);
@Autowired
private UserGroupDao userGroupDao;
@Autowired
@@ -49,6 +54,8 @@
private AuthenticationManagerIface authManager;
@Autowired
private FullConfiguration config;
+ @Autowired
+ private MailService mailService;
private static List<Role> memberRoles;
@@ -168,7 +175,7 @@
// skip owner, already added while creating group.
continue;
}
- addGroupMember(memberId, userGroup, createdBy,
+ inviteGroupMember(memberId, userGroup, createdBy,
GroupMemberStatus.PENDING);
}
}
@@ -199,7 +206,8 @@
public void deleteAutoHiddenGroup (int groupId, String deletedBy)
throws KustvaktException {
// default hard delete
- userGroupDao.deleteGroup(groupId, deletedBy, config.isSoftDeleteAutoGroup());
+ userGroupDao.deleteGroup(groupId, deletedBy,
+ config.isSoftDeleteAutoGroup());
}
/** Adds a user to the specified usergroup. If the username with
@@ -217,7 +225,7 @@
* @param status the status of the membership
* @throws KustvaktException
*/
- public void addGroupMember (String username, UserGroup userGroup,
+ public void inviteGroupMember (String username, UserGroup userGroup,
String createdBy, GroupMemberStatus status)
throws KustvaktException {
@@ -225,9 +233,10 @@
ParameterChecker.checkIntegerValue(groupId, "userGroupId");
if (memberExists(username, groupId, status)) {
- throw new KustvaktException(StatusCodes.DB_ENTRY_EXISTS,
+ throw new KustvaktException(StatusCodes.GROUP_MEMBER_EXISTS,
"Username " + username + " with status " + status
- + " exists in user-group " + userGroup.getName(),
+ + " exists in the user-group "
+ + userGroup.getName(),
username, status.name(), userGroup.getName());
}
@@ -239,8 +248,11 @@
member.setRoles(memberRoles);
member.setStatus(status);
member.setUserId(username);
-
groupMemberDao.addMember(member);
+
+ if (config.isMailEnabled() && userGroup.getStatus() != UserGroupStatus.HIDDEN) {
+ mailService.sendMemberInvitationNotification(username,userGroup.getName(), createdBy);
+ }
}
private boolean memberExists (String username, int groupId,
@@ -261,13 +273,13 @@
}
else if (existingStatus.equals(GroupMemberStatus.DELETED)) {
// hard delete, not customizable
- groupMemberDao.deleteMember(username, groupId, "system", false);
+ deleteMember(username, groupId, "system", false);
}
return false;
}
- public void addUsersToGroup (UserGroupJson group, String username)
+ public void inviteGroupMembers (UserGroupJson group, String inviter)
throws KustvaktException {
int groupId = group.getId();
String[] members = group.getMembers();
@@ -275,16 +287,16 @@
ParameterChecker.checkObjectValue(members, "members");
UserGroup userGroup = retrieveUserGroupById(groupId);
- User user = authManager.getUser(username);
- if (isUserGroupAdmin(username, userGroup) || user.isSystemAdmin()) {
+ User user = authManager.getUser(inviter);
+ if (isUserGroupAdmin(inviter, userGroup) || user.isSystemAdmin()) {
for (String memberName : members) {
- addGroupMember(memberName, userGroup, username,
+ inviteGroupMember(memberName, userGroup, inviter,
GroupMemberStatus.PENDING);
}
}
else {
throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
- "Unauthorized operation for user: " + username, username);
+ "Unauthorized operation for user: " + inviter, inviter);
}
}
@@ -307,26 +319,46 @@
* @param username the username of the group member
* @throws KustvaktException
*/
- public void subscribe (int groupId, String username)
+ public void acceptInvitation (int groupId, String username)
throws KustvaktException {
- groupMemberDao.approveMember(username, groupId);
+
+ ParameterChecker.checkStringValue(username, "userId");
+ ParameterChecker.checkIntegerValue(groupId, "groupId");
+
+ UserGroup group = userGroupDao.retrieveGroupById(groupId);
+
+ UserGroupMember member =
+ groupMemberDao.retrieveMemberById(username, groupId);
+ GroupMemberStatus status = member.getStatus();
+ if (status.equals(GroupMemberStatus.DELETED)) {
+ throw new KustvaktException(StatusCodes.GROUP_MEMBER_DELETED,
+ username + " has already been deleted from the group "
+ + group.getName(),
+ username, group.getName());
+ }
+ else if (member.getStatus().equals(GroupMemberStatus.ACTIVE)) {
+ throw new KustvaktException(StatusCodes.GROUP_MEMBER_EXISTS,
+ "Username " + username + " with status " + status
+ + " exists in the user-group " + group.getName(),
+ username, status.name(), group.getName());
+ }
+ // status pending
+ else {
+ jlog.debug("status: " + member.getStatusDate());
+ ZonedDateTime expiration = member.getStatusDate().plusMinutes(30);
+ ZonedDateTime now = ZonedDateTime.now();
+ jlog.debug("expiration: " + expiration + ", now: " + now);
+
+ if (expiration.isAfter(now)) {
+ member.setStatus(GroupMemberStatus.ACTIVE);
+ groupMemberDao.updateMember(member);
+ }
+ else {
+ throw new KustvaktException(StatusCodes.INVITATION_EXPIRED);
+ }
+ }
}
-
- /** Updates the {@link GroupMemberStatus} of a member to
- * {@link GroupMemberStatus#DELETED}
- *
- * @param groupId groupId
- * @param username member's username
- * @throws KustvaktException
- */
- public void unsubscribe (int groupId, String username)
- throws KustvaktException {
- groupMemberDao.deleteMember(username, groupId, username,
- config.isSoftDeleteGroupMember());
- }
-
-
public boolean isMember (String username, UserGroup userGroup)
throws KustvaktException {
List<UserGroupMember> members =
@@ -349,10 +381,11 @@
"Operation " + "'delete group owner'" + "is not allowed.",
"delete group owner");
}
- else if (isUserGroupAdmin(deletedBy, userGroup)
+ else if (memberId.equals(deletedBy)
+ || isUserGroupAdmin(deletedBy, userGroup)
|| user.isSystemAdmin()) {
// soft delete
- groupMemberDao.deleteMember(memberId, groupId, deletedBy,
+ deleteMember(memberId, groupId, deletedBy,
config.isSoftDeleteGroupMember());
}
else {
@@ -361,4 +394,31 @@
}
}
+ /** Updates the {@link GroupMemberStatus} of a member to
+ * {@link GroupMemberStatus#DELETED}
+ *
+ * @param userId user to be deleted
+ * @param groupId user-group id
+ * @param deletedBy user that issue the delete
+ * @param isSoftDelete true if database entry is to be deleted
+ * permanently, false otherwise
+ * @throws KustvaktException
+ */
+ private void deleteMember (String username, int groupId, String deletedBy,
+ boolean isSoftDelete) throws KustvaktException {
+
+ UserGroup group = userGroupDao.retrieveGroupById(groupId);
+
+ UserGroupMember member =
+ groupMemberDao.retrieveMemberById(username, groupId);
+ GroupMemberStatus status = member.getStatus();
+ if (isSoftDelete && status.equals(GroupMemberStatus.DELETED)) {
+ throw new KustvaktException(StatusCodes.GROUP_MEMBER_DELETED,
+ username + " has already been deleted from the group "
+ + group.getName(),
+ username, group.getName());
+ }
+
+ groupMemberDao.deleteMember(member, deletedBy, isSoftDelete);
+ }
}
diff --git a/full/src/main/java/de/ids_mannheim/korap/service/VirtualCorpusService.java b/full/src/main/java/de/ids_mannheim/korap/service/VirtualCorpusService.java
index b4e7fbc..4e0214b 100644
--- a/full/src/main/java/de/ids_mannheim/korap/service/VirtualCorpusService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/service/VirtualCorpusService.java
@@ -395,7 +395,7 @@
userGroupService.retrieveHiddenGroup(vcId);
// if (!userGroupService.isMember(username, userGroup)) {
try {
- userGroupService.addGroupMember(username, userGroup,
+ userGroupService.inviteGroupMember(username, userGroup,
"system", GroupMemberStatus.ACTIVE);
}
catch (KustvaktException e) {
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/UserGroupController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/UserGroupController.java
index ad92c84..9e15d33 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/UserGroupController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/UserGroupController.java
@@ -59,6 +59,11 @@
@Autowired
private UserGroupService service;
+ /** Returns all user-groups wherein a user is an active or pending member.
+ *
+ * @param securityContext
+ * @return a list of user-groups
+ */
@GET
@Path("list")
public Response getUserGroup (@Context SecurityContext securityContext) {
@@ -120,8 +125,7 @@
@DELETE
@Path("delete")
@Consumes(MediaType.APPLICATION_JSON)
- public Response deleteUserGroup (
- @Context SecurityContext securityContext,
+ public Response deleteUserGroup (@Context SecurityContext securityContext,
@QueryParam("groupId") int groupId) {
TokenContext context =
(TokenContext) securityContext.getUserPrincipal();
@@ -133,7 +137,7 @@
throw responseHandler.throwit(e);
}
}
-
+
/** Group owner cannot be deleted.
*
* @param securityContext
@@ -162,12 +166,12 @@
@POST
@Path("member/invite")
@Consumes(MediaType.APPLICATION_JSON)
- public Response addUserToGroup (@Context SecurityContext securityContext,
+ public Response inviteGroupMembers (@Context SecurityContext securityContext,
UserGroupJson group) {
TokenContext context =
(TokenContext) securityContext.getUserPrincipal();
try {
- service.addUsersToGroup(group, context.getUsername());
+ service.inviteGroupMembers(group, context.getUsername());
return Response.ok().build();
}
catch (KustvaktException e) {
@@ -183,7 +187,7 @@
TokenContext context =
(TokenContext) securityContext.getUserPrincipal();
try {
- service.subscribe(groupId, context.getUsername());
+ service.acceptInvitation(groupId, context.getUsername());
return Response.ok().build();
}
catch (KustvaktException e) {
@@ -200,7 +204,8 @@
TokenContext context =
(TokenContext) securityContext.getUserPrincipal();
try {
- service.unsubscribe(groupId, context.getUsername());
+ service.deleteGroupMember(context.getUsername(), groupId,
+ context.getUsername());
return Response.ok().build();
}
catch (KustvaktException e) {
diff --git a/full/src/main/resources/changelog b/full/src/main/resources/changelog
deleted file mode 100644
index e7e868c..0000000
--- a/full/src/main/resources/changelog
+++ /dev/null
@@ -1,10 +0,0 @@
-=== CHANGELOG FILE ===
-
-13/10/2016
- - MOD: updated search to use new siglen (diewald)
- - MOD: fixed matchinfo retrieval in light service (diewald)
-
-05/05/2015
- - ADD: rest test suite for user service (hanl)
- - MOD: setup parameter modification (hanl)
- - ADD: oauth2 client unique constraint (hanl)
diff --git a/full/src/main/resources/db/new-mysql/V1.1__create_virtual_corpus_tables.sql b/full/src/main/resources/db/new-mysql/V1.1__create_virtual_corpus_tables.sql
index a8df972..1fe0f26 100644
--- a/full/src/main/resources/db/new-mysql/V1.1__create_virtual_corpus_tables.sql
+++ b/full/src/main/resources/db/new-mysql/V1.1__create_virtual_corpus_tables.sql
@@ -32,6 +32,7 @@
status varchar(100) NOT NULL,
created_by varchar(100) NOT NULL,
deleted_by varchar(100) DEFAULT NULL,
+ status_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE INDEX unique_index (user_id,group_id),
INDEX status_index(status),
FOREIGN KEY (group_id)
diff --git a/full/src/main/resources/db/new-sqlite/V1.1__create_virtual_corpus_tables.sql b/full/src/main/resources/db/new-sqlite/V1.1__create_virtual_corpus_tables.sql
index 8476535..d1bbcb7 100644
--- a/full/src/main/resources/db/new-sqlite/V1.1__create_virtual_corpus_tables.sql
+++ b/full/src/main/resources/db/new-sqlite/V1.1__create_virtual_corpus_tables.sql
@@ -35,6 +35,8 @@
status varchar(100) NOT NULL,
created_by varchar(100) NOT NULL,
deleted_by varchar(100) DEFAULT NULL,
+-- interprets now as localtime and save it as UTC
+ status_date timestamp DEFAULT (datetime('now','localtime')),
FOREIGN KEY (group_id)
REFERENCES user_group (id)
ON DELETE CASCADE
diff --git a/full/src/main/resources/db/new-sqlite/V1.2__triggers.sql b/full/src/main/resources/db/new-sqlite/V1.2__triggers.sql
new file mode 100644
index 0000000..0acd2f7
--- /dev/null
+++ b/full/src/main/resources/db/new-sqlite/V1.2__triggers.sql
@@ -0,0 +1,9 @@
+--CREATE TRIGGER insert_member_status AFTER INSERT ON user_group_member
+-- BEGIN
+-- UPDATE user_group_member SET status_date = DATETIME('NOW', 'utc') WHERE rowid = new.rowid;
+-- END;
+--
+CREATE TRIGGER update_member_status AFTER UPDATE ON user_group_member
+ BEGIN
+ UPDATE user_group_member SET status_date = (datetime('now','localtime')) WHERE rowid = old.rowid;
+ END;
diff --git a/full/src/main/resources/default-config.xml b/full/src/main/resources/default-config.xml
index 625460f..5d3f9e9 100644
--- a/full/src/main/resources/default-config.xml
+++ b/full/src/main/resources/default-config.xml
@@ -41,9 +41,12 @@
<property name="ignoreResourceNotFound" value="true" />
<property name="locations">
<array>
- <value>classpath:jdbc.properties</value>
+ <value>classpath:properties/jdbc.properties</value>
<value>file:./jdbc.properties</value>
- <value>classpath:hibernate.properties</value>
+ <value>classpath:properties/mail.properties</value>
+ <value>file:./mail.properties</value>
+ <value>classpath:properties/hibernate.properties</value>
+
<value>classpath:kustvakt.conf</value>
<value>file:./kustvakt.conf</value>
</array>
@@ -87,6 +90,12 @@
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
+ <property name="connectionProperties">
+ <props>
+ <prop key="date_string_format">yyyy-MM-dd HH:mm:ss</prop>
+ </props>
+ </property>
+
<!-- relevant for single connection datasource and sqlite -->
<property name="suppressClose">
<value>true</value>
@@ -306,4 +315,35 @@
<property name="dataSource" ref="sqliteDataSource" />
</bean>
+ <!-- mail -->
+ <bean id="authenticator" class="de.ids_mannheim.korap.service.MailAuthenticator">
+ <constructor-arg index="0" value="${mail.username}"/>
+ <constructor-arg index="1" value="${mail.password}"/>
+ </bean>
+ <bean id="smtpSession" class="javax.mail.Session" factory-method="getInstance">
+ <constructor-arg index="0">
+ <props>
+ <prop key="mail.smtp.submitter">${mail.username}</prop>
+ <prop key="mail.smtp.auth">${mail.auth}</prop>
+ <prop key="mail.smtp.host">${mail.host}</prop>
+ <prop key="mail.smtp.port">${mail.port}</prop>
+ <prop key="mail.smtp.starttls.enable">${mail.starttls.enable}</prop>
+ <prop key="mail.smtp.connectiontimeout">${mail.connectiontimeout}</prop>
+ </props>
+ </constructor-arg>
+ <constructor-arg index="1" ref="authenticator"/>
+ </bean>
+ <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
+ <property name="username" value="${mail.username}" />
+ <property name="password" value="${mail.password}" />
+ <property name="session" ref="smtpSession" />
+ </bean>
+ <bean id="velocityEngine" class="org.apache.velocity.app.VelocityEngine">
+ <constructor-arg index="0">
+ <props>
+ <prop key="resource.loader">class</prop>
+ <prop key="class.resource.loader.class">org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader</prop>
+ </props>
+ </constructor-arg>
+ </bean>
</beans>
\ No newline at end of file
diff --git a/full/src/main/resources/index-kustvakt-example.zip b/full/src/main/resources/index-kustvakt-example.zip
deleted file mode 100644
index 33c4b5c..0000000
--- a/full/src/main/resources/index-kustvakt-example.zip
+++ /dev/null
Binary files differ
diff --git a/full/src/main/resources/kustvakt.conf b/full/src/main/resources/kustvakt.conf
index d8ff39d..d737a06 100644
--- a/full/src/main/resources/kustvakt.conf
+++ b/full/src/main/resources/kustvakt.conf
@@ -10,6 +10,18 @@
ldap.config = file-path-to-ldap-config
# Kustvakt
+## server
+server.port=8089
+server.host=localhost
+
+## mail settings
+mail.enabled = false
+mail.receiver = test@localhost
+mail.sender = noreply@ids-mannheim.de
+
+## mail.templates
+template.group.invitation = notification.vm
+
## default layers
default.layer.p = tt
default.layer.l = tt
diff --git a/full/src/main/resources/log4j.properties b/full/src/main/resources/log4j.properties
index 352062e..c747b68 100644
--- a/full/src/main/resources/log4j.properties
+++ b/full/src/main/resources/log4j.properties
@@ -4,9 +4,10 @@
log4j.rootLogger=ERROR, stdout, debugLog
log4j.logger.log=ERROR, errorLog
-#log4j.logger.de.ids_mannheim.korap.service.VirtualCorpusService = error, debugLog
#log4j.logger.de.ids_mannheim.korap.web.controller.AuthenticationController = debug, debugLog, stdout
-#log4j.logger.de.ids_mannheim.korap.resource.rewrite.CollectionRewrite= stdout, debugLog
+#log4j.logger.de.ids_mannheim.korap.service.UserGroupService= debug, stdout, debugLog
+#log4j.logger.de.ids_mannheim.korap.rewrite.CollectionRewrite= debug, stdout, debugLog
+#log4j.logger.de.ids_mannheim.korap.service.MailService= debug, stdout, debugLog
# Direct log messages to stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
diff --git a/full/src/main/resources/hibernate.properties b/full/src/main/resources/properties/hibernate.properties
similarity index 100%
rename from full/src/main/resources/hibernate.properties
rename to full/src/main/resources/properties/hibernate.properties
diff --git a/full/src/main/resources/jdbc.properties b/full/src/main/resources/properties/jdbc.properties
similarity index 96%
rename from full/src/main/resources/jdbc.properties
rename to full/src/main/resources/properties/jdbc.properties
index fb06a12..2bc85dd 100644
--- a/full/src/main/resources/jdbc.properties
+++ b/full/src/main/resources/properties/jdbc.properties
@@ -4,7 +4,7 @@
#jdbc.database=mysql
#jdbc.driverClassName=com.mysql.jdbc.Driver
-#jdbc.url=jdbc:mysql://localhost:3306/kustvakt?autoReconnect=true
+#jdbc.url=jdbc:mysql://localhost:3306/kustvakt?autoReconnect=true&useLegacyDatetimeCode=false
#jdbc.username=korap
#jdbc.password=password
diff --git a/full/src/main/resources/properties/mail.properties b/full/src/main/resources/properties/mail.properties
new file mode 100644
index 0000000..29d1ca1
--- /dev/null
+++ b/full/src/main/resources/properties/mail.properties
@@ -0,0 +1,7 @@
+mail.host = localhost
+mail.port = 25
+mail.connectiontimeout = 3000
+mail.auth = false
+mail.starttls.enable = false
+mail.username = username
+mail.password = password
\ No newline at end of file
diff --git a/full/src/main/resources/templates/notification.vm b/full/src/main/resources/templates/notification.vm
new file mode 100644
index 0000000..254ad83
--- /dev/null
+++ b/full/src/main/resources/templates/notification.vm
@@ -0,0 +1,12 @@
+<html>
+ <body>
+ <h3>Hi $username,</h3>
+ <p> you have been invited to group $group by $inviter! </p>
+ <p> Please login to <a href="https://korap.ids-mannheim.de/kalamar">KorAP</a> with your
+ account to accept or reject this invitation within 30 minutes. </p>
+ <p>After joining a group, you will be able to access virtual corpora shared with members of
+ the group. If you would like share your virtual corpus to a group, please contact the
+ group admin.</p>
+ <p> This is an automated generated email. Please do not reply directly to this e-mail. </p>
+ </body>
+</html>
\ No newline at end of file
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/SearchWithAvailabilityTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/AvailabilityTest.java
similarity index 83%
rename from full/src/test/java/de/ids_mannheim/korap/web/controller/SearchWithAvailabilityTest.java
rename to full/src/test/java/de/ids_mannheim/korap/web/controller/AvailabilityTest.java
index 02abd36..927e3f0 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/SearchWithAvailabilityTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/AvailabilityTest.java
@@ -1,13 +1,14 @@
package de.ids_mannheim.korap.web.controller;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertNotNull;
-import org.eclipse.jetty.http.HttpHeaders;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.net.HttpHeaders;
import com.sun.jersey.api.client.ClientHandlerException;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.UniformInterfaceException;
@@ -18,10 +19,10 @@
import de.ids_mannheim.korap.exceptions.KustvaktException;
import de.ids_mannheim.korap.utils.JsonUtils;
-public class SearchWithAvailabilityTest extends SpringJerseyTest {
+public class AvailabilityTest extends SpringJerseyTest {
@Autowired
private HttpAuthorizationHandler handler;
-
+
private void checkAndFree (String json) throws KustvaktException {
JsonNode node = JsonUtils.readTree(json);
assertEquals("availability",
@@ -38,6 +39,7 @@
private void checkAndPublic (String json) throws KustvaktException {
JsonNode node = JsonUtils.readTree(json);
assertNotNull(node);
+
assertEquals("operation:and",
node.at("/collection/operation").asText());
assertEquals("match:eq",
@@ -49,21 +51,24 @@
assertEquals("CC-BY.*",
node.at("/collection/operands/0/operands/0/value").asText());
assertEquals("match:eq",
- node.at("/collection/operands/0/operands/1/operands/0/match").asText());
+ node.at("/collection/operands/0/operands/1/operands/0/match")
+ .asText());
assertEquals("ACA.*",
- node.at("/collection/operands/0/operands/1/operands/0/value").asText());
+ node.at("/collection/operands/0/operands/1/operands/0/value")
+ .asText());
assertEquals("match:eq",
- node.at("/collection/operands/0/operands/1/operands/1/match").asText());
+ node.at("/collection/operands/0/operands/1/operands/1/match")
+ .asText());
assertEquals("QAO-NC",
- node.at("/collection/operands/0/operands/1/operands/1/value").asText());
+ node.at("/collection/operands/0/operands/1/operands/1/value")
+ .asText());
assertEquals("operation:insertion",
node.at("/collection/rewrites/0/operation").asText());
assertEquals("availability(PUB)",
node.at("/collection/rewrites/0/scope").asText());
}
- private void checkAndPublicWithACA (String json)
- throws KustvaktException {
+ private void checkAndPublicWithACA (String json) throws KustvaktException {
JsonNode node = JsonUtils.readTree(json);
assertNotNull(node);
assertEquals("operation:and",
@@ -72,7 +77,7 @@
node.at("/collection/rewrites/0/operation").asText());
assertEquals("availability(PUB)",
node.at("/collection/rewrites/0/scope").asText());
-
+
assertEquals("match:eq",
node.at("/collection/operands/1/match").asText());
assertEquals("type:regex",
@@ -80,16 +85,12 @@
assertEquals("availability",
node.at("/collection/operands/1/key").asText());
assertEquals("ACA.*", node.at("/collection/operands/1/value").asText());
-
+
node = node.at("/collection/operands/0");
- assertEquals("match:eq",
- node.at("/operands/0/match").asText());
- assertEquals("type:regex",
- node.at("/operands/0/type").asText());
- assertEquals("availability",
- node.at("/operands/0/key").asText());
- assertEquals("CC-BY.*",
- node.at("/operands/0/value").asText());
+ assertEquals("match:eq", node.at("/operands/0/match").asText());
+ assertEquals("type:regex", node.at("/operands/0/type").asText());
+ assertEquals("availability", node.at("/operands/0/key").asText());
+ assertEquals("CC-BY.*", node.at("/operands/0/value").asText());
assertEquals("match:eq",
node.at("/operands/1/operands/0/match").asText());
@@ -99,7 +100,7 @@
node.at("/operands/1/operands/0/key").asText());
assertEquals("ACA.*", node.at("/operands/1/operands/0/value").asText());
-
+
}
private void checkAndAll (String json) throws KustvaktException {
@@ -140,7 +141,7 @@
node.at("/collection/rewrites/0/operation").asText());
assertEquals("availability(ALL)",
node.at("/collection/rewrites/0/scope").asText());
-
+
assertEquals("match:eq",
node.at("/collection/operands/1/match").asText());
assertEquals("type:regex",
@@ -148,17 +149,13 @@
assertEquals("availability",
node.at("/collection/operands/1/key").asText());
assertEquals("ACA.*", node.at("/collection/operands/1/value").asText());
-
+
node = node.at("/collection/operands/0");
-
- assertEquals("match:eq",
- node.at("/operands/0/match").asText());
- assertEquals("type:regex",
- node.at("/operands/0/type").asText());
- assertEquals("availability",
- node.at("/operands/0/key").asText());
- assertEquals("CC-BY.*",
- node.at("/operands/0/value").asText());
+
+ assertEquals("match:eq", node.at("/operands/0/match").asText());
+ assertEquals("type:regex", node.at("/operands/0/type").asText());
+ assertEquals("availability", node.at("/operands/0/key").asText());
+ assertEquals("CC-BY.*", node.at("/operands/0/value").asText());
assertEquals("match:eq",
node.at("/operands/1/operands/1/operands/0/match").asText());
assertEquals("QAO-NC",
@@ -167,7 +164,7 @@
node.at("/operands/1/operands/1/operands/1/match").asText());
assertEquals("QAO.*",
node.at("/operands/1/operands/1/operands/1/value").asText());
-
+
}
@@ -180,11 +177,13 @@
private ClientResponse builtClientResponseWithIP (String collectionQuery,
- String ip) throws UniformInterfaceException, ClientHandlerException, KustvaktException {
+ String ip) throws UniformInterfaceException, ClientHandlerException,
+ KustvaktException {
return resource().path("search").queryParam("q", "[orth=das]")
.queryParam("ql", "poliqarp").queryParam("cq", collectionQuery)
.header(Attributes.AUTHORIZATION,
- handler.createBasicAuthorizationHeaderValue("kustvakt", "kustvakt2015"))
+ handler.createBasicAuthorizationHeaderValue("kustvakt",
+ "kustvakt2015"))
.header(HttpHeaders.X_FORWARDED_FOR, ip)
.get(ClientResponse.class);
}
@@ -244,7 +243,7 @@
response.getStatus());
String json = response.getEntity(String.class);
-
+
JsonNode node = JsonUtils.readTree(json);
assertEquals("operation:and",
node.at("/collection/operation").asText());
@@ -440,4 +439,61 @@
checkAndAllWithACA(response.getEntity(String.class));
}
+ @Test
+ public void testAvailabilityOr () throws KustvaktException {
+ ClientResponse response = builtSimpleClientResponse(
+ "availability=/CC-BY.*/ | availability=/ACA.*/");
+
+ assertEquals(ClientResponse.Status.OK.getStatusCode(),
+ response.getStatus());
+
+ checkAndFree(response.getEntity(String.class));
+ }
+
+ @Test
+ public void testRedundancyOrPub () throws KustvaktException {
+ ClientResponse response = builtClientResponseWithIP(
+ "availability=/CC-BY.*/ | availability=/ACA.*/ | availability=/QAO-NC/",
+ "149.27.0.32");
+
+ assertEquals(ClientResponse.Status.OK.getStatusCode(),
+ response.getStatus());
+
+ String json = response.getEntity(String.class);
+ JsonNode node = JsonUtils.readTree(json);
+ assertTrue(node.at("/collection/rewrites").isMissingNode());
+ assertEquals("operation:or", node.at("/collection/operation").asText());
+ }
+
+ @Test
+ public void testAvailabilityOrCorpusSigle () throws KustvaktException {
+ ClientResponse response = builtSimpleClientResponse(
+ "availability=/CC-BY.*/ | corpusSigle=GOE");
+
+ assertEquals(ClientResponse.Status.OK.getStatusCode(),
+ response.getStatus());
+
+ checkAndFree(response.getEntity(String.class));
+ }
+
+ @Test
+ public void testOrWithoutAvailability () throws KustvaktException {
+ ClientResponse response = builtSimpleClientResponse(
+ "corpusSigle=GOE | textClass=politik");
+
+ assertEquals(ClientResponse.Status.OK.getStatusCode(),
+ response.getStatus());
+
+ checkAndFree(response.getEntity(String.class));
+ }
+
+ @Test
+ public void testWithoutAvailability () throws KustvaktException {
+ ClientResponse response = builtSimpleClientResponse("corpusSigle=GOE");
+
+ assertEquals(ClientResponse.Status.OK.getStatusCode(),
+ response.getStatus());
+
+ checkAndFree(response.getEntity(String.class));
+ }
}
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/MatchInfoControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/MatchInfoControllerTest.java
index 11a3193..4b0004a 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/MatchInfoControllerTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/MatchInfoControllerTest.java
@@ -4,16 +4,15 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import org.eclipse.jetty.http.HttpHeaders;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.net.HttpHeaders;
import com.sun.jersey.api.client.ClientResponse;
import de.ids_mannheim.korap.authentication.http.HttpAuthorizationHandler;
import de.ids_mannheim.korap.config.Attributes;
-import de.ids_mannheim.korap.config.TokenType;
import de.ids_mannheim.korap.exceptions.KustvaktException;
import de.ids_mannheim.korap.utils.JsonUtils;
import de.ids_mannheim.korap.web.FastJerseyTest;
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/SearchControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/SearchControllerTest.java
index 8d36bd8..b27e1bf 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/SearchControllerTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/SearchControllerTest.java
@@ -10,17 +10,16 @@
import javax.ws.rs.core.MediaType;
-import org.eclipse.jetty.http.HttpHeaders;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.net.HttpHeaders;
import com.sun.jersey.api.client.ClientResponse;
import de.ids_mannheim.korap.authentication.http.HttpAuthorizationHandler;
import de.ids_mannheim.korap.config.Attributes;
-import de.ids_mannheim.korap.config.TokenType;
import de.ids_mannheim.korap.config.ContextHolder;
import de.ids_mannheim.korap.exceptions.KustvaktException;
import de.ids_mannheim.korap.interfaces.db.EntityHandlerIface;
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerTest.java
index 537f299..c907338 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerTest.java
@@ -5,11 +5,11 @@
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
-import org.eclipse.jetty.http.HttpHeaders;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.net.HttpHeaders;
import com.sun.jersey.api.client.ClientHandlerException;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.ClientResponse.Status;
@@ -236,6 +236,7 @@
node.at("/errors/0/1").asText());
}
+ // EM: same as cancel invitation
private void testDeletePendingMember () throws UniformInterfaceException,
ClientHandlerException, KustvaktException {
// dory delete pearl
@@ -270,14 +271,14 @@
.delete(ClientResponse.class);
String entity = response.getEntity(String.class);
- System.out.println(entity);
+ // System.out.println(entity);
JsonNode node = JsonUtils.readTree(entity);
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
- assertEquals(StatusCodes.DB_ENTRY_DELETED,
+ assertEquals(StatusCodes.GROUP_MEMBER_DELETED,
node.at("/errors/0/0").asInt());
- assertEquals("pearl has already been deleted from the group.",
+ assertEquals("pearl has already been deleted from the group dory group",
node.at("/errors/0/1").asText());
- assertEquals("pearl", node.at("/errors/0/2").asText());
+ assertEquals("[pearl, dory group]", node.at("/errors/0/2").asText());
}
private void testDeleteGroup (String groupId)
@@ -442,10 +443,12 @@
// System.out.println(entity);
JsonNode node = JsonUtils.readTree(entity);
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
- assertEquals(StatusCodes.DB_ENTRY_EXISTS,
+ assertEquals(StatusCodes.GROUP_MEMBER_EXISTS,
node.at("/errors/0/0").asInt());
- assertEquals("Username marlin with status PENDING exists in user-group "
- + "dory group", node.at("/errors/0/1").asText());
+ assertEquals(
+ "Username marlin with status PENDING exists in the user-group "
+ + "dory group",
+ node.at("/errors/0/1").asText());
assertEquals("[marlin, PENDING, dory group]",
node.at("/errors/0/2").asText());
}
@@ -469,8 +472,6 @@
"pass"))
.entity(userGroup).post(ClientResponse.class);
-// String entity = response.getEntity(String.class);
-// System.out.println(entity);
assertEquals(Status.OK.getStatusCode(), response.getStatus());
// check member
@@ -538,9 +539,9 @@
JsonNode node = JsonUtils.readTree(entity);
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
- assertEquals(StatusCodes.NOTHING_CHANGED,
+ assertEquals(StatusCodes.GROUP_MEMBER_DELETED,
node.at("/errors/0/0").asInt());
- assertEquals("Username pearl had been deleted in group 2",
+ assertEquals("pearl has already been deleted from the group dory group",
node.at("/errors/0/1").asText());
}
@@ -578,9 +579,9 @@
JsonNode node = JsonUtils.readTree(entity);
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
- assertEquals(StatusCodes.NO_RESULT_FOUND,
+ assertEquals(StatusCodes.GROUP_MEMBER_NOT_FOUND,
node.at("/errors/0/0").asInt());
- assertEquals("Username bruce is not found in group 2",
+ assertEquals("bruce is not found in the group",
node.at("/errors/0/1").asText());
}
@@ -601,9 +602,9 @@
JsonNode node = JsonUtils.readTree(entity);
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
- assertEquals(StatusCodes.NO_RESULT_FOUND,
+ assertEquals(StatusCodes.GROUP_NOT_FOUND,
node.at("/errors/0/0").asInt());
- assertEquals("Username pearl is not found in group 100",
+ assertEquals("Group with id 100 is not found",
node.at("/errors/0/1").asText());
}
@@ -625,4 +626,62 @@
assertEquals(1, node.size());
}
+ @Test
+ public void testUnsubscribeDeletedMember ()
+ throws UniformInterfaceException, ClientHandlerException,
+ KustvaktException {
+ // pearl unsubscribes from dory group
+ MultivaluedMap<String, String> form = new MultivaluedMapImpl();
+ // dory group
+ form.add("groupId", "2");
+
+ ClientResponse response = resource().path("group").path("unsubscribe")
+ .type(MediaType.APPLICATION_FORM_URLENCODED)
+ .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
+ .header(Attributes.AUTHORIZATION,
+ handler.createBasicAuthorizationHeaderValue("pearl",
+ "pass"))
+ .entity(form).post(ClientResponse.class);
+
+ String entity = response.getEntity(String.class);
+ // System.out.println(entity);
+ JsonNode node = JsonUtils.readTree(entity);
+ assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
+ assertEquals(StatusCodes.GROUP_MEMBER_DELETED,
+ node.at("/errors/0/0").asInt());
+ assertEquals("pearl has already been deleted from the group dory group",
+ node.at("/errors/0/1").asText());
+ assertEquals("[pearl, dory group]", node.at("/errors/0/2").asText());
+ }
+
+ @Test
+ public void testUnsubscribePendingMember ()
+ throws UniformInterfaceException, ClientHandlerException,
+ KustvaktException {
+
+ JsonNode node = retrieveUserGroups("marlin");
+ assertEquals(2, node.size());
+
+ MultivaluedMap<String, String> form = new MultivaluedMapImpl();
+ // dory group
+ form.add("groupId", "2");
+
+ ClientResponse response = resource().path("group").path("unsubscribe")
+ .type(MediaType.APPLICATION_FORM_URLENCODED)
+ .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
+ .header(Attributes.AUTHORIZATION,
+ handler.createBasicAuthorizationHeaderValue("marlin",
+ "pass"))
+ .entity(form).post(ClientResponse.class);
+
+ String entity = response.getEntity(String.class);
+ // System.out.println(entity);
+ assertEquals(Status.OK.getStatusCode(), response.getStatus());
+
+ node = retrieveUserGroups("marlin");
+ assertEquals(1, node.size());
+
+ // invite marlin to dory group to set back the GroupMemberStatus.PENDING
+ testInviteDeletedMember();
+ }
}
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/VirtualCorpusControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/VirtualCorpusControllerTest.java
index 0df3720..e36fc0f 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/VirtualCorpusControllerTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/VirtualCorpusControllerTest.java
@@ -15,11 +15,11 @@
import javax.ws.rs.core.MultivaluedMap;
import org.apache.http.entity.ContentType;
-import org.eclipse.jetty.http.HttpHeaders;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.net.HttpHeaders;
import com.sun.jersey.api.client.ClientHandlerException;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.ClientResponse.Status;
diff --git a/full/src/test/resources/kustvakt-test.conf b/full/src/test/resources/kustvakt-test.conf
index 3d5eadd..ca6b233 100644
--- a/full/src/test/resources/kustvakt-test.conf
+++ b/full/src/test/resources/kustvakt-test.conf
@@ -10,11 +10,18 @@
ldap.config = file-path-to-ldap-config
# Kustvakt
-
## server
server.port=8089
server.host=localhost
+## mail settings
+mail.enabled = false
+mail.receiver = test@localhost
+mail.sender = noreply@ids-mannheim.de
+
+## mail.templates
+template.group.invitation = notification.vm
+
## default layers
default.layer.p = tt
default.layer.l = tt
diff --git a/full/src/test/resources/test-config.xml b/full/src/test/resources/test-config.xml
index b416f1c..22da89a 100644
--- a/full/src/test/resources/test-config.xml
+++ b/full/src/test/resources/test-config.xml
@@ -36,6 +36,8 @@
<array>
<value>classpath:test-jdbc.properties</value>
<value>file:./test-jdbc.properties</value>
+ <value>classpath:properties/mail.properties</value>
+ <value>file:./mail.properties</value>
<value>classpath:test-hibernate.properties</value>
<value>classpath:kustvakt-test.conf</value>
</array>
@@ -75,22 +77,28 @@
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
+ <property name="connectionProperties">
+ <props>
+ <prop key="date_string_format">yyyy-MM-dd HH:mm:ss</prop>
+ </props>
+ </property>
+
<!-- Sqlite can only have a single connection -->
<property name="suppressClose">
<value>true</value>
</property>
</bean>
-
+
<bean id="c3p0DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
- destroy-method="close">
- <property name="driverClass" value="${jdbc.driverClassName}" />
+ destroy-method="close">
+ <property name="driverClass" value="${jdbc.driverClassName}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
- <property name="maxPoolSize" value="4" />
- <property name="minPoolSize" value="1" />
- <property name="maxStatements" value="1" />
- <property name="testConnectionOnCheckout" value="true" />
+ <property name="maxPoolSize" value="4" />
+ <property name="minPoolSize" value="1" />
+ <property name="maxStatements" value="1" />
+ <property name="testConnectionOnCheckout" value="true" />
</bean>
<!-- to configure database for sqlite, mysql, etc. migrations -->
@@ -149,12 +157,12 @@
</bean>
<!-- Data access objects -->
- <bean id="resourceDao" class="de.ids_mannheim.korap.dao.ResourceDao"/>
+ <bean id="resourceDao" class="de.ids_mannheim.korap.dao.ResourceDao" />
<!-- <bean id="annotationDao" class="de.ids_mannheim.korap.dao.AnnotationDao"/> -->
<!-- Krill -->
<bean id="search_krill" class="de.ids_mannheim.korap.web.SearchKrill">
- <constructor-arg value="${krill.indexDir}"/>
+ <constructor-arg value="${krill.indexDir}" />
</bean>
@@ -165,11 +173,10 @@
<bean id="kustvakt_auditing" class="de.ids_mannheim.korap.handlers.JDBCAuditing">
<constructor-arg ref="kustvakt_db" />
</bean>
-
- <bean id="kustvakt_response"
- class="de.ids_mannheim.korap.web.FullResponseHandler">
- <constructor-arg index="0" name="iface" ref="kustvakt_auditing"/>
- </bean>
+
+ <bean id="kustvakt_response" class="de.ids_mannheim.korap.web.FullResponseHandler">
+ <constructor-arg index="0" name="iface" ref="kustvakt_auditing" />
+ </bean>
<bean id="kustvakt_userdb" class="de.ids_mannheim.korap.handlers.EntityDao">
<constructor-arg ref="kustvakt_db" />
@@ -197,15 +204,14 @@
</bean>
<!-- authentication providers to use -->
- <!-- <bean id="api_auth" class="de.ids_mannheim.korap.authentication.APIAuthentication">
- <constructor-arg type="de.ids_mannheim.korap.config.KustvaktConfiguration"
- ref="kustvakt_config" />
- </bean> -->
+ <!-- <bean id="api_auth" class="de.ids_mannheim.korap.authentication.APIAuthentication">
+ <constructor-arg type="de.ids_mannheim.korap.config.KustvaktConfiguration"
+ ref="kustvakt_config" /> </bean> -->
<bean id="ldap_auth" class="de.ids_mannheim.korap.authentication.LdapAuth3">
<constructor-arg type="de.ids_mannheim.korap.config.KustvaktConfiguration"
ref="kustvakt_config" />
</bean>
-
+
<bean id="openid_auth"
class="de.ids_mannheim.korap.authentication.OpenIDconnectAuthentication">
<constructor-arg type="de.ids_mannheim.korap.config.KustvaktConfiguration"
@@ -214,7 +220,8 @@
type="de.ids_mannheim.korap.interfaces.db.PersistenceClient" ref="kustvakt_db" />
</bean>
- <bean id="basic_auth" class="de.ids_mannheim.korap.authentication.BasicAuthentication" />
+ <bean id="basic_auth"
+ class="de.ids_mannheim.korap.authentication.BasicAuthentication" />
<bean id="session_auth"
@@ -299,4 +306,35 @@
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
+
+ <!-- mail -->
+ <bean id="authenticator" class="de.ids_mannheim.korap.service.MailAuthenticator">
+ <constructor-arg index="0" value="${mail.username}"/>
+ <constructor-arg index="1" value="${mail.password}"/>
+ </bean>
+ <bean id="smtpSession" class="javax.mail.Session" factory-method="getInstance">
+ <constructor-arg index="0">
+ <props>
+ <prop key="mail.smtp.submitter">${mail.username}</prop>
+ <prop key="mail.smtp.auth">${mail.auth}</prop>
+ <prop key="mail.smtp.host">${mail.host}</prop>
+ <prop key="mail.smtp.port">${mail.port}</prop>
+ <prop key="mail.smtp.starttls.enable">${mail.starttls.enable}</prop>
+ <prop key="mail.smtp.connectiontimeout">${mail.connectiontimeout}</prop>
+ </props>
+ </constructor-arg>
+ <constructor-arg index="1" ref="authenticator"/>
+ </bean>
+ <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
+ <property name="session" ref="smtpSession" />
+ </bean>
+ <bean id="velocityEngine" class="org.apache.velocity.app.VelocityEngine">
+ <constructor-arg index="0">
+ <props>
+ <prop key="resource.loader">class</prop>
+ <prop key="class.resource.loader.class">org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
+ </prop>
+ </props>
+ </constructor-arg>
+ </bean>
</beans>
\ No newline at end of file
diff --git a/lite/Changes b/lite/Changes
index 4e615e9..6355c0f 100644
--- a/lite/Changes
+++ b/lite/Changes
@@ -1,8 +1,11 @@
-0.59.9 2018-02-01
+version 0.59.9
+01/02/2018
- renamed light to lite (margaretha)
- added Changes file (margaretha)
- updated library versions and java environment (margaretha)
-0.59.8 2018-01-17
+
+version 0.59.8
+17/01/2018
- restructured Kustvakt and created /lite project
- removed version from service paths (margaretha)
- updated query serialization tests (margaretha)
diff --git a/lite/src/main/java/de/ids_mannheim/korap/server/KustvaktLiteServer.java b/lite/src/main/java/de/ids_mannheim/korap/server/KustvaktLiteServer.java
index c0e31f3..acac717 100644
--- a/lite/src/main/java/de/ids_mannheim/korap/server/KustvaktLiteServer.java
+++ b/lite/src/main/java/de/ids_mannheim/korap/server/KustvaktLiteServer.java
@@ -22,10 +22,4 @@
server.start();
}
- @Override
- protected void setup () {
- // TODO Auto-generated method stub
-
- }
-
}