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
8
pom.xml
8
pom.xml
|
@ -224,7 +224,13 @@
|
|||
<artifactId>spring-security-jwt</artifactId>
|
||||
<version>1.0.9.RELEASE</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Apache HTTP -->
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Eclipse RAP / RWT -->
|
||||
<dependency>
|
||||
<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.Configuration;
|
||||
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.WebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
|
@ -90,6 +91,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter implements E
|
|||
final HttpServletResponse response,
|
||||
final AuthenticationException authException) throws IOException, ServletException {
|
||||
|
||||
response.setStatus(HttpStatus.UNAUTHORIZED.value());
|
||||
response.sendRedirect(WebSecurityConfig.this.unauthorizedRedirect);
|
||||
}
|
||||
})
|
||||
|
@ -104,6 +106,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter implements E
|
|||
|
||||
@RequestMapping("/error")
|
||||
public void handleError(final HttpServletResponse response) throws IOException {
|
||||
response.setStatus(HttpStatus.NOT_FOUND.value());
|
||||
response.sendRedirect(this.unauthorizedRedirect);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,9 +6,11 @@
|
|||
* 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.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -72,12 +74,14 @@ public class APIMessage implements Serializable {
|
|||
return new APIMessage(this.messageCode, this.systemMessage, error.getMessage());
|
||||
}
|
||||
|
||||
public ResponseEntity<APIMessage> createErrorResponse() {
|
||||
return new ResponseEntity<>(of(), this.httpStatus);
|
||||
public ResponseEntity<List<APIMessage>> createErrorResponse() {
|
||||
final APIMessage message = of();
|
||||
return new ResponseEntity<>(Arrays.asList(message), this.httpStatus);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 {
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gbl;
|
||||
package ch.ethz.seb.sebserver.gbl.api;
|
||||
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
|
@ -6,7 +6,7 @@
|
|||
* 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.List;
|
|
@ -6,9 +6,9 @@
|
|||
* 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";
|
||||
|
|
@ -22,8 +22,8 @@ public interface Entity extends ModelIdAware {
|
|||
@JsonIgnore
|
||||
String getName();
|
||||
|
||||
public static EntityKeyAndName toName(final Entity entity) {
|
||||
return new EntityKeyAndName(
|
||||
public static EntityName toName(final Entity entity) {
|
||||
return new EntityName(
|
||||
entity.entityType(),
|
||||
entity.getModelId(),
|
||||
entity.getName());
|
||||
|
|
|
@ -14,7 +14,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
|||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class EntityKeyAndName implements ModelIdAware, ModelNameAware {
|
||||
public class EntityName implements ModelIdAware, ModelNameAware {
|
||||
|
||||
@JsonProperty(value = "entityType", required = true)
|
||||
public final EntityType entityType;
|
||||
|
@ -24,7 +24,7 @@ public class EntityKeyAndName implements ModelIdAware, ModelNameAware {
|
|||
public final String name;
|
||||
|
||||
@JsonCreator
|
||||
public EntityKeyAndName(
|
||||
public EntityName(
|
||||
@JsonProperty(value = "entityType", required = true) final EntityType entityType,
|
||||
@JsonProperty(value = Domain.ATTR_ID, required = true) final String id,
|
||||
@JsonProperty(value = "name", required = true) final String name) {
|
||||
|
@ -34,7 +34,7 @@ public class EntityKeyAndName implements ModelIdAware, ModelNameAware {
|
|||
this.name = name;
|
||||
}
|
||||
|
||||
public EntityKeyAndName(final EntityKey entityKey, final String name) {
|
||||
public EntityName(final EntityKey entityKey, final String name) {
|
||||
|
||||
this.entityType = entityKey.entityType;
|
||||
this.modelId = entityKey.modelId;
|
||||
|
@ -74,7 +74,7 @@ public class EntityKeyAndName implements ModelIdAware, ModelNameAware {
|
|||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
final EntityKeyAndName other = (EntityKeyAndName) obj;
|
||||
final EntityName other = (EntityName) obj;
|
||||
if (this.entityType != other.entityType)
|
||||
return false;
|
||||
if (this.modelId == null) {
|
|
@ -14,6 +14,7 @@ import java.util.Set;
|
|||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
|
||||
public class EntityProcessingReport {
|
||||
|
|
|
@ -19,7 +19,7 @@ import com.fasterxml.jackson.annotation.JsonCreator;
|
|||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
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.Domain.EXAM;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityType;
|
||||
|
|
|
@ -13,7 +13,7 @@ import javax.validation.constraints.Size;
|
|||
|
||||
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.Domain;
|
||||
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.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.Domain;
|
||||
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.EntityKeyAndName;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityName;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityType;
|
||||
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 + "]";
|
||||
}
|
||||
|
||||
public static EntityKeyAndName toName(final LmsSetup lmsSetup) {
|
||||
return new EntityKeyAndName(
|
||||
public static EntityName toName(final LmsSetup lmsSetup) {
|
||||
return new EntityName(
|
||||
EntityType.LMS_SETUP,
|
||||
String.valueOf(lmsSetup.id),
|
||||
lmsSetup.name);
|
||||
|
|
|
@ -156,6 +156,13 @@ public final class UserInfo implements GrantEntity, Activatable, Serializable {
|
|||
return this.roles;
|
||||
}
|
||||
|
||||
public boolean hasRole(final UserRole userRole) {
|
||||
if (userRole == null) {
|
||||
return false;
|
||||
}
|
||||
return this.roles.contains(userRole.name());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
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.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_ROLE;
|
||||
import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityType;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.GrantEntity;
|
||||
|
||||
|
|
|
@ -69,23 +69,58 @@ public final class Result<T> {
|
|||
return this.value;
|
||||
}
|
||||
|
||||
/** @return the error if some was reporter or null if there was no error */
|
||||
public Throwable getError() {
|
||||
return this.error;
|
||||
/** 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 get(final Function<Throwable, T> errorHandler) {
|
||||
return this.error != null ? errorHandler.apply(this.error) : this.value;
|
||||
}
|
||||
|
||||
public boolean hasError() {
|
||||
return this.error != null;
|
||||
public T get(final Consumer<Throwable> errorHandler, final Supplier<T> supplier) {
|
||||
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
|
||||
*
|
||||
* @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 */
|
||||
public T getOrElse(final T other) {
|
||||
public T getOr(final T 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
|
||||
*
|
||||
* @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 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,
|
||||
* 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) {
|
||||
if (this.error != null) {
|
||||
block.accept(this.error);
|
||||
|
@ -172,31 +206,6 @@ public final class Result<T> {
|
|||
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.
|
||||
*
|
||||
* @param value resulting value
|
||||
|
|
|
@ -103,7 +103,7 @@ public final class Utils {
|
|||
|
||||
public static Long dateTimeStringToTimestamp(final String startTime, final Long defaultValue) {
|
||||
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) {
|
||||
|
|
|
@ -11,7 +11,6 @@ package ch.ethz.seb.sebserver.gui;
|
|||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
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.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
|
@ -43,38 +42,4 @@ public class GuiWebsecurityConfig extends WebSecurityConfigurerAdapter {
|
|||
.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.type.TypeReference;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.JSONMapper;
|
||||
import ch.ethz.seb.sebserver.gbl.model.APIMessage;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Page;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
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.jsonMapper = jsonMapper;
|
||||
return this;
|
||||
}
|
||||
|
||||
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 {
|
||||
|
||||
private final HttpHeaders httpHeaders = new HttpHeaders();
|
||||
|
@ -117,7 +122,7 @@ public abstract class RestCall<T> {
|
|||
RestCallBuilder() {
|
||||
this.httpHeaders.set(
|
||||
HttpHeaders.CONTENT_TYPE,
|
||||
RestCall.this.contentType.getType());
|
||||
RestCall.this.contentType.toString());
|
||||
}
|
||||
|
||||
public RestCallBuilder withHeaders(final HttpHeaders headers) {
|
||||
|
@ -165,7 +170,7 @@ public abstract class RestCall<T> {
|
|||
return this;
|
||||
}
|
||||
|
||||
public final Result<T> exchange() {
|
||||
public final Result<T> call() {
|
||||
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.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;
|
||||
|
||||
|
@ -27,6 +28,7 @@ public class RestCallError extends RuntimeException {
|
|||
super(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<APIMessage> getErrorMessages() {
|
||||
return this.errors;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
|
||||
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.LoggerFactory;
|
||||
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.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.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
|
||||
@Service
|
||||
|
@ -28,17 +32,23 @@ public class RestService {
|
|||
private static final Logger log = LoggerFactory.getLogger(RestService.class);
|
||||
|
||||
private final AuthorizationContextHolder authorizationContextHolder;
|
||||
private final WebserviceURIBuilderSupplier webserviceURIBuilderSupplier;
|
||||
private final JSONMapper jsonMapper;
|
||||
private final WebserviceURIService webserviceURIBuilderSupplier;
|
||||
private final Map<String, RestCall<?>> calls;
|
||||
|
||||
public RestService(
|
||||
final AuthorizationContextHolder authorizationContextHolder,
|
||||
final WebserviceURIBuilderSupplier webserviceURIBuilderSupplier,
|
||||
final JSONMapper jsonMapper) {
|
||||
final WebserviceURIService webserviceURIBuilderSupplier,
|
||||
final JSONMapper jsonMapper,
|
||||
final Collection<RestCall<?>> calls) {
|
||||
|
||||
this.authorizationContextHolder = authorizationContextHolder;
|
||||
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() {
|
||||
|
@ -51,15 +61,19 @@ public class RestService {
|
|||
return this.webserviceURIBuilderSupplier.getBuilder();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> RestCall<T> getRestCall(final Class<? extends RestCall<T>> type) {
|
||||
try {
|
||||
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);
|
||||
return (RestCall<T>) this.calls.get(type.getName());
|
||||
}
|
||||
|
||||
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() {
|
||||
if (isAvailable()) {
|
||||
return this.authContext.getLoggedInUser();
|
||||
return this.authContext
|
||||
.getLoggedInUser()
|
||||
.getOrThrow();
|
||||
}
|
||||
|
||||
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.context.annotation.Lazy;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
|
||||
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.UserRole;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
|
@ -50,23 +53,23 @@ public class OAuth2AuthorizationContextHolder implements AuthorizationContextHol
|
|||
private static final Logger log = LoggerFactory.getLogger(OAuth2AuthorizationContextHolder.class);
|
||||
|
||||
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 guiClientSecret;
|
||||
private final WebserviceURIBuilderSupplier webserviceURIBuilderSupplier;
|
||||
private final WebserviceURIService webserviceURIService;
|
||||
private final ClientHttpRequestFactory clientHttpRequestFactory;
|
||||
|
||||
@Autowired
|
||||
public OAuth2AuthorizationContextHolder(
|
||||
@Value("${sebserver.gui.webservice.clientId}") final String guiClientId,
|
||||
@Value("${sebserver.gui.webservice.clientSecret}") final String guiClientSecret,
|
||||
final WebserviceURIBuilderSupplier webserviceURIBuilderSupplier) {
|
||||
final WebserviceURIService webserviceURIService,
|
||||
final ClientHttpRequestFactory clientHttpRequestFactory) {
|
||||
|
||||
this.guiClientId = guiClientId;
|
||||
this.guiClientSecret = guiClientSecret;
|
||||
this.webserviceURIBuilderSupplier = webserviceURIBuilderSupplier;
|
||||
this.webserviceURIService = webserviceURIService;
|
||||
this.clientHttpRequestFactory = clientHttpRequestFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -85,7 +88,8 @@ public class OAuth2AuthorizationContextHolder implements AuthorizationContextHol
|
|||
context = new OAuth2AuthorizationContext(
|
||||
this.guiClientId,
|
||||
this.guiClientSecret,
|
||||
this.webserviceURIBuilderSupplier);
|
||||
this.webserviceURIService,
|
||||
this.clientHttpRequestFactory);
|
||||
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 List<String> SCOPES = Collections.unmodifiableList(
|
||||
Arrays.asList("web-service-api-read", "web-service-api-write"));
|
||||
Arrays.asList("read", "write"));
|
||||
|
||||
private boolean valid = true;
|
||||
|
||||
|
@ -141,34 +145,26 @@ public class OAuth2AuthorizationContextHolder implements AuthorizationContextHol
|
|||
private final String revokeTokenURI;
|
||||
private final String currentUserURI;
|
||||
|
||||
private UserInfo loggedInUser = null;
|
||||
private Result<UserInfo> loggedInUser = null;
|
||||
|
||||
OAuth2AuthorizationContext(
|
||||
final String guiClientId,
|
||||
final String guiClientSecret,
|
||||
final WebserviceURIBuilderSupplier webserviceURIBuilderSupplier) {
|
||||
final WebserviceURIService webserviceURIService,
|
||||
final ClientHttpRequestFactory clientHttpRequestFactory) {
|
||||
|
||||
this.resource = new ResourceOwnerPasswordResourceDetails();
|
||||
this.resource.setAccessTokenUri(
|
||||
webserviceURIBuilderSupplier
|
||||
.getBuilder()
|
||||
.path(OAUTH_TOKEN_URI_PATH)
|
||||
.toUriString() /* restCallBuilder.withPath(OAUTH_TOKEN_URI_PATH) */);
|
||||
this.resource.setAccessTokenUri(webserviceURIService.getOAuthTokenURI());
|
||||
this.resource.setClientId(guiClientId);
|
||||
this.resource.setClientSecret(guiClientSecret);
|
||||
this.resource.setGrantType(GRANT_TYPE);
|
||||
this.resource.setScope(SCOPES);
|
||||
|
||||
this.restTemplate = new DisposableOAuth2RestTemplate(this.resource);
|
||||
this.restTemplate.setRequestFactory(clientHttpRequestFactory);
|
||||
|
||||
this.revokeTokenURI = webserviceURIBuilderSupplier
|
||||
.getBuilder()
|
||||
.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);
|
||||
this.revokeTokenURI = webserviceURIService.getOAuthRevokeTokenURI();
|
||||
this.currentUserURI = webserviceURIService.getCurrentUserRequestURI();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -227,7 +223,7 @@ public class OAuth2AuthorizationContextHolder implements AuthorizationContextHol
|
|||
}
|
||||
|
||||
@Override
|
||||
public UserInfo getLoggedInUser() {
|
||||
public Result<UserInfo> getLoggedInUser() {
|
||||
if (this.loggedInUser != null) {
|
||||
return this.loggedInUser;
|
||||
}
|
||||
|
@ -237,18 +233,27 @@ public class OAuth2AuthorizationContextHolder implements AuthorizationContextHol
|
|||
try {
|
||||
if (isValid() && isLoggedIn()) {
|
||||
final ResponseEntity<UserInfo> response =
|
||||
this.restTemplate.getForEntity(this.currentUserURI, UserInfo.class);
|
||||
this.loggedInUser = response.getBody();
|
||||
return this.loggedInUser;
|
||||
this.restTemplate
|
||||
.getForEntity(this.currentUserURI, UserInfo.class);
|
||||
if (response.getStatusCode() == HttpStatus.OK) {
|
||||
this.loggedInUser = Result.of(response.getBody());
|
||||
return this.loggedInUser;
|
||||
} else {
|
||||
log.error("Unexpected error response: {}", response);
|
||||
return Result.ofError(new IllegalStateException(
|
||||
"Http Request responded with status: " + response.getStatusCode()));
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException("Logged in User requested on invalid or not logged in ");
|
||||
return Result.ofError(
|
||||
new IllegalStateException("Logged in User requested on invalid or not logged in "));
|
||||
}
|
||||
} catch (final AccessDeniedException | OAuth2AccessDeniedException 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) {
|
||||
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,8 +263,9 @@ public class OAuth2AuthorizationContextHolder implements AuthorizationContextHol
|
|||
return false;
|
||||
}
|
||||
|
||||
return getLoggedInUser().roles
|
||||
.contains(role.name());
|
||||
return getLoggedInUser()
|
||||
.getOrThrow().roles
|
||||
.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.UserRole;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
|
||||
public interface SEBServerAuthorizationContext {
|
||||
|
||||
|
@ -23,7 +24,7 @@ public interface SEBServerAuthorizationContext {
|
|||
|
||||
boolean logout();
|
||||
|
||||
UserInfo getLoggedInUser();
|
||||
Result<UserInfo> getLoggedInUser();
|
||||
|
||||
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)
|
||||
? ((ActivatableEntityDAO<?, ?>) this).setActive(all, true)
|
||||
.map(BulkActionSupportDAO::transformResult)
|
||||
.getOrHandleError(error -> handleBulkActionError(error, all))
|
||||
.get(error -> handleBulkActionError(error, all))
|
||||
: Collections.emptyList();
|
||||
case DEACTIVATE:
|
||||
return (this instanceof ActivatableEntityDAO)
|
||||
? ((ActivatableEntityDAO<?, ?>) this).setActive(all, false)
|
||||
.map(BulkActionSupportDAO::transformResult)
|
||||
.getOrHandleError(error -> handleBulkActionError(error, all))
|
||||
.get(error -> handleBulkActionError(error, all))
|
||||
: Collections.emptyList();
|
||||
case HARD_DELETE:
|
||||
return (this instanceof EntityDAO)
|
||||
? ((EntityDAO<?, ?>) this).delete(all)
|
||||
.map(BulkActionSupportDAO::transformResult)
|
||||
.getOrHandleError(error -> handleBulkActionError(error, all))
|
||||
.get(error -> handleBulkActionError(error, all))
|
||||
: 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.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.ModelIdAware;
|
||||
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);
|
||||
|
||||
@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 loadEntities(keys)
|
||||
.getOrThrow()
|
||||
.stream()
|
||||
.map(entity -> new EntityKeyAndName(
|
||||
.map(entity -> new EntityName(
|
||||
entity.entityType(),
|
||||
entity.getModelId(),
|
||||
entity.getName()))
|
||||
|
|
|
@ -11,7 +11,7 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.dao;
|
|||
import org.joda.time.DateTime;
|
||||
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.Indicator;
|
||||
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 ch.ethz.seb.sebserver.WebSecurityConfig;
|
||||
import ch.ethz.seb.sebserver.gbl.model.APIMessage.APIMessageException;
|
||||
import ch.ethz.seb.sebserver.gbl.model.APIMessage.ErrorMessage;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage.APIMessageException;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage.ErrorMessage;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityType;
|
||||
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.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
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",
|
||||
request.getRequestURI());
|
||||
|
||||
response.setStatus(HttpStatus.UNAUTHORIZED.value());
|
||||
response.sendRedirect(this.redirect);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,8 +31,8 @@ public class WebServiceUserDetails implements UserDetailsService {
|
|||
@Override
|
||||
public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {
|
||||
return this.userDAO.sebServerUserByUsername(username)
|
||||
.getOrHandleError(t -> {
|
||||
throw new UsernameNotFoundException("No User with name: " + username + " found", t);
|
||||
.get(error -> {
|
||||
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.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
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.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.APIMessage;
|
||||
import ch.ethz.seb.sebserver.gbl.model.APIMessage.APIMessageException;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||
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.dao.ResourceNotFoundException;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationException;
|
||||
|
@ -47,7 +48,8 @@ public class APIExceptionHandler extends ResponseEntityExceptionHandler {
|
|||
final WebRequest request) {
|
||||
|
||||
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
|
||||
|
|
|
@ -28,11 +28,11 @@ import org.springframework.web.bind.annotation.RequestMethod;
|
|||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
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.Entity;
|
||||
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.EntityType;
|
||||
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,
|
||||
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
|
||||
produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public Collection<EntityKeyAndName> getNames(
|
||||
public Collection<EntityName> getNames(
|
||||
@RequestParam(
|
||||
name = Entity.FILTER_ATTR_INSTITUTION,
|
||||
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.RestController;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.POSTMapper;
|
||||
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.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityType;
|
||||
|
@ -58,7 +59,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationSe
|
|||
|
||||
@WebServiceProfile
|
||||
@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> {
|
||||
|
||||
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.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.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.InstitutionRecordDynamicSqlSupport;
|
||||
|
@ -27,7 +28,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationSe
|
|||
|
||||
@WebServiceProfile
|
||||
@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> {
|
||||
|
||||
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.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.institution.LmsSetup;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
|
@ -37,7 +38,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationSe
|
|||
|
||||
@WebServiceProfile
|
||||
@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> {
|
||||
|
||||
private final LmsAPIService lmsAPIService;
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.springframework.web.bind.annotation.RequestParam;
|
|||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
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.Page;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.QuizData;
|
||||
|
@ -27,7 +28,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPITemplate;
|
|||
|
||||
@WebServiceProfile
|
||||
@RestController
|
||||
@RequestMapping("/${sebserver.webservice.api.admin.endpoint}" + RestAPI.ENDPOINT_QUIZ_IMPORT)
|
||||
@RequestMapping("/${sebserver.webservice.api.admin.endpoint}" + SEBServerRestEndpoints.ENDPOINT_QUIZ_IMPORT)
|
||||
public class QuizImportController {
|
||||
|
||||
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.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.UserMod;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
|
@ -30,7 +31,7 @@ import ch.ethz.seb.sebserver.webservice.weblayer.oauth.RevokeTokenEndpoint;
|
|||
|
||||
@WebServiceProfile
|
||||
@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> {
|
||||
|
||||
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.RestController;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.SEBServerRestEndpoints;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Page;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog;
|
||||
|
@ -32,7 +33,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;
|
|||
|
||||
@WebServiceProfile
|
||||
@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 {
|
||||
|
||||
private final UserActivityLogDAO userActivityLogDAO;
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
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;
|
||||
}
|
||||
|
||||
Composite.selectionPane {
|
||||
Composite.actionPane {
|
||||
background-color: #D3D9DB;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ import java.io.IOException;
|
|||
|
||||
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.webservice.servicelayer.dao.UserActivityLogDAO.ActivityType;
|
||||
|
||||
|
|
|
@ -75,8 +75,8 @@ public class ResultTest {
|
|||
final Result<String> resultOf = Result.of("ONE");
|
||||
final Result<String> resultOfError = Result.ofError(new RuntimeException("Some Error"));
|
||||
|
||||
assertEquals("ONE", resultOf.getOrElse("TWO"));
|
||||
assertEquals("TWO", resultOfError.getOrElse("TWO"));
|
||||
assertEquals("ONE", resultOf.getOr("TWO"));
|
||||
assertEquals("TWO", resultOfError.getOr("TWO"));
|
||||
|
||||
assertEquals("ONE", resultOf.getOrElse(() -> "TWO"));
|
||||
assertEquals("TWO", resultOfError.getOrElse(() -> "TWO"));
|
||||
|
@ -87,8 +87,8 @@ public class ResultTest {
|
|||
final Result<String> resultOf = Result.of("ONE");
|
||||
final Result<String> resultOfError = Result.ofError(new RuntimeException("Some Error"));
|
||||
|
||||
assertEquals("ONE", resultOf.getOrHandleError(t -> t.getMessage()));
|
||||
assertEquals("Some Error", resultOfError.getOrHandleError(t -> t.getMessage()));
|
||||
assertEquals("ONE", resultOf.get(t -> t.getMessage()));
|
||||
assertEquals("Some Error", resultOfError.get(t -> t.getMessage()));
|
||||
|
||||
assertEquals("ONE", resultOf.getOrThrowRuntime("Should not be thrown"));
|
||||
try {
|
||||
|
|
|
@ -41,7 +41,7 @@ import org.springframework.web.context.WebApplicationContext;
|
|||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
|
||||
import ch.ethz.seb.sebserver.SEBServer;
|
||||
import ch.ethz.seb.sebserver.gbl.JSONMapper;
|
||||
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(
|
||||
|
|
|
@ -19,11 +19,11 @@ import org.springframework.test.context.jdbc.Sql;
|
|||
|
||||
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.Page;
|
||||
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" })
|
||||
public class InstitutionAPITest extends AdministrationAPIIntegrationTester {
|
||||
|
@ -32,7 +32,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester {
|
|||
public void getInstitutions() throws Exception {
|
||||
Page<Institution> institutions = new RestAPITestHelper()
|
||||
.withAccessToken(getSebAdminAccess())
|
||||
.withPath(RestAPI.ENDPOINT_INSTITUTION)
|
||||
.withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION)
|
||||
.withExpectedStatus(HttpStatus.OK)
|
||||
.getAsObject(new TypeReference<Page<Institution>>() {
|
||||
});
|
||||
|
@ -44,7 +44,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester {
|
|||
|
||||
institutions = new RestAPITestHelper()
|
||||
.withAccessToken(getSebAdminAccess())
|
||||
.withPath(RestAPI.ENDPOINT_INSTITUTION)
|
||||
.withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION)
|
||||
.withAttribute("active", "true")
|
||||
.withExpectedStatus(HttpStatus.OK)
|
||||
.getAsObject(new TypeReference<Page<Institution>>() {
|
||||
|
@ -57,7 +57,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester {
|
|||
|
||||
institutions = new RestAPITestHelper()
|
||||
.withAccessToken(getSebAdminAccess())
|
||||
.withPath(RestAPI.ENDPOINT_INSTITUTION)
|
||||
.withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION)
|
||||
.withAttribute("active", "false")
|
||||
.withExpectedStatus(HttpStatus.OK)
|
||||
.getAsObject(new TypeReference<Page<Institution>>() {
|
||||
|
@ -70,7 +70,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester {
|
|||
// institutional admin sees only his institution
|
||||
institutions = new RestAPITestHelper()
|
||||
.withAccessToken(getAdminInstitution1Access())
|
||||
.withPath(RestAPI.ENDPOINT_INSTITUTION)
|
||||
.withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION)
|
||||
.withExpectedStatus(HttpStatus.OK)
|
||||
.getAsObject(new TypeReference<Page<Institution>>() {
|
||||
});
|
||||
|
@ -82,7 +82,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester {
|
|||
// Institutional admin tries to get data from other institution
|
||||
final APIMessage errorMessage = new RestAPITestHelper()
|
||||
.withAccessToken(getAdminInstitution1Access())
|
||||
.withPath(RestAPI.ENDPOINT_INSTITUTION)
|
||||
.withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION)
|
||||
.withAttribute("institutionId", "2") // try to hack
|
||||
.withExpectedStatus(HttpStatus.FORBIDDEN)
|
||||
.getAsObject(new TypeReference<APIMessage>() {
|
||||
|
@ -96,7 +96,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester {
|
|||
public void getInstitutionById() throws Exception {
|
||||
Institution institution = new RestAPITestHelper()
|
||||
.withAccessToken(getSebAdminAccess())
|
||||
.withPath(RestAPI.ENDPOINT_INSTITUTION + "/1")
|
||||
.withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION + "/1")
|
||||
.withExpectedStatus(HttpStatus.OK)
|
||||
.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
|
||||
institution = new RestAPITestHelper()
|
||||
.withAccessToken(getSebAdminAccess())
|
||||
.withPath(RestAPI.ENDPOINT_INSTITUTION + "/2")
|
||||
.withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION + "/2")
|
||||
.withExpectedStatus(HttpStatus.OK)
|
||||
.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
|
||||
new RestAPITestHelper()
|
||||
.withAccessToken(getAdminInstitution1Access())
|
||||
.withPath(RestAPI.ENDPOINT_INSTITUTION + "/2")
|
||||
.withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION + "/2")
|
||||
.withExpectedStatus(HttpStatus.FORBIDDEN)
|
||||
.getAsString();
|
||||
}
|
||||
|
@ -128,7 +128,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester {
|
|||
// create new institution with seb-admin
|
||||
Institution institution = new RestAPITestHelper()
|
||||
.withAccessToken(getSebAdminAccess())
|
||||
.withPath(RestAPI.ENDPOINT_INSTITUTION)
|
||||
.withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION)
|
||||
.withMethod(HttpMethod.POST)
|
||||
.withAttribute("name", "new institution")
|
||||
.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
|
||||
APIMessage errorMessage = new RestAPITestHelper()
|
||||
.withAccessToken(getAdminInstitution1Access())
|
||||
.withPath(RestAPI.ENDPOINT_INSTITUTION)
|
||||
.withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION)
|
||||
.withMethod(HttpMethod.POST)
|
||||
.withAttribute("name", "new institution")
|
||||
.withAttribute("urlSuffix", "new_inst")
|
||||
|
@ -156,7 +156,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester {
|
|||
// and name for institution must be unique
|
||||
errorMessage = new RestAPITestHelper()
|
||||
.withAccessToken(getSebAdminAccess())
|
||||
.withPath(RestAPI.ENDPOINT_INSTITUTION)
|
||||
.withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION)
|
||||
.withMethod(HttpMethod.POST)
|
||||
.withAttribute("name", "new institution")
|
||||
.withAttribute("urlSuffix", "new_inst")
|
||||
|
@ -171,7 +171,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester {
|
|||
// and predefined id should be ignored
|
||||
institution = new RestAPITestHelper()
|
||||
.withAccessToken(getSebAdminAccess())
|
||||
.withPath(RestAPI.ENDPOINT_INSTITUTION)
|
||||
.withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION)
|
||||
.withMethod(HttpMethod.POST)
|
||||
.withAttribute("id", "123")
|
||||
.withAttribute("name", "newer institution")
|
||||
|
@ -191,7 +191,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester {
|
|||
final String sebAdminAccess = getSebAdminAccess();
|
||||
Institution institution = new RestAPITestHelper()
|
||||
.withAccessToken(sebAdminAccess)
|
||||
.withPath(RestAPI.ENDPOINT_INSTITUTION)
|
||||
.withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION)
|
||||
.withMethod(HttpMethod.POST)
|
||||
.withAttribute("name", "testInstitution")
|
||||
.withExpectedStatus(HttpStatus.OK)
|
||||
|
@ -205,7 +205,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester {
|
|||
// get
|
||||
institution = new RestAPITestHelper()
|
||||
.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)
|
||||
.withExpectedStatus(HttpStatus.OK)
|
||||
.getAsObject(new TypeReference<Institution>() {
|
||||
|
@ -219,7 +219,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester {
|
|||
// modify
|
||||
institution = new RestAPITestHelper()
|
||||
.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)
|
||||
.withBodyJson(new Institution(null, "testInstitution", "testSuffix", null, null))
|
||||
.withExpectedStatus(HttpStatus.OK)
|
||||
|
@ -234,7 +234,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester {
|
|||
// activate
|
||||
EntityProcessingReport report = new RestAPITestHelper()
|
||||
.withAccessToken(sebAdminAccess)
|
||||
.withPath(RestAPI.ENDPOINT_INSTITUTION)
|
||||
.withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION)
|
||||
.withPath("/").withPath(String.valueOf(institution.id)).withPath("/active")
|
||||
.withMethod(HttpMethod.POST)
|
||||
.withExpectedStatus(HttpStatus.OK)
|
||||
|
@ -250,7 +250,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester {
|
|||
// get
|
||||
institution = new RestAPITestHelper()
|
||||
.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)
|
||||
.withExpectedStatus(HttpStatus.OK)
|
||||
.getAsObject(new TypeReference<Institution>() {
|
||||
|
@ -262,7 +262,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester {
|
|||
// deactivate
|
||||
report = new RestAPITestHelper()
|
||||
.withAccessToken(sebAdminAccess)
|
||||
.withPath(RestAPI.ENDPOINT_INSTITUTION)
|
||||
.withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION)
|
||||
.withPath("/").withPath(String.valueOf(institution.id)).withPath("/inactive")
|
||||
.withMethod(HttpMethod.POST)
|
||||
.withExpectedStatus(HttpStatus.OK)
|
||||
|
@ -278,7 +278,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester {
|
|||
// get
|
||||
institution = new RestAPITestHelper()
|
||||
.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)
|
||||
.withExpectedStatus(HttpStatus.OK)
|
||||
.getAsObject(new TypeReference<Institution>() {
|
||||
|
@ -290,7 +290,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester {
|
|||
// delete
|
||||
report = new RestAPITestHelper()
|
||||
.withAccessToken(sebAdminAccess)
|
||||
.withPath(RestAPI.ENDPOINT_INSTITUTION)
|
||||
.withPath(SEBServerRestEndpoints.ENDPOINT_INSTITUTION)
|
||||
.withPath("/").withPath(String.valueOf(institution.id))
|
||||
.withMethod(HttpMethod.DELETE)
|
||||
.withExpectedStatus(HttpStatus.OK)
|
||||
|
@ -307,7 +307,7 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester {
|
|||
// get
|
||||
final APIMessage error = new RestAPITestHelper()
|
||||
.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)
|
||||
.withExpectedStatus(HttpStatus.NOT_FOUND)
|
||||
.getAsObject(new TypeReference<APIMessage>() {
|
||||
|
|
|
@ -31,11 +31,12 @@ import org.springframework.test.context.jdbc.Sql;
|
|||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
|
||||
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.Entity;
|
||||
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.Page;
|
||||
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.UserRole;
|
||||
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" })
|
||||
public class UserAPITest extends AdministrationAPIIntegrationTester {
|
||||
|
@ -52,7 +52,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
public void getMyUserInfo() throws Exception {
|
||||
String contentAsString = new RestAPITestHelper()
|
||||
.withAccessToken(getSebAdminAccess())
|
||||
.withPath(RestAPI.ENDPOINT_USER_ACCOUNT + "/me")
|
||||
.withPath(SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/me")
|
||||
.withExpectedStatus(HttpStatus.OK)
|
||||
.getAsString();
|
||||
|
||||
|
@ -70,7 +70,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
|
||||
contentAsString = new RestAPITestHelper()
|
||||
.withAccessToken(getAdminInstitution1Access())
|
||||
.withPath(RestAPI.ENDPOINT_USER_ACCOUNT + "/me")
|
||||
.withPath(SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "/me")
|
||||
.withExpectedStatus(HttpStatus.OK)
|
||||
.getAsString();
|
||||
|
||||
|
@ -90,7 +90,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
@Test
|
||||
public void getUserInfoWithUUID() throws Exception {
|
||||
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)
|
||||
.header("Authorization", "Bearer " + sebAdminAccessToken))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -109,7 +109,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
contentAsString);
|
||||
|
||||
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)
|
||||
.header("Authorization", "Bearer " + adminInstitution2AccessToken))
|
||||
.andExpect(status().isForbidden())
|
||||
|
@ -127,7 +127,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
public void institutionalAdminNotAllowedToSeeUsersOfOtherInstitution() throws Exception {
|
||||
new RestAPITestHelper()
|
||||
.withAccessToken(getAdminInstitution1Access())
|
||||
.withPath(RestAPI.ENDPOINT_USER_ACCOUNT + "?institutionId=2")
|
||||
.withPath(SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT + "?institutionId=2")
|
||||
.withExpectedStatus(HttpStatus.FORBIDDEN)
|
||||
.getAsString();
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
public void getAllUserInfoNoFilter() throws Exception {
|
||||
Page<UserInfo> userInfos = new RestAPITestHelper()
|
||||
.withAccessToken(getSebAdminAccess())
|
||||
.withPath(RestAPI.ENDPOINT_USER_ACCOUNT)
|
||||
.withPath(SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT)
|
||||
.withExpectedStatus(HttpStatus.OK)
|
||||
.getAsObject(new TypeReference<Page<UserInfo>>() {
|
||||
});
|
||||
|
@ -150,7 +150,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
|
||||
userInfos = new RestAPITestHelper()
|
||||
.withAccessToken(getAdminInstitution2Access())
|
||||
.withPath(RestAPI.ENDPOINT_USER_ACCOUNT)
|
||||
.withPath(SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT)
|
||||
.withAttribute("institutionId", "2")
|
||||
.withExpectedStatus(HttpStatus.OK)
|
||||
.getAsObject(new TypeReference<Page<UserInfo>>() {
|
||||
|
@ -167,7 +167,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
//.. and without inactive, if active flag is set to true
|
||||
userInfos = new RestAPITestHelper()
|
||||
.withAccessToken(getAdminInstitution2Access())
|
||||
.withPath(RestAPI.ENDPOINT_USER_ACCOUNT)
|
||||
.withPath(SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT)
|
||||
.withAttribute(Entity.FILTER_ATTR_INSTITUTION, "2")
|
||||
.withAttribute(Entity.FILTER_ATTR_ACTIVE, "true")
|
||||
.withExpectedStatus(HttpStatus.OK)
|
||||
|
@ -183,7 +183,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
//.. and only inactive, if active flag is set to false
|
||||
userInfos = new RestAPITestHelper()
|
||||
.withAccessToken(getAdminInstitution2Access())
|
||||
.withPath(RestAPI.ENDPOINT_USER_ACCOUNT)
|
||||
.withPath(SEBServerRestEndpoints.ENDPOINT_USER_ACCOUNT)
|
||||
.withAttribute(Entity.FILTER_ATTR_INSTITUTION, "2")
|
||||
.withAttribute(Entity.FILTER_ATTR_ACTIVE, "false")
|
||||
.withExpectedStatus(HttpStatus.OK)
|
||||
|
@ -203,7 +203,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
|
||||
final String token = getSebAdminAccess();
|
||||
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)
|
||||
.header("Authorization", "Bearer " + token))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -225,7 +225,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
|
||||
final String token = getSebAdminAccess();
|
||||
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)
|
||||
.header("Authorization", "Bearer " + token))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -244,7 +244,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
public void getPageNoFilterNoPageAttributesDescendingOrder() throws Exception {
|
||||
final String token = getSebAdminAccess();
|
||||
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)
|
||||
.header("Authorization", "Bearer " + token))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -266,7 +266,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
// first page default sort order
|
||||
Page<UserInfo> userInfos = this.jsonMapper.readValue(
|
||||
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")
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
.header("Authorization", "Bearer " + token))
|
||||
|
@ -284,7 +284,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
// second page default sort order
|
||||
userInfos = this.jsonMapper.readValue(
|
||||
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")
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
.header("Authorization", "Bearer " + token))
|
||||
|
@ -303,7 +303,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
// invalid page number should refer to last page
|
||||
userInfos = this.jsonMapper.readValue(
|
||||
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")
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
.header("Authorization", "Bearer " + token))
|
||||
|
@ -322,7 +322,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
// first page descending sort order
|
||||
userInfos = this.jsonMapper.readValue(
|
||||
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")
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
.header("Authorization", "Bearer " + token))
|
||||
|
@ -350,7 +350,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
public void getAllUserInfo() throws Exception {
|
||||
final String token = getSebAdminAccess();
|
||||
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)
|
||||
.header("Authorization", "Bearer " + token))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -366,7 +366,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
public void getAllUserInfoWithOnlyActive() throws Exception {
|
||||
final String token = getSebAdminAccess();
|
||||
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)
|
||||
.header("Authorization", "Bearer " + token))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -385,7 +385,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
// expecting none for SEBAdmins institution
|
||||
final String token = getSebAdminAccess();
|
||||
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)
|
||||
.header("Authorization", "Bearer " + token))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -399,7 +399,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
// expecting one for institution 2
|
||||
userInfos = this.jsonMapper.readValue(
|
||||
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)
|
||||
.header("Authorization", "Bearer " + token))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -416,7 +416,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
public void getAllUserInfoWithSearchUsernameLike() throws Exception {
|
||||
final String token = getSebAdminAccess();
|
||||
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)
|
||||
.header("Authorization", "Bearer " + token))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -432,7 +432,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
@Test
|
||||
public void testOwnerGet() throws Exception {
|
||||
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))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn().getResponse().getContentAsString();
|
||||
|
@ -442,7 +442,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
public void createUserTest() throws Exception {
|
||||
final String token = getSebAdminAccess();
|
||||
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)
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
.param(Domain.USER.ATTR_NAME, "NewTestUser")
|
||||
|
@ -461,7 +461,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
|
||||
// get newly created user and check equality
|
||||
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)
|
||||
.header("Authorization", "Bearer " + token))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -477,7 +477,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
final Page<UserActivityLog> logs = this.jsonMapper.readValue(
|
||||
this.mockMvc
|
||||
.perform(
|
||||
get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG
|
||||
get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACTIVITY_LOG
|
||||
+ "?user=user1&activity_types=CREATE")
|
||||
.header("Authorization", "Bearer " + token))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -557,7 +557,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
public void modifyUserWithPUTMethod() throws Exception {
|
||||
final String token = getSebAdminAccess();
|
||||
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)
|
||||
.header("Authorization", "Bearer " + token))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -586,7 +586,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
final String modifyUserJson = this.jsonMapper.writeValueAsString(modifyUser);
|
||||
|
||||
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)
|
||||
.contentType(MediaType.APPLICATION_JSON_UTF8)
|
||||
.content(modifyUserJson))
|
||||
|
@ -604,7 +604,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
|
||||
// double check by getting the user by UUID
|
||||
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)
|
||||
.header("Authorization", "Bearer " + token))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -657,7 +657,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
public void testOwnerModifyPossibleForExamAdmin() throws Exception {
|
||||
final String examAdminToken1 = getExamAdmin1();
|
||||
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))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn().getResponse().getContentAsString(),
|
||||
|
@ -667,7 +667,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
final UserMod modifiedUser = new UserMod(examAdmin, null, null);
|
||||
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)
|
||||
.contentType(MediaType.APPLICATION_JSON_UTF8)
|
||||
.content(modifiedUserJson))
|
||||
|
@ -679,7 +679,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
public void institutionalAdminTryToCreateOrModifyUserForOtherInstituionNotPossible() throws Exception {
|
||||
|
||||
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)
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
.param(Domain.USER.ATTR_INSTITUTION_ID, "2")
|
||||
|
@ -695,7 +695,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
new HashSet<>(Arrays.asList(UserRole.EXAM_ADMIN.name())));
|
||||
final UserMod newUser = new UserMod(userInfo, "12345678", "12345678");
|
||||
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)
|
||||
.contentType(MediaType.APPLICATION_JSON_UTF8)
|
||||
.content(newUserJson))
|
||||
|
@ -707,7 +707,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
public void unauthorizedAdminTryToCreateUserNotPossible() throws Exception {
|
||||
|
||||
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)
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
.param(Domain.USER.ATTR_INSTITUTION_ID, "2")
|
||||
|
@ -723,7 +723,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
new HashSet<>(Arrays.asList(UserRole.EXAM_ADMIN.name())));
|
||||
final UserMod newUser = new UserMod(userInfo, "12345678", "12345678");
|
||||
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)
|
||||
.contentType(MediaType.APPLICATION_JSON_UTF8)
|
||||
.content(newUserJson))
|
||||
|
@ -739,7 +739,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
// a SEB Server Admin now changes the password of ExamAdmin1
|
||||
final String sebAdminToken = getSebAdminAccess();
|
||||
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)
|
||||
.header("Authorization", "Bearer " + sebAdminToken))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -753,7 +753,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
"newPassword");
|
||||
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)
|
||||
.contentType(MediaType.APPLICATION_JSON_UTF8)
|
||||
.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
|
||||
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))
|
||||
.andExpect(status().isUnauthorized())
|
||||
.andReturn().getResponse().getContentAsString();
|
||||
|
||||
// but it should be possible to get a new access token and request again
|
||||
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))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn().getResponse().getContentAsString();
|
||||
|
@ -786,7 +786,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
public void modifyUserPasswordInvalidPasswords() throws Exception {
|
||||
final String sebAdminToken = getSebAdminAccess();
|
||||
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)
|
||||
.header("Authorization", "Bearer " + sebAdminToken))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -802,7 +802,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
String modifiedUserJson = this.jsonMapper.writeValueAsString(modifiedUser);
|
||||
|
||||
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)
|
||||
.contentType(MediaType.APPLICATION_JSON_UTF8)
|
||||
.content(modifiedUserJson))
|
||||
|
@ -824,7 +824,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
modifiedUserJson = this.jsonMapper.writeValueAsString(modifiedUser);
|
||||
|
||||
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)
|
||||
.contentType(MediaType.APPLICATION_JSON_UTF8)
|
||||
.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);
|
||||
// only a SEB Administrator or an Institutional administrator should be able to deactivate a user-account
|
||||
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)
|
||||
.header("Authorization", "Bearer " + examAdminToken))
|
||||
.andExpect(status().isForbidden());
|
||||
|
@ -851,7 +851,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
// With SEB Administrator it should work
|
||||
final String sebAdminToken = getSebAdminAccess();
|
||||
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)
|
||||
.header("Authorization", "Bearer " + sebAdminToken))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -868,7 +868,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
// get user and check activity
|
||||
final EntityKey key = report.source.iterator().next();
|
||||
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)
|
||||
.header("Authorization", "Bearer " + sebAdminToken))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -883,7 +883,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
final Page<UserActivityLog> userLogs = this.jsonMapper.readValue(
|
||||
this.mockMvc
|
||||
.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)
|
||||
.header("Authorization", "Bearer " + sebAdminToken))
|
||||
.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);
|
||||
// only a SEB Administrator or an Institutional administrator should be able to deactivate a user-account
|
||||
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)
|
||||
.header("Authorization", "Bearer " + examAdminToken))
|
||||
.andExpect(status().isForbidden());
|
||||
|
@ -911,7 +911,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
// With SEB Administrator it should work
|
||||
final String sebAdminToken = getSebAdminAccess();
|
||||
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)
|
||||
.header("Authorization", "Bearer " + sebAdminToken))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -928,7 +928,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
// get user and check activity
|
||||
final EntityKey key = report.source.iterator().next();
|
||||
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)
|
||||
.header("Authorization", "Bearer " + sebAdminToken))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -942,7 +942,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
// check also user activity log
|
||||
final Page<UserActivityLog> userLogs = this.jsonMapper.readValue(
|
||||
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))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn().getResponse().getContentAsString(),
|
||||
|
@ -962,7 +962,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
|
||||
// all active for the own institution
|
||||
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)
|
||||
.header("Authorization", "Bearer " + sebAdminToken))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -976,7 +976,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
|
||||
// all inactive of the own institution
|
||||
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)
|
||||
.header("Authorization", "Bearer " + sebAdminToken))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -990,7 +990,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
|
||||
// all active of institution 2
|
||||
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)
|
||||
.header("Authorization", "Bearer " + sebAdminToken))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -1005,7 +1005,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
// all inactive of institution 2
|
||||
usersPage = this.jsonMapper.readValue(
|
||||
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)
|
||||
.header("Authorization", "Bearer " + sebAdminToken))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -1026,7 +1026,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
Collection<UserInfo> users = this.jsonMapper.readValue(
|
||||
this.mockMvc
|
||||
.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)
|
||||
.header("Authorization", "Bearer " + sebAdminToken))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -1043,7 +1043,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
users = this.jsonMapper.readValue(
|
||||
this.mockMvc
|
||||
.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)
|
||||
.header("Authorization", "Bearer " + instAdminToken))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -1061,14 +1061,14 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
final String sebAdminToken = getSebAdminAccess();
|
||||
|
||||
// for SEB Admin
|
||||
Collection<EntityKeyAndName> names = this.jsonMapper.readValue(
|
||||
Collection<EntityName> names = this.jsonMapper.readValue(
|
||||
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)
|
||||
.header("Authorization", "Bearer " + sebAdminToken))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn().getResponse().getContentAsString(),
|
||||
new TypeReference<Collection<EntityKeyAndName>>() {
|
||||
new TypeReference<Collection<EntityName>>() {
|
||||
});
|
||||
|
||||
assertNotNull(names);
|
||||
|
@ -1081,12 +1081,12 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
final String instAdminToken = getAdminInstitution2Access();
|
||||
names = this.jsonMapper.readValue(
|
||||
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)
|
||||
.header("Authorization", "Bearer " + instAdminToken))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn().getResponse().getContentAsString(),
|
||||
new TypeReference<Collection<EntityKeyAndName>>() {
|
||||
new TypeReference<Collection<EntityName>>() {
|
||||
});
|
||||
|
||||
assertNotNull(names);
|
||||
|
@ -1099,12 +1099,12 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
// for an institutional admin 2 only active
|
||||
names = this.jsonMapper.readValue(
|
||||
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)
|
||||
.header("Authorization", "Bearer " + instAdminToken))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn().getResponse().getContentAsString(),
|
||||
new TypeReference<Collection<EntityKeyAndName>>() {
|
||||
new TypeReference<Collection<EntityName>>() {
|
||||
});
|
||||
|
||||
assertNotNull(names);
|
||||
|
|
|
@ -19,9 +19,9 @@ import org.springframework.test.context.jdbc.Sql;
|
|||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
|
||||
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.user.UserActivityLog;
|
||||
import ch.ethz.seb.sebserver.webservice.weblayer.api.RestAPI;
|
||||
|
||||
@Sql(scripts = { "classpath:schema-test.sql", "classpath:data-test.sql" })
|
||||
public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester {
|
||||
|
@ -30,7 +30,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester {
|
|||
public void getAllAsSEBAdmin() throws Exception {
|
||||
final String token = getSebAdminAccess();
|
||||
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))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn().getResponse().getContentAsString(),
|
||||
|
@ -47,7 +47,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester {
|
|||
// for a user in another institution, the institution has to be defined
|
||||
Page<UserActivityLog> logs = this.jsonMapper.readValue(
|
||||
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))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn().getResponse().getContentAsString(),
|
||||
|
@ -59,7 +59,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester {
|
|||
|
||||
// for a user in the same institution no institution is needed
|
||||
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))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn().getResponse().getContentAsString(),
|
||||
|
@ -82,7 +82,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester {
|
|||
final String token = getSebAdminAccess();
|
||||
Page<UserActivityLog> logs = this.jsonMapper.readValue(
|
||||
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))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn().getResponse().getContentAsString(),
|
||||
|
@ -94,7 +94,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester {
|
|||
|
||||
logs = this.jsonMapper.readValue(
|
||||
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)
|
||||
.header("Authorization", "Bearer " + token))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -108,7 +108,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester {
|
|||
logs = this.jsonMapper.readValue(
|
||||
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
|
||||
+ "&to=" + sec5)
|
||||
.header("Authorization", "Bearer " + token))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -122,7 +122,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester {
|
|||
logs = this.jsonMapper.readValue(
|
||||
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
|
||||
+ "&to=" + sec6)
|
||||
.header("Authorization", "Bearer " + token))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -138,7 +138,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester {
|
|||
public void getAllAsSEBAdminForActivityType() throws Exception {
|
||||
final String token = getSebAdminAccess();
|
||||
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))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn().getResponse().getContentAsString(),
|
||||
|
@ -151,7 +151,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester {
|
|||
logs = this.jsonMapper.readValue(
|
||||
this.mockMvc
|
||||
.perform(
|
||||
get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG
|
||||
get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACTIVITY_LOG
|
||||
+ "?activity_types=CREATE,MODIFY")
|
||||
.header("Authorization", "Bearer " + token))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -166,7 +166,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester {
|
|||
logs = this.jsonMapper.readValue(
|
||||
this.mockMvc
|
||||
.perform(
|
||||
get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG
|
||||
get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACTIVITY_LOG
|
||||
+ "?institutionId=2&activity_types=CREATE,MODIFY")
|
||||
.header("Authorization", "Bearer " + token))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -183,7 +183,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester {
|
|||
final String token = getSebAdminAccess();
|
||||
Page<UserActivityLog> logs = this.jsonMapper.readValue(
|
||||
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))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn().getResponse().getContentAsString(),
|
||||
|
@ -196,7 +196,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester {
|
|||
logs = this.jsonMapper.readValue(
|
||||
this.mockMvc
|
||||
.perform(
|
||||
get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG
|
||||
get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACTIVITY_LOG
|
||||
+ "?entity_types=INSTITUTION,EXAM")
|
||||
.header("Authorization", "Bearer " + token))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -210,7 +210,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester {
|
|||
logs = this.jsonMapper.readValue(
|
||||
this.mockMvc
|
||||
.perform(
|
||||
get(this.endpoint + RestAPI.ENDPOINT_USER_ACTIVITY_LOG
|
||||
get(this.endpoint + SEBServerRestEndpoints.ENDPOINT_USER_ACTIVITY_LOG
|
||||
+ "?entity_types=INSTITUTION,EXAM&institutionId=2")
|
||||
.header("Authorization", "Bearer " + token))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -226,7 +226,7 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester {
|
|||
public void getAllAsInstitutionalAdmin() throws Exception {
|
||||
final String token = getAdminInstitution1Access();
|
||||
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))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn().getResponse().getContentAsString(),
|
||||
|
@ -242,18 +242,18 @@ public class UserActivityLogAPITest extends AdministrationAPIIntegrationTester {
|
|||
String token = getExamAdmin1();
|
||||
|
||||
// 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))
|
||||
.andExpect(status().isForbidden());
|
||||
// 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))
|
||||
.andExpect(status().isForbidden());
|
||||
|
||||
// no privilege to query logs of users of other institution
|
||||
token = getAdminInstitution1Access();
|
||||
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))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn().getResponse().getContentAsString(),
|
||||
|
|
|
@ -31,7 +31,7 @@ import org.springframework.util.MultiValueMap;
|
|||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import ch.ethz.seb.sebserver.SEBServer;
|
||||
import ch.ethz.seb.sebserver.gbl.JSONMapper;
|
||||
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(
|
||||
|
|
Loading…
Reference in a new issue