fixed privilege check on SEB Client Events list and update quiz filter

This commit is contained in:
anhefti 2020-03-03 09:36:43 +01:00
parent a37ab31ff1
commit e7af727854
7 changed files with 441 additions and 439 deletions

View file

@ -1,41 +1,41 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui; package ch.ethz.seb.sebserver.gui;
import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.SEBServerInit; import ch.ethz.seb.sebserver.SEBServerInit;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
@Component @Component
@GuiProfile @GuiProfile
public class GuiInit implements ApplicationListener<ApplicationReadyEvent> { public class GuiInit implements ApplicationListener<ApplicationReadyEvent> {
private final SEBServerInit sebServerInit; private final SEBServerInit sebServerInit;
protected GuiInit(final SEBServerInit sebServerInit) { protected GuiInit(final SEBServerInit sebServerInit) {
this.sebServerInit = sebServerInit; this.sebServerInit = sebServerInit;
} }
@Override @Override
public void onApplicationEvent(final ApplicationReadyEvent event) { public void onApplicationEvent(final ApplicationReadyEvent event) {
this.sebServerInit.init(); this.sebServerInit.init();
SEBServerInit.INIT_LOGGER.info("---->"); SEBServerInit.INIT_LOGGER.info("---->");
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

@ -1,164 +1,164 @@
/* /*
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui; package ch.ethz.seb.sebserver.gui;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSession;
import org.eclipse.rap.rwt.RWT; import org.eclipse.rap.rwt.RWT;
import org.eclipse.rap.rwt.application.AbstractEntryPoint; import org.eclipse.rap.rwt.application.AbstractEntryPoint;
import org.eclipse.rap.rwt.application.Application; import org.eclipse.rap.rwt.application.Application;
import org.eclipse.rap.rwt.application.ApplicationConfiguration; import org.eclipse.rap.rwt.application.ApplicationConfiguration;
import org.eclipse.rap.rwt.application.EntryPoint; import org.eclipse.rap.rwt.application.EntryPoint;
import org.eclipse.rap.rwt.application.EntryPointFactory; import org.eclipse.rap.rwt.application.EntryPointFactory;
import org.eclipse.rap.rwt.client.WebClient; import org.eclipse.rap.rwt.client.WebClient;
import org.eclipse.rap.rwt.internal.theme.ThemeUtil; import org.eclipse.rap.rwt.internal.theme.ThemeUtil;
import org.eclipse.rap.rwt.service.ServiceManager; import org.eclipse.rap.rwt.service.ServiceManager;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils; import org.springframework.web.context.support.WebApplicationContextUtils;
import ch.ethz.seb.sebserver.gui.service.remote.download.DownloadService; import ch.ethz.seb.sebserver.gui.service.remote.download.DownloadService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.SEBServerAuthorizationContext; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.SEBServerAuthorizationContext;
public class RAPConfiguration implements ApplicationConfiguration { public class RAPConfiguration implements ApplicationConfiguration {
private static final String DEFAULT_THEME_NAME = "sebserver"; private static final String DEFAULT_THEME_NAME = "sebserver";
private static final Logger log = LoggerFactory.getLogger(RAPConfiguration.class); private static final Logger log = LoggerFactory.getLogger(RAPConfiguration.class);
@Override @Override
public void configure(final Application application) { public void configure(final Application application) {
try { try {
// TODO get file path from properties // TODO get file path from properties
//application.addStyleSheet(RWT.DEFAULT_THEME_ID, "static/css/sebserver.css"); //application.addStyleSheet(RWT.DEFAULT_THEME_ID, "static/css/sebserver.css");
application.addStyleSheet(DEFAULT_THEME_NAME, "resource/theme/default.css"); application.addStyleSheet(DEFAULT_THEME_NAME, "resource/theme/default.css");
application.addStyleSheet(DEFAULT_THEME_NAME, "static/css/sebserver.css"); application.addStyleSheet(DEFAULT_THEME_NAME, "static/css/sebserver.css");
application.addStyleSheet("sms", "resource/theme/default.css"); application.addStyleSheet("sms", "resource/theme/default.css");
application.addStyleSheet("sms", "static/css/sms.css"); application.addStyleSheet("sms", "static/css/sms.css");
final Map<String, String> properties = new HashMap<>(); final Map<String, String> properties = new HashMap<>();
properties.put(WebClient.PAGE_TITLE, "SEB Server"); properties.put(WebClient.PAGE_TITLE, "SEB Server");
properties.put(WebClient.BODY_HTML, "<big>Loading Application<big>"); properties.put(WebClient.BODY_HTML, "<big>Loading Application<big>");
properties.put(WebClient.THEME_ID, DEFAULT_THEME_NAME); properties.put(WebClient.THEME_ID, DEFAULT_THEME_NAME);
// properties.put(WebClient.FAVICON, "icons/favicon.png"); // properties.put(WebClient.FAVICON, "icons/favicon.png");
application.addEntryPoint("/gui", new RAPSpringEntryPointFactory(), properties); application.addEntryPoint("/gui", new RAPSpringEntryPointFactory(), properties);
} catch (final RuntimeException re) { } catch (final RuntimeException re) {
throw re; throw re;
} catch (final Exception e) { } catch (final Exception e) {
log.error("Error during CSS parsing. Please check the custom CSS files for errors.", e); log.error("Error during CSS parsing. Please check the custom CSS files for errors.", e);
} }
} }
public static interface EntryPointService { public interface EntryPointService {
void loadLoginPage(final Composite parent); void loadLoginPage(final Composite parent);
void loadMainPage(final Composite parent); void loadMainPage(final Composite parent);
} }
public static final class RAPSpringEntryPointFactory implements EntryPointFactory { public static final class RAPSpringEntryPointFactory implements EntryPointFactory {
private boolean initialized = false; private boolean initialized = false;
@Override @Override
public EntryPoint create() { public EntryPoint create() {
return new AbstractEntryPoint() { return new AbstractEntryPoint() {
private static final long serialVersionUID = -1299125117752916270L; private static final long serialVersionUID = -1299125117752916270L;
@Override @Override
protected void createContents(final Composite parent) { protected void createContents(final Composite parent) {
final HttpSession httpSession = RWT final HttpSession httpSession = RWT
.getUISession(parent.getDisplay()) .getUISession(parent.getDisplay())
.getHttpSession(); .getHttpSession();
log.debug("Create new GUI entrypoint. HttpSession: " + httpSession); log.debug("Create new GUI entrypoint. HttpSession: " + httpSession);
if (httpSession == null) { if (httpSession == null) {
log.error("HttpSession not available from RWT.getUISession().getHttpSession()"); log.error("HttpSession not available from RWT.getUISession().getHttpSession()");
throw new IllegalStateException( throw new IllegalStateException(
"HttpSession not available from RWT.getUISession().getHttpSession()"); "HttpSession not available from RWT.getUISession().getHttpSession()");
} }
final Object themeId = httpSession.getAttribute("themeId"); final Object themeId = httpSession.getAttribute("themeId");
if (themeId != null) { if (themeId != null) {
ThemeUtil.setCurrentThemeId(RWT.getUISession(parent.getDisplay()), String.valueOf(themeId)); ThemeUtil.setCurrentThemeId(RWT.getUISession(parent.getDisplay()), String.valueOf(themeId));
parent.redraw(); parent.redraw();
parent.layout(true); parent.layout(true);
parent.redraw(); parent.redraw();
} }
final WebApplicationContext webApplicationContext = getWebApplicationContext(httpSession); final WebApplicationContext webApplicationContext = getWebApplicationContext(httpSession);
initSpringBasedRAPServices(webApplicationContext); initSpringBasedRAPServices(webApplicationContext);
final EntryPointService entryPointService = webApplicationContext final EntryPointService entryPointService = webApplicationContext
.getBean(EntryPointService.class); .getBean(EntryPointService.class);
if (isAuthenticated(httpSession, webApplicationContext)) { if (isAuthenticated(httpSession, webApplicationContext)) {
entryPointService.loadMainPage(parent); entryPointService.loadMainPage(parent);
} else { } else {
entryPointService.loadLoginPage(parent); entryPointService.loadLoginPage(parent);
} }
} }
}; };
} }
private void initSpringBasedRAPServices(final WebApplicationContext webApplicationContext) { private void initSpringBasedRAPServices(final WebApplicationContext webApplicationContext) {
if (!this.initialized) { if (!this.initialized) {
try { try {
final ServiceManager manager = RWT.getServiceManager(); final ServiceManager manager = RWT.getServiceManager();
final DownloadService downloadService = webApplicationContext.getBean(DownloadService.class); final DownloadService downloadService = webApplicationContext.getBean(DownloadService.class);
manager.registerServiceHandler(DownloadService.DOWNLOAD_SERVICE_NAME, downloadService); manager.registerServiceHandler(DownloadService.DOWNLOAD_SERVICE_NAME, downloadService);
this.initialized = true; this.initialized = true;
} catch (final IllegalArgumentException iae) { } catch (final IllegalArgumentException iae) {
log.warn("Failed to register DownloadService on ServiceManager. Already registered: ", iae); log.warn("Failed to register DownloadService on ServiceManager. Already registered: ", iae);
} }
} }
} }
private boolean isAuthenticated( private boolean isAuthenticated(
final HttpSession httpSession, final HttpSession httpSession,
final WebApplicationContext webApplicationContext) { final WebApplicationContext webApplicationContext) {
final AuthorizationContextHolder authorizationContextHolder = webApplicationContext final AuthorizationContextHolder authorizationContextHolder = webApplicationContext
.getBean(AuthorizationContextHolder.class); .getBean(AuthorizationContextHolder.class);
final SEBServerAuthorizationContext authorizationContext = authorizationContextHolder final SEBServerAuthorizationContext authorizationContext = authorizationContextHolder
.getAuthorizationContext(httpSession); .getAuthorizationContext(httpSession);
return authorizationContext.isValid() && authorizationContext.isLoggedIn(); return authorizationContext.isValid() && authorizationContext.isLoggedIn();
} }
private WebApplicationContext getWebApplicationContext(final HttpSession httpSession) { private WebApplicationContext getWebApplicationContext(final HttpSession httpSession) {
try { try {
final ServletContext servletContext = httpSession.getServletContext(); final ServletContext servletContext = httpSession.getServletContext();
log.debug("Initialize Spring-Context on Servlet-Context: " + servletContext); log.debug("Initialize Spring-Context on Servlet-Context: " + servletContext);
return WebApplicationContextUtils return WebApplicationContextUtils
.getRequiredWebApplicationContext(servletContext); .getRequiredWebApplicationContext(servletContext);
} catch (final RuntimeException e) { } catch (final RuntimeException e) {
log.error("Failed to initialize Spring-Context on HttpSession: " + httpSession); log.error("Failed to initialize Spring-Context on HttpSession: " + httpSession);
throw e; throw e;
} catch (final Exception e) { } catch (final Exception e) {
log.error("Failed to initialize Spring-Context on HttpSession: " + httpSession); log.error("Failed to initialize Spring-Context on HttpSession: " + httpSession);
throw new RuntimeException("Failed to initialize Spring-Context on HttpSession: " + httpSession); throw new RuntimeException("Failed to initialize Spring-Context on HttpSession: " + httpSession);
} }
} }
}; }
} }

View file

@ -1,83 +1,81 @@
/* /*
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
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 org.eclipse.rap.rwt.engine.RWTServlet;
import javax.servlet.ServletException; import org.eclipse.rap.rwt.engine.RWTServletContextListener;
import org.slf4j.Logger;
import org.eclipse.rap.rwt.engine.RWTServlet; import org.slf4j.LoggerFactory;
import org.eclipse.rap.rwt.engine.RWTServletContextListener; import org.springframework.beans.factory.annotation.Value;
import org.slf4j.Logger; import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.slf4j.LoggerFactory; import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.boot.web.servlet.ServletContextInitializer; import org.springframework.context.MessageSource;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean; import org.springframework.context.annotation.Bean;
import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.annotation.Configuration;
import org.springframework.context.MessageSource; import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import javax.servlet.ServletContext;
import org.springframework.context.support.ReloadableResourceBundleMessageSource; import javax.servlet.ServletContextListener;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; @Configuration
@GuiProfile
@Configuration public class RAPSpringConfig {
@GuiProfile
public class RAPSpringConfig { private static final Logger log = LoggerFactory.getLogger(RAPSpringConfig.class);
private static final Logger log = LoggerFactory.getLogger(RAPSpringConfig.class); @Value("${sebserver.gui.entrypoint}")
private String entrypoint;
@Value("${sebserver.gui.entrypoint}")
private String entrypoint; @Value("${sebserver.gui.external.messages:messages}")
private String externalMessagesPath;
@Value("${sebserver.gui.external.messages:messages}")
private String externalMessagesPath; @Bean
public ServletContextInitializer initializer() {
@Bean return new RAPServletContextInitializer();
public ServletContextInitializer initializer() { }
return new RAPServletContextInitializer();
} @Bean
public ServletListenerRegistrationBean<ServletContextListener> listenerRegistrationBean() {
@Bean final ServletListenerRegistrationBean<ServletContextListener> bean =
public ServletListenerRegistrationBean<ServletContextListener> listenerRegistrationBean() { new ServletListenerRegistrationBean<>();
final ServletListenerRegistrationBean<ServletContextListener> bean = bean.setListener(new RWTServletContextListener());
new ServletListenerRegistrationBean<>(); return bean;
bean.setListener(new RWTServletContextListener()); }
return bean;
} @Bean
public ServletRegistrationBean<RWTServlet> servletRegistrationBean() {
@Bean return new ServletRegistrationBean<>(new RWTServlet(), this.entrypoint + "/*");
public ServletRegistrationBean<RWTServlet> servletRegistrationBean() { }
return new ServletRegistrationBean<>(new RWTServlet(), this.entrypoint + "/*");
} @Bean
public MessageSource messageSource() {
@Bean final ReloadableResourceBundleMessageSource reloadableResourceBundleMessageSource =
public MessageSource messageSource() { new ReloadableResourceBundleMessageSource();
final ReloadableResourceBundleMessageSource reloadableResourceBundleMessageSource =
new ReloadableResourceBundleMessageSource(); log.info(" +++ Register external messages resources from: {}", this.externalMessagesPath);
log.info(" +++ Register external messages resources from: {}", this.externalMessagesPath); reloadableResourceBundleMessageSource.setBasenames(
this.externalMessagesPath,
reloadableResourceBundleMessageSource.setBasenames( "classpath:messages");
this.externalMessagesPath,
"classpath:messages"); return reloadableResourceBundleMessageSource;
}
return reloadableResourceBundleMessageSource;
} private static class RAPServletContextInitializer implements ServletContextInitializer {
@Override
private static class RAPServletContextInitializer implements ServletContextInitializer { public void onStartup(final ServletContext servletContext) {
@Override servletContext.setInitParameter(
public void onStartup(final ServletContext servletContext) throws ServletException { "org.eclipse.rap.applicationConfiguration",
servletContext.setInitParameter( RAPConfiguration.class.getName());
"org.eclipse.rap.applicationConfiguration", }
RAPConfiguration.class.getName()); }
}
} }
}

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

@ -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

@ -1,135 +1,141 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.webservice.weblayer.api; package ch.ethz.seb.sebserver.webservice.weblayer.api;
import java.util.Collection; import java.util.Collection;
import org.mybatis.dynamic.sql.SqlTable; import org.mybatis.dynamic.sql.SqlTable;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.util.MultiValueMap; import org.springframework.util.MultiValueMap;
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.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType; import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType;
import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType; import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.GrantEntity; import ch.ethz.seb.sebserver.gbl.model.GrantEntity;
import ch.ethz.seb.sebserver.gbl.model.Page; import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent; import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent;
import ch.ethz.seb.sebserver.gbl.model.session.ExtendedClientEvent; import ch.ethz.seb.sebserver.gbl.model.session.ExtendedClientEvent;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientEventRecordDynamicSqlSupport; import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientEventRecordDynamicSqlSupport;
import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService; import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationService; import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationService;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.PermissionDeniedException; import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.PermissionDeniedException;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.UserService; import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.UserService;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.impl.SEBServerUser; import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.impl.SEBServerUser;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionService; import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionService;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ClientEventDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ClientEventDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationService; import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationService;
@WebServiceProfile @WebServiceProfile
@RestController @RestController
@RequestMapping("${sebserver.webservice.api.admin.endpoint}" + API.SEB_CLIENT_EVENT_ENDPOINT) @RequestMapping("${sebserver.webservice.api.admin.endpoint}" + API.SEB_CLIENT_EVENT_ENDPOINT)
public class ClientEventController extends ReadonlyEntityController<ClientEvent, ClientEvent> { public class ClientEventController extends ReadonlyEntityController<ClientEvent, ClientEvent> {
private final ExamDAO examDAO; private final ExamDAO examDAO;
private final ClientEventDAO clientEventDAO; private final ClientEventDAO clientEventDAO;
protected ClientEventController( protected ClientEventController(
final AuthorizationService authorization, final AuthorizationService authorization,
final BulkActionService bulkActionService, final BulkActionService bulkActionService,
final ClientEventDAO entityDAO, final ClientEventDAO entityDAO,
final UserActivityLogDAO userActivityLogDAO, final UserActivityLogDAO userActivityLogDAO,
final PaginationService paginationService, final PaginationService paginationService,
final BeanValidationService beanValidationService, final BeanValidationService beanValidationService,
final ExamDAO examDAO) { final ExamDAO examDAO) {
super(authorization, super(authorization,
bulkActionService, bulkActionService,
entityDAO, entityDAO,
userActivityLogDAO, userActivityLogDAO,
paginationService, paginationService,
beanValidationService); beanValidationService);
this.examDAO = examDAO; this.examDAO = examDAO;
this.clientEventDAO = entityDAO; this.clientEventDAO = entityDAO;
} }
@RequestMapping( @RequestMapping(
path = API.SEB_CLIENT_EVENT_SEARCH_PATH_SEGMENT, path = API.SEB_CLIENT_EVENT_SEARCH_PATH_SEGMENT,
method = RequestMethod.GET, method = RequestMethod.GET,
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE) produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public Page<ExtendedClientEvent> getExtendedPage( public Page<ExtendedClientEvent> getExtendedPage(
@RequestParam( @RequestParam(
name = API.PARAM_INSTITUTION_ID, name = API.PARAM_INSTITUTION_ID,
required = true, required = true,
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId, defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId,
@RequestParam(name = Page.ATTR_PAGE_NUMBER, required = false) final Integer pageNumber, @RequestParam(name = Page.ATTR_PAGE_NUMBER, required = false) final Integer pageNumber,
@RequestParam(name = Page.ATTR_PAGE_SIZE, required = false) final Integer pageSize, @RequestParam(name = Page.ATTR_PAGE_SIZE, required = false) final Integer pageSize,
@RequestParam(name = Page.ATTR_SORT, required = false) final String sort, @RequestParam(name = Page.ATTR_SORT, required = false) final String sort,
@RequestParam final MultiValueMap<String, String> allRequestParams) { @RequestParam final MultiValueMap<String, String> allRequestParams) {
// at least current user must have base read access for specified entity type within its own institution // at least current user must have base read access for specified entity type within its own institution
checkReadPrivilege(institutionId); checkReadPrivilege(institutionId);
final FilterMap filterMap = new FilterMap(allRequestParams); final FilterMap filterMap = new FilterMap(allRequestParams);
// if current user has no read access for specified entity type within other institution // if current user has no read access for specified entity type within other institution
// then the current users institutionId is put as a SQL filter criteria attribute to extends query performance // then the current users institutionId is put as a SQL filter criteria attribute to extends query performance
if (!this.authorization.hasGrant(PrivilegeType.READ, getGrantEntityType())) { if (!this.authorization.hasGrant(PrivilegeType.READ, getGrantEntityType())) {
filterMap.putIfAbsent(API.PARAM_INSTITUTION_ID, String.valueOf(institutionId)); filterMap.putIfAbsent(API.PARAM_INSTITUTION_ID, String.valueOf(institutionId));
} }
return this.paginationService.getPage( try {
pageNumber,
pageSize, return this.paginationService.getPage(
sort, pageNumber,
getSQLTableOfEntity().name(), pageSize,
() -> this.clientEventDAO.allMatchingExtended(filterMap, this::hasReadAccess)) sort,
.getOrThrow(); getSQLTableOfEntity().name(),
} () -> this.clientEventDAO.allMatchingExtended(filterMap, this::hasReadAccess))
.getOrThrow();
@Override } catch (Exception e) {
public Collection<EntityKey> getDependencies(final String modelId, final BulkActionType bulkActionType) { e.printStackTrace();
throw new UnsupportedOperationException(); throw e;
} }
}
@Override
protected SqlTable getSQLTableOfEntity() { @Override
return ClientEventRecordDynamicSqlSupport.clientEventRecord; public Collection<EntityKey> getDependencies(final String modelId, final BulkActionType bulkActionType) {
} throw new UnsupportedOperationException();
}
@Override
protected GrantEntity toGrantEntity(final ClientEvent entity) { @Override
return this.examDAO protected SqlTable getSQLTableOfEntity() {
.byClientConnection(entity.connectionId) return ClientEventRecordDynamicSqlSupport.clientEventRecord;
.getOrThrow(); }
}
@Override
@Override protected GrantEntity toGrantEntity(final ClientEvent entity) {
protected void checkReadPrivilege(final Long institutionId) { return this.examDAO
final SEBServerUser currentUser = this.authorization.getUserService().getCurrentUser(); .byClientConnection(entity.connectionId)
if (currentUser.institutionId().longValue() != institutionId.longValue()) { .get();
throw new PermissionDeniedException( }
EntityType.CLIENT_EVENT,
PrivilegeType.READ, @Override
currentUser.getUserInfo()); protected void checkReadPrivilege(final Long institutionId) {
} final SEBServerUser currentUser = this.authorization.getUserService().getCurrentUser();
} if (currentUser.institutionId().longValue() != institutionId.longValue()) {
throw new PermissionDeniedException(
} EntityType.CLIENT_EVENT,
PrivilegeType.READ,
currentUser.getUserInfo());
}
}
}