From 9f752bf145e9ddcc00afca2d14ee9dde597f6b88 Mon Sep 17 00:00:00 2001 From: anhefti Date: Tue, 10 Dec 2019 13:33:15 +0100 Subject: [PATCH] added SEBSever logo added Institution show case added table attribute to user session --- .../ethz/seb/sebserver/gbl/model/Entity.java | 1 + .../gui/content/ConfigTemplateForm.java | 6 +- .../seb/sebserver/gui/content/ExamForm.java | 2 +- .../seb/sebserver/gui/content/ExamList.java | 2 +- .../gui/content/InstitutionList.java | 47 ++++-- .../sebserver/gui/content/LmsSetupList.java | 4 +- .../content/MonitoringRunningExamList.java | 2 +- .../gui/content/SebClientConfigList.java | 4 +- .../gui/content/SebExamConfigList.java | 10 +- .../gui/content/SebExamConfigPropForm.java | 2 +- .../gui/content/UserAccountList.java | 4 +- .../gui/content/action/ActionDefinition.java | 8 +- .../gui/service/ResourceService.java | 5 +- .../gui/service/page/PageService.java | 20 ++- .../gui/service/page/impl/PageAction.java | 6 +- .../service/page/impl/PageServiceImpl.java | 25 +-- .../remote/webservice/auth/CurrentUser.java | 27 ++++ .../seb/sebserver/gui/table/EntityTable.java | 144 +++++++++++++++++- .../seb/sebserver/gui/table/TableBuilder.java | 4 + .../seb/sebserver/gui/table/TableFilter.java | 104 ++++++++++++- .../dao/impl/InstitutionDAOImpl.java | 3 + .../config/application-dev-gui.properties | 2 +- src/main/resources/messages.properties | 2 +- 23 files changed, 386 insertions(+), 48 deletions(-) diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/Entity.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/Entity.java index d701fbd9..d6657132 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/Entity.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/Entity.java @@ -19,6 +19,7 @@ public interface Entity extends ModelIdAware { public static final String FILTER_ATTR_INSTITUTION = API.PARAM_INSTITUTION_ID; public static final String FILTER_ATTR_ACTIVE = "active"; public static final String FILTER_ATTR_NAME = "name"; + public static final String FILTER_ATTR_URL_SUFFIX = "urlsuffix"; /** Get the type of the entity. * 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 f8532e02..2c53a5bd 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 @@ -185,7 +185,9 @@ public class ConfigTemplateForm implements TemplateComposer { () -> this.resourceService.getAttributeTypeResources()); final EntityTable attrTable = - this.pageService.entityTableBuilder(this.restService.getRestCall(GetTemplateAttributePage.class)) + this.pageService.entityTableBuilder( + Domain.CONFIGURATION_NODE.TYPE_NAME + "_Template", + this.restService.getRestCall(GetTemplateAttributePage.class)) .withRestCallAdapter(restCall -> restCall.withURIVariable( API.PARAM_PARENT_MODEL_ID, entityKey.modelId)) @@ -226,7 +228,7 @@ public class ConfigTemplateForm implements TemplateComposer { .withParentEntityKey(entityKey) .withSelect( attrTable::getSelection, - PageAction::applySingleSelection, + PageAction::applySingleSelectionAsEntityKey, EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY) .publishIf(() -> attrTable.hasAnyContent()) diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamForm.java index 5c1cbfc4..11e4ee74 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/ExamForm.java @@ -519,7 +519,7 @@ public class ExamForm implements TemplateComposer { .withParentEntityKey(entityKey) .withSelect( indicatorTable::getSelection, - PageAction::applySingleSelection, + PageAction::applySingleSelectionAsEntityKey, INDICATOR_EMPTY_SELECTION_TEXT_KEY) .publishIf(() -> modifyGrant && indicatorTable.hasAnyContent() && editable) 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 3d310ffa..d0d75389 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 @@ -207,7 +207,7 @@ public class ExamList implements TemplateComposer { .publishIf(userGrant::im) .newAction(ActionDefinition.EXAM_VIEW_FROM_LIST) - .withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY) + .withSelect(table::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) .publishIf(table::hasAnyContent) .newAction(ActionDefinition.EXAM_MODIFY_FROM_LIST) 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 7ef51caa..0be6d66b 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 @@ -13,8 +13,10 @@ 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.Entity; import ch.ethz.seb.sebserver.gbl.model.institution.Institution; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; @@ -29,7 +31,9 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetIn import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck; 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; @Lazy @Component @@ -49,6 +53,12 @@ public class InstitutionList implements TemplateComposer { private static final LocTextKey EMPTY_SELECTION_TEXT_KEY = new LocTextKey("sebserver.institution.info.pleaseSelect"); + private final TableFilterAttribute nameFilter = + new TableFilterAttribute(CriteriaType.TEXT, Entity.FILTER_ATTR_NAME); + private final TableFilterAttribute urlSuffixFilter = + new TableFilterAttribute(CriteriaType.TEXT, Institution.FILTER_ATTR_URL_SUFFIX); + private final TableFilterAttribute activityFilter; + private final PageService pageService; private final RestService restService; private final CurrentUser currentUser; @@ -64,6 +74,12 @@ public class InstitutionList implements TemplateComposer { this.restService = restService; this.currentUser = currentUser; this.pageSize = pageSize; + + this.activityFilter = new TableFilterAttribute( + CriteriaType.SINGLE_SELECTION, + Institution.FILTER_ATTR_ACTIVE, + Constants.TRUE_STRING, + this.pageService.getResourceService()::activityResources); } @Override @@ -84,19 +100,22 @@ public class InstitutionList implements TemplateComposer { Domain.INSTITUTION.ATTR_NAME, NAME_TEXT_KEY, Institution::getName) - .sortable()) + .sortable() + .withFilter(this.nameFilter)) .withColumn(new ColumnDefinition<>( Domain.INSTITUTION.ATTR_URL_SUFFIX, URL_TEXT_KEY, Institution::getUrlSuffix) - .sortable()) + .sortable() + .withFilter(this.urlSuffixFilter)) .withColumn(new ColumnDefinition( Domain.INSTITUTION.ATTR_ACTIVE, ACTIVE_TEXT_KEY, entity -> this.pageService .getResourceService() .localizedActivityResource().apply(entity.active)) - .sortable()) + .sortable() + .withFilter(this.activityFilter)) .withDefaultAction(pageActionBuilder .newAction(ActionDefinition.INSTITUTION_VIEW_FROM_LIST) .create()) @@ -111,21 +130,31 @@ public class InstitutionList implements TemplateComposer { .newAction(ActionDefinition.INSTITUTION_NEW) .publishIf(instGrant::w) - .newAction(ActionDefinition.USER_ACCOUNT_NEW) - .publishIf(userGrant::w) - .newAction(ActionDefinition.INSTITUTION_VIEW_FROM_LIST) - .withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY) + .withSelect( + table::getSelection, + PageAction::applySingleSelectionAsEntityKey, + EMPTY_SELECTION_TEXT_KEY) .publishIf(() -> table.hasAnyContent()) .newAction(ActionDefinition.INSTITUTION_MODIFY_FROM_LIST) - .withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY) + .withSelect( + table::getSelection, + PageAction::applySingleSelectionAsEntityKey, + EMPTY_SELECTION_TEXT_KEY) .publishIf(() -> instGrant.m() && table.hasAnyContent()) .newAction(ActionDefinition.INSTITUTION_TOGGLE_ACTIVITY) .withExec(this.pageService.activationToggleActionFunction(table, EMPTY_SELECTION_TEXT_KEY)) .withConfirm(this.pageService.confirmDeactivation(table)) - .publishIf(() -> instGrant.m() && table.hasAnyContent()); + .publishIf(() -> instGrant.m() && table.hasAnyContent()) + + .newAction(ActionDefinition.INSTITUTION_USER_ACCOUNT_NEW) + .withSelect( + table::getSelection, + PageAction::applySingleSelectionAsParentEntityKey, + EMPTY_SELECTION_TEXT_KEY) + .publishIf(() -> table.hasAnyContent() && userGrant.w()); } } 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 26de7f8a..f28136a1 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 @@ -157,13 +157,13 @@ public class LmsSetupList implements TemplateComposer { .publishIf(userGrant::iw) .newAction(ActionDefinition.LMS_SETUP_VIEW_FROM_LIST) - .withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY) + .withSelect(table::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) .publishIf(() -> table.hasAnyContent()) .newAction(ActionDefinition.LMS_SETUP_MODIFY_FROM_LIST) .withSelect( table.getGrantedSelection(currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION), - PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY) + PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) .publishIf(() -> userGrant.im() && table.hasAnyContent()); } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringRunningExamList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringRunningExamList.java index f0a08104..bf01aebc 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringRunningExamList.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/MonitoringRunningExamList.java @@ -136,7 +136,7 @@ public class MonitoringRunningExamList implements TemplateComposer { actionBuilder .newAction(ActionDefinition.MONITOR_EXAM_FROM_LIST) - .withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY) + .withSelect(table::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) .publishIf(() -> currentUser.get().hasRole(UserRole.EXAM_SUPPORTER)); } 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 4f9ac88b..e405254d 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 @@ -161,13 +161,13 @@ public class SebClientConfigList implements TemplateComposer { .publishIf(clientConfigGrant::iw) .newAction(ActionDefinition.SEB_CLIENT_CONFIG_VIEW_FROM_LIST) - .withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY) + .withSelect(table::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) .publishIf(() -> table.hasAnyContent()) .newAction(ActionDefinition.SEB_CLIENT_CONFIG_MODIFY_FROM_LIST) .withSelect( table.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION), - PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY) + PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) .publishIf(() -> clientConfigGrant.im() && table.hasAnyContent()); } 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 05923eec..233be02f 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 @@ -192,19 +192,19 @@ public class SebExamConfigList implements TemplateComposer { .publishIf(examConfigGrant::iw) .newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_PROP_FROM_LIST) - .withSelect(configTable::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY) + .withSelect(configTable::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) .publishIf(() -> configTable.hasAnyContent()) .newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY_PROP_FROM_LIST) .withSelect( configTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION), - PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY) + PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) .publishIf(() -> examConfigGrant.im() && configTable.hasAnyContent()) .newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY_FROM_LIST) .withSelect( configTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION), - PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY) + PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) .publishIf(() -> examConfigGrant.im() && configTable.hasAnyContent()) .newAction(ActionDefinition.SEB_EXAM_CONFIG_IMPORT_TO_NEW_CONFIG) @@ -217,14 +217,14 @@ public class SebExamConfigList implements TemplateComposer { .publishIf(examConfigGrant::iw) .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_VIEW_FROM_LIST) - .withSelect(templateTable::getSelection, PageAction::applySingleSelection, + .withSelect(templateTable::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_TEMPLATE_SELECTION_TEXT_KEY) .publishIf(() -> templateTable.hasAnyContent()) .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_MODIFY_FROM_LIST) .withSelect( templateTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION), - PageAction::applySingleSelection, EMPTY_TEMPLATE_SELECTION_TEXT_KEY) + PageAction::applySingleSelectionAsEntityKey, EMPTY_TEMPLATE_SELECTION_TEXT_KEY) .publishIf(() -> examConfigGrant.im() && templateTable.hasAnyContent()); } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigPropForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigPropForm.java index b11ec765..0eb208fd 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigPropForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/SebExamConfigPropForm.java @@ -342,7 +342,7 @@ public class SebExamConfigPropForm implements TemplateComposer { final ExamConfigurationMap selectedROWData = getSelectedExamMapping(table); return new HashSet<>(Arrays.asList(new EntityKey(selectedROWData.examId, EntityType.EXAM))); }) - .withExec(PageAction::applySingleSelection) + .withExec(PageAction::applySingleSelectionAsEntityKey) .create(); } 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 05b80acd..fd4b1260 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 @@ -195,7 +195,7 @@ public class UserAccountList implements TemplateComposer { .publishIf(userGrant::iw) .newAction(ActionDefinition.USER_ACCOUNT_VIEW_FROM_LIST) - .withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY) + .withSelect(table::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) .publishIf(() -> table.hasAnyContent()) .newAction(ActionDefinition.USER_ACCOUNT_MODIFY_FROM_LIST) @@ -214,7 +214,7 @@ public class UserAccountList implements TemplateComposer { throw new PageMessageException(NO_EDIT_RIGHT_MESSAGE); } - return PageAction.applySingleSelection(pageAction); + return PageAction.applySingleSelectionAsEntityKey(pageAction); } private String getLocaleDisplayText(final UserInfo userInfo) { diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java index 6a71b08f..2e985700 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java @@ -25,7 +25,8 @@ public enum ActionDefinition { INSTITUTION_NEW( new LocTextKey("sebserver.institution.action.new"), ImageIcon.INSTITUTION, - PageStateDefinitionImpl.INSTITUTION_EDIT), + PageStateDefinitionImpl.INSTITUTION_EDIT, + ActionCategory.FORM), INSTITUTION_VIEW_FROM_LIST( new LocTextKey("sebserver.institution.action.list.view"), ImageIcon.SHOW, @@ -71,6 +72,11 @@ public enum ActionDefinition { ImageIcon.TOGGLE_ON, PageStateDefinitionImpl.INSTITUTION_VIEW, ActionCategory.FORM), + INSTITUTION_USER_ACCOUNT_NEW( + new LocTextKey("sebserver.useraccount.action.new"), + ImageIcon.USER, + PageStateDefinitionImpl.USER_ACCOUNT_EDIT, + ActionCategory.INSTITUTION_LIST), USER_ACCOUNT_VIEW_LIST( new LocTextKey("sebserver.useraccount.action.list"), diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/ResourceService.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/ResourceService.java index f73ed5ad..7d3b80c8 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/ResourceService.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/ResourceService.java @@ -147,8 +147,9 @@ public class ResourceService { public List> activityResources() { final List> 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"))); + result.add(new Tuple<>(Constants.TRUE_STRING, this.i18nSupport.getText("sebserver.overall.status.active"))); + result.add(new Tuple<>(Constants.FALSE_STRING, this.i18nSupport.getText("sebserver.overall.status.inactive"))); + result.add(new Tuple<>(StringUtils.EMPTY, StringUtils.EMPTY)); return result; } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageService.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageService.java index 40dd68d7..903576df 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageService.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageService.java @@ -47,6 +47,7 @@ import ch.ethz.seb.sebserver.gui.service.page.impl.PageState; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; import ch.ethz.seb.sebserver.gui.table.EntityTable; import ch.ethz.seb.sebserver.gui.table.TableBuilder; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; @@ -92,6 +93,11 @@ public interface PageService { * @return the RestService bean */ RestService getRestService(); + /** Use this to get the CurrentUser facade + * + * @return the CurrentUser facade */ + CurrentUser getCurrentUser(); + /** Get the PageState of the current user. * * @return PageState of the current user. */ @@ -187,7 +193,19 @@ public interface PageService { * @param apiCall the SEB Server API RestCall that feeds the table with data * @param the type of the Entity of the table * @return TableBuilder of specified type */ - TableBuilder entityTableBuilder(RestCall> apiCall); + default TableBuilder entityTableBuilder(final RestCall> apiCall) { + return entityTableBuilder(apiCall.getEntityType().name(), apiCall); + } + + /** Get an new TableBuilder for specified page based RestCall. + * + * @param The name of the table to build + * @param apiCall the SEB Server API RestCall that feeds the table with data + * @param the type of the Entity of the table + * @return TableBuilder of specified type */ + TableBuilder entityTableBuilder( + String name, + RestCall> apiCall); /** Get a new PageActionBuilder for a given PageContext. * diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageAction.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageAction.java index a6fccfdb..bad5b8d9 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageAction.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageAction.java @@ -231,10 +231,14 @@ public final class PageAction { return builder.toString(); } - public static PageAction applySingleSelection(final PageAction action) { + public static PageAction applySingleSelectionAsEntityKey(final PageAction action) { return action.withEntityKey(action.getSingleSelection()); } + public static PageAction applySingleSelectionAsParentEntityKey(final PageAction action) { + return action.withParentEntityKey(action.getSingleSelection()); + } + public static PageAction copyOf(final PageAction source) { return new PageAction( source.definition, diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageServiceImpl.java index 9f2b97a9..1be5f56d 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageServiceImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageServiceImpl.java @@ -56,6 +56,7 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall.CallType; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; import ch.ethz.seb.sebserver.gui.table.EntityTable; import ch.ethz.seb.sebserver.gui.table.TableBuilder; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; @@ -84,20 +85,20 @@ public class PageServiceImpl implements PageService { private final WidgetFactory widgetFactory; private final PolyglotPageService polyglotPageService; private final ResourceService resourceService; - private final AuthorizationContextHolder authorizationContextHolder; + private final CurrentUser currentUser; public PageServiceImpl( final JSONMapper jsonMapper, final WidgetFactory widgetFactory, final PolyglotPageService polyglotPageService, final ResourceService resourceService, - final AuthorizationContextHolder authorizationContextHolder) { + final CurrentUser currentUser) { this.jsonMapper = jsonMapper; this.widgetFactory = widgetFactory; this.polyglotPageService = polyglotPageService; this.resourceService = resourceService; - this.authorizationContextHolder = authorizationContextHolder; + this.currentUser = currentUser; } @Override @@ -112,7 +113,7 @@ public class PageServiceImpl implements PageService { @Override public AuthorizationContextHolder getAuthorizationContextHolder() { - return this.authorizationContextHolder; + return this.currentUser.getAuthorizationContextHolder(); } @Override @@ -139,6 +140,11 @@ public class PageServiceImpl implements PageService { return this.resourceService.getRestService(); } + @Override + public CurrentUser getCurrentUser() { + return this.currentUser; + } + @Override public PageState getCurrentState() { try { @@ -317,8 +323,11 @@ public class PageServiceImpl implements PageService { } @Override - public TableBuilder entityTableBuilder(final RestCall> apiCall) { - return new TableBuilder<>(this, apiCall); + public TableBuilder entityTableBuilder( + final String name, + final RestCall> apiCall) { + + return new TableBuilder<>(name, this, apiCall); } @Override @@ -326,9 +335,7 @@ public class PageServiceImpl implements PageService { this.clearState(); try { - final boolean logoutSuccessful = this.authorizationContextHolder - .getAuthorizationContext() - .logout(); + final boolean logoutSuccessful = this.currentUser.logout(); if (!logoutSuccessful) { log.error("Failed to logout. See logfiles for more information"); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/auth/CurrentUser.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/auth/CurrentUser.java index 22786d58..6fcd9fc5 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/auth/CurrentUser.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/auth/CurrentUser.java @@ -45,9 +45,23 @@ public class CurrentUser { private final AuthorizationContextHolder authorizationContextHolder; private SEBServerAuthorizationContext authContext = null; private Map privileges = null; + private final Map attributes; public CurrentUser(final AuthorizationContextHolder authorizationContextHolder) { this.authorizationContextHolder = authorizationContextHolder; + this.attributes = new HashMap<>(); + } + + public void putAttribute(final String name, final String value) { + this.attributes.put(name, value); + } + + public String getAttribute(final String name) { + return this.attributes.get(name); + } + + public AuthorizationContextHolder getAuthorizationContextHolder() { + return this.authorizationContextHolder; } public UserInfo get() { @@ -161,6 +175,19 @@ public class CurrentUser { this.authContext.refreshUser(userInfo); } + public boolean logout() { + if (isAvailable()) { + if (this.authContext.logout()) { + this.authContext = null; + return true; + } else { + return false; + } + } else { + return this.authorizationContextHolder.getAuthorizationContext().logout(); + } + } + private void updateContext() { if (this.authContext == null || !this.authContext.isValid()) { this.authContext = this.authorizationContextHolder.getAuthorizationContext(); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/table/EntityTable.java b/src/main/java/ch/ethz/seb/sebserver/gui/table/EntityTable.java index c5723163..b7c75fcb 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/table/EntityTable.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/table/EntityTable.java @@ -57,6 +57,7 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon; +import io.micrometer.core.instrument.util.StringUtils; public class EntityTable { @@ -67,6 +68,12 @@ public class EntityTable { private static final int HEADER_HEIGHT = 40; private static final int ROW_HEIGHT = 25; + private final String name; + private final String filterAttrName; + private final String sortAttrName; + private final String sortOrderAttrName; + private final String currentPageAttrName; + final PageService pageService; final WidgetFactory widgetFactory; final RestCall> restCall; @@ -92,6 +99,7 @@ public class EntityTable { boolean hideNavigation = false; EntityTable( + final String name, final int type, final PageContext pageContext, final RestCall> restCall, @@ -105,6 +113,12 @@ public class EntityTable { final MultiValueMap staticQueryParams, final BiConsumer rowDecorator) { + this.name = name; + this.filterAttrName = name + "_filter"; + this.sortAttrName = name + "_sort"; + this.sortOrderAttrName = name + "_sortOrder"; + this.currentPageAttrName = name + "_currentPage"; + this.composite = new Composite(pageContext.getParent(), type); this.pageService = pageService; this.i18nSupport = pageService.getI18nSupport(); @@ -125,10 +139,6 @@ public class EntityTable { this.composite.setLayoutData(gridData); this.staticQueryParams = staticQueryParams; this.rowDecorator = rowDecorator; - -// TODO just for debugging, remove when tested -// this.composite.setBackground(new Color(parent.getDisplay(), new RGB(0, 200, 0))); - this.pageSize = pageSize; this.filter = columns @@ -197,6 +207,9 @@ public class EntityTable { this.navigator = new TableNavigator(this); createTableColumns(); + initCurrentPageFromUserAttr(); + initFilterFromUserAttrs(); + initSortFromUserAttr(); updateTableRows( this.pageNumber, this.pageSize, @@ -204,6 +217,10 @@ public class EntityTable { this.sortOrder); } + public String getName() { + return this.name; + } + public EntityType getEntityType() { if (this.restCall != null) { return this.restCall.getEntityType(); @@ -245,15 +262,29 @@ public class EntityTable { this.pageSize, this.sortColumn, this.sortOrder); + + updateCurrentPageAttr(pageSelection); + } + + public void reset() { + this.applySort(null); + this.table.setSortColumn(null); + this.table.setSortDirection(SWT.NONE); + applyFilter(); } public void applyFilter() { try { + updateTableRows( this.pageNumber, this.pageSize, this.sortColumn, this.sortOrder); + + updateFilterUserAttrs(); + this.selectPage(0); + } catch (final Exception e) { log.error("Unexpected error while trying to apply filter: ", e); } @@ -269,6 +300,9 @@ public class EntityTable { this.pageSize, this.sortColumn, this.sortOrder); + + updateSortUserAttr(); + } catch (final Exception e) { log.error("Unexpected error while trying to apply sort: ", e); } @@ -285,6 +319,9 @@ public class EntityTable { this.pageSize, this.sortColumn, this.sortOrder); + + updateSortUserAttr(); + } catch (final Exception e) { log.error("Unexpected error while trying to apply sort: ", e); } @@ -366,6 +403,18 @@ public class EntityTable { }); } + private TableColumn getTableColumn(final String name) { + return Arrays.asList(this.table.getColumns()) + .stream() + .filter(col -> { + @SuppressWarnings("unchecked") + final ColumnDefinition def = (ColumnDefinition) col.getData(COLUMN_DEFINITION); + return name.equals(def.columnName); + }) + .findFirst() + .orElse(null); + } + private void createTableColumns() { for (final ColumnDefinition column : this.columns) { final TableColumn tableColumn = this.widgetFactory.tableColumnLocalized( @@ -558,4 +607,91 @@ public class EntityTable { // TODO handle selection tool-tips on cell level } + private void updateCurrentPageAttr(final int page) { + try { + this.pageService + .getCurrentUser() + .putAttribute(this.currentPageAttrName, String.valueOf(page)); + } catch (final Exception e) { + log.error("Failed to put current page attribute to current user attributes", e); + } + } + + private void initCurrentPageFromUserAttr() { + try { + final String currentPage = this.pageService + .getCurrentUser() + .getAttribute(this.currentPageAttrName); + if (StringUtils.isNotBlank(currentPage)) { + this.selectPage(Integer.parseInt(currentPage)); + } + } catch (final Exception e) { + log.error("Failed to get sort attribute form current user attributes", e); + } + } + + private void updateSortUserAttr() { + try { + this.pageService + .getCurrentUser() + .putAttribute(this.sortAttrName, this.sortColumn); + this.pageService + .getCurrentUser() + .putAttribute(this.sortOrderAttrName, this.sortOrder.name()); + } catch (final Exception e) { + log.error("Failed to put sort attribute to current user attributes", e); + } + } + + private void initSortFromUserAttr() { + try { + final String sort = this.pageService + .getCurrentUser() + .getAttribute(this.sortAttrName); + if (StringUtils.isNotBlank(sort)) { + this.sortColumn = sort; + final TableColumn tableColumn = getTableColumn(sort); + if (tableColumn != null) { + this.table.setSortColumn(tableColumn); + } + } + + final String sortOrder = this.pageService + .getCurrentUser() + .getAttribute(this.sortOrderAttrName); + if (StringUtils.isNotBlank(sortOrder)) { + this.sortOrder = PageSortOrder.valueOf(sortOrder); + this.table.setSortDirection(this.sortOrder == PageSortOrder.ASCENDING ? SWT.UP : SWT.DOWN); + } + + } catch (final Exception e) { + log.error("Failed to get sort attribute form current user attributes", e); + } + } + + private void updateFilterUserAttrs() { + if (this.filter != null) { + try { + this.pageService + .getCurrentUser() + .putAttribute(this.filterAttrName, this.filter.getFilterAttributes()); + } catch (final Exception e) { + log.error("Failed to put filter attributes to current user attributes", e); + } + } + } + + private void initFilterFromUserAttrs() { + if (this.filter != null) { + try { + this.filter.setFilterAttributes( + this.pageService + .getCurrentUser() + .getAttribute(this.filterAttrName)); + } catch (final Exception e) { + log.error("Failed to get filter attributes form current user attributes", e); + } + } + } + } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/table/TableBuilder.java b/src/main/java/ch/ethz/seb/sebserver/gui/table/TableBuilder.java index 2779af2d..45f2b173 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/table/TableBuilder.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/table/TableBuilder.java @@ -30,6 +30,7 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; public class TableBuilder { + private final String name; private final PageService pageService; final RestCall> restCall; private final MultiValueMap staticQueryParams; @@ -43,9 +44,11 @@ public class TableBuilder { private BiConsumer rowDecorator; public TableBuilder( + final String name, final PageService pageService, final RestCall> restCall) { + this.name = name; this.pageService = pageService; this.restCall = restCall; this.staticQueryParams = new LinkedMultiValueMap<>(); @@ -136,6 +139,7 @@ public class TableBuilder { public EntityTable compose(final PageContext pageContext) { return new EntityTable<>( + this.name, this.type, pageContext, this.restCall, diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/table/TableFilter.java b/src/main/java/ch/ethz/seb/sebserver/gui/table/TableFilter.java index 5d832035..2b888039 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/table/TableFilter.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/table/TableFilter.java @@ -25,12 +25,15 @@ import org.eclipse.swt.widgets.DateTime; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; import org.joda.time.DateTimeZone; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.model.Entity; import ch.ethz.seb.sebserver.gbl.util.Tuple; +import ch.ethz.seb.sebserver.gbl.util.Utils; import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute; import ch.ethz.seb.sebserver.gui.widget.Selection; @@ -38,6 +41,8 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon; public class TableFilter { + private static final Logger log = LoggerFactory.getLogger(TableFilter.class); + private static final LocTextKey DATE_FROM_TEXT = new LocTextKey("sebserver.overall.date.from"); private static final LocTextKey DATE_TO_TEXT = new LocTextKey("sebserver.overall.date.to"); @@ -137,6 +142,50 @@ public class TableFilter { return false; } + String getFilterAttributes() { + final StringBuilder builder = this.components + .stream() + .reduce( + new StringBuilder(), + (sb, filter) -> sb + .append(filter.attribute.columnName) + .append(Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR) + .append(filter.getValue()) + .append(Constants.LIST_SEPARATOR), + (sb1, sb2) -> sb1.append(sb2)); + if (builder.length() > 0) { + builder.deleteCharAt(builder.length() - 1); + } + return builder.toString(); + } + + void setFilterAttributes(final String attribute) { + if (StringUtils.isBlank(attribute)) { + return; + } + + try { + Arrays.asList(StringUtils.split( + attribute, + Constants.LIST_SEPARATOR_CHAR)) + .stream() + .map(nameValue -> StringUtils.split( + nameValue, + Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR)) + .forEach(nameValue -> { + this.components + .stream() + .filter(filter -> nameValue[0].equals(filter.attribute.columnName)) + .findFirst() + .ifPresent(filter -> filter.setValue((nameValue.length > 1) + ? nameValue[1] + : StringUtils.EMPTY)); + }); + } catch (final Exception e) { + log.error("Failed to set filter attributes: ", e); + } + } + private void addActions() { final Composite inner = new Composite(this.composite, SWT.NONE); final GridLayout gridLayout = new GridLayout(2, true); @@ -163,7 +212,7 @@ public class TableFilter { new LocTextKey("sebserver.overall.action.filter.clear"), event -> { reset(); - this.entityTable.applyFilter(); + this.entityTable.reset(); }); imageButton2.setLayoutData(gridData); } @@ -196,6 +245,8 @@ public class TableFilter { abstract String getValue(); + abstract void setValue(String value); + boolean adaptWidth(final int width) { final int _width = width + CELL_WIDTH_ADJUSTMENT; if (_width != this.rowData.width) { @@ -244,6 +295,10 @@ public class TableFilter { return null; } + @Override + void setValue(final String value) { + } + } private class TextFilter extends FilterComponent { @@ -281,6 +336,13 @@ public class TableFilter { return null; } + @Override + void setValue(final String value) { + if (this.textInput != null) { + this.textInput.setText(value); + } + } + } private class SelectionFilter extends FilterComponent { @@ -317,6 +379,9 @@ public class TableFilter { FilterComponent reset() { if (this.selector != null) { this.selector.clear(); + if (StringUtils.isNotBlank(this.attribute.initValue)) { + this.selector.select(this.attribute.initValue); + } } return this; } @@ -329,6 +394,13 @@ public class TableFilter { return null; } + + @Override + void setValue(final String value) { + if (this.selector != null) { + this.selector.select(value); + } + } } // NOTE: SWT DateTime month-number starting with 0 and joda DateTime with 1! @@ -379,13 +451,24 @@ public class TableFilter { } } + @Override + void setValue(final String value) { + if (this.selector != null) { + try { + final org.joda.time.DateTime date = Utils.toDateTime(value); + this.selector.setDate(date.getYear(), date.getMonthOfYear() - 1, date.getDayOfMonth()); + } catch (final Exception e) { + log.error("Failed to set date filter attribute: ", e); + } + } + } + @Override boolean adaptWidth(final int width) { // NOTE: for some unknown reason RWT acts differently on width-property for date selector // this is to adjust date filter criteria to the list column width return super.adaptWidth(width - 5); } - } // NOTE: SWT DateTime month-number starting with 0 and joda DateTime with 1! @@ -473,6 +556,23 @@ public class TableFilter { return null; } } + + @Override + void setValue(final String value) { + if (this.fromSelector != null && this.toSelector != null) { + try { + final String[] split = StringUtils.split(value, Constants.EMBEDDED_LIST_SEPARATOR); + final org.joda.time.DateTime fromDate = Utils.toDateTime(split[0]); + final org.joda.time.DateTime toDate = Utils.toDateTime(split[1]); + this.fromSelector.setDate(fromDate.getYear(), fromDate.getMonthOfYear() - 1, + fromDate.getDayOfMonth()); + this.toSelector.setDate(toDate.getYear(), toDate.getMonthOfYear() - 1, toDate.getDayOfMonth()); + } catch (final Exception e) { + log.error("Failed to set date range filter attribute: ", e); + } + } + + } } } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/InstitutionDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/InstitutionDAOImpl.java index f4086148..20496196 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/InstitutionDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/InstitutionDAOImpl.java @@ -106,6 +106,9 @@ public class InstitutionDAOImpl implements InstitutionDAO { .and( InstitutionRecordDynamicSqlSupport.name, SqlBuilder.isLikeWhenPresent(filterMap.getName())) + .and( + InstitutionRecordDynamicSqlSupport.urlSuffix, + SqlBuilder.isLikeWhenPresent(filterMap.getSQLWildcard(Institution.FILTER_ATTR_URL_SUFFIX))) .build() .execute() .stream() diff --git a/src/main/resources/config/application-dev-gui.properties b/src/main/resources/config/application-dev-gui.properties index 39a56676..75fc56dc 100644 --- a/src/main/resources/config/application-dev-gui.properties +++ b/src/main/resources/config/application-dev-gui.properties @@ -19,7 +19,7 @@ sebserver.gui.theme=css/sebserver.css sebserver.gui.list.page.size=15 sebserver.gui.date.displayformat=yyyy-MM-dd HH:mm sebserver.gui.date.displayformat.timezone=|ZZ -sebserver.gui.multilingual=true +sebserver.gui.multilingual=false sebserver.gui.languages=en,de sebserver.gui.seb.client.config.download.filename=SEBClientSettings.seb diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties index 14d613be..e431942d 100644 --- a/src/main/resources/messages.properties +++ b/src/main/resources/messages.properties @@ -4,7 +4,7 @@ sebserver.overall.version=SEB Server Version : {0} sebserver.overall.help=Documentation -sebserver.overall.help.link=https://www.safeexambrowser.org/news_en.html +sebserver.overall.help.link=https://seb-server.readthedocs.io/en/latest/# sebserver.overall.message.leave.without.save=You have unsaved changes!\nAre you sure you want to leave the page?\The changes will be lost. sebserver.overall.upload=Please select a file