diff --git a/pom.xml b/pom.xml
index c7d905e6..de4569e5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -152,10 +152,10 @@
ch/ethz/seb/sebserver/*
-
-
-
-
+
+
+
+
@@ -270,6 +270,11 @@
org.eclipse.rap.rwt
3.5.0
+
+ org.eclipse.rap
+ org.eclipse.rap.fileupload
+ 3.7.0
+
diff --git a/src/main/java/ch/ethz/seb/sebserver/SEBServer.java b/src/main/java/ch/ethz/seb/sebserver/SEBServer.java
index 7b9e03ee..ffa57ef9 100644
--- a/src/main/java/ch/ethz/seb/sebserver/SEBServer.java
+++ b/src/main/java/ch/ethz/seb/sebserver/SEBServer.java
@@ -12,6 +12,21 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration;
+/** SEB-Server (Safe Exam Browser Server) is a server component to maintain and support
+ * Exams running with SEB (Safe Exam Browser). TODO add link(s)
+ *
+ * SEB-Server uses Spring Boot as main framework is divided into two main components,
+ * a webservice component that implements the business logic, persistence management
+ * and defines a REST API to expose the services over HTTP. The second component is a
+ * GUI component built on RAP RWT/SWT that also uses Spring components to connect and use
+ * the webservice over HTTP. The two components are (implementation-wise) completely separated
+ * from each other by the Rest API and the webservice can also be used by another client.
+ * SEB-Server uses Spring's profiles to consequently separate sub-components of the webservice
+ * and GUI and can be used to start the components on separate servers or within the same
+ * server instance. Additional to the usual profiles like dev, prod, test there are combining
+ * profiles like dev-ws, dev-gui and prod-ws, prod-gui
+ *
+ * TODO documentation for presets to start all-in-one server or separated gui- and webservice- server */
@SpringBootApplication(exclude = {
// OAuth2ResourceServerAutoConfiguration.class,
UserDetailsServiceAutoConfiguration.class,
diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/api/API.java b/src/main/java/ch/ethz/seb/sebserver/gbl/api/API.java
index 3580a573..6ec6d19e 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gbl/api/API.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gbl/api/API.java
@@ -34,4 +34,9 @@ public class API {
public static final String INACTIVE_SUFFIX = "/inactive";
+ public static final String PATH_VAR_MODEL_ID_NAME = "modelId";
+ public static final String PATH_VAR_MODEL_ID = "/{" + PATH_VAR_MODEL_ID_NAME + "}";
+ public static final String PATH_VAR_ACTIVE = PATH_VAR_MODEL_ID + ACTIVE_SUFFIX;
+ public static final String PATH_VAR_INACTIVE = PATH_VAR_MODEL_ID + INACTIVE_SUFFIX;
+
}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/api/POSTMapper.java b/src/main/java/ch/ethz/seb/sebserver/gbl/api/POSTMapper.java
index 76e1732e..903e9843 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gbl/api/POSTMapper.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gbl/api/POSTMapper.java
@@ -8,14 +8,20 @@
package ch.ethz.seb.sebserver.gbl.api;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
+import java.util.Map;
import java.util.Set;
+import java.util.stream.Collectors;
import org.apache.commons.lang3.BooleanUtils;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
+import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import ch.ethz.seb.sebserver.gbl.util.Utils;
@@ -26,7 +32,23 @@ public class POSTMapper {
public POSTMapper(final MultiValueMap params) {
super();
- this.params = params;
+ this.params = new LinkedMultiValueMap<>();
+ if (params != null) {
+ for (final Map.Entry> entry : params.entrySet()) {
+ this.params.put(
+ entry.getKey(),
+ entry.getValue()
+ .stream()
+ .map(encoded -> {
+ try {
+ return URLDecoder.decode(encoded, "UTF-8");
+ } catch (final UnsupportedEncodingException e) {
+ return encoded;
+ }
+ })
+ .collect(Collectors.toList()));
+ }
+ }
}
public String getString(final String name) {
@@ -117,4 +139,10 @@ public class POSTMapper {
return Utils.toDateTime(value);
}
+ @SuppressWarnings("unchecked")
+ public T putIfAbsent(final String name, final String value) {
+ this.params.putIfAbsent(name, Arrays.asList(value));
+ return (T) this;
+ }
+
}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/content/Institution.java b/src/main/java/ch/ethz/seb/sebserver/gbl/authorization/EntityPrivileges.java
similarity index 74%
rename from src/main/java/ch/ethz/seb/sebserver/gui/service/page/content/Institution.java
rename to src/main/java/ch/ethz/seb/sebserver/gbl/authorization/EntityPrivileges.java
index c9cac7a3..1282a9f6 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/content/Institution.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gbl/authorization/EntityPrivileges.java
@@ -1,13 +1,13 @@
/*
* 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.content;
+package ch.ethz.seb.sebserver.gbl.authorization;
-public class Institution {
+public class EntityPrivileges {
}
diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/Privilege.java b/src/main/java/ch/ethz/seb/sebserver/gbl/authorization/Privilege.java
similarity index 90%
rename from src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/Privilege.java
rename to src/main/java/ch/ethz/seb/sebserver/gbl/authorization/Privilege.java
index 5e6afef1..e89b0dc7 100644
--- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/Privilege.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gbl/authorization/Privilege.java
@@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-package ch.ethz.seb.sebserver.webservice.servicelayer.authorization;
+package ch.ethz.seb.sebserver.gbl.authorization;
import ch.ethz.seb.sebserver.gbl.model.EntityType;
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
@@ -15,6 +15,8 @@ import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
* institutional rights and ownershipRights. */
public final class Privilege {
+ /** The RoleTypeKey defining the UserRole and EntityType for this Privilege */
+ public final RoleTypeKey roleTypeKey;
/** Defines a base-privilege type that defines the overall access for an entity-type */
public final PrivilegeType privilegeType;
/** Defines an institutional privilege type that defines the institutional restricted access for a
@@ -24,10 +26,12 @@ public final class Privilege {
public final PrivilegeType ownershipPrivilege;
public Privilege(
+ final RoleTypeKey roleTypeKey,
final PrivilegeType privilegeType,
final PrivilegeType institutionalPrivilege,
final PrivilegeType ownershipPrivilege) {
+ this.roleTypeKey = roleTypeKey;
this.privilegeType = privilegeType;
this.institutionalPrivilege = institutionalPrivilege;
this.ownershipPrivilege = ownershipPrivilege;
@@ -68,7 +72,7 @@ public final class Privilege {
}
/** A key that combines UserRole EntityType identity */
- static final class RoleTypeKey {
+ public static final class RoleTypeKey {
public final EntityType entityType;
public final UserRole userRole;
diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/authorization/PrivilegeLevel.java b/src/main/java/ch/ethz/seb/sebserver/gbl/authorization/PrivilegeLevel.java
new file mode 100644
index 00000000..4e2e11ff
--- /dev/null
+++ b/src/main/java/ch/ethz/seb/sebserver/gbl/authorization/PrivilegeLevel.java
@@ -0,0 +1,15 @@
+/*
+ * 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.gbl.authorization;
+
+public enum PrivilegeLevel {
+ BASE,
+ INSTITUTIONAL,
+ OWNERSHIP
+}
diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/PrivilegeType.java b/src/main/java/ch/ethz/seb/sebserver/gbl/authorization/PrivilegeType.java
similarity index 93%
rename from src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/PrivilegeType.java
rename to src/main/java/ch/ethz/seb/sebserver/gbl/authorization/PrivilegeType.java
index 9139c35e..b59da376 100644
--- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/PrivilegeType.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gbl/authorization/PrivilegeType.java
@@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-package ch.ethz.seb.sebserver.webservice.servicelayer.authorization;
+package ch.ethz.seb.sebserver.gbl.authorization;
/** Defines SEB-Server internal privilege types **/
public enum PrivilegeType {
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 d3bc93ff..67588d1d 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
@@ -22,6 +22,11 @@ public interface Entity extends ModelIdAware {
@JsonIgnore
String getName();
+ @JsonIgnore
+ default EntityKey getEntityKey() {
+ return new EntityKey(getModelId(), entityType());
+ }
+
public static EntityName toName(final Entity entity) {
return new EntityName(
entity.entityType(),
diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/EntityKey.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/EntityKey.java
index 259d8aab..5a287d6e 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/EntityKey.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/EntityKey.java
@@ -8,6 +8,8 @@
package ch.ethz.seb.sebserver.gbl.model;
+import javax.validation.constraints.NotNull;
+
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
@@ -15,8 +17,10 @@ import com.fasterxml.jackson.annotation.JsonProperty;
public class EntityKey {
@JsonProperty(value = "modelId", required = true)
+ @NotNull
public final String modelId;
@JsonProperty(value = "entityType", required = true)
+ @NotNull
public final EntityType entityType;
@JsonIgnore
public final boolean isIdPK;
@@ -26,6 +30,9 @@ public class EntityKey {
@JsonProperty(value = "modelId", required = true) final String modelId,
@JsonProperty(value = "entityType", required = true) final EntityType entityType) {
+ assert (modelId != null) : "modelId has null reference";
+ assert (entityType != null) : "entityType has null reference";
+
this.modelId = modelId;
this.entityType = entityType;
this.isIdPK = entityType != EntityType.USER;
diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/EntityProcessingReport.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/EntityProcessingReport.java
index 68a9c902..8d6b5580 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/EntityProcessingReport.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/EntityProcessingReport.java
@@ -12,11 +12,14 @@ import java.util.Collection;
import java.util.Set;
import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
import ch.ethz.seb.sebserver.gbl.util.Utils;
+@JsonIgnoreProperties(ignoreUnknown = true)
public class EntityProcessingReport {
@JsonProperty(value = "source", required = true)
@@ -37,6 +40,15 @@ public class EntityProcessingReport {
this.errors = Utils.immutableSetOf(errors);
}
+ @JsonIgnore
+ public EntityKey getSingleSource() {
+ if (!this.source.isEmpty()) {
+ return this.source.iterator().next();
+ }
+
+ return null;
+ }
+
public static final class ErrorEntry {
public final EntityKey entityKey;
diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/institution/Institution.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/institution/Institution.java
index 36133067..1ca2ac72 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/institution/Institution.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/institution/Institution.java
@@ -9,9 +9,11 @@
package ch.ethz.seb.sebserver.gbl.model.institution;
import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
@@ -21,6 +23,7 @@ import ch.ethz.seb.sebserver.gbl.model.Domain.INSTITUTION;
import ch.ethz.seb.sebserver.gbl.model.EntityType;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.GrantEntity;
+@JsonIgnoreProperties(ignoreUnknown = true)
public final class Institution implements GrantEntity, Activatable {
@JsonProperty(Domain.ATTR_ID)
@@ -32,7 +35,7 @@ public final class Institution implements GrantEntity, Activatable {
public final String name;
@JsonProperty(INSTITUTION.ATTR_URL_SUFFIX)
- @Size(min = 3, max = 255, message = "institution:urlSuffix:size:{min}:{max}:${validatedValue}")
+ @Pattern(regexp = "(^$|.{3,255})", message = "institution:urlSuffix:size:{min}:{max}:${validatedValue}")
public final String urlSuffix;
@JsonProperty(INSTITUTION.ATTR_LOGO_IMAGE)
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageContext.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageContext.java
index ea1bc436..63de0b8a 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageContext.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/PageContext.java
@@ -11,6 +11,7 @@ package ch.ethz.seb.sebserver.gui.service.page;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Shell;
+import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gui.service.page.action.Action;
import ch.ethz.seb.sebserver.gui.service.page.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.service.page.activity.ActivitySelection;
@@ -33,7 +34,8 @@ public interface PageContext {
public static final String PAGE_TEMPLATE_COMPOSER_NAME = "ATTR_PAGE_TEMPLATE_COMPOSER_NAME";
- public static final String INSTITUTION_ID = "INSTITUTION_ID";
+ public static final String READ_ONLY = "READ_ONLY";
+ public static final String CREATE_NEW = "CREATE_NEW";
public static final String ENTITY_ID = "ENTITY_ID";
public static final String PARENT_ENTITY_ID = "PARENT_ENTITY_ID";
@@ -55,8 +57,7 @@ public interface PageContext {
//
// public static final String AUTHORIZATION_CONTEXT = "AUTHORIZATION_CONTEXT";
// public static final String AUTHORIZATION_HEADER = "AUTHORIZATION_HEADER";
- public static final String AUTHORIZATION_FAILURE = "AUTHORIZATION_FAILURE";
- public static final String LGOUT_SUCCESS = "LGOUT_SUCCESS";
+// public static final String AUTHORIZATION_FAILURE = "AUTHORIZATION_FAILURE";
}
@@ -92,16 +93,30 @@ public interface PageContext {
* @param key the key of the attribute
* @param value the value of the attribute
* @return this PageContext instance (builder pattern) */
- PageContext withAttr(String key, String value);
+ PageContext withAttribute(String key, String value);
- PageContext withSelection(ActivitySelection selection);
+ default PageContext withSelection(final ActivitySelection selection) {
+ return withSelection(selection, true);
+ }
+
+ PageContext withSelection(ActivitySelection selection, boolean clearAttributes);
String getAttribute(String name);
String getAttribute(String name, String def);
+ EntityKey getEntityKey();
+
+ EntityKey getParentEntityKey();
+
+ PageContext withEntityKey(EntityKey entityKey);
+
+ PageContext withParentEntityKey(EntityKey entityKey);
+
boolean hasAttribute(String name);
+ PageContext removeAttribute(String name);
+
/** Publishes a given PageEvent to the current page tree
* This goes through the page-tree and collects all listeners the are listen to
* the specified page event type.
@@ -133,7 +148,7 @@ public interface PageContext {
* @param error the error as Throwable */
void notifyError(String errorMessage, Throwable error);
- void notifyError(Throwable error);
+ T notifyError(Throwable error);
T logoutOnError(Throwable error);
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/action/Action.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/action/Action.java
index 250bb662..dbf08893 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/action/Action.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/action/Action.java
@@ -9,6 +9,7 @@
package ch.ethz.seb.sebserver.gui.service.page.action;
import java.util.Set;
+import java.util.function.BooleanSupplier;
import java.util.function.Function;
import java.util.function.Supplier;
@@ -23,12 +24,13 @@ import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
import ch.ethz.seb.sebserver.gui.service.page.event.ActionPublishEvent;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
-public class Action implements Runnable {
+public final class Action implements Runnable {
private static final Logger log = LoggerFactory.getLogger(Action.class);
public final ActionDefinition definition;
String confirmationMessage;
+ BooleanSupplier confirmComdition = () -> true;
String successMessage;
boolean updateOnSelection;
@@ -49,7 +51,7 @@ public class Action implements Runnable {
@Override
public void run() {
- if (StringUtils.isNotBlank(this.confirmationMessage)) {
+ if (StringUtils.isNotBlank(this.confirmationMessage) && this.confirmComdition.getAsBoolean()) {
this.pageContext.applyConfirmDialog(
this.confirmationMessage,
() -> exec());
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/action/ActionDefinition.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/action/ActionDefinition.java
index ae4e915f..3d43e4f1 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/action/ActionDefinition.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/action/ActionDefinition.java
@@ -16,16 +16,32 @@ public enum ActionDefinition {
"sebserver.institution.action.new",
IconButtonType.NEW_ACTION),
+ INSTITUTION_VIEW(
+ "sebserver.institution.action.view",
+ IconButtonType.VIEW_ACTION),
+
INSTITUTION_MODIFY(
"sebserver.institution.action.modify",
IconButtonType.MODIFY_ACTION),
+ INSTITUTION_CANCEL_MODIFY(
+ "sebserver.overall.action.modify.cancel",
+ IconButtonType.CANCEL_ACTION),
+
INSTITUTION_SAVE(
- "actions.modify.institution",
+ "sebserver.institution.action.save",
IconButtonType.SAVE_ACTION),
+ INSTITUTION_ACTIVATE(
+ "sebserver.institution.action.activate",
+ IconButtonType.ACTIVATE_ACTION),
+
+ INSTITUTION_DEACTIVATE(
+ "sebserver.institution.action.deactivate",
+ IconButtonType.DEACTIVATE_ACTION),
+
INSTITUTION_DELETE(
- "actions.delete.institution",
+ "sebserver.institution.action.modify",
IconButtonType.DELETE_ACTION),
LMS_SETUP_NEW(
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/action/InstitutionActions.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/action/InstitutionActions.java
index 40efa674..8862b808 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/action/InstitutionActions.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/action/InstitutionActions.java
@@ -13,67 +13,92 @@ import static ch.ethz.seb.sebserver.gui.service.page.activity.ActivitySelection.
import java.util.Collection;
import java.util.function.Function;
+import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.EntityType;
+import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
import ch.ethz.seb.sebserver.gbl.util.Result;
+import ch.ethz.seb.sebserver.gui.service.page.PageContext;
+import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
import ch.ethz.seb.sebserver.gui.service.page.PageMessageException;
+import ch.ethz.seb.sebserver.gui.service.page.activity.ActivitySelection;
import ch.ethz.seb.sebserver.gui.service.page.event.ActivitySelectionEvent;
-import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.NewInstitution;
-import ch.ethz.seb.sebserver.gui.service.table.EntityTable;
+import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.ActivateInstitution;
+import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.DeactivateInstitution;
public final class InstitutionActions {
- public static Result> newInstitution(final Action action) {
- return action.restService
- .getBuilder(NewInstitution.class)
- .call();
- }
-
- public static Function> editInstitution(final EntityTable> fromTable) {
- return action -> {
- final Collection selection = fromTable.getSelection();
- if (selection.isEmpty()) {
- return Result.ofError(new PageMessageException("sebserver.institution.info.pleaseSelect"));
- }
-
- final EntityKey entityKey = new EntityKey(
- selection.iterator().next(),
- EntityType.INSTITUTION);
- action.pageContext.publishPageEvent(new ActivitySelectionEvent(
- INSTITUTION_NODE
- .createSelection()
- .withEntity(entityKey)));
-
- return Result.of(entityKey);
+ public static Function postSaveAdapter(final PageContext pageContext) {
+ return inst -> {
+ goToInstitution(pageContext, inst.getModelId(), false);
+ return inst;
};
}
-// /** Use this higher-order function to create a new Institution action function.
-// *
-// * @return */
-// static Runnable newInstitution(final PageContext composerCtx, final RestServices restServices) {
-// return () -> {
-// final IdAndName newInstitutionId = restServices
-// .sebServerAPICall(NewInstitution.class)
-// .doAPICall()
-// .onErrorThrow("Unexpected Error");
-// composerCtx.notify(new ActionEvent(ActionDefinition.INSTITUTION_NEW, newInstitutionId));
-// };
-// }
-//
-// /** Use this higher-order function to create a delete Institution action function.
-// *
-// * @return */
-// static Runnable deleteInstitution(final PageContext composerCtx, final RestServices restServices,
-// final String instId) {
-// return () -> {
-// restServices
-// .sebServerAPICall(DeleteInstitution.class)
-// .attribute(AttributeKeys.INSTITUTION_ID, instId)
-// .doAPICall()
-// .onErrorThrow("Unexpected Error");
-// composerCtx.notify(new ActionEvent(ActionDefinition.INSTITUTION_DELETE, instId));
-// };
-// }
+ public static Result> newInstitution(final Action action) {
+ return Result.of(goToInstitution(action.pageContext, null, true));
+ }
+
+ public static Result> viewInstitution(final Action action) {
+ return fromInstitution(action, false);
+ }
+
+ public static Result> editInstitutionFromList(final Action action) {
+ return fromInstitution(action, true);
+ }
+
+ public static Result> editInstitution(final Action action) {
+ return Result.of(goToInstitution(
+ action.pageContext,
+ action.pageContext.getAttribute(AttributeKeys.ENTITY_ID),
+ true));
+ }
+
+ public static Result> cancelEditInstitution(final Action action) {
+ return Result.of(goToInstitution(
+ action.pageContext,
+ action.pageContext.getAttribute(AttributeKeys.ENTITY_ID),
+ false));
+ }
+
+ public static Result> activateInstitution(final Action action) {
+ return action.restService
+ .getBuilder(ActivateInstitution.class)
+ .withURIVariable(
+ API.PATH_VAR_MODEL_ID_NAME,
+ action.pageContext.getAttribute(AttributeKeys.ENTITY_ID))
+ .call()
+ .map(report -> goToInstitution(action.pageContext, report.getSingleSource().modelId, false));
+ }
+
+ public static Result> deactivateInstitution(final Action action) {
+ return action.restService
+ .getBuilder(DeactivateInstitution.class)
+ .withURIVariable(
+ API.PATH_VAR_MODEL_ID_NAME,
+ action.pageContext.getAttribute(AttributeKeys.ENTITY_ID))
+ .call()
+ .map(report -> goToInstitution(action.pageContext, report.getSingleSource().modelId, false));
+ }
+
+ private static Result> fromInstitution(final Action action, final boolean edit) {
+ final Collection selection = action.selectionSupplier.get();
+ if (selection.isEmpty()) {
+ return Result.ofError(new PageMessageException("sebserver.institution.info.pleaseSelect"));
+ }
+
+ return Result.of(goToInstitution(action.pageContext, selection.iterator().next(), edit));
+ }
+
+ private static ActivitySelection goToInstitution(final PageContext pageContext, final String modelId,
+ final boolean edit) {
+ final ActivitySelection activitySelection = INSTITUTION_NODE
+ .createSelection()
+ .withEntity(new EntityKey(modelId, EntityType.INSTITUTION))
+ .withAttribute(AttributeKeys.READ_ONLY, String.valueOf(!edit))
+ .withAttribute(AttributeKeys.CREATE_NEW, (modelId != null) ? "false" : "true");
+ pageContext.publishPageEvent(new ActivitySelectionEvent(activitySelection));
+ return activitySelection;
+ }
}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/activity/ActivitiesPane.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/activity/ActivitiesPane.java
index 804be34b..76facaa7 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/activity/ActivitiesPane.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/activity/ActivitiesPane.java
@@ -35,7 +35,7 @@ import ch.ethz.seb.sebserver.gui.service.page.event.ActivitySelectionEvent;
import ch.ethz.seb.sebserver.gui.service.page.event.PageEventListener;
import ch.ethz.seb.sebserver.gui.service.page.impl.MainPageState;
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.service.widget.WidgetFactory;
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory.CustomVariant;
@@ -43,22 +43,25 @@ import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory.CustomVariant;
@Component
public class ActivitiesPane implements TemplateComposer {
+ private static final String ATTR_ACTIVITY_SELECTION = "ACTIVITY_SELECTION";
+
private final WidgetFactory widgetFactory;
private final RestService restService;
- private final AuthorizationContextHolder authorizationContextHolder;
+ private final CurrentUser currentUser;
+ // TODO are those really needed?
private final Map activityActionHandler =
new EnumMap<>(ActionDefinition.class);
public ActivitiesPane(
final WidgetFactory widgetFactory,
final RestService restService,
- final AuthorizationContextHolder authorizationContextHolder,
+ final CurrentUser currentUser,
final Collection activityActionHandler) {
this.widgetFactory = widgetFactory;
this.restService = restService;
- this.authorizationContextHolder = authorizationContextHolder;
+ this.currentUser = currentUser;
for (final ActivityActionHandler aah : activityActionHandler) {
this.activityActionHandler.put(aah.handlesAction(), aah);
@@ -67,10 +70,8 @@ public class ActivitiesPane implements TemplateComposer {
@Override
public void compose(final PageContext pageContext) {
- final UserInfo userInfo = this.authorizationContextHolder
- .getAuthorizationContext()
- .getLoggedInUser()
- .get(pageContext::logoutOnError);
+ final UserInfo userInfo = this.currentUser
+ .getOrHandleError(pageContext::logoutOnError);
final Label activities = this.widgetFactory.labelLocalized(
pageContext.getParent(),
@@ -80,8 +81,9 @@ public class ActivitiesPane implements TemplateComposer {
activitiesGridData.horizontalIndent = 20;
activities.setLayoutData(activitiesGridData);
- final Tree navigation =
- this.widgetFactory.treeLocalized(pageContext.getParent(), SWT.SINGLE | SWT.FULL_SELECTION);
+ final Tree navigation = this.widgetFactory.treeLocalized(
+ pageContext.getParent(),
+ SWT.SINGLE | SWT.FULL_SELECTION);
final GridData navigationGridData = new GridData(SWT.FILL, SWT.FILL, true, true);
navigationGridData.horizontalIndent = 10;
navigation.setLayoutData(navigationGridData);
@@ -96,7 +98,7 @@ public class ActivitiesPane implements TemplateComposer {
final TreeItem institutions = this.widgetFactory.treeItemLocalized(
navigation,
Activity.INSTITUTION_ROOT.title);
- ActivitySelection.inject(institutions, Activity.INSTITUTION_ROOT.createSelection());
+ injectActivitySelection(institutions, Activity.INSTITUTION_ROOT.createSelection());
// for (final EntityName inst : insitutionNames) {
// createInstitutionItem(institutions, inst);
@@ -106,7 +108,7 @@ public class ActivitiesPane implements TemplateComposer {
final TreeItem institutions = this.widgetFactory.treeItemLocalized(
navigation,
Activity.INSTITUTION_ROOT.title);
- ActivitySelection.inject(institutions, Activity.INSTITUTION_NODE.createSelection());
+ injectActivitySelection(institutions, Activity.INSTITUTION_NODE.createSelection());
// final EntityName inst = insitutionNames.iterator().next();
// createInstitutionItem(navigation, inst);
}
@@ -155,16 +157,20 @@ public class ActivitiesPane implements TemplateComposer {
navigation.addListener(SWT.Expand, this::handleExpand);
navigation.addListener(SWT.Selection, event -> handleSelection(pageContext, event));
-
navigation.setData(
PageEventListener.LISTENER_ATTRIBUTE_KEY,
new ActionEventListener() {
@Override
public void notify(final ActionEvent event) {
- final ActivityActionHandler aah =
- ActivitiesPane.this.activityActionHandler.get(event.actionDefinition);
- if (aah != null) {
- aah.notifyAction(event, navigation, pageContext);
+// final ActivityActionHandler aah =
+// ActivitiesPane.this.activityActionHandler.get(event.actionDefinition);
+// if (aah != null) {
+// aah.notifyAction(event, navigation, pageContext);
+// }
+ // on case of an Action with ActivitySelection, reset the MainPageState
+ if (event.source instanceof ActivitySelection) {
+ final MainPageState mainPageState = MainPageState.get();
+ mainPageState.activitySelection = (ActivitySelection) event.source;
}
}
});
@@ -172,11 +178,13 @@ public class ActivitiesPane implements TemplateComposer {
// page-selection on (re)load
final MainPageState mainPageState = MainPageState.get();
- if (mainPageState.activitySelection == null) {
- mainPageState.activitySelection = ActivitySelection.get(navigation.getItem(0));
+ if (mainPageState.activitySelection == null ||
+ mainPageState.activitySelection.activity == ActivitySelection.Activity.NONE) {
+ mainPageState.activitySelection = getActivitySelection(navigation.getItem(0));
}
pageContext.publishPageEvent(
new ActivitySelectionEvent(mainPageState.activitySelection));
+ navigation.select(navigation.getItem(0));
}
// private void runningExamExpand(final TreeItem item) {
@@ -202,7 +210,7 @@ public class ActivitiesPane implements TemplateComposer {
System.out.println("opened: " + treeItem);
- final ActivitySelection activity = ActivitySelection.get(treeItem);
+ final ActivitySelection activity = getActivitySelection(treeItem);
if (activity != null) {
activity.processExpand(treeItem);
}
@@ -214,7 +222,7 @@ public class ActivitiesPane implements TemplateComposer {
System.out.println("selected: " + treeItem);
final MainPageState mainPageState = MainPageState.get();
- final ActivitySelection activitySelection = ActivitySelection.get(treeItem);
+ final ActivitySelection activitySelection = getActivitySelection(treeItem);
if (mainPageState.activitySelection == null) {
mainPageState.activitySelection = Activity.NONE.createSelection();
}
@@ -239,7 +247,7 @@ public class ActivitiesPane implements TemplateComposer {
static void createInstitutionItem(final EntityName entityName, final TreeItem institution) {
institution.setText(entityName.name);
- ActivitySelection.inject(
+ injectActivitySelection(
institution,
Activity.INSTITUTION_NODE
.createSelection()
@@ -256,7 +264,7 @@ public class ActivitiesPane implements TemplateComposer {
}
for (final TreeItem item : items) {
- final ActivitySelection activitySelection = ActivitySelection.get(item);
+ final ActivitySelection activitySelection = getActivitySelection(item);
final String id = activitySelection.getEntityId();
if (activitySelection != null && activitySelection.activity == activity &&
(id == null || (objectId != null && objectId.equals(id)))) {
@@ -285,4 +293,12 @@ public class ActivitiesPane implements TemplateComposer {
expand(item.getParentItem());
}
+ public static ActivitySelection getActivitySelection(final TreeItem item) {
+ return (ActivitySelection) item.getData(ATTR_ACTIVITY_SELECTION);
+ }
+
+ public static void injectActivitySelection(final TreeItem item, final ActivitySelection selection) {
+ item.setData(ATTR_ACTIVITY_SELECTION, selection);
+ }
+
}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/activity/ActivitySelection.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/activity/ActivitySelection.java
index 29a7f7e9..03eabe17 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/activity/ActivitySelection.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/activity/ActivitySelection.java
@@ -20,6 +20,7 @@ import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.page.action.ActionPane;
+import ch.ethz.seb.sebserver.gui.service.page.content.InstitutionForm;
import ch.ethz.seb.sebserver.gui.service.page.content.InstitutionList;
import ch.ethz.seb.sebserver.gui.service.page.impl.TODOTemplate;
@@ -39,7 +40,7 @@ public class ActivitySelection {
ActionPane.class,
new LocTextKey("sebserver.activities.inst")),
INSTITUTION_NODE(
- TODOTemplate.class,
+ InstitutionForm.class,
ActionPane.class,
new LocTextKey("sebserver.activities.inst")),
//
@@ -84,8 +85,6 @@ public class ActivitySelection {
}
}
- private static final String ATTR_ACTIVITY_SELECTION = "ACTIVITY_SELECTION";
-
public final Activity activity;
final Map attributes;
Consumer expandFunction = EMPTY_FUNCTION;
@@ -114,6 +113,11 @@ public class ActivitySelection {
return this;
}
+ public ActivitySelection withAttribute(final String name, final String value) {
+ this.attributes.put(name, value);
+ return this;
+ }
+
public Map getAttributes() {
return Collections.unmodifiableMap(this.attributes);
}
@@ -134,12 +138,4 @@ public class ActivitySelection {
return this.attributes.get(AttributeKeys.ENTITY_ID);
}
- public static ActivitySelection get(final TreeItem item) {
- return (ActivitySelection) item.getData(ATTR_ACTIVITY_SELECTION);
- }
-
- public static void inject(final TreeItem item, final ActivitySelection selection) {
- item.setData(ATTR_ACTIVITY_SELECTION, selection);
- }
-
}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/content/InstitutionForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/content/InstitutionForm.java
new file mode 100644
index 00000000..fc09f1d6
--- /dev/null
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/content/InstitutionForm.java
@@ -0,0 +1,172 @@
+/*
+ * 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.content;
+
+import java.util.UUID;
+
+import org.apache.commons.lang3.BooleanUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Component;
+
+import ch.ethz.seb.sebserver.gbl.api.API;
+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.service.i18n.LocTextKey;
+import ch.ethz.seb.sebserver.gui.service.page.PageContext;
+import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
+import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
+import ch.ethz.seb.sebserver.gui.service.page.action.ActionDefinition;
+import ch.ethz.seb.sebserver.gui.service.page.action.InstitutionActions;
+import ch.ethz.seb.sebserver.gui.service.page.event.ActionEventListener;
+import ch.ethz.seb.sebserver.gui.service.page.form.FormHandle;
+import ch.ethz.seb.sebserver.gui.service.page.form.PageFormService;
+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.NewInstitution;
+import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.SaveInstitution;
+import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory;
+
+@Lazy
+@Component
+@GuiProfile
+public class InstitutionForm implements TemplateComposer {
+
+ private final PageFormService pageFormService;
+ private final RestService restService;
+
+ protected InstitutionForm(final PageFormService pageFormService, final RestService restService) {
+ this.pageFormService = pageFormService;
+ this.restService = restService;
+ }
+
+ @Override
+ public void compose(final PageContext pageContext) {
+ final WidgetFactory widgetFactory = this.pageFormService.getWidgetFactory();
+
+ final boolean readonly = BooleanUtils.toBoolean(
+ pageContext.getAttribute(AttributeKeys.READ_ONLY, "true"));
+ final boolean createNew = BooleanUtils.toBoolean(
+ pageContext.getAttribute(AttributeKeys.CREATE_NEW, "false"));
+
+ // get data or create new and handle error
+ Institution institution = null;
+ PageContext formContext = pageContext;
+
+ if (createNew) {
+ institution = this.restService
+ .getBuilder(NewInstitution.class)
+ .withQueryParam(Domain.INSTITUTION.ATTR_NAME, "[NEW-" + UUID.randomUUID() + "]")
+ .call()
+ .get(pageContext::notifyError);
+ formContext = pageContext.withEntityKey(institution.getEntityKey());
+ } else {
+ final String instId = pageContext.getAttribute(AttributeKeys.ENTITY_ID);
+ institution = this.restService
+ .getBuilder(GetInstitution.class)
+ .withURIVariable(API.PATH_VAR_MODEL_ID_NAME, instId)
+ .call()
+ .get(pageContext::notifyError);
+ }
+
+ if (institution == null) {
+ // TODO should here be a forward to institution list page for SEB Admin?
+ return;
+ }
+
+ // page grid
+ final Composite content = new Composite(formContext.getParent(), SWT.NONE);
+ final GridLayout contentLayout = new GridLayout();
+ contentLayout.marginLeft = 10;
+ content.setLayout(contentLayout);
+ content.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ // title
+ final Label pageTitle = widgetFactory.labelLocalizedTitle(
+ content, new LocTextKey(
+ "sebserver.institution.form.title",
+ institution.name));
+
+ pageTitle.setLayoutData(new GridData(SWT.TOP, SWT.LEFT, true, false));
+ ActionEventListener.injectListener(
+ pageTitle,
+ ActionDefinition.INSTITUTION_SAVE,
+ event -> {
+ final Entity entity = (Entity) event.source;
+ widgetFactory.injectI18n(pageTitle, new LocTextKey(
+ "sebserver.institution.form.title",
+ entity.getName()));
+ content.layout();
+ });
+
+ // The Institution form
+ final FormHandle formHandle = this.pageFormService.getBuilder(
+ formContext.copyOf(content), 4)
+ .readonly(readonly)
+ .putStaticValue("id", institution.getModelId())
+ .addTextField(
+ Domain.INSTITUTION.ATTR_NAME,
+ "sebserver.institution.form.name",
+ institution.name, 2)
+ .addEmptyCell()
+ .addTextField(
+ Domain.INSTITUTION.ATTR_URL_SUFFIX,
+ "sebserver.institution.form.urlSuffix",
+ institution.urlSuffix, 2)
+ .addEmptyCell()
+ .addImageUpload(
+ Domain.INSTITUTION.ATTR_LOGO_IMAGE,
+ "sebserver.institution.form.logoImage",
+ institution.logoImage, 2)
+ .addEmptyCell()
+ .addTextField(
+ Domain.INSTITUTION.ATTR_URL_SUFFIX,
+ "sebserver.institution.form.urlSuffix",
+ institution.urlSuffix, 2)
+ .buildFor(
+ this.restService.getRestCall(SaveInstitution.class),
+ InstitutionActions.postSaveAdapter(pageContext));
+
+ // propagate content actions to action-pane
+ if (readonly) {
+ formContext.createAction(ActionDefinition.INSTITUTION_NEW)
+ .withExec(InstitutionActions::newInstitution)
+ .publish()
+ .createAction(ActionDefinition.INSTITUTION_MODIFY)
+ .withExec(InstitutionActions::editInstitution)
+ .publish();
+ if (!institution.isActive()) {
+ formContext.createAction(ActionDefinition.INSTITUTION_ACTIVATE)
+ .withExec(InstitutionActions::activateInstitution)
+ .publish();
+ } else {
+ formContext.createAction(ActionDefinition.INSTITUTION_DEACTIVATE)
+ .withExec(InstitutionActions::deactivateInstitution)
+ .publish();
+ }
+ } else {
+ formContext.createAction(ActionDefinition.INSTITUTION_SAVE)
+ .withExec(formHandle::postChanges)
+ .publish()
+ .createAction(ActionDefinition.INSTITUTION_CANCEL_MODIFY)
+ .withExec(InstitutionActions::cancelEditInstitution)
+ .withConfirm("sebserver.overall.action.modify.cancel.confirm")
+ .publish();
+
+ }
+
+ }
+
+}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/content/InstitutionList.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/content/InstitutionList.java
index c7b121b6..33b834fa 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/content/InstitutionList.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/content/InstitutionList.java
@@ -83,8 +83,13 @@ public class InstitutionList implements TemplateComposer {
pageContext.createAction(ActionDefinition.INSTITUTION_NEW)
.withExec(InstitutionActions::newInstitution)
.publish()
+ .createAction(ActionDefinition.INSTITUTION_VIEW)
+ .withSelectionSupplier(table::getSelection)
+ .withExec(InstitutionActions::viewInstitution)
+ .publish()
.createAction(ActionDefinition.INSTITUTION_MODIFY)
- .withExec(InstitutionActions.editInstitution(table))
+ .withSelectionSupplier(table::getSelection)
+ .withExec(InstitutionActions::editInstitutionFromList)
.publish();
}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/event/ActionEventListener.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/event/ActionEventListener.java
index 14f302e2..b018c425 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/event/ActionEventListener.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/event/ActionEventListener.java
@@ -22,14 +22,15 @@ public interface ActionEventListener extends PageEventListener {
return type == ActionEvent.class;
}
- static ActionEventListener of(final Consumer eventConsumer) {
- return new ActionEventListener() {
- @Override
- public void notify(final ActionEvent event) {
- eventConsumer.accept(event);
- }
- };
- }
+// static ActionEventListener of(final Consumer eventConsumer) {
+// return new ActionEventListener() {
+// @Override
+// public void notify(final ActionEvent event) {
+// eventConsumer.accept(event);
+// }
+// };
+// }
+//
static ActionEventListener of(
final Predicate predicate,
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/form/Form.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/form/Form.java
index 0c754a8b..7d07f9c3 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/form/Form.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/form/Form.java
@@ -27,7 +27,9 @@ import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
+import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.FormBinding;
+import ch.ethz.seb.sebserver.gui.service.widget.ImageUpload;
import ch.ethz.seb.sebserver.gui.service.widget.SingleSelection;
public final class Form implements FormBinding {
@@ -40,9 +42,17 @@ public final class Form implements FormBinding {
private final Map> subLists = new LinkedHashMap<>();
private final Map> groups = new LinkedHashMap<>();
- Form(final JSONMapper jsonMapper) {
+ private final EntityKey entityKey;
+
+ Form(final JSONMapper jsonMapper, final EntityKey entityKey) {
this.jsonMapper = jsonMapper;
this.objectRoot = this.jsonMapper.createObjectNode();
+ this.entityKey = entityKey;
+ }
+
+ @Override
+ public EntityKey entityKey() {
+ return this.entityKey;
}
@Override
@@ -91,6 +101,10 @@ public final class Form implements FormBinding {
}
}
+ public void putField(final String name, final Label label, final ImageUpload imageUpload) {
+ this.formFields.put(name, createAccessor(label, imageUpload));
+ }
+
public void putSubForm(final String name, final Form form) {
this.subForms.put(name, form);
}
@@ -190,6 +204,13 @@ public final class Form implements FormBinding {
@Override public void setValue(final String value) { singleSelection.select(value); }
};
}
+
+ private FormFieldAccessor createAccessor(final Label label, final ImageUpload imageUpload) {
+ return new FormFieldAccessor(label, imageUpload) {
+ @Override public String getValue() { return imageUpload.getImageBase64(); }
+ @Override public void setValue(final String value) { imageUpload.setImageBase64(value); }
+ };
+ }
//@formatter:on
public static abstract class FormFieldAccessor {
@@ -215,7 +236,6 @@ public final class Form implements FormBinding {
public void setError(final String errorTooltip) {
if (!this.hasError) {
this.control.setData(RWT.CUSTOM_VARIANT, "error");
- //this.control.setBackground(new Color(this.control.getDisplay(), 255, 0, 0, 50));
this.control.setToolTipText(errorTooltip);
this.hasError = true;
}
@@ -224,7 +244,6 @@ public final class Form implements FormBinding {
public void resetError() {
if (this.hasError) {
this.control.setData(RWT.CUSTOM_VARIANT, null);
- //this.control.setBackground(new Color(this.control.getDisplay(), 0, 0, 0, 0));
this.control.setToolTipText(null);
this.hasError = false;
}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/form/FormBuilder.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/form/FormBuilder.java
index 8a62427c..eb78f6de 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/form/FormBuilder.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/form/FormBuilder.java
@@ -10,6 +10,7 @@ package ch.ethz.seb.sebserver.gui.service.page.form;
import java.util.List;
import java.util.function.Consumer;
+import java.util.function.Function;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.swt.SWT;
@@ -23,10 +24,13 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
+import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.util.Tuple;
+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.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
+import ch.ethz.seb.sebserver.gui.service.widget.ImageUpload;
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory;
public class FormBuilder {
@@ -42,6 +46,7 @@ public class FormBuilder {
private boolean readonly = false;
FormBuilder(
+ final EntityKey entityKey,
final JSONMapper jsonMapper,
final WidgetFactory widgetFactory,
final PolyglotPageService polyglotPageService,
@@ -51,7 +56,7 @@ public class FormBuilder {
this.widgetFactory = widgetFactory;
this.polyglotPageService = polyglotPageService;
this.pageContext = pageContext;
- this.form = new Form(jsonMapper);
+ this.form = new Form(jsonMapper, entityKey);
this.formParent = new Composite(pageContext.getParent(), SWT.NONE);
final GridLayout layout = new GridLayout(rows, true);
@@ -181,8 +186,48 @@ public class FormBuilder {
return this;
}
- public FormHandle buildFor(final RestCall post) {
- return new FormHandle<>(this.pageContext, this.form, post, this.polyglotPageService.getI18nSupport());
+ public FormBuilder addImageUpload(
+ final String name,
+ final String label,
+ final String value,
+ final int span) {
+
+ return addImageUpload(name, label, value, span, null);
+ }
+
+ public FormBuilder addImageUpload(
+ final String name,
+ final String label,
+ final String value,
+ final int span,
+ final String group) {
+
+ final Label lab = this.widgetFactory.formLabelLocalized(this.formParent, label);
+ final ImageUpload imageUpload = this.widgetFactory.formImageUpload(
+ this.formParent,
+ value,
+ new LocTextKey("sebserver.overall.upload"),
+ span, 1);
+ if (this.readonly) {
+ imageUpload.setReadonly();
+ this.form.putField(name, lab, imageUpload);
+ } else {
+ this.form.putField(name, lab, imageUpload);
+ }
+
+ return this;
+ }
+
+ public FormHandle buildFor(
+ final RestCall post,
+ final Function postPostHandle) {
+
+ return new FormHandle<>(
+ this.pageContext,
+ this.form,
+ post,
+ (postPostHandle == null) ? Function.identity() : postPostHandle,
+ this.polyglotPageService.getI18nSupport());
}
}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/form/FormHandle.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/form/FormHandle.java
index 0827e24f..92ec7804 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/form/FormHandle.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/form/FormHandle.java
@@ -9,13 +9,16 @@
package ch.ethz.seb.sebserver.gui.service.page.form;
import java.util.function.Consumer;
+import java.util.function.Function;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
+import ch.ethz.seb.sebserver.gui.service.page.action.Action;
import ch.ethz.seb.sebserver.gui.service.page.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
import ch.ethz.seb.sebserver.gui.service.page.form.Form.FormFieldAccessor;
@@ -27,31 +30,38 @@ public class FormHandle {
private static final Logger log = LoggerFactory.getLogger(FormHandle.class);
- public static final String FIELD_VALIDATION_LOCTEXT_PREFIX = "org.sebserver.form.validation.fieldError.";
+ public static final String FIELD_VALIDATION_LOCTEXT_PREFIX = "sebserver.form.validation.fieldError.";
private final PageContext pageContext;
private final Form form;
private final RestCall post;
+ private final Function postPostHandle;
private final I18nSupport i18nSupport;
FormHandle(
final PageContext pageContext,
final Form form,
final RestCall post,
+ final Function postPostHandle,
final I18nSupport i18nSupport) {
this.pageContext = pageContext;
this.form = form;
this.post = post;
+ this.postPostHandle = postPostHandle;
this.i18nSupport = i18nSupport;
}
- public void doAPIPost(final ActionDefinition action) {
+ public final Result postChanges(final Action action) {
+ return doAPIPost(action.definition);
+ }
+
+ public Result doAPIPost(final ActionDefinition action) {
this.form.process(
name -> true,
fieldAccessor -> fieldAccessor.resetError());
- this.post
+ return this.post
.newBuilder()
.withFormBinding(this.form)
.call()
@@ -71,7 +81,8 @@ public class FormHandle {
log.error("Unexpected error while trying to post form: ", error);
this.pageContext.notifyError(error);
}
- });
+ })
+ .map(this.postPostHandle);
}
private final void showValidationError(
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/form/PageFormService.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/form/PageFormService.java
index e9d1c2dd..718ad67a 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/form/PageFormService.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/form/PageFormService.java
@@ -12,12 +12,15 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
+import ch.ethz.seb.sebserver.gbl.model.EntityKey;
+import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory;
@Lazy
@Component
+@GuiProfile
public class PageFormService {
private final JSONMapper jsonMapper;
@@ -34,8 +37,26 @@ public class PageFormService {
this.polyglotPageService = polyglotPageService;
}
- public FormBuilder getBuilder(final PageContext pageContext, final int rows) {
+ public FormBuilder getBuilder(
+ final PageContext pageContext,
+ final int rows) {
+
return new FormBuilder(
+ pageContext.getEntityKey(),
+ this.jsonMapper,
+ this.widgetFactory,
+ this.polyglotPageService,
+ pageContext,
+ rows);
+ }
+
+ public FormBuilder getBuilder(
+ final EntityKey entityKey,
+ final PageContext pageContext,
+ final int rows) {
+
+ return new FormBuilder(
+ entityKey,
this.jsonMapper,
this.widgetFactory,
this.polyglotPageService,
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/DefaultLoginPage.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/DefaultLoginPage.java
index d1bc02ae..1ab66970 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/DefaultLoginPage.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/DefaultLoginPage.java
@@ -29,7 +29,7 @@ public class DefaultLoginPage implements PageDefinition {
@Override
public PageContext applyPageContext(final PageContext pageContext) {
- return pageContext.withAttr(
+ return pageContext.withAttribute(
AttributeKeys.PAGE_TEMPLATE_COMPOSER_NAME,
SEBLogin.class.getName());
}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/DefaultMainPage.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/DefaultMainPage.java
index 6735963d..20428438 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/DefaultMainPage.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/DefaultMainPage.java
@@ -29,7 +29,7 @@ public class DefaultMainPage implements PageDefinition {
@Override
public PageContext applyPageContext(final PageContext pageContext) {
- return pageContext.withAttr(
+ return pageContext.withAttribute(
AttributeKeys.PAGE_TEMPLATE_COMPOSER_NAME,
SEBMainPage.class.getName());
}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/DefaultPageLayout.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/DefaultPageLayout.java
index 4bef2edb..49e9a9a1 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/DefaultPageLayout.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/DefaultPageLayout.java
@@ -21,6 +21,7 @@ import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.MessageBox;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
@@ -37,6 +38,7 @@ import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.WebserviceURIService;
+import ch.ethz.seb.sebserver.gui.service.widget.Message;
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory;
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory.CustomVariant;
@@ -138,8 +140,15 @@ public class DefaultPageLayout implements TemplateComposer {
MainPageState.clear();
// forward to login page with success message
- pageContext.forwardToLoginPage(
- pageContext.withAttr(AttributeKeys.LGOUT_SUCCESS, "true"));
+ pageContext.forwardToLoginPage(pageContext);
+
+ // show successful logout message
+ final MessageBox logoutSuccess = new Message(
+ pageContext.getShell(),
+ this.polyglotPageService.getI18nSupport().getText("sebserver.logout"),
+ this.polyglotPageService.getI18nSupport().getText("sebserver.logout.success.message"),
+ SWT.ICON_INFORMATION);
+ logoutSuccess.open(null);
});
}
}
@@ -184,7 +193,7 @@ public class DefaultPageLayout implements TemplateComposer {
logo.setBackgroundImage(new Image(pageContext.getShell().getDisplay(), input));
} catch (final Exception e) {
- log.warn("Get institutional logo failed: ", e);
+ log.warn("Get institutional logo failed: {}", e.getMessage());
logo.setData(RWT.CUSTOM_VARIANT, "bgLogo");
}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageContextImpl.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageContextImpl.java
index b5f21e18..8f7b2a11 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageContextImpl.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/PageContextImpl.java
@@ -24,6 +24,8 @@ import org.slf4j.LoggerFactory;
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
import ch.ethz.seb.sebserver.gbl.api.APIMessageError;
+import ch.ethz.seb.sebserver.gbl.model.EntityKey;
+import ch.ethz.seb.sebserver.gbl.model.EntityType;
import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
import ch.ethz.seb.sebserver.gui.service.page.ComposerService;
@@ -99,7 +101,7 @@ public class PageContextImpl implements PageContext {
this.composerService,
this.root,
parent,
- this.attributes);
+ new HashMap<>(this.attributes));
}
@Override
@@ -117,7 +119,7 @@ public class PageContextImpl implements PageContext {
}
@Override
- public PageContext withAttr(final String key, final String value) {
+ public PageContext withAttribute(final String key, final String value) {
final Map attrs = new HashMap<>();
attrs.putAll(this.attributes);
attrs.put(key, value);
@@ -131,13 +133,15 @@ public class PageContextImpl implements PageContext {
}
@Override
- public PageContext withSelection(final ActivitySelection selection) {
+ public PageContext withSelection(final ActivitySelection selection, final boolean clearAttributes) {
if (selection == null) {
return this;
}
final Map attrs = new HashMap<>();
- attrs.putAll(this.attributes);
+ if (!clearAttributes) {
+ attrs.putAll(this.attributes);
+ }
attrs.putAll(selection.getAttributes());
return new PageContextImpl(
@@ -163,11 +167,59 @@ public class PageContextImpl implements PageContext {
}
}
+ @Override
+ public EntityKey getEntityKey() {
+ if (hasAttribute(AttributeKeys.ENTITY_ID) && hasAttribute(AttributeKeys.ENTITY_TYPE)) {
+ return new EntityKey(
+ getAttribute(AttributeKeys.ENTITY_ID),
+ EntityType.valueOf(getAttribute(AttributeKeys.ENTITY_TYPE)));
+ }
+
+ return null;
+ }
+
+ @Override
+ public EntityKey getParentEntityKey() {
+ if (hasAttribute(AttributeKeys.PARENT_ENTITY_ID) && hasAttribute(AttributeKeys.PARENT_ENTITY_TYPE)) {
+ return new EntityKey(
+ getAttribute(AttributeKeys.PARENT_ENTITY_ID),
+ EntityType.valueOf(getAttribute(AttributeKeys.PARENT_ENTITY_TYPE)));
+ }
+
+ return null;
+ }
+
+ @Override
+ public PageContext withEntityKey(final EntityKey entityKey) {
+ return withAttribute(AttributeKeys.ENTITY_ID, entityKey.modelId)
+ .withAttribute(AttributeKeys.ENTITY_TYPE, entityKey.entityType.name());
+ }
+
+ @Override
+ public PageContext withParentEntityKey(final EntityKey entityKey) {
+ return withAttribute(AttributeKeys.PARENT_ENTITY_ID, entityKey.modelId)
+ .withAttribute(AttributeKeys.PARENT_ENTITY_TYPE, entityKey.entityType.name());
+ }
+
@Override
public boolean hasAttribute(final String name) {
return this.attributes.containsKey(name);
}
+ @Override
+ public PageContext removeAttribute(final String name) {
+ final Map attrs = new HashMap<>();
+ attrs.putAll(this.attributes);
+ attrs.remove(name);
+ return new PageContextImpl(
+ this.restService,
+ this.i18nSupport,
+ this.composerService,
+ this.root,
+ this.parent,
+ attrs);
+ }
+
@Override
@SuppressWarnings("unchecked")
public void publishPageEvent(final T event) {
@@ -282,8 +334,9 @@ public class PageContextImpl implements PageContext {
}
@Override
- public void notifyError(final Throwable error) {
+ public T notifyError(final Throwable error) {
notifyError(error.getMessage(), error);
+ return null;
}
@Override
@@ -298,9 +351,7 @@ public class PageContextImpl implements PageContext {
}
MainPageState.clear();
- forwardToLoginPage(this.withAttr(
- AttributeKeys.AUTHORIZATION_FAILURE,
- error.getMessage()));
+ forwardToLoginPage(this);
return null;
}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/SEBLogin.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/SEBLogin.java
index 4468f90f..4468ff5d 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/SEBLogin.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/SEBLogin.java
@@ -25,7 +25,6 @@ import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
-import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.SEBServerAuthorizationContext;
@@ -57,14 +56,15 @@ public class SEBLogin implements TemplateComposer {
public void compose(final PageContext pageContext) {
final Composite parent = pageContext.getParent();
- if (pageContext.hasAttribute((AttributeKeys.LGOUT_SUCCESS))) {
- final MessageBox logoutSuccess = new Message(
- pageContext.getShell(),
- this.i18nSupport.getText("sebserver.logout"),
- this.i18nSupport.getText("sebserver.logout.success.message"),
- SWT.ICON_INFORMATION);
- logoutSuccess.open(null);
- }
+// if (pageContext.hasAttribute((AttributeKeys.LGOUT_SUCCESS))) {
+// final MessageBox logoutSuccess = new Message(
+// pageContext.getShell(),
+// this.i18nSupport.getText("sebserver.logout"),
+// this.i18nSupport.getText("sebserver.logout.success.message"),
+// SWT.ICON_INFORMATION);
+// logoutSuccess.open(null);
+// pageContext = pageContext.removeAttribute(AttributeKeys.LGOUT_SUCCESS);
+// }
final Composite loginGroup = new Composite(parent, SWT.NONE);
final GridLayout rowLayout = new GridLayout();
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/push/ServerPushContext.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/push/ServerPushContext.java
new file mode 100644
index 00000000..d4309ce3
--- /dev/null
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/push/ServerPushContext.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2018 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.push;
+
+import java.util.function.Predicate;
+
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+
+/** ServerPushContext defines the state of a server push session.
+ *
+ * @author anhefti */
+public final class ServerPushContext {
+
+ private final Composite anchor;
+ private final Predicate runAgain;
+
+ public ServerPushContext(final Composite anchor) {
+ this(anchor, context -> false);
+ }
+
+ public ServerPushContext(
+ final Composite anchor,
+ final Predicate runAgain) {
+
+ this.anchor = anchor;
+ this.runAgain = runAgain;
+ }
+
+ public boolean runAgain() {
+ return this.runAgain.test(this);
+ }
+
+ public boolean isDisposed() {
+ return this.anchor.isDisposed();
+ }
+
+ public Display getDisplay() {
+ return this.anchor.getDisplay();
+ }
+
+ public Composite getAnchor() {
+ return this.anchor;
+ }
+
+ public void layout() {
+ this.anchor.pack();
+ this.anchor.layout();
+ this.anchor.getParent().layout(true, true);
+ }
+
+}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/push/ServerPushService.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/push/ServerPushService.java
new file mode 100644
index 00000000..f9892627
--- /dev/null
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/push/ServerPushService.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2018 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.push;
+
+import java.util.function.Consumer;
+
+import org.eclipse.rap.rwt.service.ServerPushSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Service;
+
+@Lazy
+@Service
+public class ServerPushService {
+
+ private static final Logger log = LoggerFactory.getLogger(ServerPushService.class);
+
+ public void runServerPush(
+ final ServerPushContext context,
+ final Consumer business,
+ final Consumer update) {
+
+ final ServerPushSession pushSession = new ServerPushSession();
+
+ pushSession.start();
+ final Thread bgThread = new Thread(() -> {
+ while (!context.isDisposed() && context.runAgain()) {
+
+ try {
+ log.trace("Call business on Server Push Session on: {}", Thread.currentThread().getName());
+ business.accept(context);
+ } catch (final Exception e) {
+ log.error("Unexpected error while do business for server push service", e);
+ if (context.runAgain()) {
+ continue;
+ } else {
+ return;
+ }
+ }
+
+ if (!context.isDisposed()) {
+
+ log.trace("Call update on Server Push Session on: {}", Thread.currentThread().getName());
+
+ context.getDisplay().asyncExec(() -> {
+ try {
+ update.accept(context);
+ } catch (final Exception e) {
+ log.warn(
+ "Failed to update on Server Push Session {}. It seems that the UISession is not available anymore. This may source from a connection interruption",
+ Thread.currentThread().getName(), e);
+ }
+ });
+ }
+ }
+
+ log.info("Stop Server Push Session on: {}", Thread.currentThread().getName());
+ try {
+ pushSession.stop();
+ } catch (final Exception e) {
+ log.warn(
+ "Failed to stop Server Push Session on: {}. It seems that the UISession is not available anymore. This may source from a connection interruption",
+ Thread.currentThread().getName(), e);
+ }
+
+ });
+
+ log.info("Start new Server Push Session on: {}", bgThread.getName());
+
+ bgThread.setDaemon(true);
+ bgThread.start();
+ }
+}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/FormBinding.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/FormBinding.java
index 5192e8d5..9193b177 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/FormBinding.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/FormBinding.java
@@ -8,8 +8,12 @@
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api;
+import ch.ethz.seb.sebserver.gbl.model.EntityKey;
+
public interface FormBinding {
+ EntityKey entityKey();
+
String getFormAsJson();
}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestCall.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestCall.java
index 2257b69f..efea4f8e 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestCall.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestCall.java
@@ -28,6 +28,7 @@ import org.springframework.web.client.RestClientResponseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
+import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
import ch.ethz.seb.sebserver.gbl.model.Entity;
@@ -111,6 +112,7 @@ public abstract class RestCall {
}));
} catch (final Exception e) {
log.error("Unexpected error-response while webservice API call for: {}", builder, e);
+ restCallError.errors.add(APIMessage.ErrorMessage.UNEXPECTED.of(e));
}
return Result.ofError(restCallError);
@@ -147,6 +149,7 @@ public abstract class RestCall {
public RestCallBuilder withBody(final Object body) {
if (body instanceof String) {
this.body = String.valueOf(body);
+ return this;
}
try {
@@ -189,8 +192,8 @@ public abstract class RestCall {
}
public RestCallBuilder withFormBinding(final FormBinding formBinding) {
- // TODO Auto-generated method stub
- return this;
+ return withURIVariable(API.PATH_VAR_MODEL_ID_NAME, formBinding.entityKey().modelId)
+ .withBody(formBinding.getFormAsJson());
}
public RestCallBuilder onlyActive(final boolean active) {
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/institution/ActivateInstitution.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/institution/ActivateInstitution.java
new file mode 100644
index 00000000..ac0a33a9
--- /dev/null
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/institution/ActivateInstitution.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution;
+
+import org.springframework.context.annotation.Lazy;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Component;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+
+import ch.ethz.seb.sebserver.gbl.api.API;
+import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
+import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
+import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
+
+@Lazy
+@Component
+@GuiProfile
+public class ActivateInstitution extends RestCall {
+
+ protected ActivateInstitution() {
+ super(
+ new TypeReference() {
+ },
+ HttpMethod.POST,
+ MediaType.APPLICATION_FORM_URLENCODED,
+ API.INSTITUTION_ENDPOINT + API.PATH_VAR_ACTIVE);
+ }
+
+}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/institution/DeactivateInstitution.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/institution/DeactivateInstitution.java
new file mode 100644
index 00000000..534874c6
--- /dev/null
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/institution/DeactivateInstitution.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution;
+
+import org.springframework.context.annotation.Lazy;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Component;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+
+import ch.ethz.seb.sebserver.gbl.api.API;
+import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
+import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
+import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
+
+@Lazy
+@Component
+@GuiProfile
+public class DeactivateInstitution extends RestCall {
+
+ protected DeactivateInstitution() {
+ super(
+ new TypeReference() {
+ },
+ HttpMethod.POST,
+ MediaType.APPLICATION_FORM_URLENCODED,
+ API.INSTITUTION_ENDPOINT + API.PATH_VAR_INACTIVE);
+ }
+
+}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/institution/GetInstitution.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/institution/GetInstitution.java
index 08e9c7c8..f748f883 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/institution/GetInstitution.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/institution/GetInstitution.java
@@ -31,7 +31,7 @@ public class GetInstitution extends RestCall {
},
HttpMethod.GET,
MediaType.APPLICATION_FORM_URLENCODED,
- API.INSTITUTION_ENDPOINT);
+ API.INSTITUTION_ENDPOINT + API.PATH_VAR_MODEL_ID);
}
}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/institution/SaveInstitution.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/institution/SaveInstitution.java
new file mode 100644
index 00000000..380d1713
--- /dev/null
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/institution/SaveInstitution.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution;
+
+import org.springframework.context.annotation.Lazy;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Component;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+
+import ch.ethz.seb.sebserver.gbl.api.API;
+import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
+import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
+import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
+
+@Lazy
+@Component
+@GuiProfile
+public class SaveInstitution extends RestCall {
+
+ protected SaveInstitution() {
+ super(
+ new TypeReference() {
+ },
+ HttpMethod.PUT,
+ MediaType.APPLICATION_JSON_UTF8,
+ API.INSTITUTION_ENDPOINT + API.PATH_VAR_MODEL_ID);
+ }
+
+}
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 0725da60..86f5bda8 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
@@ -8,6 +8,8 @@
package ch.ethz.seb.sebserver.gui.service.remote.webservice.auth;
+import java.util.function.Function;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
@@ -44,6 +46,18 @@ public class CurrentUser {
return null;
}
+ public UserInfo getOrHandleError(final Function errorHandler) {
+ if (isAvailable()) {
+ return this.authContext
+ .getLoggedInUser()
+ .get(errorHandler);
+ }
+
+ log.warn("Current user requested but no user is currently logged in");
+
+ return null;
+ }
+
public boolean isAvailable() {
updateContext();
return this.authContext != null && this.authContext.isLoggedIn();
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/table/EntityTable.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/table/EntityTable.java
index fa9d9851..fe7d258e 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/table/EntityTable.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/table/EntityTable.java
@@ -9,9 +9,9 @@
package ch.ethz.seb.sebserver.gui.service.table;
import java.util.Arrays;
-import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.Set;
import java.util.stream.Collectors;
import org.eclipse.swt.SWT;
@@ -25,6 +25,7 @@ import org.eclipse.swt.widgets.TableItem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gbl.util.Utils;
@@ -153,16 +154,16 @@ public class EntityTable extends Composite {
this.sortOrder);
}
- public Collection getSelection() {
+ public Set getSelection() {
final TableItem[] selection = this.table.getSelection();
if (selection == null) {
- return Collections.emptyList();
+ return Collections.emptySet();
}
return Arrays.asList(selection)
.stream()
.map(this::getRowDataId)
- .collect(Collectors.toList());
+ .collect(Collectors.toSet());
}
private void createTableColumns() {
@@ -227,7 +228,11 @@ public class EntityTable extends Composite {
// TODO set an image or HTML with checkbox
item.setText(index, String.valueOf(value));
} else {
- item.setText(index, String.valueOf(value));
+ if (value != null) {
+ item.setText(index, String.valueOf(value));
+ } else {
+ item.setText(index, Constants.EMPTY_NOTE);
+ }
}
index++;
}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/widget/ImageUpload.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/widget/ImageUpload.java
new file mode 100644
index 00000000..e686b967
--- /dev/null
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/widget/ImageUpload.java
@@ -0,0 +1,149 @@
+/*
+ * 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.widget;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+
+import org.apache.commons.codec.binary.Base64InputStream;
+import org.eclipse.rap.fileupload.FileDetails;
+import org.eclipse.rap.fileupload.FileUploadHandler;
+import org.eclipse.rap.fileupload.FileUploadReceiver;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.widgets.FileUpload;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ch.ethz.seb.sebserver.gui.service.push.ServerPushContext;
+import ch.ethz.seb.sebserver.gui.service.push.ServerPushService;
+
+public class ImageUpload extends Composite {
+
+ private static final long serialVersionUID = 368264811155804533L;
+
+ private static final Logger log = LoggerFactory.getLogger(ImageUpload.class);
+
+ private final ServerPushService serverPushService;
+
+ final Composite imageCanvas;
+ final FileUpload fileUpload;
+ private String imageBase64 = null;
+ private boolean loadNewImage = false;
+ private boolean imageLoaded = false;
+
+ ImageUpload(final Composite parent, final ServerPushService serverPushService) {
+ super(parent, SWT.NONE);
+ super.setLayout(new GridLayout(2, false));
+
+ this.serverPushService = serverPushService;
+
+ this.fileUpload = new FileUpload(this, SWT.NONE);
+ this.fileUpload.setText("Select File");
+ this.fileUpload.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));
+
+ this.imageCanvas = new Composite(this, SWT.NONE);
+ final GridData canvas = new GridData(SWT.FILL, SWT.FILL, true, true);
+ this.imageCanvas.setLayoutData(canvas);
+
+ final FileUploadHandler uploadHandler = new FileUploadHandler(new FileUploadReceiver() {
+
+ @Override
+ public void receive(final InputStream stream, final FileDetails details) throws IOException {
+ try {
+ final String contentType = details.getContentType();
+ if (contentType != null && contentType.startsWith("image")) {
+ ImageUpload.this.imageBase64 = Base64.getEncoder().encodeToString(stream.readAllBytes());
+ }
+ } catch (final Exception e) {
+ log.error("Error while trying to upload image", e);
+ } finally {
+ ImageUpload.this.imageLoaded = true;
+ stream.close();
+ }
+ }
+ });
+
+ this.fileUpload.addSelectionListener(new SelectionAdapter() {
+
+ private static final long serialVersionUID = -6776734104137568801L;
+
+ @Override
+ public void widgetSelected(final SelectionEvent event) {
+ ImageUpload.this.loadNewImage = true;
+ ImageUpload.this.imageLoaded = false;
+ ImageUpload.this.fileUpload.submit(uploadHandler.getUploadUrl());
+
+ ImageUpload.this.serverPushService.runServerPush(
+ new ServerPushContext(
+ ImageUpload.this,
+ runAgainContext -> {
+ final ImageUpload imageUpload = (ImageUpload) runAgainContext.getAnchor();
+ return imageUpload.loadNewImage && !imageUpload.imageLoaded;
+ }),
+ context -> {
+ try {
+ Thread.sleep(200);
+ } catch (final Exception e) {
+ e.printStackTrace();
+ }
+ },
+ context -> {
+ final ImageUpload imageUpload = (ImageUpload) context.getAnchor();
+ if (imageUpload.imageBase64 != null
+ && imageUpload.loadNewImage
+ && imageUpload.imageLoaded) {
+ final Base64InputStream input = new Base64InputStream(
+ new ByteArrayInputStream(
+ imageUpload.imageBase64.getBytes(StandardCharsets.UTF_8)),
+ false);
+
+ imageUpload.imageCanvas.setData(RWT.CUSTOM_VARIANT, "bgLogoNoImage");
+ imageUpload.imageCanvas.setBackgroundImage(new Image(context.getDisplay(), input));
+ context.layout();
+ imageUpload.layout();
+ imageUpload.loadNewImage = false;
+ }
+ });
+ }
+ });
+
+ }
+
+ public String getImageBase64() {
+ return this.imageBase64;
+ }
+
+ public void setImageBase64(final String imageBase64) {
+ if (imageBase64 == null) {
+ return;
+ }
+
+ this.imageBase64 = imageBase64;
+ final Base64InputStream input = new Base64InputStream(
+ new ByteArrayInputStream(imageBase64.getBytes(StandardCharsets.UTF_8)), false);
+ this.imageCanvas.setData(RWT.CUSTOM_VARIANT, "bgLogoNoImage");
+ this.imageCanvas.setBackgroundImage(new Image(super.getDisplay(), input));
+ }
+
+ public void setReadonly() {
+ this.fileUpload.setVisible(false);
+ this.fileUpload.setEnabled(false);
+ }
+
+}
diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/widget/WidgetFactory.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/widget/WidgetFactory.java
index c3194a71..e3056745 100644
--- a/src/main/java/ch/ethz/seb/sebserver/gui/service/widget/WidgetFactory.java
+++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/widget/WidgetFactory.java
@@ -16,6 +16,7 @@ import java.util.List;
import java.util.Locale;
import java.util.function.Consumer;
+import org.apache.commons.lang3.StringUtils;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Device;
@@ -39,6 +40,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
+import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
@@ -47,6 +49,7 @@ import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
+import ch.ethz.seb.sebserver.gui.service.push.ServerPushService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
import ch.ethz.seb.sebserver.gui.service.table.TableBuilder;
@@ -78,6 +81,10 @@ public class WidgetFactory {
MAXIMIZE("maximize.png"),
MINIMIZE("minimize.png"),
MODIFY_ACTION("editAction.png"),
+ CANCEL_ACTION("cancelEditAction.png"),
+ VIEW_ACTION("viewAction.png"),
+ ACTIVATE_ACTION("inactive.png"),
+ DEACTIVATE_ACTION("active.png"),
SAVE_ACTION("saveAction.png"),
NEW_ACTION("newAction.png"),
DELETE_ACTION("deleteAction.png"),
@@ -108,10 +115,15 @@ public class WidgetFactory {
private final PolyglotPageService polyglotPageService;
private final I18nSupport i18nSupport;
+ private final ServerPushService serverPushService;
+
+ public WidgetFactory(
+ final PolyglotPageService polyglotPageService,
+ final ServerPushService serverPushService) {
- public WidgetFactory(final PolyglotPageService polyglotPageService) {
this.polyglotPageService = polyglotPageService;
this.i18nSupport = polyglotPageService.getI18nSupport();
+ this.serverPushService = serverPushService;
}
public Button buttonLocalized(final Composite parent, final String locTextKey) {
@@ -265,7 +277,7 @@ public class WidgetFactory {
public Label formValueLabel(final Composite parent, final String value, final int span) {
final Label label = new Label(parent, SWT.NONE);
- label.setText(value);
+ label.setText((StringUtils.isNoneBlank(value)) ? value : Constants.EMPTY_NOTE);
final GridData gridData = new GridData(SWT.LEFT, SWT.CENTER, true, false, span, 1);
label.setLayoutData(gridData);
return label;
@@ -280,7 +292,9 @@ public class WidgetFactory {
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false, hspan, vspan);
gridData.heightHint = 15;
textInput.setLayoutData(gridData);
- textInput.setText(value);
+ if (value != null) {
+ textInput.setText(value);
+ }
return textInput;
}
@@ -325,6 +339,31 @@ public class WidgetFactory {
return combo;
}
+ public ImageUpload formImageUpload(
+ final Composite parent,
+ final String value,
+ final LocTextKey locTextKey,
+ final int hspan, final int vspan) {
+
+ final ImageUpload imageUpload = imageUploadLocalized(parent, locTextKey);
+ final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false, hspan, vspan);
+ imageUpload.setLayoutData(gridData);
+ imageUpload.setImageBase64(value);
+ return imageUpload;
+ }
+
+ public ImageUpload imageUploadLocalized(final Composite parent, final LocTextKey locTextKey) {
+ final ImageUpload imageUpload = new ImageUpload(parent, this.serverPushService);
+ injectI18n(imageUpload, locTextKey);
+ return imageUpload;
+ }
+
+ public void injectI18n(final ImageUpload imageUpload, final LocTextKey locTextKey) {
+ final Consumer imageUploadFunction = imageUploadFunction(locTextKey, this.i18nSupport);
+ imageUpload.setData(POLYGLOT_WIDGET_FUNCTION_KEY, imageUploadFunction);
+ imageUploadFunction.accept(imageUpload);
+ }
+
public void injectI18n(final Label label, final LocTextKey locTextKey) {
injectI18n(label, locTextKey, null);
}
@@ -409,6 +448,17 @@ public class WidgetFactory {
}
}
+ private static Consumer imageUploadFunction(
+ final LocTextKey locTextKey,
+ final I18nSupport i18nSupport) {
+
+ return imageUpload -> {
+ if (locTextKey != null) {
+ imageUpload.fileUpload.setText(i18nSupport.getText(locTextKey));
+ }
+ };
+ }
+
private static Consumer treeFunction(final I18nSupport i18nSupport) {
return tree -> updateLocale(tree.getItems(), i18nSupport);
}
diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/AuthorizationGrantRule.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/AuthorizationGrantRule.java
index 728fbdd3..9d61d8d8 100644
--- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/AuthorizationGrantRule.java
+++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/AuthorizationGrantRule.java
@@ -8,6 +8,7 @@
package ch.ethz.seb.sebserver.webservice.servicelayer.authorization;
+import ch.ethz.seb.sebserver.gbl.authorization.PrivilegeType;
import ch.ethz.seb.sebserver.gbl.model.EntityType;
/** Defines a authorization grant rule for a specified EntityType.
diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/AuthorizationGrantService.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/AuthorizationGrantService.java
index 394eec7c..fba56339 100644
--- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/AuthorizationGrantService.java
+++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/AuthorizationGrantService.java
@@ -11,6 +11,7 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.authorization;
import java.security.Principal;
import java.util.function.Predicate;
+import ch.ethz.seb.sebserver.gbl.authorization.PrivilegeType;
import ch.ethz.seb.sebserver.gbl.model.EntityType;
import ch.ethz.seb.sebserver.gbl.util.Result;
diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/AuthorizationGrantServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/AuthorizationGrantServiceImpl.java
index 5ebc5d52..1bed9fbc 100644
--- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/AuthorizationGrantServiceImpl.java
+++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/AuthorizationGrantServiceImpl.java
@@ -20,11 +20,13 @@ import javax.annotation.PostConstruct;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
+import ch.ethz.seb.sebserver.gbl.authorization.Privilege;
+import ch.ethz.seb.sebserver.gbl.authorization.PrivilegeType;
+import ch.ethz.seb.sebserver.gbl.authorization.Privilege.RoleTypeKey;
import ch.ethz.seb.sebserver.gbl.model.EntityType;
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.gbl.util.Result;
-import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.Privilege.RoleTypeKey;
@Lazy
@Service
@@ -430,6 +432,7 @@ public class AuthorizationGrantServiceImpl implements AuthorizationGrantService
public void create() {
final RoleTypeKey roleTypeKey = new RoleTypeKey(this.entityType, this.userRole);
final Privilege roleTypeGrant = new Privilege(
+ roleTypeKey,
this.basePrivilege,
this.institutionalPrivilege,
this.ownerPrivilege);
diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/PermissionDeniedException.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/PermissionDeniedException.java
index 91cee845..e82552f9 100644
--- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/PermissionDeniedException.java
+++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/PermissionDeniedException.java
@@ -8,6 +8,7 @@
package ch.ethz.seb.sebserver.webservice.servicelayer.authorization;
+import ch.ethz.seb.sebserver.gbl.authorization.PrivilegeType;
import ch.ethz.seb.sebserver.gbl.model.EntityType;
public class PermissionDeniedException extends RuntimeException {
diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ActivatableEntityController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ActivatableEntityController.java
index 8a3b0da7..ed4f13b0 100644
--- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ActivatableEntityController.java
+++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ActivatableEntityController.java
@@ -15,6 +15,7 @@ import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import ch.ethz.seb.sebserver.gbl.api.API;
+import ch.ethz.seb.sebserver.gbl.authorization.PrivilegeType;
import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
@@ -25,7 +26,6 @@ import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.UserRecordDynamic
import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationGrantService;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.GrantEntity;
-import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.PrivilegeType;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.UserService;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction.Type;
diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/EntityController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/EntityController.java
index f63d5b1e..f501c760 100644
--- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/EntityController.java
+++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/EntityController.java
@@ -28,8 +28,9 @@ import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import ch.ethz.seb.sebserver.gbl.Constants;
-import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
import ch.ethz.seb.sebserver.gbl.api.API;
+import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
+import ch.ethz.seb.sebserver.gbl.authorization.PrivilegeType;
import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
@@ -41,7 +42,6 @@ import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationGrantService;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.GrantEntity;
-import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.PrivilegeType;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.UserService;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction.Type;
@@ -103,10 +103,8 @@ public abstract class EntityController allRequestParams) {
checkReadPrivilege(institutionId);
- final FilterMap filterMap = new FilterMap(allRequestParams);
- allRequestParams.putIfAbsent(
- Entity.FILTER_ATTR_INSTITUTION,
- Arrays.asList(String.valueOf(institutionId)));
+ final FilterMap filterMap = new FilterMap(allRequestParams)
+ .putIfAbsent(Entity.FILTER_ATTR_INSTITUTION, String.valueOf(institutionId));
return this.paginationService.getPage(
pageNumber,
@@ -133,10 +131,8 @@ public abstract class EntityController allRequestParams) {
checkReadPrivilege(institutionId);
- final FilterMap filterMap = new FilterMap(allRequestParams);
- allRequestParams.putIfAbsent(
- Entity.FILTER_ATTR_INSTITUTION,
- Arrays.asList(String.valueOf(institutionId)));
+ final FilterMap filterMap = new FilterMap(allRequestParams)
+ .putIfAbsent(Entity.FILTER_ATTR_INSTITUTION, String.valueOf(institutionId));
return getAll(filterMap)
.getOrThrow()
@@ -211,10 +207,10 @@ public abstract class EntityController