added diverse activity action use cases (possibilities) to Institution

This commit is contained in:
anhefti 2019-11-27 15:19:19 +01:00
parent 71fb39749b
commit 952e8ef12f
29 changed files with 237 additions and 108 deletions

View file

@ -22,6 +22,9 @@
<Match> <Match>
<Package name="~ch\.ethz\.seb\.sebserver\.gui\..*" /> <Package name="~ch\.ethz\.seb\.sebserver\.gui\..*" />
<Bug pattern="SE_BAD_FIELD" /> <Bug pattern="SE_BAD_FIELD" />
</Match>
<Match>
<Package name="~ch\.ethz\.seb\.sebserver\.gui\..*" />
<Bug pattern="REC_CATCH_EXCEPTION" /> <Bug pattern="REC_CATCH_EXCEPTION" />
</Match> </Match>
<Match> <Match>

View file

@ -14,11 +14,12 @@ import java.util.Set;
import org.joda.time.DateTimeZone; import org.joda.time.DateTimeZone;
import ch.ethz.seb.sebserver.gbl.model.Activatable;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.GrantEntity; import ch.ethz.seb.sebserver.gbl.model.GrantEntity;
/** Defines a User-Account object */ /** Defines a User-Account object */
public interface UserAccount extends GrantEntity { public interface UserAccount extends GrantEntity, Activatable {
/** The model id of the User-Account (UUID) */ /** The model id of the User-Account (UUID) */
@Override @Override
@ -42,6 +43,7 @@ public interface UserAccount extends GrantEntity {
Boolean getActive(); Boolean getActive();
/** Indicates whether the User-Account is active or not */ /** Indicates whether the User-Account is active or not */
@Override
boolean isActive(); boolean isActive();
/** The language of the User-Account */ /** The language of the User-Account */

View file

@ -614,7 +614,7 @@ public class ExamForm implements TemplateComposer {
.removeAttribute(AttributeKeys.IMPORT_FROM_QUIZ_DATA)) .removeAttribute(AttributeKeys.IMPORT_FROM_QUIZ_DATA))
.newAction(ActionDefinition.EXAM_CONFIGURATION_EXAM_CONFIG_VIEW_PROP) .newAction(ActionDefinition.EXAM_CONFIGURATION_EXAM_CONFIG_VIEW_PROP)
.withSelectionSupplier(() -> { .withSelectionSupplier(() -> {
final ExamConfigurationMap selectedROWData = table.getSelectedROWData(); final ExamConfigurationMap selectedROWData = table.getSingleSelectedROWData();
final HashSet<EntityKey> result = new HashSet<>(); final HashSet<EntityKey> result = new HashSet<>();
if (selectedROWData != null) { if (selectedROWData != null) {
result.add(new EntityKey( result.add(new EntityKey(

View file

@ -220,7 +220,7 @@ public class ExamList implements TemplateComposer {
} }
static final PageAction modifyExam(final PageAction action, final EntityTable<Exam> table) { static final PageAction modifyExam(final PageAction action, final EntityTable<Exam> table) {
final Exam exam = table.getSelectedROWData(); final Exam exam = table.getSingleSelectedROWData();
if (exam == null) { if (exam == null) {
throw new PageMessageException(EMPTY_SELECTION_TEXT_KEY); throw new PageMessageException(EMPTY_SELECTION_TEXT_KEY);

View file

@ -26,7 +26,6 @@ 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;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.page.impl.DefaultPageLayout; import ch.ethz.seb.sebserver.gui.service.page.impl.DefaultPageLayout;
import ch.ethz.seb.sebserver.gui.service.page.impl.PageUtils;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.ActivateInstitution; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.ActivateInstitution;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.DeactivateInstitution; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.DeactivateInstitution;
@ -143,7 +142,7 @@ public class InstitutionForm implements TemplateComposer {
.newAction(ActionDefinition.INSTITUTION_DEACTIVATE) .newAction(ActionDefinition.INSTITUTION_DEACTIVATE)
.withEntityKey(entityKey) .withEntityKey(entityKey)
.withSimpleRestCall(this.restService, DeactivateInstitution.class) .withSimpleRestCall(this.restService, DeactivateInstitution.class)
.withConfirm(PageUtils.confirmDeactivation(institution, this.restService)) .withConfirm(this.pageService.confirmDeactivation(institution))
.publishIf(() -> writeGrant && isReadonly && institution.isActive()) .publishIf(() -> writeGrant && isReadonly && institution.isActive())
.newAction(ActionDefinition.INSTITUTION_ACTIVATE) .newAction(ActionDefinition.INSTITUTION_ACTIVATE)
@ -157,6 +156,12 @@ public class InstitutionForm implements TemplateComposer {
.ignoreMoveAwayFromEdit() .ignoreMoveAwayFromEdit()
.publishIf(() -> !isReadonly) .publishIf(() -> !isReadonly)
.newAction(ActionDefinition.INSTITUTION_SAVE_AND_ACTIVATE)
.withEntityKey(entityKey)
.withExec(formHandle::saveAndActivate)
.ignoreMoveAwayFromEdit()
.publishIf(() -> !isReadonly && !institution.isActive())
.newAction(ActionDefinition.INSTITUTION_CANCEL_MODIFY) .newAction(ActionDefinition.INSTITUTION_CANCEL_MODIFY)
.withEntityKey(entityKey) .withEntityKey(entityKey)
.withExec(this.pageService.backToCurrentFunction()) .withExec(this.pageService.backToCurrentFunction())

View file

@ -120,6 +120,11 @@ public class InstitutionList implements TemplateComposer {
.newAction(ActionDefinition.INSTITUTION_MODIFY_FROM_LIST) .newAction(ActionDefinition.INSTITUTION_MODIFY_FROM_LIST)
.withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY) .withSelect(table::getSelection, PageAction::applySingleSelection, 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());
} }

View file

@ -40,7 +40,6 @@ import ch.ethz.seb.sebserver.gui.service.page.PageMessageException;
import ch.ethz.seb.sebserver.gui.service.page.PageService; import ch.ethz.seb.sebserver.gui.service.page.PageService;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction; import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
import ch.ethz.seb.sebserver.gui.service.page.impl.PageUtils;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCallError; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCallError;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitution; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitution;
@ -266,7 +265,7 @@ public class LmsSetupForm implements TemplateComposer {
.newAction(ActionDefinition.LMS_SETUP_DEACTIVATE) .newAction(ActionDefinition.LMS_SETUP_DEACTIVATE)
.withEntityKey(entityKey) .withEntityKey(entityKey)
.withSimpleRestCall(restService, DeactivateLmsSetup.class) .withSimpleRestCall(restService, DeactivateLmsSetup.class)
.withConfirm(PageUtils.confirmDeactivation(lmsSetup, restService)) .withConfirm(this.pageService.confirmDeactivation(lmsSetup))
.publishIf(() -> writeGrant && readonly && institutionActive && lmsSetup.isActive()) .publishIf(() -> writeGrant && readonly && institutionActive && lmsSetup.isActive())
.newAction(ActionDefinition.LMS_SETUP_ACTIVATE) .newAction(ActionDefinition.LMS_SETUP_ACTIVATE)

View file

@ -194,7 +194,7 @@ public class QuizDiscoveryList implements TemplateComposer {
.newAction(ActionDefinition.QUIZ_DISCOVERY_SHOW_DETAILS) .newAction(ActionDefinition.QUIZ_DISCOVERY_SHOW_DETAILS)
.withExec(action -> this.showDetails( .withExec(action -> this.showDetails(
action, action,
t.getSelectedROWData(), t.getSingleSelectedROWData(),
institutionNameFunction)) institutionNameFunction))
.noEventPropagation() .noEventPropagation()
.create()) .create())
@ -214,7 +214,7 @@ public class QuizDiscoveryList implements TemplateComposer {
table::getSelection, table::getSelection,
action -> this.showDetails( action -> this.showDetails(
action, action,
table.getSelectedROWData(), table.getSingleSelectedROWData(),
institutionNameFunction), institutionNameFunction),
EMPTY_SELECTION_TEXT) EMPTY_SELECTION_TEXT)
.noEventPropagation() .noEventPropagation()
@ -235,7 +235,7 @@ public class QuizDiscoveryList implements TemplateComposer {
private PageAction importQuizData(final PageAction action, final EntityTable<QuizData> table) { private PageAction importQuizData(final PageAction action, final EntityTable<QuizData> table) {
action.getSingleSelection(); action.getSingleSelection();
final QuizData selectedROWData = table.getSelectedROWData(); final QuizData selectedROWData = table.getSingleSelectedROWData();
if (selectedROWData.endTime != null) { if (selectedROWData.endTime != null) {
final DateTime now = DateTime.now(DateTimeZone.UTC); final DateTime now = DateTime.now(DateTimeZone.UTC);

View file

@ -30,7 +30,6 @@ 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.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.PageService; import ch.ethz.seb.sebserver.gui.service.page.PageService;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.page.impl.PageUtils;
import ch.ethz.seb.sebserver.gui.service.remote.download.DownloadService; import ch.ethz.seb.sebserver.gui.service.remote.download.DownloadService;
import ch.ethz.seb.sebserver.gui.service.remote.download.SebClientConfigDownload; import ch.ethz.seb.sebserver.gui.service.remote.download.SebClientConfigDownload;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
@ -183,7 +182,7 @@ public class SebClientConfigForm implements TemplateComposer {
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_DEACTIVATE) .newAction(ActionDefinition.SEB_CLIENT_CONFIG_DEACTIVATE)
.withEntityKey(entityKey) .withEntityKey(entityKey)
.withSimpleRestCall(this.restService, DeactivateClientConfig.class) .withSimpleRestCall(this.restService, DeactivateClientConfig.class)
.withConfirm(PageUtils.confirmDeactivation(clientConfig, this.restService)) .withConfirm(this.pageService.confirmDeactivation(clientConfig))
.publishIf(() -> writeGrant && isReadonly && clientConfig.isActive()) .publishIf(() -> writeGrant && isReadonly && clientConfig.isActive())
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_ACTIVATE) .newAction(ActionDefinition.SEB_CLIENT_CONFIG_ACTIVATE)

View file

@ -219,7 +219,7 @@ public class SebClientLogs implements TemplateComposer {
.withDefaultAction(t -> actionBuilder .withDefaultAction(t -> actionBuilder
.newAction(ActionDefinition.LOGS_SEB_CLIENT_SHOW_DETAILS) .newAction(ActionDefinition.LOGS_SEB_CLIENT_SHOW_DETAILS)
.withExec(action -> this.showDetails(action, t.getSelectedROWData())) .withExec(action -> this.showDetails(action, t.getSingleSelectedROWData()))
.noEventPropagation() .noEventPropagation()
.create()) .create())
@ -229,7 +229,7 @@ public class SebClientLogs implements TemplateComposer {
.newAction(ActionDefinition.LOGS_SEB_CLIENT_SHOW_DETAILS) .newAction(ActionDefinition.LOGS_SEB_CLIENT_SHOW_DETAILS)
.withSelect( .withSelect(
table::getSelection, table::getSelection,
action -> this.showDetails(action, table.getSelectedROWData()), action -> this.showDetails(action, table.getSingleSelectedROWData()),
EMPTY_SELECTION_TEXT) EMPTY_SELECTION_TEXT)
.noEventPropagation() .noEventPropagation()
.publishIf(table::hasAnyContent); .publishIf(table::hasAnyContent);

View file

@ -347,7 +347,7 @@ public class SebExamConfigPropForm implements TemplateComposer {
} }
private ExamConfigurationMap getSelectedExamMapping(final EntityTable<ExamConfigurationMap> table) { private ExamConfigurationMap getSelectedExamMapping(final EntityTable<ExamConfigurationMap> table) {
final ExamConfigurationMap selectedROWData = table.getSelectedROWData(); final ExamConfigurationMap selectedROWData = table.getSingleSelectedROWData();
if (selectedROWData == null) { if (selectedROWData == null) {
throw new PageMessageException(ExamList.EMPTY_SELECTION_TEXT_KEY); throw new PageMessageException(ExamList.EMPTY_SELECTION_TEXT_KEY);

View file

@ -37,7 +37,6 @@ 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.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.PageService; import ch.ethz.seb.sebserver.gui.service.page.PageService;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.page.impl.PageUtils;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitution; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitution;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.ActivateUserAccount; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.ActivateUserAccount;
@ -225,7 +224,7 @@ public class UserAccountForm implements TemplateComposer {
.newAction(ActionDefinition.USER_ACCOUNT_DEACTIVATE) .newAction(ActionDefinition.USER_ACCOUNT_DEACTIVATE)
.withEntityKey(entityKey) .withEntityKey(entityKey)
.withSimpleRestCall(restService, DeactivateUserAccount.class) .withSimpleRestCall(restService, DeactivateUserAccount.class)
.withConfirm(PageUtils.confirmDeactivation(userAccount, restService)) .withConfirm(this.pageService.confirmDeactivation(userAccount))
.publishIf(() -> writeGrant && readonly && institutionActive && userAccount.isActive()) .publishIf(() -> writeGrant && readonly && institutionActive && userAccount.isActive())
.newAction(ActionDefinition.USER_ACCOUNT_ACTIVATE) .newAction(ActionDefinition.USER_ACCOUNT_ACTIVATE)

View file

@ -191,7 +191,7 @@ public class UserActivityLogs implements TemplateComposer {
.withDefaultAction(t -> actionBuilder .withDefaultAction(t -> actionBuilder
.newAction(ActionDefinition.LOGS_USER_ACTIVITY_SHOW_DETAILS) .newAction(ActionDefinition.LOGS_USER_ACTIVITY_SHOW_DETAILS)
.withExec(action -> this.showDetails(action, t.getSelectedROWData())) .withExec(action -> this.showDetails(action, t.getSingleSelectedROWData()))
.noEventPropagation() .noEventPropagation()
.create()) .create())
@ -201,7 +201,7 @@ public class UserActivityLogs implements TemplateComposer {
.newAction(ActionDefinition.LOGS_USER_ACTIVITY_SHOW_DETAILS) .newAction(ActionDefinition.LOGS_USER_ACTIVITY_SHOW_DETAILS)
.withSelect( .withSelect(
table::getSelection, table::getSelection,
action -> this.showDetails(action, table.getSelectedROWData()), action -> this.showDetails(action, table.getSingleSelectedROWData()),
EMPTY_SELECTION_TEXT) EMPTY_SELECTION_TEXT)
.noEventPropagation() .noEventPropagation()
.publishIf(table::hasAnyContent); .publishIf(table::hasAnyContent);

View file

@ -36,6 +36,11 @@ public enum ActionDefinition {
ImageIcon.EDIT, ImageIcon.EDIT,
PageStateDefinitionImpl.INSTITUTION_EDIT, PageStateDefinitionImpl.INSTITUTION_EDIT,
ActionCategory.INSTITUTION_LIST), ActionCategory.INSTITUTION_LIST),
INSTITUTION_TOGGLE_ACTIVITY(
new LocTextKey("sebserver.overall.action.toggle-activity"),
ImageIcon.SWITCH,
PageStateDefinitionImpl.INSTITUTION_LIST,
ActionCategory.INSTITUTION_LIST),
INSTITUTION_MODIFY( INSTITUTION_MODIFY(
new LocTextKey("sebserver.institution.action.modify"), new LocTextKey("sebserver.institution.action.modify"),
ImageIcon.EDIT, ImageIcon.EDIT,
@ -51,6 +56,11 @@ public enum ActionDefinition {
ImageIcon.SAVE, ImageIcon.SAVE,
PageStateDefinitionImpl.INSTITUTION_VIEW, PageStateDefinitionImpl.INSTITUTION_VIEW,
ActionCategory.FORM), ActionCategory.FORM),
INSTITUTION_SAVE_AND_ACTIVATE(
new LocTextKey("sebserver.institution.action.activate"),
ImageIcon.ACTIVE,
PageStateDefinitionImpl.INSTITUTION_VIEW,
ActionCategory.FORM),
INSTITUTION_ACTIVATE( INSTITUTION_ACTIVATE(
new LocTextKey("sebserver.institution.action.activate"), new LocTextKey("sebserver.institution.action.activate"),
ImageIcon.TOGGLE_OFF, ImageIcon.TOGGLE_OFF,

View file

@ -15,6 +15,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.APIMessage; import ch.ethz.seb.sebserver.gbl.api.APIMessage;
import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Entity; import ch.ethz.seb.sebserver.gbl.model.Entity;
@ -29,6 +30,7 @@ import ch.ethz.seb.sebserver.gui.service.page.PageService;
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction; import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.FormBinding; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.FormBinding;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; 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.RestCallError; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCallError;
public class FormHandle<T extends Entity> { public class FormHandle<T extends Entity> {
@ -79,6 +81,16 @@ public class FormHandle<T extends Entity> {
return handleFormPost(doAPIPost(), action); return handleFormPost(doAPIPost(), action);
} }
public final PageAction saveAndActivate(final PageAction action) {
final PageAction handleFormPost = handleFormPost(doAPIPost(), action);
final EntityType entityType = this.post.getEntityType();
this.pageService.getRestService().getBuilder(entityType, CallType.ACTIVATION_ACTIVATE)
.withURIVariable(API.PARAM_MODEL_ID, handleFormPost.getEntityKey().getModelId())
.call()
.getOrThrow();
return handleFormPost;
}
/** process a form post by first resetting all field validation errors (if there are some) /** process a form post by first resetting all field validation errors (if there are some)
* then collecting all input data from the form by form-binding to a either a JSON string in * then collecting all input data from the form by form-binding to a either a JSON string in
* HTTP PUT case or to an form-URL-encoded string on HTTP POST case. And PUT or POST the data * HTTP PUT case or to an form-URL-encoded string on HTTP POST case. And PUT or POST the data
@ -136,7 +148,7 @@ public class FormHandle<T extends Entity> {
return true; return true;
} else { } else {
log.error("Unexpected error while trying to post form: {}", error.getMessage()); log.error("Unexpected error while trying to post form: {}", error.getMessage());
final EntityType resultType = this.post.getResultType(); final EntityType resultType = this.post.getEntityType();
if (resultType != null) { if (resultType != null) {
this.pageContext.notifySaveError(resultType, error); this.pageContext.notifySaveError(resultType, error);
} else { } else {

View file

@ -8,23 +8,28 @@
package ch.ethz.seb.sebserver.gui.service.page; package ch.ethz.seb.sebserver.gui.service.page;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.function.BooleanSupplier; import java.util.function.BooleanSupplier;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.eclipse.swt.SWT; import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite; import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.api.JSONMapper; import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
import ch.ethz.seb.sebserver.gbl.model.Activatable;
import ch.ethz.seb.sebserver.gbl.model.Entity; import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.Page; import ch.ethz.seb.sebserver.gbl.model.Page;
@ -42,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.RestCall;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; 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.AuthorizationContextHolder;
import ch.ethz.seb.sebserver.gui.table.EntityTable;
import ch.ethz.seb.sebserver.gui.table.TableBuilder; import ch.ethz.seb.sebserver.gui.table.TableBuilder;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@ -99,6 +105,45 @@ public interface PageService {
return action -> (currentState != null) ? currentState.gotoAction : action; return action -> (currentState != null) ? currentState.gotoAction : action;
} }
/** Get a page action execution function for switching the activity of currently selected
* entities from a given entity-table.
*
* @param table the entity table
* @param noSelectionText LocTextKey for missing selection message
* @return page action execution function for switching the activity */
<T extends Entity & Activatable> Function<PageAction, PageAction> activationToggleActionFunction(
EntityTable<T> table,
LocTextKey noSelectionText);
/** Get a message supplier to notify deactivation dependencies to the user for all given entities
*
* @param entities Set of entities to collect the dependencies for
* @return a message supplier to notify deactivation dependencies to the user */
<T extends Entity & Activatable> Supplier<LocTextKey> confirmDeactivation(final Set<? extends T> entities);
/** Get a message supplier to notify deactivation dependencies to the user for given entity
*
* @param entity the entity instance
* @return a message supplier to notify deactivation dependencies to the user */
default <T extends Entity & Activatable> Supplier<LocTextKey> confirmDeactivation(final T entity) {
return confirmDeactivation(new HashSet<>(Arrays.asList(entity)));
}
/** Get a message supplier to notify deactivation dependencies to the user for given entity table selection
*
* @param table the entity table
* @return a message supplier to notify deactivation dependencies to the user */
default <T extends Entity & Activatable> Supplier<LocTextKey> confirmDeactivation(final EntityTable<T> table) {
return () -> {
return confirmDeactivation(table
.getSelectedROWData()
.stream()
.filter(e -> e.isActive()) // NOTE: Activatable::isActive leads to an error here!?
.collect(Collectors.toSet()))
.get();
};
}
/** Publishes a given PageEvent to the current page tree /** Publishes a given PageEvent to the current page tree
* This goes through the page-tree and collects all listeners the are listen to * This goes through the page-tree and collects all listeners the are listen to
* the specified page event type. * the specified page event type.
@ -229,6 +274,16 @@ public interface PageService {
} }
} }
static void clearComposite(final Composite parent) {
if (parent == null) {
return;
}
for (final Control control : parent.getChildren()) {
control.dispose();
}
}
public class PageActionBuilder { public class PageActionBuilder {
private final PageService pageService; private final PageService pageService;
private final PageContext originalPageContext; private final PageContext originalPageContext;

View file

@ -115,7 +115,7 @@ public class ComposerServiceImpl implements ComposerService {
if (composer.validate(pageContext)) { if (composer.validate(pageContext)) {
PageUtils.clearComposite(pageContext.getParent()); PageService.clearComposite(pageContext.getParent());
try { try {
composer.compose(pageContext); composer.compose(pageContext);

View file

@ -10,9 +10,14 @@ package ch.ethz.seb.sebserver.gui.service.page.impl;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSession;
@ -22,8 +27,13 @@ import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.api.JSONMapper; import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
import ch.ethz.seb.sebserver.gbl.model.Activatable;
import ch.ethz.seb.sebserver.gbl.model.Entity; import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.Page; import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.gbl.util.Result;
@ -34,6 +44,7 @@ import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService; import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
import ch.ethz.seb.sebserver.gui.service.page.ComposerService; import ch.ethz.seb.sebserver.gui.service.page.ComposerService;
import ch.ethz.seb.sebserver.gui.service.page.PageContext; import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.PageMessageException;
import ch.ethz.seb.sebserver.gui.service.page.PageService; import ch.ethz.seb.sebserver.gui.service.page.PageService;
import ch.ethz.seb.sebserver.gui.service.page.PageStateDefinition.Type; import ch.ethz.seb.sebserver.gui.service.page.PageStateDefinition.Type;
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent; import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
@ -41,8 +52,10 @@ import ch.ethz.seb.sebserver.gui.service.page.event.ActionPublishEvent;
import ch.ethz.seb.sebserver.gui.service.page.event.PageEvent; import ch.ethz.seb.sebserver.gui.service.page.event.PageEvent;
import ch.ethz.seb.sebserver.gui.service.page.event.PageEventListener; import ch.ethz.seb.sebserver.gui.service.page.event.PageEventListener;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; 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.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder;
import ch.ethz.seb.sebserver.gui.table.EntityTable;
import ch.ethz.seb.sebserver.gui.table.TableBuilder; import ch.ethz.seb.sebserver.gui.table.TableBuilder;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@ -51,6 +64,11 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@GuiProfile @GuiProfile
public class PageServiceImpl implements PageService { public class PageServiceImpl implements PageService {
private static final LocTextKey CONFIRM_DEACTIVATION_NO_DEP_KEY =
new LocTextKey("sebserver.dialog.confirm.deactivation.noDependencies");
private static final String CONFIRM_DEACTIVATION_KEY = "sebserver.dialog.confirm.deactivation";
private static final Logger log = LoggerFactory.getLogger(PageServiceImpl.class); private static final Logger log = LoggerFactory.getLogger(PageServiceImpl.class);
private static final LocTextKey MSG_GO_AWAY_FROM_EDIT = private static final LocTextKey MSG_GO_AWAY_FROM_EDIT =
@ -183,6 +201,80 @@ public class PageServiceImpl implements PageService {
} }
} }
@Override
public <T extends Entity & Activatable> Supplier<LocTextKey> confirmDeactivation(final Set<? extends T> entities) {
final RestService restService = this.resourceService.getRestService();
return () -> {
if (entities == null || entities.isEmpty()) {
return null;
}
try {
final int dependencies = entities.stream()
.flatMap(entity -> {
final RestCall<Set<EntityKey>>.RestCallBuilder builder =
restService.<Set<EntityKey>> getBuilder(
entity.entityType(),
CallType.GET_DEPENDENCIES);
return builder
.withURIVariable(API.PARAM_MODEL_ID, String.valueOf(entity.getModelId()))
.withQueryParam(API.PARAM_BULK_ACTION_TYPE, BulkActionType.DEACTIVATE.name())
.call()
.getOrThrow().stream();
})
.collect(Collectors.toList())
.size();
if (dependencies > 0) {
return new LocTextKey(CONFIRM_DEACTIVATION_KEY, String.valueOf(dependencies));
} else {
return CONFIRM_DEACTIVATION_NO_DEP_KEY;
}
} catch (final Exception e) {
log.warn("Failed to get dependencyies. Error: {}", e.getMessage());
return new LocTextKey(CONFIRM_DEACTIVATION_KEY, "");
}
};
}
@Override
public <T extends Entity & Activatable> Function<PageAction, PageAction> activationToggleActionFunction(
final EntityTable<T> table,
final LocTextKey noSelectionText) {
return action -> {
final Set<T> selectedROWData = table.getSelectedROWData();
if (selectedROWData == null || selectedROWData.isEmpty()) {
throw new PageMessageException(noSelectionText);
}
final RestService restService = this.resourceService.getRestService();
final EntityType entityType = table.getEntityType();
final Collection<Exception> errors = new ArrayList<>();
for (final T entity : selectedROWData) {
if (entity.isActive()) {
restService.getBuilder(entityType, CallType.ACTIVATION_DEACTIVATE)
.withURIVariable(API.PARAM_MODEL_ID, entity.getModelId())
.call()
.onError(errors::add);
} else {
restService.getBuilder(entityType, CallType.ACTIVATION_ACTIVATE)
.withURIVariable(API.PARAM_MODEL_ID, entity.getModelId())
.call()
.onError(errors::add);
}
}
if (!errors.isEmpty()) {
// TODO notify message for user
}
return action;
};
}
private void exec(final PageAction pageAction, final Consumer<Result<PageAction>> callback) { private void exec(final PageAction pageAction, final Consumer<Result<PageAction>> callback) {
pageAction.applyAction(result -> { pageAction.applyAction(result -> {
if (!result.hasError()) { if (!result.hasError()) {

View file

@ -1,75 +0,0 @@
/*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gui.service.page.impl;
import java.util.Set;
import java.util.function.Supplier;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType;
import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
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;
public final class PageUtils {
private static final Logger log = LoggerFactory.getLogger(PageUtils.class);
public static void clearComposite(final Composite parent) {
if (parent == null) {
return;
}
for (final Control control : parent.getChildren()) {
control.dispose();
}
}
public static final Supplier<LocTextKey> confirmDeactivation(
final Entity entity,
final RestService restService) {
return () -> {
try {
final RestCall<Set<EntityKey>>.RestCallBuilder builder =
restService.<Set<EntityKey>> getBuilder(
entity.entityType(),
CallType.GET_DEPENDENCIES);
if (builder == null) {
throw new RuntimeException("No RestCall builder found for entity type: " + entity.entityType());
}
final Set<EntityKey> dependencies = builder
.withURIVariable(API.PARAM_MODEL_ID, String.valueOf(entity.getModelId()))
.withQueryParam(API.PARAM_BULK_ACTION_TYPE, BulkActionType.DEACTIVATE.name())
.call()
.getOrThrow();
final int size = dependencies.size();
if (size > 0) {
return new LocTextKey("sebserver.dialog.confirm.deactivation", String.valueOf(size));
} else {
return new LocTextKey("sebserver.dialog.confirm.deactivation.noDependencies");
}
} catch (final Exception e) {
log.info("Failed to get dependencyies for Entity: {} error: ", entity, e.getMessage());
return new LocTextKey("sebserver.dialog.confirm.deactivation", "");
}
};
}
}

View file

@ -94,7 +94,7 @@ public abstract class RestCall<T> {
return this; return this;
} }
public EntityType getResultType() { public EntityType getEntityType() {
if (this.typeKey != null) { if (this.typeKey != null) {
return this.typeKey.entityType; return this.typeKey.entityType;
} }

View file

@ -40,6 +40,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.util.MultiValueMap; import org.springframework.util.MultiValueMap;
import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Entity; import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.GrantEntity; import ch.ethz.seb.sebserver.gbl.model.GrantEntity;
@ -203,6 +204,14 @@ public class EntityTable<ROW extends Entity> {
this.sortOrder); this.sortOrder);
} }
public EntityType getEntityType() {
if (this.restCall != null) {
return this.restCall.getEntityType();
}
return null;
}
public PageContext getPageContext() { public PageContext getPageContext() {
if (this.pageContext == null) { if (this.pageContext == null) {
return null; return null;
@ -303,7 +312,7 @@ public class EntityTable<ROW extends Entity> {
return getRowData(item); return getRowData(item);
} }
public ROW getSelectedROWData() { public ROW getSingleSelectedROWData() {
final TableItem[] selection = this.table.getSelection(); final TableItem[] selection = this.table.getSelection();
if (selection == null || selection.length == 0) { if (selection == null || selection.length == 0) {
return null; return null;
@ -312,6 +321,18 @@ public class EntityTable<ROW extends Entity> {
return getRowData(selection[0]); return getRowData(selection[0]);
} }
public Set<ROW> getSelectedROWData() {
final TableItem[] selection = this.table.getSelection();
if (selection == null || selection.length == 0) {
return Collections.emptySet();
}
return Arrays.asList(selection)
.stream()
.map(this::getRowData)
.collect(Collectors.toSet());
}
public Set<EntityKey> getSelection() { public Set<EntityKey> getSelection() {
return getSelection(null); return getSelection(null);
} }

View file

@ -17,7 +17,7 @@ import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Label;
import ch.ethz.seb.sebserver.gbl.model.Page; import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gui.service.page.impl.PageUtils; import ch.ethz.seb.sebserver.gui.service.page.PageService;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
public class TableNavigator { public class TableNavigator {
@ -40,7 +40,7 @@ public class TableNavigator {
public Page<?> update(final Page<?> pageData) { public Page<?> update(final Page<?> pageData) {
// clear all // clear all
PageUtils.clearComposite(this.composite); PageService.clearComposite(this.composite);
if (pageData.isEmpty()) { if (pageData.isEmpty()) {
// show empty message // show empty message

View file

@ -24,7 +24,7 @@ import org.eclipse.swt.widgets.Listener;
import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.util.Tuple; import ch.ethz.seb.sebserver.gbl.util.Tuple;
import ch.ethz.seb.sebserver.gui.service.page.impl.PageUtils; import ch.ethz.seb.sebserver.gui.service.page.PageService;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
public final class MultiSelection extends Composite implements Selection { public final class MultiSelection extends Composite implements Selection {
@ -61,7 +61,7 @@ public final class MultiSelection extends Composite implements Selection {
final String selectionValue = getSelectionValue(); final String selectionValue = getSelectionValue();
this.selected.clear(); this.selected.clear();
this.labels.clear(); this.labels.clear();
PageUtils.clearComposite(this); PageService.clearComposite(this);
for (final Tuple<String> tuple : mapping) { for (final Tuple<String> tuple : mapping) {
final Label label = new Label(this, SWT.NONE); final Label label = new Label(this, SWT.NONE);

View file

@ -24,7 +24,7 @@ import org.eclipse.swt.widgets.Listener;
import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.util.Tuple; import ch.ethz.seb.sebserver.gbl.util.Tuple;
import ch.ethz.seb.sebserver.gui.service.page.impl.PageUtils; import ch.ethz.seb.sebserver.gui.service.page.PageService;
public final class MultiSelectionCheckbox extends Composite implements Selection { public final class MultiSelectionCheckbox extends Composite implements Selection {
@ -54,7 +54,7 @@ public final class MultiSelectionCheckbox extends Composite implements Selection
public void applyNewMapping(final List<Tuple<String>> mapping) { public void applyNewMapping(final List<Tuple<String>> mapping) {
final String selectionValue = getSelectionValue(); final String selectionValue = getSelectionValue();
this.checkboxes.clear(); this.checkboxes.clear();
PageUtils.clearComposite(this); PageService.clearComposite(this);
for (final Tuple<String> tuple : mapping) { for (final Tuple<String> tuple : mapping) {
final Button button = new Button(this, SWT.CHECK); final Button button = new Button(this, SWT.CHECK);

View file

@ -21,7 +21,7 @@ import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Listener;
import ch.ethz.seb.sebserver.gbl.util.Tuple; import ch.ethz.seb.sebserver.gbl.util.Tuple;
import ch.ethz.seb.sebserver.gui.service.page.impl.PageUtils; import ch.ethz.seb.sebserver.gui.service.page.PageService;
public final class RadioSelection extends Composite implements Selection { public final class RadioSelection extends Composite implements Selection {
@ -51,7 +51,7 @@ public final class RadioSelection extends Composite implements Selection {
public void applyNewMapping(final List<Tuple<String>> mapping) { public void applyNewMapping(final List<Tuple<String>> mapping) {
final String selectionValue = getSelectionValue(); final String selectionValue = getSelectionValue();
this.radioButtons.clear(); this.radioButtons.clear();
PageUtils.clearComposite(this); PageService.clearComposite(this);
for (final Tuple<String> tuple : mapping) { for (final Tuple<String> tuple : mapping) {
final Button button = new Button(this, SWT.RADIO); final Button button = new Button(this, SWT.RADIO);

View file

@ -82,6 +82,7 @@ public class WidgetFactory {
INACTIVE("inactive.png"), INACTIVE("inactive.png"),
TOGGLE_ON("toggle_on.png"), TOGGLE_ON("toggle_on.png"),
TOGGLE_OFF("toggle_off.png"), TOGGLE_OFF("toggle_off.png"),
SWITCH("switch.png"),
YES("yes.png"), YES("yes.png"),
NO("no.png"), NO("no.png"),
SAVE("save.png"), SAVE("save.png"),
@ -440,7 +441,7 @@ public class WidgetFactory {
} }
public Table tableLocalized(final Composite parent) { public Table tableLocalized(final Composite parent) {
final Table table = new Table(parent, SWT.SINGLE | SWT.NO_SCROLL); final Table table = new Table(parent, SWT.MULTI | SWT.NO_SCROLL);
this.polyglotPageService.injectI18n(table); this.polyglotPageService.injectI18n(table);
return table; return table;
} }

View file

@ -16,7 +16,7 @@ sebserver.gui.webservice.mock-lms-enabled=true
sebserver.gui.theme=css/sebserver.css sebserver.gui.theme=css/sebserver.css
sebserver.gui.list.page.size=20 sebserver.gui.list.page.size=15
sebserver.gui.date.displayformat=MM/dd/yyyy HH:mm sebserver.gui.date.displayformat=MM/dd/yyyy HH:mm
sebserver.gui.date.displayformat.timezone=|ZZ sebserver.gui.date.displayformat.timezone=|ZZ
sebserver.gui.multilingual=true sebserver.gui.multilingual=true

View file

@ -28,6 +28,7 @@ sebserver.overall.date.to=To
sebserver.overall.action.add=Add; sebserver.overall.action.add=Add;
sebserver.overall.action.remove=Remove sebserver.overall.action.remove=Remove
sebserver.overall.action.select=Please Select sebserver.overall.action.select=Please Select
sebserver.overall.action.toggle-activity=Switch Activity
sebserver.overall.types.activityType.CREATE=Create New sebserver.overall.types.activityType.CREATE=Create New
sebserver.overall.types.activityType.IMPORT=Import sebserver.overall.types.activityType.IMPORT=Import

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 B