SEBSERV-18 SEBSERV-19 #ported from prototype
This commit is contained in:
		
							parent
							
								
									f21f959ad2
								
							
						
					
					
						commit
						d5f7752e98
					
				
					 92 changed files with 4016 additions and 336 deletions
				
			
		
							
								
								
									
										6
									
								
								pom.xml
									
										
									
									
									
								
							
							
						
						
									
										6
									
								
								pom.xml
									
										
									
									
									
								
							|  | @ -225,6 +225,12 @@ | ||||||
|       <version>1.0.9.RELEASE</version> |       <version>1.0.9.RELEASE</version> | ||||||
|     </dependency> |     </dependency> | ||||||
| 
 | 
 | ||||||
|  |     <!-- Apache HTTP --> | ||||||
|  |     <dependency> | ||||||
|  |       <groupId>org.apache.httpcomponents</groupId> | ||||||
|  |       <artifactId>httpclient</artifactId> | ||||||
|  |     </dependency> | ||||||
|  | 
 | ||||||
|     <!-- Eclipse RAP / RWT --> |     <!-- Eclipse RAP / RWT --> | ||||||
|     <dependency> |     <dependency> | ||||||
|       <groupId>org.eclipse.rap</groupId> |       <groupId>org.eclipse.rap</groupId> | ||||||
|  |  | ||||||
|  | @ -19,6 +19,7 @@ import org.springframework.boot.web.servlet.error.ErrorController; | ||||||
| import org.springframework.context.annotation.Bean; | import org.springframework.context.annotation.Bean; | ||||||
| import org.springframework.context.annotation.Configuration; | import org.springframework.context.annotation.Configuration; | ||||||
| import org.springframework.core.annotation.Order; | import org.springframework.core.annotation.Order; | ||||||
|  | import org.springframework.http.HttpStatus; | ||||||
| import org.springframework.security.config.annotation.web.builders.HttpSecurity; | import org.springframework.security.config.annotation.web.builders.HttpSecurity; | ||||||
| import org.springframework.security.config.annotation.web.builders.WebSecurity; | import org.springframework.security.config.annotation.web.builders.WebSecurity; | ||||||
| import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; | ||||||
|  | @ -90,6 +91,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter implements E | ||||||
|                                     final HttpServletResponse response, |                                     final HttpServletResponse response, | ||||||
|                                     final AuthenticationException authException) throws IOException, ServletException { |                                     final AuthenticationException authException) throws IOException, ServletException { | ||||||
| 
 | 
 | ||||||
|  |                                 response.setStatus(HttpStatus.UNAUTHORIZED.value()); | ||||||
|                                 response.sendRedirect(WebSecurityConfig.this.unauthorizedRedirect); |                                 response.sendRedirect(WebSecurityConfig.this.unauthorizedRedirect); | ||||||
|                             } |                             } | ||||||
|                         }) |                         }) | ||||||
|  | @ -104,6 +106,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter implements E | ||||||
| 
 | 
 | ||||||
