This commit is contained in:
anhefti 2020-03-03 15:47:22 +01:00
commit cccbc48805
61 changed files with 7744 additions and 7773 deletions

View file

@ -34,7 +34,7 @@ public class GuiInit implements ApplicationListener<ApplicationReadyEvent> {
SEBServerInit.INIT_LOGGER.info("----> **** GUI Service starting up... ****"); SEBServerInit.INIT_LOGGER.info("----> **** GUI Service starting up... ****");
SEBServerInit.INIT_LOGGER.info("---->"); SEBServerInit.INIT_LOGGER.info("---->");
SEBServerInit.INIT_LOGGER.info("----> GUI Service sucessfully successfully started up!"); SEBServerInit.INIT_LOGGER.info("----> GUI Service successfully successfully started up!");
SEBServerInit.INIT_LOGGER.info("---->"); SEBServerInit.INIT_LOGGER.info("---->");
} }

View file

@ -73,12 +73,12 @@ public final class InstitutionalAuthenticationEntryPoint implements Authenticati
this.webserviceURIService = webserviceURIService; this.webserviceURIService = webserviceURIService;
this.clientHttpRequestFactoryService = clientHttpRequestFactoryService; this.clientHttpRequestFactoryService = clientHttpRequestFactoryService;
String _defaultLogo = null; String _defaultLogo;
if (!Constants.NO_NAME.equals(defaultLogoFileName)) { if (!Constants.NO_NAME.equals(defaultLogoFileName)) {
try { try {
final String extension = ImageUploadSelection.SUPPORTED_IMAGE_FILES.stream() final String extension = ImageUploadSelection.SUPPORTED_IMAGE_FILES.stream()
.filter(ext -> defaultLogoFileName.endsWith(ext)) .filter(defaultLogoFileName::endsWith)
.findFirst() .findFirst()
.orElse(null); .orElse(null);
@ -141,7 +141,7 @@ public final class InstitutionalAuthenticationEntryPoint implements Authenticati
: null); : null);
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("Known and active gui entrypoint requested:", institutions); log.debug("Known and active gui entrypoint requested: {}", institutions);
} }
final String logoImageBase64 = requestLogoImage(institutionalEndpoint); final String logoImageBase64 = requestLogoImage(institutionalEndpoint);
@ -184,9 +184,7 @@ public final class InstitutionalAuthenticationEntryPoint implements Authenticati
} }
try { try {
return requestURI.substring( return requestURI.substring(requestURI.lastIndexOf(Constants.SLASH) + 1);
requestURI.lastIndexOf(Constants.SLASH) + 1,
requestURI.length());
} catch (final Exception e) { } catch (final Exception e) {
log.error("Failed to extract institutional URL suffix: {}", e.getMessage()); log.error("Failed to extract institutional URL suffix: {}", e.getMessage());
return null; return null;
@ -231,12 +229,12 @@ public final class InstitutionalAuthenticationEntryPoint implements Authenticati
if (exchange.getStatusCodeValue() == HttpStatus.OK.value()) { if (exchange.getStatusCodeValue() == HttpStatus.OK.value()) {
return exchange.getBody(); return exchange.getBody();
} else { } else {
log.warn("Failed to verify insitution from requested entrypoint url: {}, response: {}", log.warn("Failed to verify institution from requested entrypoint url: {}, response: {}",
institutionalEndpoint, institutionalEndpoint,
exchange); exchange);
} }
} catch (final Exception e) { } catch (final Exception e) {
log.warn("Failed to verify insitution from requested entrypoint url: {}", log.warn("Failed to verify institution from requested entrypoint url: {}",
institutionalEndpoint, institutionalEndpoint,
e); e);
} }
@ -245,7 +243,7 @@ public final class InstitutionalAuthenticationEntryPoint implements Authenticati
} }
/** TODO this seems not to work as expected. Different Theme is only possible in RAP on different /** TODO this seems not to work as expected. Different Theme is only possible in RAP on different
* entry-points and since entry-points are statically defined within the RAPConficuration * entry-points and since entry-points are statically defined within the RAPConfiguration
* there is no possibility to apply them dynamically within an institution so far. * there is no possibility to apply them dynamically within an institution so far.
* *
* @param institutionalEndpoint * @param institutionalEndpoint

View file

@ -63,7 +63,7 @@ public class RAPConfiguration implements ApplicationConfiguration {
} }
} }
public static interface EntryPointService { public interface EntryPointService {
void loadLoginPage(final Composite parent); void loadLoginPage(final Composite parent);
@ -160,5 +160,5 @@ public class RAPConfiguration implements ApplicationConfiguration {
} }
} }
}; }
} }

View file

@ -8,10 +8,7 @@
package ch.ethz.seb.sebserver.gui; package ch.ethz.seb.sebserver.gui;
import javax.servlet.ServletContext; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletException;
import org.eclipse.rap.rwt.engine.RWTServlet; import org.eclipse.rap.rwt.engine.RWTServlet;
import org.eclipse.rap.rwt.engine.RWTServletContextListener; import org.eclipse.rap.rwt.engine.RWTServletContextListener;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -25,7 +22,8 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource; import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import javax.servlet.ServletContext;
import javax.servlet.ServletContextListener;
@Configuration @Configuration
@GuiProfile @GuiProfile
@ -73,7 +71,7 @@ public class RAPSpringConfig {
private static class RAPServletContextInitializer implements ServletContextInitializer { private static class RAPServletContextInitializer implements ServletContextInitializer {
@Override @Override
public void onStartup(final ServletContext servletContext) throws ServletException { public void onStartup(final ServletContext servletContext) {
servletContext.setInitParameter( servletContext.setInitParameter(
"org.eclipse.rap.applicationConfiguration", "org.eclipse.rap.applicationConfiguration",
RAPConfiguration.class.getName()); RAPConfiguration.class.getName());

View file

@ -82,8 +82,8 @@ public class ResourceService {
private static final String MISSING_CLIENT_PING_NAME_KEY = "MISSING"; private static final String MISSING_CLIENT_PING_NAME_KEY = "MISSING";
public static final Comparator<Tuple<String>> RESOURCE_COMPARATOR = (t1, t2) -> t1._2.compareTo(t2._2); public static final Comparator<Tuple<String>> RESOURCE_COMPARATOR = Comparator.comparing(t -> t._2);
public static final Comparator<Tuple3<String>> RESOURCE_COMPARATOR_TUPLE_3 = (t1, t2) -> t1._2.compareTo(t2._2); public static final Comparator<Tuple3<String>> RESOURCE_COMPARATOR_TUPLE_3 = Comparator.comparing(t -> t._2);
public static final EnumSet<EntityType> ENTITY_TYPE_EXCLUDE_MAP = EnumSet.of( public static final EnumSet<EntityType> ENTITY_TYPE_EXCLUDE_MAP = EnumSet.of(
EntityType.ADDITIONAL_ATTRIBUTES, EntityType.ADDITIONAL_ATTRIBUTES,

View file

@ -24,7 +24,7 @@ public class FieldValidationError {
public FieldValidationError(final APIMessage apiMessage) { public FieldValidationError(final APIMessage apiMessage) {
this( this(
apiMessage.messageCode, apiMessage.messageCode,
apiMessage.attributes.toArray(new String[apiMessage.attributes.size()])); apiMessage.attributes.toArray(new String[0]));
} }
public FieldValidationError( public FieldValidationError(
@ -44,7 +44,7 @@ public class FieldValidationError {
return new String[0]; return new String[0];
} }
return this.attributes.toArray(new String[this.attributes.size()]); return this.attributes.toArray(new String[0]);
} }
} }

View file

@ -27,34 +27,34 @@ public interface PageContext {
Logger log = LoggerFactory.getLogger(PageContext.class); Logger log = LoggerFactory.getLogger(PageContext.class);
/** Defines attribute keys that can be used to store attribute values within the page context state */ /** Defines attribute keys that can be used to store attribute values within the page context state */
public interface AttributeKeys { interface AttributeKeys {
public static final String PAGE_TEMPLATE_COMPOSER_NAME = "ATTR_PAGE_TEMPLATE_COMPOSER_NAME"; String PAGE_TEMPLATE_COMPOSER_NAME = "ATTR_PAGE_TEMPLATE_COMPOSER_NAME";
public static final String READ_ONLY = "READ_ONLY"; String READ_ONLY = "READ_ONLY";
public static final String READ_ONLY_FROM = "READ_ONLY_FROM"; String READ_ONLY_FROM = "READ_ONLY_FROM";
public static final String ENTITY_ID = "ENTITY_ID"; String ENTITY_ID = "ENTITY_ID";
public static final String PARENT_ENTITY_ID = "PARENT_ENTITY_ID"; String PARENT_ENTITY_ID = "PARENT_ENTITY_ID";
public static final String ENTITY_TYPE = "ENTITY_TYPE"; String ENTITY_TYPE = "ENTITY_TYPE";
public static final String PARENT_ENTITY_TYPE = "PARENT_ENTITY_TYPE"; String PARENT_ENTITY_TYPE = "PARENT_ENTITY_TYPE";
public static final String IMPORT_FROM_QUIZ_DATA = "IMPORT_FROM_QUIZ_DATA"; String IMPORT_FROM_QUIZ_DATA = "IMPORT_FROM_QUIZ_DATA";
public static final String COPY_AS_TEMPLATE = "COPY_AS_TEMPLATE"; String COPY_AS_TEMPLATE = "COPY_AS_TEMPLATE";
public static final String CREATE_FROM_TEMPLATE = "CREATE_FROM_TEMPLATE"; String CREATE_FROM_TEMPLATE = "CREATE_FROM_TEMPLATE";
} }
/** The resource-bundle key of the generic load entity error message. */ /** The resource-bundle key of the generic load entity error message. */
public static final String GENERIC_LOAD_ERROR_TEXT_KEY = "sebserver.error.get.entity"; String GENERIC_LOAD_ERROR_TEXT_KEY = "sebserver.error.get.entity";
public static final String GENERIC_REMOVE_ERROR_TEXT_KEY = "sebserver.error.remove.entity"; String GENERIC_REMOVE_ERROR_TEXT_KEY = "sebserver.error.remove.entity";
public static final String GENERIC_SAVE_ERROR_TEXT_KEY = "sebserver.error.save.entity"; String GENERIC_SAVE_ERROR_TEXT_KEY = "sebserver.error.save.entity";
public static final String GENERIC_ACTIVATE_ERROR_TEXT_KEY = "sebserver.error.activate.entity"; String GENERIC_ACTIVATE_ERROR_TEXT_KEY = "sebserver.error.activate.entity";
public static final String GENERIC_IMPORT_ERROR_TEXT_KEY = "sebserver.error.import"; String GENERIC_IMPORT_ERROR_TEXT_KEY = "sebserver.error.import";
public static final LocTextKey SUCCESS_MSG_TITLE = LocTextKey SUCCESS_MSG_TITLE =
new LocTextKey("sebserver.page.message"); new LocTextKey("sebserver.page.message");
public static final LocTextKey UNEXPECTED_ERROR_KEY = LocTextKey UNEXPECTED_ERROR_KEY =
new LocTextKey("sebserver.error.action.unexpected.message"); new LocTextKey("sebserver.error.action.unexpected.message");
/** Get the I18nSupport service /** Get the I18nSupport service
@ -84,11 +84,11 @@ public interface PageContext {
/** Get a copy of this PageContext. /** Get a copy of this PageContext.
* *
* @return */ * @return a deep copy of this PageContext */
PageContext copy(); PageContext copy();
/** Create a copy of this PageContext with a new parent Composite. /** Create a copy of this PageContext with a new parent Composite.
* The implementation should take care of the imutability of PageContext and return a copy with the new parent * The implementation should take care of the immutability of PageContext and return a copy with the new parent
* by leave this PageContext as is. * by leave this PageContext as is.
* *
* @param parent the new parent Composite * @param parent the new parent Composite
@ -97,15 +97,15 @@ public interface PageContext {
/** Create a copy of this PageContext with and additionally page context attributes. /** Create a copy of this PageContext with and additionally page context attributes.
* The additionally page context attributes will get merged with them already defined * The additionally page context attributes will get merged with them already defined
* The implementation should take care of the imutability of PageContext and return a copy with the merge * The implementation should take care of the immutability of PageContext and return a copy with the merge
* by leave this and the given PageContext as is. * by leave this and the given PageContext as is.
* *
* @param attributes additionally page context attributes. * @param otherContext the other PageContext to copy the attributes from
* @return a copy of this PageContext with with and additionally page context attributes. */ * @return a copy of this PageContext with with and additionally page context attributes. */
PageContext copyOfAttributes(PageContext otherContext); PageContext copyOfAttributes(PageContext otherContext);
/** Adds the specified attribute to the existing page context attributes. /** Adds the specified attribute to the existing page context attributes.
* The implementation should take care of the imutability of PageContext and return a copy * The implementation should take care of the immutability of PageContext and return a copy
* by leave this PageContext as is. * by leave this PageContext as is.
* *
* @param key the key of the attribute * @param key the key of the attribute
@ -162,7 +162,7 @@ public interface PageContext {
/** Create a copy of this PageContext and resets both entity keys attributes, the base and the parent EntityKey /** Create a copy of this PageContext and resets both entity keys attributes, the base and the parent EntityKey
* *
* @return copy of this PageContext with reseted EntityKey attributes (base and parent) */ * @return copy of this PageContext with reset EntityKey attributes (base and parent) */
PageContext clearEntityKeys(); PageContext clearEntityKeys();
/** Indicates if an attribute with the specified name exists within this PageContext /** Indicates if an attribute with the specified name exists within this PageContext
@ -181,7 +181,7 @@ public interface PageContext {
* block that will be executed on users OK selection. * block that will be executed on users OK selection.
* *
* @param confirmMessage the localized confirm message key * @param confirmMessage the localized confirm message key
* @param onOK callback code block that will be called on users selection */ * @param callback callback code block that will be called on users selection */
void applyConfirmDialog(LocTextKey confirmMessage, final Consumer<Boolean> callback); void applyConfirmDialog(LocTextKey confirmMessage, final Consumer<Boolean> callback);
/** This can be used to forward to a defined page. /** This can be used to forward to a defined page.

View file

@ -8,8 +8,12 @@
package ch.ethz.seb.sebserver.gui.service.page; package ch.ethz.seb.sebserver.gui.service.page;
/** Defines a global SEB Server page */
public interface PageDefinition { public interface PageDefinition {
/** Get the type class of the TemplateComposer that composes the page.
*
* @return the type class of the TemplateComposer that composes the page. */
Class<? extends TemplateComposer> composer(); Class<? extends TemplateComposer> composer();
PageContext applyPageContext(PageContext pageContext); PageContext applyPageContext(PageContext pageContext);

View file

@ -363,7 +363,7 @@ public interface PageService {
return content; return content;
} }
/** Used to update the crolledComposite when some if its content has dynamically changed /** Used to update the scrolledComposite when some if its content has dynamically changed
* its dimensions. * its dimensions.
* *
* @param composite The Component that changed its dimensions */ * @param composite The Component that changed its dimensions */

View file

@ -22,9 +22,9 @@ public interface PageStateDefinition {
Type type(); Type type();
public Class<? extends TemplateComposer> contentPaneComposer(); Class<? extends TemplateComposer> contentPaneComposer();
public Class<? extends TemplateComposer> actionPaneComposer(); Class<? extends TemplateComposer> actionPaneComposer();
Activity activityAnchor(); Activity activityAnchor();
} }

