Merged changelog to Changes & updated status codes.

Change-Id: I8a9a7c80b8785b17d17d5307e28783399274eb82
diff --git a/full/Changes b/full/Changes
index 7e42673..e3dc087 100644
--- a/full/Changes
+++ b/full/Changes
@@ -1,4 +1,5 @@
-0.59.10	2018-02-06 
+version 0.59.10	
+07/02/2018 
 	- added sort VC by id (margaretha)
 	- added test cases regarding VC sharing (margaretha)
 	- implemented withdraw VC from publication (margaretha)
@@ -11,8 +12,12 @@
 	- 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)
 	
-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)
@@ -38,8 +43,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)
@@ -55,5 +60,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/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 5aa06d8..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,18 +36,17 @@
         entityManager.persist(member);
     }
 
-//    @Deprecated
-//    public void addMembers (List<UserGroupMember> members)
-//            throws KustvaktException {
-//        ParameterChecker.checkObjectValue(members, "List<UserGroupMember>");
-//
-//        for (UserGroupMember member : members) {
-//            addMember(member);
-//        }
-//    }
+    //    @Deprecated
+    //    public void addMembers (List<UserGroupMember> members)
+    //            throws KustvaktException {
+    //        ParameterChecker.checkObjectValue(members, "List<UserGroupMember>");
+    //
+    //        for (UserGroupMember member : members) {
+    //            addMember(member);
+    //        }
+    //    }
 
-    public void updateMember (UserGroupMember member)
-            throws KustvaktException {
+    public void updateMember (UserGroupMember member) throws KustvaktException {
         ParameterChecker.checkObjectValue(member, "UserGroupMember");
         entityManager.merge(member);
     }
@@ -96,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/service/UserGroupService.java b/full/src/main/java/de/ids_mannheim/korap/service/UserGroupService.java
index d39eb89..1dfd16f 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
@@ -322,24 +322,24 @@
 
         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)) {
-            UserGroup group = userGroupDao.retrieveGroupById(groupId);
             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)) {
-            UserGroup userGroup = retrieveUserGroupById(groupId);
             throw new KustvaktException(StatusCodes.GROUP_MEMBER_EXISTS,
                     "Username " + username + " with status " + status
                             + " exists in the user-group "
-                            + userGroup.getName(),
-                    username, status.name(), userGroup.getName());
+                            + group.getName(),
+                    username, status.name(), group.getName());
         }
         // status pending
         else {
@@ -405,11 +405,13 @@
      */
     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)) {
-            UserGroup group = userGroupDao.retrieveGroupById(groupId);
             throw new KustvaktException(StatusCodes.GROUP_MEMBER_DELETED,
                     username + " has already been deleted from the group "
                             + group.getName(),
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/default-config.xml b/full/src/main/resources/default-config.xml
index cd52fc0..8466d6a 100644
--- a/full/src/main/resources/default-config.xml
+++ b/full/src/main/resources/default-config.xml
@@ -41,9 +41,9 @@
 		<property name="ignoreResourceNotFound" value="true" />
 		<property name="locations">
 			<array>
-				<value>classpath:jdbc.properties</value>
+				<value>classpath:*/jdbc.properties</value>
 				<value>file:./jdbc.properties</value>
-				<value>classpath:hibernate.properties</value>
+				<value>classpath:*/hibernate.properties</value>
 				<value>classpath:kustvakt.conf</value>
 				<value>file:./kustvakt.conf</value>
 			</array>
@@ -312,4 +312,20 @@
 		<property name="dataSource" ref="sqliteDataSource" />
 	</bean>
 	
+	<!-- mail -->
+	<!-- <bean id="smtpSession" class="org.springframework.jndi.JndiObjectFactoryBean">
+		<property name="jndiName" value="java:comp/env/mail/jetty" />
+	</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/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/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 100%
rename from full/src/main/resources/jdbc.properties
rename to full/src/main/resources/properties/jdbc.properties
diff --git a/full/src/main/resources/log4j.properties b/full/src/main/resources/properties/log4j.properties
similarity index 100%
rename from full/src/main/resources/log4j.properties
rename to full/src/main/resources/properties/log4j.properties
diff --git a/full/src/main/resources/validation.properties b/full/src/main/resources/validation.properties
deleted file mode 100644
index 0a8f4f0..0000000
--- a/full/src/main/resources/validation.properties
+++ /dev/null
@@ -1,38 +0,0 @@
-# The ESAPI validator does many security checks on input, such as canonicalization
-# and whitelist validation. Note that all of these validation rules are applied *after*
-# canonicalization. Double-encoded characters (even with different encodings involved,
-# are never allowed.
-#
-# To use:
-#
-# First set up a pattern below. You can choose any name you want, prefixed by the word
-# "Validation." For example:
-#   Validation.Email=^[A-Za-z0-9._%-]+@[A-Za-z0-9.-]+\\.[a-zA-Z]{2,4}$
-# 
-# Then you can validate in your code against the pattern like this:
-#     ESAPI.validator().isValidInput("User Email", input, "Email", maxLength, allowNull);
-# Where maxLength and allowNull are set for you needs, respectively.
-#
-# But note, when you use boolean variants of validation functions, you lose critical 
-# canonicalization. It is preferable to use the "get" methods (which throw exceptions) and
-# and use the returned user input which is in canonical form. Consider the following:
-#  
-# try {
-#    someObject.setEmail(ESAPI.validator().getValidInput("User Email", input, "Email", maxLength, allowNull));
-#
-# Validator.SafeString=^[.;:\\-\\p{Alnum}\\p{Space}]{0,1024}$
-# Validator.password_cap=((?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{8,20})
-Validator.SafeString=^[.;:,=\\*\/\/_()\\-0-9\\p{L}\\p{Space}]{0,1024}$
-Validator.email=^[A-Za-z0-9._%'-]+@[A-Za-z0-9.-]+\\.[a-zA-Z]{2,4}$
-Validator.ipddress=^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$
-Validator.url=^(ht|f)tp(s?)\\:\\/\\/[0-9a-zA-Z]([-.\\w]*[0-9a-zA-Z])*(:(0-9)*)*(\\/?)([a-zA-Z0-9\\-\\.\\?\\,\\:\\'\\/\\\\\\+=&amp;%\\$#_]*)?$
-# Validator.CreditCard=^(\\d{4}[- ]?){3}\\d{4}$
-# Validator.SSN=^(?!000)([0-6]\\d{2}|7([0-6]\\d|7[012]))([ -]?)(?!00)\\d\\d\\3(?!0000)\\d{4}$
-
-# as used by apache commons validator for strings
-# Validator.string=^[\\.;:,\\=&\\*\\/\\/_()\\[\\]@\\|\\-0-9\\p{L}\\p{Space}]{0,1024}$
-
-#Validator.username=^[A-Za-z_.\\d]{6,15}$ by Hanl
-# 21.04.17/FB
-Validator.username=^[A-Za-z_.\\d]{3,20}$
-Validator.password=^((?=.*\\d)(?=.*[A-Za-z])(?!.*[\\(\\)-]).{8,20})$
\ No newline at end of file
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 818f215..ce88df3 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
@@ -445,7 +445,7 @@
         assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
         assertEquals(StatusCodes.GROUP_MEMBER_EXISTS,
                 node.at("/errors/0/0").asInt());
-        assertEquals("Username marlin with status PENDING exists in user-group "
+        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());
@@ -539,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());
     }
 
@@ -579,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());
     }
 
@@ -602,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());
     }