added SEBSever logo

added Institution show case
added table attribute to user session
This commit is contained in:
anhefti 2019-12-10 13:33:15 +01:00
parent b27c79e1d8
commit 9f752bf145
23 changed files with 386 additions and 48 deletions

View file

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

View file

@ -185,7 +185,9 @@ public class ConfigTemplateForm implements TemplateComposer {
() -> this.resourceService.getAttributeTypeResources());
final EntityTable<TemplateAttribute> 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())

View file

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

View file

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

View file

@ -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<Institution>(
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());
}
}

View file

@ -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());
}

View file

@ -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));
}

View file

@ -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());
}

View file

@ -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());
}

View file

@ -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();
}

View file

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

View file

@ -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"),

View file

@ -147,8 +147,9 @@ public class ResourceService {
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")));
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;
}

View file

@ -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 <T> the type of the Entity of the table
* @return TableBuilder of specified type */
<T extends Entity> TableBuilder<T> entityTableBuilder(RestCall<Page<T>> apiCall);
default <T extends Entity> TableBuilder<T> entityTableBuilder(final RestCall<Page<T>> 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 <T> the type of the Entity of the table
* @return TableBuilder of specified type */
<T extends Entity> TableBuilder<T> entityTableBuilder(
String name,
RestCall<Page<T>> apiCall);
/** Get a new PageActionBuilder for a given PageContext.
*

View file

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

View file

@ -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 <T extends Entity> TableBuilder<T> entityTableBuilder(final RestCall<Page<T>> apiCall) {
return new TableBuilder<>(this, apiCall);
public <T extends Entity> TableBuilder<T> entityTableBuilder(
final String name,
final RestCall<Page<T>> 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");

View file

@ -45,9 +45,23 @@ public class CurrentUser {
private final AuthorizationContextHolder authorizationContextHolder;
private SEBServerAuthorizationContext authContext = null;
private Map<RoleTypeKey, Privilege> privileges = null;
private final Map<String, String> 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();

View file

@ -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<ROW extends Entity> {
@ -67,6 +68,12 @@ public class EntityTable<ROW extends Entity> {
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<Page<ROW>> restCall;
@ -92,6 +99,7 @@ public class EntityTable<ROW extends Entity> {
boolean hideNavigation = false;
EntityTable(
final String name,
final int type,
final PageContext pageContext,
final RestCall<Page<ROW>> restCall,
@ -105,6 +113,12 @@ public class EntityTable<ROW extends Entity> {
final MultiValueMap<String, String> staticQueryParams,
final BiConsumer<TableItem, ROW> 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<ROW extends Entity> {
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<ROW extends Entity> {
this.navigator = new TableNavigator(this);
createTableColumns();
initCurrentPageFromUserAttr();
initFilterFromUserAttrs();
initSortFromUserAttr();
updateTableRows(
this.pageNumber,
this.pageSize,
@ -204,6 +217,10 @@ public class EntityTable<ROW extends Entity> {
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<ROW extends Entity> {
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<ROW extends Entity> {
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<ROW extends Entity> {
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<ROW extends Entity> {
});
}
private TableColumn getTableColumn(final String name) {
return Arrays.asList(this.table.getColumns())
.stream()
.filter(col -> {
@SuppressWarnings("unchecked")
final ColumnDefinition<ROW> def = (ColumnDefinition<ROW>) col.getData(COLUMN_DEFINITION);
return name.equals(def.columnName);
})
.findFirst()
.orElse(null);
}
private void createTableColumns() {
for (final ColumnDefinition<ROW> column : this.columns) {
final TableColumn tableColumn = this.widgetFactory.tableColumnLocalized(
@ -558,4 +607,91 @@ public class EntityTable<ROW extends Entity> {
// 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);
}
}
}
}

View file

@ -30,6 +30,7 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
public class TableBuilder<ROW extends Entity> {
private final String name;
private final PageService pageService;
final RestCall<Page<ROW>> restCall;
private final MultiValueMap<String, String> staticQueryParams;
@ -43,9 +44,11 @@ public class TableBuilder<ROW extends Entity> {
private BiConsumer<TableItem, ROW> rowDecorator;
public TableBuilder(
final String name,
final PageService pageService,
final RestCall<Page<ROW>> restCall) {
this.name = name;
this.pageService = pageService;
this.restCall = restCall;
this.staticQueryParams = new LinkedMultiValueMap<>();
@ -136,6 +139,7 @@ public class TableBuilder<ROW extends Entity> {
public EntityTable<ROW> compose(final PageContext pageContext) {
return new EntityTable<>(
this.name,
this.type,
pageContext,
this.restCall,

View file

@ -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<ROW extends Entity> {
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<ROW extends Entity> {
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<ROW extends Entity> {
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<ROW extends Entity> {
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<ROW extends Entity> {
return null;
}
@Override
void setValue(final String value) {
}
}
private class TextFilter extends FilterComponent {
@ -281,6 +336,13 @@ public class TableFilter<ROW extends Entity> {
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<ROW extends Entity> {
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<ROW extends Entity> {
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<ROW extends Entity> {
}
}
@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<ROW extends Entity> {
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);
}
}
}
}
}

View file

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

View file

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

View file

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