View file

@ -8,12 +8,20 @@
package ch.ethz.seb.sebserver.gui.service.page; package ch.ethz.seb.sebserver.gui.service.page;
/** interface defining a RAP page template composer */
public interface TemplateComposer { public interface TemplateComposer {
/** Validate given PageContext for completeness to compose a specific TemplateComposer implementation
* Default returns always true.
* @param pageContext The PageContext instance to check
* @return true if the PageContext contains all mandatory data to compose this page template */
default boolean validate(final PageContext pageContext) { default boolean validate(final PageContext pageContext) {
return true; return true;
} }
/** Compose a specific page template for the given PageContext
*
* @param pageContext The PageContext instance */
void compose(PageContext pageContext); void compose(PageContext pageContext);
} }

View file

@ -156,7 +156,7 @@ public class DefaultPageLayout implements TemplateComposer {
logoutSuccess.open(null); logoutSuccess.open(null);
// TODO Try to invalidate RWT's user session. // TODO Try to invalidate RWT's user session.
// This seems to be more difficult then expected and just invalidate the HttpSession dosn't work // This seems to be more difficult then expected and just invalidate the HttpSession doesn't work
// Try to send a redirect JSON to the client: https://bugs.eclipse.org/bugs/show_bug.cgi?id=388249 // Try to send a redirect JSON to the client: https://bugs.eclipse.org/bugs/show_bug.cgi?id=388249
}); });
} }
@ -347,12 +347,8 @@ public class DefaultPageLayout implements TemplateComposer {
final Display display = pageContext.getShell().getDisplay(); final Display display = pageContext.getShell().getDisplay();
final Image image = new Image(display, input); final Image image = new Image(display, input);
final Rectangle imageBounds = image.getBounds(); final Rectangle imageBounds = image.getBounds();
final int width = (imageBounds.width > LOGO_IMAGE_MAX_WIDTH) final int width = Math.min(imageBounds.width, LOGO_IMAGE_MAX_WIDTH);
? LOGO_IMAGE_MAX_WIDTH final int height = Math.min(imageBounds.height, LOGO_IMAGE_MAX_HEIGHT);
: imageBounds.width;
final int height = (imageBounds.height > LOGO_IMAGE_MAX_HEIGHT)
? LOGO_IMAGE_MAX_HEIGHT
: imageBounds.height;
final ImageData imageData = image.getImageData().scaledTo(width, height); final ImageData imageData = image.getImageData().scaledTo(width, height);
logo.setData(RWT.CUSTOM_VARIANT, "bgLogoNoImage"); logo.setData(RWT.CUSTOM_VARIANT, "bgLogoNoImage");

View file

@ -89,7 +89,7 @@ public class ModalInputDialog<T> extends Dialog {
open( open(
title, title,
(Predicate<T>) t -> true, t -> true,
() -> { () -> {
}, contentComposer); }, contentComposer);
} }
@ -130,7 +130,7 @@ public class ModalInputDialog<T> extends Dialog {
gridData.widthHint = this.dialogWidth; gridData.widthHint = this.dialogWidth;
main.setLayoutData(gridData); main.setLayoutData(gridData);
final Supplier<T> valueSuppier = contentComposer.compose(main); final Supplier<T> valueSupplier = contentComposer.compose(main);
gridData.heightHint = calcDialogHeight(main); gridData.heightHint = calcDialogHeight(main);
final Button ok = this.widgetFactory.buttonLocalized(shell, OK_TEXT_KEY); final Button ok = this.widgetFactory.buttonLocalized(shell, OK_TEXT_KEY);
@ -138,8 +138,8 @@ public class ModalInputDialog<T> extends Dialog {
data.widthHint = this.buttonWidth; data.widthHint = this.buttonWidth;
ok.setLayoutData(data); ok.setLayoutData(data);
ok.addListener(SWT.Selection, event -> { ok.addListener(SWT.Selection, event -> {
if (valueSuppier != null) { if (valueSupplier != null) {
final T result = valueSuppier.get(); final T result = valueSupplier.get();
if (callback.test(result)) { if (callback.test(result)) {
shell.close(); shell.close();
} }
@ -192,9 +192,7 @@ public class ModalInputDialog<T> extends Dialog {
final GridData data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER); final GridData data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER);
data.widthHint = this.buttonWidth; data.widthHint = this.buttonWidth;
close.setLayoutData(data); close.setLayoutData(data);
close.addListener(SWT.Selection, event -> { close.addListener(SWT.Selection, event -> shell.close());
shell.close();
});
finishUp(shell); finishUp(shell);
} }
@ -216,10 +214,7 @@ public class ModalInputDialog<T> extends Dialog {
final int availableHeight = (displayHeight < actualHeight + 100) final int availableHeight = (displayHeight < actualHeight + 100)
? displayHeight - 100 ? displayHeight - 100
: actualHeight; : actualHeight;
final int height = (availableHeight > this.dialogHeight) return Math.min(availableHeight, this.dialogHeight);
? this.dialogHeight
: availableHeight;
return height;
} }
} }

View file

@ -118,8 +118,7 @@ public class PageContextImpl implements PageContext {
@Override @Override
public PageContext withAttribute(final String key, final String value) { public PageContext withAttribute(final String key, final String value) {
final Map<String, String> attrs = new HashMap<>(); final Map<String, String> attrs = new HashMap<>(this.attributes);
attrs.putAll(this.attributes);
attrs.put(key, value); attrs.put(key, value);
return new PageContextImpl( return new PageContextImpl(
this.i18nSupport, this.i18nSupport,
@ -136,11 +135,7 @@ public class PageContextImpl implements PageContext {
@Override @Override
public String getAttribute(final String name, final String def) { public String getAttribute(final String name, final String def) {
if (this.attributes.containsKey(name)) { return this.attributes.getOrDefault(name, def);
return this.attributes.get(name);
} else {
return def;
}
} }
@Override @Override
@ -203,8 +198,7 @@ public class PageContextImpl implements PageContext {
@Override @Override
public PageContext removeAttribute(final String name) { public PageContext removeAttribute(final String name) {
final Map<String, String> attrs = new HashMap<>(); final Map<String, String> attrs = new HashMap<>(this.attributes);
attrs.putAll(this.attributes);
attrs.remove(name); attrs.remove(name);
return new PageContextImpl( return new PageContextImpl(
this.i18nSupport, this.i18nSupport,
@ -333,7 +327,7 @@ public class PageContextImpl implements PageContext {
this.onOK.accept(true); this.onOK.accept(true);
} catch (final Exception e) { } catch (final Exception e) {
log.error( log.error(
"Unexpected on confirm callback execution. This should not happen, plase secure the given onOK Runnable", "Unexpected on confirm callback execution. This should not happen, please secure the given onOK Runnable",
e); e);
this.onOK.accept(false); this.onOK.accept(false);
} }

View file

@ -227,7 +227,7 @@ public class PageServiceImpl implements PageService {
final int dependencies = (int) entities.stream() final int dependencies = (int) entities.stream()
.flatMap(entity -> { .flatMap(entity -> {
final RestCall<Set<EntityKey>>.RestCallBuilder builder = final RestCall<Set<EntityKey>>.RestCallBuilder builder =
restService.<Set<EntityKey>>getBuilder( restService.getBuilder(
entity.entityType(), entity.entityType(),
CallType.GET_DEPENDENCIES); CallType.GET_DEPENDENCIES);
@ -366,7 +366,7 @@ public class PageServiceImpl implements PageService {
final boolean logoutSuccessful = this.currentUser.logout(); final boolean logoutSuccessful = this.currentUser.logout();
if (!logoutSuccessful) { if (!logoutSuccessful) {
log.warn("Failed to logout. See logfiles for more information"); log.warn("Failed to logout. See log-files for more information");
} }
} catch (final Exception e) { } catch (final Exception e) {

View file

@ -78,7 +78,7 @@ public class ServerPushService {
} catch (final Exception e) { } catch (final Exception e) {
log.warn( log.warn(
"Failed to update on Server Push Session {}. It seems that the UISession is not available anymore. " "Failed to update on Server Push Session {}. It seems that the UISession is not available anymore. "
+ "This may source from a connection interruption.", + "This may source from a connection interruption. cause: {}",
Thread.currentThread().getName(), e.getMessage()); Thread.currentThread().getName(), e.getMessage());
} }
}); });

View file

@ -8,16 +8,9 @@
package ch.ethz.seb.sebserver.gui.service.remote.download; package ch.ethz.seb.sebserver.gui.service.remote.download;
import java.io.IOException; import ch.ethz.seb.sebserver.gbl.Constants;
import java.util.Collection; import ch.ethz.seb.sebserver.gbl.api.API;
import java.util.Map; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.eclipse.rap.rwt.RWT; import org.eclipse.rap.rwt.RWT;
import org.eclipse.rap.rwt.service.ServiceHandler; import org.eclipse.rap.rwt.service.ServiceHandler;
@ -26,10 +19,14 @@ import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ch.ethz.seb.sebserver.gbl.Constants; import javax.servlet.http.HttpServletRequest;
import ch.ethz.seb.sebserver.gbl.api.API; import javax.servlet.http.HttpServletResponse;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import java.util.Collection;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
/** Implements a eclipse RAP ServiceHandler to handle downloads */
@Lazy @Lazy
@Service @Service
@GuiProfile @GuiProfile
@ -54,7 +51,7 @@ public class DownloadService implements ServiceHandler {
@Override @Override
public void service( public void service(
final HttpServletRequest request, final HttpServletRequest request,
final HttpServletResponse response) throws IOException, ServletException { final HttpServletResponse response) {
log.debug("Received download service request: {}", request.getRequestURI()); log.debug("Received download service request: {}", request.getRequestURI());

View file

@ -11,8 +11,13 @@ package ch.ethz.seb.sebserver.gui.service.remote.download;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
/** Interface defining a service to handle downloads */
public interface DownloadServiceHandler { public interface DownloadServiceHandler {
/** Process a requested download
*
* @param request The download HttpServletRequest
* @param response the response to send the download to */
void processDownload(final HttpServletRequest request, final HttpServletResponse response); void processDownload(final HttpServletRequest request, final HttpServletResponse response);
} }

View file

@ -54,7 +54,7 @@ public class SebClientConfigDownload extends AbstractDownloadServiceHandler {
IOUtils.copyLarge(input, downloadOut); IOUtils.copyLarge(input, downloadOut);
} catch (final IOException e) { } catch (final IOException e) {
log.error( log.error(
"Unexpected error while streaming incomming config data from web-service to output-stream of download response: ", "Unexpected error while streaming incoming config data from web-service to output-stream of download response: ",
e); e);
} finally { } finally {
try { try {

View file

@ -49,7 +49,7 @@ public class SebExamConfigDownload extends AbstractDownloadServiceHandler {
IOUtils.copyLarge(input, downloadOut); IOUtils.copyLarge(input, downloadOut);
} catch (final IOException e) { } catch (final IOException e) {
log.error( log.error(
"Unexpected error while streaming incomming config data from web-service to output-stream of download response: ", "Unexpected error while streaming incoming config data from web-service to output-stream of download response: ",
e); e);
} finally { } finally {
try { try {

View file

@ -48,7 +48,7 @@ public class SebExamConfigPlaintextDownload extends AbstractDownloadServiceHandl
IOUtils.copyLarge(input, downloadOut); IOUtils.copyLarge(input, downloadOut);
} catch (final IOException e) { } catch (final IOException e) {
log.error( log.error(
"Unexpected error while streaming incomming config data from web-service to output-stream of download response: ", "Unexpected error while streaming incoming config data from web-service to output-stream of download response: ",
e); e);
} finally { } finally {
try { try {

View file

@ -31,9 +31,7 @@ public abstract class AbstractExportCall extends RestCall<InputStream> {
@Override @Override
protected Result<InputStream> exchange(final RestCallBuilder builder) { protected Result<InputStream> exchange(final RestCallBuilder builder) {
return Result.tryCatch(() -> { return Result.tryCatch(() -> builder
return builder
.getRestTemplate() .getRestTemplate()
.execute( .execute(
builder.buildURI(), builder.buildURI(),
@ -41,9 +39,7 @@ public abstract class AbstractExportCall extends RestCall<InputStream> {
(final ClientHttpRequest requestCallback) -> { (final ClientHttpRequest requestCallback) -> {
}, },
response -> IOUtils.toBufferedInputStream(response.getBody()), response -> IOUtils.toBufferedInputStream(response.getBody()),
builder.getURIVariables()); builder.getURIVariables()));
});
} }
} }

View file

@ -8,10 +8,18 @@
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api; package ch.ethz.seb.sebserver.gui.service.remote.webservice.api;
/** Defines a form binding to get form parameter and values either in JSON format
* or as form-url-encoded string */
public interface FormBinding { public interface FormBinding {
/** Get the form parameter and values in JSON format
*
* @return the form parameter and values in JSON format */
String getFormAsJson(); String getFormAsJson();
/** Get the form parameter and values in form-url-encoded string format.
*
* @return the form parameter and values in form-url-encoded string format.*/
String getFormUrlEncoded(); String getFormUrlEncoded();
} }

View file

@ -8,14 +8,18 @@
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api; package ch.ethz.seb.sebserver.gui.service.remote.webservice.api;
import java.io.IOException; import ch.ethz.seb.sebserver.gbl.Constants;
import java.io.InputStream; import ch.ethz.seb.sebserver.gbl.api.APIMessage;
import java.util.Arrays; import ch.ethz.seb.sebserver.gbl.api.EntityType;
import java.util.HashMap; import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
import java.util.List; import ch.ethz.seb.sebserver.gbl.model.Entity;
import java.util.Map; import ch.ethz.seb.sebserver.gbl.model.Page;
import java.util.function.Function; import ch.ethz.seb.sebserver.gbl.model.PageSortOrder;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.gbl.util.Utils;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -32,20 +36,13 @@ import org.springframework.web.client.RestClientResponseException;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder; import org.springframework.web.util.UriComponentsBuilder;
import com.fasterxml.jackson.core.JsonParseException; import java.io.IOException;
import com.fasterxml.jackson.core.JsonProcessingException; import java.io.InputStream;
import com.fasterxml.jackson.core.type.TypeReference; import java.util.Arrays;
import com.fasterxml.jackson.databind.JsonMappingException; import java.util.HashMap;
import java.util.List;
import ch.ethz.seb.sebserver.gbl.Constants; import java.util.Map;
import ch.ethz.seb.sebserver.gbl.api.APIMessage; import java.util.function.Function;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gbl.model.PageSortOrder;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.gbl.util.Utils;
public abstract class RestCall<T> { public abstract class RestCall<T> {
@ -173,7 +170,7 @@ public abstract class RestCall<T> {
} }
private Result<T> handleRestCallError(final ResponseEntity<String> responseEntity) private Result<T> handleRestCallError(final ResponseEntity<String> responseEntity)
throws IOException, JsonParseException, JsonMappingException { throws IOException {
final RestCallError restCallError = final RestCallError restCallError =
new RestCallError("Response Entity: " + responseEntity.toString()); new RestCallError("Response Entity: " + responseEntity.toString());
@ -225,6 +222,7 @@ public abstract class RestCall<T> {
this.uriComponentsBuilder = builder.uriComponentsBuilder; this.uriComponentsBuilder = builder.uriComponentsBuilder;
this.httpHeaders = builder.httpHeaders; this.httpHeaders = builder.httpHeaders;
this.body = builder.body; this.body = builder.body;
this.streamingBody = builder.streamingBody;
this.queryParams = new LinkedMultiValueMap<>(builder.queryParams); this.queryParams = new LinkedMultiValueMap<>(builder.queryParams);
this.uriVariables = new HashMap<>(builder.uriVariables); this.uriVariables = new HashMap<>(builder.uriVariables);
} }

View file

@ -49,9 +49,7 @@ public class RestCallError extends RuntimeException implements APIMessageError {
public boolean isFieldValidationError() { public boolean isFieldValidationError() {
return this.errors return this.errors
.stream() .stream()
.filter(error -> APIMessage.ErrorMessage.FIELD_VALIDATION.isOf(error)) .anyMatch(APIMessage.ErrorMessage.FIELD_VALIDATION::isOf);
.findFirst()
.isPresent();
} }
@Override @Override

View file

@ -52,7 +52,7 @@ public interface RestService {
* NOTE not all RestCall can be get within this method. Only the ones that have a defined CallType * NOTE not all RestCall can be get within this method. Only the ones that have a defined CallType
* *
* @param entityType The EntityType of the RestCall * @param entityType The EntityType of the RestCall
* @param callType The CallType of the RestCall (not UNDEFINDED) * @param callType The CallType of the RestCall (not UNDEFINED)
* @return RestCall instance */ * @return RestCall instance */
<T> RestCall<T> getRestCall(EntityType entityType, CallType callType); <T> RestCall<T> getRestCall(EntityType entityType, CallType callType);
@ -65,7 +65,7 @@ public interface RestService {
/** Get a certain RestCallBuilder by EntityType and CallType. /** Get a certain RestCallBuilder by EntityType and CallType.
* *
* @param entityType The EntityType of the RestCall to get a builder for * @param entityType The EntityType of the RestCall to get a builder for
* @param callType The CallType of the RestCall to get a builder for (not UNDEFINDED) * @param callType The CallType of the RestCall to get a builder for (not UNDEFINED)
* @return RestCallBuilder instance to build a dedicated call and execute it */ * @return RestCallBuilder instance to build a dedicated call and execute it */
<T> RestCall<T>.RestCallBuilder getBuilder( <T> RestCall<T>.RestCallBuilder getBuilder(
EntityType entityType, EntityType entityType,

View file

@ -21,6 +21,7 @@ import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
@Lazy @Lazy
@Component @Component
@GuiProfile @GuiProfile

View file

@ -119,17 +119,15 @@ public class CurrentUser {
return userInfo return userInfo
.getRoles() .getRoles()
.stream() .stream()
.map(roleName -> UserRole.valueOf(roleName)) .map(UserRole::valueOf)
.map(role -> new RoleTypeKey(entityType, role)) .map(role -> new RoleTypeKey(entityType, role))
.map(key -> this.privileges.get(key)) .map(key -> this.privileges.get(key))
.filter(priv -> (priv != null) && priv.hasGrant( .anyMatch(privilege -> (privilege != null) && privilege.hasGrant(
userInfo.uuid, userInfo.uuid,
userInfo.institutionId, userInfo.institutionId,
privilegeType, privilegeType,
institutionId, institutionId,
ownerId)) ownerId));
.findFirst()
.isPresent();
} catch (final Exception e) { } catch (final Exception e) {
log.error("Failed to verify privilege: PrivilegeType {} EntityType {}", log.error("Failed to verify privilege: PrivilegeType {} EntityType {}",
privilegeType, entityType, e); privilegeType, entityType, e);
@ -149,17 +147,15 @@ public class CurrentUser {
final UserInfo userInfo = get(); final UserInfo userInfo = get();
return userInfo.getRoles() return userInfo.getRoles()
.stream() .stream()
.map(roleName -> UserRole.valueOf(roleName)) .map(UserRole::valueOf)
.map(role -> new RoleTypeKey(entityType, role)) .map(role -> new RoleTypeKey(entityType, role))
.map(key -> this.privileges.get(key)) .map(key -> this.privileges.get(key))
.filter(priv -> (priv != null) && priv.hasGrant( .anyMatch(privilege -> (privilege != null) && privilege.hasGrant(
userInfo.uuid, userInfo.uuid,
userInfo.institutionId, userInfo.institutionId,
privilegeType, privilegeType,
grantEntity.getInstitutionId(), grantEntity.getInstitutionId(),
grantEntity.getOwnerId())) grantEntity.getOwnerId()));
.findFirst()
.isPresent();
} catch (final Exception e) { } catch (final Exception e) {
log.error("Failed to verify privilege: PrivilegeType {} EntityType {}", log.error("Failed to verify privilege: PrivilegeType {} EntityType {}",
privilegeType, entityType, e); privilegeType, entityType, e);
@ -234,9 +230,9 @@ public class CurrentUser {
if (privileges != null) { if (privileges != null) {
this.privileges = privileges this.privileges = privileges
.stream() .stream()
.reduce(new HashMap<RoleTypeKey, Privilege>(), .reduce(new HashMap<>(),
(map, priv) -> { (map, privilege) -> {
map.put(priv.roleTypeKey, priv); map.put(privilege.roleTypeKey, privilege);
return map; return map;
}, },
(map1, map2) -> { (map1, map2) -> {

View file

@ -8,15 +8,12 @@
package ch.ethz.seb.sebserver.gui.service.remote.webservice.auth; package ch.ethz.seb.sebserver.gui.service.remote.webservice.auth;
import java.io.IOException; import ch.ethz.seb.sebserver.ClientHttpRequestFactoryService;
import java.net.URI; import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
import java.nio.charset.Charset; import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
import java.util.Arrays; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import java.util.Collections; import ch.ethz.seb.sebserver.gbl.util.Result;
import java.util.List; import ch.ethz.seb.sebserver.gbl.util.Utils;
import javax.servlet.http.HttpSession;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -44,12 +41,13 @@ import org.springframework.web.client.ResponseExtractor;
import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import ch.ethz.seb.sebserver.ClientHttpRequestFactoryService; import javax.servlet.http.HttpSession;
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; import java.io.IOException;
import ch.ethz.seb.sebserver.gbl.model.user.UserRole; import java.net.URI;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import java.nio.charset.StandardCharsets;
import ch.ethz.seb.sebserver.gbl.util.Result; import java.util.Arrays;
import ch.ethz.seb.sebserver.gbl.util.Utils; import java.util.Collections;
import java.util.List;
@Lazy @Lazy
@Component @Component
@ -171,7 +169,7 @@ public class OAuth2AuthorizationContextHolder implements AuthorizationContextHol
this.restTemplate.setErrorHandler(new ErrorHandler(this.resource)); this.restTemplate.setErrorHandler(new ErrorHandler(this.resource));
this.restTemplate this.restTemplate
.getMessageConverters() .getMessageConverters()
.add(0, new StringHttpMessageConverter(Charset.forName("UTF-8"))); .add(0, new StringHttpMessageConverter(StandardCharsets.UTF_8));
this.revokeTokenURI = webserviceURIService.getOAuthRevokeTokenURI(); this.revokeTokenURI = webserviceURIService.getOAuthRevokeTokenURI();
this.currentUserURI = webserviceURIService.getCurrentUserRequestURI(); this.currentUserURI = webserviceURIService.getCurrentUserRequestURI();

View file

@ -34,7 +34,7 @@ public interface SEBServerAuthorizationContext {
* *
* @param username the username for login * @param username the username for login
* @param password the password for login * @param password the password for login
* @return */ * @return true if login was successful, false if no */
boolean login(String username, CharSequence password); boolean login(String username, CharSequence password);
/** Requests a logout on SEB Server webservice if a user is currently logged in /** Requests a logout on SEB Server webservice if a user is currently logged in

View file

@ -14,29 +14,29 @@ public class WebserviceConnectionData {
final String id; final String id;
final String webserviceProtocol; final String webserviceProtocol;
final String webserviceServerAdress; final String webserviceServerAddress;
final String webserviceServerPort; final String webserviceServerPort;
final String webserviceAPIPath; final String webserviceAPIPath;
final String webserviceServerAddress; final String webserviceServerURL;
private final UriComponentsBuilder webserviceURIBuilder; private final UriComponentsBuilder webserviceURIBuilder;
protected WebserviceConnectionData( protected WebserviceConnectionData(
final String id, final String id,
final String webserviceProtocol, final String webserviceProtocol,
final String webserviceServerAdress, final String webserviceServerAddress,
final String webserviceServerPort, final String webserviceServerPort,
final String webserviceAPIPath) { final String webserviceAPIPath) {
this.id = id; this.id = id;
this.webserviceProtocol = webserviceProtocol; this.webserviceProtocol = webserviceProtocol;
this.webserviceServerAdress = webserviceServerAdress; this.webserviceServerAddress = webserviceServerAddress;
this.webserviceServerPort = webserviceServerPort; this.webserviceServerPort = webserviceServerPort;
this.webserviceAPIPath = webserviceAPIPath; this.webserviceAPIPath = webserviceAPIPath;
this.webserviceServerAddress = webserviceProtocol + "://" + webserviceServerAdress + ":" + webserviceServerPort; this.webserviceServerURL = webserviceProtocol + "://" + webserviceServerAddress + ":" + webserviceServerPort;
this.webserviceURIBuilder = UriComponentsBuilder this.webserviceURIBuilder = UriComponentsBuilder
.fromHttpUrl(webserviceProtocol + "://" + webserviceServerAdress) .fromHttpUrl(webserviceProtocol + "://" + webserviceServerAddress)
.port(webserviceServerPort) .port(webserviceServerPort)
.path(webserviceAPIPath); .path(webserviceAPIPath);
} }
@ -49,8 +49,8 @@ public class WebserviceConnectionData {
return this.webserviceProtocol; return this.webserviceProtocol;
} }
public String getWebserviceServerAdress() { public String getWebserviceServerAddress() {
return this.webserviceServerAdress; return this.webserviceServerAddress;
} }
public String getWebserviceServerPort() { public String getWebserviceServerPort() {
@ -61,8 +61,8 @@ public class WebserviceConnectionData {
return this.webserviceAPIPath; return this.webserviceAPIPath;
} }
public String getWebserviceServerAddress() { public String getWebserviceServerURL() {
return this.webserviceServerAddress; return this.webserviceServerURL;
} }
public UriComponentsBuilder getWebserviceURIBuilder() { public UriComponentsBuilder getWebserviceURIBuilder() {
@ -101,8 +101,8 @@ public class WebserviceConnectionData {
builder.append(this.id); builder.append(this.id);
builder.append(", webserviceProtocol="); builder.append(", webserviceProtocol=");
builder.append(this.webserviceProtocol); builder.append(this.webserviceProtocol);
builder.append(", webserviceServerAdress="); builder.append(", webserviceServerAddress=");
builder.append(this.webserviceServerAdress); builder.append(this.webserviceServerAddress);
builder.append(", webserviceServerPort="); builder.append(", webserviceServerPort=");
builder.append(this.webserviceServerPort); builder.append(this.webserviceServerPort);
builder.append(", webserviceAPIPath="); builder.append(", webserviceAPIPath=");

View file

@ -25,15 +25,15 @@ public class WebserviceURIService {
public WebserviceURIService( public WebserviceURIService(
@Value("${sebserver.gui.webservice.protocol}") final String webserviceProtocol, @Value("${sebserver.gui.webservice.protocol}") final String webserviceProtocol,
@Value("${sebserver.gui.webservice.address}") final String webserviceServerAdress, @Value("${sebserver.gui.webservice.address}") final String webserviceServerAddress,
@Value("${sebserver.gui.webservice.port}") final String webserviceServerPort, @Value("${sebserver.gui.webservice.port}") final String webserviceServerPort,
@Value("${server.servlet.context-path}") final String servletContextPath, @Value("${server.servlet.context-path}") final String servletContextPath,
@Value("${sebserver.gui.webservice.apipath}") final String webserviceAPIPath) { @Value("${sebserver.gui.webservice.apipath}") final String webserviceAPIPath) {
this.servletContextPath = servletContextPath; this.servletContextPath = servletContextPath;
this.webserviceServerAddress = webserviceProtocol + "://" + webserviceServerAdress + ":" + webserviceServerPort; this.webserviceServerAddress = webserviceProtocol + "://" + webserviceServerAddress + ":" + webserviceServerPort;
this.webserviceURIBuilder = UriComponentsBuilder this.webserviceURIBuilder = UriComponentsBuilder
.fromHttpUrl(webserviceProtocol + "://" + webserviceServerAdress) .fromHttpUrl(webserviceProtocol + "://" + webserviceServerAddress)
.port(webserviceServerPort) .port(webserviceServerPort)
.path(servletContextPath) .path(servletContextPath)
.path(webserviceAPIPath); .path(webserviceAPIPath);

View file

@ -49,12 +49,10 @@ public class ClientConnectionDetails {
private static final int NUMBER_OF_NONE_INDICATOR_ROWS = 3; private static final int NUMBER_OF_NONE_INDICATOR_ROWS = 3;
private final PageService pageService;
private final ResourceService resourceService; private final ResourceService resourceService;
private final Exam exam;
private final EnumMap<IndicatorType, IndicatorData> indicatorMapping; private final EnumMap<IndicatorType, IndicatorData> indicatorMapping;
private final RestCall<ClientConnectionData>.RestCallBuilder restCallBuilder; private final RestCall<ClientConnectionData>.RestCallBuilder restCallBuilder;
private final FormHandle<?> formhandle; private final FormHandle<?> formHandle;
private final ColorData colorData; private final ColorData colorData;
private ClientConnectionData connectionData = null; private ClientConnectionData connectionData = null;
@ -69,9 +67,7 @@ public class ClientConnectionDetails {
final Display display = pageContext.getRoot().getDisplay(); final Display display = pageContext.getRoot().getDisplay();
this.pageService = pageService;
this.resourceService = pageService.getResourceService(); this.resourceService = pageService.getResourceService();
this.exam = exam;
this.restCallBuilder = restCallBuilder; this.restCallBuilder = restCallBuilder;
this.colorData = new ColorData(display); this.colorData = new ColorData(display);
this.indicatorMapping = IndicatorData.createFormIndicators( this.indicatorMapping = IndicatorData.createFormIndicators(
@ -80,12 +76,12 @@ public class ClientConnectionDetails {
this.colorData, this.colorData,
NUMBER_OF_NONE_INDICATOR_ROWS); NUMBER_OF_NONE_INDICATOR_ROWS);
final FormBuilder formBuilder = this.pageService.formBuilder(pageContext) final FormBuilder formBuilder = pageService.formBuilder(pageContext)
.readonly(true) .readonly(true)
.addField(FormBuilder.text( .addField(FormBuilder.text(
QuizData.QUIZ_ATTR_NAME, QuizData.QUIZ_ATTR_NAME,
EXAM_NAME_TEXT_KEY, EXAM_NAME_TEXT_KEY,
this.exam.getName())) exam.getName()))
.addField(FormBuilder.text( .addField(FormBuilder.text(
Domain.CLIENT_CONNECTION.ATTR_EXAM_USER_SESSION_ID, Domain.CLIENT_CONNECTION.ATTR_EXAM_USER_SESSION_ID,
CONNECTION_ID_TEXT_KEY, CONNECTION_ID_TEXT_KEY,
@ -112,7 +108,7 @@ public class ClientConnectionDetails {
.withDefaultLabel(indData.indicator.name)) .withDefaultLabel(indData.indicator.name))
.addEmptyCell()); .addEmptyCell());
this.formhandle = formBuilder.build(); this.formHandle = formBuilder.build();
} }
public void updateData() { public void updateData() {
@ -136,7 +132,7 @@ public class ClientConnectionDetails {
return; return;
} }
final Form form = this.formhandle.getForm(); final Form form = this.formHandle.getForm();
form.setFieldValue( form.setFieldValue(
Domain.CLIENT_CONNECTION.ATTR_EXAM_USER_SESSION_ID, Domain.CLIENT_CONNECTION.ATTR_EXAM_USER_SESSION_ID,
this.connectionData.clientConnection.userSessionId); this.connectionData.clientConnection.userSessionId);

View file

@ -371,7 +371,7 @@ public final class ClientConnectionTable {
private void sortTable() { private void sortTable() {
this.tableMapping = this.tableMapping.entrySet() this.tableMapping = this.tableMapping.entrySet()
.stream() .stream()
.sorted((e1, e2) -> e1.getValue().compareTo(e2.getValue())) .sorted(Entry.comparingByValue())
.collect(Collectors.toMap( .collect(Collectors.toMap(
Entry::getKey, Entry::getKey,
Entry::getValue, Entry::getValue,
@ -398,13 +398,12 @@ public final class ClientConnectionTable {
final String attribute = this.resourceService final String attribute = this.resourceService
.getCurrentUser() .getCurrentUser()
.getAttribute(USER_SESSION_STATUS_FILTER_ATTRIBUTE); .getAttribute(USER_SESSION_STATUS_FILTER_ATTRIBUTE);
if (attribute != null) {
this.statusFilter.clear(); this.statusFilter.clear();
if (attribute != null) {
Arrays.asList(StringUtils.split(attribute, Constants.LIST_SEPARATOR)) Arrays.asList(StringUtils.split(attribute, Constants.LIST_SEPARATOR))
.forEach(name -> this.statusFilter.add(ConnectionStatus.valueOf(name))); .forEach(name -> this.statusFilter.add(ConnectionStatus.valueOf(name)));
} else { } else {
this.statusFilter.clear();
this.statusFilter.add(ConnectionStatus.DISABLED); this.statusFilter.add(ConnectionStatus.DISABLED);
} }
} catch (final Exception e) { } catch (final Exception e) {
@ -460,7 +459,7 @@ public final class ClientConnectionTable {
} }
void updateData(final TableItem tableItem) { void updateData(final TableItem tableItem) {
tableItem.setText(0, getConnectionIdentifer()); tableItem.setText(0, getConnectionIdentifier());
tableItem.setText(1, getConnectionAddress()); tableItem.setText(1, getConnectionAddress());
tableItem.setText(2, getStatusName()); tableItem.setText(2, getStatusName());
} }
@ -533,7 +532,7 @@ public final class ClientConnectionTable {
public int compareTo(final UpdatableTableItem other) { public int compareTo(final UpdatableTableItem other) {
return Comparator.comparingInt(UpdatableTableItem::statusWeight) return Comparator.comparingInt(UpdatableTableItem::statusWeight)
.thenComparingInt(UpdatableTableItem::thresholdsWeight) .thenComparingInt(UpdatableTableItem::thresholdsWeight)
.thenComparing(UpdatableTableItem::getConnectionIdentifer) .thenComparing(UpdatableTableItem::getConnectionIdentifier)
.compare(this, other); .compare(this, other);
} }
@ -580,7 +579,7 @@ public final class ClientConnectionTable {
return Constants.EMPTY_NOTE; return Constants.EMPTY_NOTE;
} }
String getConnectionIdentifer() { String getConnectionIdentifier() {
if (this.connectionData != null && this.connectionData.clientConnection.userSessionId != null) { if (this.connectionData != null && this.connectionData.clientConnection.userSessionId != null) {
return this.connectionData.clientConnection.userSessionId; return this.connectionData.clientConnection.userSessionId;
} }
@ -608,10 +607,7 @@ public final class ClientConnectionTable {
final IndicatorData indicatorData = final IndicatorData indicatorData =
ClientConnectionTable.this.indicatorMapping.get(indicatorValue.getType()); ClientConnectionTable.this.indicatorMapping.get(indicatorValue.getType());
if (indicatorData == null) { if (indicatorData != null) {
log.error("No IndicatorData of type: {} found", indicatorValue.getType());
} else {
final double value = indicatorValue.getValue(); final double value = indicatorValue.getValue();
final int indicatorWeight = IndicatorData.getWeight(indicatorData, value); final int indicatorWeight = IndicatorData.getWeight(indicatorData, value);
if (this.indicatorWeights[indicatorData.index] != indicatorWeight) { if (this.indicatorWeights[indicatorData.index] != indicatorWeight) {

View file

@ -8,18 +8,17 @@
package ch.ethz.seb.sebserver.gui.service.session; package ch.ethz.seb.sebserver.gui.service.session;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumMap;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.widgets.Display;
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator; import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.IndicatorType; import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.IndicatorType;
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.Threshold; import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.Threshold;
import ch.ethz.seb.sebserver.gbl.util.Utils; import ch.ethz.seb.sebserver.gbl.util.Utils;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.widgets.Display;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.EnumMap;
final class IndicatorData { final class IndicatorData {
@ -47,13 +46,13 @@ final class IndicatorData {
this.thresholdColor = new ThresholdColor[indicator.thresholds.size()]; this.thresholdColor = new ThresholdColor[indicator.thresholds.size()];
final ArrayList<Threshold> sortedThresholds = new ArrayList<>(indicator.thresholds); final ArrayList<Threshold> sortedThresholds = new ArrayList<>(indicator.thresholds);
Collections.sort(sortedThresholds, (t1, t2) -> t1.value.compareTo(t2.value)); sortedThresholds.sort(Comparator.comparing(t -> t.value));
for (int i = 0; i < indicator.thresholds.size(); i++) { for (int i = 0; i < indicator.thresholds.size(); i++) {
this.thresholdColor[i] = new ThresholdColor(sortedThresholds.get(i), display, colorData); this.thresholdColor[i] = new ThresholdColor(sortedThresholds.get(i), display, colorData);
} }
} }
static final EnumMap<IndicatorType, IndicatorData> createFormIndicators( static EnumMap<IndicatorType, IndicatorData> createFormIndicators(
final Collection<Indicator> indicators, final Collection<Indicator> indicators,
final Display display, final Display display,
final ColorData colorData, final ColorData colorData,
@ -73,7 +72,7 @@ final class IndicatorData {
return indicatorMapping; return indicatorMapping;
} }
static final int getWeight(final IndicatorData indicatorData, final double value) { static int getWeight(final IndicatorData indicatorData, final double value) {
for (int j = 0; j < indicatorData.thresholdColor.length; j++) { for (int j = 0; j < indicatorData.thresholdColor.length; j++) {
if (value < indicatorData.thresholdColor[j].value) { if (value < indicatorData.thresholdColor[j].value) {
return (j == 0) ? -1 : j - 1; return (j == 0) ? -1 : j - 1;

View file

@ -92,13 +92,11 @@ public class InstructionProcessor {
StringUtils.join(connectionTokens, Constants.LIST_SEPARATOR), StringUtils.join(connectionTokens, Constants.LIST_SEPARATOR),
null); null);
processInstruction(() -> { processInstruction(() -> this.restService.getBuilder(PropagateInstruction.class)
return this.restService.getBuilder(PropagateInstruction.class)
.withURIVariable(API.PARAM_MODEL_ID, String.valueOf(examId)) .withURIVariable(API.PARAM_MODEL_ID, String.valueOf(examId))
.withBody(clientInstruction) .withBody(clientInstruction)
.call() .call()
.getOrThrow(); .getOrThrow(),
},
pageContext); pageContext);
} }
@ -116,7 +114,6 @@ public class InstructionProcessor {
ConnectionStatus.AUTHENTICATED)); ConnectionStatus.AUTHENTICATED));
if (connectionTokens.isEmpty()) { if (connectionTokens.isEmpty()) {
// TOOD message
return; return;
} }
@ -126,15 +123,13 @@ public class InstructionProcessor {
connectionTokens); connectionTokens);
} }
processInstruction(() -> { processInstruction(() -> this.restService.getBuilder(DisableClientConnection.class)
return this.restService.getBuilder(DisableClientConnection.class)
.withURIVariable(API.PARAM_MODEL_ID, String.valueOf(examId)) .withURIVariable(API.PARAM_MODEL_ID, String.valueOf(examId))
.withFormParam( .withFormParam(
Domain.CLIENT_CONNECTION.ATTR_CONNECTION_TOKEN, Domain.CLIENT_CONNECTION.ATTR_CONNECTION_TOKEN,
StringUtils.join(connectionTokens, Constants.LIST_SEPARATOR)) StringUtils.join(connectionTokens, Constants.LIST_SEPARATOR))
.call() .call()
.getOrThrow(); .getOrThrow(),
},
pageContext); pageContext);
} }

View file

@ -96,12 +96,12 @@ public class EntityTable<ROW extends Entity> {
private final BiConsumer<TableItem, ROW> rowDecorator; private final BiConsumer<TableItem, ROW> rowDecorator;
private final Consumer<Set<ROW>> selectionListener; private final Consumer<Set<ROW>> selectionListener;
int pageNumber = 1; int pageNumber;
int pageSize; int pageSize;
String sortColumn = null; String sortColumn = null;
PageSortOrder sortOrder = PageSortOrder.ASCENDING; PageSortOrder sortOrder = PageSortOrder.ASCENDING;
boolean columnsWithSameWidth = true; boolean columnsWithSameWidth = true;
boolean hideNavigation = false; boolean hideNavigation;
EntityTable( EntityTable(
final String name, final String name,
@ -149,13 +149,10 @@ public class EntityTable<ROW extends Entity> {
this.rowDecorator = rowDecorator; this.rowDecorator = rowDecorator;
this.selectionListener = selectionListener; this.selectionListener = selectionListener;
this.pageSize = pageSize; this.pageSize = pageSize;
this.filter = this.filter = columns
columns
.stream() .stream()
.map(column -> column.getFilterAttribute()) .map(ColumnDefinition::getFilterAttribute)
.filter(Objects::nonNull) .anyMatch(Objects::nonNull) ? new TableFilter<>(this) : null;
.findFirst()
.isPresent() ? new TableFilter<>(this) : null;
this.table = this.widgetFactory.tableLocalized(this.composite); this.table = this.widgetFactory.tableLocalized(this.composite);
final GridLayout gridLayout = new GridLayout(columns.size(), true); final GridLayout gridLayout = new GridLayout(columns.size(), true);
@ -207,17 +204,15 @@ public class EntityTable<ROW extends Entity> {
} }
for (int i = 0; i < columns.size(); i++) { for (int i = 0; i < columns.size(); i++) {
final Rectangle itemBoundes = item.getBounds(i); final Rectangle itemBounds = item.getBounds(i);
if (itemBoundes.contains(point)) { if (itemBounds.contains(point)) {
handleCellSelection(item, i); handleCellSelection(item, i);
return; return;
} }
} }
}); });
this.table.addListener(SWT.Selection, event -> { this.table.addListener(SWT.Selection, event -> this.notifySelectionChange());
this.notifySelectionChange();
});
this.navigator = new TableNavigator(this); this.navigator = new TableNavigator(this);
@ -375,8 +370,7 @@ public class EntityTable<ROW extends Entity> {
return Collections.emptySet(); return Collections.emptySet();
} }
return Arrays.asList(selection) return Arrays.stream(selection)
.stream()
.map(this::getRowData) .map(this::getRowData)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
} }
@ -391,8 +385,7 @@ public class EntityTable<ROW extends Entity> {
return Collections.emptySet(); return Collections.emptySet();
} }
return Arrays.asList(selection) return Arrays.stream(selection)
.stream()
.filter(item -> grantCheck == null || grantCheck.test(getRowData(item))) .filter(item -> grantCheck == null || grantCheck.test(getRowData(item)))
.map(this::getRowDataId) .map(this::getRowDataId)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
@ -415,8 +408,7 @@ public class EntityTable<ROW extends Entity> {
} }
private TableColumn getTableColumn(final String name) { private TableColumn getTableColumn(final String name) {
return Arrays.asList(this.table.getColumns()) return Arrays.stream(this.table.getColumns())
.stream()
.filter(col -> { .filter(col -> {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
final ColumnDefinition<ROW> def = (ColumnDefinition<ROW>) col.getData(COLUMN_DEFINITION); final ColumnDefinition<ROW> def = (ColumnDefinition<ROW>) col.getData(COLUMN_DEFINITION);
@ -541,7 +533,7 @@ public class EntityTable<ROW extends Entity> {
.filter(c -> c.getWidthProportion() > 0) .filter(c -> c.getWidthProportion() > 0)
.reduce(0, .reduce(0,
(acc, c) -> acc + c.getWidthProportion(), (acc, c) -> acc + c.getWidthProportion(),
(acc1, acc2) -> acc1 + acc2); Integer::sum);
// The unit size either with proportion or for a entire column if all columns are equal in size // The unit size either with proportion or for a entire column if all columns are equal in size
final int columnUnitSize = (pSize > 0) final int columnUnitSize = (pSize > 0)

View file

@ -100,7 +100,7 @@ public class TableBuilder<ROW extends Entity> {
return this; return this;
} }
public TableBuilder<ROW> withMultiselection() { public TableBuilder<ROW> withMultiSelection() {
this.type |= SWT.MULTI; this.type |= SWT.MULTI;
return this; return this;
} }

View file

@ -49,7 +49,7 @@ public class TableFilter<ROW extends Entity> {
private static final LocTextKey DATE_TO_TEXT = new LocTextKey("sebserver.overall.date.to"); private static final LocTextKey DATE_TO_TEXT = new LocTextKey("sebserver.overall.date.to");
private static final LocTextKey ALL_TEXT = new LocTextKey("sebserver.overall.status.all"); private static final LocTextKey ALL_TEXT = new LocTextKey("sebserver.overall.status.all");
public static enum CriteriaType { public enum CriteriaType {
TEXT, TEXT,
SINGLE_SELECTION, SINGLE_SELECTION,
DATE, DATE,
@ -82,7 +82,7 @@ public class TableFilter<ROW extends Entity> {
public MultiValueMap<String, String> getFilterParameter() { public MultiValueMap<String, String> getFilterParameter() {
return this.components return this.components
.stream() .stream()
.reduce(new LinkedMultiValueMap<String, String>(), .reduce(new LinkedMultiValueMap<>(),
(map, comp) -> comp.putFilterParameter(map), (map, comp) -> comp.putFilterParameter(map),
(map1, map2) -> { (map1, map2) -> {
map1.putAll(map2); map1.putAll(map2);
@ -92,8 +92,7 @@ public class TableFilter<ROW extends Entity> {
public void reset() { public void reset() {
this.components this.components
.stream() .forEach(FilterComponent::reset);
.forEach(comp -> comp.reset());
} }
private void buildComponents() { private void buildComponents() {
@ -158,7 +157,7 @@ public class TableFilter<ROW extends Entity> {
.append(Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR) .append(Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR)
.append(filter.getValue()) .append(filter.getValue())
.append(Constants.LIST_SEPARATOR), .append(Constants.LIST_SEPARATOR),
(sb1, sb2) -> sb1.append(sb2)); StringBuilder::append);
if (builder.length() > 0) { if (builder.length() > 0) {
builder.deleteCharAt(builder.length() - 1); builder.deleteCharAt(builder.length() - 1);
} }
@ -171,22 +170,19 @@ public class TableFilter<ROW extends Entity> {
} }
try { try {
Arrays.asList(StringUtils.split( Arrays.stream(StringUtils.split(
attribute, attribute,
Constants.LIST_SEPARATOR_CHAR)) Constants.LIST_SEPARATOR_CHAR))
.stream()
.map(nameValue -> StringUtils.split( .map(nameValue -> StringUtils.split(
nameValue, nameValue,
Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR)) Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR))
.forEach(nameValue -> { .forEach(nameValue -> this.components
this.components
.stream() .stream()
.filter(filter -> nameValue[0].equals(filter.attribute.columnName)) .filter(filter -> nameValue[0].equals(filter.attribute.columnName))
.findFirst() .findFirst()
.ifPresent(filter -> filter.setValue((nameValue.length > 1) .ifPresent(filter -> filter.setValue((nameValue.length > 1)
? nameValue[1] ? nameValue[1]
: StringUtils.EMPTY)); : StringUtils.EMPTY)));
});
} catch (final Exception e) { } catch (final Exception e) {
log.error("Failed to set filter attributes: ", e); log.error("Failed to set filter attributes: ", e);
} }
@ -208,9 +204,7 @@ public class TableFilter<ROW extends Entity> {
ImageIcon.SEARCH, ImageIcon.SEARCH,
inner, inner,
new LocTextKey("sebserver.overall.action.filter"), new LocTextKey("sebserver.overall.action.filter"),
event -> { event -> this.entityTable.applyFilter());
this.entityTable.applyFilter();
});
imageButton.setLayoutData(gridData); imageButton.setLayoutData(gridData);
final Label imageButton2 = this.entityTable.widgetFactory.imageButton( final Label imageButton2 = this.entityTable.widgetFactory.imageButton(
ImageIcon.CANCEL, ImageIcon.CANCEL,
@ -276,7 +270,7 @@ public class TableFilter<ROW extends Entity> {
} }
} }
private class NullFilter extends FilterComponent { private static class NullFilter extends FilterComponent {
private Label label; private Label label;
@ -493,7 +487,6 @@ public class TableFilter<ROW extends Entity> {
private class DateRange extends FilterComponent { private class DateRange extends FilterComponent {
private Composite innerComposite; private Composite innerComposite;
//private final GridData rw1 = new GridData(SWT.FILL, SWT.FILL, true, true);
private DateTime fromDateSelector; private DateTime fromDateSelector;
private DateTime toDateSelector; private DateTime toDateSelector;
private DateTime fromTimeSelector; private DateTime fromTimeSelector;

View file

@ -68,7 +68,7 @@ public class TableNavigator {
if (numberOfPages > 1) { if (numberOfPages > 1) {
createBackwardLabel(pageNumber > 1, pageNumber, numNav); createBackwardLabel(pageNumber > 1, pageNumber, numNav);
final int pageNavSize = (numberOfPages > PAGE_NAV_SIZE) ? PAGE_NAV_SIZE : numberOfPages; final int pageNavSize = Math.min(numberOfPages, PAGE_NAV_SIZE);
final int half = pageNavSize / 2; final int half = pageNavSize / 2;
int start = pageNumber - half; int start = pageNumber - half;
if (start < 1) { if (start < 1) {
@ -107,14 +107,12 @@ public class TableNavigator {
final GridData rowData = new GridData(22, 16); final GridData rowData = new GridData(22, 16);
final Label pageLabel = new Label(parent, SWT.NONE); final Label pageLabel = new Label(parent, SWT.NONE);
pageLabel.setText(" " + String.valueOf(page) + " "); pageLabel.setText(" " + page + " ");
pageLabel.setLayoutData(rowData); pageLabel.setLayoutData(rowData);
pageLabel.setAlignment(SWT.CENTER); pageLabel.setAlignment(SWT.CENTER);
if (selectable) { if (selectable) {
pageLabel.setData(RWT.CUSTOM_VARIANT, CustomVariant.LIST_NAVIGATION.key); pageLabel.setData(RWT.CUSTOM_VARIANT, CustomVariant.LIST_NAVIGATION.key);
pageLabel.addListener(SWT.MouseDown, event -> { pageLabel.addListener(SWT.MouseDown, event -> this.entityTable.selectPage(page));
this.entityTable.selectPage(page);
});
} }
} }
@ -131,9 +129,7 @@ public class TableNavigator {
forward.setLayoutData(rowData); forward.setLayoutData(rowData);
forward.setAlignment(SWT.CENTER); forward.setAlignment(SWT.CENTER);
if (visible) { if (visible) {
forward.addListener(SWT.MouseDown, event -> { forward.addListener(SWT.MouseDown, event -> this.entityTable.selectPage(pageNumber + 1));
this.entityTable.selectPage(pageNumber + 1);
});
} else { } else {
forward.setVisible(false); forward.setVisible(false);
} }
@ -144,9 +140,7 @@ public class TableNavigator {
end.setLayoutData(rowData); end.setLayoutData(rowData);
end.setAlignment(SWT.CENTER); end.setAlignment(SWT.CENTER);
if (visible) { if (visible) {
end.addListener(SWT.MouseDown, event -> { end.addListener(SWT.MouseDown, event -> this.entityTable.selectPage(numberOfPages));
this.entityTable.selectPage(numberOfPages);
});
} else { } else {
end.setVisible(false); end.setVisible(false);
} }
@ -164,9 +158,7 @@ public class TableNavigator {
start.setAlignment(SWT.CENTER); start.setAlignment(SWT.CENTER);
start.setData(RWT.CUSTOM_VARIANT, CustomVariant.LIST_NAVIGATION.key); start.setData(RWT.CUSTOM_VARIANT, CustomVariant.LIST_NAVIGATION.key);
if (visible) { if (visible) {
start.addListener(SWT.MouseDown, event -> { start.addListener(SWT.MouseDown, event -> this.entityTable.selectPage(1));
this.entityTable.selectPage(1);
});
} else { } else {
start.setVisible(false); start.setVisible(false);
} }
@ -177,9 +169,7 @@ public class TableNavigator {
backward.setAlignment(SWT.CENTER); backward.setAlignment(SWT.CENTER);
backward.setData(RWT.CUSTOM_VARIANT, CustomVariant.LIST_NAVIGATION.key); backward.setData(RWT.CUSTOM_VARIANT, CustomVariant.LIST_NAVIGATION.key);
if (visible) { if (visible) {
backward.addListener(SWT.MouseDown, event -> { backward.addListener(SWT.MouseDown, event -> this.entityTable.selectPage(pageNumber - 1));
this.entityTable.selectPage(pageNumber - 1);
});
} else { } else {
backward.setVisible(false); backward.setVisible(false);
} }

View file

@ -166,10 +166,8 @@ public class FileUploadSelection extends Composite {
private boolean fileSupported(final String fileName) { private boolean fileSupported(final String fileName) {
return this.supportedFileExtensions return this.supportedFileExtensions
.stream() .stream()
.filter(fileType -> fileName.toUpperCase(Locale.ROOT) .anyMatch(fileType -> fileName.toUpperCase(Locale.ROOT)
.endsWith(fileType.toUpperCase(Locale.ROOT))) .endsWith(fileType.toUpperCase(Locale.ROOT)));
.findFirst()
.isPresent();
} }
private final class InputReceiver extends FileUploadReceiver { private final class InputReceiver extends FileUploadReceiver {

View file

@ -157,7 +157,7 @@ public class GridTable extends Composite {
return StringUtils.join( return StringUtils.join(
this.rows this.rows
.stream() .stream()
.map(row -> row.getValue()) .map(Row::getValue)
.collect(Collectors.toList()), .collect(Collectors.toList()),
Constants.LIST_SEPARATOR); Constants.LIST_SEPARATOR);
} }
@ -209,10 +209,9 @@ public class GridTable extends Composite {
.stream() .stream()
.reduce(0, .reduce(0,
(i, c2) -> i + c2.columnDef.widthFactor, (i, c2) -> i + c2.columnDef.widthFactor,
(i1, i2) -> i1 + i2); Integer::sum);
this.columns this.columns
.stream()
.forEach(c -> c.header.widthHint = c.columnDef.widthFactor * widthUnit); .forEach(c -> c.header.widthHint = c.columnDef.widthFactor * widthUnit);
super.layout(true, true); super.layout(true, true);
@ -273,7 +272,7 @@ public class GridTable extends Composite {
this.defaultValue = defaultValue; this.defaultValue = defaultValue;
} }
public static final ColumnDef fromString( public static ColumnDef fromString(
final String string, final String string,
final Map<String, String> defaultValueMap) { final Map<String, String> defaultValueMap) {

View file

@ -48,10 +48,7 @@ public final class ImageUploadSelection extends Composite {
private static final long serialVersionUID = 368264811155804533L; private static final long serialVersionUID = 368264811155804533L;
private static final Logger log = LoggerFactory.getLogger(ImageUploadSelection.class); private static final Logger log = LoggerFactory.getLogger(ImageUploadSelection.class);
public static final Set<String> SUPPORTED_IMAGE_FILES = Collections.unmodifiableSet(new HashSet<>(Arrays.asList( public static final Set<String> SUPPORTED_IMAGE_FILES = Set.of(".png", ".jpg", ".jpeg");
".png",
".jpg",
".jpeg")));
private final ServerPushService serverPushService; private final ServerPushService serverPushService;
@ -152,12 +149,12 @@ public final class ImageUploadSelection extends Composite {
setImage(this, input); setImage(this, input);
} }
private static final boolean uploadInProgress(final ServerPushContext context) { private static boolean uploadInProgress(final ServerPushContext context) {
final ImageUploadSelection imageUpload = (ImageUploadSelection) context.getAnchor(); final ImageUploadSelection imageUpload = (ImageUploadSelection) context.getAnchor();
return imageUpload.loadNewImage && !imageUpload.imageLoaded; return imageUpload.loadNewImage && !imageUpload.imageLoaded;
} }
private static final void update(final ServerPushContext context) { private static void update(final ServerPushContext context) {
final ImageUploadSelection imageUpload = (ImageUploadSelection) context.getAnchor(); final ImageUploadSelection imageUpload = (ImageUploadSelection) context.getAnchor();
if (imageUpload.imageBase64 != null if (imageUpload.imageBase64 != null
&& imageUpload.loadNewImage && imageUpload.loadNewImage
@ -181,12 +178,8 @@ public final class ImageUploadSelection extends Composite {
final Image image = new Image(imageUpload.imageCanvas.getDisplay(), input); final Image image = new Image(imageUpload.imageCanvas.getDisplay(), input);
final Rectangle imageBounds = image.getBounds(); final Rectangle imageBounds = image.getBounds();
final int width = (imageBounds.width > imageUpload.maxWidth) final int width = Math.min(imageBounds.width, imageUpload.maxWidth);
? imageUpload.maxWidth final int height = Math.min(imageBounds.height, imageUpload.maxHeight);
: imageBounds.width;
final int height = (imageBounds.height > imageUpload.maxHeight)
? imageUpload.maxHeight
: imageBounds.height;
final ImageData imageData = image.getImageData().scaledTo(width, height); final ImageData imageData = image.getImageData().scaledTo(width, height);
imageUpload.imageCanvas.setBackgroundImage(new Image(imageUpload.imageCanvas.getDisplay(), imageData)); imageUpload.imageCanvas.setBackgroundImage(new Image(imageUpload.imageCanvas.getDisplay(), imageData));
} }
@ -194,10 +187,8 @@ public final class ImageUploadSelection extends Composite {
private static boolean fileSupported(final String fileName) { private static boolean fileSupported(final String fileName) {
return SUPPORTED_IMAGE_FILES return SUPPORTED_IMAGE_FILES
.stream() .stream()
.filter(fileType -> fileName.toUpperCase(Locale.ROOT) .anyMatch(fileType -> fileName.toUpperCase(Locale.ROOT)
.endsWith(fileType.toUpperCase(Locale.ROOT))) .endsWith(fileType.toUpperCase(Locale.ROOT)));
.findFirst()
.isPresent();
} }
private final class ImageReceiver extends FileUploadReceiver { private final class ImageReceiver extends FileUploadReceiver {

View file

@ -8,12 +8,11 @@
package ch.ethz.seb.sebserver.gui.widget; package ch.ethz.seb.sebserver.gui.widget;
import java.util.Arrays; import ch.ethz.seb.sebserver.gbl.Constants;
import java.util.LinkedHashMap; import ch.ethz.seb.sebserver.gbl.util.Tuple;
import java.util.List; import ch.ethz.seb.sebserver.gbl.util.Tuple3;
import java.util.Map; import ch.ethz.seb.sebserver.gbl.util.Utils;
import java.util.stream.Collectors; import ch.ethz.seb.sebserver.gui.service.page.PageService;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.eclipse.swt.SWT; import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridData;
@ -22,11 +21,10 @@ import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Listener;
import ch.ethz.seb.sebserver.gbl.Constants; import java.util.Arrays;
import ch.ethz.seb.sebserver.gbl.util.Tuple; import java.util.LinkedHashMap;
import ch.ethz.seb.sebserver.gbl.util.Tuple3; import java.util.List;
import ch.ethz.seb.sebserver.gbl.util.Utils; import java.util.Map;
import ch.ethz.seb.sebserver.gui.service.page.PageService;
public final class MultiSelectionCheckbox extends Composite implements Selection { public final class MultiSelectionCheckbox extends Composite implements Selection {
@ -121,7 +119,7 @@ public final class MultiSelectionCheckbox extends Composite implements Selection
.stream() .stream()
.filter(Button::getSelection) .filter(Button::getSelection)
.map(button -> (String) button.getData(OPTION_VALUE)) .map(button -> (String) button.getData(OPTION_VALUE))
.collect(Collectors.toList()).toArray()); .toArray());
} }
@Override @Override

View file

@ -8,13 +8,9 @@
package ch.ethz.seb.sebserver.gui.widget; package ch.ethz.seb.sebserver.gui.widget;
import java.util.ArrayList; import ch.ethz.seb.sebserver.gbl.Constants;
import java.util.Arrays; import ch.ethz.seb.sebserver.gbl.util.Tuple;
import java.util.Collection; import ch.ethz.seb.sebserver.gui.service.page.PageService;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.eclipse.rap.rwt.widgets.DropDown; import org.eclipse.rap.rwt.widgets.DropDown;
import org.eclipse.swt.SWT; import org.eclipse.swt.SWT;
@ -29,9 +25,10 @@ import org.eclipse.swt.widgets.Text;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import ch.ethz.seb.sebserver.gbl.Constants; import java.util.ArrayList;
import ch.ethz.seb.sebserver.gbl.util.Tuple; import java.util.Arrays;
import ch.ethz.seb.sebserver.gui.service.page.PageService; import java.util.List;
import java.util.Optional;
public final class MultiSelectionCombo extends Composite implements Selection { public final class MultiSelectionCombo extends Composite implements Selection {
@ -75,12 +72,8 @@ public final class MultiSelectionCombo extends Composite implements Selection {
this.textCell = new GridData(SWT.LEFT, SWT.CENTER, true, true); this.textCell = new GridData(SWT.LEFT, SWT.CENTER, true, true);
this.textInput.setLayoutData(this.textCell); this.textInput.setLayoutData(this.textCell);
this.dropDown = new DropDown(this.textInput, SWT.NONE); this.dropDown = new DropDown(this.textInput, SWT.NONE);
this.textInput.addListener(SWT.FocusIn, event -> { this.textInput.addListener(SWT.FocusIn, event -> openDropDown());
openDropDown(); this.textInput.addListener(SWT.Modify, event -> openDropDown());
});
this.textInput.addListener(SWT.Modify, event -> {
openDropDown();
});
this.dropDown.addListener(SWT.Selection, event -> { this.dropDown.addListener(SWT.Selection, event -> {
final int selectionIndex = this.dropDown.getSelectionIndex(); final int selectionIndex = this.dropDown.getSelectionIndex();
if (selectionIndex >= 0) { if (selectionIndex >= 0) {
@ -98,12 +91,10 @@ public final class MultiSelectionCombo extends Composite implements Selection {
this.dropDown.setVisible(false); this.dropDown.setVisible(false);
return; return;
} }
final Collection<String> items = this.availableValues this.dropDown.setItems(this.availableValues
.stream() .stream()
.filter(it -> it._2 != null && it._2.startsWith(text)) .filter(it -> it._2 != null && it._2.startsWith(text))
.map(t -> t._2) .map(t -> t._2).toArray(String[]::new));
.collect(Collectors.toList());
this.dropDown.setItems(items.toArray(new String[items.size()]));
this.dropDown.setSelectionIndex(0); this.dropDown.setSelectionIndex(0);
this.dropDown.setVisible(true); this.dropDown.setVisible(true);
} }
@ -132,8 +123,7 @@ public final class MultiSelectionCombo extends Composite implements Selection {
return; return;
} }
Arrays.asList(StringUtils.split(keys, Constants.LIST_SEPARATOR)) Arrays.stream(StringUtils.split(keys, Constants.LIST_SEPARATOR))
.stream()
.map(this::itemForId) .map(this::itemForId)
.forEach(this::addSelection); .forEach(this::addSelection);
} }
@ -159,7 +149,6 @@ public final class MultiSelectionCombo extends Composite implements Selection {
public void clear() { public void clear() {
this.selectedValues.clear(); this.selectedValues.clear();
this.selectionControls this.selectionControls
.stream()
.forEach(Control::dispose); .forEach(Control::dispose);
this.selectionControls.clear(); this.selectionControls.clear();
this.availableValues.clear(); this.availableValues.clear();
@ -176,9 +165,7 @@ public final class MultiSelectionCombo extends Composite implements Selection {
label.setData(OPTION_VALUE, item._2); label.setData(OPTION_VALUE, item._2);
final GridData textCell = new GridData(SWT.LEFT, SWT.CENTER, true, true); final GridData textCell = new GridData(SWT.LEFT, SWT.CENTER, true, true);
label.setLayoutData(textCell); label.setLayoutData(textCell);
label.addListener(SWT.MouseDoubleClick, event -> { label.addListener(SWT.MouseDoubleClick, this::removeComboSelection);
removeComboSelection(event);
});
this.selectionControls.add(label); this.selectionControls.add(label);
this.availableValues.remove(item); this.availableValues.remove(item);
@ -217,8 +204,7 @@ public final class MultiSelectionCombo extends Composite implements Selection {
private void adaptColumnWidth(final Event event) { private void adaptColumnWidth(final Event event) {
try { try {
final int currentTableWidth = this.getClientArea().width; this.textCell.widthHint = this.getClientArea().width;
this.textCell.widthHint = currentTableWidth;
this.layout(); this.layout();
} catch (final Exception e) { } catch (final Exception e) {
log.warn("Failed to adaptColumnWidth: ", e); log.warn("Failed to adaptColumnWidth: ", e);
@ -230,11 +216,7 @@ public final class MultiSelectionCombo extends Composite implements Selection {
.stream() .stream()
.filter(it -> it._2 != null && it._2.equals(name)) .filter(it -> it._2 != null && it._2.equals(name))
.findFirst(); .findFirst();
if (findFirst.isPresent()) { return findFirst.orElse(null);
return findFirst.get();
}
return null;
} }
private Tuple<String> itemForId(final String id) { private Tuple<String> itemForId(final String id) {
@ -242,11 +224,7 @@ public final class MultiSelectionCombo extends Composite implements Selection {
.stream() .stream()
.filter(it -> it._1 != null && it._1.equals(id)) .filter(it -> it._1 != null && it._1.equals(id))
.findFirst(); .findFirst();
if (findFirst.isPresent()) { return findFirst.orElse(null);
return findFirst.get();
}
return null;
} }
} }

View file

@ -99,7 +99,7 @@ public final class RadioSelection extends Composite implements Selection {
return this.radioButtons return this.radioButtons
.values() .values()
.stream() .stream()
.filter(button -> button.getSelection()) .filter(Button::getSelection)
.findFirst() .findFirst()
.map(button -> (String) button.getData(OPTION_VALUE)) .map(button -> (String) button.getData(OPTION_VALUE))
.orElse(null); .orElse(null);
@ -109,7 +109,6 @@ public final class RadioSelection extends Composite implements Selection {
public void clear() { public void clear() {
this.radioButtons this.radioButtons
.values() .values()
.stream()
.forEach(button -> button.setSelection(false)); .forEach(button -> button.setSelection(false));
} }

View file

@ -17,7 +17,7 @@ import ch.ethz.seb.sebserver.gbl.util.Tuple;
public interface Selection { public interface Selection {
static final String OPTION_VALUE = "OPTION_VALUE"; String OPTION_VALUE = "OPTION_VALUE";
enum Type { enum Type {
SINGLE, SINGLE,

View file

@ -87,7 +87,7 @@ public final class SingleSelection extends Combo implements Selection {
@Override @Override
public void clear() { public void clear() {
super.clearSelection(); super.clearSelection();
super.setItems(this.valueMapping.toArray(new String[this.valueMapping.size()])); super.setItems(this.valueMapping.toArray(new String[0]));
} }
@Override @Override

View file

@ -123,7 +123,7 @@ public class WidgetFactory {
private ImageData image = null; private ImageData image = null;
private ImageData greyedImage = null; private ImageData greyedImage = null;
private ImageIcon(final String fileName) { ImageIcon(final String fileName) {
this.fileName = fileName; this.fileName = fileName;
} }
@ -199,7 +199,7 @@ public class WidgetFactory {
public final String key; public final String key;
private CustomVariant(final String key) { CustomVariant(final String key) {
this.key = key; this.key = key;
} }
} }
@ -268,7 +268,7 @@ public class WidgetFactory {
* @param parent The parent Composite * @param parent The parent Composite
* @return the scrolled Composite to add the form content */ * @return the scrolled Composite to add the form content */
public Composite createPopupScrollComposite(final Composite parent) { public Composite createPopupScrollComposite(final Composite parent) {
final Composite grid = PageService.createManagedVScrolledComposite( return PageService.createManagedVScrolledComposite(
parent, parent,
scrolledComposite -> { scrolledComposite -> {
final Composite g = new Composite(scrolledComposite, SWT.NONE); final Composite g = new Composite(scrolledComposite, SWT.NONE);
@ -277,7 +277,6 @@ public class WidgetFactory {
return g; return g;
}, },
false); false);
return grid;
} }
public Composite createWarningPanel(final Composite parent) { public Composite createWarningPanel(final Composite parent) {
@ -733,7 +732,7 @@ public class WidgetFactory {
new FileUploadSelection(parent, this.i18nSupport, readonly); new FileUploadSelection(parent, this.i18nSupport, readonly);
if (supportedFiles != null) { if (supportedFiles != null) {
supportedFiles.forEach(ext -> fileUploadSelection.withSupportFor(ext)); supportedFiles.forEach(fileUploadSelection::withSupportFor);
} }
return fileUploadSelection; return fileUploadSelection;
} }

View file

@ -57,13 +57,6 @@ public class WebserviceInit implements ApplicationListener<ApplicationReadyEvent
SEBServerInit.INIT_LOGGER.info("----> **** Webservice starting up... ****"); SEBServerInit.INIT_LOGGER.info("----> **** Webservice starting up... ****");
SEBServerInit.INIT_LOGGER.info("----> ");
SEBServerInit.INIT_LOGGER.info("----> Init Database with flyway...");
SEBServerInit.INIT_LOGGER.info("----> TODO ");
// TODO integration of Flyway for database initialization and migration: https://flywaydb.org
// see also https://flywaydb.org/getstarted/firststeps/api
SEBServerInit.INIT_LOGGER.info("----> "); SEBServerInit.INIT_LOGGER.info("----> ");
SEBServerInit.INIT_LOGGER.info("----> Intitialize Services..."); SEBServerInit.INIT_LOGGER.info("----> Intitialize Services...");
SEBServerInit.INIT_LOGGER.info("----> "); SEBServerInit.INIT_LOGGER.info("----> ");

View file

@ -23,6 +23,7 @@ import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetupTestResult; import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetupTestResult;
import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
import org.joda.time.DateTimeZone;
/** Defines the LMS API access service interface with all functionality needed to access /** Defines the LMS API access service interface with all functionality needed to access
* a LMS API within a given LmsSetup configuration. * a LMS API within a given LmsSetup configuration.
@ -101,12 +102,12 @@ public interface LmsAPIService {
static Predicate<QuizData> quizFilterPredicate(final FilterMap filterMap) { static Predicate<QuizData> quizFilterPredicate(final FilterMap filterMap) {
final String name = filterMap.getQuizName(); final String name = filterMap.getQuizName();
final DateTime from = filterMap.getQuizFromTime(); final DateTime from = filterMap.getQuizFromTime();
//final DateTime now = DateTime.now(DateTimeZone.UTC);
return q -> { return q -> {
final boolean nameFilter = StringUtils.isBlank(name) || (q.name != null && q.name.contains(name)); final boolean nameFilter = StringUtils.isBlank(name) || (q.name != null && q.name.contains(name));
final boolean startTimeFilter = final boolean startTimeFilter =
(from == null) || (q.startTime != null && (q.startTime.isEqual(from) || q.startTime.isAfter(from))); (from == null) || (q.startTime != null && (q.startTime.isEqual(from) || q.startTime.isAfter(from)));
return nameFilter && startTimeFilter /* && endTimeFilter */; final boolean currentlyRunning = DateTime.now(DateTimeZone.UTC).isBefore(q.endTime);
return nameFilter && (startTimeFilter || currentlyRunning) ;
}; };
} }

View file

@ -60,10 +60,10 @@ public interface ClientConfigService {
unless = "#result.hasError()") unless = "#result.hasError()")
Result<ClientDetails> getClientConfigDetails(String clientName); Result<ClientDetails> getClientConfigDetails(String clientName);
@CacheEvict( /** Internally used to check OAuth2 access for a active SebClientConfig.
cacheNames = EXAM_CLIENT_DETAILS_CACHE, *
allEntries = true) * @param config the SebClientConfig to check access
@EventListener(BulkActionEvent.class) * @return true if the system was able to gain an access token for the client. False otherwise
void flushClientConfigData(BulkActionEvent event); */
boolean checkAccess(SebClientConfig config);
} }

View file

@ -10,8 +10,7 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl;
import ch.ethz.seb.sebserver.WebSecurityConfig; import ch.ethz.seb.sebserver.WebSecurityConfig;
import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType; import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.institution.Institution; import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SebClientConfig; import ch.ethz.seb.sebserver.gbl.model.sebconfig.SebClientConfig;
@ -19,8 +18,6 @@ import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.gbl.util.Utils; import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.webservice.WebserviceInfo; import ch.ethz.seb.sebserver.webservice.WebserviceInfo;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.impl.BulkActionEvent;
import ch.ethz.seb.sebserver.webservice.servicelayer.client.ClientCredentialService; import ch.ethz.seb.sebserver.webservice.servicelayer.client.ClientCredentialService;
import ch.ethz.seb.sebserver.webservice.servicelayer.client.ClientCredentials; import ch.ethz.seb.sebserver.webservice.servicelayer.client.ClientCredentials;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.InstitutionDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.InstitutionDAO;
@ -38,12 +35,21 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.common.OAuth2AccessToken; import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.ClientDetails; import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.client.BaseClientDetails; import org.springframework.security.oauth2.provider.client.BaseClientDetails;
import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -51,6 +57,7 @@ import java.io.OutputStream;
import java.io.PipedInputStream; import java.io.PipedInputStream;
import java.io.PipedOutputStream; import java.io.PipedOutputStream;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.UUID; import java.util.UUID;
@ -316,19 +323,48 @@ public class ClientConfigServiceImpl implements ClientConfigService {
} }
@Override @Override
public void flushClientConfigData(final BulkActionEvent event) { public boolean checkAccess(SebClientConfig config) {
try { if(!config.isActive()) {
final BulkAction bulkAction = event.getBulkAction(); return false;
if (bulkAction.type == BulkActionType.DEACTIVATE ||
bulkAction.type == BulkActionType.HARD_DELETE) {
bulkAction.extractKeys(EntityType.SEB_CLIENT_CONFIGURATION)
.forEach(this::flushClientConfigData);
} }
} catch (final Exception e) { try {
log.error("Unexpected error while trying to flush ClientConfig data ", e); RestTemplate restTemplate = new RestTemplate();
String externalServerURL = webserviceInfo.getExternalServerURL() +
API.OAUTH_TOKEN_ENDPOINT;
MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE);
ClientCredentials credentials = sebClientConfigDAO
.getSebClientCredentials(config.getModelId())
.getOrThrow();
CharSequence plainClientSecret = clientCredentialService.getPlainClientSecret(credentials);
String basicAuth = credentials.clientId +
String.valueOf(Constants.COLON) +
plainClientSecret;
String encoded = Base64.getEncoder()
.encodeToString(basicAuth.getBytes());
headers.add(HttpHeaders.AUTHORIZATION, "Basic " + encoded);
HttpEntity<String> entity = new HttpEntity<>(
"grant_type=client_credentials&scope=read write",
headers);
ResponseEntity<String> exchange = restTemplate.exchange(
externalServerURL,
HttpMethod.POST,
entity,
String.class);
if (exchange.getStatusCode().value() == HttpStatus.OK.value()) {
return true;
} else {
log.warn("Failed to check access SebClientConfig {} response: {}", config, exchange.getStatusCode());
return false;
}
} catch (Exception e) {
log.warn("Failed to check access for SebClientConfig: {} cause: {}", config, e.getMessage());
return false;
} }
} }

View file

@ -9,6 +9,7 @@
package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl; package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -93,6 +94,17 @@ public class ClientIndicatorFactory {
final PingIntervalClientIndicator pingIndicator = this.applicationContext final PingIntervalClientIndicator pingIndicator = this.applicationContext
.getBean(PingIntervalClientIndicator.class); .getBean(PingIntervalClientIndicator.class);
pingIndicator.hidden = true; pingIndicator.hidden = true;
final Indicator indicator = new Indicator(
null,
clientConnection.examId,
"hidden_ping_indicator",
IndicatorType.LAST_PING,
"",
Arrays.asList(new Indicator.Threshold(5000d, "")));
pingIndicator.init(
indicator,
clientConnection.id,
this.enableCaching);
result.add(pingIndicator); result.add(pingIndicator);
} }

View file

@ -38,7 +38,6 @@ public final class PingIntervalClientIndicator extends AbstractPingIndicator {
long pingErrorThreshold; long pingErrorThreshold;
boolean missingPing = false; boolean missingPing = false;
boolean hidden = false; boolean hidden = false;
public PingIntervalClientIndicator(final ClientEventExtensionMapper clientEventExtensionMapper) { public PingIntervalClientIndicator(final ClientEventExtensionMapper clientEventExtensionMapper) {

View file

@ -95,6 +95,8 @@ public class ClientEventController extends ReadonlyEntityController<ClientEvent,
filterMap.putIfAbsent(API.PARAM_INSTITUTION_ID, String.valueOf(institutionId)); filterMap.putIfAbsent(API.PARAM_INSTITUTION_ID, String.valueOf(institutionId));
} }
try {
return this.paginationService.getPage( return this.paginationService.getPage(
pageNumber, pageNumber,
pageSize, pageSize,
@ -102,6 +104,10 @@ public class ClientEventController extends ReadonlyEntityController<ClientEvent,
getSQLTableOfEntity().name(), getSQLTableOfEntity().name(),
() -> this.clientEventDAO.allMatchingExtended(filterMap, this::hasReadAccess)) () -> this.clientEventDAO.allMatchingExtended(filterMap, this::hasReadAccess))
.getOrThrow(); .getOrThrow();
} catch (Exception e) {
e.printStackTrace();
throw e;
}
} }
@Override @Override
@ -118,7 +124,7 @@ public class ClientEventController extends ReadonlyEntityController<ClientEvent,
protected GrantEntity toGrantEntity(final ClientEvent entity) { protected GrantEntity toGrantEntity(final ClientEvent entity) {
return this.examDAO return this.examDAO
.byClientConnection(entity.connectionId) .byClientConnection(entity.connectionId)
.getOrThrow(); .get();
} }
@Override @Override

View file

@ -39,6 +39,7 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.servlet.ServletOutputStream; import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@ -144,6 +145,15 @@ public class SebClientConfigController extends ActivatableEntityController<SebCl
.map(this::checkPasswordMatch); .map(this::checkPasswordMatch);
} }
@Override
protected Result<SebClientConfig> notifySaved(SebClientConfig entity) {
if (entity.isActive()) {
// try to get access token for SEB client
sebClientConfigService.checkAccess(entity);
}
return super.notifySaved(entity);
}
private SebClientConfig checkPasswordMatch(final SebClientConfig entity) { private SebClientConfig checkPasswordMatch(final SebClientConfig entity) {
Collection<APIMessage> errors = new ArrayList<>(); Collection<APIMessage> errors = new ArrayList<>();
if (entity.hasEncryptionSecret() && !entity.encryptSecret.equals(entity.encryptSecretConfirm)) { if (entity.hasEncryptionSecret() && !entity.encryptSecret.equals(entity.encryptSecretConfirm)) {

View file

@ -17,6 +17,7 @@ import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication; import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices; import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
// TODO check if we can apply some caching here to get better performance for SEB client connection attempts
public class DefaultTokenServicesFallback extends DefaultTokenServices { public class DefaultTokenServicesFallback extends DefaultTokenServices {
private static final Logger log = LoggerFactory.getLogger(DefaultTokenServicesFallback.class); private static final Logger log = LoggerFactory.getLogger(DefaultTokenServicesFallback.class);
@ -29,22 +30,22 @@ public class DefaultTokenServicesFallback extends DefaultTokenServices {
return super.createAccessToken(authentication); return super.createAccessToken(authentication);
} catch (final DuplicateKeyException e) { } catch (final DuplicateKeyException e) {
log.info( log.warn(
"Catched DuplicateKeyException, try to handle it by trying to get the already stored access token after waited some time"); "Caught DuplicateKeyException, try to handle it by trying to get the already stored access token after waited some time");
final String clientName = authentication.getName(); final String clientName = authentication.getName();
if (StringUtils.isNotBlank(clientName)) { if (StringUtils.isNotBlank(clientName)) {
// wait a second... // wait some time...
try { try {
Thread.sleep(1000); Thread.sleep(500);
} catch (final InterruptedException e1) { } catch (final InterruptedException e1) {
log.warn("Failed to sleep: {}", e1.getMessage()); log.warn("Failed to sleep: {}", e1.getMessage());
} }
final OAuth2AccessToken accessToken = this.getAccessToken(authentication); final OAuth2AccessToken accessToken = this.getAccessToken(authentication);
if (accessToken != null) { if (accessToken != null) {
log.info("Found original accees token for client: {} token: {}", clientName, accessToken); log.debug("Found original access token for client: {} ", clientName);
return accessToken; return accessToken;
} }
} }

View file

@ -25,7 +25,7 @@ sebserver.init.adminaccount.gen-on-init=false
sebserver.webservice.distributed=false sebserver.webservice.distributed=false
sebserver.webservice.http.scheme=http sebserver.webservice.http.scheme=http
sebserver.webservice.http.external.servername= sebserver.webservice.http.external.servername=
sebserver.webservice.http.external.port= sebserver.webservice.http.external.port=${server.port}
sebserver.webservice.http.redirect.gui=/gui sebserver.webservice.http.redirect.gui=/gui

View file

@ -175,7 +175,7 @@ INSERT INTO configuration_attribute VALUES
(304, 'enablePrivateClipboard', 'CHECKBOX', null, null, null, null, 'true'), (304, 'enablePrivateClipboard', 'CHECKBOX', null, null, null, null, 'true'),
(305, 'enableLogging', 'CHECKBOX', null, null, null, null, 'false'), (305, 'enableLogging', 'CHECKBOX', null, null, null, null, 'false'),
(306, 'logDirectoryWin', 'TEXT_FIELD', null, null, null, null, ''), (306, 'logDirectoryWin', 'TEXT_FIELD', null, null, null, null, ''),
(307, 'logDirectoryOSX', 'TEXT_FIELD', null, null, null, null, 'NSTemporaryDirectory'), (307, 'logDirectoryOSX', 'TEXT_FIELD', null, null, null, null, 'F'),
(308, 'minMacOSVersion', 'SINGLE_SELECTION', null, '0,1,2,3,4,5,6,7', null, null, '0'), (308, 'minMacOSVersion', 'SINGLE_SELECTION', null, '0,1,2,3,4,5,6,7', null, null, '0'),
(309, 'enableAppSwitcherCheck', 'CHECKBOX', null, null, null, null, 'true'), (309, 'enableAppSwitcherCheck', 'CHECKBOX', null, null, null, null, 'true'),
(310, 'forceAppFolderInstall', 'CHECKBOX', null, null, null, null, 'true'), (310, 'forceAppFolderInstall', 'CHECKBOX', null, null, null, null, 'true'),
@ -263,7 +263,7 @@ INSERT INTO configuration_attribute VALUES
(927, 'mobileStatusBarAppearanceExtended', 'SINGLE_SELECTION', null, '0,1,2,3,4', null, null, '1'), (927, 'mobileStatusBarAppearanceExtended', 'SINGLE_SELECTION', null, '0,1,2,3,4', null, null, '1'),
(928, 'newBrowserWindowShowURL', 'SINGLE_SELECTION', null, '0,1,2,3', null, null, '1'), (928, 'newBrowserWindowShowURL', 'SINGLE_SELECTION', null, '0,1,2,3', null, null, '1'),
(929, 'pinEmbeddedCertificates', 'CHECKBOX', null, null, null, null, 'false'), (929, 'pinEmbeddedCertificates', 'CHECKBOX', null, null, null, null, 'false'),
(930, 'sendBrowserExamKey', 'CHECKBOX', null, null, null, null, 'false'), (930, 'sendBrowserExamKey', 'CHECKBOX', null, null, null, null, 'true'),
(931, 'showNavigationButtons', 'CHECKBOX', null, null, null, null, 'false'), (931, 'showNavigationButtons', 'CHECKBOX', null, null, null, null, 'false'),
(932, 'showScanQRCodeButton', 'CHECKBOX', null, null, null, null, 'false'), (932, 'showScanQRCodeButton', 'CHECKBOX', null, null, null, null, 'false'),
(933, 'startResource', 'TEXT_FIELD', null, null, null, null, ''), (933, 'startResource', 'TEXT_FIELD', null, null, null, null, ''),

View file

@ -198,7 +198,7 @@ INSERT IGNORE INTO configuration_attribute VALUES
(304, 'enablePrivateClipboard', 'CHECKBOX', null, null, null, null, 'true'), (304, 'enablePrivateClipboard', 'CHECKBOX', null, null, null, null, 'true'),
(305, 'enableLogging', 'CHECKBOX', null, null, null, null, 'false'), (305, 'enableLogging', 'CHECKBOX', null, null, null, null, 'false'),
(306, 'logDirectoryWin', 'TEXT_FIELD', null, null, null, null, ''), (306, 'logDirectoryWin', 'TEXT_FIELD', null, null, null, null, ''),
(307, 'logDirectoryOSX', 'TEXT_FIELD', null, null, null, null, 'NSTemporaryDirectory'), (307, 'logDirectoryOSX', 'TEXT_FIELD', null, null, null, null, ''),
(308, 'minMacOSVersion', 'SINGLE_SELECTION', null, '0,1,2,3,4,5,6,7', null, null, '0'), (308, 'minMacOSVersion', 'SINGLE_SELECTION', null, '0,1,2,3,4,5,6,7', null, null, '0'),
(309, 'enableAppSwitcherCheck', 'CHECKBOX', null, null, null, null, 'true'), (309, 'enableAppSwitcherCheck', 'CHECKBOX', null, null, null, null, 'true'),
(310, 'forceAppFolderInstall', 'CHECKBOX', null, null, null, null, 'true'), (310, 'forceAppFolderInstall', 'CHECKBOX', null, null, null, null, 'true'),
@ -286,7 +286,7 @@ INSERT IGNORE INTO configuration_attribute VALUES
(927, 'mobileStatusBarAppearanceExtended', 'SINGLE_SELECTION', null, '0,1,2,3,4', null, null, '1'), (927, 'mobileStatusBarAppearanceExtended', 'SINGLE_SELECTION', null, '0,1,2,3,4', null, null, '1'),
(928, 'newBrowserWindowShowURL', 'SINGLE_SELECTION', null, '0,1,2,3', null, null, '1'), (928, 'newBrowserWindowShowURL', 'SINGLE_SELECTION', null, '0,1,2,3', null, null, '1'),
(929, 'pinEmbeddedCertificates', 'CHECKBOX', null, null, null, null, 'false'), (929, 'pinEmbeddedCertificates', 'CHECKBOX', null, null, null, null, 'false'),
(930, 'sendBrowserExamKey', 'CHECKBOX', null, null, null, null, 'false'), (930, 'sendBrowserExamKey', 'CHECKBOX', null, null, null, null, 'true'),
(931, 'showNavigationButtons', 'CHECKBOX', null, null, null, null, 'false'), (931, 'showNavigationButtons', 'CHECKBOX', null, null, null, null, 'false'),
(932, 'showScanQRCodeButton', 'CHECKBOX', null, null, null, null, 'false'), (932, 'showScanQRCodeButton', 'CHECKBOX', null, null, null, null, 'false'),
(933, 'startResource', 'TEXT_FIELD', null, null, null, null, ''), (933, 'startResource', 'TEXT_FIELD', null, null, null, null, ''),