diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/ConfigTemplateForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/ConfigTemplateForm.java index cfcda419..41ffe42c 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/ConfigTemplateForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/ConfigTemplateForm.java @@ -252,7 +252,7 @@ public class ConfigTemplateForm implements TemplateComposer { attrTable::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY) - .publishIf(() -> attrTable.hasAnyContent() && modifyGrant, false) + .publishIf(() -> modifyGrant, false) .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_SET_DEFAULT) .withParentEntityKey(entityKey) @@ -261,7 +261,7 @@ public class ConfigTemplateForm implements TemplateComposer { action -> this.resetToDefaults(action, attrTable), EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY) .noEventPropagation() - .publishIf(() -> attrTable.hasAnyContent() && modifyGrant, false) + .publishIf(() -> modifyGrant, false) .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_LIST_REMOVE_VIEW) .withParentEntityKey(entityKey) @@ -270,7 +270,7 @@ public class ConfigTemplateForm implements TemplateComposer { action -> this.removeFormView(action, attrTable), EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY) .noEventPropagation() - .publishIf(() -> attrTable.hasAnyContent() && modifyGrant, false) + .publishIf(() -> modifyGrant, false) .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_LIST_ATTACH_DEFAULT_VIEW) .withParentEntityKey(entityKey) @@ -279,7 +279,7 @@ public class ConfigTemplateForm implements TemplateComposer { action -> this.attachView(action, attrTable), EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY) .noEventPropagation() - .publishIf(() -> attrTable.hasAnyContent() && modifyGrant, false); + .publishIf(() -> modifyGrant, false); } pageActionBuilder diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/ConfigTemplateList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/ConfigTemplateList.java index 53884ebb..5576b2c8 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/ConfigTemplateList.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/ConfigTemplateList.java @@ -146,12 +146,12 @@ public class ConfigTemplateList implements TemplateComposer { .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_VIEW_FROM_LIST) .withSelect(templateTable::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_TEMPLATE_SELECTION_TEXT_KEY) - .publishIf(templateTable::hasAnyContent, false) + .publish(false) .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_MODIFY_FROM_LIST) .withSelect( templateTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION), PageAction::applySingleSelectionAsEntityKey, EMPTY_TEMPLATE_SELECTION_TEXT_KEY) - .publishIf(() -> examConfigGrant.im() && templateTable.hasAnyContent(), false); + .publishIf(() -> examConfigGrant.im(), false); } } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamList.java index 03194813..e7be7a46 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamList.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamList.java @@ -208,14 +208,14 @@ public class ExamList implements TemplateComposer { actionBuilder .newAction(ActionDefinition.EXAM_VIEW_FROM_LIST) .withSelect(table::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) - .publishIf(table::hasAnyContent, false) + .publish(false) .newAction(ActionDefinition.EXAM_MODIFY_FROM_LIST) .withSelect( table.getGrantedSelection(currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION), action -> modifyExam(action, table), EMPTY_SELECTION_TEXT_KEY) - .publishIf(() -> userGrant.im() && table.hasAnyContent(), false); + .publishIf(() -> userGrant.im(), false); } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/InstitutionList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/InstitutionList.java index 9b05b633..bf763abd 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/InstitutionList.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/InstitutionList.java @@ -140,19 +140,19 @@ public class InstitutionList implements TemplateComposer { table::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) - .publishIf(table::hasAnyContent, false) + .publish(false) .newAction(ActionDefinition.INSTITUTION_MODIFY_FROM_LIST) .withSelect( table::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) - .publishIf(() -> instGrant.m() && table.hasAnyContent(), false) + .publishIf(() -> instGrant.m(), false) .newAction(ActionDefinition.INSTITUTION_TOGGLE_ACTIVITY) .withExec(this.pageService.activationToggleActionFunction(table, EMPTY_SELECTION_TEXT_KEY)) .withConfirm(this.pageService.confirmDeactivation(table)) - .publishIf(() -> instGrant.m() && table.hasAnyContent(), false); + .publishIf(() -> instGrant.m(), false); } } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupList.java index 0639f01c..82ee213f 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupList.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/LmsSetupList.java @@ -168,13 +168,13 @@ public class LmsSetupList implements TemplateComposer { .newAction(ActionDefinition.LMS_SETUP_VIEW_FROM_LIST) .withSelect(table::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) - .publishIf(table::hasAnyContent, false) + .publish(false) .newAction(ActionDefinition.LMS_SETUP_MODIFY_FROM_LIST) .withSelect( table.getGrantedSelection(currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION), PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) - .publishIf(() -> userGrant.im() && table.hasAnyContent(), false) + .publishIf(() -> userGrant.im(), false) .newAction(ActionDefinition.LMS_SETUP_TOGGLE_ACTIVITY) .withSelect( @@ -185,7 +185,7 @@ public class LmsSetupList implements TemplateComposer { action -> LmsSetupForm.testLmsSetup(action, null, restService)), EMPTY_SELECTION_TEXT_KEY) .withConfirm(this.pageService.confirmDeactivation(table)) - .publishIf(() -> userGrant.iw() && table.hasAnyContent(), false); + .publishIf(() -> userGrant.iw(), false); } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/QuizLookupList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/QuizLookupList.java index 2cce042e..b17ebf58 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/QuizLookupList.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/QuizLookupList.java @@ -234,7 +234,7 @@ public class QuizLookupList implements TemplateComposer { institutionNameFunction), EMPTY_SELECTION_TEXT) .noEventPropagation() - .publishIf(table::hasAnyContent, false) + .publish(false) .newAction(ActionDefinition.QUIZ_DISCOVERY_EXAM_IMPORT) .withConfirm(importQuizConfirm(table, restService)) @@ -242,7 +242,7 @@ public class QuizLookupList implements TemplateComposer { table.getGrantedSelection(currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION), action -> this.importQuizData(action, table), EMPTY_SELECTION_TEXT) - .publishIf(() -> examGrant.im() && table.hasAnyContent(), false); + .publishIf(() -> examGrant.im(), false); } private static Function quizDataLmsSetupNameFunction(final ResourceService resourceService) { diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBClientConfigList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBClientConfigList.java index a59b4b33..35d0b0d9 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBClientConfigList.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBClientConfigList.java @@ -170,13 +170,13 @@ public class SEBClientConfigList implements TemplateComposer { .newAction(ActionDefinition.SEB_CLIENT_CONFIG_VIEW_FROM_LIST) .withSelect(table::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) - .publishIf(table::hasAnyContent, false) + .publish(false) .newAction(ActionDefinition.SEB_CLIENT_CONFIG_MODIFY_FROM_LIST) .withSelect( table.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION), PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) - .publishIf(() -> clientConfigGrant.im() && table.hasAnyContent(), false) + .publishIf(() -> clientConfigGrant.im(), false) .newAction(ActionDefinition.SEB_CLIENT_CONFIG_TOGGLE_ACTIVITY) .withSelect( @@ -184,7 +184,7 @@ public class SEBClientConfigList implements TemplateComposer { this.pageService.activationToggleActionFunction(table, EMPTY_SELECTION_TEXT_KEY), EMPTY_SELECTION_TEXT_KEY) .withConfirm(this.pageService.confirmDeactivation(table)) - .publishIf(() -> clientConfigGrant.im() && table.hasAnyContent(), false); + .publishIf(() -> clientConfigGrant.im(), false); } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBClientLogs.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBClientLogs.java new file mode 100644 index 00000000..95bbbcf1 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBClientLogs.java @@ -0,0 +1,205 @@ +/* + * 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 java.util.Map; +import java.util.function.Function; + +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.Constants; +import ch.ethz.seb.sebserver.gbl.model.Domain; +import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection; +import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent; +import ch.ethz.seb.sebserver.gbl.model.session.ExtendedClientEvent; +import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; +import ch.ethz.seb.sebserver.gbl.util.Utils; +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.remote.webservice.api.RestService; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs.GetExtendedClientEventPage; +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 SEBClientLogs implements TemplateComposer { + + private static final LocTextKey TITLE_TEXT_KEY = + new LocTextKey("sebserver.seblogs.list.title"); + private static final LocTextKey EMPTY_TEXT_KEY = + new LocTextKey("sebserver.seblogs.list.empty"); + + private static final LocTextKey EXAM_TEXT_KEY = + new LocTextKey("sebserver.seblogs.list.column.exam"); + private static final LocTextKey CLIENT_SESSION_TEXT_KEY = + new LocTextKey("sebserver.seblogs.list.column.client-session"); + private static final LocTextKey TYPE_TEXT_KEY = + new LocTextKey("sebserver.seblogs.list.column.type"); + private static final LocTextKey TIME_TEXT_KEY = + new LocTextKey("sebserver.seblogs.list.column.time"); + private static final LocTextKey VALUE_TEXT_KEY = + new LocTextKey("sebserver.seblogs.list.column.value"); + private final static LocTextKey EMPTY_SELECTION_TEXT = + new LocTextKey("sebserver.seblogs.info.pleaseSelect"); + + private final TableFilterAttribute examFilter; + private final TableFilterAttribute clientSessionFilter; + private final TableFilterAttribute eventTypeFilter; + + private final PageService pageService; + private final ResourceService resourceService; + private final RestService restService; + private final I18nSupport i18nSupport; + private final SEBClientLogDetailsPopup sebClientLogDetailsPopup; + private final int pageSize; + + public SEBClientLogs( + final PageService pageService, + final SEBClientLogDetailsPopup sebClientLogDetailsPopup, + @Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) { + + this.pageService = pageService; + this.resourceService = pageService.getResourceService(); + this.restService = this.resourceService.getRestService(); + this.i18nSupport = this.resourceService.getI18nSupport(); + this.sebClientLogDetailsPopup = sebClientLogDetailsPopup; + this.pageSize = pageSize; + + this.examFilter = new TableFilterAttribute( + CriteriaType.SINGLE_SELECTION, + ExtendedClientEvent.FILTER_ATTRIBUTE_EXAM, + this.resourceService::getExamLogSelectionResources); + + this.clientSessionFilter = new TableFilterAttribute( + CriteriaType.TEXT, + ClientConnection.FILTER_ATTR_SESSION_ID); + + this.eventTypeFilter = new TableFilterAttribute( + CriteriaType.SINGLE_SELECTION, + ClientEvent.FILTER_ATTR_TYPE, + this.resourceService::clientEventTypeResources); + } + + @Override + public void compose(final PageContext pageContext) { + final WidgetFactory widgetFactory = this.pageService.getWidgetFactory(); + // content page layout with title + final Composite content = widgetFactory.defaultPageLayout( + pageContext.getParent(), + TITLE_TEXT_KEY); + + final PageActionBuilder actionBuilder = this.pageService.pageActionBuilder( + pageContext + .clearEntityKeys() + .clearAttributes()); + + // table + final EntityTable table = this.pageService.entityTableBuilder( + this.restService.getRestCall(GetExtendedClientEventPage.class)) + .withEmptyMessage(EMPTY_TEXT_KEY) + .withPaging(this.pageSize) + + .withColumn(new ColumnDefinition<>( + Domain.CLIENT_CONNECTION.ATTR_EXAM_ID, + EXAM_TEXT_KEY, + examNameFunction()) + .withFilter(this.examFilter) + .widthProportion(2)) + + .withColumn(new ColumnDefinition<>( + Domain.CLIENT_CONNECTION.ATTR_EXAM_USER_SESSION_ID, + CLIENT_SESSION_TEXT_KEY, + ExtendedClientEvent::getUserSessionId) + .withFilter(this.clientSessionFilter) + .sortable() + .widthProportion(2)) + + .withColumn(new ColumnDefinition( + Domain.CLIENT_EVENT.ATTR_TYPE, + TYPE_TEXT_KEY, + this.resourceService::getEventTypeName) + .withFilter(this.eventTypeFilter) + .sortable() + .widthProportion(1)) + + .withColumn(new ColumnDefinition<>( + Domain.CLIENT_EVENT.ATTR_SERVER_TIME, + new LocTextKey( + TIME_TEXT_KEY.name, + this.i18nSupport.getUsersTimeZoneTitleSuffix()), + this::getEventTime) + .withFilter(new TableFilterAttribute( + CriteriaType.DATE_TIME_RANGE, + ClientEvent.FILTER_ATTR_SERVER_TIME_FROM_TO, + Utils.toDateTimeUTC(Utils.getMillisecondsNow()) + .minusYears(1) + .toString())) + .sortable() + .widthProportion(2)) + + .withColumn(new ColumnDefinition( + Domain.CLIENT_EVENT.ATTR_NUMERIC_VALUE, + VALUE_TEXT_KEY, + clientEvent -> (clientEvent.numValue != null) + ? String.valueOf(clientEvent.numValue) + : Constants.EMPTY_NOTE) + .widthProportion(1)) + + .withDefaultAction(t -> actionBuilder + .newAction(ActionDefinition.LOGS_SEB_CLIENT_SHOW_DETAILS) + .withExec(action -> this.sebClientLogDetailsPopup.showDetails(action, + t.getSingleSelectedROWData())) + .noEventPropagation() + .create()) + + .withSelectionListener(this.pageService.getSelectionPublisher( + pageContext, + ActionDefinition.LOGS_SEB_CLIENT_SHOW_DETAILS)) + + .compose(pageContext.copyOf(content)); + + actionBuilder + .newAction(ActionDefinition.LOGS_SEB_CLIENT_SHOW_DETAILS) + .withSelect( + table::getSelection, + action -> this.sebClientLogDetailsPopup.showDetails(action, table.getSingleSelectedROWData()), + EMPTY_SELECTION_TEXT) + .noEventPropagation() + .publish(false); + } + + private Function examNameFunction() { + final Map examNameMapping = this.resourceService.getExamNameMapping(); + return event -> examNameMapping.get(event.examId); + } + + private String getEventTime(final ExtendedClientEvent event) { + if (event == null || event.serverTime == null) { + return Constants.EMPTY_NOTE; + } + + return this.i18nSupport + .formatDisplayDateTime(Utils.toDateTimeUTC(event.serverTime)); + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBExamConfigForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBExamConfigForm.java index f442d7cc..7f42784e 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBExamConfigForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBExamConfigForm.java @@ -339,7 +339,7 @@ public class SEBExamConfigForm implements TemplateComposer { return pageAction.withEntityKey( new EntityKey(selectedExamMapping.examId, EntityType.EXAM)); }) - .publishIf(table::hasAnyContent, false); + .publish(false); } } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBExamConfigList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBExamConfigList.java index a9df221e..d5eef79b 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBExamConfigList.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBExamConfigList.java @@ -159,13 +159,13 @@ public class SEBExamConfigList implements TemplateComposer { .newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_PROP_FROM_LIST) .withSelect(configTable::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) - .publishIf(configTable::hasAnyContent, false) + .publish(false) .newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY_PROP_FROM_LIST) .withSelect( configTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION), PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) - .publishIf(() -> examConfigGrant.im() && configTable.hasAnyContent(), false) + .publishIf(() -> examConfigGrant.im(), false) .newAction(ActionDefinition.SEB_EXAM_CONFIG_IMPORT_TO_NEW_CONFIG) .withSelect( diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountList.java index 2d6690b7..9766af20 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountList.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/UserAccountList.java @@ -222,16 +222,16 @@ public class UserAccountList implements TemplateComposer { .newAction(ActionDefinition.USER_ACCOUNT_VIEW_FROM_LIST) .withSelect(table::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) - .publishIf(table::hasAnyContent, false) + .publish(false) .newAction(ActionDefinition.USER_ACCOUNT_MODIFY_FROM_LIST) .withSelect(table::getSelection, this::editAction, EMPTY_SELECTION_TEXT_KEY) - .publishIf(() -> userGrant.im() && table.hasAnyContent(), false) + .publishIf(() -> userGrant.im(), false) .newAction(ActionDefinition.USER_ACCOUNT_TOGGLE_ACTIVITY) .withExec(this.pageService.activationToggleActionFunction(table, EMPTY_SELECTION_TEXT_KEY)) .withConfirm(this.pageService.confirmDeactivation(table)) - .publishIf(() -> userGrant.m() && table.hasAnyContent(), false); + .publishIf(() -> userGrant.m(), false); } private PageAction editAction(final PageAction pageAction) {