SEBSERV-63 monitoring and running exam list page
This commit is contained in:
parent
43283fe14f
commit
5f9a2c6fe0
27 changed files with 546 additions and 96 deletions
src/main
java/ch/ethz/seb/sebserver
gui
content
ExamList.javaInstitutionList.javaLmsSetupList.javaMonitoringRunningExam.javaMonitoringRunningExamList.javaQuizDiscoveryList.javaSebClientConfigList.javaSebExamConfigList.javaUserAccountList.java
action
activity
service
table
webservice
resources
|
@ -17,7 +17,6 @@ import org.springframework.beans.factory.annotation.Value;
|
|||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
||||
|
@ -49,6 +48,8 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
|||
@GuiProfile
|
||||
public class ExamList implements TemplateComposer {
|
||||
|
||||
private static final LocTextKey PAGE_TITLE_KEY =
|
||||
new LocTextKey("sebserver.exam.list.title");
|
||||
private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION =
|
||||
new LocTextKey("sebserver.exam.list.action.no.modify.privilege");
|
||||
private final static LocTextKey EMPTY_SELECTION_TEXT_KEY =
|
||||
|
@ -69,6 +70,7 @@ public class ExamList implements TemplateComposer {
|
|||
new TableFilterAttribute(CriteriaType.TEXT, QuizData.FILTER_ATTR_NAME);
|
||||
private final TableFilterAttribute startTimeFilter =
|
||||
new TableFilterAttribute(CriteriaType.DATE, QuizData.FILTER_ATTR_START_TIME);
|
||||
private final TableFilterAttribute typeFilter;
|
||||
|
||||
private final PageService pageService;
|
||||
private final ResourceService resourceService;
|
||||
|
@ -77,16 +79,21 @@ public class ExamList implements TemplateComposer {
|
|||
protected ExamList(
|
||||
final PageService pageService,
|
||||
final ResourceService resourceService,
|
||||
@Value("${sebserver.gui.list.page.size}") final Integer pageSize) {
|
||||
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.resourceService = resourceService;
|
||||
this.pageSize = (pageSize != null) ? pageSize : 20;
|
||||
this.pageSize = pageSize;
|
||||
|
||||
this.lmsFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
LmsSetup.FILTER_ATTR_LMS_SETUP,
|
||||
this.resourceService::lmsSetupResource);
|
||||
|
||||
this.typeFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
Exam.FILTER_ATTR_TYPE,
|
||||
this.resourceService::examTypeResources);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -100,9 +107,10 @@ public class ExamList implements TemplateComposer {
|
|||
// content page layout with title
|
||||
final Composite content = widgetFactory.defaultPageLayout(
|
||||
pageContext.getParent(),
|
||||
new LocTextKey("sebserver.exam.list.title"));
|
||||
PAGE_TITLE_KEY);
|
||||
|
||||
final PageActionBuilder actionBuilder = this.pageService.pageActionBuilder(pageContext.clearEntityKeys());
|
||||
final PageActionBuilder actionBuilder = this.pageService
|
||||
.pageActionBuilder(pageContext.clearEntityKeys());
|
||||
|
||||
// table
|
||||
final EntityTable<Exam> table =
|
||||
|
@ -132,7 +140,8 @@ public class ExamList implements TemplateComposer {
|
|||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.EXAM.ATTR_TYPE,
|
||||
COLUMN_TITLE_TYPE_KEY,
|
||||
this::examTypeName)
|
||||
this.resourceService::examTypeName)
|
||||
.withFilter(this.typeFilter)
|
||||
.sortable())
|
||||
.withDefaultAction(actionBuilder
|
||||
.newAction(ActionDefinition.EXAM_VIEW_FROM_LIST)
|
||||
|
@ -177,13 +186,4 @@ public class ExamList implements TemplateComposer {
|
|||
.apply(String.valueOf(exam.lmsSetupId));
|
||||
}
|
||||
|
||||
private String examTypeName(final Exam exam) {
|
||||
if (exam.type == null) {
|
||||
return Constants.EMPTY_NOTE;
|
||||
}
|
||||
|
||||
return this.resourceService.getI18nSupport()
|
||||
.getText(ResourceService.EXAM_TYPE_PREFIX + exam.type.name());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
@ -51,15 +52,18 @@ public class InstitutionList implements TemplateComposer {
|
|||
private final PageService pageService;
|
||||
private final RestService restService;
|
||||
private final CurrentUser currentUser;
|
||||
private final int pageSize;
|
||||
|
||||
protected InstitutionList(
|
||||
final PageService pageService,
|
||||
final RestService restService,
|
||||
final CurrentUser currentUser) {
|
||||
final CurrentUser currentUser,
|
||||
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.restService = restService;
|
||||
this.currentUser = currentUser;
|
||||
this.pageSize = pageSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -75,7 +79,7 @@ public class InstitutionList implements TemplateComposer {
|
|||
final EntityTable<Institution> table =
|
||||
this.pageService.entityTableBuilder(this.restService.getRestCall(GetInstitutionPage.class))
|
||||
.withEmptyMessage(EMPTY_LIST_TEXT_KEY)
|
||||
.withPaging(3)
|
||||
.withPaging(this.pageSize)
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.INSTITUTION.ATTR_NAME,
|
||||
NAME_TEXT_KEY,
|
||||
|
|
|
@ -20,6 +20,7 @@ import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
|||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
|
@ -66,6 +67,7 @@ public class LmsSetupList implements TemplateComposer {
|
|||
private final TableFilterAttribute nameFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, Entity.FILTER_ATTR_NAME);
|
||||
private final TableFilterAttribute typeFilter;
|
||||
private final TableFilterAttribute activityFilter;
|
||||
|
||||
private final PageService pageService;
|
||||
private final ResourceService resourceService;
|
||||
|
@ -74,11 +76,11 @@ public class LmsSetupList implements TemplateComposer {
|
|||
protected LmsSetupList(
|
||||
final PageService pageService,
|
||||
final ResourceService resourceService,
|
||||
@Value("${sebserver.gui.list.page.size}") final Integer pageSize) {
|
||||
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.resourceService = resourceService;
|
||||
this.pageSize = (pageSize != null) ? pageSize : 20;
|
||||
this.pageSize = pageSize;
|
||||
|
||||
this.institutionFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
|
@ -89,6 +91,11 @@ public class LmsSetupList implements TemplateComposer {
|
|||
CriteriaType.SINGLE_SELECTION,
|
||||
Domain.LMS_SETUP.ATTR_LMS_TYPE,
|
||||
this.resourceService::lmsTypeResources);
|
||||
|
||||
this.activityFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
UserInfo.FILTER_ATTR_ACTIVE,
|
||||
this.resourceService::activityResources);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -135,6 +142,7 @@ public class LmsSetupList implements TemplateComposer {
|
|||
Domain.LMS_SETUP.ATTR_ACTIVE,
|
||||
ACTIVITY_TEXT_KEY,
|
||||
LmsSetup::getActive)
|
||||
.withFilter(this.activityFilter)
|
||||
.sortable())
|
||||
.withDefaultAction(actionBuilder
|
||||
.newAction(ActionDefinition.LMS_SETUP_VIEW_FROM_LIST)
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class MonitoringRunningExam implements TemplateComposer {
|
||||
|
||||
public MonitoringRunningExam() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.QuizData;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.service.ResourceService;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetRunningExamPage;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute;
|
||||
import ch.ethz.seb.sebserver.gui.table.EntityTable;
|
||||
import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class MonitoringRunningExamList implements TemplateComposer {
|
||||
|
||||
private static final LocTextKey PAGE_TITLE_KEY =
|
||||
new LocTextKey("sebserver.monitoring.exam.list.title");
|
||||
private final static LocTextKey EMPTY_SELECTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.monitoring.exam.info.pleaseSelect");
|
||||
private final static LocTextKey COLUMN_TITLE_NAME_KEY =
|
||||
new LocTextKey("sebserver.monitoring.exam.list.column.name");
|
||||
private final static LocTextKey COLUMN_TITLE_TYPE_KEY =
|
||||
new LocTextKey("sebserver.monitoring.exam.list.column.type");
|
||||
private final static LocTextKey EMPTY_LIST_TEXT_KEY =
|
||||
new LocTextKey("sebserver.monitoring.exam.list.empty");
|
||||
|
||||
private final TableFilterAttribute nameFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, QuizData.FILTER_ATTR_NAME);
|
||||
private final TableFilterAttribute typeFilter;
|
||||
|
||||
private final PageService pageService;
|
||||
private final ResourceService resourceService;
|
||||
private final int pageSize;
|
||||
|
||||
protected MonitoringRunningExamList(
|
||||
final PageService pageService,
|
||||
final ResourceService resourceService,
|
||||
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.resourceService = resourceService;
|
||||
this.pageSize = pageSize;
|
||||
|
||||
this.typeFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
Exam.FILTER_ATTR_TYPE,
|
||||
this.resourceService::examTypeResources);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
|
||||
final CurrentUser currentUser = this.resourceService.getCurrentUser();
|
||||
final RestService restService = this.resourceService.getRestService();
|
||||
final I18nSupport i18nSupport = this.resourceService.getI18nSupport();
|
||||
|
||||
// content page layout with title
|
||||
final Composite content = widgetFactory.defaultPageLayout(
|
||||
pageContext.getParent(),
|
||||
PAGE_TITLE_KEY);
|
||||
|
||||
final PageActionBuilder actionBuilder = this.pageService
|
||||
.pageActionBuilder(pageContext.clearEntityKeys());
|
||||
|
||||
// table
|
||||
final EntityTable<Exam> table =
|
||||
this.pageService.entityTableBuilder(restService.getRestCall(GetRunningExamPage.class))
|
||||
.withEmptyMessage(EMPTY_LIST_TEXT_KEY)
|
||||
.withPaging(this.pageSize)
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
QuizData.QUIZ_ATTR_NAME,
|
||||
COLUMN_TITLE_NAME_KEY,
|
||||
Exam::getName)
|
||||
.withFilter(this.nameFilter)
|
||||
.sortable())
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.EXAM.ATTR_TYPE,
|
||||
COLUMN_TITLE_TYPE_KEY,
|
||||
this.resourceService::examTypeName)
|
||||
.withFilter(this.typeFilter)
|
||||
.sortable())
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
QuizData.QUIZ_ATTR_START_TIME,
|
||||
new LocTextKey(
|
||||
"sebserver.monitoring.exam.list.column.startTime",
|
||||
i18nSupport.getUsersTimeZoneTitleSuffix()),
|
||||
Exam::getStartTime)
|
||||
.sortable())
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
QuizData.QUIZ_ATTR_END_TIME,
|
||||
new LocTextKey(
|
||||
"sebserver.monitoring.exam.list.column.endTime",
|
||||
i18nSupport.getUsersTimeZoneTitleSuffix()),
|
||||
Exam::getEndTime)
|
||||
.sortable())
|
||||
.withDefaultAction(actionBuilder
|
||||
.newAction(ActionDefinition.MONITOR_EXAM)
|
||||
.create())
|
||||
.compose(content);
|
||||
|
||||
actionBuilder
|
||||
|
||||
.newAction(ActionDefinition.MONITOR_EXAM)
|
||||
.withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY)
|
||||
.publishIf(() -> currentUser.get().hasRole(UserRole.EXAM_SUPPORTER));
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -94,12 +94,12 @@ public class QuizDiscoveryList implements TemplateComposer {
|
|||
protected QuizDiscoveryList(
|
||||
final PageService pageService,
|
||||
final ResourceService resourceService,
|
||||
@Value("${sebserver.gui.list.page.size}") final Integer pageSize) {
|
||||
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.widgetFactory = pageService.getWidgetFactory();
|
||||
this.resourceService = resourceService;
|
||||
this.pageSize = (pageSize != null) ? pageSize : 20;
|
||||
this.pageSize = pageSize;
|
||||
|
||||
this.lmsFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
|
|
|
@ -22,6 +22,7 @@ import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
|||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SebClientConfig;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
|
@ -72,6 +73,7 @@ public class SebClientConfigList implements TemplateComposer {
|
|||
DateTime.now(DateTimeZone.UTC)
|
||||
.minusYears(1)
|
||||
.toString(Constants.DEFAULT_DATE_TIME_FORMAT));
|
||||
private final TableFilterAttribute activityFilter;
|
||||
|
||||
private final PageService pageService;
|
||||
private final RestService restService;
|
||||
|
@ -83,7 +85,7 @@ public class SebClientConfigList implements TemplateComposer {
|
|||
final PageService pageService,
|
||||
final RestService restService,
|
||||
final CurrentUser currentUser,
|
||||
@Value("${sebserver.gui.list.page.size}") final Integer pageSize) {
|
||||
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.restService = restService;
|
||||
|
@ -95,6 +97,11 @@ public class SebClientConfigList implements TemplateComposer {
|
|||
CriteriaType.SINGLE_SELECTION,
|
||||
Entity.FILTER_ATTR_INSTITUTION,
|
||||
this.resourceService::institutionResource);
|
||||
|
||||
this.activityFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
UserInfo.FILTER_ATTR_ACTIVE,
|
||||
this.resourceService::activityResources);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -139,6 +146,7 @@ public class SebClientConfigList implements TemplateComposer {
|
|||
Domain.SEB_CLIENT_CONFIGURATION.ATTR_ACTIVE,
|
||||
ACTIVE_TEXT_KEY,
|
||||
SebClientConfig::getActive)
|
||||
.withFilter(this.activityFilter)
|
||||
.sortable())
|
||||
.withDefaultAction(pageActionBuilder
|
||||
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_VIEW_FROM_LIST)
|
||||
|
|
|
@ -73,7 +73,7 @@ public class SebExamConfigList implements TemplateComposer {
|
|||
final PageService pageService,
|
||||
final RestService restService,
|
||||
final CurrentUser currentUser,
|
||||
@Value("${sebserver.gui.list.page.size}") final Integer pageSize) {
|
||||
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.restService = restService;
|
||||
|
|
|
@ -73,6 +73,7 @@ public class UserAccountList implements TemplateComposer {
|
|||
private final TableFilterAttribute mailFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, UserInfo.FILTER_ATTR_EMAIL);
|
||||
private final TableFilterAttribute languageFilter;
|
||||
private final TableFilterAttribute activityFilter;
|
||||
|
||||
// dependencies
|
||||
private final PageService pageService;
|
||||
|
@ -82,11 +83,11 @@ public class UserAccountList implements TemplateComposer {
|
|||
protected UserAccountList(
|
||||
final PageService pageService,
|
||||
final ResourceService resourceService,
|
||||
@Value("${sebserver.gui.list.page.size}") final Integer pageSize) {
|
||||
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.resourceService = resourceService;
|
||||
this.pageSize = (pageSize != null) ? pageSize : 20;
|
||||
this.pageSize = pageSize;
|
||||
|
||||
this.institutionFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
|
@ -97,6 +98,11 @@ public class UserAccountList implements TemplateComposer {
|
|||
CriteriaType.SINGLE_SELECTION,
|
||||
UserInfo.FILTER_ATTR_LANGUAGE,
|
||||
this.resourceService::languageResources);
|
||||
|
||||
this.activityFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
UserInfo.FILTER_ATTR_ACTIVE,
|
||||
this.resourceService::activityResources);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -154,12 +160,13 @@ public class UserAccountList implements TemplateComposer {
|
|||
.withFilter(this.languageFilter)
|
||||
.localized()
|
||||
.sortable()
|
||||
.widthProportion(2))
|
||||
.widthProportion(1))
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.USER.ATTR_ACTIVE,
|
||||
ACTIVE_TEXT_KEY,
|
||||
UserInfo::getActive)
|
||||
.sortable()
|
||||
.withFilter(this.activityFilter)
|
||||
.widthProportion(1))
|
||||
.withDefaultAction(actionBuilder
|
||||
.newAction(ActionDefinition.USER_ACCOUNT_VIEW_FROM_LIST)
|
||||
|
|
|
@ -21,6 +21,7 @@ public enum ActionCategory {
|
|||
INDICATOR_LIST(new LocTextKey("sebserver.exam.indicator.list.actions"), 2),
|
||||
SEB_CLIENT_CONFIG_LIST(new LocTextKey("sebserver.clientconfig.list.actions"), 1),
|
||||
SEB_EXAM_CONFIG_LIST(new LocTextKey("sebserver.examconfig.list.actions"), 1),
|
||||
RUNNING_EXAM_LIST(new LocTextKey("sebserver.monitoring.exam.list.actions"), 1),
|
||||
VARIA(new LocTextKey("sebserver.overall.action.category.varia"), 100),
|
||||
;
|
||||
|
||||
|
|
|
@ -388,7 +388,14 @@ public enum ActionDefinition {
|
|||
PageStateDefinition.SEB_EXAM_CONFIG_EDIT,
|
||||
ActionCategory.SEB_EXAM_CONFIG_LIST),
|
||||
|
||||
;
|
||||
RUNNING_EXAM_VIEW_LIST(
|
||||
new LocTextKey("sebserver.monitoring.action.list"),
|
||||
PageStateDefinition.MONITORING_RUNNING_EXAM_LIST),
|
||||
MONITOR_EXAM(
|
||||
new LocTextKey("sebserver.monitoring.exam.action.list.view"),
|
||||
ImageIcon.SHOW,
|
||||
PageStateDefinition.MONITORING_RUNNING_EXAM,
|
||||
ActionCategory.RUNNING_EXAM_LIST);
|
||||
|
||||
public final LocTextKey title;
|
||||
public final ImageIcon icon;
|
||||
|
|
|
@ -202,7 +202,18 @@ public class ActivitiesPane implements TemplateComposer {
|
|||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_LIST)
|
||||
.create());
|
||||
}
|
||||
}
|
||||
|
||||
// Monitoring exams
|
||||
if (this.currentUser.get().hasRole(UserRole.EXAM_SUPPORTER)) {
|
||||
final TreeItem clientConfig = this.widgetFactory.treeItemLocalized(
|
||||
navigation,
|
||||
ActivityDefinition.MONITORING_EXAMS.displayName);
|
||||
injectActivitySelection(
|
||||
clientConfig,
|
||||
actionBuilder
|
||||
.newAction(ActionDefinition.RUNNING_EXAM_VIEW_LIST)
|
||||
.create());
|
||||
}
|
||||
|
||||
// TODO other activities
|
||||
|
|
|
@ -19,7 +19,8 @@ public enum ActivityDefinition implements Activity {
|
|||
EXAM(new LocTextKey("sebserver.exam.action.list")),
|
||||
SEB_CONFIGURATION(new LocTextKey("sebserver.sebconfig.activity.name")),
|
||||
SEB_CLIENT_CONFIG(new LocTextKey("sebserver.clientconfig.action.list")),
|
||||
SEB_EXAM_CONFIG(new LocTextKey("sebserver.examconfig.action.list"));
|
||||
SEB_EXAM_CONFIG(new LocTextKey("sebserver.examconfig.action.list")),
|
||||
MONITORING_EXAMS(new LocTextKey("sebserver.monitoring.action.list"));
|
||||
|
||||
public final LocTextKey displayName;
|
||||
|
||||
|
|
|
@ -16,12 +16,14 @@ import ch.ethz.seb.sebserver.gui.content.InstitutionForm;
|
|||
import ch.ethz.seb.sebserver.gui.content.InstitutionList;
|
||||
import ch.ethz.seb.sebserver.gui.content.LmsSetupForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.LmsSetupList;
|
||||
import ch.ethz.seb.sebserver.gui.content.MonitoringRunningExam;
|
||||
import ch.ethz.seb.sebserver.gui.content.MonitoringRunningExamList;
|
||||
import ch.ethz.seb.sebserver.gui.content.QuizDiscoveryList;
|
||||
import ch.ethz.seb.sebserver.gui.content.SebClientConfigForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.SebClientConfigList;
|
||||
import ch.ethz.seb.sebserver.gui.content.SebExamConfigSettingsForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.SebExamConfigList;
|
||||
import ch.ethz.seb.sebserver.gui.content.SebExamConfigPropForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.SebExamConfigSettingsForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.UserAccountChangePasswordForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.UserAccountForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.UserAccountList;
|
||||
|
@ -62,6 +64,9 @@ public enum PageStateDefinition implements PageState {
|
|||
SEB_EXAM_CONFIG_PROP_EDIT(Type.FORM_EDIT, SebExamConfigPropForm.class, ActivityDefinition.SEB_EXAM_CONFIG),
|
||||
SEB_EXAM_CONFIG_EDIT(Type.FORM_VIEW, SebExamConfigSettingsForm.class, ActivityDefinition.SEB_EXAM_CONFIG),
|
||||
|
||||
MONITORING_RUNNING_EXAM_LIST(Type.LIST_VIEW, MonitoringRunningExamList.class, ActivityDefinition.MONITORING_EXAMS),
|
||||
MONITORING_RUNNING_EXAM(Type.FORM_VIEW, MonitoringRunningExam.class, ActivityDefinition.MONITORING_EXAMS)
|
||||
|
||||
;
|
||||
|
||||
public final Type type;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.gui.service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
@ -25,6 +26,7 @@ import org.springframework.stereotype.Service;
|
|||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityName;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Exam.ExamType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.ExamConfigurationMap;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.IndicatorType;
|
||||
|
@ -93,6 +95,13 @@ public class ResourceService {
|
|||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<Tuple<String>> activityResources() {
|
||||
final List<Tuple<String>> result = new ArrayList<>();
|
||||
result.add(new Tuple<>("true", this.i18nSupport.getText("sebserver.overall.status.active")));
|
||||
result.add(new Tuple<>("false", this.i18nSupport.getText("sebserver.overall.status.inactive")));
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<Tuple<String>> lmsTypeResources() {
|
||||
return Arrays.asList(LmsType.values())
|
||||
.stream()
|
||||
|
@ -119,20 +128,6 @@ public class ResourceService {
|
|||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
// public Function<String, String> getExamConfigurationNameFunction() {
|
||||
// final Map<String, String> idNameMap = getExamConfigurationSelection()
|
||||
// .getOr(Collections.emptyList())
|
||||
// .stream()
|
||||
// .collect(Collectors.toMap(e -> e.modelId, e -> e.name));
|
||||
//
|
||||
// return id -> {
|
||||
// if (!idNameMap.containsKey(id)) {
|
||||
// return Constants.EMPTY_NOTE;
|
||||
// }
|
||||
// return idNameMap.get(id);
|
||||
// };
|
||||
// }
|
||||
|
||||
public List<Tuple<String>> userRoleResources() {
|
||||
return UserRole.publicRolesForUser(this.currentUser.get())
|
||||
.stream()
|
||||
|
@ -229,6 +224,7 @@ public class ResourceService {
|
|||
public List<Tuple<String>> examTypeResources() {
|
||||
return Arrays.asList(ExamType.values())
|
||||
.stream()
|
||||
.filter(type -> type != ExamType.UNDEFINED)
|
||||
.map(type -> new Tuple<>(
|
||||
type.name(),
|
||||
this.i18nSupport.getText(EXAM_TYPE_PREFIX + type.name())))
|
||||
|
@ -313,4 +309,13 @@ public class ResourceService {
|
|||
.call();
|
||||
}
|
||||
|
||||
public String examTypeName(final Exam exam) {
|
||||
if (exam.type == null) {
|
||||
return Constants.EMPTY_NOTE;
|
||||
}
|
||||
|
||||
return this.i18nSupport
|
||||
.getText(ResourceService.EXAM_TYPE_PREFIX + exam.type.name());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session;
|
||||
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Page;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class GetRunningExamPage extends RestCall<Page<Exam>> {
|
||||
|
||||
public GetRunningExamPage() {
|
||||
super(new TypeKey<>(
|
||||
CallType.GET_PAGE,
|
||||
EntityType.EXAM,
|
||||
new TypeReference<Page<Exam>>() {
|
||||
}),
|
||||
HttpMethod.GET,
|
||||
MediaType.APPLICATION_FORM_URLENCODED,
|
||||
API.EXAM_MONITORING_ENDPOINT);
|
||||
}
|
||||
|
||||
}
|
|
@ -92,9 +92,10 @@ public class TableFilter<ROW extends Entity> {
|
|||
.map(FilterComponent::reset)
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
final FilterComponent lastComp = this.components.get(this.components.size() - 1);
|
||||
if (lastComp instanceof TableFilter.NullFilter) {
|
||||
FilterComponent lastComp = this.components.get(this.components.size() - 1);
|
||||
while (lastComp instanceof TableFilter.NullFilter) {
|
||||
this.components.remove(lastComp);
|
||||
lastComp = this.components.get(this.components.size() - 1);
|
||||
}
|
||||
|
||||
addActions();
|
||||
|
|
|
@ -269,6 +269,9 @@ public class PaginationServiceImpl implements PaginationService {
|
|||
configurationNodeTableMap.put(
|
||||
Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION,
|
||||
ConfigurationNodeRecordDynamicSqlSupport.description.name());
|
||||
configurationNodeTableMap.put(
|
||||
Domain.CONFIGURATION_NODE.ATTR_STATUS,
|
||||
ConfigurationNodeRecordDynamicSqlSupport.status.name());
|
||||
this.sortColumnMapping.put(
|
||||
ConfigurationNodeRecordDynamicSqlSupport.configurationNodeRecord.name(),
|
||||
configurationNodeTableMap);
|
||||
|
|
|
@ -10,10 +10,12 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.session;
|
|||
|
||||
import java.io.OutputStream;
|
||||
import java.util.Collection;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnectionData;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
|
||||
|
||||
/** A Service to handle running exam sessions */
|
||||
public interface ExamSessionService {
|
||||
|
@ -33,13 +35,22 @@ public interface ExamSessionService {
|
|||
* @return Result referencing the running Exam or an error if the Exam not exists or is not currently running */
|
||||
Result<Exam> getRunningExam(Long examId);
|
||||
|
||||
/** Gets all all currently running Exams for a particular Institution.
|
||||
/** Gets all currently running Exams for a particular Institution.
|
||||
*
|
||||
* @param institutionId the Institution identifier
|
||||
* @return Result referencing the list of all currently running Exams of the institution or to an error if
|
||||
* happened. */
|
||||
Result<Collection<Exam>> getRunningExamsForInstitution(Long institutionId);
|
||||
|
||||
/** Gets all currently running Exams for a particular FilterMap.
|
||||
*
|
||||
* @param filterMap the FilterMap containing the filter attributes
|
||||
* @param predicate additional filter predicate
|
||||
* @return Result referencing the list of all currently running Exams or to an error if happened. */
|
||||
Result<Collection<Exam>> getFilteredRunningExams(
|
||||
FilterMap filterMap,
|
||||
Predicate<Exam> predicate);
|
||||
|
||||
/** Streams the default SEB Exam Configuration to a ClientConnection with given connectionToken.
|
||||
*
|
||||
* @param connectionToken The connection token that identifiers the ClientConnection
|
||||
|
|
|
@ -13,6 +13,7 @@ import java.io.OutputStream;
|
|||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
@ -30,6 +31,7 @@ import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
|||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ClientConnectionDAO;
|
||||
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.session.ExamSessionService;
|
||||
|
||||
@Lazy
|
||||
|
@ -96,6 +98,18 @@ public class ExamSessionServiceImpl implements ExamSessionService {
|
|||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Collection<Exam>> getFilteredRunningExams(
|
||||
final FilterMap filterMap,
|
||||
final Predicate<Exam> predicate) {
|
||||
|
||||
return this.examDAO.allMatching(filterMap, predicate)
|
||||
.map(col -> col.stream()
|
||||
.map(exam -> this.examSessionCacheService.getRunningExam(exam.id))
|
||||
.filter(exam -> exam != null)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void streamDefaultExamConfig(
|
||||
final String connectionToken,
|
||||
|
|
|
@ -126,6 +126,7 @@ public class APIExceptionHandler extends ResponseEntityExceptionHandler {
|
|||
final Exception ex,
|
||||
final WebRequest request) {
|
||||
|
||||
log.error("Unexpected internal error catched at the API endpoint: ", ex);
|
||||
return APIMessage.ErrorMessage.UNEXPECTED
|
||||
.createErrorResponse(ex.getMessage());
|
||||
}
|
||||
|
|
|
@ -144,7 +144,8 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
|
|||
pageSize,
|
||||
sort,
|
||||
getSQLTableOfEntity().name(),
|
||||
() -> getAll(filterMap)).getOrThrow();
|
||||
() -> getAll(filterMap))
|
||||
.getOrThrow();
|
||||
}
|
||||
|
||||
// ******************
|
||||
|
|
|
@ -120,39 +120,54 @@ public class ExamAdministrationController extends ActivatableEntityController<Ex
|
|||
EntityType.EXAM,
|
||||
institutionId);
|
||||
|
||||
final int pageNum = this.paginationService.getPageNumber(pageNumber);
|
||||
final int pSize = this.paginationService.getPageSize(pageSize);
|
||||
|
||||
final List<Exam> exams = new ArrayList<>(
|
||||
this.examDAO.allMatching(new FilterMap(allRequestParams)).getOrThrow());
|
||||
this.examDAO
|
||||
.allMatching(new FilterMap(allRequestParams))
|
||||
.getOrThrow());
|
||||
|
||||
if (!StringUtils.isBlank(sort)) {
|
||||
final String sortBy = PageSortOrder.decode(sort);
|
||||
if (sortBy.equals(QuizData.QUIZ_ATTR_NAME)) {
|
||||
Collections.sort(exams, (exam1, exam2) -> exam1.name.compareTo(exam2.name));
|
||||
}
|
||||
if (sortBy.equals(QuizData.FILTER_ATTR_START_TIME)) {
|
||||
Collections.sort(exams, (exam1, exam2) -> exam1.startTime.compareTo(exam2.startTime));
|
||||
}
|
||||
}
|
||||
|
||||
if (PageSortOrder.DESCENDING == PageSortOrder.getSortOrder(sort)) {
|
||||
Collections.reverse(exams);
|
||||
}
|
||||
|
||||
final int start = (pageNum - 1) * pSize;
|
||||
int end = start + pageSize;
|
||||
if (exams.size() < end) {
|
||||
end = exams.size();
|
||||
}
|
||||
return new Page<>(
|
||||
exams.size() / pSize,
|
||||
pageNum,
|
||||
return buildSortedExamPage(
|
||||
this.paginationService.getPageNumber(pageNumber),
|
||||
this.paginationService.getPageSize(pageSize),
|
||||
sort,
|
||||
exams.subList(start, end));
|
||||
exams);
|
||||
}
|
||||
}
|
||||
|
||||
public static Page<Exam> buildSortedExamPage(
|
||||
final Integer pageNumber,
|
||||
final Integer pageSize,
|
||||
final String sort,
|
||||
final List<Exam> exams) {
|
||||
|
||||
if (!StringUtils.isBlank(sort)) {
|
||||
final String sortBy = PageSortOrder.decode(sort);
|
||||
if (sortBy.equals(Exam.FILTER_ATTR_NAME)) {
|
||||
Collections.sort(exams, (exam1, exam2) -> exam1.name.compareTo(exam2.name));
|
||||
}
|
||||
if (sortBy.equals(Exam.FILTER_ATTR_TYPE)) {
|
||||
Collections.sort(exams, (exam1, exam2) -> exam1.type.compareTo(exam2.type));
|
||||
}
|
||||
if (sortBy.equals(QuizData.FILTER_ATTR_START_TIME)) {
|
||||
Collections.sort(exams, (exam1, exam2) -> exam1.startTime.compareTo(exam2.startTime));
|
||||
}
|
||||
}
|
||||
|
||||
if (PageSortOrder.DESCENDING == PageSortOrder.getSortOrder(sort)) {
|
||||
Collections.reverse(exams);
|
||||
}
|
||||
|
||||
final int start = (pageNumber - 1) * pageSize;
|
||||
int end = start + pageSize;
|
||||
if (exams.size() < end) {
|
||||
end = exams.size();
|
||||
}
|
||||
return new Page<>(
|
||||
exams.size() / pageSize,
|
||||
pageNumber,
|
||||
sort,
|
||||
exams.subList(start, end));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Exam createNew(final POSTMapper postParams) {
|
||||
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.webservice.weblayer.api;
|
||||
|
||||
public class ExamMonitiroingEndpoint {
|
||||
|
||||
public ExamMonitiroingEndpoint() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.webservice.weblayer.api;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.annotation.InitBinder;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Page;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
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.PermissionDeniedException;
|
||||
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.dao.FilterMap;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamSessionService;
|
||||
|
||||
@WebServiceProfile
|
||||
@RestController
|
||||
@RequestMapping("${sebserver.webservice.api.admin.endpoint}" + API.EXAM_MONITORING_ENDPOINT)
|
||||
public class ExamMonitoringController {
|
||||
|
||||
private final ExamSessionService examSessionService;
|
||||
private final AuthorizationService authorization;
|
||||
private final PaginationService paginationService;
|
||||
|
||||
public ExamMonitoringController(
|
||||
final ExamSessionService examSessionService,
|
||||
final AuthorizationService authorization,
|
||||
final PaginationService paginationService) {
|
||||
|
||||
this.examSessionService = examSessionService;
|
||||
this.authorization = authorization;
|
||||
this.paginationService = paginationService;
|
||||
}
|
||||
|
||||
/** This is called by Spring to initialize the WebDataBinder and is used here to
|
||||
* initialize the default value binding for the institutionId request-parameter
|
||||
* that has the current users insitutionId as default.
|
||||
*
|
||||
* See also UserService.addUsersInstitutionDefaultPropertySupport */
|
||||
@InitBinder
|
||||
public void initBinder(final WebDataBinder binder) throws Exception {
|
||||
this.authorization
|
||||
.getUserService()
|
||||
.addUsersInstitutionDefaultPropertySupport(binder);
|
||||
}
|
||||
|
||||
// ******************
|
||||
// * GET (getAll)
|
||||
// ******************
|
||||
|
||||
/** Get a page of all currently running exams
|
||||
*
|
||||
* GET /{api}/{entity-type-endpoint-name}
|
||||
*
|
||||
* GET /admin-api/v1/monitoring
|
||||
* GET /admin-api/v1/monitoring?page_number=2&page_size=10&sort=-name
|
||||
* GET /admin-api/v1/monitoring?name=seb&active=true
|
||||
*
|
||||
* @param institutionId The institution identifier of the request.
|
||||
* Default is the institution identifier of the institution of the current user
|
||||
* @param pageNumber the number of the page that is requested
|
||||
* @param pageSize the size of the page that is requested
|
||||
* @param sort the sort parameter to sort the list of entities before paging
|
||||
* the sort parameter is the name of the entity-model attribute to sort with a leading '-' sign for
|
||||
* descending sort order
|
||||
* @param allRequestParams a MultiValueMap of all request parameter that is used for filtering
|
||||
* @return Page of domain-model-entities of specified type */
|
||||
@RequestMapping(
|
||||
method = RequestMethod.GET,
|
||||
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
|
||||
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public Page<Exam> getPage(
|
||||
@RequestParam(
|
||||
name = API.PARAM_INSTITUTION_ID,
|
||||
required = true,
|
||||
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_SIZE, required = false) final Integer pageSize,
|
||||
@RequestParam(name = Page.ATTR_SORT, required = false) final String sort,
|
||||
@RequestParam final MultiValueMap<String, String> allRequestParams) {
|
||||
|
||||
// check if user has EXAM_SUPPORTER privilege.
|
||||
final SEBServerUser currentUser = this.authorization
|
||||
.getUserService()
|
||||
.getCurrentUser();
|
||||
|
||||
if (!currentUser.getUserRoles().contains(UserRole.EXAM_SUPPORTER)) {
|
||||
throw new PermissionDeniedException(
|
||||
EntityType.EXAM,
|
||||
PrivilegeType.READ,
|
||||
currentUser.getUserInfo().uuid);
|
||||
}
|
||||
|
||||
final FilterMap filterMap = new FilterMap(allRequestParams);
|
||||
|
||||
// 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
|
||||
if (!this.authorization.hasGrant(PrivilegeType.READ, EntityType.EXAM)) {
|
||||
filterMap.putIfAbsent(API.PARAM_INSTITUTION_ID, String.valueOf(institutionId));
|
||||
}
|
||||
|
||||
final List<Exam> exams = new ArrayList<>(this.examSessionService
|
||||
.getFilteredRunningExams(filterMap, exam -> true)
|
||||
.getOrThrow());
|
||||
|
||||
return ExamAdministrationController.buildSortedExamPage(
|
||||
this.paginationService.getPageNumber(pageNumber),
|
||||
this.paginationService.getPageSize(pageSize),
|
||||
sort,
|
||||
exams);
|
||||
}
|
||||
|
||||
}
|
|
@ -852,11 +852,29 @@ sebserver.examconfig.props.label.enableF10=Enable F10
|
|||
sebserver.examconfig.props.label.enableF11=Enable F11
|
||||
sebserver.examconfig.props.label.enableF12=Enable F12
|
||||
|
||||
|
||||
|
||||
sebserver.examconfig.props.validation.password.confirm=Please enter correct confirm password
|
||||
sebserver.examconfig.props.validation.unexpected=Unexpected error happened. Value was not set correctly
|
||||
sebserver.examconfig.props.validation.IntegerTypeValidator=Invalid number
|
||||
sebserver.examconfig.props.validation.DecimalTypeValidator=Invalid decimal number
|
||||
sebserver.examconfig.props.validation.ExitKeySequenceValidator=Key is already in sequence
|
||||
sebserver.examconfig.props.validation.WindowsSizeValidator=Invalid number
|
||||
|
||||
|
||||
################################
|
||||
# Monitoring
|
||||
################################
|
||||
|
||||
sebserver.monitoring.action.list=Monitoring
|
||||
sebserver.monitoring.exam.list.title=Running Exams
|
||||
|
||||
sebserver.monitoring.exam.list.actions=Selected Exam
|
||||
sebserver.monitoring.exam.action.list.view=Monitoring
|
||||
|
||||
|
||||
sebserver.monitoring.exam.info.pleaseSelect=Please select an exam first
|
||||
sebserver.monitoring.exam.list.empty=There are currently no running exams
|
||||
sebserver.monitoring.exam.list.column.name=Name
|
||||
sebserver.monitoring.exam.list.column.type=Type
|
||||
sebserver.monitoring.exam.list.column.startTime=Start Time
|
||||
sebserver.monitoring.exam.list.column.endTime=End Time
|
||||
|
||||
|
|
|
@ -281,11 +281,11 @@ Combo-Button {
|
|||
background-color: #ffffff;
|
||||
background-image: gradient(linear, left top, left bottom, from(#ffffff), to(#ffffff));
|
||||
border: none;
|
||||
width: 30px;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
Combo-Field {
|
||||
padding: 3px 10px 1px 10px;
|
||||
padding: 3px 0px 1px 10px;
|
||||
}
|
||||
|
||||
Combo.error {
|
||||
|
|
Loading…
Add table
Reference in a new issue