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…
Reference in a new issue