|     @RequestMapping("/error") |     @RequestMapping("/error") | ||||||
|     public void handleError(final HttpServletResponse response) throws IOException { |     public void handleError(final HttpServletResponse response) throws IOException { | ||||||
|  |         response.setStatus(HttpStatus.NOT_FOUND.value()); | ||||||
|         response.sendRedirect(this.unauthorizedRedirect); |         response.sendRedirect(this.unauthorizedRedirect); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -6,9 +6,11 @@ | ||||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| package ch.ethz.seb.sebserver.gbl.model; | package ch.ethz.seb.sebserver.gbl.api; | ||||||
| 
 | 
 | ||||||
| import java.io.Serializable; | import java.io.Serializable; | ||||||
|  | import java.util.Arrays; | ||||||
|  | import java.util.Collection; | ||||||
| import java.util.Collections; | import java.util.Collections; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| 
 | 
 | ||||||
|  | @ -72,12 +74,14 @@ public class APIMessage implements Serializable { | ||||||
|             return new APIMessage(this.messageCode, this.systemMessage, error.getMessage()); |             return new APIMessage(this.messageCode, this.systemMessage, error.getMessage()); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public ResponseEntity<APIMessage> createErrorResponse() { |         public ResponseEntity<List<APIMessage>> createErrorResponse() { | ||||||
|             return new ResponseEntity<>(of(), this.httpStatus); |             final APIMessage message = of(); | ||||||
|  |             return new ResponseEntity<>(Arrays.asList(message), this.httpStatus); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public ResponseEntity<Object> createErrorResponse(final String details, final String... attributes) { |         public ResponseEntity<Object> createErrorResponse(final String details, final String... attributes) { | ||||||
|             return new ResponseEntity<>(of(details, attributes), this.httpStatus); |             final APIMessage message = of(details, attributes); | ||||||
|  |             return new ResponseEntity<>(Arrays.asList(message), this.httpStatus); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -134,6 +138,24 @@ public class APIMessage implements Serializable { | ||||||
|         return ErrorMessage.FIELD_VALIDATION.of(error.toString(), args); |         return ErrorMessage.FIELD_VALIDATION.of(error.toString(), args); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public static String toHTML(final Collection<APIMessage> messages) { | ||||||
|  |         final StringBuilder builder = new StringBuilder(); | ||||||
|  |         builder.append("<b>Messages:</b><br/><br/>"); | ||||||
|  |         messages.stream().forEach(message -> { | ||||||
|  |             builder | ||||||
|  |                     .append("  code : ") | ||||||
|  |                     .append(message.messageCode) | ||||||
|  |                     .append("<br/>") | ||||||
|  |                     .append("  system message : ") | ||||||
|  |                     .append(message.systemMessage) | ||||||
|  |                     .append("<br/>") | ||||||
|  |                     .append("  details : ") | ||||||
|  |                     .append(StringUtils.abbreviate(message.details, 100)) | ||||||
|  |                     .append("<br/><br/>"); | ||||||
|  |         }); | ||||||
|  |         return builder.toString(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public static class APIMessageException extends RuntimeException { |     public static class APIMessageException extends RuntimeException { | ||||||
| 
 | 
 | ||||||
|         private static final long serialVersionUID = 1453431210820677296L; |         private static final long serialVersionUID = 1453431210820677296L; | ||||||
|  | @ -0,0 +1,17 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gbl.api; | ||||||
|  | 
 | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | public interface APIMessageError { | ||||||
|  | 
 | ||||||
|  |     List<APIMessage> getErrorMessages(); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -6,7 +6,7 @@ | ||||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| package ch.ethz.seb.sebserver.gbl; | package ch.ethz.seb.sebserver.gbl.api; | ||||||
| 
 | 
 | ||||||
| import org.springframework.context.annotation.Lazy; | import org.springframework.context.annotation.Lazy; | ||||||
| import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||||
|  | @ -6,7 +6,7 @@ | ||||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| package ch.ethz.seb.sebserver.gbl; | package ch.ethz.seb.sebserver.gbl.api; | ||||||
| 
 | 
 | ||||||
| import java.util.Collections; | import java.util.Collections; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  | @ -6,9 +6,9 @@ | ||||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| package ch.ethz.seb.sebserver.webservice.weblayer.api; | package ch.ethz.seb.sebserver.gbl.api; | ||||||
| 
 | 
 | ||||||
| public class RestAPI { | public class SEBServerRestEndpoints { | ||||||
| 
 | 
 | ||||||
|     public static final String ENDPOINT_INSTITUTION = "/institution"; |     public static final String ENDPOINT_INSTITUTION = "/institution"; | ||||||
| 
 | 
 | ||||||
|  | @ -22,8 +22,8 @@ public interface Entity extends ModelIdAware { | ||||||
|     @JsonIgnore |     @JsonIgnore | ||||||
|     String getName(); |     String getName(); | ||||||
| 
 | 
 | ||||||
|     public static EntityKeyAndName toName(final Entity entity) { |     public static EntityName toName(final Entity entity) { | ||||||
|         return new EntityKeyAndName( |         return new EntityName( | ||||||
|                 entity.entityType(), |                 entity.entityType(), | ||||||
|                 entity.getModelId(), |                 entity.getModelId(), | ||||||
|                 entity.getName()); |                 entity.getName()); | ||||||
|  |  | ||||||
|  | @ -14,7 +14,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; | ||||||
| import com.fasterxml.jackson.annotation.JsonProperty; | import com.fasterxml.jackson.annotation.JsonProperty; | ||||||
| 
 | 
 | ||||||
| @JsonIgnoreProperties(ignoreUnknown = true) | @JsonIgnoreProperties(ignoreUnknown = true) | ||||||
| public class EntityKeyAndName implements ModelIdAware, ModelNameAware { | public class EntityName implements ModelIdAware, ModelNameAware { | ||||||
| 
 | 
 | ||||||
|     @JsonProperty(value = "entityType", required = true) |     @JsonProperty(value = "entityType", required = true) | ||||||
|     public final EntityType entityType; |     public final EntityType entityType; | ||||||
|  | @ -24,7 +24,7 @@ public class EntityKeyAndName implements ModelIdAware, ModelNameAware { | ||||||
|     public final String name; |     public final String name; | ||||||
| 
 | 
 | ||||||
|     @JsonCreator |     @JsonCreator | ||||||
|     public EntityKeyAndName( |     public EntityName( | ||||||
|             @JsonProperty(value = "entityType", required = true) final EntityType entityType, |             @JsonProperty(value = "entityType", required = true) final EntityType entityType, | ||||||
|             @JsonProperty(value = Domain.ATTR_ID, required = true) final String id, |             @JsonProperty(value = Domain.ATTR_ID, required = true) final String id, | ||||||
|             @JsonProperty(value = "name", required = true) final String name) { |             @JsonProperty(value = "name", required = true) final String name) { | ||||||
|  | @ -34,7 +34,7 @@ public class EntityKeyAndName implements ModelIdAware, ModelNameAware { | ||||||
|         this.name = name; |         this.name = name; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public EntityKeyAndName(final EntityKey entityKey, final String name) { |     public EntityName(final EntityKey entityKey, final String name) { | ||||||
| 
 | 
 | ||||||
|         this.entityType = entityKey.entityType; |         this.entityType = entityKey.entityType; | ||||||
|         this.modelId = entityKey.modelId; |         this.modelId = entityKey.modelId; | ||||||
|  | @ -74,7 +74,7 @@ public class EntityKeyAndName implements ModelIdAware, ModelNameAware { | ||||||
|             return false; |             return false; | ||||||
|         if (getClass() != obj.getClass()) |         if (getClass() != obj.getClass()) | ||||||
|             return false; |             return false; | ||||||
|         final EntityKeyAndName other = (EntityKeyAndName) obj; |         final EntityName other = (EntityName) obj; | ||||||
|         if (this.entityType != other.entityType) |         if (this.entityType != other.entityType) | ||||||
|             return false; |             return false; | ||||||
|         if (this.modelId == null) { |         if (this.modelId == null) { | ||||||
|  | @ -14,6 +14,7 @@ import java.util.Set; | ||||||
| import com.fasterxml.jackson.annotation.JsonCreator; | import com.fasterxml.jackson.annotation.JsonCreator; | ||||||
| import com.fasterxml.jackson.annotation.JsonProperty; | import com.fasterxml.jackson.annotation.JsonProperty; | ||||||
| 
 | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gbl.api.APIMessage; | ||||||
| import ch.ethz.seb.sebserver.gbl.util.Utils; | import ch.ethz.seb.sebserver.gbl.util.Utils; | ||||||
| 
 | 
 | ||||||
| public class EntityProcessingReport { | public class EntityProcessingReport { | ||||||
|  |  | ||||||
|  | @ -19,7 +19,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; | ||||||
| import com.fasterxml.jackson.annotation.JsonIgnore; | import com.fasterxml.jackson.annotation.JsonIgnore; | ||||||
| import com.fasterxml.jackson.annotation.JsonProperty; | import com.fasterxml.jackson.annotation.JsonProperty; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.gbl.POSTMapper; | import ch.ethz.seb.sebserver.gbl.api.POSTMapper; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Activatable; | import ch.ethz.seb.sebserver.gbl.model.Activatable; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Domain.EXAM; | import ch.ethz.seb.sebserver.gbl.model.Domain.EXAM; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.EntityType; | import ch.ethz.seb.sebserver.gbl.model.EntityType; | ||||||
|  |  | ||||||
|  | @ -13,7 +13,7 @@ import javax.validation.constraints.Size; | ||||||
| 
 | 
 | ||||||
| import com.fasterxml.jackson.annotation.JsonProperty; | import com.fasterxml.jackson.annotation.JsonProperty; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.gbl.POSTMapper; | import ch.ethz.seb.sebserver.gbl.api.POSTMapper; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Activatable; | import ch.ethz.seb.sebserver.gbl.model.Activatable; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Domain; | import ch.ethz.seb.sebserver.gbl.model.Domain; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Domain.INSTITUTION; | import ch.ethz.seb.sebserver.gbl.model.Domain.INSTITUTION; | ||||||
|  |  | ||||||
|  | @ -15,12 +15,12 @@ import com.fasterxml.jackson.annotation.JsonCreator; | ||||||
| import com.fasterxml.jackson.annotation.JsonIgnore; | import com.fasterxml.jackson.annotation.JsonIgnore; | ||||||
| import com.fasterxml.jackson.annotation.JsonProperty; | import com.fasterxml.jackson.annotation.JsonProperty; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.gbl.POSTMapper; | import ch.ethz.seb.sebserver.gbl.api.POSTMapper; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Activatable; | import ch.ethz.seb.sebserver.gbl.model.Activatable; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Domain; | import ch.ethz.seb.sebserver.gbl.model.Domain; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Domain.INSTITUTION; | import ch.ethz.seb.sebserver.gbl.model.Domain.INSTITUTION; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Domain.LMS_SETUP; | import ch.ethz.seb.sebserver.gbl.model.Domain.LMS_SETUP; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.EntityKeyAndName; | import ch.ethz.seb.sebserver.gbl.model.EntityName; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.EntityType; | import ch.ethz.seb.sebserver.gbl.model.EntityType; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.GrantEntity; | import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.GrantEntity; | ||||||
| 
 | 
 | ||||||
|  | @ -198,8 +198,8 @@ public final class LmsSetup implements GrantEntity, Activatable { | ||||||
|                 + this.sebAuthSecret + ", active=" + this.active + "]"; |                 + this.sebAuthSecret + ", active=" + this.active + "]"; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public static EntityKeyAndName toName(final LmsSetup lmsSetup) { |     public static EntityName toName(final LmsSetup lmsSetup) { | ||||||
|         return new EntityKeyAndName( |         return new EntityName( | ||||||
|                 EntityType.LMS_SETUP, |                 EntityType.LMS_SETUP, | ||||||
|                 String.valueOf(lmsSetup.id), |                 String.valueOf(lmsSetup.id), | ||||||
|                 lmsSetup.name); |                 lmsSetup.name); | ||||||
|  |  | ||||||
|  | @ -156,6 +156,13 @@ public final class UserInfo implements GrantEntity, Activatable, Serializable { | ||||||
|         return this.roles; |         return this.roles; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public boolean hasRole(final UserRole userRole) { | ||||||
|  |         if (userRole == null) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         return this.roles.contains(userRole.name()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     @Override |     @Override | ||||||
|     public int hashCode() { |     public int hashCode() { | ||||||
|         final int prime = 31; |         final int prime = 31; | ||||||
|  |  | ||||||
|  | @ -22,9 +22,9 @@ import com.fasterxml.jackson.annotation.JsonCreator; | ||||||
| import com.fasterxml.jackson.annotation.JsonIgnoreProperties; | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; | ||||||
| import com.fasterxml.jackson.annotation.JsonProperty; | import com.fasterxml.jackson.annotation.JsonProperty; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.gbl.POSTMapper; |  | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Domain.USER; | import ch.ethz.seb.sebserver.gbl.model.Domain.USER; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Domain.USER_ROLE; | import ch.ethz.seb.sebserver.gbl.model.Domain.USER_ROLE; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.api.POSTMapper; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.EntityType; | import ch.ethz.seb.sebserver.gbl.model.EntityType; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.GrantEntity; | import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.GrantEntity; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -69,23 +69,58 @@ public final class Result<T> { | ||||||
|         return this.value; |         return this.value; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** @return the error if some was reporter or null if there was no error */ |     /** Use this to get the resulting value. In an error case, a given error handling | ||||||
|     public Throwable getError() { |      * function is used that receives the error and returns a resulting value instead | ||||||
|         return this.error; |      * (or throw some error instead) | ||||||
|  |      * | ||||||
|  |      * @param errorHandler the error handling function | ||||||
|  |      * @return */ | ||||||
|  |     public T get(final Function<Throwable, T> errorHandler) { | ||||||
|  |         return this.error != null ? errorHandler.apply(this.error) : this.value; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public boolean hasError() { |     public T get(final Consumer<Throwable> errorHandler, final Supplier<T> supplier) { | ||||||
|         return this.error != null; |         if (this.error != null) { | ||||||
|  |             errorHandler.accept(this.error); | ||||||
|  |             return supplier.get(); | ||||||
|  |         } else { | ||||||
|  |             return this.value; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** Use this to get the resulting value or (if null) to get a given other value |     /** Use this to get the resulting value or (if null) to get a given other value | ||||||
|      * |      * | ||||||
|      * @param other the other value to get if the computed value is null |      * @param other the other value to get if the computed value is null | ||||||
|      * @return return either the computed value if existing or a given other value */ |      * @return return either the computed value if existing or a given other value */ | ||||||
|     public T getOrElse(final T other) { |     public T getOr(final T other) { | ||||||
|         return this.value != null ? this.value : other; |         return this.value != null ? this.value : other; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** Use this to get the resulting value if existing or throw an Runtime exception with | ||||||
|  |      * given message otherwise. | ||||||
|  |      * | ||||||
|  |      * @param message the message for the RuntimeException in error case | ||||||
|  |      * @return the resulting value */ | ||||||
|  |     public T getOrThrowRuntime(final String message) { | ||||||
|  |         if (this.error != null) { | ||||||
|  |             throw new RuntimeException(message, this.error); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return this.value; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public T getOrThrow() { | ||||||
|  |         if (this.error != null) { | ||||||
|  |             if (this.error instanceof RuntimeException) { | ||||||
|  |                 throw (RuntimeException) this.error; | ||||||
|  |             } else { | ||||||
|  |                 throw new RuntimeException("RuntimeExceptionWrapper cause: ", this.error); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return this.value; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /** Use this to get the resulting value or (if null) to get a given other value |     /** Use this to get the resulting value or (if null) to get a given other value | ||||||
|      * |      * | ||||||
|      * @param supplier supplier to get the value from if the computed value is null |      * @param supplier supplier to get the value from if the computed value is null | ||||||
|  | @ -94,6 +129,15 @@ public final class Result<T> { | ||||||
|         return this.value != null ? this.value : supplier.get(); |         return this.value != null ? this.value : supplier.get(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** @return the error if some was reporter or null if there was no error */ | ||||||
|  |     public Throwable getError() { | ||||||
|  |         return this.error; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public boolean hasError() { | ||||||
|  |         return this.error != null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /** If a value is present, performs the given action with the value, |     /** If a value is present, performs the given action with the value, | ||||||
|      * otherwise performs the given empty-based action. |      * otherwise performs the given empty-based action. | ||||||
|      * |      * | ||||||
|  | @ -155,16 +199,6 @@ public final class Result<T> { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** Use this to get the resulting value. In an error case, a given error handling |  | ||||||
|      * function is used that receives the error and returns a resulting value instead |  | ||||||
|      * (or throw some error instead) |  | ||||||
|      * |  | ||||||
|      * @param errorHandler the error handling function |  | ||||||
|      * @return */ |  | ||||||
|     public T getOrHandleError(final Function<Throwable, T> errorHandler) { |  | ||||||
|         return this.error != null ? errorHandler.apply(this.error) : this.value; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public Result<T> onErrorDo(final Consumer<Throwable> block) { |     public Result<T> onErrorDo(final Consumer<Throwable> block) { | ||||||
|         if (this.error != null) { |         if (this.error != null) { | ||||||
|             block.accept(this.error); |             block.accept(this.error); | ||||||
|  | @ -172,31 +206,6 @@ public final class Result<T> { | ||||||
|         return this; |         return this; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** Use this to get the resulting value if existing or throw an Runtime exception with |  | ||||||
|      * given message otherwise. |  | ||||||
|      * |  | ||||||
|      * @param message the message for the RuntimeException in error case |  | ||||||
|      * @return the resulting value */ |  | ||||||
|     public T getOrThrowRuntime(final String message) { |  | ||||||
|         if (this.error != null) { |  | ||||||
|             throw new RuntimeException(message, this.error); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return this.value; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public T getOrThrow() { |  | ||||||
|         if (this.error != null) { |  | ||||||
|             if (this.error instanceof RuntimeException) { |  | ||||||
|                 throw (RuntimeException) this.error; |  | ||||||
|             } else { |  | ||||||
|                 throw new RuntimeException("RuntimeExceptionWrapper cause: ", this.error); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return this.value; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** Use this to create a Result of a given resulting value. |     /** Use this to create a Result of a given resulting value. | ||||||
|      * |      * | ||||||
|      * @param value resulting value |      * @param value resulting value | ||||||
|  |  | ||||||
|  | @ -103,7 +103,7 @@ public final class Utils { | ||||||
| 
 | 
 | ||||||
|     public static Long dateTimeStringToTimestamp(final String startTime, final Long defaultValue) { |     public static Long dateTimeStringToTimestamp(final String startTime, final Long defaultValue) { | ||||||
|         return dateTimeStringToTimestamp(startTime) |         return dateTimeStringToTimestamp(startTime) | ||||||
|                 .getOrElse(defaultValue); |                 .getOr(defaultValue); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public static <M extends Map<K, V>, K, V> M mapPut(final M map, final K key, final V value) { |     public static <M extends Map<K, V>, K, V> M mapPut(final M map, final K key, final V value) { | ||||||
|  |  | ||||||
|  | @ -11,7 +11,6 @@ package ch.ethz.seb.sebserver.gui; | ||||||
| import org.springframework.beans.factory.annotation.Value; | import org.springframework.beans.factory.annotation.Value; | ||||||
| import org.springframework.context.annotation.Configuration; | import org.springframework.context.annotation.Configuration; | ||||||
| import org.springframework.core.annotation.Order; | import org.springframework.core.annotation.Order; | ||||||
| import org.springframework.security.config.annotation.web.builders.HttpSecurity; |  | ||||||
| import org.springframework.security.config.annotation.web.builders.WebSecurity; | import org.springframework.security.config.annotation.web.builders.WebSecurity; | ||||||
| import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; | ||||||
| import org.springframework.security.web.util.matcher.AntPathRequestMatcher; | import org.springframework.security.web.util.matcher.AntPathRequestMatcher; | ||||||
|  | @ -43,38 +42,4 @@ public class GuiWebsecurityConfig extends WebSecurityConfigurerAdapter { | ||||||
|                 .requestMatchers(PUBLIC_URLS); |                 .requestMatchers(PUBLIC_URLS); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |  | ||||||
|     protected void configure(final HttpSecurity http) throws Exception { |  | ||||||
|         System.out.println("**************** GuiWebConfig: "); |  | ||||||
| //        //@formatter:off |  | ||||||
| //        http |  | ||||||
| //            .sessionManagement() |  | ||||||
| //            .sessionCreationPolicy(SessionCreationPolicy.STATELESS) |  | ||||||
| //        .and() |  | ||||||
| //            .antMatcher("/**"/*this.guiEndpointPath + "/**"*/) |  | ||||||
| //            .authorizeRequests() |  | ||||||
| //            .anyRequest() |  | ||||||
| //            .authenticated() |  | ||||||
| //            .and() |  | ||||||
| //            .exceptionHandling() |  | ||||||
| //            .authenticationEntryPoint( |  | ||||||
| //                    new AuthenticationEntryPoint() { |  | ||||||
| // |  | ||||||
| //                        @Override |  | ||||||
| //                        public void commence(final HttpServletRequest request, final HttpServletResponse response, |  | ||||||
| //                                final AuthenticationException authException) throws IOException, ServletException { |  | ||||||
| //                            response.sendRedirect("/gui"); |  | ||||||
| //                        } |  | ||||||
| // |  | ||||||
| //                    }) |  | ||||||
| //        .and() |  | ||||||
| //            .formLogin().disable() |  | ||||||
| //            .httpBasic().disable() |  | ||||||
| //            .logout().disable() |  | ||||||
| //            .headers().frameOptions().disable() |  | ||||||
| //         .and() |  | ||||||
| //            .csrf().disable(); |  | ||||||
|       //@formatter:on |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,72 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.i18n; | ||||||
|  | 
 | ||||||
|  | import java.util.Collection; | ||||||
|  | import java.util.Locale; | ||||||
|  | 
 | ||||||
|  | import org.joda.time.DateTime; | ||||||
|  | 
 | ||||||
|  | public interface I18nSupport { | ||||||
|  | 
 | ||||||
|  |     Collection<Locale> supportedLanguages(); | ||||||
|  | 
 | ||||||
|  |     /** Get the current Locale either form a user if this is called from a logged in user context or the | ||||||
|  |      * applications default locale. | ||||||
|  |      * | ||||||
|  |      * @return the current Locale to use in context */ | ||||||
|  |     Locale getCurrentLocale(); | ||||||
|  | 
 | ||||||
|  |     void setSessionLocale(Locale locale); | ||||||
|  | 
 | ||||||
|  |     /** Format a DateTime to a text format to display. | ||||||
|  |      * | ||||||
|  |      * @param date | ||||||
|  |      * @return */ | ||||||
|  |     String formatDisplayDate(DateTime date); | ||||||
|  | 
 | ||||||
|  |     /** Get localized text of specified key for currently set Locale. | ||||||
|  |      * | ||||||
|  |      * @param key the key name of localized text | ||||||
|  |      * @param args additional arguments to parse the localized text | ||||||
|  |      * @return the text in current language parsed from localized text */ | ||||||
|  |     String getText(String key, Object... args); | ||||||
|  | 
 | ||||||
|  |     /** Get localized text of specified key for currently set Locale. | ||||||
|  |      * | ||||||
|  |      * @param key LocTextKey instance | ||||||
|  |      * @return the text in current language parsed from localized text */ | ||||||
|  |     String getText(LocTextKey key); | ||||||
|  | 
 | ||||||
|  |     /** Get localized text of specified key for currently set Locale. | ||||||
|  |      * | ||||||
|  |      * @param key the key name of localized text | ||||||
|  |      * @param def default text that is returned if no localized test with specified key was found | ||||||
|  |      * @param args additional arguments to parse the localized text | ||||||
|  |      * @return the text in current language parsed from localized text */ | ||||||
|  |     String getText(final String key, String def, Object... args); | ||||||
|  | 
 | ||||||
|  |     /** Get localized text of specified key and Locale. | ||||||
|  |      * | ||||||
|  |      * @param key the key name of localized text | ||||||
|  |      * @param locale the Locale | ||||||
|  |      * @param args additional arguments to parse the localized text | ||||||
|  |      * @return the text in current language parsed from localized text */ | ||||||
|  |     String getText(String key, Locale locale, Object... args); | ||||||
|  | 
 | ||||||
|  |     /** Get localized text of specified key and Locale. | ||||||
|  |      * | ||||||
|  |      * @param key the key name of localized text | ||||||
|  |      * @param locale the Locale | ||||||
|  |      * @param def default text that is returned if no localized test with specified key was found | ||||||
|  |      * @param args additional arguments to parse the localized text | ||||||
|  |      * @return the text in current language parsed from localized text */ | ||||||
|  |     String getText(String key, Locale locale, String def, Object... args); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,58 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.i18n; | ||||||
|  | 
 | ||||||
|  | import java.util.Arrays; | ||||||
|  | 
 | ||||||
|  | public class LocTextKey { | ||||||
|  | 
 | ||||||
|  |     public final String name; | ||||||
|  |     public final Object[] args; | ||||||
|  | 
 | ||||||
|  |     public LocTextKey(final String name) { | ||||||
|  |         this.name = name; | ||||||
|  |         this.args = null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public LocTextKey(final String name, final Object... args) { | ||||||
|  |         this.name = name; | ||||||
|  |         this.args = args; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public int hashCode() { | ||||||
|  |         final int prime = 31; | ||||||
|  |         int result = 1; | ||||||
|  |         result = prime * result + ((this.name == null) ? 0 : this.name.hashCode()); | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean equals(final Object obj) { | ||||||
|  |         if (this == obj) | ||||||
|  |             return true; | ||||||
|  |         if (obj == null) | ||||||
|  |             return false; | ||||||
|  |         if (getClass() != obj.getClass()) | ||||||
|  |             return false; | ||||||
|  |         final LocTextKey other = (LocTextKey) obj; | ||||||
|  |         if (this.name == null) { | ||||||
|  |             if (other.name != null) | ||||||
|  |                 return false; | ||||||
|  |         } else if (!this.name.equals(other.name)) | ||||||
|  |             return false; | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public String toString() { | ||||||
|  |         return "LocTextKey [name=" + this.name + ", args=" + Arrays.toString(this.args) + "]"; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,38 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.i18n; | ||||||
|  | 
 | ||||||
|  | import java.util.Locale; | ||||||
|  | 
 | ||||||
|  | import org.eclipse.swt.widgets.Composite; | ||||||
|  | 
 | ||||||
|  | public interface PolyglotPageService { | ||||||
|  | 
 | ||||||
|  |     String POLYGLOT_WIDGET_FUNCTION_KEY = "POLYGLOT_WIDGET_FUNCTION"; | ||||||
|  |     String POLYGLOT_TREE_ITEM_TEXT_DATA_KEY = "POLYGLOT_TREE_ITEM_TEXT_DATA"; | ||||||
|  | 
 | ||||||
|  |     /** Gets the underling I18nSupport | ||||||
|  |      *  | ||||||
|  |      * @return the underling I18nSupport */ | ||||||
|  |     I18nSupport getI18nSupport(); | ||||||
|  | 
 | ||||||
|  |     /** The default locale for the page. | ||||||
|  |      * Uses I18nSupport.getCurrentLocale to do so. | ||||||
|  |      *  | ||||||
|  |      * @param root the root Composite of the page to change the language */ | ||||||
|  |     void setDefaultPageLocale(Composite root); | ||||||
|  | 
 | ||||||
|  |     /** Sets the given Locale and if needed, updates the page language according to the | ||||||
|  |      * given Locale | ||||||
|  |      *  | ||||||
|  |      * @param root root the root Composite of the page to change the language | ||||||
|  |      * @param locale the Locale to set */ | ||||||
|  |     void setPageLocale(Composite root, Locale locale); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,131 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.i18n.impl; | ||||||
|  | 
 | ||||||
|  | import java.util.Arrays; | ||||||
|  | import java.util.Collection; | ||||||
|  | import java.util.Locale; | ||||||
|  | 
 | ||||||
|  | import org.eclipse.rap.rwt.RWT; | ||||||
|  | import org.joda.time.DateTime; | ||||||
|  | import org.joda.time.format.DateTimeFormat; | ||||||
|  | import org.joda.time.format.DateTimeFormatter; | ||||||
|  | import org.slf4j.Logger; | ||||||
|  | import org.slf4j.LoggerFactory; | ||||||
|  | import org.springframework.beans.factory.annotation.Value; | ||||||
|  | import org.springframework.context.MessageSource; | ||||||
|  | import org.springframework.context.annotation.Lazy; | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; | ||||||
|  | 
 | ||||||
|  | @Lazy | ||||||
|  | @Component | ||||||
|  | public class I18nSupportImpl implements I18nSupport { | ||||||
|  | 
 | ||||||
|  |     private static final Logger log = LoggerFactory.getLogger(I18nSupportImpl.class); | ||||||
|  | 
 | ||||||
|  |     public static final String EMPTY_DISPLAY_VALUE = "--"; | ||||||
|  |     private static final String ATTR_CURRENT_SESSION_LOCALE = "CURRENT_SESSION_LOCALE"; | ||||||
|  | 
 | ||||||
|  |     private final DateTimeFormatter displayDateFormatter; | ||||||
|  |     private final CurrentUser currentUser; | ||||||
|  |     private final MessageSource messageSource; | ||||||
|  |     private final Locale defaultLocale = Locale.ENGLISH; | ||||||
|  | 
 | ||||||
|  |     public I18nSupportImpl( | ||||||
|  |             final CurrentUser currentUser, | ||||||
|  |             final MessageSource messageSource, | ||||||
|  |             @Value("${sebserver.gui.date.displayformat}") final String displayDateFormat) { | ||||||
|  | 
 | ||||||
|  |         this.currentUser = currentUser; | ||||||
|  |         this.messageSource = messageSource; | ||||||
|  |         this.displayDateFormatter = DateTimeFormat | ||||||
|  |                 .forPattern(displayDateFormat) | ||||||
|  |                 .withZoneUTC(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private static final Collection<Locale> SUPPORTED = Arrays.asList(Locale.ENGLISH, Locale.GERMANY); | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public Collection<Locale> supportedLanguages() { | ||||||
|  |         return SUPPORTED; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void setSessionLocale(final Locale locale) { | ||||||
|  |         try { | ||||||
|  |             RWT.getUISession() | ||||||
|  |                     .getHttpSession() | ||||||
|  |                     .setAttribute(ATTR_CURRENT_SESSION_LOCALE, locale); | ||||||
|  |             RWT.setLocale(locale); | ||||||
|  |         } catch (final IllegalStateException e) { | ||||||
|  |             log.error("Set current locale for session failed: ", e); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public Locale getCurrentLocale() { | ||||||
|  |         // first session-locale if available | ||||||
|  |         try { | ||||||
|  |             final Locale sessionLocale = (Locale) RWT.getUISession() | ||||||
|  |                     .getHttpSession() | ||||||
|  |                     .getAttribute(ATTR_CURRENT_SESSION_LOCALE); | ||||||
|  |             if (sessionLocale != null) { | ||||||
|  |                 return sessionLocale; | ||||||
|  |             } | ||||||
|  |         } catch (final IllegalStateException e) { | ||||||
|  |             log.warn("Get current locale for session failed: {}", e.getMessage()); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // second user-locale if available | ||||||
|  |         if (this.currentUser.isAvailable()) { | ||||||
|  |             return this.currentUser.get().locale; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // last the default locale | ||||||
|  |         return this.defaultLocale; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public String formatDisplayDate(final DateTime date) { | ||||||
|  |         if (date == null) { | ||||||
|  |             return EMPTY_DISPLAY_VALUE; | ||||||
|  |         } | ||||||
|  |         return date.toString(this.displayDateFormatter); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public String getText(final LocTextKey key) { | ||||||
|  |         return getText(key.name, key.args); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public String getText(final String key, final Object... args) { | ||||||
|  |         return getText(key, key, args); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public String getText(final String key, final String def, final Object... args) { | ||||||
|  |         return this.messageSource.getMessage(key, args, def, this.getCurrentLocale()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public String getText(final String key, final Locale locale, final Object... args) { | ||||||
|  |         return getText(key, locale, key, args); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public String getText(final String key, final Locale locale, final String def, final Object... args) { | ||||||
|  |         return this.messageSource.getMessage(key, args, def, locale); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,58 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.i18n.impl; | ||||||
|  | 
 | ||||||
|  | import java.util.Locale; | ||||||
|  | import java.util.function.Consumer; | ||||||
|  | 
 | ||||||
|  | import org.eclipse.swt.widgets.Composite; | ||||||
|  | import org.eclipse.swt.widgets.Control; | ||||||
|  | import org.springframework.context.annotation.Lazy; | ||||||
|  | import org.springframework.stereotype.Service; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.ComposerService; | ||||||
|  | 
 | ||||||
|  | /** Service that supports page language change on the fly */ | ||||||
|  | @Lazy | ||||||
|  | @Service | ||||||
|  | @GuiProfile | ||||||
|  | public final class PolyglotPageServiceImpl implements PolyglotPageService { | ||||||
|  | 
 | ||||||
|  |     private final I18nSupport i18nSupport; | ||||||
|  | 
 | ||||||
|  |     public PolyglotPageServiceImpl(final I18nSupport i18nSupport) { | ||||||
|  |         this.i18nSupport = i18nSupport; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public I18nSupport getI18nSupport() { | ||||||
|  |         return this.i18nSupport; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void setDefaultPageLocale(final Composite root) { | ||||||
|  |         setPageLocale(root, this.i18nSupport.getCurrentLocale()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     @SuppressWarnings("unchecked") | ||||||
|  |     public void setPageLocale(final Composite root, final Locale locale) { | ||||||
|  |         this.i18nSupport.setSessionLocale(locale); | ||||||
|  |         ComposerService.traversePageTree( | ||||||
|  |                 root, | ||||||
|  |                 comp -> comp.getData(POLYGLOT_WIDGET_FUNCTION_KEY) != null, | ||||||
|  |                 comp -> ((Consumer<Control>) comp.getData(POLYGLOT_WIDGET_FUNCTION_KEY)).accept(comp)); | ||||||
|  | 
 | ||||||
|  |         root.layout(true, true); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,66 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.page; | ||||||
|  | 
 | ||||||
|  | import java.util.function.Consumer; | ||||||
|  | import java.util.function.Predicate; | ||||||
|  | 
 | ||||||
|  | import org.eclipse.swt.widgets.Composite; | ||||||
|  | import org.eclipse.swt.widgets.Control; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gui.RAPConfiguration.EntryPointService; | ||||||
|  | 
 | ||||||
|  | public interface ComposerService extends EntryPointService { | ||||||
|  | 
 | ||||||
|  |     boolean validate(String composerName, PageContext pageContext); | ||||||
|  | 
 | ||||||
|  |     PageDefinition mainPage(); | ||||||
|  | 
 | ||||||
|  |     PageDefinition loginPage(); | ||||||
|  | 
 | ||||||
|  |     void compose( | ||||||
|  |             String composerName, | ||||||
|  |             PageContext pageContext); | ||||||
|  | 
 | ||||||
|  |     void compose( | ||||||
|  |             Class<? extends TemplateComposer> composerType, | ||||||
|  |             PageContext pageContext); | ||||||
|  | 
 | ||||||
|  |     void composePage( | ||||||
|  |             Class<? extends PageDefinition> pageType, | ||||||
|  |             Composite root); | ||||||
|  | 
 | ||||||
|  |     void composePage( | ||||||
|  |             PageDefinition pageDefinition, | ||||||
|  |             Composite root); | ||||||
|  | 
 | ||||||
|  |     static void traversePageTree( | ||||||
|  |             final Composite root, | ||||||
|  |             final Predicate<Control> predicate, | ||||||
|  |             final Consumer<Control> f) { | ||||||
|  | 
 | ||||||
|  |         if (predicate.test(root)) { | ||||||
|  |             f.accept(root); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         final Control[] children = root.getChildren(); | ||||||
|  |         if (children != null) { | ||||||
|  |             for (final Control control : children) { | ||||||
|  |                 if (!(control instanceof Composite)) { | ||||||
|  |                     if (predicate.test(control)) { | ||||||
|  |                         f.accept(control); | ||||||
|  |                     } | ||||||
|  |                 } else { | ||||||
|  |                     traversePageTree((Composite) control, predicate, f); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,128 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.page; | ||||||
|  | 
 | ||||||
|  | import org.eclipse.swt.widgets.Composite; | ||||||
|  | import org.eclipse.swt.widgets.Shell; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.event.PageEvent; | ||||||
|  | 
 | ||||||
|  | public interface PageContext { | ||||||
|  | 
 | ||||||
|  |     public static final class PageAttr { | ||||||
|  | 
 | ||||||
|  |         public final String name; | ||||||
|  |         public final String value; | ||||||
|  | 
 | ||||||
|  |         public PageAttr(final String name, final String value) { | ||||||
|  |             this.name = name; | ||||||
|  |             this.value = value; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public interface AttributeKeys { | ||||||
|  | 
 | ||||||
|  |         public static final String ATTR_PAGE_TEMPLATE_COMPOSER_NAME = "ATTR_PAGE_TEMPLATE_COMPOSER_NAME"; | ||||||
|  | 
 | ||||||
|  |         public static final String INSTITUTION_ID = "INSTITUTION_ID"; | ||||||
|  | 
 | ||||||
|  | //        public static final String USER_NAME = "USER_NAME"; | ||||||
|  | //        public static final String PASSWORD = "PASSWORD"; | ||||||
|  | // | ||||||
|  | 
 | ||||||
|  | // | ||||||
|  | //        public static final String CONFIG_ID = "CONFIG_ID"; | ||||||
|  | //        public static final String CONFIG_VIEW_NAME = "CONFIG_VIEW_NAME"; | ||||||
|  | //        public static final String CONFIG_ATTRIBUTE_SAVE_TYPE = "CONFIG_ATTRIBUTE_SAVE_TYPE"; | ||||||
|  | //        public static final String CONFIG_ATTRIBUTE_VALUE = "CONFIG_ATTRIBUTE_VALUE"; | ||||||
|  | // | ||||||
|  | //        public static final String EXAM_ID = "EXAM_ID"; | ||||||
|  | //        public static final String STATE_NAME = "STATE_NAME"; | ||||||
|  | // | ||||||
|  | //        public static final String AUTHORIZATION_CONTEXT = "AUTHORIZATION_CONTEXT"; | ||||||
|  | //        public static final String AUTHORIZATION_HEADER = "AUTHORIZATION_HEADER"; | ||||||
|  |         public static final String AUTHORIZATION_FAILURE = "AUTHORIZATION_FAILURE"; | ||||||
|  |         public static final String LGOUT_SUCCESS = "LGOUT_SUCCESS"; | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ComposerService composerService(); | ||||||
|  | 
 | ||||||
|  |     Shell getShell(); | ||||||
|  | 
 | ||||||
|  |     /** Get the page root Component. | ||||||
|  |      * | ||||||
|  |      * @return the page root Component. */ | ||||||
|  |     Composite getRoot(); | ||||||
|  | 
 | ||||||
|  |     /** Get the Component that is currently set as parent during page tree compose | ||||||
|  |      * | ||||||
|  |      * @return the parent Component */ | ||||||
|  |     Composite getParent(); | ||||||
|  | 
 | ||||||
|  |     /** Create a copy of this PageContext with a new parent Composite. | ||||||
|  |      * | ||||||
|  |      * @param parent the new parent Composite | ||||||
|  |      * @return a copy of this PageContext with a new parent Composite. */ | ||||||
|  |     PageContext copyOf(Composite parent); | ||||||
|  | 
 | ||||||
|  |     /** Create a copy of this PageContext with and additionally page context attributes. | ||||||
|  |      * The additionally page context attributes will get merged with them already defined | ||||||
|  |      * | ||||||
|  |      * @param attributes additionally page context attributes. | ||||||
|  |      * @return a copy of this PageContext with with and additionally page context attributes. */ | ||||||
|  |     PageContext copyOfAttributes(PageContext otherContext); | ||||||
|  | 
 | ||||||
|  |     /** Adds the specified attribute to the existing page context attributes. | ||||||
|  |      * | ||||||
|  |      * @param key the key of the attribute | ||||||
|  |      * @param value the value of the attribute | ||||||
|  |      * @return this PageContext instance (builder pattern) */ | ||||||
|  |     PageContext withAttr(String key, String value); | ||||||
|  | 
 | ||||||
|  |     String getAttribute(String name); | ||||||
|  | 
 | ||||||
|  |     String getAttribute(String name, String def); | ||||||
|  | 
 | ||||||
|  |     boolean hasAttribute(String name); | ||||||
|  | 
 | ||||||
|  |     /** Publishes a given PageEvent to the current page tree | ||||||
|  |      * This goes through the page-tree and collects all listeners the are listen to | ||||||
|  |      * the specified page event type. | ||||||
|  |      * | ||||||
|  |      * @param event the concrete PageEvent instance */ | ||||||
|  |     <T extends PageEvent> void publishPageEvent(T event); | ||||||
|  | 
 | ||||||
|  |     /** Apply a confirm dialog with a specified confirm message and a callback code | ||||||
|  |      * block that will be executed on users OK selection. | ||||||
|  |      * | ||||||
|  |      * @param confirmMessage | ||||||
|  |      * @param onOK callback code block that will be executed on users OK selection */ | ||||||
|  |     void applyConfirmDialog(String confirmMessage, Runnable onOK); | ||||||
|  | 
 | ||||||
|  |     void forwardToPage( | ||||||
|  |             PageDefinition pageDefinition, | ||||||
|  |             PageContext pageContext); | ||||||
|  | 
 | ||||||
|  |     void forwardToMainPage(PageContext pageContext); | ||||||
|  | 
 | ||||||
|  |     void forwardToLoginPage(PageContext pageContext); | ||||||
|  | 
 | ||||||
|  |     /** Notify an error dialog to the user with specified error message and | ||||||
|  |      * optional exception instance | ||||||
|  |      * | ||||||
|  |      * @param errorMessage the error message to display | ||||||
|  |      * @param error the error as Throwable */ | ||||||
|  |     void notifyError(String errorMessage, Throwable error); | ||||||
|  | 
 | ||||||
|  |     void notifyError(Throwable error); | ||||||
|  | 
 | ||||||
|  |     <T> T logoutOnError(Throwable error); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,16 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.page; | ||||||
|  | 
 | ||||||
|  | public interface PageDefinition { | ||||||
|  | 
 | ||||||
|  |     Class<? extends TemplateComposer> composer(); | ||||||
|  | 
 | ||||||
|  |     PageContext applyPageContext(PageContext pageContext); | ||||||
|  | } | ||||||
|  | @ -0,0 +1,25 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.page; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.event.PageEvent; | ||||||
|  | 
 | ||||||
|  | public interface PageEventListener<T extends PageEvent> { | ||||||
|  | 
 | ||||||
|  |     String LISTENER_ATTRIBUTE_KEY = "PageEventListener"; | ||||||
|  | 
 | ||||||
|  |     boolean match(Class<? extends PageEvent> eventType); | ||||||
|  | 
 | ||||||
|  |     default int priority() { | ||||||
|  |         return 1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void notify(T event); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,17 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.page; | ||||||
|  | 
 | ||||||
|  | import org.eclipse.swt.widgets.Event; | ||||||
|  | 
 | ||||||
|  | public interface PopupMenuComposer { | ||||||
|  | 
 | ||||||
|  |     void onMenuEvent(final Event event); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,19 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.page; | ||||||
|  | 
 | ||||||
|  | public interface TemplateComposer { | ||||||
|  | 
 | ||||||
|  |     default boolean validate(final PageContext context) { | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void compose(PageContext composerCtx); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,77 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.page.action; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory.IconButtonType; | ||||||
|  | 
 | ||||||
|  | public enum ActionDefinition { | ||||||
|  | 
 | ||||||
|  |     INSTITUTION_NEW( | ||||||
|  |             "actions.new.institution", | ||||||
|  |             IconButtonType.NEW_ACTION), | ||||||
|  | 
 | ||||||
|  |     INSTITUTION_MODIFY( | ||||||
|  |             "actions.modify.institution", | ||||||
|  |             IconButtonType.SAVE_ACTION), | ||||||
|  | 
 | ||||||
|  |     INSTITUTION_DELETE( | ||||||
|  |             "actions.delete.institution", | ||||||
|  |             IconButtonType.DELETE_ACTION), | ||||||
|  | 
 | ||||||
|  |     LMS_SETUP_NEW( | ||||||
|  |             "New LMS Setup", | ||||||
|  |             IconButtonType.NEW_ACTION), | ||||||
|  | 
 | ||||||
|  |     LMS_SETUP_MODIFY( | ||||||
|  |             "Save LMS Setup", | ||||||
|  |             IconButtonType.SAVE_ACTION), | ||||||
|  | 
 | ||||||
|  |     LMS_SETUP_DELETE( | ||||||
|  |             "Delete LMS Setup", | ||||||
|  |             IconButtonType.DELETE_ACTION), | ||||||
|  | 
 | ||||||
|  |     LMS_SETUP_TEST( | ||||||
|  |             "Test LMS Setup", | ||||||
|  |             IconButtonType.SAVE_ACTION), | ||||||
|  | 
 | ||||||
|  |     SEB_CONFIG_NEW( | ||||||
|  |             "New Configuration", | ||||||
|  |             IconButtonType.NEW_ACTION), | ||||||
|  | 
 | ||||||
|  |     SEB_CONFIG_MODIFY( | ||||||
|  |             "Save Configuration", | ||||||
|  |             IconButtonType.SAVE_ACTION), | ||||||
|  | 
 | ||||||
|  |     SEB_CONFIG_DELETE( | ||||||
|  |             "Delete Configuration", | ||||||
|  |             IconButtonType.DELETE_ACTION), | ||||||
|  | 
 | ||||||
|  |     EXAM_IMPORT( | ||||||
|  |             "Import Exam", | ||||||
|  |             IconButtonType.SAVE_ACTION), | ||||||
|  | 
 | ||||||
|  |     EXAM_EDIT( | ||||||
|  |             "Edit Selected Exam", | ||||||
|  |             IconButtonType.NEW_ACTION), | ||||||
|  | 
 | ||||||
|  |     EXAM_DELETE( | ||||||
|  |             "Delete Selected Exam", | ||||||
|  |             IconButtonType.DELETE_ACTION), | ||||||
|  | 
 | ||||||
|  |     ; | ||||||
|  | 
 | ||||||
|  |     public final String name; | ||||||
|  |     public final IconButtonType icon; | ||||||
|  | 
 | ||||||
|  |     private ActionDefinition(final String name, final IconButtonType icon) { | ||||||
|  |         this.name = name; | ||||||
|  |         this.icon = icon; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,96 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.page.action; | ||||||
|  | 
 | ||||||
|  | import org.eclipse.rap.rwt.RWT; | ||||||
|  | import org.eclipse.rap.rwt.template.ImageCell; | ||||||
|  | import org.eclipse.rap.rwt.template.Template; | ||||||
|  | import org.eclipse.rap.rwt.template.TextCell; | ||||||
|  | import org.eclipse.swt.SWT; | ||||||
|  | import org.eclipse.swt.layout.GridData; | ||||||
|  | import org.eclipse.swt.widgets.Label; | ||||||
|  | import org.eclipse.swt.widgets.Tree; | ||||||
|  | import org.eclipse.swt.widgets.TreeItem; | ||||||
|  | import org.springframework.context.annotation.Lazy; | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageContext; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageEventListener; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.event.ActionPublishEvent; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.event.ActionPublishEventListener; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory; | ||||||
|  | 
 | ||||||
|  | @Lazy | ||||||
|  | @Component | ||||||
|  | public class ActionPane implements TemplateComposer { | ||||||
|  | 
 | ||||||
|  |     private static final String ACTION_EVENT_CALL_KEY = "ACTION_EVENT_CALL"; | ||||||
|  | 
 | ||||||
|  |     private final WidgetFactory widgetFactory; | ||||||
|  | 
 | ||||||
|  |     public ActionPane(final WidgetFactory widgetFactory) { | ||||||
|  |         super(); | ||||||
|  |         this.widgetFactory = widgetFactory; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void compose(final PageContext composerCtx) { | ||||||
|  | 
 | ||||||
|  |         final Label label = this.widgetFactory.labelLocalized( | ||||||
|  |                 composerCtx.getParent(), | ||||||
|  |                 "h3", | ||||||
|  |                 new LocTextKey("sebserver.actionpane.title")); | ||||||
|  |         final GridData titleLayout = new GridData(SWT.FILL, SWT.TOP, true, false); | ||||||
|  |         titleLayout.verticalIndent = 10; | ||||||
|  |         titleLayout.horizontalIndent = 10; | ||||||
|  |         label.setLayoutData(titleLayout); | ||||||
|  | 
 | ||||||
|  |         final Tree actions = this.widgetFactory.treeLocalized(composerCtx.getParent(), SWT.SINGLE | SWT.FULL_SELECTION); | ||||||
|  |         actions.setData(RWT.CUSTOM_VARIANT, "actions"); | ||||||
|  |         final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true); | ||||||
|  |         actions.setLayoutData(gridData); | ||||||
|  |         final Template template = new Template(); | ||||||
|  |         final ImageCell imageCell = new ImageCell(template); | ||||||
|  |         imageCell.setLeft(0, 0).setWidth(40).setTop(0).setBottom(0, 0).setHorizontalAlignment(SWT.LEFT); | ||||||
|  |         imageCell.setBindingIndex(0); | ||||||
|  |         final TextCell textCell = new TextCell(template); | ||||||
|  |         textCell.setLeft(0, 30).setWidth(150).setTop(7).setBottom(0, 0).setHorizontalAlignment(SWT.LEFT); | ||||||
|  |         textCell.setBindingIndex(0); | ||||||
|  |         actions.setData(RWT.ROW_TEMPLATE, template); | ||||||
|  | 
 | ||||||
|  |         actions.addListener(SWT.Selection, event -> { | ||||||
|  |             final TreeItem treeItem = (TreeItem) event.item; | ||||||
|  | 
 | ||||||
|  |             final Runnable action = (Runnable) treeItem.getData(ACTION_EVENT_CALL_KEY); | ||||||
|  |             action.run(); | ||||||
|  | 
 | ||||||
|  |             if (!treeItem.isDisposed()) { | ||||||
|  |                 treeItem.getParent().deselectAll(); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         actions.setData( | ||||||
|  |                 PageEventListener.LISTENER_ATTRIBUTE_KEY, | ||||||
|  |                 new ActionPublishEventListener() { | ||||||
|  |                     @Override | ||||||
|  |                     public void notify(final ActionPublishEvent event) { | ||||||
|  |                         final TreeItem actionItem = ActionPane.this.widgetFactory.treeItemLocalized( | ||||||
|  |                                 actions, | ||||||
|  |                                 event.actionDefinition.name); | ||||||
|  |                         actionItem.setImage(event.actionDefinition.icon.getImage(composerCtx.getParent().getDisplay())); | ||||||
|  |                         actionItem.setData(ACTION_EVENT_CALL_KEY, | ||||||
|  |                                 new SafeActionExecution(composerCtx, event, event.run)); | ||||||
|  |                     } | ||||||
|  |                 }); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,41 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.page.action; | ||||||
|  | 
 | ||||||
|  | public interface InstitutionActions { | ||||||
|  | 
 | ||||||
|  | //    /** Use this higher-order function to create a new Institution action Runnable. | ||||||
|  | //     * | ||||||
|  | //     * @return */ | ||||||
|  | //    static Runnable newInstitution(final PageContext composerCtx, final RestServices restServices) { | ||||||
|  | //        return () -> { | ||||||
|  | //            final IdAndName newInstitutionId = restServices | ||||||
|  | //                    .sebServerAPICall(NewInstitution.class) | ||||||
|  | //                    .doAPICall() | ||||||
|  | //                    .onErrorThrow("Unexpected Error"); | ||||||
|  | //            composerCtx.notify(new ActionEvent(ActionDefinition.INSTITUTION_NEW, newInstitutionId)); | ||||||
|  | //        }; | ||||||
|  | //    } | ||||||
|  | // | ||||||
|  | //    /** Use this higher-order function to create a delete Institution action Runnable. | ||||||
|  | //     * | ||||||
|  | //     * @return */ | ||||||
|  | //    static Runnable deleteInstitution(final PageContext composerCtx, final RestServices restServices, | ||||||
|  | //            final String instId) { | ||||||
|  | //        return () -> { | ||||||
|  | //            restServices | ||||||
|  | //                    .sebServerAPICall(DeleteInstitution.class) | ||||||
|  | //                    .attribute(AttributeKeys.INSTITUTION_ID, instId) | ||||||
|  | //                    .doAPICall() | ||||||
|  | //                    .onErrorThrow("Unexpected Error"); | ||||||
|  | //            composerCtx.notify(new ActionEvent(ActionDefinition.INSTITUTION_DELETE, instId)); | ||||||
|  | //        }; | ||||||
|  | //    } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,68 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.page.action; | ||||||
|  | 
 | ||||||
|  | import org.apache.commons.lang3.StringUtils; | ||||||
|  | import org.slf4j.Logger; | ||||||
|  | import org.slf4j.LoggerFactory; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageContext; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.event.ActionPublishEvent; | ||||||
|  | 
 | ||||||
|  | public class SafeActionExecution implements Runnable { | ||||||
|  | 
 | ||||||
|  |     private static final Logger log = LoggerFactory.getLogger(SafeActionExecution.class); | ||||||
|  | 
 | ||||||
|  |     private final PageContext pageContext; | ||||||
|  |     private final ActionPublishEvent actionEvent; | ||||||
|  |     private final Runnable actionExecution; | ||||||
|  | 
 | ||||||
|  |     public SafeActionExecution( | ||||||
|  |             final PageContext pageContext, | ||||||
|  |             final ActionPublishEvent actionEvent, | ||||||
|  |             final Runnable actionExecution) { | ||||||
|  | 
 | ||||||
|  |         this.pageContext = pageContext; | ||||||
|  |         this.actionEvent = actionEvent; | ||||||
|  |         this.actionExecution = actionExecution; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void run() { | ||||||
|  |         try { | ||||||
|  |             if (StringUtils.isNotBlank(this.actionEvent.confirmationMessage)) { | ||||||
|  |                 this.pageContext.applyConfirmDialog( | ||||||
|  |                         this.actionEvent.confirmationMessage, | ||||||
|  |                         createConfirmationCallback()); | ||||||
|  |             } else { | ||||||
|  |                 this.actionExecution.run(); | ||||||
|  |             } | ||||||
|  |         } catch (final Throwable t) { | ||||||
|  |             log.error("Failed to execute action: {}", this.actionEvent, t); | ||||||
|  |             this.pageContext.notifyError("action.error.unexpected.message", t); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private final Runnable createConfirmationCallback() { | ||||||
|  |         return new Runnable() { | ||||||
|  | 
 | ||||||
|  |             @Override | ||||||
|  |             public void run() { | ||||||
|  |                 try { | ||||||
|  |                     SafeActionExecution.this.actionExecution.run(); | ||||||
|  |                 } catch (final Throwable t) { | ||||||
|  |                     log.error("Failed to execute action: {}", SafeActionExecution.this.actionEvent, t); | ||||||
|  |                     SafeActionExecution.this.pageContext.notifyError("action.error.unexpected.message", t); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,281 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.page.activity; | ||||||
|  | 
 | ||||||
|  | import java.util.Collection; | ||||||
|  | import java.util.Collections; | ||||||
|  | import java.util.EnumMap; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
|  | 
 | ||||||
|  | import org.eclipse.swt.SWT; | ||||||
|  | import org.eclipse.swt.layout.GridData; | ||||||
|  | import org.eclipse.swt.widgets.Event; | ||||||
|  | import org.eclipse.swt.widgets.Label; | ||||||
|  | import org.eclipse.swt.widgets.Tree; | ||||||
|  | import org.eclipse.swt.widgets.TreeItem; | ||||||
|  | import org.springframework.context.annotation.Lazy; | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gbl.model.EntityName; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.model.user.UserRole; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageContext; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageEventListener; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.action.ActionDefinition; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.activity.ActivitySelection.Activity; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.event.ActionEventListener; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.event.ActivitySelectionEvent; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.impl.MainPageState; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitutionNames; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory; | ||||||
|  | 
 | ||||||
|  | @Lazy | ||||||
|  | @Component | ||||||
|  | public class ActivitiesPane implements TemplateComposer { | ||||||
|  | 
 | ||||||
|  |     private final WidgetFactory widgetFactory; | ||||||
|  |     private final RestService restService; | ||||||
|  |     private final AuthorizationContextHolder authorizationContextHolder; | ||||||
|  | 
 | ||||||
|  |     private final Map<ActionDefinition, ActivityActionHandler> activityActionHandler = | ||||||
|  |             new EnumMap<>(ActionDefinition.class); | ||||||
|  | 
 | ||||||
|  |     public ActivitiesPane( | ||||||
|  |             final WidgetFactory widgetFactory, | ||||||
|  |             final RestService restService, | ||||||
|  |             final AuthorizationContextHolder authorizationContextHolder, | ||||||
|  |             final Collection<ActivityActionHandler> activityActionHandler) { | ||||||
|  | 
 | ||||||
|  |         this.widgetFactory = widgetFactory; | ||||||
|  |         this.restService = restService; | ||||||
|  |         this.authorizationContextHolder = authorizationContextHolder; | ||||||
|  | 
 | ||||||
|  |         for (final ActivityActionHandler aah : activityActionHandler) { | ||||||
|  |             this.activityActionHandler.put(aah.handlesAction(), aah); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void compose(final PageContext pageContext) { | ||||||
|  |         final UserInfo userInfo = this.authorizationContextHolder | ||||||
|  |                 .getAuthorizationContext() | ||||||
|  |                 .getLoggedInUser() | ||||||
|  |                 .get(pageContext::logoutOnError); | ||||||
|  | 
 | ||||||
|  |         final Label activities = this.widgetFactory.labelLocalized( | ||||||
|  |                 pageContext.getParent(), | ||||||
|  |                 "h3", | ||||||
|  |                 new LocTextKey("sebserver.activitiespane.title")); | ||||||
|  |         final GridData activitiesGridData = new GridData(SWT.FILL, SWT.TOP, true, false); | ||||||
|  |         activitiesGridData.horizontalIndent = 20; | ||||||
|  |         activities.setLayoutData(activitiesGridData); | ||||||
|  | 
 | ||||||
|  |         final Tree navigation = | ||||||
|  |                 this.widgetFactory.treeLocalized(pageContext.getParent(), SWT.SINGLE | SWT.FULL_SELECTION); | ||||||
|  |         final GridData navigationGridData = new GridData(SWT.FILL, SWT.FILL, true, true); | ||||||
|  |         navigationGridData.horizontalIndent = 10; | ||||||
|  |         navigation.setLayoutData(navigationGridData); | ||||||
|  | 
 | ||||||
|  |         final List<EntityName> insitutionNames = this.restService | ||||||
|  |                 .getBuilder(GetInstitutionNames.class) | ||||||
|  |                 .call() | ||||||
|  |                 .get(pageContext::notifyError, () -> Collections.emptyList()); | ||||||
|  | 
 | ||||||
|  |         if (userInfo.hasRole(UserRole.SEB_SERVER_ADMIN)) { | ||||||
|  |             // institutions (list) as root | ||||||
|  |             final TreeItem institutions = this.widgetFactory.treeItemLocalized( | ||||||
|  |                     navigation, | ||||||
|  |                     Activity.INSTITUTION_ROOT.title); | ||||||
|  |             ActivitySelection.inject(institutions, Activity.INSTITUTION_ROOT.createSelection()); | ||||||
|  | 
 | ||||||
|  |             for (final EntityName inst : insitutionNames) { | ||||||
|  |                 createInstitutionItem(institutions, inst); | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             final EntityName inst = insitutionNames.iterator().next(); | ||||||
|  |             createInstitutionItem(navigation, inst); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  | //        final TreeItem user = this.widgetFactory.treeItemLocalized( | ||||||
|  | //                navigation, | ||||||
|  | //                "org.sebserver.activities.user"); | ||||||
|  | //        ActivitySelection.set(user, Activity.USERS.createSelection()); | ||||||
|  | // | ||||||
|  | //        final TreeItem configs = this.widgetFactory.treeItemLocalized( | ||||||
|  | //                navigation, | ||||||
|  | //                "org.sebserver.activities.sebconfigs"); | ||||||
|  | //        ActivitySelection.set(configs, Activity.SEB_CONFIGS.createSelection()); | ||||||
|  | // | ||||||
|  | //        final TreeItem config = this.widgetFactory.treeItemLocalized( | ||||||
|  | //                configs, | ||||||
|  | //                "org.sebserver.activities.sebconfig"); | ||||||
|  | //        ActivitySelection.set(config, Activity.SEB_CONFIG.createSelection()); | ||||||
|  | // | ||||||
|  | //        final TreeItem configTemplates = this.widgetFactory.treeItemLocalized( | ||||||
|  | //                configs, | ||||||
|  | //                "org.sebserver.activities.sebconfig.templates"); | ||||||
|  | //        ActivitySelection.set(configTemplates, Activity.SEB_CONFIG_TEMPLATES.createSelection()); | ||||||
|  | // | ||||||
|  | //        final TreeItem exams = this.widgetFactory.treeItemLocalized( | ||||||
|  | //                navigation, | ||||||
|  | //                "org.sebserver.activities.exam"); | ||||||
|  | //        ActivitySelection.set(exams, Activity.EXAMS.createSelection()); | ||||||
|  | // | ||||||
|  | //        final TreeItem monitoring = this.widgetFactory.treeItemLocalized( | ||||||
|  | //                navigation, | ||||||
|  | //                "org.sebserver.activities.monitoring"); | ||||||
|  | //        ActivitySelection.set(monitoring, Activity.MONITORING.createSelection()); | ||||||
|  | // | ||||||
|  | //        final TreeItem runningExams = this.widgetFactory.treeItemLocalized( | ||||||
|  | //                monitoring, | ||||||
|  | //                "org.sebserver.activities.runningExams"); | ||||||
|  | //        ActivitySelection.set(runningExams, Activity.RUNNING_EXAMS.createSelection() | ||||||
|  | //                .withExpandFunction(this::runningExamExpand)); | ||||||
|  | //        runningExams.setItemCount(1); | ||||||
|  | // | ||||||
|  | //        final TreeItem logs = this.widgetFactory.treeItemLocalized( | ||||||
|  | //                monitoring, | ||||||
|  | //                "org.sebserver.activities.logs"); | ||||||
|  | //        ActivitySelection.set(logs, Activity.LOGS.createSelection()); | ||||||
|  | 
 | ||||||
|  |         navigation.addListener(SWT.Expand, this::handleExpand); | ||||||
|  |         navigation.addListener(SWT.Selection, event -> handleSelection(pageContext, event)); | ||||||
|  | 
 | ||||||
|  |         navigation.setData( | ||||||
|  |                 PageEventListener.LISTENER_ATTRIBUTE_KEY, | ||||||
|  |                 new ActionEventListener() { | ||||||
|  |                     @Override | ||||||
|  |                     public void notify(final ActionEvent event) { | ||||||
|  |                         final ActivityActionHandler aah = | ||||||
|  |                                 ActivitiesPane.this.activityActionHandler.get(event.actionDefinition); | ||||||
|  |                         if (aah != null) { | ||||||
|  |                             aah.notifyAction(event, navigation, pageContext); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 }); | ||||||
|  | 
 | ||||||
|  |         // page-selection on (re)load | ||||||
|  |         final MainPageState mainPageState = MainPageState.get(); | ||||||
|  | 
 | ||||||
|  |         if (mainPageState.activitySelection == null) { | ||||||
|  |             mainPageState.activitySelection = ActivitySelection.get(navigation.getItem(0)); | ||||||
|  |         } | ||||||
|  |         pageContext.publishPageEvent( | ||||||
|  |                 new ActivitySelectionEvent(mainPageState.activitySelection)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | //    private void runningExamExpand(final TreeItem item) { | ||||||
|  | //        item.removeAll(); | ||||||
|  | //        final List<EntityName> runningExamNames = this.restService | ||||||
|  | //                .sebServerCall(GetRunningExamNames.class) | ||||||
|  | //                .onError(t -> { | ||||||
|  | //                    throw new RuntimeException(t); | ||||||
|  | //                }); | ||||||
|  | // | ||||||
|  | //        if (runningExamNames != null) { | ||||||
|  | //            for (final EntityName runningExamName : runningExamNames) { | ||||||
|  | //                final TreeItem runningExams = this.widgetFactory.treeItemLocalized( | ||||||
|  | //                        item, | ||||||
|  | //                        runningExamName.name); | ||||||
|  | //                ActivitySelection.set(runningExams, Activity.RUNNING_EXAM.createSelection(runningExamName)); | ||||||
|  | //            } | ||||||
|  | //        } | ||||||
|  | //    } | ||||||
|  | 
 | ||||||
|  |     private void handleExpand(final Event event) { | ||||||
|  |         final TreeItem treeItem = (TreeItem) event.item; | ||||||
|  | 
 | ||||||
|  |         System.out.println("opened: " + treeItem); | ||||||
|  | 
 | ||||||
|  |         final ActivitySelection activity = ActivitySelection.get(treeItem); | ||||||
|  |         if (activity != null) { | ||||||
|  |             activity.processExpand(treeItem); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void handleSelection(final PageContext composerCtx, final Event event) { | ||||||
|  |         final TreeItem treeItem = (TreeItem) event.item; | ||||||
|  | 
 | ||||||
|  |         System.out.println("selected: " + treeItem); | ||||||
|  | 
 | ||||||
|  |         final MainPageState mainPageState = MainPageState.get(); | ||||||
|  |         final ActivitySelection activitySelection = ActivitySelection.get(treeItem); | ||||||
|  |         if (mainPageState.activitySelection == null) { | ||||||
|  |             mainPageState.activitySelection = Activity.NONE.createSelection(); | ||||||
|  |         } | ||||||
|  |         if (!mainPageState.activitySelection.equals(activitySelection)) { | ||||||
|  |             mainPageState.activitySelection = activitySelection; | ||||||
|  |             composerCtx.publishPageEvent( | ||||||
|  |                     new ActivitySelectionEvent(mainPageState.activitySelection)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     static TreeItem createInstitutionItem(final Tree parent, final EntityName idAndName) { | ||||||
|  |         final TreeItem institution = new TreeItem(parent, SWT.NONE); | ||||||
|  |         createInstitutionItem(idAndName, institution); | ||||||
|  |         return institution; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     static TreeItem createInstitutionItem(final TreeItem parent, final EntityName idAndName) { | ||||||
|  |         final TreeItem institution = new TreeItem(parent, SWT.NONE); | ||||||
|  |         createInstitutionItem(idAndName, institution); | ||||||
|  |         return institution; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     static void createInstitutionItem(final EntityName idAndName, final TreeItem institution) { | ||||||
|  |         institution.setText(idAndName.name); | ||||||
|  |         ActivitySelection.inject(institution, Activity.INSTITUTION_NODE.createSelection(idAndName)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     static final TreeItem findItemByActivity( | ||||||
|  |             final TreeItem[] items, | ||||||
|  |             final Activity activity, | ||||||
|  |             final String objectId) { | ||||||
|  | 
 | ||||||
|  |         if (items == null) { | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         for (final TreeItem item : items) { | ||||||
|  |             final ActivitySelection activitySelection = ActivitySelection.get(item); | ||||||
|  |             final String id = activitySelection.getObjectIdentifier(); | ||||||
|  |             if (activitySelection != null && activitySelection.activity == activity && | ||||||
|  |                     (id == null || (objectId != null && objectId.equals(id)))) { | ||||||
|  |                 return item; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             final TreeItem _item = findItemByActivity(item.getItems(), activity, objectId); | ||||||
|  |             if (_item != null) { | ||||||
|  |                 return _item; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     static final TreeItem findItemByActivity(final TreeItem[] items, final Activity activity) { | ||||||
|  |         return findItemByActivity(items, activity, null); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     static final void expand(final TreeItem item) { | ||||||
|  |         if (item == null) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         item.setExpanded(true); | ||||||
|  |         expand(item.getParentItem()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,26 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.page.activity; | ||||||
|  | 
 | ||||||
|  | import org.eclipse.swt.widgets.Tree; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageContext; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.action.ActionDefinition; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent; | ||||||
|  | 
 | ||||||
|  | public interface ActivityActionHandler { | ||||||
|  | 
 | ||||||
|  |     public ActionDefinition handlesAction(); | ||||||
|  | 
 | ||||||
|  |     void notifyAction( | ||||||
|  |             final ActionEvent event, | ||||||
|  |             final Tree navigation, | ||||||
|  |             final PageContext composerCtx); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,162 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.page.activity; | ||||||
|  | 
 | ||||||
|  | import java.util.function.Consumer; | ||||||
|  | 
 | ||||||
|  | import org.eclipse.swt.widgets.TreeItem; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gbl.model.EntityName; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.action.ActionPane; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.impl.TODOTemplate; | ||||||
|  | 
 | ||||||
|  | public class ActivitySelection { | ||||||
|  | 
 | ||||||
|  |     public static final Consumer<TreeItem> EMPTY_FUNCTION = ti -> { | ||||||
|  |     }; | ||||||
|  |     public static final Consumer<TreeItem> COLLAPSE_NONE_EMPTY = ti -> { | ||||||
|  |         ti.removeAll(); | ||||||
|  |         ti.setItemCount(1); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     public enum Activity { | ||||||
|  |         NONE(TODOTemplate.class, TODOTemplate.class, (String) null), | ||||||
|  |         INSTITUTION_ROOT( | ||||||
|  |                 TODOTemplate.class, | ||||||
|  |                 ActionPane.class, | ||||||
|  |                 new LocTextKey("sebserver.activities.inst")), | ||||||
|  |         INSTITUTION_NODE( | ||||||
|  |                 TODOTemplate.class, | ||||||
|  |                 ActionPane.class, | ||||||
|  |                 AttributeKeys.INSTITUTION_ID), | ||||||
|  | // | ||||||
|  | //        USERS(UserAccountsForm.class, ActionPane.class), | ||||||
|  | // | ||||||
|  | //        EXAMS(ExamsListPage.class, ActionPane.class), | ||||||
|  | //        SEB_CONFIGS(SEBConfigurationForm.class, ActionPane.class), | ||||||
|  | //        SEB_CONFIG(SEBConfigurationPage.class, ActionPane.class), | ||||||
|  | //        SEB_CONFIG_TEMPLATES(TODOTemplate.class, ActionPane.class), | ||||||
|  | //        MONITORING(MonitoringForm.class, ActionPane.class), | ||||||
|  | //        RUNNING_EXAMS(RunningExamForm.class, ActionPane.class), | ||||||
|  | //        RUNNING_EXAM(RunningExamPage.class, ActionPane.class, AttributeKeys.EXAM_ID), | ||||||
|  | //        LOGS(TODOTemplate.class, ActionPane.class), | ||||||
|  |         ; | ||||||
|  | 
 | ||||||
|  |         public final LocTextKey title; | ||||||
|  |         public final Class<? extends TemplateComposer> contentPaneComposer; | ||||||
|  |         public final Class<? extends TemplateComposer> actionPaneComposer; | ||||||
|  |         public final String objectIdentifierAttribute; | ||||||
|  | 
 | ||||||
|  |         private Activity( | ||||||
|  |                 final Class<? extends TemplateComposer> objectPaneComposer, | ||||||
|  |                 final Class<? extends TemplateComposer> selectionPaneComposer, | ||||||
|  |                 final LocTextKey title) { | ||||||
|  | 
 | ||||||
|  |             this.title = title; | ||||||
|  |             this.contentPaneComposer = objectPaneComposer; | ||||||
|  |             this.actionPaneComposer = selectionPaneComposer; | ||||||
|  |             this.objectIdentifierAttribute = null; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         private Activity( | ||||||
|  |                 final Class<? extends TemplateComposer> objectPaneComposer, | ||||||
|  |                 final Class<? extends TemplateComposer> selectionPaneComposer, | ||||||
|  |                 final String objectIdentifierAttribute) { | ||||||
|  | 
 | ||||||
|  |             this.title = null; | ||||||
|  |             this.contentPaneComposer = objectPaneComposer; | ||||||
|  |             this.actionPaneComposer = selectionPaneComposer; | ||||||
|  |             this.objectIdentifierAttribute = objectIdentifierAttribute; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public final ActivitySelection createSelection() { | ||||||
|  |             return new ActivitySelection(this); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public final ActivitySelection createSelection(final EntityName entityName) { | ||||||
|  |             return new ActivitySelection(this, entityName); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private static final String ATTR_ACTIVITY_SELECTION = "ACTIVITY_SELECTION"; | ||||||
|  | 
 | ||||||
|  |     public final Activity activity; | ||||||
|  |     public final EntityName entityName; | ||||||
|  |     Consumer<TreeItem> expandFunction = EMPTY_FUNCTION; | ||||||
|  | 
 | ||||||
|  |     ActivitySelection(final Activity activity) { | ||||||
|  |         this(activity, null); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ActivitySelection(final Activity activity, final EntityName entityName) { | ||||||
|  |         this.activity = activity; | ||||||
|  |         this.entityName = entityName; | ||||||
|  |         this.expandFunction = EMPTY_FUNCTION; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public ActivitySelection withExpandFunction(final Consumer<TreeItem> expandFunction) { | ||||||
|  |         if (expandFunction == null) { | ||||||
|  |             this.expandFunction = EMPTY_FUNCTION; | ||||||
|  |         } | ||||||
|  |         this.expandFunction = expandFunction; | ||||||
|  |         return this; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getObjectIdentifier() { | ||||||
|  |         if (this.entityName == null) { | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return this.entityName.modelId; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void processExpand(final TreeItem item) { | ||||||
|  |         this.expandFunction.accept(item); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public int hashCode() { | ||||||
|  |         final int prime = 31; | ||||||
|  |         int result = 1; | ||||||
|  |         result = prime * result + ((this.activity == null) ? 0 : this.activity.hashCode()); | ||||||
|  |         result = prime * result + ((this.entityName == null) ? 0 : this.entityName.hashCode()); | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean equals(final Object obj) { | ||||||
|  |         if (this == obj) | ||||||
|  |             return true; | ||||||
|  |         if (obj == null) | ||||||
|  |             return false; | ||||||
|  |         if (getClass() != obj.getClass()) | ||||||
|  |             return false; | ||||||
|  |         final ActivitySelection other = (ActivitySelection) obj; | ||||||
|  |         if (this.activity != other.activity) | ||||||
|  |             return false; | ||||||
|  |         if (this.entityName == null) { | ||||||
|  |             if (other.entityName != null) | ||||||
|  |                 return false; | ||||||
|  |         } else if (!this.entityName.equals(other.entityName)) | ||||||
|  |             return false; | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static ActivitySelection get(final TreeItem item) { | ||||||
|  |         return (ActivitySelection) item.getData(ATTR_ACTIVITY_SELECTION); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static void inject(final TreeItem item, final ActivitySelection selection) { | ||||||
|  |         item.setData(ATTR_ACTIVITY_SELECTION, selection); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,26 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.page.event; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.action.ActionDefinition; | ||||||
|  | 
 | ||||||
|  | public final class ActionEvent implements PageEvent { | ||||||
|  | 
 | ||||||
|  |     public final ActionDefinition actionDefinition; | ||||||
|  |     public final Object source; | ||||||
|  | 
 | ||||||
|  |     public ActionEvent( | ||||||
|  |             final ActionDefinition actionDefinition, | ||||||
|  |             final Object source) { | ||||||
|  | 
 | ||||||
|  |         this.actionDefinition = actionDefinition; | ||||||
|  |         this.source = source; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,73 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.page.event; | ||||||
|  | 
 | ||||||
|  | import java.util.function.Consumer; | ||||||
|  | import java.util.function.Predicate; | ||||||
|  | 
 | ||||||
|  | import org.eclipse.swt.widgets.Widget; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageEventListener; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.action.ActionDefinition; | ||||||
|  | 
 | ||||||
|  | public interface ActionEventListener extends PageEventListener<ActionEvent> { | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     default boolean match(final Class<? extends PageEvent> type) { | ||||||
|  |         return type == ActionEvent.class; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     static ActionEventListener of(final Consumer<ActionEvent> eventConsumer) { | ||||||
|  |         return new ActionEventListener() { | ||||||
|  |             @Override | ||||||
|  |             public void notify(final ActionEvent event) { | ||||||
|  |                 eventConsumer.accept(event); | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     static ActionEventListener of( | ||||||
|  |             final Predicate<ActionEvent> predicate, | ||||||
|  |             final Consumer<ActionEvent> eventConsumer) { | ||||||
|  | 
 | ||||||
|  |         return new ActionEventListener() { | ||||||
|  |             @Override | ||||||
|  |             public void notify(final ActionEvent event) { | ||||||
|  |                 if (predicate.test(event)) { | ||||||
|  |                     eventConsumer.accept(event); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     static ActionEventListener of( | ||||||
|  |             final ActionDefinition actionDefinition, | ||||||
|  |             final Consumer<ActionEvent> eventConsumer) { | ||||||
|  | 
 | ||||||
|  |         return new ActionEventListener() { | ||||||
|  |             @Override | ||||||
|  |             public void notify(final ActionEvent event) { | ||||||
|  |                 if (event.actionDefinition == actionDefinition) { | ||||||
|  |                     eventConsumer.accept(event); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     static void injectListener( | ||||||
|  |             final Widget widget, | ||||||
|  |             final ActionDefinition actionDefinition, | ||||||
|  |             final Consumer<ActionEvent> eventConsumer) { | ||||||
|  | 
 | ||||||
|  |         widget.setData( | ||||||
|  |                 PageEventListener.LISTENER_ATTRIBUTE_KEY, | ||||||
|  |                 of(actionDefinition, eventConsumer)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,53 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.page.event; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.action.ActionDefinition; | ||||||
|  | 
 | ||||||
|  | public class ActionPublishEvent implements PageEvent { | ||||||
|  | 
 | ||||||
|  |     public final ActionDefinition actionDefinition; | ||||||
|  |     public final Runnable run; | ||||||
|  |     public final String confirmationMessage; | ||||||
|  |     public final String successMessage; | ||||||
|  | 
 | ||||||
|  |     public ActionPublishEvent( | ||||||
|  |             final ActionDefinition actionDefinition, | ||||||
|  |             final Runnable run) { | ||||||
|  | 
 | ||||||
|  |         this(actionDefinition, run, null, null); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public ActionPublishEvent( | ||||||
|  |             final ActionDefinition actionDefinition, | ||||||
|  |             final Runnable run, | ||||||
|  |             final String confirmationMessage) { | ||||||
|  | 
 | ||||||
|  |         this(actionDefinition, run, confirmationMessage, null); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public ActionPublishEvent( | ||||||
|  |             final ActionDefinition actionDefinition, | ||||||
|  |             final Runnable run, | ||||||
|  |             final String confirmationMessage, | ||||||
|  |             final String successMessage) { | ||||||
|  | 
 | ||||||
|  |         this.actionDefinition = actionDefinition; | ||||||
|  |         this.run = run; | ||||||
|  |         this.confirmationMessage = confirmationMessage; | ||||||
|  |         this.successMessage = successMessage; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public String toString() { | ||||||
|  |         return "ActionPublishEvent [actionDefinition=" + this.actionDefinition + ", confirmationMessage=" | ||||||
|  |                 + this.confirmationMessage + ", successMessage=" + this.successMessage + "]"; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,20 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.page.event; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageEventListener; | ||||||
|  | 
 | ||||||
|  | public interface ActionPublishEventListener extends PageEventListener<ActionPublishEvent> { | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     default boolean match(final Class<? extends PageEvent> type) { | ||||||
|  |         return type == ActionPublishEvent.class; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,21 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.page.event; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.activity.ActivitySelection; | ||||||
|  | 
 | ||||||
|  | public class ActivitySelectionEvent implements PageEvent { | ||||||
|  | 
 | ||||||
|  |     public final ActivitySelection selection; | ||||||
|  | 
 | ||||||
|  |     public ActivitySelectionEvent(final ActivitySelection selection) { | ||||||
|  |         this.selection = selection; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,20 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.page.event; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageEventListener; | ||||||
|  | 
 | ||||||
|  | public interface ActivitySelectionListener extends PageEventListener<ActivitySelectionEvent> { | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     default boolean match(final Class<? extends PageEvent> eventType) { | ||||||
|  |         return eventType == ActivitySelectionEvent.class; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,21 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.page.event; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageContext; | ||||||
|  | 
 | ||||||
|  | public final class LogoutEvent implements PageEvent { | ||||||
|  | 
 | ||||||
|  |     public final PageContext pageContext; | ||||||
|  | 
 | ||||||
|  |     public LogoutEvent(final PageContext pageContext) { | ||||||
|  |         this.pageContext = pageContext; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,20 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.page.event; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageEventListener; | ||||||
|  | 
 | ||||||
|  | public interface LogoutEventListener extends PageEventListener<LogoutEvent> { | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     default boolean match(final Class<? extends PageEvent> eventType) { | ||||||
|  |         return eventType == LogoutEvent.class; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,13 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.page.event; | ||||||
|  | 
 | ||||||
|  | public interface PageEvent { | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,186 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.page.impl; | ||||||
|  | 
 | ||||||
|  | import java.util.Collection; | ||||||
|  | import java.util.Map; | ||||||
|  | import java.util.function.Function; | ||||||
|  | import java.util.stream.Collectors; | ||||||
|  | 
 | ||||||
|  | import org.eclipse.swt.widgets.Composite; | ||||||
|  | import org.eclipse.swt.widgets.Control; | ||||||
|  | import org.slf4j.Logger; | ||||||
|  | import org.slf4j.LoggerFactory; | ||||||
|  | import org.springframework.context.annotation.Lazy; | ||||||
|  | import org.springframework.stereotype.Service; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.ComposerService; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageContext; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageDefinition; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder; | ||||||
|  | 
 | ||||||
|  | @Lazy | ||||||
|  | @Service | ||||||
|  | @GuiProfile | ||||||
|  | public class ComposerServiceImpl implements ComposerService { | ||||||
|  | 
 | ||||||
|  |     private static final Logger log = LoggerFactory.getLogger(ComposerServiceImpl.class); | ||||||
|  | 
 | ||||||
|  |     // TODO configurable | ||||||
|  |     private final Class<? extends PageDefinition> loginPageType = DefaultLoginPage.class; | ||||||
|  |     private final Class<? extends PageDefinition> mainPageType = DefaultMainPage.class; | ||||||
|  | 
 | ||||||
|  |     final AuthorizationContextHolder authorizationContextHolder; | ||||||
|  |     private final I18nSupport i18nSupport; | ||||||
|  |     private final Map<String, TemplateComposer> composer; | ||||||
|  |     private final Map<String, PageDefinition> pages; | ||||||
|  | 
 | ||||||
|  |     public ComposerServiceImpl( | ||||||
|  |             final AuthorizationContextHolder authorizationContextHolder, | ||||||
|  |             final I18nSupport i18nSupport, | ||||||
|  |             final Collection<TemplateComposer> composer, | ||||||
|  |             final Collection<PageDefinition> pageDefinitions) { | ||||||
|  | 
 | ||||||
|  |         this.authorizationContextHolder = authorizationContextHolder; | ||||||
|  |         this.i18nSupport = i18nSupport; | ||||||
|  |         this.composer = composer | ||||||
|  |                 .stream() | ||||||
|  |                 .collect(Collectors.toMap( | ||||||
|  |                         comp -> comp.getClass().getName(), | ||||||
|  |                         Function.identity())); | ||||||
|  | 
 | ||||||
|  |         this.pages = pageDefinitions | ||||||
|  |                 .stream() | ||||||
|  |                 .collect(Collectors.toMap( | ||||||
|  |                         page -> page.getClass().getName(), | ||||||
|  |                         Function.identity())); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public PageDefinition mainPage() { | ||||||
|  |         return this.pages.get(this.mainPageType.getName()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public PageDefinition loginPage() { | ||||||
|  |         return this.pages.get(this.loginPageType.getName()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean validate(final String composerName, final PageContext pageContext) { | ||||||
|  |         if (!this.composer.containsKey(composerName)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return this.composer | ||||||
|  |                 .get(composerName) | ||||||
|  |                 .validate(pageContext); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void compose( | ||||||
|  |             final Class<? extends TemplateComposer> composerType, | ||||||
|  |             final PageContext pageContext) { | ||||||
|  | 
 | ||||||
|  |         compose(composerType.getName(), pageContext); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void compose( | ||||||
|  |             final String name, | ||||||
|  |             final PageContext pageContext) { | ||||||
|  | 
 | ||||||
|  |         if (!this.composer.containsKey(name)) { | ||||||
|  |             log.error("No TemplateComposer with name: " + name + " found. Check Spring confiuration and beans"); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         final TemplateComposer composer = this.composer.get(name); | ||||||
|  | 
 | ||||||
|  |         if (composer.validate(pageContext)) { | ||||||
|  | 
 | ||||||
|  |             clear(pageContext.getParent()); | ||||||
|  | 
 | ||||||
|  |             try { | ||||||
|  |                 composer.compose(pageContext); | ||||||
|  |             } catch (final Exception e) { | ||||||
|  |                 log.warn("Failed to compose: {}, pageContext: {}", name, pageContext, e); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             try { | ||||||
|  |                 pageContext.getParent().layout(); | ||||||
|  |             } catch (final Exception e) { | ||||||
|  |                 log.warn("Failed to layout new composition: {}, pageContext: {}", name, pageContext, e); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         } else { | ||||||
|  |             log.error( | ||||||
|  |                     "Invalid or missing mandatory attributes to handle compose request of ViewComposer: {} pageContext: {}", | ||||||
|  |                     name, | ||||||
|  |                     pageContext); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void composePage( | ||||||
|  |             final PageDefinition pageDefinition, | ||||||
|  |             final Composite root) { | ||||||
|  | 
 | ||||||
|  |         compose( | ||||||
|  |                 pageDefinition.composer(), | ||||||
|  |                 pageDefinition.applyPageContext(createPageContext(root))); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void composePage( | ||||||
|  |             final Class<? extends PageDefinition> pageType, | ||||||
|  |             final Composite root) { | ||||||
|  | 
 | ||||||
|  |         final String pageName = pageType.getName(); | ||||||
|  |         if (!this.pages.containsKey(pageName)) { | ||||||
|  |             log.error("Unknown page with name: {}", pageName); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         final PageDefinition pageDefinition = this.pages.get(pageName); | ||||||
|  |         compose( | ||||||
|  |                 pageDefinition.composer(), | ||||||
|  |                 pageDefinition.applyPageContext(createPageContext(root))); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void loadLoginPage(final Composite parent) { | ||||||
|  |         composePage(this.loginPageType, parent); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void loadMainPage(final Composite parent) { | ||||||
|  |         composePage(this.mainPageType, parent); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private PageContext createPageContext(final Composite root) { | ||||||
|  |         return new PageContextImpl( | ||||||
|  |                 this.i18nSupport, this, root, root, null); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void clear(final Composite parent) { | ||||||
|  |         if (parent == null) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         for (final Control control : parent.getChildren()) { | ||||||
|  |             control.dispose(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,37 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.page.impl; | ||||||
|  | 
 | ||||||
|  | import org.springframework.context.annotation.Lazy; | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageContext; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageDefinition; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; | ||||||
|  | 
 | ||||||
|  | /** Default login page works with the DefaultPageLayout and the | ||||||
|  |  * SEBLogin template */ | ||||||
|  | @Lazy | ||||||
|  | @Component | ||||||
|  | public class DefaultLoginPage implements PageDefinition { | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public Class<? extends TemplateComposer> composer() { | ||||||
|  |         return DefaultPageLayout.class; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public PageContext applyPageContext(final PageContext pageContext) { | ||||||
|  |         return pageContext.withAttr( | ||||||
|  |                 AttributeKeys.ATTR_PAGE_TEMPLATE_COMPOSER_NAME, | ||||||
|  |                 SEBLogin.class.getName()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,37 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.page.impl; | ||||||
|  | 
 | ||||||
|  | import org.springframework.context.annotation.Lazy; | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageContext; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageDefinition; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; | ||||||
|  | 
 | ||||||
|  | /** Default main page works with the DefaultPageLayout and the | ||||||
|  |  * SEBMainPage template */ | ||||||
|  | @Lazy | ||||||
|  | @Component | ||||||
|  | public class DefaultMainPage implements PageDefinition { | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public Class<? extends TemplateComposer> composer() { | ||||||
|  |         return DefaultPageLayout.class; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public PageContext applyPageContext(final PageContext pageContext) { | ||||||
|  |         return pageContext.withAttr( | ||||||
|  |                 AttributeKeys.ATTR_PAGE_TEMPLATE_COMPOSER_NAME, | ||||||
|  |                 SEBMainPage.class.getName()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,275 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.page.impl; | ||||||
|  | 
 | ||||||
|  | import org.eclipse.rap.rwt.RWT; | ||||||
|  | import org.eclipse.swt.SWT; | ||||||
|  | import org.eclipse.swt.layout.GridData; | ||||||
|  | import org.eclipse.swt.layout.GridLayout; | ||||||
|  | import org.eclipse.swt.layout.RowLayout; | ||||||
|  | import org.eclipse.swt.widgets.Button; | ||||||
|  | import org.eclipse.swt.widgets.Composite; | ||||||
|  | import org.eclipse.swt.widgets.Label; | ||||||
|  | import org.springframework.beans.factory.annotation.Value; | ||||||
|  | import org.springframework.context.annotation.Lazy; | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageContext; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory; | ||||||
|  | 
 | ||||||
|  | @Lazy | ||||||
|  | @Component | ||||||
|  | public class DefaultPageLayout implements TemplateComposer { | ||||||
|  | 
 | ||||||
|  |     private final WidgetFactory widgetFactory; | ||||||
|  |     private final PolyglotPageService polyglotPageService; | ||||||
|  |     private final AuthorizationContextHolder authorizationContextHolder; | ||||||
|  |     private final String sebServerVersion; | ||||||
|  | 
 | ||||||
|  |     public DefaultPageLayout( | ||||||
|  |             final WidgetFactory widgetFactory, | ||||||
|  |             final PolyglotPageService polyglotPageService, | ||||||
|  |             final AuthorizationContextHolder authorizationContextHolder, | ||||||
|  |             @Value("${sebserver.version}") final String sebServerVersion) { | ||||||
|  | 
 | ||||||
|  |         this.widgetFactory = widgetFactory; | ||||||
|  |         this.polyglotPageService = polyglotPageService; | ||||||
|  |         this.authorizationContextHolder = authorizationContextHolder; | ||||||
|  |         this.sebServerVersion = sebServerVersion; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean validate(final PageContext pageContext) { | ||||||
|  |         return pageContext.hasAttribute(AttributeKeys.ATTR_PAGE_TEMPLATE_COMPOSER_NAME); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void compose(final PageContext pageContext) { | ||||||
|  | 
 | ||||||
|  |         final GridLayout skeletonLayout = new GridLayout(); | ||||||
|  |         skeletonLayout.marginBottom = 0; | ||||||
|  |         skeletonLayout.marginLeft = 0; | ||||||
|  |         skeletonLayout.marginRight = 0; | ||||||
|  |         skeletonLayout.marginTop = 0; | ||||||
|  |         skeletonLayout.marginHeight = 0; | ||||||
|  |         skeletonLayout.marginWidth = 0; | ||||||
|  |         skeletonLayout.verticalSpacing = 0; | ||||||
|  |         skeletonLayout.horizontalSpacing = 0; | ||||||
|  |         pageContext.getParent().setLayout(skeletonLayout); | ||||||
|  | 
 | ||||||
|  |         composeHeader(pageContext); | ||||||
|  |         composeLogoBar(pageContext); | ||||||
|  |         composeContent(pageContext); | ||||||
|  |         composeFooter(pageContext); | ||||||
|  | 
 | ||||||
|  |         this.polyglotPageService.setDefaultPageLocale(pageContext.getRoot()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void composeHeader(final PageContext pageContext) { | ||||||
|  |         final Composite header = new Composite(pageContext.getParent(), SWT.NONE); | ||||||
|  |         final GridLayout gridLayout = new GridLayout(); | ||||||
|  |         gridLayout.marginRight = 50; | ||||||
|  |         gridLayout.marginLeft = 50; | ||||||
|  |         header.setLayout(gridLayout); | ||||||
|  |         final GridData headerCell = new GridData(SWT.FILL, SWT.TOP, true, false); | ||||||
|  |         headerCell.minimumHeight = 40; | ||||||
|  |         headerCell.heightHint = 40; | ||||||
|  |         header.setLayoutData(headerCell); | ||||||
|  |         header.setData(RWT.CUSTOM_VARIANT, "header"); | ||||||
|  | 
 | ||||||
|  |         final Composite headerRight = new Composite(header, SWT.NONE); | ||||||
|  |         headerRight.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, true, true)); | ||||||
|  |         final GridLayout headerRightGrid = new GridLayout(2, false); | ||||||
|  |         headerRightGrid.marginHeight = 0; | ||||||
|  |         headerRightGrid.marginWidth = 0; | ||||||
|  |         headerRightGrid.horizontalSpacing = 20; | ||||||
|  |         headerRight.setLayout(headerRightGrid); | ||||||
|  |         headerRight.setData(RWT.CUSTOM_VARIANT, "header"); | ||||||
|  | 
 | ||||||
|  |         if (this.authorizationContextHolder.getAuthorizationContext().isLoggedIn()) { | ||||||
|  |             final Label username = new Label(headerRight, SWT.NONE); | ||||||
|  |             username.setData(RWT.CUSTOM_VARIANT, "header"); | ||||||
|  |             username.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, true, true)); | ||||||
|  |             username.setText(this.authorizationContextHolder | ||||||
|  |                     .getAuthorizationContext() | ||||||
|  |                     .getLoggedInUser() | ||||||
|  |                     .get(pageContext::logoutOnError).username); | ||||||
|  | 
 | ||||||
|  |             final Button logout = this.widgetFactory.buttonLocalized(headerRight, "sebserver.logout"); | ||||||
|  |             logout.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true)); | ||||||
|  |             logout.setData(RWT.CUSTOM_VARIANT, "header"); | ||||||
|  |             logout.addListener(SWT.Selection, event -> { | ||||||
|  |                 final boolean logoutSuccessful = this.authorizationContextHolder | ||||||
|  |                         .getAuthorizationContext() | ||||||
|  |                         .logout(); | ||||||
|  | 
 | ||||||
|  |                 if (!logoutSuccessful) { | ||||||
|  |                     // TODO error handling | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 MainPageState.clear(); | ||||||
|  | 
 | ||||||
|  |                 // forward to login page with success message | ||||||
|  |                 pageContext.forwardToLoginPage( | ||||||
|  |                         pageContext.withAttr(AttributeKeys.LGOUT_SUCCESS, "true")); | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void composeLogoBar(final PageContext pageContext) { | ||||||
|  |         final Composite logoBar = new Composite(pageContext.getParent(), SWT.NONE); | ||||||
|  |         final GridData logoBarCell = new GridData(SWT.FILL, SWT.TOP, false, false); | ||||||
|  |         logoBarCell.minimumHeight = 80; | ||||||
|  |         logoBarCell.heightHint = 80; | ||||||
|  |         logoBar.setLayoutData(logoBarCell); | ||||||
|  |         logoBar.setData(RWT.CUSTOM_VARIANT, "logo"); | ||||||
|  |         final GridLayout logoBarLayout = new GridLayout(2, false); | ||||||
|  |         logoBarLayout.horizontalSpacing = 0; | ||||||
|  |         logoBarLayout.marginHeight = 0; | ||||||
|  |         logoBar.setLayout(logoBarLayout); | ||||||
|  | 
 | ||||||
|  |         final Composite logo = new Composite(logoBar, SWT.NONE); | ||||||
|  |         final GridData logoCell = new GridData(SWT.LEFT, SWT.CENTER, true, true); | ||||||
|  |         logoCell.minimumHeight = 80; | ||||||
|  |         logoCell.heightHint = 80; | ||||||
|  |         logoCell.minimumWidth = 400; | ||||||
|  |         logoCell.horizontalIndent = 50; | ||||||
|  |         logo.setLayoutData(logoCell); | ||||||
|  |         logo.setData(RWT.CUSTOM_VARIANT, "bgLogo"); | ||||||
|  | 
 | ||||||
|  |         final Composite langSupport = new Composite(logoBar, SWT.NONE); | ||||||
|  |         final GridData langSupportCell = new GridData(SWT.RIGHT, SWT.CENTER, false, false); | ||||||
|  |         langSupportCell.heightHint = 20; | ||||||
|  |         logoCell.horizontalIndent = 50; | ||||||
|  |         langSupport.setLayoutData(langSupportCell); | ||||||
|  |         langSupport.setData(RWT.CUSTOM_VARIANT, "logo"); | ||||||
|  |         final RowLayout rowLayout = new RowLayout(SWT.HORIZONTAL); | ||||||
|  |         rowLayout.spacing = 7; | ||||||
|  |         rowLayout.marginRight = 70; | ||||||
|  |         langSupport.setLayout(rowLayout); | ||||||
|  | 
 | ||||||
|  |         this.widgetFactory.createLanguageSelector(pageContext.copyOf(langSupport)); | ||||||
|  | //        for (final Locale locale : this.i18nSupport.supportedLanguages()) { | ||||||
|  | //            final LanguageSelection languageSelection = new LanguageSelection(langSupport, locale); | ||||||
|  | //            languageSelection.updateLocale(this.i18nSupport); | ||||||
|  | //            languageSelection.addListener(SWT.MouseDown, event -> { | ||||||
|  | //                this.polyglotPageService.setPageLocale(pageContext.root, languageSelection.locale); | ||||||
|  | // | ||||||
|  | //            }); | ||||||
|  | //        } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void composeContent(final PageContext pageContext) { | ||||||
|  |         final Composite contentBackground = new Composite(pageContext.getParent(), SWT.NONE); | ||||||
|  |         contentBackground.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); | ||||||
|  |         contentBackground.setData(RWT.CUSTOM_VARIANT, "bgContent"); | ||||||
|  |         final GridLayout innerGrid = new GridLayout(); | ||||||
|  |         innerGrid.marginLeft = 50; | ||||||
|  |         innerGrid.marginRight = 50; | ||||||
|  |         innerGrid.marginHeight = 0; | ||||||
|  |         innerGrid.marginWidth = 0; | ||||||
|  | 
 | ||||||
|  |         contentBackground.setLayout(innerGrid); | ||||||
|  | 
 | ||||||
|  |         final Composite content = new Composite(contentBackground, SWT.NONE); | ||||||
|  |         content.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); | ||||||
|  |         content.setData(RWT.CUSTOM_VARIANT, "content"); | ||||||
|  |         final GridLayout contentGrid = new GridLayout(); | ||||||
|  |         contentGrid.marginHeight = 0; | ||||||
|  |         contentGrid.marginWidth = 0; | ||||||
|  |         content.setLayout(contentGrid); | ||||||
|  | 
 | ||||||
|  |         final Composite contentInner = new Composite(content, SWT.NONE); | ||||||
|  |         contentInner.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true)); | ||||||
|  |         final GridLayout gridLayout = new GridLayout(); | ||||||
|  |         gridLayout.marginHeight = 0; | ||||||
|  |         gridLayout.marginWidth = 0; | ||||||
|  |         contentInner.setLayout(gridLayout); | ||||||
|  | 
 | ||||||
|  |         final String contentComposerName = pageContext.getAttribute( | ||||||
|  |                 AttributeKeys.ATTR_PAGE_TEMPLATE_COMPOSER_NAME); | ||||||
|  |         pageContext.composerService().compose( | ||||||
|  |                 contentComposerName, | ||||||
|  |                 pageContext.copyOf(contentInner)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void composeFooter(final PageContext pageContext) { | ||||||
|  |         final Composite footerBar = new Composite(pageContext.getParent(), SWT.NONE); | ||||||
|  |         final GridData footerCell = new GridData(SWT.FILL, SWT.BOTTOM, false, false); | ||||||
|  |         footerCell.minimumHeight = 30; | ||||||
|  |         footerCell.heightHint = 30; | ||||||
|  |         footerBar.setLayoutData(footerCell); | ||||||
|  |         footerBar.setData(RWT.CUSTOM_VARIANT, "bgFooter"); | ||||||
|  |         final GridLayout innerBarGrid = new GridLayout(); | ||||||
|  |         innerBarGrid.marginHeight = 0; | ||||||
|  |         innerBarGrid.marginWidth = 0; | ||||||
|  |         innerBarGrid.marginLeft = 50; | ||||||
|  |         innerBarGrid.marginRight = 50; | ||||||
|  |         footerBar.setLayout(innerBarGrid); | ||||||
|  | 
 | ||||||
|  |         final Composite footer = new Composite(footerBar, SWT.NONE); | ||||||
|  |         final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true); | ||||||
|  |         footer.setLayoutData(gridData); | ||||||
|  |         final GridLayout footerGrid = new GridLayout(2, false); | ||||||
|  |         footerGrid.marginHeight = 0; | ||||||
|  |         footerGrid.marginWidth = 0; | ||||||
|  |         footerGrid.horizontalSpacing = 0; | ||||||
|  |         footer.setLayout(footerGrid); | ||||||
|  |         footer.setData(RWT.CUSTOM_VARIANT, "footer"); | ||||||
|  | 
 | ||||||
|  |         final Composite footerLeft = new Composite(footer, SWT.NONE); | ||||||
|  |         footerLeft.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, true)); | ||||||
|  |         footerLeft.setData(RWT.CUSTOM_VARIANT, "footer"); | ||||||
|  |         RowLayout rowLayout = new RowLayout(SWT.HORIZONTAL); | ||||||
|  |         rowLayout.marginLeft = 20; | ||||||
|  |         rowLayout.spacing = 20; | ||||||
|  |         footerLeft.setLayout(rowLayout); | ||||||
|  | 
 | ||||||
|  |         final Composite footerRight = new Composite(footer, SWT.NONE); | ||||||
|  |         footerRight.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, true, true)); | ||||||
|  |         footerRight.setData(RWT.CUSTOM_VARIANT, "footer"); | ||||||
|  |         rowLayout = new RowLayout(SWT.HORIZONTAL); | ||||||
|  |         rowLayout.marginRight = 20; | ||||||
|  |         footerRight.setLayout(rowLayout); | ||||||
|  | 
 | ||||||
|  |         this.widgetFactory.labelLocalized(footerLeft, "footer", new LocTextKey("sebserver.overall.imprint")); | ||||||
|  |         this.widgetFactory.labelLocalized(footerLeft, "footer", new LocTextKey("sebserver.overall.about")); | ||||||
|  |         this.widgetFactory.labelLocalized( | ||||||
|  |                 footerRight, | ||||||
|  |                 "footer", | ||||||
|  |                 new LocTextKey("sebserver.overall.version", this.sebServerVersion)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | //    private final class LanguageSelection extends Label implements Polyglot { | ||||||
|  | // | ||||||
|  | //        private static final long serialVersionUID = 8110167162843383940L; | ||||||
|  | //        private final Locale locale; | ||||||
|  | // | ||||||
|  | //        public LanguageSelection(final Composite parent, final Locale locale) { | ||||||
|  | //            super(parent, SWT.NONE); | ||||||
|  | //            this.locale = locale; | ||||||
|  | //            super.setData(RWT.CUSTOM_VARIANT, "header"); | ||||||
|  | //            super.setText("|  " + locale.getLanguage().toUpperCase()); | ||||||
|  | //        } | ||||||
|  | // | ||||||
|  | //        @Override | ||||||
|  | //        public void updateLocale(final I18nSupport i18nSupport) { | ||||||
|  | //            super.setVisible( | ||||||
|  | //                    !i18nSupport.getCurrentLocale() | ||||||
|  | //                            .getLanguage() | ||||||
|  | //                            .equals(this.locale.getLanguage())); | ||||||
|  | //        } | ||||||
|  | //    } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,49 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  *  | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.page.impl; | ||||||
|  | 
 | ||||||
|  | import javax.servlet.http.HttpSession; | ||||||
|  | 
 | ||||||
|  | import org.eclipse.rap.rwt.RWT; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.activity.ActivitySelection; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.activity.ActivitySelection.Activity; | ||||||
|  | 
 | ||||||
|  | public final class MainPageState { | ||||||
|  | 
 | ||||||
|  |     public ActivitySelection activitySelection = Activity.NONE.createSelection(); | ||||||
|  | 
 | ||||||
|  |     private MainPageState() { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static MainPageState get() { | ||||||
|  |         try { | ||||||
|  |             final HttpSession httpSession = RWT | ||||||
|  |                     .getUISession() | ||||||
|  |                     .getHttpSession(); | ||||||
|  | 
 | ||||||
|  |             MainPageState mainPageState = (MainPageState) httpSession.getAttribute(SEBMainPage.ATTR_MAIN_PAGE_STATE); | ||||||
|  |             if (mainPageState == null) { | ||||||
|  |                 mainPageState = new MainPageState(); | ||||||
|  |                 httpSession.setAttribute(SEBMainPage.ATTR_MAIN_PAGE_STATE, mainPageState); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             return mainPageState; | ||||||
|  |         } catch (final Exception e) { | ||||||
|  |             SEBMainPage.log.error("Unexpected error while trying to get MainPageState from user-session"); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static void clear() { | ||||||
|  |         final MainPageState mainPageState = get(); | ||||||
|  |         mainPageState.activitySelection = Activity.NONE.createSelection(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,275 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.page.impl; | ||||||
|  | 
 | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.Comparator; | ||||||
|  | import java.util.HashMap; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
|  | 
 | ||||||
|  | import org.eclipse.rap.rwt.widgets.DialogCallback; | ||||||
|  | import org.eclipse.swt.SWT; | ||||||
|  | import org.eclipse.swt.widgets.Composite; | ||||||
|  | import org.eclipse.swt.widgets.MessageBox; | ||||||
|  | import org.eclipse.swt.widgets.Shell; | ||||||
|  | import org.slf4j.Logger; | ||||||
|  | import org.slf4j.LoggerFactory; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gbl.api.APIMessage; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.api.APIMessageError; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.util.Utils; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.ComposerService; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageContext; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageDefinition; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageEventListener; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.event.PageEvent; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.widget.Message; | ||||||
|  | 
 | ||||||
|  | public class PageContextImpl implements PageContext { | ||||||
|  | 
 | ||||||
|  |     private static final Logger log = LoggerFactory.getLogger(PageContextImpl.class); | ||||||
|  | 
 | ||||||
|  |     private final I18nSupport i18nSupport; | ||||||
|  |     private final ComposerService composerService; | ||||||
|  |     private final Composite root; | ||||||
|  |     private final Composite parent; | ||||||
|  |     private final Map<String, String> attributes; | ||||||
|  | 
 | ||||||
|  |     PageContextImpl( | ||||||
|  |             final I18nSupport i18nSupport, | ||||||
|  |             final ComposerService composerService, | ||||||
|  |             final Composite root, | ||||||
|  |             final Composite parent, | ||||||
|  |             final Map<String, String> attributes) { | ||||||
|  | 
 | ||||||
|  |         this.i18nSupport = i18nSupport; | ||||||
|  |         this.composerService = composerService; | ||||||
|  |         this.root = root; | ||||||
|  |         this.parent = parent; | ||||||
|  |         this.attributes = Utils.immutableMapOf(attributes); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public Shell getShell() { | ||||||
|  |         if (this.root == null) { | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return this.root.getShell(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public ComposerService composerService() { | ||||||
|  |         return this.composerService; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public Composite getRoot() { | ||||||
|  |         return this.root; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public Composite getParent() { | ||||||
|  |         return this.parent; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public PageContext copyOf(final Composite parent) { | ||||||
|  |         return new PageContextImpl( | ||||||
|  |                 this.i18nSupport, | ||||||
|  |                 this.composerService, | ||||||
|  |                 this.root, | ||||||
|  |                 parent, | ||||||
|  |                 this.attributes); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public PageContext copyOfAttributes(final PageContext otherContext) { | ||||||
|  |         final Map<String, String> attrs = new HashMap<>(); | ||||||
|  |         attrs.putAll(this.attributes); | ||||||
|  |         attrs.putAll(((PageContextImpl) otherContext).attributes); | ||||||
|  |         return new PageContextImpl( | ||||||
|  |                 this.i18nSupport, | ||||||
|  |                 this.composerService, | ||||||
|  |                 this.root, | ||||||
|  |                 this.parent, | ||||||
|  |                 attrs); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public PageContext withAttr(final String key, final String value) { | ||||||
|  |         final Map<String, String> attrs = new HashMap<>(); | ||||||
|  |         attrs.putAll(this.attributes); | ||||||
|  |         attrs.put(key, value); | ||||||
|  |         return new PageContextImpl( | ||||||
|  |                 this.i18nSupport, | ||||||
|  |                 this.composerService, | ||||||
|  |                 this.root, | ||||||
|  |                 this.parent, attrs); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public String getAttribute(final String name) { | ||||||
|  |         return this.attributes.get(name); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public String getAttribute(final String name, final String def) { | ||||||
|  |         if (this.attributes.containsKey(name)) { | ||||||
|  |             return this.attributes.get(name); | ||||||
|  |         } else { | ||||||
|  |             return def; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean hasAttribute(final String name) { | ||||||
|  |         return this.attributes.containsKey(name); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     @SuppressWarnings("unchecked") | ||||||
|  |     public <T extends PageEvent> void publishPageEvent(final T event) { | ||||||
|  |         final Class<? extends PageEvent> typeClass = event.getClass(); | ||||||
|  |         final List<PageEventListener<T>> listeners = new ArrayList<>(); | ||||||
|  |         ComposerService.traversePageTree( | ||||||
|  |                 this.root, | ||||||
|  |                 c -> { | ||||||
|  |                     final PageEventListener<?> listener = | ||||||
|  |                             (PageEventListener<?>) c.getData(PageEventListener.LISTENER_ATTRIBUTE_KEY); | ||||||
|  |                     return listener != null && listener.match(typeClass); | ||||||
|  |                 }, | ||||||
|  |                 c -> listeners.add(((PageEventListener<T>) c.getData(PageEventListener.LISTENER_ATTRIBUTE_KEY)))); | ||||||
|  | 
 | ||||||
|  |         if (listeners.isEmpty()) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         listeners.stream() | ||||||
|  |                 .sorted(LISTENER_COMPARATOR) | ||||||
|  |                 .forEach(listener -> listener.notify(event)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     @SuppressWarnings("serial") | ||||||
|  |     public void applyConfirmDialog(final String confirmMessage, final Runnable onOK) { | ||||||
|  |         final Message messageBox = new Message( | ||||||
|  |                 this.root.getShell(), | ||||||
|  |                 this.i18nSupport.getText("org.sebserver.dialog.confirm.title"), | ||||||
|  |                 this.i18nSupport.getText(confirmMessage), | ||||||
|  |                 SWT.OK | SWT.CANCEL); | ||||||
|  |         messageBox.open(new DialogCallback() { | ||||||
|  |             @Override | ||||||
|  |             public void dialogClosed(final int returnCode) { | ||||||
|  |                 if (returnCode == SWT.OK) { | ||||||
|  |                     try { | ||||||
|  |                         onOK.run(); | ||||||
|  |                     } catch (final Throwable t) { | ||||||
|  |                         log.error( | ||||||
|  |                                 "Unexpected on confirm callback execution. This should not happen, plase secure the given onOK Runnable", | ||||||
|  |                                 t); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | //    public void applyValidationErrorDialog(final Collection<FieldValidationError> validationErrors) { | ||||||
|  | //        final Message messageBox = new Message( | ||||||
|  | //                this.root.getShell(), | ||||||
|  | //                this.i18nSupport.getText("org.sebserver.dialog.validationErrors.title"), | ||||||
|  | //                this.i18nSupport.getText(confirmMessage), | ||||||
|  | //                SWT.OK); | ||||||
|  | //    } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void forwardToPage( | ||||||
|  |             final PageDefinition pageDefinition, | ||||||
|  |             final PageContext pageContext) { | ||||||
|  | 
 | ||||||
|  |         this.composerService.compose( | ||||||
|  |                 pageDefinition.composer(), | ||||||
|  |                 pageDefinition.applyPageContext(pageContext.copyOf(pageContext.getRoot()))); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void forwardToMainPage(final PageContext pageContext) { | ||||||
|  |         forwardToPage(this.composerService.mainPage(), pageContext); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void forwardToLoginPage(final PageContext pageContext) { | ||||||
|  |         forwardToPage(this.composerService.loginPage(), pageContext); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void notifyError(final String errorMessage, final Throwable error) { | ||||||
|  |         if (error instanceof APIMessageError) { | ||||||
|  |             final List<APIMessage> errorMessages = ((APIMessageError) error).getErrorMessages(); | ||||||
|  |             final MessageBox messageBox = new Message( | ||||||
|  |                     getShell(), | ||||||
|  |                     this.i18nSupport.getText("sebserver.error.unexpected"), | ||||||
|  |                     APIMessage.toHTML(errorMessages), | ||||||
|  |                     SWT.ERROR); | ||||||
|  |             messageBox.setMarkupEnabled(true); | ||||||
|  |             messageBox.open(null); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         final MessageBox messageBox = new Message( | ||||||
|  |                 getShell(), | ||||||
|  |                 this.i18nSupport.getText("sebserver.error.unexpected"), | ||||||
|  |                 error.toString(), | ||||||
|  |                 SWT.ERROR); | ||||||
|  |         messageBox.open(null); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void notifyError(final Throwable error) { | ||||||
|  |         notifyError(error.getMessage(), error); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public <T> T logoutOnError(final Throwable error) { | ||||||
|  |         // just to be sure we leave a clean and proper authorizationContext | ||||||
|  |         try { | ||||||
|  |             ((ComposerServiceImpl) this.composerService).authorizationContextHolder | ||||||
|  |                     .getAuthorizationContext() | ||||||
|  |                     .logout(); | ||||||
|  |         } catch (final Exception e) { | ||||||
|  |             log.info("Cleanup logout failed: {}", e.getMessage()); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         MainPageState.clear(); | ||||||
|  |         forwardToLoginPage(this.withAttr( | ||||||
|  |                 AttributeKeys.AUTHORIZATION_FAILURE, | ||||||
|  |                 error.getMessage())); | ||||||
|  | 
 | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public String toString() { | ||||||
|  |         return "PageContextImpl [root=" + this.root + ", parent=" + this.parent + ", attributes=" + this.attributes | ||||||
|  |                 + "]"; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private static final Comparator<PageEventListener<?>> LISTENER_COMPARATOR = | ||||||
|  |             new Comparator<>() { | ||||||
|  |                 @Override | ||||||
|  |                 public int compare(final PageEventListener<?> o1, final PageEventListener<?> o2) { | ||||||
|  |                     final int x = o1.priority(); | ||||||
|  |                     final int y = o2.priority(); | ||||||
|  |                     return (x < y) ? -1 : ((x == y) ? 0 : 1); | ||||||
|  |                 } | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,147 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.page.impl; | ||||||
|  | 
 | ||||||
|  | import org.eclipse.rap.rwt.RWT; | ||||||
|  | import org.eclipse.swt.SWT; | ||||||
|  | import org.eclipse.swt.layout.GridData; | ||||||
|  | import org.eclipse.swt.layout.GridLayout; | ||||||
|  | import org.eclipse.swt.widgets.Button; | ||||||
|  | import org.eclipse.swt.widgets.Composite; | ||||||
|  | import org.eclipse.swt.widgets.Label; | ||||||
|  | import org.eclipse.swt.widgets.MessageBox; | ||||||
|  | import org.eclipse.swt.widgets.Text; | ||||||
|  | import org.slf4j.Logger; | ||||||
|  | import org.slf4j.LoggerFactory; | ||||||
|  | import org.springframework.context.annotation.Lazy; | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageContext; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.SEBServerAuthorizationContext; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.widget.Message; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory; | ||||||
|  | 
 | ||||||
|  | @Lazy | ||||||
|  | @Component | ||||||
|  | @GuiProfile | ||||||
|  | public class SEBLogin implements TemplateComposer { | ||||||
|  | 
 | ||||||
|  |     private static final Logger log = LoggerFactory.getLogger(SEBLogin.class); | ||||||
|  | 
 | ||||||
|  |     private final AuthorizationContextHolder authorizationContextHolder; | ||||||
|  |     private final WidgetFactory widgetFactory; | ||||||
|  |     private final I18nSupport i18nSupport; | ||||||
|  | 
 | ||||||
|  |     public SEBLogin( | ||||||
|  |             final AuthorizationContextHolder authorizationContextHolder, | ||||||
|  |             final WidgetFactory widgetFactory, | ||||||
|  |             final I18nSupport i18nSupport) { | ||||||
|  | 
 | ||||||
|  |         this.authorizationContextHolder = authorizationContextHolder; | ||||||
|  |         this.widgetFactory = widgetFactory; | ||||||
|  |         this.i18nSupport = i18nSupport; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void compose(final PageContext pageContext) { | ||||||
|  |         final Composite parent = pageContext.getParent(); | ||||||
|  | 
 | ||||||
|  |         if (pageContext.hasAttribute((AttributeKeys.LGOUT_SUCCESS))) { | ||||||
|  |             final MessageBox logoutSuccess = new Message( | ||||||
|  |                     pageContext.getShell(), | ||||||
|  |                     this.i18nSupport.getText("org.sebserver.logout"), | ||||||
|  |                     this.i18nSupport.getText("org.sebserver.logout.success.message"), | ||||||
|  |                     SWT.ICON_INFORMATION); | ||||||
|  |             logoutSuccess.open(null); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         final Composite loginGroup = new Composite(parent, SWT.NONE); | ||||||
|  |         final GridLayout rowLayout = new GridLayout(); | ||||||
|  |         rowLayout.marginWidth = 20; | ||||||
|  |         rowLayout.marginRight = 100; | ||||||
|  |         loginGroup.setLayout(rowLayout); | ||||||
|  |         loginGroup.setData(RWT.CUSTOM_VARIANT, "login"); | ||||||
|  | 
 | ||||||
|  |         final Label name = this.widgetFactory.labelLocalized(loginGroup, "sebserver.login.username"); | ||||||
|  |         name.setLayoutData(new GridData(300, -1)); | ||||||
|  |         name.setAlignment(SWT.BOTTOM); | ||||||
|  |         final Text loginName = new Text(loginGroup, SWT.LEFT | SWT.BORDER); | ||||||
|  |         loginName.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false)); | ||||||
|  |         GridData gridData = new GridData(SWT.FILL, SWT.TOP, false, false); | ||||||
|  |         gridData.verticalIndent = 10; | ||||||
|  |         final Label pwd = this.widgetFactory.labelLocalized(loginGroup, "sebserver.login.pwd"); | ||||||
|  |         pwd.setLayoutData(gridData); | ||||||
|  |         final Text loginPassword = new Text(loginGroup, SWT.LEFT | SWT.PASSWORD | SWT.BORDER); | ||||||
|  |         loginPassword.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false)); | ||||||
|  | 
 | ||||||
|  |         final Button button = this.widgetFactory.buttonLocalized(loginGroup, "sebserver.login.login"); | ||||||
|  |         gridData = new GridData(SWT.LEFT, SWT.TOP, false, false); | ||||||
|  |         gridData.verticalIndent = 10; | ||||||
|  |         button.setLayoutData(gridData); | ||||||
|  | 
 | ||||||
|  |         final SEBServerAuthorizationContext authorizationContext = this.authorizationContextHolder | ||||||
|  |                 .getAuthorizationContext(RWT.getUISession().getHttpSession()); | ||||||
|  | 
 | ||||||
|  |         button.addListener(SWT.Selection, event -> { | ||||||
|  |             final String username = loginName.getText(); | ||||||
|  |             try { | ||||||
|  | 
 | ||||||
|  |                 final boolean loggedIn = authorizationContext.login( | ||||||
|  |                         username, | ||||||
|  |                         loginPassword.getText()); | ||||||
|  | 
 | ||||||
|  |                 if (loggedIn) { | ||||||
|  |                     // Set users locale on page after successful login | ||||||
|  |                     this.i18nSupport.setSessionLocale( | ||||||
|  |                             authorizationContext | ||||||
|  |                                     .getLoggedInUser() | ||||||
|  |                                     .get(pageContext::logoutOnError).locale); | ||||||
|  | 
 | ||||||
|  |                     pageContext.forwardToMainPage(pageContext); | ||||||
|  | 
 | ||||||
|  |                 } else { | ||||||
|  |                     loginError(pageContext, "sebserver.login.failed.message"); | ||||||
|  |                 } | ||||||
|  |             } catch (final Exception e) { | ||||||
|  |                 log.error("Unexpected error while trying to login with user: {}", username, e); | ||||||
|  |                 loginError(pageContext, "Unexpected Error. Please call an Administrator"); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |         loginName.addListener(SWT.KeyDown, event -> { | ||||||
|  |             if (event.character == '\n' || event.character == '\r') { | ||||||
|  |                 loginPassword.setFocus(); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |         loginPassword.addListener(SWT.KeyDown, event -> { | ||||||
|  |             if (event.character == '\n' || event.character == '\r') { | ||||||
|  |                 button.setFocus(); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void loginError( | ||||||
|  |             final PageContext pageContext, | ||||||
|  |             final String message) { | ||||||
|  | 
 | ||||||
|  |         final MessageBox error = new Message( | ||||||
|  |                 pageContext.getShell(), | ||||||
|  |                 this.i18nSupport.getText("sebserver.login.failed.title"), | ||||||
|  |                 this.i18nSupport.getText(message, message), | ||||||
|  |                 SWT.ERROR); | ||||||
|  |         error.open(null); | ||||||
|  |         pageContext.logoutOnError(new RuntimeException(message)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,166 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.page.impl; | ||||||
|  | 
 | ||||||
|  | import org.eclipse.rap.rwt.RWT; | ||||||
|  | import org.eclipse.swt.SWT; | ||||||
|  | import org.eclipse.swt.custom.SashForm; | ||||||
|  | import org.eclipse.swt.layout.GridData; | ||||||
|  | import org.eclipse.swt.layout.GridLayout; | ||||||
|  | import org.eclipse.swt.widgets.Composite; | ||||||
|  | import org.eclipse.swt.widgets.Label; | ||||||
|  | import org.slf4j.Logger; | ||||||
|  | import org.slf4j.LoggerFactory; | ||||||
|  | import org.springframework.context.annotation.Lazy; | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageContext; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageEventListener; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.activity.ActivitiesPane; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.event.ActivitySelectionEvent; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.event.ActivitySelectionListener; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory.IconButtonType; | ||||||
|  | 
 | ||||||
|  | @Lazy | ||||||
|  | @Component | ||||||
|  | @GuiProfile | ||||||
|  | public class SEBMainPage implements TemplateComposer { | ||||||
|  | 
 | ||||||
|  |     static final Logger log = LoggerFactory.getLogger(SEBMainPage.class); | ||||||
|  | 
 | ||||||
|  |     public static final String ATTR_MAIN_PAGE_STATE = "MAIN_PAGE_STATE"; | ||||||
|  | 
 | ||||||
|  |     private static final int ACTIVITY_PANE_WEIGHT = 20; | ||||||
|  |     private static final int CONTENT_PANE_WEIGHT = 65; | ||||||
|  |     private static final int ACTION_PANE_WEIGHT = 15; | ||||||
|  |     private static final int[] DEFAULT_SASH_WEIGHTS = new int[] { | ||||||
|  |             ACTIVITY_PANE_WEIGHT, | ||||||
|  |             CONTENT_PANE_WEIGHT, | ||||||
|  |             ACTION_PANE_WEIGHT | ||||||
|  |     }; | ||||||
|  |     private static final int[] OPENED_SASH_WEIGHTS = new int[] { 0, 100, 0 }; | ||||||
|  | 
 | ||||||
|  |     private final WidgetFactory widgetFactory; | ||||||
|  | 
 | ||||||
|  |     public SEBMainPage(final WidgetFactory widgetFactory) { | ||||||
|  |         this.widgetFactory = widgetFactory; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void compose(final PageContext pageContext) { | ||||||
|  |         MainPageState.clear(); | ||||||
|  | 
 | ||||||
|  |         final Composite parent = pageContext.getParent(); | ||||||
|  |         parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); | ||||||
|  | 
 | ||||||
|  |         final SashForm mainSash = new SashForm(parent, SWT.HORIZONTAL); | ||||||
|  |         final GridLayout gridLayout = new GridLayout(); | ||||||
|  | 
 | ||||||
|  |         mainSash.setLayout(gridLayout); | ||||||
|  |         mainSash.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); | ||||||
|  | 
 | ||||||
|  |         final Composite nav = new Composite(mainSash, SWT.NONE); | ||||||
|  |         nav.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); | ||||||
|  |         final GridLayout navLayout = new GridLayout(); | ||||||
|  |         navLayout.marginHeight = 20; | ||||||
|  |         navLayout.marginWidth = 0; | ||||||
|  |         nav.setLayout(navLayout); | ||||||
|  | 
 | ||||||
|  |         final Composite content = new Composite(mainSash, SWT.NONE); | ||||||
|  |         content.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); | ||||||
|  |         final GridLayout contentOuterlayout = new GridLayout(); | ||||||
|  |         contentOuterlayout.marginHeight = 0; | ||||||
|  |         contentOuterlayout.marginWidth = 0; | ||||||
|  |         content.setLayout(contentOuterlayout); | ||||||
|  | 
 | ||||||
|  |         final Label toggleView = this.widgetFactory.imageButton( | ||||||
|  |                 IconButtonType.MAXIMIZE, | ||||||
|  |                 content, | ||||||
|  |                 new LocTextKey("sebserver.mainpage.maximize.tooltip"), | ||||||
|  |                 event -> { | ||||||
|  |                     final Label ib = (Label) event.widget; | ||||||
|  |                     if ((Boolean) ib.getData("fullScreen")) { | ||||||
|  |                         mainSash.setWeights(DEFAULT_SASH_WEIGHTS); | ||||||
|  |                         ib.setData("fullScreen", false); | ||||||
|  |                         ib.setImage(WidgetFactory.IconButtonType.MAXIMIZE.getImage(ib.getDisplay())); | ||||||
|  |                         this.widgetFactory.injectI18n( | ||||||
|  |                                 ib, | ||||||
|  |                                 null, | ||||||
|  |                                 new LocTextKey("sebserver.mainpage.maximize.tooltip")); | ||||||
|  |                     } else { | ||||||
|  |                         mainSash.setWeights(OPENED_SASH_WEIGHTS); | ||||||
|  |                         ib.setData("fullScreen", true); | ||||||
|  |                         ib.setImage(WidgetFactory.IconButtonType.MINIMIZE.getImage(ib.getDisplay())); | ||||||
|  |                         this.widgetFactory.injectI18n( | ||||||
|  |                                 ib, | ||||||
|  |                                 null, | ||||||
|  |                                 new LocTextKey("sebserver.mainpage.minimize.tooltip")); | ||||||
|  |                     } | ||||||
|  |                 }); | ||||||
|  |         final GridData gridData = new GridData(SWT.RIGHT, SWT.TOP, true, false); | ||||||
|  |         toggleView.setLayoutData(gridData); | ||||||
|  |         toggleView.setData("fullScreen", false); | ||||||
|  | 
 | ||||||
|  |         final Composite contentObjects = new Composite(content, SWT.NONE); | ||||||
|  |         contentObjects.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); | ||||||
|  |         final GridLayout contentObjectslayout = new GridLayout(); | ||||||
|  |         contentObjectslayout.marginHeight = 0; | ||||||
|  |         contentObjectslayout.marginWidth = 0; | ||||||
|  |         contentObjects.setLayout(contentObjectslayout); | ||||||
|  |         contentObjects.setData(PageEventListener.LISTENER_ATTRIBUTE_KEY, | ||||||
|  |                 new ActivitySelectionListener() { | ||||||
|  |                     @Override | ||||||
|  |                     public int priority() { | ||||||
|  |                         return 2; | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     @Override | ||||||
|  |                     public void notify(final ActivitySelectionEvent event) { | ||||||
|  |                         pageContext.composerService().compose( | ||||||
|  |                                 event.selection.activity.contentPaneComposer, | ||||||
|  |                                 pageContext.copyOf(contentObjects).withAttr( | ||||||
|  |                                         event.selection.activity.objectIdentifierAttribute, | ||||||
|  |                                         event.selection.getObjectIdentifier())); | ||||||
|  |                     } | ||||||
|  |                 }); | ||||||
|  | 
 | ||||||
|  |         final Composite actionPane = new Composite(mainSash, SWT.NONE); | ||||||
|  |         actionPane.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); | ||||||
|  |         final GridLayout actionPaneGrid = new GridLayout(); | ||||||
|  |         actionPane.setLayout(actionPaneGrid); | ||||||
|  |         actionPane.setData(RWT.CUSTOM_VARIANT, "actionPane"); | ||||||
|  |         actionPane.setData(PageEventListener.LISTENER_ATTRIBUTE_KEY, | ||||||
|  |                 new ActivitySelectionListener() { | ||||||
|  |                     @Override | ||||||
|  |                     public int priority() { | ||||||
|  |                         return 1; | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     @Override | ||||||
|  |                     public void notify(final ActivitySelectionEvent event) { | ||||||
|  |                         pageContext.composerService().compose( | ||||||
|  |                                 event.selection.activity.actionPaneComposer, | ||||||
|  |                                 pageContext.copyOf(actionPane).withAttr( | ||||||
|  |                                         event.selection.activity.objectIdentifierAttribute, | ||||||
|  |                                         event.selection.getObjectIdentifier())); | ||||||
|  |                     } | ||||||
|  |                 }); | ||||||
|  | 
 | ||||||
|  |         pageContext.composerService().compose( | ||||||
|  |                 ActivitiesPane.class, | ||||||
|  |                 pageContext.copyOf(nav)); | ||||||
|  | 
 | ||||||
|  |         mainSash.setWeights(DEFAULT_SASH_WEIGHTS); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,33 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.page.impl; | ||||||
|  | 
 | ||||||
|  | import org.eclipse.swt.SWT; | ||||||
|  | import org.eclipse.swt.layout.GridData; | ||||||
|  | import org.eclipse.swt.widgets.Label; | ||||||
|  | import org.springframework.context.annotation.Lazy; | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageContext; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; | ||||||
|  | 
 | ||||||
|  | @Lazy | ||||||
|  | @Component | ||||||
|  | public class TODOTemplate implements TemplateComposer { | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void compose(final PageContext composerCtx) { | ||||||
|  | 
 | ||||||
|  |         final Label tree = new Label(composerCtx.getParent(), SWT.NONE); | ||||||
|  |         tree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); | ||||||
|  |         tree.setText("[TODO]"); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,96 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.remote.webservice; | ||||||
|  | 
 | ||||||
|  | import java.io.FileNotFoundException; | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.net.HttpURLConnection; | ||||||
|  | import java.security.KeyManagementException; | ||||||
|  | import java.security.KeyStoreException; | ||||||
|  | import java.security.NoSuchAlgorithmException; | ||||||
|  | import java.security.cert.CertificateException; | ||||||
|  | 
 | ||||||
|  | import javax.net.ssl.SSLContext; | ||||||
|  | 
 | ||||||
|  | import org.apache.http.client.HttpClient; | ||||||
|  | import org.apache.http.impl.client.HttpClients; | ||||||
|  | import org.apache.http.ssl.SSLContextBuilder; | ||||||
|  | import org.springframework.context.annotation.Bean; | ||||||
|  | import org.springframework.context.annotation.Configuration; | ||||||
|  | import org.springframework.core.env.Environment; | ||||||
|  | import org.springframework.http.client.ClientHttpRequestFactory; | ||||||
|  | import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; | ||||||
|  | import org.springframework.http.client.SimpleClientHttpRequestFactory; | ||||||
|  | import org.springframework.util.ResourceUtils; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gbl.profile.DevGuiProfile; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.profile.ProdGuiProfile; | ||||||
|  | 
 | ||||||
|  | @Configuration | ||||||
|  | @GuiProfile | ||||||
|  | public class WebserviceConnectionConfig { | ||||||
|  | 
 | ||||||
|  |     /** A ClientHttpRequestFactory for development profile with no TSL SSL protocol and | ||||||
|  |      * not following redirects on redirect responses. | ||||||
|  |      * | ||||||
|  |      * @return ClientHttpRequestFactory bean for development profiles */ | ||||||
|  |     @Bean | ||||||
|  |     @DevGuiProfile | ||||||
|  |     public ClientHttpRequestFactory clientHttpRequestFactory() { | ||||||
|  |         return new SimpleClientHttpRequestFactory() { | ||||||
|  | 
 | ||||||
|  |             @Override | ||||||
|  |             protected void prepareConnection(final HttpURLConnection connection, final String httpMethod) | ||||||
|  |                     throws IOException { | ||||||
|  |                 super.prepareConnection(connection, httpMethod); | ||||||
|  |                 connection.setInstanceFollowRedirects(false); | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** A ClientHttpRequestFactory used in production with TSL SSL configuration. | ||||||
|  |      * | ||||||
|  |      * NOTE: | ||||||
|  |      * environment property: sebserver.gui.truststore.pwd is expected to have the correct truststore password set | ||||||
|  |      * environment property: sebserver.gui.truststore.type is expected to set to the correct type of truststore | ||||||
|  |      * truststore.jks is expected to be on the classpath containing all trusted certificates for request | ||||||
|  |      * to SSL secured SEB Server webservice | ||||||
|  |      * | ||||||
|  |      * @return ClientHttpRequestFactory with TLS / SSL configuration | ||||||
|  |      * @throws IOException | ||||||
|  |      * @throws FileNotFoundException | ||||||
|  |      * @throws CertificateException | ||||||
|  |      * @throws KeyStoreException | ||||||
|  |      * @throws NoSuchAlgorithmException | ||||||
|  |      * @throws KeyManagementException */ | ||||||
|  |     @Bean | ||||||
|  |     @ProdGuiProfile | ||||||
|  |     public ClientHttpRequestFactory clientHttpRequestFactoryTLS(final Environment env) throws KeyManagementException, | ||||||
|  |             NoSuchAlgorithmException, KeyStoreException, CertificateException, FileNotFoundException, IOException { | ||||||
|  | 
 | ||||||
|  |         final char[] password = env | ||||||
|  |                 .getProperty("sebserver.gui.truststore.pwd") | ||||||
|  |                 .toCharArray(); | ||||||
|  | 
 | ||||||
|  |         final SSLContext sslContext = SSLContextBuilder | ||||||
|  |                 .create() | ||||||
|  |                 .loadTrustMaterial(ResourceUtils.getFile( | ||||||
|  |                         "classpath:truststore.jks"), | ||||||
|  |                         password) | ||||||
|  |                 .build(); | ||||||
|  | 
 | ||||||
|  |         final HttpClient client = HttpClients.custom() | ||||||
|  |                 .setSSLContext(sslContext) | ||||||
|  |                 .build(); | ||||||
|  | 
 | ||||||
|  |         return new HttpComponentsClientHttpRequestFactory(client); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -28,8 +28,8 @@ import org.springframework.web.client.RestClientResponseException; | ||||||
| import com.fasterxml.jackson.core.JsonProcessingException; | import com.fasterxml.jackson.core.JsonProcessingException; | ||||||
| import com.fasterxml.jackson.core.type.TypeReference; | import com.fasterxml.jackson.core.type.TypeReference; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.gbl.JSONMapper; | import ch.ethz.seb.sebserver.gbl.api.APIMessage; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.APIMessage; | import ch.ethz.seb.sebserver.gbl.api.JSONMapper; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Page; | import ch.ethz.seb.sebserver.gbl.model.Page; | ||||||
| import ch.ethz.seb.sebserver.gbl.util.Result; | import ch.ethz.seb.sebserver.gbl.util.Result; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService.SortOrder; | import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService.SortOrder; | ||||||
|  | @ -58,9 +58,10 @@ public abstract class RestCall<T> { | ||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void init(final RestService restService, final JSONMapper jsonMapper) { |     RestCall<T> init(final RestService restService, final JSONMapper jsonMapper) { | ||||||
|         this.restService = restService; |         this.restService = restService; | ||||||
|         this.jsonMapper = jsonMapper; |         this.jsonMapper = jsonMapper; | ||||||
|  |         return this; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected Result<T> exchange(final RestCallBuilder builder) { |     protected Result<T> exchange(final RestCallBuilder builder) { | ||||||
|  | @ -107,6 +108,10 @@ public abstract class RestCall<T> { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public RestCallBuilder newBuilder() { | ||||||
|  |         return new RestCallBuilder(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public final class RestCallBuilder { |     public final class RestCallBuilder { | ||||||
| 
 | 
 | ||||||
|         private final HttpHeaders httpHeaders = new HttpHeaders(); |         private final HttpHeaders httpHeaders = new HttpHeaders(); | ||||||
|  | @ -117,7 +122,7 @@ public abstract class RestCall<T> { | ||||||
|         RestCallBuilder() { |         RestCallBuilder() { | ||||||
|             this.httpHeaders.set( |             this.httpHeaders.set( | ||||||
|                     HttpHeaders.CONTENT_TYPE, |                     HttpHeaders.CONTENT_TYPE, | ||||||
|                     RestCall.this.contentType.getType()); |                     RestCall.this.contentType.toString()); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public RestCallBuilder withHeaders(final HttpHeaders headers) { |         public RestCallBuilder withHeaders(final HttpHeaders headers) { | ||||||
|  | @ -165,7 +170,7 @@ public abstract class RestCall<T> { | ||||||
|             return this; |             return this; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public final Result<T> exchange() { |         public final Result<T> call() { | ||||||
|             return RestCall.this.exchange(this); |             return RestCall.this.exchange(this); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -11,9 +11,10 @@ package ch.ethz.seb.sebserver.gui.service.remote.webservice.api; | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.gbl.model.APIMessage; | import ch.ethz.seb.sebserver.gbl.api.APIMessage; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.api.APIMessageError; | ||||||
| 
 | 
 | ||||||
| public class RestCallError extends RuntimeException { | public class RestCallError extends RuntimeException implements APIMessageError { | ||||||
| 
 | 
 | ||||||
|     private static final long serialVersionUID = -5201349295667957490L; |     private static final long serialVersionUID = -5201349295667957490L; | ||||||
| 
 | 
 | ||||||
|  | @ -27,6 +28,7 @@ public class RestCallError extends RuntimeException { | ||||||
|         super(message); |         super(message); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @Override | ||||||
|     public List<APIMessage> getErrorMessages() { |     public List<APIMessage> getErrorMessages() { | ||||||
|         return this.errors; |         return this.errors; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -8,6 +8,10 @@ | ||||||
| 
 | 
 | ||||||
| package ch.ethz.seb.sebserver.gui.service.remote.webservice.api; | package ch.ethz.seb.sebserver.gui.service.remote.webservice.api; | ||||||
| 
 | 
 | ||||||
|  | import java.util.Collection; | ||||||
|  | import java.util.Map; | ||||||
|  | import java.util.stream.Collectors; | ||||||
|  | 
 | ||||||
| import org.slf4j.Logger; | import org.slf4j.Logger; | ||||||
| import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||||
| import org.springframework.context.annotation.Lazy; | import org.springframework.context.annotation.Lazy; | ||||||
|  | @ -15,10 +19,10 @@ import org.springframework.stereotype.Service; | ||||||
| import org.springframework.web.client.RestTemplate; | import org.springframework.web.client.RestTemplate; | ||||||
| import org.springframework.web.util.UriComponentsBuilder; | import org.springframework.web.util.UriComponentsBuilder; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.gbl.JSONMapper; | import ch.ethz.seb.sebserver.gbl.api.JSONMapper; | ||||||
| import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; | import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; | ||||||
| import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder; | import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder; | ||||||
| import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.WebserviceURIBuilderSupplier; | import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.WebserviceURIService; | ||||||
| 
 | 
 | ||||||
| @Lazy | @Lazy | ||||||
| @Service | @Service | ||||||
|  | @ -28,17 +32,23 @@ public class RestService { | ||||||
|     private static final Logger log = LoggerFactory.getLogger(RestService.class); |     private static final Logger log = LoggerFactory.getLogger(RestService.class); | ||||||
| 
 | 
 | ||||||
|     private final AuthorizationContextHolder authorizationContextHolder; |     private final AuthorizationContextHolder authorizationContextHolder; | ||||||
|     private final WebserviceURIBuilderSupplier webserviceURIBuilderSupplier; |     private final WebserviceURIService webserviceURIBuilderSupplier; | ||||||
|     private final JSONMapper jsonMapper; |     private final Map<String, RestCall<?>> calls; | ||||||
| 
 | 
 | ||||||
|     public RestService( |     public RestService( | ||||||
|             final AuthorizationContextHolder authorizationContextHolder, |             final AuthorizationContextHolder authorizationContextHolder, | ||||||
|             final WebserviceURIBuilderSupplier webserviceURIBuilderSupplier, |             final WebserviceURIService webserviceURIBuilderSupplier, | ||||||
|             final JSONMapper jsonMapper) { |             final JSONMapper jsonMapper, | ||||||
|  |             final Collection<RestCall<?>> calls) { | ||||||
| 
 | 
 | ||||||
|         this.authorizationContextHolder = authorizationContextHolder; |         this.authorizationContextHolder = authorizationContextHolder; | ||||||
|         this.webserviceURIBuilderSupplier = webserviceURIBuilderSupplier; |         this.webserviceURIBuilderSupplier = webserviceURIBuilderSupplier; | ||||||
|         this.jsonMapper = jsonMapper; | 
 | ||||||
|  |         this.calls = calls | ||||||
|  |                 .stream() | ||||||
|  |                 .collect(Collectors.toMap( | ||||||
|  |                         call -> call.getClass().getName(), | ||||||
|  |                         call -> call.init(this, jsonMapper))); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public RestTemplate getWebserviceAPIRestTemplate() { |     public RestTemplate getWebserviceAPIRestTemplate() { | ||||||
|  | @ -51,15 +61,19 @@ public class RestService { | ||||||
|         return this.webserviceURIBuilderSupplier.getBuilder(); |         return this.webserviceURIBuilderSupplier.getBuilder(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @SuppressWarnings("unchecked") | ||||||
|     public <T> RestCall<T> getRestCall(final Class<? extends RestCall<T>> type) { |     public <T> RestCall<T> getRestCall(final Class<? extends RestCall<T>> type) { | ||||||
|         try { |         return (RestCall<T>) this.calls.get(type.getName()); | ||||||
|             final RestCall<T> restCall = type.getDeclaredConstructor().newInstance(); |  | ||||||
|             restCall.init(this, this.jsonMapper); |  | ||||||
|             return restCall; |  | ||||||
|         } catch (final Exception e) { |  | ||||||
|             log.error("Error while trying to create RestCall of type: {}", type, e); |  | ||||||
|             return new BuildErrorCall<>(e); |  | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     public <T> RestCall<T>.RestCallBuilder getBuilder(final Class<? extends RestCall<T>> type) { | ||||||
|  |         @SuppressWarnings("unchecked") | ||||||
|  |         final RestCall<T> restCall = (RestCall<T>) this.calls.get(type.getName()); | ||||||
|  |         if (restCall == null) { | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return restCall.newBuilder(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,39 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution; | ||||||
|  | 
 | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | import org.springframework.context.annotation.Lazy; | ||||||
|  | import org.springframework.http.HttpMethod; | ||||||
|  | import org.springframework.http.MediaType; | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  | 
 | ||||||
|  | import com.fasterxml.jackson.core.type.TypeReference; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gbl.api.SEBServerRestEndpoints; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.model.EntityName; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; | ||||||
|  | 
 | ||||||
|  | @Lazy | ||||||
|  | @Component | ||||||
|  | @GuiProfile | ||||||
|  | public class GetInstitutionNames extends RestCall<List<EntityName>> { | ||||||
|  | 
 | ||||||
|  |     protected GetInstitutionNames() { | ||||||
|  |         super( | ||||||
|  |                 new TypeReference<List<EntityName>>() { | ||||||
|  |                 }, | ||||||
|  |                 HttpMethod.GET, | ||||||
|  |                 MediaType.APPLICATION_FORM_URLENCODED, | ||||||
|  |                 SEBServerRestEndpoints.ENDPOINT_INSTITUTION + "/names"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -34,7 +34,9 @@ public class CurrentUser { | ||||||
| 
 | 
 | ||||||
|     public UserInfo get() { |     public UserInfo get() { | ||||||
|         if (isAvailable()) { |         if (isAvailable()) { | ||||||
|             return this.authContext.getLoggedInUser(); |             return this.authContext | ||||||
|  |                     .getLoggedInUser() | ||||||
|  |                     .getOrThrow(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         log.warn("Current user requested but no user is currently logged in"); |         log.warn("Current user requested but no user is currently logged in"); | ||||||
|  |  | ||||||
|  | @ -22,7 +22,9 @@ import org.springframework.beans.factory.annotation.Autowired; | ||||||
| import org.springframework.beans.factory.annotation.Value; | import org.springframework.beans.factory.annotation.Value; | ||||||
| import org.springframework.context.annotation.Lazy; | import org.springframework.context.annotation.Lazy; | ||||||
| import org.springframework.http.HttpMethod; | import org.springframework.http.HttpMethod; | ||||||
|  | import org.springframework.http.HttpStatus; | ||||||
| import org.springframework.http.ResponseEntity; | import org.springframework.http.ResponseEntity; | ||||||
|  | import org.springframework.http.client.ClientHttpRequestFactory; | ||||||
| import org.springframework.security.access.AccessDeniedException; | import org.springframework.security.access.AccessDeniedException; | ||||||
| import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext; | import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext; | ||||||
| import org.springframework.security.oauth2.client.OAuth2RestTemplate; | import org.springframework.security.oauth2.client.OAuth2RestTemplate; | ||||||
|  | @ -41,6 +43,7 @@ import org.springframework.web.client.RestTemplate; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; | import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.user.UserRole; | import ch.ethz.seb.sebserver.gbl.model.user.UserRole; | ||||||
| import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; | import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.util.Result; | ||||||
| 
 | 
 | ||||||
| @Lazy | @Lazy | ||||||
| @Component | @Component | ||||||
|  | @ -50,23 +53,23 @@ public class OAuth2AuthorizationContextHolder implements AuthorizationContextHol | ||||||
|     private static final Logger log = LoggerFactory.getLogger(OAuth2AuthorizationContextHolder.class); |     private static final Logger log = LoggerFactory.getLogger(OAuth2AuthorizationContextHolder.class); | ||||||
| 
 | 
 | ||||||
|     private static final String CONTEXT_HOLDER_ATTRIBUTE = "CONTEXT_HOLDER_ATTRIBUTE"; |     private static final String CONTEXT_HOLDER_ATTRIBUTE = "CONTEXT_HOLDER_ATTRIBUTE"; | ||||||
|     private static final String OAUTH_TOKEN_URI_PATH = "oauth/token"; // TODO to config properties? |  | ||||||
|     private static final String OAUTH_REVOKE_TOKEN_URI_PATH = "/oauth/revoke-token"; // TODO to config properties? |  | ||||||
|     private static final String CURRENT_USER_URI_PATH = "/user/me"; // TODO to config properties? |  | ||||||
| 
 | 
 | ||||||
|     private final String guiClientId; |     private final String guiClientId; | ||||||
|     private final String guiClientSecret; |     private final String guiClientSecret; | ||||||
|     private final WebserviceURIBuilderSupplier webserviceURIBuilderSupplier; |     private final WebserviceURIService webserviceURIService; | ||||||
|  |     private final ClientHttpRequestFactory clientHttpRequestFactory; | ||||||
| 
 | 
 | ||||||
|     @Autowired |     @Autowired | ||||||
|     public OAuth2AuthorizationContextHolder( |     public OAuth2AuthorizationContextHolder( | ||||||
|             @Value("${sebserver.gui.webservice.clientId}") final String guiClientId, |             @Value("${sebserver.gui.webservice.clientId}") final String guiClientId, | ||||||
|             @Value("${sebserver.gui.webservice.clientSecret}") final String guiClientSecret, |             @Value("${sebserver.gui.webservice.clientSecret}") final String guiClientSecret, | ||||||
|             final WebserviceURIBuilderSupplier webserviceURIBuilderSupplier) { |             final WebserviceURIService webserviceURIService, | ||||||
|  |             final ClientHttpRequestFactory clientHttpRequestFactory) { | ||||||
| 
 | 
 | ||||||
|         this.guiClientId = guiClientId; |         this.guiClientId = guiClientId; | ||||||
|         this.guiClientSecret = guiClientSecret; |         this.guiClientSecret = guiClientSecret; | ||||||
|         this.webserviceURIBuilderSupplier = webserviceURIBuilderSupplier; |         this.webserviceURIService = webserviceURIService; | ||||||
|  |         this.clientHttpRequestFactory = clientHttpRequestFactory; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|  | @ -85,7 +88,8 @@ public class OAuth2AuthorizationContextHolder implements AuthorizationContextHol | ||||||
|             context = new OAuth2AuthorizationContext( |             context = new OAuth2AuthorizationContext( | ||||||
|                     this.guiClientId, |                     this.guiClientId, | ||||||
|                     this.guiClientSecret, |                     this.guiClientSecret, | ||||||
|                     this.webserviceURIBuilderSupplier); |                     this.webserviceURIService, | ||||||
|  |                     this.clientHttpRequestFactory); | ||||||
|             session.setAttribute(CONTEXT_HOLDER_ATTRIBUTE, context); |             session.setAttribute(CONTEXT_HOLDER_ATTRIBUTE, context); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -132,7 +136,7 @@ public class OAuth2AuthorizationContextHolder implements AuthorizationContextHol | ||||||
| 
 | 
 | ||||||
|         private static final String GRANT_TYPE = "password"; |         private static final String GRANT_TYPE = "password"; | ||||||
|         private static final List<String> SCOPES = Collections.unmodifiableList( |         private static final List<String> SCOPES = Collections.unmodifiableList( | ||||||
|                 Arrays.asList("web-service-api-read", "web-service-api-write")); |                 Arrays.asList("read", "write")); | ||||||
| 
 | 
 | ||||||
|         private boolean valid = true; |         private boolean valid = true; | ||||||
| 
 | 
 | ||||||
|  | @ -141,34 +145,26 @@ public class OAuth2AuthorizationContextHolder implements AuthorizationContextHol | ||||||
|         private final String revokeTokenURI; |         private final String revokeTokenURI; | ||||||
|         private final String currentUserURI; |         private final String currentUserURI; | ||||||
| 
 | 
 | ||||||
|         private UserInfo loggedInUser = null; |         private Result<UserInfo> loggedInUser = null; | ||||||
| 
 | 
 | ||||||
|         OAuth2AuthorizationContext( |         OAuth2AuthorizationContext( | ||||||
|                 final String guiClientId, |                 final String guiClientId, | ||||||
|                 final String guiClientSecret, |                 final String guiClientSecret, | ||||||
|                 final WebserviceURIBuilderSupplier webserviceURIBuilderSupplier) { |                 final WebserviceURIService webserviceURIService, | ||||||
|  |                 final ClientHttpRequestFactory clientHttpRequestFactory) { | ||||||
| 
 | 
 | ||||||
|             this.resource = new ResourceOwnerPasswordResourceDetails(); |             this.resource = new ResourceOwnerPasswordResourceDetails(); | ||||||
|             this.resource.setAccessTokenUri( |             this.resource.setAccessTokenUri(webserviceURIService.getOAuthTokenURI()); | ||||||
|                     webserviceURIBuilderSupplier |  | ||||||
|                             .getBuilder() |  | ||||||
|                             .path(OAUTH_TOKEN_URI_PATH) |  | ||||||
|                             .toUriString() /* restCallBuilder.withPath(OAUTH_TOKEN_URI_PATH) */); |  | ||||||
|             this.resource.setClientId(guiClientId); |             this.resource.setClientId(guiClientId); | ||||||
|             this.resource.setClientSecret(guiClientSecret); |             this.resource.setClientSecret(guiClientSecret); | ||||||
|             this.resource.setGrantType(GRANT_TYPE); |             this.resource.setGrantType(GRANT_TYPE); | ||||||
|             this.resource.setScope(SCOPES); |             this.resource.setScope(SCOPES); | ||||||
| 
 | 
 | ||||||
|             this.restTemplate = new DisposableOAuth2RestTemplate(this.resource); |             this.restTemplate = new DisposableOAuth2RestTemplate(this.resource); | ||||||
|  |             this.restTemplate.setRequestFactory(clientHttpRequestFactory); | ||||||
| 
 | 
 | ||||||
|             this.revokeTokenURI = webserviceURIBuilderSupplier |             this.revokeTokenURI = webserviceURIService.getOAuthRevokeTokenURI(); | ||||||
|                     .getBuilder() |             this.currentUserURI = webserviceURIService.getCurrentUserRequestURI(); | ||||||
|                     .path(OAUTH_REVOKE_TOKEN_URI_PATH) |  | ||||||
|                     .toUriString(); //restCallBuilder.withPath(OAUTH_REVOKE_TOKEN_URI_PATH); |  | ||||||
|             this.currentUserURI = webserviceURIBuilderSupplier |  | ||||||
|                     .getBuilder() |  | ||||||
|                     .path(CURRENT_USER_URI_PATH) |  | ||||||
|                     .toUriString(); //restCallBuilder.withPath(CURRENT_USER_URI_PATH); |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         @Override |         @Override | ||||||
|  | @ -227,7 +223,7 @@ public class OAuth2AuthorizationContextHolder implements AuthorizationContextHol | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         @Override |         @Override | ||||||
|         public UserInfo getLoggedInUser() { |         public Result<UserInfo> getLoggedInUser() { | ||||||
|             if (this.loggedInUser != null) { |             if (this.loggedInUser != null) { | ||||||
|                 return this.loggedInUser; |                 return this.loggedInUser; | ||||||
|             } |             } | ||||||
|  | @ -237,18 +233,27 @@ public class OAuth2AuthorizationContextHolder implements AuthorizationContextHol | ||||||
|             try { |             try { | ||||||
|                 if (isValid() && isLoggedIn()) { |                 if (isValid() && isLoggedIn()) { | ||||||
|                     final ResponseEntity<UserInfo> response = |                     final ResponseEntity<UserInfo> response = | ||||||
|                             this.restTemplate.getForEntity(this.currentUserURI, UserInfo.class); |                             this.restTemplate | ||||||
|                     this.loggedInUser = response.getBody(); |                                     .getForEntity(this.currentUserURI, UserInfo.class); | ||||||
|  |                     if (response.getStatusCode() == HttpStatus.OK) { | ||||||
|  |                         this.loggedInUser = Result.of(response.getBody()); | ||||||
|                         return this.loggedInUser; |                         return this.loggedInUser; | ||||||
|                     } else { |                     } else { | ||||||
|                     throw new IllegalStateException("Logged in User requested on invalid or not logged in "); |                         log.error("Unexpected error response: {}", response); | ||||||
|  |                         return Result.ofError(new IllegalStateException( | ||||||
|  |                                 "Http Request responded with status: " + response.getStatusCode())); | ||||||
|  |                     } | ||||||
|  |                 } else { | ||||||
|  |                     return Result.ofError( | ||||||
|  |                             new IllegalStateException("Logged in User requested on invalid or not logged in ")); | ||||||
|                 } |                 } | ||||||
|             } catch (final AccessDeniedException | OAuth2AccessDeniedException ade) { |             } catch (final AccessDeniedException | OAuth2AccessDeniedException ade) { | ||||||
|                 log.error("Acccess denied while trying to request logged in User from API", ade); |                 log.error("Acccess denied while trying to request logged in User from API", ade); | ||||||
|                 throw ade; |                 return Result.ofError(ade); | ||||||
|             } catch (final Exception e) { |             } catch (final Exception e) { | ||||||
|                 log.error("Unexpected error while trying to request logged in User from API", e); |                 log.error("Unexpected error while trying to request logged in User from API", e); | ||||||
|                 throw new RuntimeException("Unexpected error while trying to request logged in User from API", e); |                 return Result.ofError( | ||||||
|  |                         new RuntimeException("Unexpected error while trying to request logged in User from API", e)); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -258,7 +263,8 @@ public class OAuth2AuthorizationContextHolder implements AuthorizationContextHol | ||||||
|                 return false; |                 return false; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             return getLoggedInUser().roles |             return getLoggedInUser() | ||||||
|  |                     .getOrThrow().roles | ||||||
|                             .contains(role.name()); |                             .contains(role.name()); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -12,6 +12,7 @@ import org.springframework.web.client.RestTemplate; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; | import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.user.UserRole; | import ch.ethz.seb.sebserver.gbl.model.user.UserRole; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.util.Result; | ||||||
| 
 | 
 | ||||||
| public interface SEBServerAuthorizationContext { | public interface SEBServerAuthorizationContext { | ||||||
| 
 | 
 | ||||||
|  | @ -23,7 +24,7 @@ public interface SEBServerAuthorizationContext { | ||||||
| 
 | 
 | ||||||
|     boolean logout(); |     boolean logout(); | ||||||
| 
 | 
 | ||||||
|     UserInfo getLoggedInUser(); |     Result<UserInfo> getLoggedInUser(); | ||||||
| 
 | 
 | ||||||
|     public boolean hasRole(UserRole role); |     public boolean hasRole(UserRole role); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,40 +0,0 @@ | ||||||
| /* |  | ||||||
|  * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) |  | ||||||
|  * |  | ||||||
|  * This Source Code Form is subject to the terms of the Mozilla Public |  | ||||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this |  | ||||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| package ch.ethz.seb.sebserver.gui.service.remote.webservice.auth; |  | ||||||
| 
 |  | ||||||
| import org.springframework.beans.factory.annotation.Value; |  | ||||||
| import org.springframework.context.annotation.Lazy; |  | ||||||
| import org.springframework.stereotype.Component; |  | ||||||
| import org.springframework.web.util.UriComponentsBuilder; |  | ||||||
| 
 |  | ||||||
| import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; |  | ||||||
| 
 |  | ||||||
| @Lazy |  | ||||||
| @Component |  | ||||||
| @GuiProfile |  | ||||||
| public class WebserviceURIBuilderSupplier { |  | ||||||
| 
 |  | ||||||
|     private final UriComponentsBuilder webserviceURIBuilder; |  | ||||||
| 
 |  | ||||||
|     public WebserviceURIBuilderSupplier( |  | ||||||
|             @Value("${sebserver.gui.webservice.protocol}") final String webserviceProtocol, |  | ||||||
|             @Value("${sebserver.gui.webservice.address}") final String webserviceServerAdress, |  | ||||||
|             @Value("${sebserver.gui.webservice.portol}") final String webserviceServerPort, |  | ||||||
|             @Value("${sebserver.gui.webservice.apipath}") final String webserviceAPIPath) { |  | ||||||
| 
 |  | ||||||
|         this.webserviceURIBuilder = UriComponentsBuilder |  | ||||||
|                 .fromHttpUrl(webserviceProtocol + "://" + webserviceServerAdress) |  | ||||||
|                 .port(webserviceServerPort) |  | ||||||
|                 .path(webserviceAPIPath); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public UriComponentsBuilder getBuilder() { |  | ||||||
|         return this.webserviceURIBuilder.cloneBuilder(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -0,0 +1,63 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.remote.webservice.auth; | ||||||
|  | 
 | ||||||
|  | import org.springframework.beans.factory.annotation.Value; | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  | import org.springframework.web.util.UriComponentsBuilder; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gbl.api.SEBServerRestEndpoints; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; | ||||||
|  | 
 | ||||||
|  | @Component | ||||||
|  | @GuiProfile | ||||||
|  | public class WebserviceURIService { | ||||||
|  | 
 | ||||||
|  |     private static final String OAUTH_TOKEN_URI_PATH = "oauth/token"; // TODO to config properties? | ||||||
|  |     private static final String OAUTH_REVOKE_TOKEN_URI_PATH = "/oauth/revoke-token"; // TODO to config properties? | ||||||
|  |     private static final String CURRENT_USER_URI_PATH = SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/me"; | ||||||
|  | 
 | ||||||
|  |     private final String webserviceServerAddress; | ||||||
|  |     private final UriComponentsBuilder webserviceURIBuilder; | ||||||
|  | 
 | ||||||
|  |     public WebserviceURIService( | ||||||
|  |             @Value("${sebserver.gui.webservice.protocol}") final String webserviceProtocol, | ||||||
|  |             @Value("${sebserver.gui.webservice.address}") final String webserviceServerAdress, | ||||||
|  |             @Value("${sebserver.gui.webservice.port}") final String webserviceServerPort, | ||||||
|  |             @Value("${sebserver.gui.webservice.apipath}") final String webserviceAPIPath) { | ||||||
|  | 
 | ||||||
|  |         this.webserviceServerAddress = webserviceProtocol + "://" + webserviceServerAdress + ":" + webserviceServerPort; | ||||||
|  |         this.webserviceURIBuilder = UriComponentsBuilder | ||||||
|  |                 .fromHttpUrl(webserviceProtocol + "://" + webserviceServerAdress) | ||||||
|  |                 .port(webserviceServerPort) | ||||||
|  |                 .path(webserviceAPIPath); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public UriComponentsBuilder getBuilder() { | ||||||
|  |         return this.webserviceURIBuilder.cloneBuilder(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getOAuthTokenURI() { | ||||||
|  |         return UriComponentsBuilder.fromHttpUrl(this.webserviceServerAddress) | ||||||
|  |                 .path(OAUTH_TOKEN_URI_PATH) | ||||||
|  |                 .toUriString(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getOAuthRevokeTokenURI() { | ||||||
|  |         return UriComponentsBuilder.fromHttpUrl(this.webserviceServerAddress) | ||||||
|  |                 .path(OAUTH_REVOKE_TOKEN_URI_PATH) | ||||||
|  |                 .toUriString(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getCurrentUserRequestURI() { | ||||||
|  |         return getBuilder() | ||||||
|  |                 .path(CURRENT_USER_URI_PATH) | ||||||
|  |                 .toUriString(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,42 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.widget; | ||||||
|  | 
 | ||||||
|  | import org.eclipse.rap.rwt.RWT; | ||||||
|  | import org.eclipse.swt.graphics.Rectangle; | ||||||
|  | import org.eclipse.swt.layout.GridLayout; | ||||||
|  | import org.eclipse.swt.widgets.MessageBox; | ||||||
|  | import org.eclipse.swt.widgets.Shell; | ||||||
|  | 
 | ||||||
|  | public class Message extends MessageBox { | ||||||
|  | 
 | ||||||
|  |     private static final long serialVersionUID = 6973272221493264432L; | ||||||
|  | 
 | ||||||
|  |     public Message(final Shell parent, final String title, final String message, final int type) { | ||||||
|  |         super(parent, type); | ||||||
|  |         super.setText(title); | ||||||
|  |         super.setMessage(message); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     protected void prepareOpen() { | ||||||
|  |         super.prepareOpen(); | ||||||
|  |         final GridLayout layout = (GridLayout) super.shell.getLayout(); | ||||||
|  |         layout.marginTop = 10; | ||||||
|  |         layout.marginBottom = 10; | ||||||
|  |         super.shell.setData(RWT.CUSTOM_VARIANT, "message"); | ||||||
|  |         final Rectangle bounds = super.shell.getBounds(); | ||||||
|  |         if (bounds.width < 400) { | ||||||
|  |             bounds.x = bounds.x - (400 - bounds.width) / 2; | ||||||
|  |             bounds.width = 400; | ||||||
|  |             super.shell.setBounds(bounds); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,56 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.widget; | ||||||
|  | 
 | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.stream.Collectors; | ||||||
|  | 
 | ||||||
|  | import org.eclipse.swt.SWT; | ||||||
|  | import org.eclipse.swt.widgets.Combo; | ||||||
|  | import org.eclipse.swt.widgets.Composite; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gbl.util.Tuple; | ||||||
|  | 
 | ||||||
|  | public class SingleSelection extends Combo { | ||||||
|  | 
 | ||||||
|  |     private static final long serialVersionUID = 6522063655406404279L; | ||||||
|  | 
 | ||||||
|  |     final List<String> valueMapping; | ||||||
|  |     final List<String> keyMapping; | ||||||
|  | 
 | ||||||
|  |     public SingleSelection(final Composite parent, final List<Tuple<String>> mapping) { | ||||||
|  |         super(parent, SWT.READ_ONLY); | ||||||
|  |         this.valueMapping = mapping.stream() | ||||||
|  |                 .map(t -> t._2) | ||||||
|  |                 .collect(Collectors.toList()); | ||||||
|  |         this.keyMapping = mapping.stream() | ||||||
|  |                 .map(t -> t._1) | ||||||
|  |                 .collect(Collectors.toList()); | ||||||
|  |         super.setItems(this.valueMapping.toArray(new String[mapping.size()])); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void select(final String key) { | ||||||
|  |         final int selectionindex = this.keyMapping.indexOf(key); | ||||||
|  |         if (selectionindex < 0) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         super.select(selectionindex); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getSelectionValue() { | ||||||
|  |         final int selectionindex = super.getSelectionIndex(); | ||||||
|  |         if (selectionindex < 0) { | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return this.keyMapping.get(selectionindex); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,470 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  * | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package ch.ethz.seb.sebserver.gui.service.widget; | ||||||
|  | 
 | ||||||
|  | import static ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService.POLYGLOT_TREE_ITEM_TEXT_DATA_KEY; | ||||||
|  | import static ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService.POLYGLOT_WIDGET_FUNCTION_KEY; | ||||||
|  | 
 | ||||||
|  | import java.io.InputStream; | ||||||
|  | import java.util.Iterator; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Locale; | ||||||
|  | import java.util.function.Consumer; | ||||||
|  | 
 | ||||||
|  | import org.eclipse.rap.rwt.RWT; | ||||||
|  | import org.eclipse.swt.SWT; | ||||||
|  | import org.eclipse.swt.graphics.Device; | ||||||
|  | import org.eclipse.swt.graphics.Image; | ||||||
|  | import org.eclipse.swt.graphics.ImageData; | ||||||
|  | import org.eclipse.swt.layout.GridData; | ||||||
|  | import org.eclipse.swt.widgets.Button; | ||||||
|  | import org.eclipse.swt.widgets.Combo; | ||||||
|  | import org.eclipse.swt.widgets.Composite; | ||||||
|  | import org.eclipse.swt.widgets.Label; | ||||||
|  | import org.eclipse.swt.widgets.Listener; | ||||||
|  | import org.eclipse.swt.widgets.Table; | ||||||
|  | import org.eclipse.swt.widgets.TableColumn; | ||||||
|  | import org.eclipse.swt.widgets.TableItem; | ||||||
|  | import org.eclipse.swt.widgets.Text; | ||||||
|  | import org.eclipse.swt.widgets.Tree; | ||||||
|  | import org.eclipse.swt.widgets.TreeItem; | ||||||
|  | import org.slf4j.Logger; | ||||||
|  | import org.slf4j.LoggerFactory; | ||||||
|  | import org.springframework.context.annotation.Lazy; | ||||||
|  | import org.springframework.stereotype.Service; | ||||||
|  | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.util.Tuple; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.page.PageContext; | ||||||
|  | 
 | ||||||
|  | @Lazy | ||||||
|  | @Service | ||||||
|  | @GuiProfile | ||||||
|  | public class WidgetFactory { | ||||||
|  | 
 | ||||||
|  |     private static final Logger log = LoggerFactory.getLogger(WidgetFactory.class); | ||||||
|  | 
 | ||||||
|  |     public enum IconButtonType { | ||||||
|  |         MAXIMIZE("maximize.png"), | ||||||
|  |         MINIMIZE("minimize.png"), | ||||||
|  |         SAVE_ACTION("saveAction.png"), | ||||||
|  |         NEW_ACTION("newAction.png"), | ||||||
|  |         DELETE_ACTION("deleteAction.png"), | ||||||
|  |         ; | ||||||
|  | 
 | ||||||
|  |         private String fileName; | ||||||
|  |         private ImageData image = null; | ||||||
|  | 
 | ||||||
|  |         private IconButtonType(final String fileName) { | ||||||
|  |             this.fileName = fileName; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public Image getImage(final Device device) { | ||||||
|  |             if (this.image == null) { | ||||||
|  |                 try { | ||||||
|  |                     final InputStream resourceAsStream = | ||||||
|  |                             WidgetFactory.class.getResourceAsStream("/static/images/" + this.fileName); | ||||||
|  |                     this.image = new ImageData(resourceAsStream); | ||||||
|  |                 } catch (final Exception e) { | ||||||
|  |                     log.error("Failed to load resource image: {}", this.fileName, e); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             return new Image(device, this.image); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private final PolyglotPageService polyglotPageService; | ||||||
|  |     private final I18nSupport i18nSupport; | ||||||
|  | 
 | ||||||
|  |     public WidgetFactory(final PolyglotPageService polyglotPageService) { | ||||||
|  |         this.polyglotPageService = polyglotPageService; | ||||||
|  |         this.i18nSupport = polyglotPageService.getI18nSupport(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Button buttonLocalized(final Composite parent, final String locTextKey) { | ||||||
|  |         final Button button = new Button(parent, SWT.NONE); | ||||||
|  |         this.injectI18n(button, new LocTextKey(locTextKey)); | ||||||
|  |         return button; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Button buttonLocalized(final Composite parent, final LocTextKey locTextKey) { | ||||||
|  |         final Button button = new Button(parent, SWT.NONE); | ||||||
|  |         this.injectI18n(button, locTextKey); | ||||||
|  |         return button; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Button buttonLocalized(final Composite parent, final String style, final String locTextKey) { | ||||||
|  |         final Button button = new Button(parent, SWT.NONE); | ||||||
|  |         this.injectI18n(button, new LocTextKey(locTextKey)); | ||||||
|  |         button.setData(RWT.CUSTOM_VARIANT, style); | ||||||
|  |         return button; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Label label(final Composite parent, final String text) { | ||||||
|  |         final Label label = new Label(parent, SWT.NONE); | ||||||
|  |         label.setText(text); | ||||||
|  |         return label; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Label labelLocalized(final Composite parent, final String locTextKey) { | ||||||
|  |         final Label label = new Label(parent, SWT.NONE); | ||||||
|  |         this.injectI18n(label, new LocTextKey(locTextKey)); | ||||||
|  |         return label; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Label labelLocalized(final Composite parent, final LocTextKey locTextKey) { | ||||||
|  |         final Label label = new Label(parent, SWT.NONE); | ||||||
|  |         this.injectI18n(label, locTextKey); | ||||||
|  |         return label; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Label labelLocalized(final Composite parent, final String style, final LocTextKey locTextKey) { | ||||||
|  |         final Label label = new Label(parent, SWT.NONE); | ||||||
|  |         this.injectI18n(label, locTextKey); | ||||||
|  |         label.setData(RWT.CUSTOM_VARIANT, style); | ||||||
|  |         return label; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Label labelLocalized( | ||||||
|  |             final Composite parent, | ||||||
|  |             final LocTextKey locTextKey, | ||||||
|  |             final LocTextKey locToolTextKey) { | ||||||
|  | 
 | ||||||
|  |         final Label label = new Label(parent, SWT.NONE); | ||||||
|  |         this.injectI18n(label, locTextKey, locToolTextKey); | ||||||
|  |         return label; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Label labelLocalized( | ||||||
|  |             final Composite parent, | ||||||
|  |             final String style, | ||||||
|  |             final LocTextKey locTextKey, | ||||||
|  |             final LocTextKey locToolTextKey) { | ||||||
|  | 
 | ||||||
|  |         final Label label = new Label(parent, SWT.NONE); | ||||||
|  |         this.injectI18n(label, locTextKey, locToolTextKey); | ||||||
|  |         label.setData(RWT.CUSTOM_VARIANT, style); | ||||||
|  |         return label; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Tree treeLocalized(final Composite parent, final int style) { | ||||||
|  |         final Tree tree = new Tree(parent, SWT.SINGLE | SWT.FULL_SELECTION); | ||||||
|  |         this.injectI18n(tree); | ||||||
|  |         return tree; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public TreeItem treeItemLocalized(final Tree parent, final String locTextKey) { | ||||||
|  |         final TreeItem item = new TreeItem(parent, SWT.NONE); | ||||||
|  |         this.injectI18n(item, new LocTextKey(locTextKey)); | ||||||
|  |         return item; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public TreeItem treeItemLocalized(final Tree parent, final LocTextKey locTextKey) { | ||||||
|  |         final TreeItem item = new TreeItem(parent, SWT.NONE); | ||||||
|  |         this.injectI18n(item, locTextKey); | ||||||
|  |         return item; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public TreeItem treeItemLocalized(final TreeItem parent, final String locTextKey) { | ||||||
|  |         final TreeItem item = new TreeItem(parent, SWT.NONE); | ||||||
|  |         this.injectI18n(item, new LocTextKey(locTextKey)); | ||||||
|  |         return item; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public TreeItem treeItemLocalized(final TreeItem parent, final LocTextKey locTextKey) { | ||||||
|  |         final TreeItem item = new TreeItem(parent, SWT.NONE); | ||||||
|  |         this.injectI18n(item, locTextKey); | ||||||
|  |         return item; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Table tableLocalized(final Composite parent) { | ||||||
|  |         final Table table = new Table(parent, SWT.NONE); | ||||||
|  |         this.injectI18n(table); | ||||||
|  |         return table; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public TableColumn tableColumnLocalized(final Table table, final String locTextKey) { | ||||||
|  |         final TableColumn tableColumn = new TableColumn(table, SWT.NONE); | ||||||
|  |         this.injectI18n(tableColumn, new LocTextKey(locTextKey)); | ||||||
|  |         return tableColumn; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Label labelSeparator(final Composite parent) { | ||||||
|  |         final Label label = new Label(parent, SWT.SEPARATOR); | ||||||
|  |         return label; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Label imageButton( | ||||||
|  |             final IconButtonType type, | ||||||
|  |             final Composite parent, | ||||||
|  |             final LocTextKey toolTip, | ||||||
|  |             final Listener listener) { | ||||||
|  | 
 | ||||||
|  |         final Label imageButton = labelLocalized(parent, (LocTextKey) null, toolTip); | ||||||
|  |         imageButton.setData(RWT.CUSTOM_VARIANT, "imageButton"); | ||||||
|  |         imageButton.setImage(type.getImage(parent.getDisplay())); | ||||||
|  |         if (listener != null) { | ||||||
|  |             imageButton.addListener(SWT.MouseDown, listener); | ||||||
|  |         } | ||||||
|  |         return imageButton; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Label formLabelLocalized(final Composite parent, final String locTextKey) { | ||||||
|  |         final Label label = labelLocalized(parent, locTextKey); | ||||||
|  |         final GridData gridData = new GridData(SWT.RIGHT, SWT.CENTER, true, false); | ||||||
|  |         label.setLayoutData(gridData); | ||||||
|  |         return label; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Label formValueLabel(final Composite parent, final String value, final int span) { | ||||||
|  |         final Label label = new Label(parent, SWT.NONE); | ||||||
|  |         label.setText(value); | ||||||
|  |         final GridData gridData = new GridData(SWT.LEFT, SWT.CENTER, true, false, span, 1); | ||||||
|  |         label.setLayoutData(gridData); | ||||||
|  |         return label; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Text formTextInput(final Composite parent, final String value) { | ||||||
|  |         return formTextInput(parent, value, 1, 1); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Text formTextInput(final Composite parent, final String value, final int hspan, final int vspan) { | ||||||
|  |         final Text textInput = new Text(parent, SWT.LEFT | SWT.BORDER); | ||||||
|  |         final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false, hspan, vspan); | ||||||
|  |         gridData.heightHint = 15; | ||||||
|  |         textInput.setLayoutData(gridData); | ||||||
|  |         textInput.setText(value); | ||||||
|  |         return textInput; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Combo formSingleSelectionLocalized( | ||||||
|  |             final Composite parent, | ||||||
|  |             final String selection, | ||||||
|  |             final List<Tuple<String>> items) { | ||||||
|  | 
 | ||||||
|  |         return formSingleSelectionLocalized(parent, selection, items, 1, 1); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Combo formSingleSelectionLocalized( | ||||||
|  |             final Composite parent, | ||||||
|  |             final String selection, | ||||||
|  |             final List<Tuple<String>> items, | ||||||
|  |             final int hspan, final int vspan) { | ||||||
|  | 
 | ||||||
|  |         final SingleSelection combo = singleSelectionLocalized(parent, items); | ||||||
|  |         final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false, hspan, vspan); | ||||||
|  |         gridData.heightHint = 25; | ||||||
|  |         combo.setLayoutData(gridData); | ||||||
|  |         combo.select(selection); | ||||||
|  |         return combo; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void formEmpty(final Composite parent) { | ||||||
|  |         formEmpty(parent, 1, 1); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void formEmpty(final Composite parent, final int hspan, final int vspan) { | ||||||
|  |         final Label empty = new Label(parent, SWT.LEFT); | ||||||
|  |         empty.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, hspan, vspan)); | ||||||
|  |         empty.setText(""); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public SingleSelection singleSelectionLocalized( | ||||||
|  |             final Composite parent, | ||||||
|  |             final List<Tuple<String>> items) { | ||||||
|  | 
 | ||||||
|  |         final SingleSelection combo = new SingleSelection(parent, items); | ||||||
|  |         this.injectI18n(combo, combo.valueMapping); | ||||||
|  |         return combo; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void injectI18n(final Label label, final LocTextKey locTextKey) { | ||||||
|  |         injectI18n(label, locTextKey, null); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void injectI18n(final Label label, final LocTextKey locTextKey, final LocTextKey locToolTipKey) { | ||||||
|  |         final Consumer<Label> labelFunction = labelFunction(locTextKey, locToolTipKey, this.i18nSupport); | ||||||
|  |         label.setData(POLYGLOT_WIDGET_FUNCTION_KEY, labelFunction); | ||||||
|  |         labelFunction.accept(label); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void injectI18n(final Button button, final LocTextKey locTextKey) { | ||||||
|  |         injectI18n(button, locTextKey, null); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void injectI18n(final Button button, final LocTextKey locTextKey, final LocTextKey locToolTipKey) { | ||||||
|  |         final Consumer<Button> buttonFunction = buttonFunction(locTextKey, locToolTipKey, this.i18nSupport); | ||||||
|  |         button.setData(POLYGLOT_WIDGET_FUNCTION_KEY, buttonFunction); | ||||||
|  |         buttonFunction.accept(button); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void injectI18n(final Tree tree) { | ||||||
|  |         tree.setData(POLYGLOT_WIDGET_FUNCTION_KEY, treeFunction(this.i18nSupport)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void injectI18n(final TreeItem treeItem, final LocTextKey locTextKey) { | ||||||
|  |         treeItem.setData(POLYGLOT_TREE_ITEM_TEXT_DATA_KEY, locTextKey); | ||||||
|  |         treeItem.setText(this.i18nSupport.getText(locTextKey)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void injectI18n(final Table table) { | ||||||
|  |         table.setData(POLYGLOT_WIDGET_FUNCTION_KEY, tableFunction(this.i18nSupport)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void injectI18n(final TableColumn tableColumn, final LocTextKey locTextKey) { | ||||||
|  |         tableColumn.setData(POLYGLOT_TREE_ITEM_TEXT_DATA_KEY, locTextKey); | ||||||
|  |         tableColumn.setText(this.i18nSupport.getText(locTextKey)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void injectI18n(final TableItem tableItem, final LocTextKey... locTextKey) { | ||||||
|  |         if (locTextKey == null) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         tableItem.setData(POLYGLOT_TREE_ITEM_TEXT_DATA_KEY, locTextKey); | ||||||
|  |         for (int i = 0; i < locTextKey.length; i++) { | ||||||
|  |             tableItem.setText(i, this.i18nSupport.getText(locTextKey[i])); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void injectI18n(final Combo combo, final List<String> items) { | ||||||
|  |         final Consumer<Combo> comboFunction = comboFunction(items, this.i18nSupport); | ||||||
|  |         combo.setData(POLYGLOT_WIDGET_FUNCTION_KEY, comboFunction); | ||||||
|  |         comboFunction.accept(combo); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void createLanguageSelector(final PageContext composerCtx) { | ||||||
|  |         for (final Locale locale : this.i18nSupport.supportedLanguages()) { | ||||||
|  |             final Label languageSelection = new Label(composerCtx.getParent(), SWT.NONE); | ||||||
|  |             languageSelection.setData(POLYGLOT_WIDGET_FUNCTION_KEY, | ||||||
|  |                     langSelectionLabelFunction(locale, this.i18nSupport)); | ||||||
|  |             languageSelection.setData(RWT.CUSTOM_VARIANT, "header"); | ||||||
|  |             languageSelection.setText("|  " + locale.getLanguage().toUpperCase()); | ||||||
|  |             //languageSelection.updateLocale(this.i18nSupport); | ||||||
|  |             languageSelection.addListener(SWT.MouseDown, event -> { | ||||||
|  |                 this.polyglotPageService.setPageLocale(composerCtx.getRoot(), locale); | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private static Consumer<Tree> treeFunction(final I18nSupport i18nSupport) { | ||||||
|  |         return tree -> updateLocale(tree.getItems(), i18nSupport); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private static Consumer<Table> tableFunction(final I18nSupport i18nSupport) { | ||||||
|  |         return table -> { | ||||||
|  |             updateLocale(table.getColumns(), i18nSupport); | ||||||
|  |             updateLocale(table.getItems(), i18nSupport); | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private static final Consumer<Label> langSelectionLabelFunction( | ||||||
|  |             final Locale locale, | ||||||
|  |             final I18nSupport i18nSupport) { | ||||||
|  | 
 | ||||||
|  |         return label -> label.setVisible( | ||||||
|  |                 !i18nSupport.getCurrentLocale() | ||||||
|  |                         .getLanguage() | ||||||
|  |                         .equals(locale.getLanguage())); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private static final Consumer<Label> labelFunction( | ||||||
|  |             final LocTextKey locTextKey, | ||||||
|  |             final LocTextKey locToolTipKey, | ||||||
|  |             final I18nSupport i18nSupport) { | ||||||
|  | 
 | ||||||
|  |         return label -> { | ||||||
|  |             if (locTextKey != null) { | ||||||
|  |                 label.setText(i18nSupport.getText(locTextKey)); | ||||||
|  |             } | ||||||
|  |             if (locToolTipKey != null) { | ||||||
|  |                 label.setToolTipText(i18nSupport.getText(locToolTipKey)); | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private static final Consumer<Combo> comboFunction( | ||||||
|  |             final List<String> items, | ||||||
|  |             final I18nSupport i18nSupport) { | ||||||
|  | 
 | ||||||
|  |         return combo -> { | ||||||
|  |             int i = 0; | ||||||
|  |             final Iterator<String> iterator = items.iterator(); | ||||||
|  |             while (iterator.hasNext()) { | ||||||
|  |                 combo.setItem(i, i18nSupport.getText(iterator.next())); | ||||||
|  |                 i++; | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private static final Consumer<Button> buttonFunction( | ||||||
|  |             final LocTextKey locTextKey, | ||||||
|  |             final LocTextKey locToolTipKey, | ||||||
|  |             final I18nSupport i18nSupport) { | ||||||
|  | 
 | ||||||
|  |         return button -> { | ||||||
|  |             if (locTextKey != null) { | ||||||
|  |                 button.setText(i18nSupport.getText(locTextKey)); | ||||||
|  |             } | ||||||
|  |             if (locToolTipKey != null) { | ||||||
|  |                 button.setToolTipText(i18nSupport.getText(locToolTipKey)); | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private static final void updateLocale(final TreeItem[] items, final I18nSupport i18nSupport) { | ||||||
|  |         if (items == null) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         for (final TreeItem childItem : items) { | ||||||
|  |             final LocTextKey locTextKey = (LocTextKey) childItem.getData(POLYGLOT_TREE_ITEM_TEXT_DATA_KEY); | ||||||
|  |             if (locTextKey != null) { | ||||||
|  |                 childItem.setText(i18nSupport.getText(locTextKey)); | ||||||
|  |             } | ||||||
|  |             updateLocale(childItem.getItems(), i18nSupport); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private static void updateLocale(final TableItem[] items, final I18nSupport i18nSupport) { | ||||||
|  |         if (items == null) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         for (final TableItem childItem : items) { | ||||||
|  |             final LocTextKey[] locTextKey = (LocTextKey[]) childItem.getData(POLYGLOT_TREE_ITEM_TEXT_DATA_KEY); | ||||||
|  |             if (locTextKey != null) { | ||||||
|  |                 for (int i = 0; i < locTextKey.length; i++) { | ||||||
|  |                     if (locTextKey[i] != null) { | ||||||
|  |                         childItem.setText(i, i18nSupport.getText(locTextKey[i])); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private static void updateLocale(final TableColumn[] columns, final I18nSupport i18nSupport) { | ||||||
|  |         if (columns == null) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         for (final TableColumn childItem : columns) { | ||||||
|  |             final LocTextKey locTextKey = (LocTextKey) childItem.getData(POLYGLOT_TREE_ITEM_TEXT_DATA_KEY); | ||||||
|  |             if (locTextKey != null) { | ||||||
|  |                 childItem.setText(i18nSupport.getText(locTextKey)); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -43,19 +43,19 @@ public interface BulkActionSupportDAO<T extends Entity> { | ||||||
|                 return (this instanceof ActivatableEntityDAO) |                 return (this instanceof ActivatableEntityDAO) | ||||||
|                         ? ((ActivatableEntityDAO<?, ?>) this).setActive(all, true) |                         ? ((ActivatableEntityDAO<?, ?>) this).setActive(all, true) | ||||||
|                                 .map(BulkActionSupportDAO::transformResult) |                                 .map(BulkActionSupportDAO::transformResult) | ||||||
|                                 .getOrHandleError(error -> handleBulkActionError(error, all)) |                                 .get(error -> handleBulkActionError(error, all)) | ||||||
|                         : Collections.emptyList(); |                         : Collections.emptyList(); | ||||||
|             case DEACTIVATE: |             case DEACTIVATE: | ||||||
|                 return (this instanceof ActivatableEntityDAO) |                 return (this instanceof ActivatableEntityDAO) | ||||||
|                         ? ((ActivatableEntityDAO<?, ?>) this).setActive(all, false) |                         ? ((ActivatableEntityDAO<?, ?>) this).setActive(all, false) | ||||||
|                                 .map(BulkActionSupportDAO::transformResult) |                                 .map(BulkActionSupportDAO::transformResult) | ||||||
|                                 .getOrHandleError(error -> handleBulkActionError(error, all)) |                                 .get(error -> handleBulkActionError(error, all)) | ||||||
|                         : Collections.emptyList(); |                         : Collections.emptyList(); | ||||||
|             case HARD_DELETE: |             case HARD_DELETE: | ||||||
|                 return (this instanceof EntityDAO) |                 return (this instanceof EntityDAO) | ||||||
|                         ? ((EntityDAO<?, ?>) this).delete(all) |                         ? ((EntityDAO<?, ?>) this).delete(all) | ||||||
|                                 .map(BulkActionSupportDAO::transformResult) |                                 .map(BulkActionSupportDAO::transformResult) | ||||||
|                                 .getOrHandleError(error -> handleBulkActionError(error, all)) |                                 .get(error -> handleBulkActionError(error, all)) | ||||||
|                         : Collections.emptyList(); |                         : Collections.emptyList(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -19,7 +19,7 @@ import org.springframework.transaction.annotation.Transactional; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Entity; | import ch.ethz.seb.sebserver.gbl.model.Entity; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.EntityKey; | import ch.ethz.seb.sebserver.gbl.model.EntityKey; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.EntityKeyAndName; | import ch.ethz.seb.sebserver.gbl.model.EntityName; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.EntityType; | import ch.ethz.seb.sebserver.gbl.model.EntityType; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.ModelIdAware; | import ch.ethz.seb.sebserver.gbl.model.ModelIdAware; | ||||||
| import ch.ethz.seb.sebserver.gbl.util.Result; | import ch.ethz.seb.sebserver.gbl.util.Result; | ||||||
|  | @ -66,12 +66,12 @@ public interface EntityDAO<T extends Entity, M extends ModelIdAware> { | ||||||
|     Result<Collection<T>> loadEntities(Collection<EntityKey> keys); |     Result<Collection<T>> loadEntities(Collection<EntityKey> keys); | ||||||
| 
 | 
 | ||||||
|     @Transactional(readOnly = true) |     @Transactional(readOnly = true) | ||||||
|     default Result<Collection<EntityKeyAndName>> loadEntityNames(final Collection<EntityKey> keys) { |     default Result<Collection<EntityName>> loadEntityNames(final Collection<EntityKey> keys) { | ||||||
|         return Result.tryCatch(() -> { |         return Result.tryCatch(() -> { | ||||||
|             return loadEntities(keys) |             return loadEntities(keys) | ||||||
|                     .getOrThrow() |                     .getOrThrow() | ||||||
|                     .stream() |                     .stream() | ||||||
|                     .map(entity -> new EntityKeyAndName( |                     .map(entity -> new EntityName( | ||||||
|                             entity.entityType(), |                             entity.entityType(), | ||||||
|                             entity.getModelId(), |                             entity.getModelId(), | ||||||
|                             entity.getName())) |                             entity.getName())) | ||||||
|  |  | ||||||
|  | @ -11,7 +11,7 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.dao; | ||||||
| import org.joda.time.DateTime; | import org.joda.time.DateTime; | ||||||
| import org.springframework.util.MultiValueMap; | import org.springframework.util.MultiValueMap; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.gbl.POSTMapper; | import ch.ethz.seb.sebserver.gbl.api.POSTMapper; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.exam.Exam; | import ch.ethz.seb.sebserver.gbl.model.exam.Exam; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.exam.Indicator; | import ch.ethz.seb.sebserver.gbl.model.exam.Indicator; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup; | import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup; | ||||||
|  |  | ||||||
|  | @ -32,8 +32,8 @@ import org.springframework.stereotype.Component; | ||||||
| import org.springframework.transaction.annotation.Transactional; | import org.springframework.transaction.annotation.Transactional; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.WebSecurityConfig; | import ch.ethz.seb.sebserver.WebSecurityConfig; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.APIMessage.APIMessageException; | import ch.ethz.seb.sebserver.gbl.api.APIMessage.APIMessageException; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.APIMessage.ErrorMessage; | import ch.ethz.seb.sebserver.gbl.api.APIMessage.ErrorMessage; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.EntityKey; | import ch.ethz.seb.sebserver.gbl.model.EntityKey; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.EntityType; | import ch.ethz.seb.sebserver.gbl.model.EntityType; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; | import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; | ||||||
|  |  | ||||||
|  | @ -22,6 +22,7 @@ import org.springframework.beans.factory.annotation.Value; | ||||||
| import org.springframework.context.annotation.Bean; | import org.springframework.context.annotation.Bean; | ||||||
| import org.springframework.context.annotation.Configuration; | import org.springframework.context.annotation.Configuration; | ||||||
| import org.springframework.core.annotation.Order; | import org.springframework.core.annotation.Order; | ||||||
|  | import org.springframework.http.HttpStatus; | ||||||
| import org.springframework.http.MediaType; | import org.springframework.http.MediaType; | ||||||
| import org.springframework.security.authentication.AuthenticationManager; | import org.springframework.security.authentication.AuthenticationManager; | ||||||
| import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; | ||||||
|  | @ -219,6 +220,7 @@ public class ClientSessionWebSecurityConfig extends WebSecurityConfigurerAdapter | ||||||
|             log.warn("Unauthorized Request: {} : Redirect to login after unauthorized request", |             log.warn("Unauthorized Request: {} : Redirect to login after unauthorized request", | ||||||
|                     request.getRequestURI()); |                     request.getRequestURI()); | ||||||
| 
 | 
 | ||||||
|  |             response.setStatus(HttpStatus.UNAUTHORIZED.value()); | ||||||
|             response.sendRedirect(this.redirect); |             response.sendRedirect(this.redirect); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -31,8 +31,8 @@ public class WebServiceUserDetails implements UserDetailsService { | ||||||
|     @Override |     @Override | ||||||
|     public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException { |     public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException { | ||||||
|         return this.userDAO.sebServerUserByUsername(username) |         return this.userDAO.sebServerUserByUsername(username) | ||||||
|                 .getOrHandleError(t -> { |                 .get(error -> { | ||||||
|                     throw new UsernameNotFoundException("No User with name: " + username + " found", t); |                     throw new UsernameNotFoundException("No User with name: " + username + " found", error); | ||||||
|                 }); |                 }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -10,6 +10,7 @@ package ch.ethz.seb.sebserver.webservice.weblayer.api; | ||||||
| 
 | 
 | ||||||
| import java.util.Arrays; | import java.util.Arrays; | ||||||
| import java.util.Collection; | import java.util.Collection; | ||||||
|  | import java.util.List; | ||||||
| import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||||
| 
 | 
 | ||||||
| import org.slf4j.Logger; | import org.slf4j.Logger; | ||||||
|  | @ -26,8 +27,8 @@ import org.springframework.web.bind.annotation.ExceptionHandler; | ||||||
| import org.springframework.web.context.request.WebRequest; | import org.springframework.web.context.request.WebRequest; | ||||||
| import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; | import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.gbl.model.APIMessage; | import ch.ethz.seb.sebserver.gbl.api.APIMessage; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.APIMessage.APIMessageException; | import ch.ethz.seb.sebserver.gbl.api.APIMessage.APIMessageException; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.PermissionDeniedException; | import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.PermissionDeniedException; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ResourceNotFoundException; | import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ResourceNotFoundException; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationException; | import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationException; | ||||||
|  | @ -47,7 +48,8 @@ public class APIExceptionHandler extends ResponseEntityExceptionHandler { | ||||||
|             final WebRequest request) { |             final WebRequest request) { | ||||||
| 
 | 
 | ||||||
|         log.error("Unexpected generic error catched at the API endpoint: ", ex); |         log.error("Unexpected generic error catched at the API endpoint: ", ex); | ||||||
|         return new ResponseEntity<>(APIMessage.ErrorMessage.GENERIC.of(ex.getMessage()), status); |         final List<APIMessage> errors = Arrays.asList(APIMessage.ErrorMessage.GENERIC.of(ex.getMessage())); | ||||||
|  |         return new ResponseEntity<>(errors, status); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|  |  | ||||||
|  | @ -28,11 +28,11 @@ import org.springframework.web.bind.annotation.RequestMethod; | ||||||
| import org.springframework.web.bind.annotation.RequestParam; | import org.springframework.web.bind.annotation.RequestParam; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.gbl.Constants; | import ch.ethz.seb.sebserver.gbl.Constants; | ||||||
| import ch.ethz.seb.sebserver.gbl.POSTMapper; | import ch.ethz.seb.sebserver.gbl.api.POSTMapper; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Domain; | import ch.ethz.seb.sebserver.gbl.model.Domain; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Entity; | import ch.ethz.seb.sebserver.gbl.model.Entity; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.EntityKey; | import ch.ethz.seb.sebserver.gbl.model.EntityKey; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.EntityKeyAndName; | import ch.ethz.seb.sebserver.gbl.model.EntityName; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport; | import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.EntityType; | import ch.ethz.seb.sebserver.gbl.model.EntityType; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Page; | import ch.ethz.seb.sebserver.gbl.model.Page; | ||||||
|  | @ -124,7 +124,7 @@ public abstract class EntityController<T extends GrantEntity, M extends GrantEnt | ||||||
|             method = RequestMethod.GET, |             method = RequestMethod.GET, | ||||||
|             consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, |             consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, | ||||||
|             produces = MediaType.APPLICATION_JSON_VALUE) |             produces = MediaType.APPLICATION_JSON_VALUE) | ||||||
|     public Collection<EntityKeyAndName> getNames( |     public Collection<EntityName> getNames( | ||||||
|             @RequestParam( |             @RequestParam( | ||||||
|                     name = Entity.FILTER_ATTR_INSTITUTION, |                     name = Entity.FILTER_ATTR_INSTITUTION, | ||||||
|                     required = true, |                     required = true, | ||||||
|  |  | ||||||
|  | @ -30,8 +30,9 @@ import org.springframework.web.bind.annotation.RequestMethod; | ||||||
| import org.springframework.web.bind.annotation.RequestParam; | import org.springframework.web.bind.annotation.RequestParam; | ||||||
| import org.springframework.web.bind.annotation.RestController; | import org.springframework.web.bind.annotation.RestController; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.gbl.POSTMapper; |  | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Domain.LMS_SETUP; | import ch.ethz.seb.sebserver.gbl.model.Domain.LMS_SETUP; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.api.POSTMapper; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.api.SEBServerRestEndpoints; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Entity; | import ch.ethz.seb.sebserver.gbl.model.Entity; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.EntityKey; | import ch.ethz.seb.sebserver.gbl.model.EntityKey; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.EntityType; | import ch.ethz.seb.sebserver.gbl.model.EntityType; | ||||||
|  | @ -58,7 +59,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationSe | ||||||
| 
 | 
 | ||||||
| @WebServiceProfile | @WebServiceProfile | ||||||
| @RestController | @RestController | ||||||
| @RequestMapping("/${sebserver.webservice.api.admin.endpoint}" + RestAPI.ENDPOINT_EXAM_ADMINISTRATION) | @RequestMapping("/${sebserver.webservice.api.admin.endpoint}" + SEBServerRestEndpoints.ENDPOINT_EXAM_ADMINISTRATION) | ||||||
| public class ExamAdministrationController extends ActivatableEntityController<Exam, Exam> { | public class ExamAdministrationController extends ActivatableEntityController<Exam, Exam> { | ||||||
| 
 | 
 | ||||||
|     private final ExamDAO examDAO; |     private final ExamDAO examDAO; | ||||||
|  |  | ||||||
|  | @ -13,7 +13,8 @@ import org.springframework.web.bind.annotation.RequestMapping; | ||||||
| import org.springframework.web.bind.annotation.RequestMethod; | import org.springframework.web.bind.annotation.RequestMethod; | ||||||
| import org.springframework.web.bind.annotation.RestController; | import org.springframework.web.bind.annotation.RestController; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.gbl.POSTMapper; | import ch.ethz.seb.sebserver.gbl.api.POSTMapper; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.api.SEBServerRestEndpoints; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.institution.Institution; | import ch.ethz.seb.sebserver.gbl.model.institution.Institution; | ||||||
| import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; | import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; | ||||||
| import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.InstitutionRecordDynamicSqlSupport; | import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.InstitutionRecordDynamicSqlSupport; | ||||||
|  | @ -27,7 +28,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationSe | ||||||
| 
 | 
 | ||||||
| @WebServiceProfile | @WebServiceProfile | ||||||
| @RestController | @RestController | ||||||
| @RequestMapping("/${sebserver.webservice.api.admin.endpoint}" + RestAPI.ENDPOINT_INSTITUTION) | @RequestMapping("/${sebserver.webservice.api.admin.endpoint}" + SEBServerRestEndpoints.ENDPOINT_INSTITUTION) | ||||||
| public class InstitutionController extends ActivatableEntityController<Institution, Institution> { | public class InstitutionController extends ActivatableEntityController<Institution, Institution> { | ||||||
| 
 | 
 | ||||||
|     private final InstitutionDAO institutionDAO; |     private final InstitutionDAO institutionDAO; | ||||||
|  |  | ||||||
|  | @ -21,7 +21,8 @@ import org.springframework.web.bind.annotation.RequestMapping; | ||||||
| import org.springframework.web.bind.annotation.RequestMethod; | import org.springframework.web.bind.annotation.RequestMethod; | ||||||
| import org.springframework.web.bind.annotation.RestController; | import org.springframework.web.bind.annotation.RestController; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.gbl.POSTMapper; | import ch.ethz.seb.sebserver.gbl.api.POSTMapper; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.api.SEBServerRestEndpoints; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.EntityType; | import ch.ethz.seb.sebserver.gbl.model.EntityType; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup; | import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup; | ||||||
| import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; | import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; | ||||||
|  | @ -37,7 +38,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationSe | ||||||
| 
 | 
 | ||||||
| @WebServiceProfile | @WebServiceProfile | ||||||
| @RestController | @RestController | ||||||
| @RequestMapping("/${sebserver.webservice.api.admin.endpoint}" + RestAPI.ENDPOINT_LMS_SETUP) | @RequestMapping("/${sebserver.webservice.api.admin.endpoint}" + SEBServerRestEndpoints.ENDPOINT_LMS_SETUP) | ||||||
| public class LmsSetupController extends ActivatableEntityController<LmsSetup, LmsSetup> { | public class LmsSetupController extends ActivatableEntityController<LmsSetup, LmsSetup> { | ||||||
| 
 | 
 | ||||||
|     private final LmsAPIService lmsAPIService; |     private final LmsAPIService lmsAPIService; | ||||||
|  |  | ||||||
|  | @ -15,6 +15,7 @@ import org.springframework.web.bind.annotation.RequestParam; | ||||||
| import org.springframework.web.bind.annotation.RestController; | import org.springframework.web.bind.annotation.RestController; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Domain.LMS_SETUP; | import ch.ethz.seb.sebserver.gbl.model.Domain.LMS_SETUP; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.api.SEBServerRestEndpoints; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.EntityType; | import ch.ethz.seb.sebserver.gbl.model.EntityType; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Page; | import ch.ethz.seb.sebserver.gbl.model.Page; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.exam.QuizData; | import ch.ethz.seb.sebserver.gbl.model.exam.QuizData; | ||||||
|  | @ -27,7 +28,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplate; | ||||||
| 
 | 
 | ||||||
| @WebServiceProfile | @WebServiceProfile | ||||||
| @RestController | @RestController | ||||||
| @RequestMapping("/${sebserver.webservice.api.admin.endpoint}" + RestAPI.ENDPOINT_QUIZ_IMPORT) | @RequestMapping("/${sebserver.webservice.api.admin.endpoint}" + SEBServerRestEndpoints.ENDPOINT_QUIZ_IMPORT) | ||||||
| public class QuizImportController { | public class QuizImportController { | ||||||
| 
 | 
 | ||||||
|     private final int defaultPageSize; |     private final int defaultPageSize; | ||||||
|  |  | ||||||
|  | @ -14,7 +14,8 @@ import org.springframework.web.bind.annotation.RequestMapping; | ||||||
| import org.springframework.web.bind.annotation.RequestMethod; | import org.springframework.web.bind.annotation.RequestMethod; | ||||||
| import org.springframework.web.bind.annotation.RestController; | import org.springframework.web.bind.annotation.RestController; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.gbl.POSTMapper; | import ch.ethz.seb.sebserver.gbl.api.POSTMapper; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.api.SEBServerRestEndpoints; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; | import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.user.UserMod; | import ch.ethz.seb.sebserver.gbl.model.user.UserMod; | ||||||
| import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; | import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; | ||||||
|  | @ -30,7 +31,7 @@ import ch.ethz.seb.sebserver.webservice.weblayer.oauth.RevokeTokenEndpoint; | ||||||
| 
 | 
 | ||||||
| @WebServiceProfile | @WebServiceProfile | ||||||
| @RestController | @RestController | ||||||
| @RequestMapping("${sebserver.webservice.api.admin.endpoint}" + RestAPI.ENDPOINT_USER_ACCOUNT) | @RequestMapping("${sebserver.webservice.api.admin.endpoint}" + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT) | ||||||
| public class UserAccountController extends ActivatableEntityController<UserInfo, UserMod> { | public class UserAccountController extends ActivatableEntityController<UserInfo, UserMod> { | ||||||
| 
 | 
 | ||||||
|     private final ApplicationEventPublisher applicationEventPublisher; |     private final ApplicationEventPublisher applicationEventPublisher; | ||||||
|  |  | ||||||
|  | @ -17,6 +17,7 @@ import org.springframework.web.bind.annotation.RequestMethod; | ||||||
| import org.springframework.web.bind.annotation.RequestParam; | import org.springframework.web.bind.annotation.RequestParam; | ||||||
| import org.springframework.web.bind.annotation.RestController; | import org.springframework.web.bind.annotation.RestController; | ||||||
| 
 | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gbl.api.SEBServerRestEndpoints; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.EntityType; | import ch.ethz.seb.sebserver.gbl.model.EntityType; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Page; | import ch.ethz.seb.sebserver.gbl.model.Page; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog; | import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog; | ||||||
|  | @ -32,7 +33,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO; | ||||||
| 
 | 
 | ||||||
| @WebServiceProfile | @WebServiceProfile | ||||||
| @RestController | @RestController | ||||||
| @RequestMapping("/${sebserver.webservice.api.admin.endpoint}" + RestAPI.ENDPOINT_USER_ACTIVITY_LOG) | @RequestMapping("/${sebserver.webservice.api.admin.endpoint}" + SEBServerRestEndpoints.ENDPOINT_USER_ACTIVITY_LOG) | ||||||
| public class UserActivityLogController { | public class UserActivityLogController { | ||||||
| 
 | 
 | ||||||
|     private final UserActivityLogDAO userActivityLogDAO; |     private final UserActivityLogDAO userActivityLogDAO; | ||||||
|  |  | ||||||
|  | @ -1,2 +1,4 @@ | ||||||
| spring.application.name=SEB Server | spring.application.name=SEB Server | ||||||
| spring.profiles.active=dev | spring.profiles.active=dev | ||||||
|  | 
 | ||||||
|  | sebserver.version=1.0 beta | ||||||
							
								
								
									
										0
									
								
								src/main/resources/messages-de.properties
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								src/main/resources/messages-de.properties
									
										
									
									
									
										Normal file
									
								
							
							
								
								
									
										31
									
								
								src/main/resources/messages.properties
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/main/resources/messages.properties
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,31 @@ | ||||||
|  | ################################ | ||||||
|  | # Overall | ||||||
|  | ################################ | ||||||
|  | 
 | ||||||
|  | sebserver.overall.version=SEB Server Version : {0} | ||||||
|  | sebserver.overall.imprint=Imprint | ||||||
|  | sebserver.overall.about=About | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ################################ | ||||||
|  | # Login Page | ||||||
|  | ################################ | ||||||
|  | 
 | ||||||
|  | sebserver.login.username=User Name | ||||||
|  | sebserver.login.pwd=Password | ||||||
|  | sebserver.login.login=Sign In | ||||||
|  | sebserver.login.failed.title=Login Failed | ||||||
|  | sebserver.login.failed.message=Access Denied: Wrong username or password | ||||||
|  | 
 | ||||||
|  | ################################ | ||||||
|  | # Main Page | ||||||
|  | ################################ | ||||||
|  | 
 | ||||||
|  | sebserver.logout=Logout | ||||||
|  | sebserver.mainpage.maximize.tooltip=Maximize | ||||||
|  | sebserver.mainpage.minimize.tooltip=Minimize | ||||||
|  | sebserver.activitiespane.title=Activities | ||||||
|  | sebserver.actionpane.title=Actions | ||||||
|  | sebserver.activities.inst=Institution | ||||||
|  | 
 | ||||||
|  | sebserver.error.unexpected=Unexpected Error | ||||||
|  | @ -84,7 +84,7 @@ Composite.content { | ||||||
|     margin: 0 0 0 0; |     margin: 0 0 0 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Composite.selectionPane { | Composite.actionPane { | ||||||
|     background-color: #D3D9DB; |     background-color: #D3D9DB; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -14,7 +14,7 @@ import java.io.IOException; | ||||||
| 
 | 
 | ||||||
| import org.junit.Test; | import org.junit.Test; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.gbl.JSONMapper; | import ch.ethz.seb.sebserver.gbl.api.JSONMapper; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.EntityType; | import ch.ethz.seb.sebserver.gbl.model.EntityType; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO.ActivityType; | import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO.ActivityType; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -75,8 +75,8 @@ public class ResultTest { | ||||||
|         final Result<String> resultOf = Result.of("ONE"); |         final Result<String> resultOf = Result.of("ONE"); | ||||||
|         final Result<String> resultOfError = Result.ofError(new RuntimeException("Some Error")); |         final Result<String> resultOfError = Result.ofError(new RuntimeException("Some Error")); | ||||||
| 
 | 
 | ||||||
|         assertEquals("ONE", resultOf.getOrElse("TWO")); |         assertEquals("ONE", resultOf.getOr("TWO")); | ||||||
|         assertEquals("TWO", resultOfError.getOrElse("TWO")); |         assertEquals("TWO", resultOfError.getOr("TWO")); | ||||||
| 
 | 
 | ||||||
|         assertEquals("ONE", resultOf.getOrElse(() -> "TWO")); |         assertEquals("ONE", resultOf.getOrElse(() -> "TWO")); | ||||||
|         assertEquals("TWO", resultOfError.getOrElse(() -> "TWO")); |         assertEquals("TWO", resultOfError.getOrElse(() -> "TWO")); | ||||||
|  | @ -87,8 +87,8 @@ public class ResultTest { | ||||||
|         final Result<String> resultOf = Result.of("ONE"); |         final Result<String> resultOf = Result.of("ONE"); | ||||||
|         final Result<String> resultOfError = Result.ofError(new RuntimeException("Some Error")); |         final Result<String> resultOfError = Result.ofError(new RuntimeException("Some Error")); | ||||||
| 
 | 
 | ||||||
|         assertEquals("ONE", resultOf.getOrHandleError(t -> t.getMessage())); |         assertEquals("ONE", resultOf.get(t -> t.getMessage())); | ||||||
|         assertEquals("Some Error", resultOfError.getOrHandleError(t -> t.getMessage())); |         assertEquals("Some Error", resultOfError.get(t -> t.getMessage())); | ||||||
| 
 | 
 | ||||||
|         assertEquals("ONE", resultOf.getOrThrowRuntime("Should not be thrown")); |         assertEquals("ONE", resultOf.getOrThrowRuntime("Should not be thrown")); | ||||||
|         try { |         try { | ||||||
|  |  | ||||||
|  | @ -41,7 +41,7 @@ import org.springframework.web.context.WebApplicationContext; | ||||||
| import com.fasterxml.jackson.core.type.TypeReference; | import com.fasterxml.jackson.core.type.TypeReference; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.SEBServer; | import ch.ethz.seb.sebserver.SEBServer; | ||||||
| import ch.ethz.seb.sebserver.gbl.JSONMapper; | import ch.ethz.seb.sebserver.gbl.api.JSONMapper; | ||||||
| 
 | 
 | ||||||
| @RunWith(SpringRunner.class) | @RunWith(SpringRunner.class) | ||||||
| @SpringBootTest( | @SpringBootTest( | ||||||
|  |  | ||||||
|  | @ -19,11 +19,11 @@ import org.springframework.test.context.jdbc.Sql; | ||||||
| 
 | 
 | ||||||
| import com.fasterxml.jackson.core.type.TypeReference; | import com.fasterxml.jackson.core.type.TypeReference; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.gbl.model.APIMessage; | import ch.ethz.seb.sebserver.gbl.api.APIMessage; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.api.SEBServerRestEndpoints; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport; | import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Page; | import ch.ethz.seb.sebserver.gbl.model.Page; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.institution.Institution; | import ch.ethz.seb.sebserver.gbl.model.institution.Institution; | ||||||
| import ch.ethz.seb.sebserver.webservice.weblayer.api.RestAPI; |  | ||||||
| 
 | 
 | ||||||
| @Sql(scripts = { "classpath:schema-test.sql", "classpath:data-test.sql" }) | @Sql(scripts = { "classpath:schema-test.sql", "classpath:data-test.sql" }) | ||||||
| public class InstitutionAPITest extends AdministrationAPIIntegrationTester { | public class InstitutionAPITest extends AdministrationAPIIntegrationTester { | ||||||
|  | @ -32,7 +32,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester { | ||||||
|     public void getInstitutions() throws Exception { |     public void getInstitutions() throws Exception { | ||||||
|         Page<Institution> institutions = new RestAPITestHelper() |         Page<Institution> institutions = new RestAPITestHelper() | ||||||
|                 .withAccessToken(getSebAdminAccess()) |                 .withAccessToken(getSebAdminAccess()) | ||||||
|                 .withPath(RestAPI.ENDPOINT_INSTITUTION) |                 .withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION) | ||||||
|                 .withExpectedStatus(HttpStatus.OK) |                 .withExpectedStatus(HttpStatus.OK) | ||||||
|                 .getAsObject(new TypeReference<Page<Institution>>() { |                 .getAsObject(new TypeReference<Page<Institution>>() { | ||||||
|                 }); |                 }); | ||||||
|  | @ -44,7 +44,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester { | ||||||
| 
 | 
 | ||||||
|         institutions = new RestAPITestHelper() |         institutions = new RestAPITestHelper() | ||||||
|                 .withAccessToken(getSebAdminAccess()) |                 .withAccessToken(getSebAdminAccess()) | ||||||
|                 .withPath(RestAPI.ENDPOINT_INSTITUTION) |                 .withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION) | ||||||
|                 .withAttribute("active", "true") |                 .withAttribute("active", "true") | ||||||
|                 .withExpectedStatus(HttpStatus.OK) |                 .withExpectedStatus(HttpStatus.OK) | ||||||
|                 .getAsObject(new TypeReference<Page<Institution>>() { |                 .getAsObject(new TypeReference<Page<Institution>>() { | ||||||
|  | @ -57,7 +57,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester { | ||||||
| 
 | 
 | ||||||
|         institutions = new RestAPITestHelper() |         institutions = new RestAPITestHelper() | ||||||
|                 .withAccessToken(getSebAdminAccess()) |                 .withAccessToken(getSebAdminAccess()) | ||||||
|                 .withPath(RestAPI.ENDPOINT_INSTITUTION) |                 .withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION) | ||||||
|                 .withAttribute("active", "false") |                 .withAttribute("active", "false") | ||||||
|                 .withExpectedStatus(HttpStatus.OK) |                 .withExpectedStatus(HttpStatus.OK) | ||||||
|                 .getAsObject(new TypeReference<Page<Institution>>() { |                 .getAsObject(new TypeReference<Page<Institution>>() { | ||||||
|  | @ -70,7 +70,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         // institutional admin sees only his institution |         // institutional admin sees only his institution | ||||||
|         institutions = new RestAPITestHelper() |         institutions = new RestAPITestHelper() | ||||||
|                 .withAccessToken(getAdminInstitution1Access()) |                 .withAccessToken(getAdminInstitution1Access()) | ||||||
|                 .withPath(RestAPI.ENDPOINT_INSTITUTION) |                 .withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION) | ||||||
|                 .withExpectedStatus(HttpStatus.OK) |                 .withExpectedStatus(HttpStatus.OK) | ||||||
|                 .getAsObject(new TypeReference<Page<Institution>>() { |                 .getAsObject(new TypeReference<Page<Institution>>() { | ||||||
|                 }); |                 }); | ||||||
|  | @ -82,7 +82,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         // Institutional admin tries to get data from other institution |         // Institutional admin tries to get data from other institution | ||||||
|         final APIMessage errorMessage = new RestAPITestHelper() |         final APIMessage errorMessage = new RestAPITestHelper() | ||||||
|                 .withAccessToken(getAdminInstitution1Access()) |                 .withAccessToken(getAdminInstitution1Access()) | ||||||
|                 .withPath(RestAPI.ENDPOINT_INSTITUTION) |                 .withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION) | ||||||
|                 .withAttribute("institutionId", "2") // try to hack |                 .withAttribute("institutionId", "2") // try to hack | ||||||
|                 .withExpectedStatus(HttpStatus.FORBIDDEN) |                 .withExpectedStatus(HttpStatus.FORBIDDEN) | ||||||
|                 .getAsObject(new TypeReference<APIMessage>() { |                 .getAsObject(new TypeReference<APIMessage>() { | ||||||
|  | @ -96,7 +96,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester { | ||||||
|     public void getInstitutionById() throws Exception { |     public void getInstitutionById() throws Exception { | ||||||
|         Institution institution = new RestAPITestHelper() |         Institution institution = new RestAPITestHelper() | ||||||
|                 .withAccessToken(getSebAdminAccess()) |                 .withAccessToken(getSebAdminAccess()) | ||||||
|                 .withPath(RestAPI.ENDPOINT_INSTITUTION + "/1") |                 .withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION + "/1") | ||||||
|                 .withExpectedStatus(HttpStatus.OK) |                 .withExpectedStatus(HttpStatus.OK) | ||||||
|                 .getAsObject(new TypeReference<Institution>() { |                 .getAsObject(new TypeReference<Institution>() { | ||||||
|                 }); |                 }); | ||||||
|  | @ -107,7 +107,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         // a seb-admin is also able to get an institution that is not the one he self belongs to |         // a seb-admin is also able to get an institution that is not the one he self belongs to | ||||||
|         institution = new RestAPITestHelper() |         institution = new RestAPITestHelper() | ||||||
|                 .withAccessToken(getSebAdminAccess()) |                 .withAccessToken(getSebAdminAccess()) | ||||||
|                 .withPath(RestAPI.ENDPOINT_INSTITUTION + "/2") |                 .withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION + "/2") | ||||||
|                 .withExpectedStatus(HttpStatus.OK) |                 .withExpectedStatus(HttpStatus.OK) | ||||||
|                 .getAsObject(new TypeReference<Institution>() { |                 .getAsObject(new TypeReference<Institution>() { | ||||||
|                 }); |                 }); | ||||||
|  | @ -118,7 +118,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         // but a institutional-admin is not able to get an institution that is not the one he self belongs to |         // but a institutional-admin is not able to get an institution that is not the one he self belongs to | ||||||
|         new RestAPITestHelper() |         new RestAPITestHelper() | ||||||
|                 .withAccessToken(getAdminInstitution1Access()) |                 .withAccessToken(getAdminInstitution1Access()) | ||||||
|                 .withPath(RestAPI.ENDPOINT_INSTITUTION + "/2") |                 .withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION + "/2") | ||||||
|                 .withExpectedStatus(HttpStatus.FORBIDDEN) |                 .withExpectedStatus(HttpStatus.FORBIDDEN) | ||||||
|                 .getAsString(); |                 .getAsString(); | ||||||
|     } |     } | ||||||
|  | @ -128,7 +128,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         // create new institution with seb-admin |         // create new institution with seb-admin | ||||||
|         Institution institution = new RestAPITestHelper() |         Institution institution = new RestAPITestHelper() | ||||||
|                 .withAccessToken(getSebAdminAccess()) |                 .withAccessToken(getSebAdminAccess()) | ||||||
|                 .withPath(RestAPI.ENDPOINT_INSTITUTION) |                 .withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION) | ||||||
|                 .withMethod(HttpMethod.POST) |                 .withMethod(HttpMethod.POST) | ||||||
|                 .withAttribute("name", "new institution") |                 .withAttribute("name", "new institution") | ||||||
|                 .withAttribute("urlSuffix", "new_inst") |                 .withAttribute("urlSuffix", "new_inst") | ||||||
|  | @ -144,7 +144,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         // an institutional admin should not be allowed to create a new institution |         // an institutional admin should not be allowed to create a new institution | ||||||
|         APIMessage errorMessage = new RestAPITestHelper() |         APIMessage errorMessage = new RestAPITestHelper() | ||||||
|                 .withAccessToken(getAdminInstitution1Access()) |                 .withAccessToken(getAdminInstitution1Access()) | ||||||
|                 .withPath(RestAPI.ENDPOINT_INSTITUTION) |                 .withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION) | ||||||
|                 .withMethod(HttpMethod.POST) |                 .withMethod(HttpMethod.POST) | ||||||
|                 .withAttribute("name", "new institution") |                 .withAttribute("name", "new institution") | ||||||
|                 .withAttribute("urlSuffix", "new_inst") |                 .withAttribute("urlSuffix", "new_inst") | ||||||
|  | @ -156,7 +156,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         // and name for institution must be unique |         // and name for institution must be unique | ||||||
|         errorMessage = new RestAPITestHelper() |         errorMessage = new RestAPITestHelper() | ||||||
|                 .withAccessToken(getSebAdminAccess()) |                 .withAccessToken(getSebAdminAccess()) | ||||||
|                 .withPath(RestAPI.ENDPOINT_INSTITUTION) |                 .withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION) | ||||||
|                 .withMethod(HttpMethod.POST) |                 .withMethod(HttpMethod.POST) | ||||||
|                 .withAttribute("name", "new institution") |                 .withAttribute("name", "new institution") | ||||||
|                 .withAttribute("urlSuffix", "new_inst") |                 .withAttribute("urlSuffix", "new_inst") | ||||||
|  | @ -171,7 +171,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         // and predefined id should be ignored |         // and predefined id should be ignored | ||||||
|         institution = new RestAPITestHelper() |         institution = new RestAPITestHelper() | ||||||
|                 .withAccessToken(getSebAdminAccess()) |                 .withAccessToken(getSebAdminAccess()) | ||||||
|                 .withPath(RestAPI.ENDPOINT_INSTITUTION) |                 .withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION) | ||||||
|                 .withMethod(HttpMethod.POST) |                 .withMethod(HttpMethod.POST) | ||||||
|                 .withAttribute("id", "123") |                 .withAttribute("id", "123") | ||||||
|                 .withAttribute("name", "newer institution") |                 .withAttribute("name", "newer institution") | ||||||
|  | @ -191,7 +191,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         final String sebAdminAccess = getSebAdminAccess(); |         final String sebAdminAccess = getSebAdminAccess(); | ||||||
|         Institution institution = new RestAPITestHelper() |         Institution institution = new RestAPITestHelper() | ||||||
|                 .withAccessToken(sebAdminAccess) |                 .withAccessToken(sebAdminAccess) | ||||||
|                 .withPath(RestAPI.ENDPOINT_INSTITUTION) |                 .withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION) | ||||||
|                 .withMethod(HttpMethod.POST) |                 .withMethod(HttpMethod.POST) | ||||||
|                 .withAttribute("name", "testInstitution") |                 .withAttribute("name", "testInstitution") | ||||||
|                 .withExpectedStatus(HttpStatus.OK) |                 .withExpectedStatus(HttpStatus.OK) | ||||||
|  | @ -205,7 +205,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         // get |         // get | ||||||
|         institution = new RestAPITestHelper() |         institution = new RestAPITestHelper() | ||||||
|                 .withAccessToken(sebAdminAccess) |                 .withAccessToken(sebAdminAccess) | ||||||
|                 .withPath(RestAPI.ENDPOINT_INSTITUTION).withPath("/").withPath(String.valueOf(institution.id)) |                 .withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION).withPath("/").withPath(String.valueOf(institution.id)) | ||||||
|                 .withMethod(HttpMethod.GET) |                 .withMethod(HttpMethod.GET) | ||||||
|                 .withExpectedStatus(HttpStatus.OK) |                 .withExpectedStatus(HttpStatus.OK) | ||||||
|                 .getAsObject(new TypeReference<Institution>() { |                 .getAsObject(new TypeReference<Institution>() { | ||||||
|  | @ -219,7 +219,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         // modify |         // modify | ||||||
|         institution = new RestAPITestHelper() |         institution = new RestAPITestHelper() | ||||||
|                 .withAccessToken(sebAdminAccess) |                 .withAccessToken(sebAdminAccess) | ||||||
|                 .withPath(RestAPI.ENDPOINT_INSTITUTION).withPath("/").withPath(String.valueOf(institution.id)) |                 .withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION).withPath("/").withPath(String.valueOf(institution.id)) | ||||||
|                 .withMethod(HttpMethod.PUT) |                 .withMethod(HttpMethod.PUT) | ||||||
|                 .withBodyJson(new Institution(null, "testInstitution", "testSuffix", null, null)) |                 .withBodyJson(new Institution(null, "testInstitution", "testSuffix", null, null)) | ||||||
|                 .withExpectedStatus(HttpStatus.OK) |                 .withExpectedStatus(HttpStatus.OK) | ||||||
|  | @ -234,7 +234,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         // activate |         // activate | ||||||
|         EntityProcessingReport report = new RestAPITestHelper() |         EntityProcessingReport report = new RestAPITestHelper() | ||||||
|                 .withAccessToken(sebAdminAccess) |                 .withAccessToken(sebAdminAccess) | ||||||
|                 .withPath(RestAPI.ENDPOINT_INSTITUTION) |                 .withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION) | ||||||
|                 .withPath("/").withPath(String.valueOf(institution.id)).withPath("/active") |                 .withPath("/").withPath(String.valueOf(institution.id)).withPath("/active") | ||||||
|                 .withMethod(HttpMethod.POST) |                 .withMethod(HttpMethod.POST) | ||||||
|                 .withExpectedStatus(HttpStatus.OK) |                 .withExpectedStatus(HttpStatus.OK) | ||||||
|  | @ -250,7 +250,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         // get |         // get | ||||||
|         institution = new RestAPITestHelper() |         institution = new RestAPITestHelper() | ||||||
|                 .withAccessToken(sebAdminAccess) |                 .withAccessToken(sebAdminAccess) | ||||||
|                 .withPath(RestAPI.ENDPOINT_INSTITUTION).withPath("/").withPath(String.valueOf(institution.id)) |                 .withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION).withPath("/").withPath(String.valueOf(institution.id)) | ||||||
|                 .withMethod(HttpMethod.GET) |                 .withMethod(HttpMethod.GET) | ||||||
|                 .withExpectedStatus(HttpStatus.OK) |                 .withExpectedStatus(HttpStatus.OK) | ||||||
|                 .getAsObject(new TypeReference<Institution>() { |                 .getAsObject(new TypeReference<Institution>() { | ||||||
|  | @ -262,7 +262,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         // deactivate |         // deactivate | ||||||
|         report = new RestAPITestHelper() |         report = new RestAPITestHelper() | ||||||
|                 .withAccessToken(sebAdminAccess) |                 .withAccessToken(sebAdminAccess) | ||||||
|                 .withPath(RestAPI.ENDPOINT_INSTITUTION) |                 .withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION) | ||||||
|                 .withPath("/").withPath(String.valueOf(institution.id)).withPath("/inactive") |                 .withPath("/").withPath(String.valueOf(institution.id)).withPath("/inactive") | ||||||
|                 .withMethod(HttpMethod.POST) |                 .withMethod(HttpMethod.POST) | ||||||
|                 .withExpectedStatus(HttpStatus.OK) |                 .withExpectedStatus(HttpStatus.OK) | ||||||
|  | @ -278,7 +278,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         // get |         // get | ||||||
|         institution = new RestAPITestHelper() |         institution = new RestAPITestHelper() | ||||||
|                 .withAccessToken(sebAdminAccess) |                 .withAccessToken(sebAdminAccess) | ||||||
|                 .withPath(RestAPI.ENDPOINT_INSTITUTION).withPath("/").withPath(String.valueOf(institution.id)) |                 .withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION).withPath("/").withPath(String.valueOf(institution.id)) | ||||||
|                 .withMethod(HttpMethod.GET) |                 .withMethod(HttpMethod.GET) | ||||||
|                 .withExpectedStatus(HttpStatus.OK) |                 .withExpectedStatus(HttpStatus.OK) | ||||||
|                 .getAsObject(new TypeReference<Institution>() { |                 .getAsObject(new TypeReference<Institution>() { | ||||||
|  | @ -290,7 +290,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         // delete |         // delete | ||||||
|         report = new RestAPITestHelper() |         report = new RestAPITestHelper() | ||||||
|                 .withAccessToken(sebAdminAccess) |                 .withAccessToken(sebAdminAccess) | ||||||
|                 .withPath(RestAPI.ENDPOINT_INSTITUTION) |                 .withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION) | ||||||
|                 .withPath("/").withPath(String.valueOf(institution.id)) |                 .withPath("/").withPath(String.valueOf(institution.id)) | ||||||
|                 .withMethod(HttpMethod.DELETE) |                 .withMethod(HttpMethod.DELETE) | ||||||
|                 .withExpectedStatus(HttpStatus.OK) |                 .withExpectedStatus(HttpStatus.OK) | ||||||
|  | @ -307,7 +307,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         // get |         // get | ||||||
|         final APIMessage error = new RestAPITestHelper() |         final APIMessage error = new RestAPITestHelper() | ||||||
|                 .withAccessToken(sebAdminAccess) |                 .withAccessToken(sebAdminAccess) | ||||||
|                 .withPath(RestAPI.ENDPOINT_INSTITUTION).withPath("/").withPath(String.valueOf(institution.id)) |                 .withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION).withPath("/").withPath(String.valueOf(institution.id)) | ||||||
|                 .withMethod(HttpMethod.GET) |                 .withMethod(HttpMethod.GET) | ||||||
|                 .withExpectedStatus(HttpStatus.NOT_FOUND) |                 .withExpectedStatus(HttpStatus.NOT_FOUND) | ||||||
|                 .getAsObject(new TypeReference<APIMessage>() { |                 .getAsObject(new TypeReference<APIMessage>() { | ||||||
|  |  | ||||||
|  | @ -31,11 +31,12 @@ import org.springframework.test.context.jdbc.Sql; | ||||||
| import com.fasterxml.jackson.core.type.TypeReference; | import com.fasterxml.jackson.core.type.TypeReference; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.gbl.Constants; | import ch.ethz.seb.sebserver.gbl.Constants; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.APIMessage; | import ch.ethz.seb.sebserver.gbl.api.APIMessage; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.api.SEBServerRestEndpoints; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Domain; | import ch.ethz.seb.sebserver.gbl.model.Domain; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Entity; | import ch.ethz.seb.sebserver.gbl.model.Entity; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.EntityKey; | import ch.ethz.seb.sebserver.gbl.model.EntityKey; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.EntityKeyAndName; | import ch.ethz.seb.sebserver.gbl.model.EntityName; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport; | import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Page; | import ch.ethz.seb.sebserver.gbl.model.Page; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog; | import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog; | ||||||
|  | @ -43,7 +44,6 @@ import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.user.UserMod; | import ch.ethz.seb.sebserver.gbl.model.user.UserMod; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.user.UserRole; | import ch.ethz.seb.sebserver.gbl.model.user.UserRole; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO.ActivityType; | import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO.ActivityType; | ||||||
| import ch.ethz.seb.sebserver.webservice.weblayer.api.RestAPI; |  | ||||||
| 
 | 
 | ||||||
| @Sql(scripts = { "classpath:schema-test.sql", "classpath:data-test.sql" }) | @Sql(scripts = { "classpath:schema-test.sql", "classpath:data-test.sql" }) | ||||||
| public class UserAPITest extends AdministrationAPIIntegrationTester { | public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|  | @ -52,7 +52,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|     public void getMyUserInfo() throws Exception { |     public void getMyUserInfo() throws Exception { | ||||||
|         String contentAsString = new RestAPITestHelper() |         String contentAsString = new RestAPITestHelper() | ||||||
|                 .withAccessToken(getSebAdminAccess()) |                 .withAccessToken(getSebAdminAccess()) | ||||||
|                 .withPath(RestAPI.ENDPOINT_USER_ACCOUNT + "/me") |                 .withPath(SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/me") | ||||||
|                 .withExpectedStatus(HttpStatus.OK) |                 .withExpectedStatus(HttpStatus.OK) | ||||||
|                 .getAsString(); |                 .getAsString(); | ||||||
| 
 | 
 | ||||||
|  | @ -70,7 +70,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
| 
 | 
 | ||||||
|         contentAsString = new RestAPITestHelper() |         contentAsString = new RestAPITestHelper() | ||||||
|                 .withAccessToken(getAdminInstitution1Access()) |                 .withAccessToken(getAdminInstitution1Access()) | ||||||
|                 .withPath(RestAPI.ENDPOINT_USER_ACCOUNT + "/me") |                 .withPath(SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/me") | ||||||
|                 .withExpectedStatus(HttpStatus.OK) |                 .withExpectedStatus(HttpStatus.OK) | ||||||
|                 .getAsString(); |                 .getAsString(); | ||||||
| 
 | 
 | ||||||
|  | @ -90,7 +90,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|     @Test |     @Test | ||||||
|     public void getUserInfoWithUUID() throws Exception { |     public void getUserInfoWithUUID() throws Exception { | ||||||
|         final String sebAdminAccessToken = getSebAdminAccess(); |         final String sebAdminAccessToken = getSebAdminAccess(); | ||||||
|         String contentAsString = this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user2") |         String contentAsString = this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/user2") | ||||||
|                 .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                 .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                 .header("Authorization", "Bearer " + sebAdminAccessToken)) |                 .header("Authorization", "Bearer " + sebAdminAccessToken)) | ||||||
|                 .andExpect(status().isOk()) |                 .andExpect(status().isOk()) | ||||||
|  | @ -109,7 +109,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|                 contentAsString); |                 contentAsString); | ||||||
| 
 | 
 | ||||||
|         final String adminInstitution2AccessToken = getAdminInstitution2Access(); |         final String adminInstitution2AccessToken = getAdminInstitution2Access(); | ||||||
|         contentAsString = this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user1") |         contentAsString = this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/user1") | ||||||
|                 .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                 .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                 .header("Authorization", "Bearer " + adminInstitution2AccessToken)) |                 .header("Authorization", "Bearer " + adminInstitution2AccessToken)) | ||||||
|                 .andExpect(status().isForbidden()) |                 .andExpect(status().isForbidden()) | ||||||
|  | @ -127,7 +127,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|     public void institutionalAdminNotAllowedToSeeUsersOfOtherInstitution() throws Exception { |     public void institutionalAdminNotAllowedToSeeUsersOfOtherInstitution() throws Exception { | ||||||
|         new RestAPITestHelper() |         new RestAPITestHelper() | ||||||
|                 .withAccessToken(getAdminInstitution1Access()) |                 .withAccessToken(getAdminInstitution1Access()) | ||||||
|                 .withPath(RestAPI.ENDPOINT_USER_ACCOUNT + "?institutionId=2") |                 .withPath(SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "?institutionId=2") | ||||||
|                 .withExpectedStatus(HttpStatus.FORBIDDEN) |                 .withExpectedStatus(HttpStatus.FORBIDDEN) | ||||||
|                 .getAsString(); |                 .getAsString(); | ||||||
|     } |     } | ||||||
|  | @ -136,7 +136,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|     public void getAllUserInfoNoFilter() throws Exception { |     public void getAllUserInfoNoFilter() throws Exception { | ||||||
|         Page<UserInfo> userInfos = new RestAPITestHelper() |         Page<UserInfo> userInfos = new RestAPITestHelper() | ||||||
|                 .withAccessToken(getSebAdminAccess()) |                 .withAccessToken(getSebAdminAccess()) | ||||||
|                 .withPath(RestAPI.ENDPOINT_USER_ACCOUNT) |                 .withPath(SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT) | ||||||
|                 .withExpectedStatus(HttpStatus.OK) |                 .withExpectedStatus(HttpStatus.OK) | ||||||
|                 .getAsObject(new TypeReference<Page<UserInfo>>() { |                 .getAsObject(new TypeReference<Page<UserInfo>>() { | ||||||
|                 }); |                 }); | ||||||
|  | @ -150,7 +150,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
| 
 | 
 | ||||||
|         userInfos = new RestAPITestHelper() |         userInfos = new RestAPITestHelper() | ||||||
|                 .withAccessToken(getAdminInstitution2Access()) |                 .withAccessToken(getAdminInstitution2Access()) | ||||||
|                 .withPath(RestAPI.ENDPOINT_USER_ACCOUNT) |                 .withPath(SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT) | ||||||
|                 .withAttribute("institutionId", "2") |                 .withAttribute("institutionId", "2") | ||||||
|                 .withExpectedStatus(HttpStatus.OK) |                 .withExpectedStatus(HttpStatus.OK) | ||||||
|                 .getAsObject(new TypeReference<Page<UserInfo>>() { |                 .getAsObject(new TypeReference<Page<UserInfo>>() { | ||||||
|  | @ -167,7 +167,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         //.. and without inactive, if active flag is set to true |         //.. and without inactive, if active flag is set to true | ||||||
|         userInfos = new RestAPITestHelper() |         userInfos = new RestAPITestHelper() | ||||||
|                 .withAccessToken(getAdminInstitution2Access()) |                 .withAccessToken(getAdminInstitution2Access()) | ||||||
|                 .withPath(RestAPI.ENDPOINT_USER_ACCOUNT) |                 .withPath(SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT) | ||||||
|                 .withAttribute(Entity.FILTER_ATTR_INSTITUTION, "2") |                 .withAttribute(Entity.FILTER_ATTR_INSTITUTION, "2") | ||||||
|                 .withAttribute(Entity.FILTER_ATTR_ACTIVE, "true") |                 .withAttribute(Entity.FILTER_ATTR_ACTIVE, "true") | ||||||
|                 .withExpectedStatus(HttpStatus.OK) |                 .withExpectedStatus(HttpStatus.OK) | ||||||
|  | @ -183,7 +183,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         //.. and only inactive, if active flag is set to false |         //.. and only inactive, if active flag is set to false | ||||||
|         userInfos = new RestAPITestHelper() |         userInfos = new RestAPITestHelper() | ||||||
|                 .withAccessToken(getAdminInstitution2Access()) |                 .withAccessToken(getAdminInstitution2Access()) | ||||||
|                 .withPath(RestAPI.ENDPOINT_USER_ACCOUNT) |                 .withPath(SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT) | ||||||
|                 .withAttribute(Entity.FILTER_ATTR_INSTITUTION, "2") |                 .withAttribute(Entity.FILTER_ATTR_INSTITUTION, "2") | ||||||
|                 .withAttribute(Entity.FILTER_ATTR_ACTIVE, "false") |                 .withAttribute(Entity.FILTER_ATTR_ACTIVE, "false") | ||||||
|                 .withExpectedStatus(HttpStatus.OK) |                 .withExpectedStatus(HttpStatus.OK) | ||||||
|  | @ -203,7 +203,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
| 
 | 
 | ||||||
|         final String token = getSebAdminAccess(); |         final String token = getSebAdminAccess(); | ||||||
|         final Page<UserInfo> userInfos = this.jsonMapper.readValue( |         final Page<UserInfo> userInfos = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT) |                 this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT) | ||||||
|                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                         .header("Authorization", "Bearer " + token)) |                         .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -225,7 +225,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
| 
 | 
 | ||||||
|         final String token = getSebAdminAccess(); |         final String token = getSebAdminAccess(); | ||||||
|         final Page<UserInfo> userInfos = this.jsonMapper.readValue( |         final Page<UserInfo> userInfos = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "?institutionId=2") |                 this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "?institutionId=2") | ||||||
|                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                         .header("Authorization", "Bearer " + token)) |                         .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -244,7 +244,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|     public void getPageNoFilterNoPageAttributesDescendingOrder() throws Exception { |     public void getPageNoFilterNoPageAttributesDescendingOrder() throws Exception { | ||||||
|         final String token = getSebAdminAccess(); |         final String token = getSebAdminAccess(); | ||||||
|         final Page<UserInfo> userInfos = this.jsonMapper.readValue( |         final Page<UserInfo> userInfos = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "?sort=-") |                 this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "?sort=-") | ||||||
|                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                         .header("Authorization", "Bearer " + token)) |                         .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -266,7 +266,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         // first page default sort order |         // first page default sort order | ||||||
|         Page<UserInfo> userInfos = this.jsonMapper.readValue( |         Page<UserInfo> userInfos = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc |                 this.mockMvc | ||||||
|                         .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT |                         .perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT | ||||||
|                                 + "?page_number=1&page_size=3&institutionId=2") |                                 + "?page_number=1&page_size=3&institutionId=2") | ||||||
|                                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                                         .header("Authorization", "Bearer " + token)) |                                         .header("Authorization", "Bearer " + token)) | ||||||
|  | @ -284,7 +284,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         // second page default sort order |         // second page default sort order | ||||||
|         userInfos = this.jsonMapper.readValue( |         userInfos = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc |                 this.mockMvc | ||||||
|                         .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT |                         .perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT | ||||||
|                                 + "?page_number=2&page_size=3&institutionId=2") |                                 + "?page_number=2&page_size=3&institutionId=2") | ||||||
|                                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                                         .header("Authorization", "Bearer " + token)) |                                         .header("Authorization", "Bearer " + token)) | ||||||
|  | @ -303,7 +303,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         // invalid page number should refer to last page |         // invalid page number should refer to last page | ||||||
|         userInfos = this.jsonMapper.readValue( |         userInfos = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc |                 this.mockMvc | ||||||
|                         .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT |                         .perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT | ||||||
|                                 + "?page_number=3&page_size=3&institutionId=2") |                                 + "?page_number=3&page_size=3&institutionId=2") | ||||||
|                                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                                         .header("Authorization", "Bearer " + token)) |                                         .header("Authorization", "Bearer " + token)) | ||||||
|  | @ -322,7 +322,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         // first page descending sort order |         // first page descending sort order | ||||||
|         userInfos = this.jsonMapper.readValue( |         userInfos = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc |                 this.mockMvc | ||||||
|                         .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT |                         .perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT | ||||||
|                                 + "?page_number=1&page_size=3&sort=-&institutionId=2") |                                 + "?page_number=1&page_size=3&sort=-&institutionId=2") | ||||||
|                                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                                         .header("Authorization", "Bearer " + token)) |                                         .header("Authorization", "Bearer " + token)) | ||||||
|  | @ -350,7 +350,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|     public void getAllUserInfo() throws Exception { |     public void getAllUserInfo() throws Exception { | ||||||
|         final String token = getSebAdminAccess(); |         final String token = getSebAdminAccess(); | ||||||
|         final Page<UserInfo> userInfos = this.jsonMapper.readValue( |         final Page<UserInfo> userInfos = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT) |                 this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT) | ||||||
|                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                         .header("Authorization", "Bearer " + token)) |                         .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -366,7 +366,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|     public void getAllUserInfoWithOnlyActive() throws Exception { |     public void getAllUserInfoWithOnlyActive() throws Exception { | ||||||
|         final String token = getSebAdminAccess(); |         final String token = getSebAdminAccess(); | ||||||
|         final Page<UserInfo> userInfos = this.jsonMapper.readValue( |         final Page<UserInfo> userInfos = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "?active=true&institutionId=2") |                 this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "?active=true&institutionId=2") | ||||||
|                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                         .header("Authorization", "Bearer " + token)) |                         .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -385,7 +385,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         // expecting none for SEBAdmins institution |         // expecting none for SEBAdmins institution | ||||||
|         final String token = getSebAdminAccess(); |         final String token = getSebAdminAccess(); | ||||||
|         Page<UserInfo> userInfos = this.jsonMapper.readValue( |         Page<UserInfo> userInfos = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "?active=false") |                 this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "?active=false") | ||||||
|                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                         .header("Authorization", "Bearer " + token)) |                         .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -399,7 +399,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         // expecting one for institution 2 |         // expecting one for institution 2 | ||||||
|         userInfos = this.jsonMapper.readValue( |         userInfos = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc |                 this.mockMvc | ||||||
|                         .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "?active=false&institutionId=2") |                         .perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "?active=false&institutionId=2") | ||||||
|                                 .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                                 .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                                 .header("Authorization", "Bearer " + token)) |                                 .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -416,7 +416,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|     public void getAllUserInfoWithSearchUsernameLike() throws Exception { |     public void getAllUserInfoWithSearchUsernameLike() throws Exception { | ||||||
|         final String token = getSebAdminAccess(); |         final String token = getSebAdminAccess(); | ||||||
|         final Page<UserInfo> userInfos = this.jsonMapper.readValue( |         final Page<UserInfo> userInfos = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "?username=exam") |                 this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "?username=exam") | ||||||
|                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                         .header("Authorization", "Bearer " + token)) |                         .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -432,7 +432,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|     @Test |     @Test | ||||||
|     public void testOwnerGet() throws Exception { |     public void testOwnerGet() throws Exception { | ||||||
|         final String examAdminToken1 = getExamAdmin1(); |         final String examAdminToken1 = getExamAdmin1(); | ||||||
|         this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/me") |         this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/me") | ||||||
|                 .header("Authorization", "Bearer " + examAdminToken1)) |                 .header("Authorization", "Bearer " + examAdminToken1)) | ||||||
|                 .andExpect(status().isOk()) |                 .andExpect(status().isOk()) | ||||||
|                 .andReturn().getResponse().getContentAsString(); |                 .andReturn().getResponse().getContentAsString(); | ||||||
|  | @ -442,7 +442,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|     public void createUserTest() throws Exception { |     public void createUserTest() throws Exception { | ||||||
|         final String token = getSebAdminAccess(); |         final String token = getSebAdminAccess(); | ||||||
|         final UserInfo createdUser = this.jsonMapper.readValue( |         final UserInfo createdUser = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(post(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT) |                 this.mockMvc.perform(post(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT) | ||||||
|                         .header("Authorization", "Bearer " + token) |                         .header("Authorization", "Bearer " + token) | ||||||
|                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                         .param(Domain.USER.ATTR_NAME, "NewTestUser") |                         .param(Domain.USER.ATTR_NAME, "NewTestUser") | ||||||
|  | @ -461,7 +461,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
| 
 | 
 | ||||||
|         // get newly created user and check equality |         // get newly created user and check equality | ||||||
|         final UserInfo createdUserGet = this.jsonMapper.readValue( |         final UserInfo createdUserGet = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/" + createdUser.uuid) |                 this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/" + createdUser.uuid) | ||||||
|                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                         .header("Authorization", "Bearer " + token)) |                         .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -477,7 +477,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         final Page<UserActivityLog> logs = this.jsonMapper.readValue( |         final Page<UserActivityLog> logs = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc |                 this.mockMvc | ||||||
|                         .perform( |                         .perform( | ||||||
|                                 get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG |                                 get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACTIVITY_LOG | ||||||
|                                         + "?user=user1&activity_types=CREATE") |                                         + "?user=user1&activity_types=CREATE") | ||||||
|                                                 .header("Authorization", "Bearer " + token)) |                                                 .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -557,7 +557,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|     public void modifyUserWithPUTMethod() throws Exception { |     public void modifyUserWithPUTMethod() throws Exception { | ||||||
|         final String token = getSebAdminAccess(); |         final String token = getSebAdminAccess(); | ||||||
|         final UserInfo user = this.jsonMapper.readValue( |         final UserInfo user = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user7") |                 this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/user7") | ||||||
|                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                         .header("Authorization", "Bearer " + token)) |                         .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -586,7 +586,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         final String modifyUserJson = this.jsonMapper.writeValueAsString(modifyUser); |         final String modifyUserJson = this.jsonMapper.writeValueAsString(modifyUser); | ||||||
| 
 | 
 | ||||||
|         UserInfo modifiedUserResult = this.jsonMapper.readValue( |         UserInfo modifiedUserResult = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(put(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/" + user.getUuid()) |                 this.mockMvc.perform(put(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/" + user.getUuid()) | ||||||
|                         .header("Authorization", "Bearer " + token) |                         .header("Authorization", "Bearer " + token) | ||||||
|                         .contentType(MediaType.APPLICATION_JSON_UTF8) |                         .contentType(MediaType.APPLICATION_JSON_UTF8) | ||||||
|                         .content(modifyUserJson)) |                         .content(modifyUserJson)) | ||||||
|  | @ -604,7 +604,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
| 
 | 
 | ||||||
|         // double check by getting the user by UUID |         // double check by getting the user by UUID | ||||||
|         modifiedUserResult = this.jsonMapper.readValue( |         modifiedUserResult = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/" + modifiedUserResult.uuid) |                 this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/" + modifiedUserResult.uuid) | ||||||
|                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                         .header("Authorization", "Bearer " + token)) |                         .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -657,7 +657,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|     public void testOwnerModifyPossibleForExamAdmin() throws Exception { |     public void testOwnerModifyPossibleForExamAdmin() throws Exception { | ||||||
|         final String examAdminToken1 = getExamAdmin1(); |         final String examAdminToken1 = getExamAdmin1(); | ||||||
|         final UserInfo examAdmin = this.jsonMapper.readValue( |         final UserInfo examAdmin = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/me") |                 this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/me") | ||||||
|                         .header("Authorization", "Bearer " + examAdminToken1)) |                         .header("Authorization", "Bearer " + examAdminToken1)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|                         .andReturn().getResponse().getContentAsString(), |                         .andReturn().getResponse().getContentAsString(), | ||||||
|  | @ -667,7 +667,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         final UserMod modifiedUser = new UserMod(examAdmin, null, null); |         final UserMod modifiedUser = new UserMod(examAdmin, null, null); | ||||||
|         final String modifiedUserJson = this.jsonMapper.writeValueAsString(modifiedUser); |         final String modifiedUserJson = this.jsonMapper.writeValueAsString(modifiedUser); | ||||||
| 
 | 
 | ||||||
|         this.mockMvc.perform(put(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/" + modifiedUser.uuid) |         this.mockMvc.perform(put(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/" + modifiedUser.uuid) | ||||||
|                 .header("Authorization", "Bearer " + examAdminToken1) |                 .header("Authorization", "Bearer " + examAdminToken1) | ||||||
|                 .contentType(MediaType.APPLICATION_JSON_UTF8) |                 .contentType(MediaType.APPLICATION_JSON_UTF8) | ||||||
|                 .content(modifiedUserJson)) |                 .content(modifiedUserJson)) | ||||||
|  | @ -679,7 +679,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|     public void institutionalAdminTryToCreateOrModifyUserForOtherInstituionNotPossible() throws Exception { |     public void institutionalAdminTryToCreateOrModifyUserForOtherInstituionNotPossible() throws Exception { | ||||||
| 
 | 
 | ||||||
|         final String token = getAdminInstitution1Access(); |         final String token = getAdminInstitution1Access(); | ||||||
|         this.mockMvc.perform(post(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT) |         this.mockMvc.perform(post(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT) | ||||||
|                 .header("Authorization", "Bearer " + token) |                 .header("Authorization", "Bearer " + token) | ||||||
|                 .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                 .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                 .param(Domain.USER.ATTR_INSTITUTION_ID, "2") |                 .param(Domain.USER.ATTR_INSTITUTION_ID, "2") | ||||||
|  | @ -695,7 +695,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|                 new HashSet<>(Arrays.asList(UserRole.EXAM_ADMIN.name()))); |                 new HashSet<>(Arrays.asList(UserRole.EXAM_ADMIN.name()))); | ||||||
|         final UserMod newUser = new UserMod(userInfo, "12345678", "12345678"); |         final UserMod newUser = new UserMod(userInfo, "12345678", "12345678"); | ||||||
|         final String newUserJson = this.jsonMapper.writeValueAsString(newUser); |         final String newUserJson = this.jsonMapper.writeValueAsString(newUser); | ||||||
|         this.mockMvc.perform(put(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/NewTestUser") |         this.mockMvc.perform(put(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/NewTestUser") | ||||||
|                 .header("Authorization", "Bearer " + token) |                 .header("Authorization", "Bearer " + token) | ||||||
|                 .contentType(MediaType.APPLICATION_JSON_UTF8) |                 .contentType(MediaType.APPLICATION_JSON_UTF8) | ||||||
|                 .content(newUserJson)) |                 .content(newUserJson)) | ||||||
|  | @ -707,7 +707,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|     public void unauthorizedAdminTryToCreateUserNotPossible() throws Exception { |     public void unauthorizedAdminTryToCreateUserNotPossible() throws Exception { | ||||||
| 
 | 
 | ||||||
|         final String token = getExamAdmin1(); |         final String token = getExamAdmin1(); | ||||||
|         this.mockMvc.perform(post(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT) |         this.mockMvc.perform(post(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT) | ||||||
|                 .header("Authorization", "Bearer " + token) |                 .header("Authorization", "Bearer " + token) | ||||||
|                 .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                 .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                 .param(Domain.USER.ATTR_INSTITUTION_ID, "2") |                 .param(Domain.USER.ATTR_INSTITUTION_ID, "2") | ||||||
|  | @ -723,7 +723,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|                 new HashSet<>(Arrays.asList(UserRole.EXAM_ADMIN.name()))); |                 new HashSet<>(Arrays.asList(UserRole.EXAM_ADMIN.name()))); | ||||||
|         final UserMod newUser = new UserMod(userInfo, "12345678", "12345678"); |         final UserMod newUser = new UserMod(userInfo, "12345678", "12345678"); | ||||||
|         final String newUserJson = this.jsonMapper.writeValueAsString(newUser); |         final String newUserJson = this.jsonMapper.writeValueAsString(newUser); | ||||||
|         this.mockMvc.perform(put(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/NewTestUser") |         this.mockMvc.perform(put(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/NewTestUser") | ||||||
|                 .header("Authorization", "Bearer " + token) |                 .header("Authorization", "Bearer " + token) | ||||||
|                 .contentType(MediaType.APPLICATION_JSON_UTF8) |                 .contentType(MediaType.APPLICATION_JSON_UTF8) | ||||||
|                 .content(newUserJson)) |                 .content(newUserJson)) | ||||||
|  | @ -739,7 +739,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         // a SEB Server Admin now changes the password of ExamAdmin1 |         // a SEB Server Admin now changes the password of ExamAdmin1 | ||||||
|         final String sebAdminToken = getSebAdminAccess(); |         final String sebAdminToken = getSebAdminAccess(); | ||||||
|         final UserInfo examAdmin1 = this.jsonMapper.readValue( |         final UserInfo examAdmin1 = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user4") |                 this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/user4") | ||||||
|                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                         .header("Authorization", "Bearer " + sebAdminToken)) |                         .header("Authorization", "Bearer " + sebAdminToken)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -753,7 +753,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|                 "newPassword"); |                 "newPassword"); | ||||||
|         final String modifiedUserJson = this.jsonMapper.writeValueAsString(modifiedUser); |         final String modifiedUserJson = this.jsonMapper.writeValueAsString(modifiedUser); | ||||||
| 
 | 
 | ||||||
|         this.mockMvc.perform(put(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/" + modifiedUser.uuid) |         this.mockMvc.perform(put(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/" + modifiedUser.uuid) | ||||||
|                 .header("Authorization", "Bearer " + sebAdminToken) |                 .header("Authorization", "Bearer " + sebAdminToken) | ||||||
|                 .contentType(MediaType.APPLICATION_JSON_UTF8) |                 .contentType(MediaType.APPLICATION_JSON_UTF8) | ||||||
|                 .content(modifiedUserJson)) |                 .content(modifiedUserJson)) | ||||||
|  | @ -769,14 +769,14 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // it should also not be possible to use an old token again after password change |         // it should also not be possible to use an old token again after password change | ||||||
|         this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/me") |         this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/me") | ||||||
|                 .header("Authorization", "Bearer " + examAdminToken1)) |                 .header("Authorization", "Bearer " + examAdminToken1)) | ||||||
|                 .andExpect(status().isUnauthorized()) |                 .andExpect(status().isUnauthorized()) | ||||||
|                 .andReturn().getResponse().getContentAsString(); |                 .andReturn().getResponse().getContentAsString(); | ||||||
| 
 | 
 | ||||||
|         // but it should be possible to get a new access token and request again |         // but it should be possible to get a new access token and request again | ||||||
|         final String examAdminToken2 = obtainAccessToken("examAdmin1", "newPassword"); |         final String examAdminToken2 = obtainAccessToken("examAdmin1", "newPassword"); | ||||||
|         this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/me") |         this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/me") | ||||||
|                 .header("Authorization", "Bearer " + examAdminToken2)) |                 .header("Authorization", "Bearer " + examAdminToken2)) | ||||||
|                 .andExpect(status().isOk()) |                 .andExpect(status().isOk()) | ||||||
|                 .andReturn().getResponse().getContentAsString(); |                 .andReturn().getResponse().getContentAsString(); | ||||||
|  | @ -786,7 +786,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|     public void modifyUserPasswordInvalidPasswords() throws Exception { |     public void modifyUserPasswordInvalidPasswords() throws Exception { | ||||||
|         final String sebAdminToken = getSebAdminAccess(); |         final String sebAdminToken = getSebAdminAccess(); | ||||||
|         final UserInfo examAdmin1 = this.jsonMapper.readValue( |         final UserInfo examAdmin1 = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user4") |                 this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/user4") | ||||||
|                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                         .header("Authorization", "Bearer " + sebAdminToken)) |                         .header("Authorization", "Bearer " + sebAdminToken)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -802,7 +802,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         String modifiedUserJson = this.jsonMapper.writeValueAsString(modifiedUser); |         String modifiedUserJson = this.jsonMapper.writeValueAsString(modifiedUser); | ||||||
| 
 | 
 | ||||||
|         List<APIMessage> messages = this.jsonMapper.readValue( |         List<APIMessage> messages = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(put(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/" + modifiedUser.uuid) |                 this.mockMvc.perform(put(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/" + modifiedUser.uuid) | ||||||
|                         .header("Authorization", "Bearer " + sebAdminToken) |                         .header("Authorization", "Bearer " + sebAdminToken) | ||||||
|                         .contentType(MediaType.APPLICATION_JSON_UTF8) |                         .contentType(MediaType.APPLICATION_JSON_UTF8) | ||||||
|                         .content(modifiedUserJson)) |                         .content(modifiedUserJson)) | ||||||
|  | @ -824,7 +824,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         modifiedUserJson = this.jsonMapper.writeValueAsString(modifiedUser); |         modifiedUserJson = this.jsonMapper.writeValueAsString(modifiedUser); | ||||||
| 
 | 
 | ||||||
|         messages = this.jsonMapper.readValue( |         messages = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(put(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/" + modifiedUser.uuid) |                 this.mockMvc.perform(put(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/" + modifiedUser.uuid) | ||||||
|                         .header("Authorization", "Bearer " + sebAdminToken) |                         .header("Authorization", "Bearer " + sebAdminToken) | ||||||
|                         .contentType(MediaType.APPLICATION_JSON_UTF8) |                         .contentType(MediaType.APPLICATION_JSON_UTF8) | ||||||
|                         .content(modifiedUserJson)) |                         .content(modifiedUserJson)) | ||||||
|  | @ -843,7 +843,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         final String timeNow = DateTime.now(DateTimeZone.UTC).toString(Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS); |         final String timeNow = DateTime.now(DateTimeZone.UTC).toString(Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS); | ||||||
|         // only a SEB Administrator or an Institutional administrator should be able to deactivate a user-account |         // only a SEB Administrator or an Institutional administrator should be able to deactivate a user-account | ||||||
|         final String examAdminToken = getExamAdmin1(); |         final String examAdminToken = getExamAdmin1(); | ||||||
|         this.mockMvc.perform(post(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user4/inactive") |         this.mockMvc.perform(post(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/user4/inactive") | ||||||
|                 .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                 .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                 .header("Authorization", "Bearer " + examAdminToken)) |                 .header("Authorization", "Bearer " + examAdminToken)) | ||||||
|                 .andExpect(status().isForbidden()); |                 .andExpect(status().isForbidden()); | ||||||
|  | @ -851,7 +851,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         // With SEB Administrator it should work |         // With SEB Administrator it should work | ||||||
|         final String sebAdminToken = getSebAdminAccess(); |         final String sebAdminToken = getSebAdminAccess(); | ||||||
|         final EntityProcessingReport report = this.jsonMapper.readValue( |         final EntityProcessingReport report = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(post(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user4/inactive") |                 this.mockMvc.perform(post(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/user4/inactive") | ||||||
|                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                         .header("Authorization", "Bearer " + sebAdminToken)) |                         .header("Authorization", "Bearer " + sebAdminToken)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -868,7 +868,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         // get user and check activity |         // get user and check activity | ||||||
|         final EntityKey key = report.source.iterator().next(); |         final EntityKey key = report.source.iterator().next(); | ||||||
|         final UserInfo user = this.jsonMapper.readValue( |         final UserInfo user = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/" + key.modelId) |                 this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/" + key.modelId) | ||||||
|                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                         .header("Authorization", "Bearer " + sebAdminToken)) |                         .header("Authorization", "Bearer " + sebAdminToken)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -883,7 +883,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         final Page<UserActivityLog> userLogs = this.jsonMapper.readValue( |         final Page<UserActivityLog> userLogs = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc |                 this.mockMvc | ||||||
|                         .perform( |                         .perform( | ||||||
|                                 get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "/?user=user1&from=" + timeNow) |                                 get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACTIVITY_LOG + "/?user=user1&from=" + timeNow) | ||||||
|                                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                                         .header("Authorization", "Bearer " + sebAdminToken)) |                                         .header("Authorization", "Bearer " + sebAdminToken)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -903,7 +903,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         final String timeNow = DateTime.now(DateTimeZone.UTC).toString(Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS); |         final String timeNow = DateTime.now(DateTimeZone.UTC).toString(Constants.DATE_TIME_PATTERN_UTC_NO_MILLIS); | ||||||
|         // only a SEB Administrator or an Institutional administrator should be able to deactivate a user-account |         // only a SEB Administrator or an Institutional administrator should be able to deactivate a user-account | ||||||
|         final String examAdminToken = getExamAdmin1(); |         final String examAdminToken = getExamAdmin1(); | ||||||
|         this.mockMvc.perform(post(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user6/active") |         this.mockMvc.perform(post(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/user6/active") | ||||||
|                 .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                 .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                 .header("Authorization", "Bearer " + examAdminToken)) |                 .header("Authorization", "Bearer " + examAdminToken)) | ||||||
|                 .andExpect(status().isForbidden()); |                 .andExpect(status().isForbidden()); | ||||||
|  | @ -911,7 +911,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         // With SEB Administrator it should work |         // With SEB Administrator it should work | ||||||
|         final String sebAdminToken = getSebAdminAccess(); |         final String sebAdminToken = getSebAdminAccess(); | ||||||
|         final EntityProcessingReport report = this.jsonMapper.readValue( |         final EntityProcessingReport report = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(post(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/user6/active") |                 this.mockMvc.perform(post(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/user6/active") | ||||||
|                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                         .header("Authorization", "Bearer " + sebAdminToken)) |                         .header("Authorization", "Bearer " + sebAdminToken)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -928,7 +928,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         // get user and check activity |         // get user and check activity | ||||||
|         final EntityKey key = report.source.iterator().next(); |         final EntityKey key = report.source.iterator().next(); | ||||||
|         final UserInfo user = this.jsonMapper.readValue( |         final UserInfo user = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/" + key.modelId) |                 this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/" + key.modelId) | ||||||
|                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                         .header("Authorization", "Bearer " + sebAdminToken)) |                         .header("Authorization", "Bearer " + sebAdminToken)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -942,7 +942,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         // check also user activity log |         // check also user activity log | ||||||
|         final Page<UserActivityLog> userLogs = this.jsonMapper.readValue( |         final Page<UserActivityLog> userLogs = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc |                 this.mockMvc | ||||||
|                         .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?user=user1&from=" + timeNow) |                         .perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACTIVITY_LOG + "?user=user1&from=" + timeNow) | ||||||
|                                 .header("Authorization", "Bearer " + sebAdminToken)) |                                 .header("Authorization", "Bearer " + sebAdminToken)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|                         .andReturn().getResponse().getContentAsString(), |                         .andReturn().getResponse().getContentAsString(), | ||||||
|  | @ -962,7 +962,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
| 
 | 
 | ||||||
|         // all active for the own institution |         // all active for the own institution | ||||||
|         Page<UserInfo> usersPage = this.jsonMapper.readValue( |         Page<UserInfo> usersPage = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/all/active") |                 this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/all/active") | ||||||
|                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                         .header("Authorization", "Bearer " + sebAdminToken)) |                         .header("Authorization", "Bearer " + sebAdminToken)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -976,7 +976,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
| 
 | 
 | ||||||
|         // all inactive of the own institution |         // all inactive of the own institution | ||||||
|         usersPage = this.jsonMapper.readValue( |         usersPage = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/all/inactive") |                 this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/all/inactive") | ||||||
|                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                         .header("Authorization", "Bearer " + sebAdminToken)) |                         .header("Authorization", "Bearer " + sebAdminToken)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -990,7 +990,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
| 
 | 
 | ||||||
|         // all active of institution 2 |         // all active of institution 2 | ||||||
|         usersPage = this.jsonMapper.readValue( |         usersPage = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/all/active?institutionId=2") |                 this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/all/active?institutionId=2") | ||||||
|                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                         .header("Authorization", "Bearer " + sebAdminToken)) |                         .header("Authorization", "Bearer " + sebAdminToken)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -1005,7 +1005,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         // all inactive of institution 2 |         // all inactive of institution 2 | ||||||
|         usersPage = this.jsonMapper.readValue( |         usersPage = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc |                 this.mockMvc | ||||||
|                         .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/all/inactive?institutionId=2") |                         .perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/all/inactive?institutionId=2") | ||||||
|                                 .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                                 .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                                 .header("Authorization", "Bearer " + sebAdminToken)) |                                 .header("Authorization", "Bearer " + sebAdminToken)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -1026,7 +1026,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         Collection<UserInfo> users = this.jsonMapper.readValue( |         Collection<UserInfo> users = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc |                 this.mockMvc | ||||||
|                         .perform( |                         .perform( | ||||||
|                                 get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/list?ids=user1,user2,user6,user7") |                                 get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/list?ids=user1,user2,user6,user7") | ||||||
|                                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                                         .header("Authorization", "Bearer " + sebAdminToken)) |                                         .header("Authorization", "Bearer " + sebAdminToken)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -1043,7 +1043,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         users = this.jsonMapper.readValue( |         users = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc |                 this.mockMvc | ||||||
|                         .perform( |                         .perform( | ||||||
|                                 get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/list?ids=user1,user2,user6,user7") |                                 get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/list?ids=user1,user2,user6,user7") | ||||||
|                                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                                         .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                                         .header("Authorization", "Bearer " + instAdminToken)) |                                         .header("Authorization", "Bearer " + instAdminToken)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -1061,14 +1061,14 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         final String sebAdminToken = getSebAdminAccess(); |         final String sebAdminToken = getSebAdminAccess(); | ||||||
| 
 | 
 | ||||||
|         // for SEB Admin |         // for SEB Admin | ||||||
|         Collection<EntityKeyAndName> names = this.jsonMapper.readValue( |         Collection<EntityName> names = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc |                 this.mockMvc | ||||||
|                         .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/names") |                         .perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/names") | ||||||
|                                 .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                                 .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                                 .header("Authorization", "Bearer " + sebAdminToken)) |                                 .header("Authorization", "Bearer " + sebAdminToken)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|                         .andReturn().getResponse().getContentAsString(), |                         .andReturn().getResponse().getContentAsString(), | ||||||
|                 new TypeReference<Collection<EntityKeyAndName>>() { |                 new TypeReference<Collection<EntityName>>() { | ||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
|         assertNotNull(names); |         assertNotNull(names); | ||||||
|  | @ -1081,12 +1081,12 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         final String instAdminToken = getAdminInstitution2Access(); |         final String instAdminToken = getAdminInstitution2Access(); | ||||||
|         names = this.jsonMapper.readValue( |         names = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc |                 this.mockMvc | ||||||
|                         .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/names") |                         .perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/names") | ||||||
|                                 .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                                 .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                                 .header("Authorization", "Bearer " + instAdminToken)) |                                 .header("Authorization", "Bearer " + instAdminToken)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|                         .andReturn().getResponse().getContentAsString(), |                         .andReturn().getResponse().getContentAsString(), | ||||||
|                 new TypeReference<Collection<EntityKeyAndName>>() { |                 new TypeReference<Collection<EntityName>>() { | ||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
|         assertNotNull(names); |         assertNotNull(names); | ||||||
|  | @ -1099,12 +1099,12 @@ public class UserAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         // for an institutional admin 2 only active |         // for an institutional admin 2 only active | ||||||
|         names = this.jsonMapper.readValue( |         names = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc |                 this.mockMvc | ||||||
|                         .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACCOUNT + "/names?active=true") |                         .perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/names?active=true") | ||||||
|                                 .contentType(MediaType.APPLICATION_FORM_URLENCODED) |                                 .contentType(MediaType.APPLICATION_FORM_URLENCODED) | ||||||
|                                 .header("Authorization", "Bearer " + instAdminToken)) |                                 .header("Authorization", "Bearer " + instAdminToken)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|                         .andReturn().getResponse().getContentAsString(), |                         .andReturn().getResponse().getContentAsString(), | ||||||
|                 new TypeReference<Collection<EntityKeyAndName>>() { |                 new TypeReference<Collection<EntityName>>() { | ||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
|         assertNotNull(names); |         assertNotNull(names); | ||||||
|  |  | ||||||
|  | @ -19,9 +19,9 @@ import org.springframework.test.context.jdbc.Sql; | ||||||
| import com.fasterxml.jackson.core.type.TypeReference; | import com.fasterxml.jackson.core.type.TypeReference; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.gbl.Constants; | import ch.ethz.seb.sebserver.gbl.Constants; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.api.SEBServerRestEndpoints; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Page; | import ch.ethz.seb.sebserver.gbl.model.Page; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog; | import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog; | ||||||
| import ch.ethz.seb.sebserver.webservice.weblayer.api.RestAPI; |  | ||||||
| 
 | 
 | ||||||
| @Sql(scripts = { "classpath:schema-test.sql", "classpath:data-test.sql" }) | @Sql(scripts = { "classpath:schema-test.sql", "classpath:data-test.sql" }) | ||||||
| public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester { | public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester { | ||||||
|  | @ -30,7 +30,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester { | ||||||
|     public void getAllAsSEBAdmin() throws Exception { |     public void getAllAsSEBAdmin() throws Exception { | ||||||
|         final String token = getSebAdminAccess(); |         final String token = getSebAdminAccess(); | ||||||
|         final Page<UserActivityLog> logs = this.jsonMapper.readValue( |         final Page<UserActivityLog> logs = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG) |                 this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACTIVITY_LOG) | ||||||
|                         .header("Authorization", "Bearer " + token)) |                         .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|                         .andReturn().getResponse().getContentAsString(), |                         .andReturn().getResponse().getContentAsString(), | ||||||
|  | @ -47,7 +47,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         // for a user in another institution, the institution has to be defined |         // for a user in another institution, the institution has to be defined | ||||||
|         Page<UserActivityLog> logs = this.jsonMapper.readValue( |         Page<UserActivityLog> logs = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc |                 this.mockMvc | ||||||
|                         .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?user=user4&institutionId=2") |                         .perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACTIVITY_LOG + "?user=user4&institutionId=2") | ||||||
|                                 .header("Authorization", "Bearer " + token)) |                                 .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|                         .andReturn().getResponse().getContentAsString(), |                         .andReturn().getResponse().getContentAsString(), | ||||||
|  | @ -59,7 +59,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester { | ||||||
| 
 | 
 | ||||||
|         // for a user in the same institution no institution is needed |         // for a user in the same institution no institution is needed | ||||||
|         logs = this.jsonMapper.readValue( |         logs = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?user=user2") |                 this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACTIVITY_LOG + "?user=user2") | ||||||
|                         .header("Authorization", "Bearer " + token)) |                         .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|                         .andReturn().getResponse().getContentAsString(), |                         .andReturn().getResponse().getContentAsString(), | ||||||
|  | @ -82,7 +82,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         final String token = getSebAdminAccess(); |         final String token = getSebAdminAccess(); | ||||||
|         Page<UserActivityLog> logs = this.jsonMapper.readValue( |         Page<UserActivityLog> logs = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform( |                 this.mockMvc.perform( | ||||||
|                         get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?institutionId=2&from=" + sec2) |                         get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACTIVITY_LOG + "?institutionId=2&from=" + sec2) | ||||||
|                                 .header("Authorization", "Bearer " + token)) |                                 .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|                         .andReturn().getResponse().getContentAsString(), |                         .andReturn().getResponse().getContentAsString(), | ||||||
|  | @ -94,7 +94,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester { | ||||||
| 
 | 
 | ||||||
|         logs = this.jsonMapper.readValue( |         logs = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc |                 this.mockMvc | ||||||
|                         .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?institutionId=2&from=" |                         .perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACTIVITY_LOG + "?institutionId=2&from=" | ||||||
|                                 + sec2 + "&to=" + sec4) |                                 + sec2 + "&to=" + sec4) | ||||||
|                                         .header("Authorization", "Bearer " + token)) |                                         .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -108,7 +108,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         logs = this.jsonMapper.readValue( |         logs = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc |                 this.mockMvc | ||||||
|                         .perform( |                         .perform( | ||||||
|                                 get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?institutionId=2&from=" + sec2 |                                 get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACTIVITY_LOG + "?institutionId=2&from=" + sec2 | ||||||
|                                         + "&to=" + sec5) |                                         + "&to=" + sec5) | ||||||
|                                                 .header("Authorization", "Bearer " + token)) |                                                 .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -122,7 +122,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         logs = this.jsonMapper.readValue( |         logs = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc |                 this.mockMvc | ||||||
|                         .perform( |                         .perform( | ||||||
|                                 get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?institutionId=2&from=" + sec2 |                                 get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACTIVITY_LOG + "?institutionId=2&from=" + sec2 | ||||||
|                                         + "&to=" + sec6) |                                         + "&to=" + sec6) | ||||||
|                                                 .header("Authorization", "Bearer " + token)) |                                                 .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -138,7 +138,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester { | ||||||
|     public void getAllAsSEBAdminForActivityType() throws Exception { |     public void getAllAsSEBAdminForActivityType() throws Exception { | ||||||
|         final String token = getSebAdminAccess(); |         final String token = getSebAdminAccess(); | ||||||
|         Page<UserActivityLog> logs = this.jsonMapper.readValue( |         Page<UserActivityLog> logs = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?activity_types=CREATE") |                 this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACTIVITY_LOG + "?activity_types=CREATE") | ||||||
|                         .header("Authorization", "Bearer " + token)) |                         .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|                         .andReturn().getResponse().getContentAsString(), |                         .andReturn().getResponse().getContentAsString(), | ||||||
|  | @ -151,7 +151,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         logs = this.jsonMapper.readValue( |         logs = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc |                 this.mockMvc | ||||||
|                         .perform( |                         .perform( | ||||||
|                                 get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG |                                 get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACTIVITY_LOG | ||||||
|                                         + "?activity_types=CREATE,MODIFY") |                                         + "?activity_types=CREATE,MODIFY") | ||||||
|                                                 .header("Authorization", "Bearer " + token)) |                                                 .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -166,7 +166,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         logs = this.jsonMapper.readValue( |         logs = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc |                 this.mockMvc | ||||||
|                         .perform( |                         .perform( | ||||||
|                                 get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG |                                 get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACTIVITY_LOG | ||||||
|                                         + "?institutionId=2&activity_types=CREATE,MODIFY") |                                         + "?institutionId=2&activity_types=CREATE,MODIFY") | ||||||
|                                                 .header("Authorization", "Bearer " + token)) |                                                 .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -183,7 +183,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         final String token = getSebAdminAccess(); |         final String token = getSebAdminAccess(); | ||||||
|         Page<UserActivityLog> logs = this.jsonMapper.readValue( |         Page<UserActivityLog> logs = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc |                 this.mockMvc | ||||||
|                         .perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?entity_types=INSTITUTION") |                         .perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACTIVITY_LOG + "?entity_types=INSTITUTION") | ||||||
|                                 .header("Authorization", "Bearer " + token)) |                                 .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|                         .andReturn().getResponse().getContentAsString(), |                         .andReturn().getResponse().getContentAsString(), | ||||||
|  | @ -196,7 +196,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         logs = this.jsonMapper.readValue( |         logs = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc |                 this.mockMvc | ||||||
|                         .perform( |                         .perform( | ||||||
|                                 get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG |                                 get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACTIVITY_LOG | ||||||
|                                         + "?entity_types=INSTITUTION,EXAM") |                                         + "?entity_types=INSTITUTION,EXAM") | ||||||
|                                                 .header("Authorization", "Bearer " + token)) |                                                 .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -210,7 +210,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         logs = this.jsonMapper.readValue( |         logs = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc |                 this.mockMvc | ||||||
|                         .perform( |                         .perform( | ||||||
|                                 get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG |                                 get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACTIVITY_LOG | ||||||
|                                         + "?entity_types=INSTITUTION,EXAM&institutionId=2") |                                         + "?entity_types=INSTITUTION,EXAM&institutionId=2") | ||||||
|                                                 .header("Authorization", "Bearer " + token)) |                                                 .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|  | @ -226,7 +226,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester { | ||||||
|     public void getAllAsInstitutionalAdmin() throws Exception { |     public void getAllAsInstitutionalAdmin() throws Exception { | ||||||
|         final String token = getAdminInstitution1Access(); |         final String token = getAdminInstitution1Access(); | ||||||
|         final Page<UserActivityLog> logs = this.jsonMapper.readValue( |         final Page<UserActivityLog> logs = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG) |                 this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACTIVITY_LOG) | ||||||
|                         .header("Authorization", "Bearer " + token)) |                         .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|                         .andReturn().getResponse().getContentAsString(), |                         .andReturn().getResponse().getContentAsString(), | ||||||
|  | @ -242,18 +242,18 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester { | ||||||
|         String token = getExamAdmin1(); |         String token = getExamAdmin1(); | ||||||
| 
 | 
 | ||||||
|         // no privilege at all |         // no privilege at all | ||||||
|         this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG) |         this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACTIVITY_LOG) | ||||||
|                 .header("Authorization", "Bearer " + token)) |                 .header("Authorization", "Bearer " + token)) | ||||||
|                 .andExpect(status().isForbidden()); |                 .andExpect(status().isForbidden()); | ||||||
|         // no privilege at all |         // no privilege at all | ||||||
|         this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?user=user4") |         this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACTIVITY_LOG + "?user=user4") | ||||||
|                 .header("Authorization", "Bearer " + token)) |                 .header("Authorization", "Bearer " + token)) | ||||||
|                 .andExpect(status().isForbidden()); |                 .andExpect(status().isForbidden()); | ||||||
| 
 | 
 | ||||||
|         // no privilege to query logs of users of other institution |         // no privilege to query logs of users of other institution | ||||||
|         token = getAdminInstitution1Access(); |         token = getAdminInstitution1Access(); | ||||||
|         final Page<UserActivityLog> logs = this.jsonMapper.readValue( |         final Page<UserActivityLog> logs = this.jsonMapper.readValue( | ||||||
|                 this.mockMvc.perform(get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG + "?user=user4") |                 this.mockMvc.perform(get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACTIVITY_LOG + "?user=user4") | ||||||
|                         .header("Authorization", "Bearer " + token)) |                         .header("Authorization", "Bearer " + token)) | ||||||
|                         .andExpect(status().isOk()) |                         .andExpect(status().isOk()) | ||||||
|                         .andReturn().getResponse().getContentAsString(), |                         .andReturn().getResponse().getContentAsString(), | ||||||
|  |  | ||||||
|  | @ -31,7 +31,7 @@ import org.springframework.util.MultiValueMap; | ||||||
| import org.springframework.web.context.WebApplicationContext; | import org.springframework.web.context.WebApplicationContext; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.SEBServer; | import ch.ethz.seb.sebserver.SEBServer; | ||||||
| import ch.ethz.seb.sebserver.gbl.JSONMapper; | import ch.ethz.seb.sebserver.gbl.api.JSONMapper; | ||||||
| 
 | 
 | ||||||
| @RunWith(SpringRunner.class) | @RunWith(SpringRunner.class) | ||||||
| @SpringBootTest( | @SpringBootTest( | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 anhefti
						anhefti