GUI improvements

This commit is contained in:
anhefti 2020-02-13 16:46:36 +01:00
parent 8ea0def877
commit 25485b1fd4
28 changed files with 7160 additions and 6921 deletions

View file

@ -1,136 +1,137 @@
/* /*
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gbl; package ch.ethz.seb.sebserver.gbl;
import java.util.Collection; import java.util.Collection;
import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.graphics.RGB;
import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.DateTimeFormatter;
import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.ParameterizedTypeReference;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import ch.ethz.seb.sebserver.gbl.api.APIMessage; import ch.ethz.seb.sebserver.gbl.api.APIMessage;
import ch.ethz.seb.sebserver.gbl.api.authorization.Privilege; import ch.ethz.seb.sebserver.gbl.api.authorization.Privilege;
/** Global Constants used in SEB Server web-service as well as in web-gui component */ /** Global Constants used in SEB Server web-service as well as in web-gui component */
public final class Constants { public final class Constants {
public static final String DEFAULT_LANG_CODE = "en"; public static final String DEFAULT_LANG_CODE = "en";
public static final String DEFAULT_TIME_ZONE_CODE = "UTC"; public static final String DEFAULT_TIME_ZONE_CODE = "UTC";
public static final String TOOLTIP_TEXT_KEY_SUFFIX = ".tooltip";
public static final int SEB_FILE_HEADER_SIZE = 4;
public static final int JN_CRYPTOR_ITERATIONS = 10000; public static final int SEB_FILE_HEADER_SIZE = 4;
public static final int JN_CRYPTOR_VERSION_HEADER_SIZE = 1; public static final int JN_CRYPTOR_ITERATIONS = 10000;
public static final int JN_CRYPTOR_VERSION_HEADER_SIZE = 1;
public static final String TRUE_STRING = Boolean.TRUE.toString();
public static final String FALSE_STRING = Boolean.FALSE.toString(); public static final String TRUE_STRING = Boolean.TRUE.toString();
public static final String FALSE_STRING = Boolean.FALSE.toString();
public static final long SECOND_IN_MILLIS = 1000;
public static final long MINUTE_IN_MILLIS = 60 * SECOND_IN_MILLIS; public static final long SECOND_IN_MILLIS = 1000;
public static final long HOUR_IN_MILLIS = 60 * MINUTE_IN_MILLIS; public static final long MINUTE_IN_MILLIS = 60 * SECOND_IN_MILLIS;
public static final long DAY_IN_MILLIS = 24 * HOUR_IN_MILLIS; public static final long HOUR_IN_MILLIS = 60 * MINUTE_IN_MILLIS;
public static final long DAY_IN_MILLIS = 24 * HOUR_IN_MILLIS;
public static final Character CARRIAGE_RETURN = '\n';
public static final Character CURLY_BRACE_OPEN = '{'; public static final Character CARRIAGE_RETURN = '\n';
public static final Character CURLY_BRACE_CLOSE = '}'; public static final Character CURLY_BRACE_OPEN = '{';
public static final Character SQUARE_BRACE_OPEN = '['; public static final Character CURLY_BRACE_CLOSE = '}';
public static final Character SQUARE_BRACE_CLOSE = ']'; public static final Character SQUARE_BRACE_OPEN = '[';
public static final Character COLON = ':'; public static final Character SQUARE_BRACE_CLOSE = ']';
public static final Character SEMICOLON = ';'; public static final Character COLON = ':';
public static final Character PERCENTAGE = '%'; public static final Character SEMICOLON = ';';
public static final Character SLASH = '/'; public static final Character PERCENTAGE = '%';
public static final Character BACKSLASH = '\\'; public static final Character SLASH = '/';
public static final Character QUOTE = '\''; public static final Character BACKSLASH = '\\';
public static final Character DOUBLE_QUOTE = '"'; public static final Character QUOTE = '\'';
public static final Character COMMA = ','; public static final Character DOUBLE_QUOTE = '"';
public static final Character PIPE = '|'; public static final Character COMMA = ',';
public static final Character AMPERSAND = '&'; public static final Character PIPE = '|';
public static final Character EQUALITY_SIGN = '='; public static final Character AMPERSAND = '&';
public static final Character LIST_SEPARATOR_CHAR = COMMA; public static final Character EQUALITY_SIGN = '=';
public static final Character COMPLEX_VALUE_SEPARATOR = COLON; public static final Character LIST_SEPARATOR_CHAR = COMMA;
public static final Character COMPLEX_VALUE_SEPARATOR = COLON;
public static final String NULL = "null";
public static final String PERCENTAGE_STRING = Constants.PERCENTAGE.toString(); public static final String NULL = "null";
public static final String LIST_SEPARATOR = COMMA.toString(); public static final String PERCENTAGE_STRING = Constants.PERCENTAGE.toString();
public static final String EMBEDDED_LIST_SEPARATOR = PIPE.toString(); public static final String LIST_SEPARATOR = COMMA.toString();
public static final String NO_NAME = "NONE"; public static final String EMBEDDED_LIST_SEPARATOR = PIPE.toString();
public static final String EMPTY_NOTE = "--"; public static final String NO_NAME = "NONE";
public static final String FORM_URL_ENCODED_SEPARATOR = AMPERSAND.toString(); public static final String EMPTY_NOTE = "--";
public static final String FORM_URL_ENCODED_NAME_VALUE_SEPARATOR = EQUALITY_SIGN.toString(); public static final String FORM_URL_ENCODED_SEPARATOR = AMPERSAND.toString();
public static final String URL_PORT_SEPARATOR = COLON.toString(); public static final String FORM_URL_ENCODED_NAME_VALUE_SEPARATOR = EQUALITY_SIGN.toString();
public static final String URL_ADDRESS_SEPARATOR = COLON.toString() + SLASH.toString() + SLASH.toString(); public static final String URL_PORT_SEPARATOR = COLON.toString();
public static final String URL_PATH_SEPARATOR = SLASH.toString(); public static final String URL_ADDRESS_SEPARATOR = COLON.toString() + SLASH.toString() + SLASH.toString();
public static final String URL_PATH_SEPARATOR = SLASH.toString();
public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
public static final String TIME_ZONE_OFFSET_TAIL_FORMAT = "|ZZ"; public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
public static final String TIME_ZONE_OFFSET_TAIL_FORMAT = "|ZZ";
//public static final String DEFAULT_DIPLAY_DATE_TIME_FORMAT = "MM-dd-yyyy HH:mm:ss";
public static final String DEFAULT_DISPLAY_DATE_FORMAT = "MM-dd-yyyy"; //public static final String DEFAULT_DIPLAY_DATE_TIME_FORMAT = "MM-dd-yyyy HH:mm:ss";
public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss"; public static final String DEFAULT_DISPLAY_DATE_FORMAT = "MM-dd-yyyy";
public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
public static final DateTimeFormatter STANDARD_DATE_TIME_FORMATTER = DateTimeFormat
.forPattern(DEFAULT_DATE_TIME_FORMAT) public static final DateTimeFormatter STANDARD_DATE_TIME_FORMATTER = DateTimeFormat
.withZoneUTC(); .forPattern(DEFAULT_DATE_TIME_FORMAT)
.withZoneUTC();
public static final String XML_VERSION_HEADER =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"; public static final String XML_VERSION_HEADER =
public static final String XML_DOCTYPE_HEADER = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
"<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">"; public static final String XML_DOCTYPE_HEADER =
public static final String XML_PLIST_START_V1 = "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">";
"<plist version=\"1.0\">"; public static final String XML_PLIST_START_V1 =
public static final String XML_PLIST_END = "<plist version=\"1.0\">";
"</plist>"; public static final String XML_PLIST_END =
public static final String XML_DICT_START = "</plist>";
"<dict>"; public static final String XML_DICT_START =
public static final String XML_DICT_END = "<dict>";
"</dict>"; public static final String XML_DICT_END =
"</dict>";
public static final String XML_PLIST_NAME = "plist";
public static final String XML_PLIST_DICT_NAME = "dict"; public static final String XML_PLIST_NAME = "plist";
public static final String XML_PLIST_ARRAY_NAME = "array"; public static final String XML_PLIST_DICT_NAME = "dict";
public static final String XML_PLIST_KEY_NAME = "key"; public static final String XML_PLIST_ARRAY_NAME = "array";
public static final String XML_PLIST_BOOLEAN_TRUE = "true"; public static final String XML_PLIST_KEY_NAME = "key";
public static final String XML_PLIST_BOOLEAN_FALSE = "false"; public static final String XML_PLIST_BOOLEAN_TRUE = "true";
public static final String XML_PLIST_STRING = "string"; public static final String XML_PLIST_BOOLEAN_FALSE = "false";
public static final String XML_PLIST_DATA = "data"; public static final String XML_PLIST_STRING = "string";
public static final String XML_PLIST_INTEGER = "integer"; public static final String XML_PLIST_DATA = "data";
public static final String XML_PLIST_INTEGER = "integer";
public static final String OAUTH2_GRANT_TYPE_PASSWORD = "password";
public static final String OAUTH2_CLIENT_SECRET = "client_secret"; public static final String OAUTH2_GRANT_TYPE_PASSWORD = "password";
public static final String OAUTH2_GRANT_TYPE_REFRESH_TOKEN = "refresh_token"; public static final String OAUTH2_CLIENT_SECRET = "client_secret";
public static final String OAUTH2_GRANT_TYPE_CLIENT_CREDENTIALS = "client_credentials"; public static final String OAUTH2_GRANT_TYPE_REFRESH_TOKEN = "refresh_token";
public static final String OAUTH2_SCOPE_READ = "read"; public static final String OAUTH2_GRANT_TYPE_CLIENT_CREDENTIALS = "client_credentials";
public static final String OAUTH2_SCOPE_WRITE = "write"; public static final String OAUTH2_SCOPE_READ = "read";
public static final String OAUTH2_SCOPE_WRITE = "write";
public static final int RWT_MOUSE_BUTTON_1 = 1;
public static final int RWT_MOUSE_BUTTON_2 = 2; public static final int RWT_MOUSE_BUTTON_1 = 1;
public static final int RWT_MOUSE_BUTTON_3 = 3; public static final int RWT_MOUSE_BUTTON_2 = 2;
public static final int RWT_MOUSE_BUTTON_3 = 3;
public static final int GZIP_HEADER_LENGTH = 4;
public static final int GZIP_ID1 = 0x1F; public static final int GZIP_HEADER_LENGTH = 4;
public static final int GZIP_ID2 = 0x8B; public static final int GZIP_ID1 = 0x1F;
public static final int GZIP_CM = 8; public static final int GZIP_ID2 = 0x8B;
public static final int GZIP_CM = 8;
public static final RGB WHITE_RGB = new RGB(255, 255, 255);
public static final RGB BLACK_RGB = new RGB(0, 0, 0); public static final RGB WHITE_RGB = new RGB(255, 255, 255);
public static final RGB BLACK_RGB = new RGB(0, 0, 0);
public static final TypeReference<Collection<APIMessage>> TYPE_REFERENCE_API_MESSAGE =
new TypeReferenceAPIMessage(); public static final TypeReference<Collection<APIMessage>> TYPE_REFERENCE_API_MESSAGE =
public static final ParameterizedTypeReference<Collection<Privilege>> TYPE_REFERENCE_PRIVILEGES = new TypeReferenceAPIMessage();
new TypeReferencePrivileges(); public static final ParameterizedTypeReference<Collection<Privilege>> TYPE_REFERENCE_PRIVILEGES =
new TypeReferencePrivileges();
public static final class TypeReferenceAPIMessage extends TypeReference<Collection<APIMessage>> {
} public static final class TypeReferenceAPIMessage extends TypeReference<Collection<APIMessage>> {
}
public static final class TypeReferencePrivileges extends ParameterizedTypeReference<Collection<Privilege>> {
} public static final class TypeReferencePrivileges extends ParameterizedTypeReference<Collection<Privilege>> {
}
}
}

View file

@ -1,360 +1,361 @@
/* /*
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gbl.model.user; package ch.ethz.seb.sebserver.gbl.model.user;
import java.io.Serializable; import java.io.Serializable;
import java.util.Arrays; import java.util.Arrays;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.HashSet; import java.util.HashSet;
import java.util.Locale; import java.util.Locale;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.validation.constraints.Email; import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size; import javax.validation.constraints.Size;
import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.joda.time.DateTimeZone; import org.joda.time.DateTimeZone;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Domain.USER; import ch.ethz.seb.sebserver.gbl.model.Domain.USER;
import ch.ethz.seb.sebserver.gbl.model.Domain.USER_ROLE; import ch.ethz.seb.sebserver.gbl.model.Domain.USER_ROLE;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.util.Utils; import ch.ethz.seb.sebserver.gbl.util.Utils;
/** The user info domain model contains primary user information /** The user info domain model contains primary user information
* *
* This domain model is annotated and fully serializable and deserializable * This domain model is annotated and fully serializable and deserializable
* to and from JSON within the Jackson library. * to and from JSON within the Jackson library.
* *
* This domain model is immutable and thread-save */ * This domain model is immutable and thread-save */
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
public final class UserInfo implements UserAccount, Serializable { public final class UserInfo implements UserAccount, Serializable {
private static final long serialVersionUID = 2526446136264377808L; private static final long serialVersionUID = 2526446136264377808L;
public static final String FILTER_ATTR_USER_NAME = "username"; public static final String FILTER_ATTR_USER_NAME = "username";
public static final String FILTER_ATTR_EMAIL = "email"; public static final String FILTER_ATTR_EMAIL = "email";
public static final String FILTER_ATTR_LANGUAGE = "language"; public static final String FILTER_ATTR_LANGUAGE = "language";
public static final String FILTER_ATTR_ROLE = "role"; public static final String FILTER_ATTR_ROLE = "role";
/** The user's UUID */ /** The user's UUID */
@JsonProperty(USER.ATTR_UUID) @JsonProperty(USER.ATTR_UUID)
public final String uuid; public final String uuid;
/** The foreign key identifier to the institution where the User belongs to */ /** The foreign key identifier to the institution where the User belongs to */
@NotNull @NotNull(message = "user:institutionId:notNull")
@JsonProperty(USER.ATTR_INSTITUTION_ID) @JsonProperty(USER.ATTR_INSTITUTION_ID)
public final Long institutionId; public final Long institutionId;
@JsonProperty(USER.ATTR_CREATION_DATE) @JsonProperty(USER.ATTR_CREATION_DATE)
public final DateTime creationDate; public final DateTime creationDate;
/** First name of the user */ /** First name of the user */
@NotNull(message = "user:name:notNull") @NotNull(message = "user:name:notNull")
@Size(min = 3, max = 255, message = "user:name:size:{min}:{max}:${validatedValue}") @Size(max = 255, message = "user:name:size:{min}:{max}:${validatedValue}")
@JsonProperty(USER.ATTR_NAME) @JsonProperty(USER.ATTR_NAME)
public final String name; public final String name;
/** Surname of the user */ /** Surname of the user */
@Size(max = 255, message = "user:surname:size:{min}:{max}:${validatedValue}") @NotNull(message = "user:surname:notNull")
@JsonProperty(USER.ATTR_SURNAME) @Size(max = 255, message = "user:surname:size:{min}:{max}:${validatedValue}")
public final String surname; @JsonProperty(USER.ATTR_SURNAME)
public final String surname;
/** The internal user name */
@NotNull(message = "user:username:notNull") /** The internal user name */
@Size(min = 3, max = 255, message = "user:username:size:{min}:{max}:${validatedValue}") @NotNull(message = "user:username:notNull")
@JsonProperty(USER.ATTR_USERNAME) @Size(min = 3, max = 255, message = "user:username:size:{min}:{max}:${validatedValue}")
public final String username; @JsonProperty(USER.ATTR_USERNAME)
public final String username;
/** E-mail address of the user */
@Email(message = "user:email:email:_:_:${validatedValue}") /** E-mail address of the user */
@JsonProperty(USER.ATTR_EMAIL) @Email(message = "user:email:email:_:_:${validatedValue}")
public final String email; @JsonProperty(USER.ATTR_EMAIL)
public final String email;
/** Indicates whether this user is still active or not */
@NotNull /** Indicates whether this user is still active or not */
@JsonProperty(USER.ATTR_ACTIVE) @NotNull
public final Boolean active; @JsonProperty(USER.ATTR_ACTIVE)
public final Boolean active;
/** The users locale */
@NotNull(message = "user:language:notNull") /** The users locale */
@JsonProperty(USER.ATTR_LANGUAGE) @NotNull(message = "user:language:notNull")
public final Locale language; @JsonProperty(USER.ATTR_LANGUAGE)
public final Locale language;
/** The users time zone */
@NotNull(message = "user:timeZone:notNull") /** The users time zone */
@JsonProperty(USER.ATTR_TIMEZONE) @NotNull(message = "user:timeZone:notNull")
public final DateTimeZone timeZone; @JsonProperty(USER.ATTR_TIMEZONE)
public final DateTimeZone timeZone;
/** The users roles in a unmodifiable set. Is never null */
@NotNull(message = "user:userRoles:notNull") /** The users roles in a unmodifiable set. Is never null */
@NotEmpty(message = "user:userRoles:notNull") @NotNull(message = "user:userRoles:notNull")
@JsonProperty(USER_ROLE.REFERENCE_NAME) @NotEmpty(message = "user:userRoles:notNull")
public final Set<String> roles; @JsonProperty(USER_ROLE.REFERENCE_NAME)
public final Set<String> roles;
@JsonCreator
public UserInfo( @JsonCreator
@JsonProperty(USER.ATTR_UUID) final String uuid, public UserInfo(
@JsonProperty(USER.ATTR_INSTITUTION_ID) final Long institutionId, @JsonProperty(USER.ATTR_UUID) final String uuid,
@JsonProperty(USER.ATTR_CREATION_DATE) final DateTime creationDate, @JsonProperty(USER.ATTR_INSTITUTION_ID) final Long institutionId,
@JsonProperty(USER.ATTR_NAME) final String name, @JsonProperty(USER.ATTR_CREATION_DATE) final DateTime creationDate,
@JsonProperty(USER.ATTR_SURNAME) final String surname, @JsonProperty(USER.ATTR_NAME) final String name,
@JsonProperty(USER.ATTR_USERNAME) final String username, @JsonProperty(USER.ATTR_SURNAME) final String surname,
@JsonProperty(USER.ATTR_EMAIL) final String email, @JsonProperty(USER.ATTR_USERNAME) final String username,
@JsonProperty(USER.ATTR_ACTIVE) final Boolean active, @JsonProperty(USER.ATTR_EMAIL) final String email,
@JsonProperty(USER.ATTR_LANGUAGE) final Locale language, @JsonProperty(USER.ATTR_ACTIVE) final Boolean active,
@JsonProperty(USER.ATTR_TIMEZONE) final DateTimeZone timeZone, @JsonProperty(USER.ATTR_LANGUAGE) final Locale language,
@JsonProperty(USER_ROLE.REFERENCE_NAME) final Set<String> roles) { @JsonProperty(USER.ATTR_TIMEZONE) final DateTimeZone timeZone,
@JsonProperty(USER_ROLE.REFERENCE_NAME) final Set<String> roles) {
this.uuid = uuid;
this.institutionId = institutionId; this.uuid = uuid;
this.creationDate = creationDate; this.institutionId = institutionId;
this.name = name; this.creationDate = creationDate;
this.surname = surname; this.name = name;
this.username = username; this.surname = surname;
this.email = email; this.username = username;
this.active = BooleanUtils.isTrue(active); this.email = email;
this.language = language; this.active = BooleanUtils.isTrue(active);
this.timeZone = timeZone; this.language = language;
this.roles = Utils.immutableSetOf(roles); this.timeZone = timeZone;
} this.roles = Utils.immutableSetOf(roles);
}
@Override
public EntityType entityType() { @Override
return EntityType.USER; public EntityType entityType() {
} return EntityType.USER;
}
@Override
public String getModelId() { @Override
return this.uuid; public String getModelId() {
} return this.uuid;
}
public String getUuid() {
return this.uuid; public String getUuid() {
} return this.uuid;
}
@Override
public DateTime getCreationDate() { @Override
return this.creationDate; public DateTime getCreationDate() {
} return this.creationDate;
}
@Override
public Long getInstitutionId() { @Override
return this.institutionId; public Long getInstitutionId() {
} return this.institutionId;
}
@Override
public String getOwnerId() { @Override
return this.uuid; public String getOwnerId() {
} return this.uuid;
}
@Override
public String getName() { @Override
return this.name; public String getName() {
} return this.name;
}
@Override
public String getSurname() { @Override
return this.surname; public String getSurname() {
} return this.surname;
}
@Override
public String getUsername() { @Override
return this.username; public String getUsername() {
} return this.username;
}
@Override
public String getEmail() { @Override
return this.email; public String getEmail() {
} return this.email;
}
@Override
public Boolean getActive() { @Override
return this.active; public Boolean getActive() {
} return this.active;
}
@Override
public boolean isActive() { @Override
return this.active; public boolean isActive() {
} return this.active;
}
@Override
public Locale getLanguage() { @Override
return this.language; public Locale getLanguage() {
} return this.language;
}
@Override
public DateTimeZone getTimeZone() { @Override
return this.timeZone; public DateTimeZone getTimeZone() {
} return this.timeZone;
}
@Override
public Set<String> getRoles() { @Override
return this.roles; public Set<String> getRoles() {
} return this.roles;
}
@Override
@JsonIgnore @Override
public EnumSet<UserRole> getUserRoles() { @JsonIgnore
return EnumSet.copyOf( public EnumSet<UserRole> getUserRoles() {
getRoles().stream() return EnumSet.copyOf(
.map(r -> UserRole.valueOf(r)) getRoles().stream()
.collect(Collectors.toList())); .map(UserRole::valueOf)
} .collect(Collectors.toList()));
}
public boolean hasRole(final UserRole userRole) {
if (userRole == null) { public boolean hasRole(final UserRole userRole) {
return false; if (userRole == null) {
} return false;
return this.roles.contains(userRole.name()); }
} return this.roles.contains(userRole.name());
}
public boolean hasAnyRole(final UserRole... userRole) {
if (userRole == null) { public boolean hasAnyRole(final UserRole... userRole) {
return false; if (userRole == null) {
} return false;
return CollectionUtils.containsAny(getUserRoles(), Arrays.asList(userRole)); }
} return CollectionUtils.containsAny(getUserRoles(), Arrays.asList(userRole));
}
@JsonIgnore
@Override @JsonIgnore
public EntityKey getEntityKey() { @Override
if (StringUtils.isBlank(this.uuid)) { public EntityKey getEntityKey() {
return null; if (StringUtils.isBlank(this.uuid)) {
} return null;
return new EntityKey(this.uuid, entityType()); }
} return new EntityKey(this.uuid, entityType());
}
@Override
public int hashCode() { @Override
final int prime = 31; public int hashCode() {
int result = 1; final int prime = 31;
result = prime * result + ((this.uuid == null) ? 0 : this.uuid.hashCode()); int result = 1;
return result; result = prime * result + ((this.uuid == null) ? 0 : this.uuid.hashCode());
} return result;
}
@Override
public boolean equals(final Object obj) { @Override
if (this == obj) public boolean equals(final Object obj) {
return true; if (this == obj)
if (obj == null) return true;
return false; if (obj == null)
if (getClass() != obj.getClass()) return false;
return false; if (getClass() != obj.getClass())
final UserInfo other = (UserInfo) obj; return false;
if (this.uuid == null) { final UserInfo other = (UserInfo) obj;
if (other.uuid != null) if (this.uuid == null) {
return false; if (other.uuid != null)
} else if (!this.uuid.equals(other.uuid)) return false;
return false; } else if (!this.uuid.equals(other.uuid))
return true; return false;
} return true;
}
@Override
public String toString() { @Override
final StringBuilder builder = new StringBuilder(); public String toString() {
builder.append("UserInfo [uuid="); final StringBuilder builder = new StringBuilder();
builder.append(this.uuid); builder.append("UserInfo [uuid=");
builder.append(", institutionId="); builder.append(this.uuid);
builder.append(this.institutionId); builder.append(", institutionId=");
builder.append(", creationDate="); builder.append(this.institutionId);
builder.append(this.creationDate); builder.append(", creationDate=");
builder.append(", name="); builder.append(this.creationDate);
builder.append(this.name); builder.append(", name=");
builder.append(", surname="); builder.append(this.name);
builder.append(this.surname); builder.append(", surname=");
builder.append(", username="); builder.append(this.surname);
builder.append(this.username); builder.append(", username=");
builder.append(", email="); builder.append(this.username);
builder.append(this.email); builder.append(", email=");
builder.append(", active="); builder.append(this.email);
builder.append(this.active); builder.append(", active=");
builder.append(", language="); builder.append(this.active);
builder.append(this.language); builder.append(", language=");
builder.append(", timeZone="); builder.append(this.language);
builder.append(this.timeZone); builder.append(", timeZone=");
builder.append(", roles="); builder.append(this.timeZone);
builder.append(this.roles); builder.append(", roles=");
builder.append("]"); builder.append(this.roles);
return builder.toString(); builder.append("]");
} return builder.toString();
}
/** Use this to create a copy of a given UserInfo instance.
* /** Use this to create a copy of a given UserInfo instance.
* @param userInfo UserInfo instance to copy *
* @return copied UserInfo instance */ * @param userInfo UserInfo instance to copy
public static final UserInfo of(final UserInfo userInfo) { * @return copied UserInfo instance */
return new UserInfo( public static UserInfo of(final UserInfo userInfo) {
userInfo.getUuid(), return new UserInfo(
userInfo.getInstitutionId(), userInfo.getUuid(),
userInfo.creationDate, userInfo.getInstitutionId(),
userInfo.getName(), userInfo.creationDate,
userInfo.getUsername(), userInfo.getName(),
userInfo.getSurname(), userInfo.getUsername(),
userInfo.getEmail(), userInfo.getSurname(),
userInfo.getActive(), userInfo.getEmail(),
userInfo.getLanguage(), userInfo.getActive(),
userInfo.getTimeZone(), userInfo.getLanguage(),
userInfo.roles); userInfo.getTimeZone(),
} userInfo.roles);
}
/** Use this to create a copy of a given UserInfo by overriding available arguments.
* /** Use this to create a copy of a given UserInfo by overriding available arguments.
* @param userInfo UserInfo instance to copy *
* @param name new name or null if the name of given userInfo should be taken * @param userInfo UserInfo instance to copy
* @param surname new surname or null if the name of given userInfo should be taken * @param name new name or null if the name of given userInfo should be taken
* @param username new username or null if the username of given userInfo should be taken * @param surname new surname or null if the name of given userInfo should be taken
* @param email new email or null if the email of given userInfo should be taken * @param username new username or null if the username of given userInfo should be taken
* @param language new language or null if the language of given userInfo should be taken * @param email new email or null if the email of given userInfo should be taken
* @param timeZone new timeZone or null if the timeZone of given userInfo should be taken * @param language new language or null if the language of given userInfo should be taken
* @param roles new timeZone or null if the roles of given userInfo should be taken * @param timeZone new timeZone or null if the timeZone of given userInfo should be taken
* @return copied UserInfo instance with the given attributes */ * @param roles new timeZone or null if the roles of given userInfo should be taken
public static final UserInfo of( * @return copied UserInfo instance with the given attributes */
final UserInfo userInfo, public static UserInfo of(
final String name, final UserInfo userInfo,
final String username, final String name,
final String surname, final String username,
final String email, final String surname,
final Locale language, final String email,
final DateTimeZone timeZone, final Locale language,
final String... roles) { final DateTimeZone timeZone,
final String... roles) {
return new UserInfo(
userInfo.getUuid(), return new UserInfo(
userInfo.getInstitutionId(), userInfo.getUuid(),
userInfo.creationDate, userInfo.getInstitutionId(),
(name != null) ? name : userInfo.getName(), userInfo.creationDate,
(surname != null) ? surname : userInfo.getSurname(), (name != null) ? name : userInfo.getName(),
(username != null) ? username : userInfo.getUsername(), (surname != null) ? surname : userInfo.getSurname(),
(email != null) ? email : userInfo.getEmail(), (username != null) ? username : userInfo.getUsername(),
userInfo.getActive(), (email != null) ? email : userInfo.getEmail(),
(language != null) ? language : userInfo.getLanguage(), userInfo.getActive(),
(timeZone != null) ? timeZone : userInfo.getTimeZone(), (language != null) ? language : userInfo.getLanguage(),
(roles != null) ? new HashSet<>(Arrays.asList(roles)) : userInfo.roles); (timeZone != null) ? timeZone : userInfo.getTimeZone(),
} (roles != null) ? new HashSet<>(Arrays.asList(roles)) : userInfo.roles);
}
public static final UserInfo withEMail(final UserInfo userInfo, final String email) {
return of(userInfo, null, null, null, email, null, null, (String[]) null); public static UserInfo withEMail(final UserInfo userInfo, final String email) {
} return of(userInfo, null, null, null, email, null, null, (String[]) null);
}
public static final UserInfo withRoles(final UserInfo userInfo, final String... roles) {
return of(userInfo, null, null, null, null, null, null, roles); public static UserInfo withRoles(final UserInfo userInfo, final String... roles) {
} return of(userInfo, null, null, null, null, null, null, roles);
} }
}

View file

@ -1,284 +1,285 @@
/* /*
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gbl.model.user; package ch.ethz.seb.sebserver.gbl.model.user;
import java.util.Collections; import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.validation.constraints.Email; import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size; import javax.validation.constraints.Size;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.joda.time.DateTimeZone; import org.joda.time.DateTimeZone;
import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.api.POSTMapper; import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
import ch.ethz.seb.sebserver.gbl.model.Domain.USER; import ch.ethz.seb.sebserver.gbl.model.Domain.USER;
import ch.ethz.seb.sebserver.gbl.model.Domain.USER_ROLE; import ch.ethz.seb.sebserver.gbl.model.Domain.USER_ROLE;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.EntityKey;
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
public final class UserMod implements UserAccount { public final class UserMod implements UserAccount {
@JsonProperty(USER.ATTR_UUID) @JsonProperty(USER.ATTR_UUID)
public final String uuid; public final String uuid;
/** The foreign key identifier to the institution where the User belongs to */ /** The foreign key identifier to the institution where the User belongs to */
@NotNull(message = "user:institutionId:notNull") @NotNull(message = "user:institutionId:notNull")
@JsonProperty(USER.ATTR_INSTITUTION_ID) @JsonProperty(USER.ATTR_INSTITUTION_ID)
public final Long institutionId; public final Long institutionId;
/** first (or full) name of the user */ /** first (or full) name of the user */
@NotNull(message = "user:name:notNull") @NotNull(message = "user:name:notNull")
@Size(min = 3, max = 255, message = "user:name:size:{min}:{max}:${validatedValue}") @Size(max = 255, message = "user:name:size:{min}:{max}:${validatedValue}")
@JsonProperty(USER.ATTR_NAME) @JsonProperty(USER.ATTR_NAME)
public final String name; public final String name;
/** surname of the user */ /** surname of the user */
@Size(max = 255, message = "user:surname:size:{min}:{max}:${validatedValue}") @NotNull(message = "user:surname:notNull")
@JsonProperty(USER.ATTR_SURNAME) @Size(max = 255, message = "user:surname:size:{min}:{max}:${validatedValue}")
public final String surname; @JsonProperty(USER.ATTR_SURNAME)
public final String surname;
/** The internal user name */
@NotNull(message = "user:username:notNull") /** The internal user name */
@Size(min = 3, max = 255, message = "user:username:size:{min}:{max}:${validatedValue}") @NotNull(message = "user:username:notNull")
@JsonProperty(USER.ATTR_USERNAME) @Size(min = 3, max = 255, message = "user:username:size:{min}:{max}:${validatedValue}")
public final String username; @JsonProperty(USER.ATTR_USERNAME)
public final String username;
/** E-mail address of the user */
@Email(message = "user:email:email:_:_:${validatedValue}") /** E-mail address of the user */
@JsonProperty(USER.ATTR_EMAIL) @Email(message = "user:email:email:_:_:${validatedValue}")
public final String email; @JsonProperty(USER.ATTR_EMAIL)
public final String email;
/** The users locale */
@NotNull(message = "user:language:notNull") /** The users locale */
@JsonProperty(USER.ATTR_LANGUAGE) @NotNull(message = "user:language:notNull")
public final Locale language; @JsonProperty(USER.ATTR_LANGUAGE)
public final Locale language;
/** The users time zone */
@NotNull(message = "user:timeZone:notNull") /** The users time zone */
@JsonProperty(USER.ATTR_TIMEZONE) @NotNull(message = "user:timeZone:notNull")
public final DateTimeZone timeZone; @JsonProperty(USER.ATTR_TIMEZONE)
public final DateTimeZone timeZone;
/** The users roles in a unmodifiable set */
@NotNull(message = "user:userRoles:notNull") /** The users roles in a unmodifiable set */
@NotEmpty(message = "user:userRoles:notNull") @NotNull(message = "user:userRoles:notNull")
@JsonProperty(USER_ROLE.REFERENCE_NAME) @NotEmpty(message = "user:userRoles:notNull")
public final Set<String> roles; @JsonProperty(USER_ROLE.REFERENCE_NAME)
public final Set<String> roles;
@NotNull(message = "user:newPassword:notNull")
@Size(min = 8, max = 255, message = "user:newPassword:size:{min}:{max}:${validatedValue}") @NotNull(message = "user:newPassword:notNull")
@JsonProperty(PasswordChange.ATTR_NAME_NEW_PASSWORD) @Size(min = 8, max = 255, message = "user:newPassword:size:{min}:{max}:${validatedValue}")
private final CharSequence newPassword; @JsonProperty(PasswordChange.ATTR_NAME_NEW_PASSWORD)
private final CharSequence newPassword;
@NotNull(message = "user:confirmNewPassword:notNull")
@JsonProperty(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD) @NotNull(message = "user:confirmNewPassword:notNull")
private final CharSequence confirmNewPassword; @JsonProperty(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD)
private final CharSequence confirmNewPassword;
@JsonCreator
public UserMod( @JsonCreator
@JsonProperty(USER.ATTR_UUID) final String uuid, public UserMod(
@JsonProperty(USER.ATTR_INSTITUTION_ID) final Long institutionId, @JsonProperty(USER.ATTR_UUID) final String uuid,
@JsonProperty(USER.ATTR_NAME) final String name, @JsonProperty(USER.ATTR_INSTITUTION_ID) final Long institutionId,
@JsonProperty(USER.ATTR_SURNAME) final String surname, @JsonProperty(USER.ATTR_NAME) final String name,
@JsonProperty(USER.ATTR_USERNAME) final String username, @JsonProperty(USER.ATTR_SURNAME) final String surname,
@JsonProperty(PasswordChange.ATTR_NAME_NEW_PASSWORD) final CharSequence newPassword, @JsonProperty(USER.ATTR_USERNAME) final String username,
@JsonProperty(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD) final CharSequence confirmNewPassword, @JsonProperty(PasswordChange.ATTR_NAME_NEW_PASSWORD) final CharSequence newPassword,
@JsonProperty(USER.ATTR_EMAIL) final String email, @JsonProperty(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD) final CharSequence confirmNewPassword,
@JsonProperty(USER.ATTR_LANGUAGE) final Locale language, @JsonProperty(USER.ATTR_EMAIL) final String email,
@JsonProperty(USER.ATTR_TIMEZONE) final DateTimeZone timeZone, @JsonProperty(USER.ATTR_LANGUAGE) final Locale language,
@JsonProperty(USER_ROLE.REFERENCE_NAME) final Set<String> roles) { @JsonProperty(USER.ATTR_TIMEZONE) final DateTimeZone timeZone,
@JsonProperty(USER_ROLE.REFERENCE_NAME) final Set<String> roles) {
this.uuid = uuid;
this.institutionId = institutionId; this.uuid = uuid;
this.newPassword = newPassword; this.institutionId = institutionId;
this.confirmNewPassword = confirmNewPassword; this.newPassword = newPassword;
this.name = name; this.confirmNewPassword = confirmNewPassword;
this.surname = surname; this.name = name;
this.username = username; this.surname = surname;
this.email = email; this.username = username;
this.language = (language != null) ? language : Locale.ENGLISH; this.email = email;
this.timeZone = (timeZone != null) ? timeZone : DateTimeZone.UTC; this.language = (language != null) ? language : Locale.ENGLISH;
this.roles = (roles != null) this.timeZone = (timeZone != null) ? timeZone : DateTimeZone.UTC;
? Collections.unmodifiableSet(roles) this.roles = (roles != null)
: Collections.emptySet(); ? Collections.unmodifiableSet(roles)
} : Collections.emptySet();
}
public UserMod(final String modelId, final POSTMapper postAttrMapper) {
this.uuid = modelId; public UserMod(final String modelId, final POSTMapper postAttrMapper) {
this.institutionId = postAttrMapper.getLong(USER.ATTR_INSTITUTION_ID); this.uuid = modelId;
this.newPassword = postAttrMapper.getString(PasswordChange.ATTR_NAME_NEW_PASSWORD); this.institutionId = postAttrMapper.getLong(USER.ATTR_INSTITUTION_ID);
this.confirmNewPassword = postAttrMapper.getString(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD); this.newPassword = postAttrMapper.getString(PasswordChange.ATTR_NAME_NEW_PASSWORD);
this.name = postAttrMapper.getString(USER.ATTR_NAME); this.confirmNewPassword = postAttrMapper.getString(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD);
this.surname = postAttrMapper.getString(USER.ATTR_SURNAME); this.name = postAttrMapper.getString(USER.ATTR_NAME);
this.username = postAttrMapper.getString(USER.ATTR_USERNAME); this.surname = postAttrMapper.getString(USER.ATTR_SURNAME);
this.email = postAttrMapper.getString(USER.ATTR_EMAIL); this.username = postAttrMapper.getString(USER.ATTR_USERNAME);
this.language = postAttrMapper.getLocale(USER.ATTR_LANGUAGE); this.email = postAttrMapper.getString(USER.ATTR_EMAIL);
this.timeZone = postAttrMapper.getDateTimeZone(USER.ATTR_TIMEZONE); this.language = postAttrMapper.getLocale(USER.ATTR_LANGUAGE);
this.roles = postAttrMapper.getStringSet(USER_ROLE.REFERENCE_NAME); this.timeZone = postAttrMapper.getDateTimeZone(USER.ATTR_TIMEZONE);
} this.roles = postAttrMapper.getStringSet(USER_ROLE.REFERENCE_NAME);
}
@Override
public String getModelId() { @Override
return this.uuid; public String getModelId() {
} return this.uuid;
}
@Override
public EntityType entityType() { @Override
return EntityType.USER; public EntityType entityType() {
} return EntityType.USER;
}
@Override
public Long getInstitutionId() { @Override
return this.institutionId; public Long getInstitutionId() {
} return this.institutionId;
}
@Override
public DateTime getCreationDate() { @Override
return null; public DateTime getCreationDate() {
} return null;
}
@Override
public String getOwnerId() { @Override
return this.uuid; public String getOwnerId() {
} return this.uuid;
}
public CharSequence getNewPassword() {
return this.newPassword; public CharSequence getNewPassword() {
} return this.newPassword;
}
@Override
public String getName() { @Override
return this.name; public String getName() {
} return this.name;
}
@Override
public String getSurname() { @Override
return this.surname; public String getSurname() {
} return this.surname;
}
@Override
public String getUsername() { @Override
return this.username; public String getUsername() {
} return this.username;
}
@Override
public String getEmail() { @Override
return this.email; public String getEmail() {
} return this.email;
}
@Override
public Locale getLanguage() { @Override
return this.language; public Locale getLanguage() {
} return this.language;
}
@Override
public DateTimeZone getTimeZone() { @Override
return this.timeZone; public DateTimeZone getTimeZone() {
} return this.timeZone;
}
@Override
public Set<String> getRoles() { @Override
return this.roles; public Set<String> getRoles() {
} return this.roles;
}
@Override
@JsonIgnore @Override
public EnumSet<UserRole> getUserRoles() { @JsonIgnore
final List<UserRole> roles = getRoles() public EnumSet<UserRole> getUserRoles() {
.stream() final List<UserRole> roles = getRoles()
.map(r -> UserRole.valueOf(r)) .stream()
.collect(Collectors.toList()); .map(r -> UserRole.valueOf(r))
if (roles.isEmpty()) { .collect(Collectors.toList());
return EnumSet.noneOf(UserRole.class); if (roles.isEmpty()) {
} return EnumSet.noneOf(UserRole.class);
return EnumSet.copyOf(roles); }
} return EnumSet.copyOf(roles);
}
public CharSequence getRetypedNewPassword() {
return this.confirmNewPassword; public CharSequence getRetypedNewPassword() {
} return this.confirmNewPassword;
}
public boolean passwordChangeRequest() {
return this.newPassword != null; public boolean passwordChangeRequest() {
} return this.newPassword != null;
}
public boolean newPasswordMatch() {
return passwordChangeRequest() && this.newPassword.equals(this.confirmNewPassword); public boolean newPasswordMatch() {
} return passwordChangeRequest() && this.newPassword.equals(this.confirmNewPassword);
}
@Override
public Boolean getActive() { @Override
return false; public Boolean getActive() {
} return false;
}
@Override
public boolean isActive() { @Override
return false; public boolean isActive() {
} return false;
}
@JsonIgnore
@Override @JsonIgnore
public EntityKey getEntityKey() { @Override
if (StringUtils.isBlank(this.uuid)) { public EntityKey getEntityKey() {
return null; if (StringUtils.isBlank(this.uuid)) {
} return null;
return new EntityKey(this.uuid, entityType()); }
} return new EntityKey(this.uuid, entityType());
}
@Override
public String toString() { @Override
final StringBuilder builder = new StringBuilder(); public String toString() {
builder.append("UserMod [uuid="); final StringBuilder builder = new StringBuilder();
builder.append(this.uuid); builder.append("UserMod [uuid=");
builder.append(", institutionId="); builder.append(this.uuid);
builder.append(this.institutionId); builder.append(", institutionId=");
builder.append(", name="); builder.append(this.institutionId);
builder.append(this.name); builder.append(", name=");
builder.append(", surname="); builder.append(this.name);
builder.append(this.surname); builder.append(", surname=");
builder.append(", username="); builder.append(this.surname);
builder.append(this.username); builder.append(", username=");
builder.append(", email="); builder.append(this.username);
builder.append(this.email); builder.append(", email=");
builder.append(", language="); builder.append(this.email);
builder.append(this.language); builder.append(", language=");
builder.append(", timeZone="); builder.append(this.language);
builder.append(this.timeZone); builder.append(", timeZone=");
builder.append(", roles="); builder.append(this.timeZone);
builder.append(this.roles); builder.append(", roles=");
builder.append(", newPassword="); builder.append(this.roles);
builder.append(this.newPassword); builder.append(", newPassword=");
builder.append(", confirmNewPassword="); builder.append(this.newPassword);
builder.append(this.confirmNewPassword); builder.append(", confirmNewPassword=");
builder.append("]"); builder.append(this.confirmNewPassword);
return builder.toString(); builder.append("]");
} return builder.toString();
}
public static UserMod createNew(final Long institutionId) {
return new UserMod( public static UserMod createNew(final Long institutionId) {
UUID.randomUUID().toString(), return new UserMod(
institutionId, UUID.randomUUID().toString(),
null, null, null, null, null, null, null, null, null); institutionId,
} null, null, null, null, null, null, null, null, null);
}
}
}

View file

@ -1,70 +1,79 @@
/* /*
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gbl.util; package ch.ethz.seb.sebserver.gbl.util;
/** A tuple of two elements of the same type */ /** A tuple of two elements of the same type */
public class Tuple<T> { public class Tuple<T> {
/** The first element of the tuple */ /** The first element of the tuple */
public final T _1; public final T _1;
/** The second element of the tuple */ /** The second element of the tuple */
public final T _2; public final T _2;
public Tuple(final T _1, final T _2) { public Tuple(final T _1, final T _2) {
super(); super();
this._1 = _1; this._1 = _1;
this._2 = _2; this._2 = _2;
} }
public T get_1() { public T get_1() {
return this._1; return this._1;
} }
public T get_2() { public T get_2() {
return this._2; return this._2;
} }
@Override @SuppressWarnings("unchecked")
public int hashCode() { public <TT extends Tuple<T>> TT adaptTo(Class<TT> type) {
final int prime = 31; if (type.equals(this.getClass())) {
int result = 1; return (TT) this;
result = prime * result + ((this._1 == null) ? 0 : this._1.hashCode()); }
result = prime * result + ((this._2 == null) ? 0 : this._2.hashCode());
return result; return null;
} }
@Override @Override
public boolean equals(final Object obj) { public int hashCode() {
if (this == obj) final int prime = 31;
return true; int result = 1;
if (obj == null) result = prime * result + ((this._1 == null) ? 0 : this._1.hashCode());
return false; result = prime * result + ((this._2 == null) ? 0 : this._2.hashCode());
if (getClass() != obj.getClass()) return result;
return false; }
@SuppressWarnings("rawtypes")
final Tuple other = (Tuple) obj; @Override
if (this._1 == null) { public boolean equals(final Object obj) {
if (other._1 != null) if (this == obj)
return false; return true;
} else if (!this._1.equals(other._1)) if (obj == null)
return false; return false;
if (this._2 == null) { if (getClass() != obj.getClass())
if (other._2 != null) return false;
return false; @SuppressWarnings("rawtypes")
} else if (!this._2.equals(other._2)) final Tuple other = (Tuple) obj;
return false; if (this._1 == null) {
return true; if (other._1 != null)
} return false;
} else if (!this._1.equals(other._1))
@Override return false;
public String toString() { if (this._2 == null) {
return "( " + this._1 + ", " + this._2 + ")"; if (other._2 != null)
} return false;
} else if (!this._2.equals(other._2))
} return false;
return true;
}
@Override
public String toString() {
return "( " + this._1 + ", " + this._2 + ")";
}
}

View file

@ -0,0 +1,41 @@
/*
* Copyright (c) 2020 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.util;
import java.util.Objects;
/** A tuple of three elements of the same type */
public class Tuple3<T> extends Tuple<T> {
/** The third element of the tuple */
public final T _3;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
Tuple3<?> tuple3 = (Tuple3<?>) o;
return Objects.equals(_3, tuple3._3);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), _3);
}
public Tuple3(T _1, T _2, T _3) {
super(_1, _2);
this._3 = _3;
}
public T get_3() {
return _3;
}
}

View file

@ -1,253 +1,257 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.content; package ch.ethz.seb.sebserver.gui.content;
import java.util.Arrays; import java.util.Collections;
import org.eclipse.swt.SWT; import org.apache.commons.lang3.StringUtils;
import org.eclipse.swt.layout.GridData; import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.layout.GridLayout;
import org.springframework.context.annotation.Lazy; import org.eclipse.swt.widgets.Composite;
import org.springframework.stereotype.Component; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration; import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode; import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.TemplateAttribute; import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.TitleOrientation; import ch.ethz.seb.sebserver.gbl.model.sebconfig.TemplateAttribute;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.View; import ch.ethz.seb.sebserver.gbl.model.sebconfig.TitleOrientation;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.model.sebconfig.View;
import ch.ethz.seb.sebserver.gbl.util.Utils; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.gui.form.FormBuilder; import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.service.ResourceService; import ch.ethz.seb.sebserver.gui.form.FormBuilder;
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService; import ch.ethz.seb.sebserver.gui.service.ResourceService;
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField; import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder; import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
import ch.ethz.seb.sebserver.gui.service.examconfig.impl.AttributeMapping; import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
import ch.ethz.seb.sebserver.gui.service.examconfig.impl.ViewContext; import ch.ethz.seb.sebserver.gui.service.examconfig.impl.AttributeMapping;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; import ch.ethz.seb.sebserver.gui.service.examconfig.impl.ViewContext;
import ch.ethz.seb.sebserver.gui.service.page.PageContext; import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.PageService; import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; import ch.ethz.seb.sebserver.gui.service.page.PageService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetConfigurations; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigNode; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetConfigurations;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetTemplateAttribute; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigNode;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetTemplateAttribute;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.EntityGrantCheck; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.EntityGrantCheck;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
@Lazy
@Component @Lazy
@GuiProfile @Component
public class ConfigTemplateAttributeForm implements TemplateComposer { @GuiProfile
public class ConfigTemplateAttributeForm implements TemplateComposer {
private static final LocTextKey FORM_TITLE =
new LocTextKey("sebserver.configtemplate.attr.form.title"); private static final LocTextKey FORM_TITLE =
private static final LocTextKey FORM_NAME_TEXT_KEY = new LocTextKey("sebserver.configtemplate.attr.form.title");
new LocTextKey("sebserver.configtemplate.attr.form.name"); private static final LocTextKey FORM_NAME_TEXT_KEY =
private static final LocTextKey FORM_TYPE_TEXT_KEY = new LocTextKey("sebserver.configtemplate.attr.form.name");
new LocTextKey("sebserver.configtemplate.attr.form.type"); private static final LocTextKey FORM_TYPE_TEXT_KEY =
private static final LocTextKey FORM_VIEW_TEXT_KEY = new LocTextKey("sebserver.configtemplate.attr.form.type");
new LocTextKey("sebserver.configtemplate.attr.form.view"); private static final LocTextKey FORM_VIEW_TEXT_KEY =
private static final LocTextKey FORM_GROUP_TEXT_KEY = new LocTextKey("sebserver.configtemplate.attr.form.view");
new LocTextKey("sebserver.configtemplate.attr.form.group"); private static final LocTextKey FORM_GROUP_TEXT_KEY =
private static final LocTextKey FORM_VALUE_TEXT_KEY = new LocTextKey("sebserver.configtemplate.attr.form.group");
new LocTextKey("sebserver.configtemplate.attr.form.value"); private static final LocTextKey FORM_VALUE_TEXT_KEY =
new LocTextKey("sebserver.configtemplate.attr.form.value");
private final PageService pageService; private static final LocTextKey FORM_VALUE_TOOLTIP_TEXT_KEY =
private final RestService restService; new LocTextKey("sebserver.configtemplate.attr.form.value" + Constants.TOOLTIP_TEXT_KEY_SUFFIX);
private final CurrentUser currentUser;
private final ResourceService resourceService; private final PageService pageService;
private final ExamConfigurationService examConfigurationService; private final RestService restService;
private final CurrentUser currentUser;
protected ConfigTemplateAttributeForm( private final ResourceService resourceService;
final PageService pageService, private final ExamConfigurationService examConfigurationService;
final RestService restService,
final CurrentUser currentUser, protected ConfigTemplateAttributeForm(
final ExamConfigurationService examConfigurationService) { final PageService pageService,
final RestService restService,
this.pageService = pageService; final CurrentUser currentUser,
this.restService = restService; final ExamConfigurationService examConfigurationService) {
this.currentUser = currentUser;
this.resourceService = pageService.getResourceService(); this.pageService = pageService;
this.examConfigurationService = examConfigurationService; this.restService = restService;
this.currentUser = currentUser;
} this.resourceService = pageService.getResourceService();
this.examConfigurationService = examConfigurationService;
@Override
public void compose(final PageContext pageContext) { }
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
@Override
final EntityKey attributeKey = pageContext.getEntityKey(); public void compose(final PageContext pageContext) {
final EntityKey templateKey = pageContext.getParentEntityKey(); final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
final Long templateId = Long.valueOf(templateKey.modelId);
final EntityKey attributeKey = pageContext.getEntityKey();
try { final EntityKey templateKey = pageContext.getParentEntityKey();
final Long templateId = Long.valueOf(templateKey.modelId);
final ConfigurationNode template = this.restService
.getBuilder(GetExamConfigNode.class) try {
.withURIVariable(API.PARAM_MODEL_ID, templateKey.modelId)
.call() final ConfigurationNode template = this.restService
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_NODE, error)) .getBuilder(GetExamConfigNode.class)
.getOrThrow(); .withURIVariable(API.PARAM_MODEL_ID, templateKey.modelId)
.call()
final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(template); .onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_NODE, error))
final boolean modifyGrant = entityGrant.m(); .getOrThrow();
// the attribute final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(template);
final TemplateAttribute attribute = this.restService.getBuilder(GetTemplateAttribute.class) final boolean modifyGrant = entityGrant.m();
.withURIVariable(API.PARAM_PARENT_MODEL_ID, templateKey.modelId)
.withURIVariable(API.PARAM_MODEL_ID, attributeKey.modelId) // the attribute
.call() final TemplateAttribute attribute = this.restService.getBuilder(GetTemplateAttribute.class)
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_NODE, error)) .withURIVariable(API.PARAM_PARENT_MODEL_ID, templateKey.modelId)
.getOrThrow(); .withURIVariable(API.PARAM_MODEL_ID, attributeKey.modelId)
.call()
// the follow-up configuration .onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_NODE, error))
final Configuration configuration = this.restService.getBuilder(GetConfigurations.class) .getOrThrow();
.withQueryParam(Configuration.FILTER_ATTR_CONFIGURATION_NODE_ID, templateKey.getModelId())
.withQueryParam(Configuration.FILTER_ATTR_FOLLOWUP, Constants.TRUE_STRING) // the follow-up configuration
.call() final Configuration configuration = this.restService.getBuilder(GetConfigurations.class)
.map(Utils::toSingleton) .withQueryParam(Configuration.FILTER_ATTR_CONFIGURATION_NODE_ID, templateKey.getModelId())
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION, error)) .withQueryParam(Configuration.FILTER_ATTR_FOLLOWUP, Constants.TRUE_STRING)
.getOrThrow(); .call()
.map(Utils::toSingleton)
// the default page layout with title .onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION, error))
final Composite content = widgetFactory.defaultPageLayout( .getOrThrow();
pageContext.getParent(),
FORM_TITLE); // the default page layout with title
final Composite content = widgetFactory.defaultPageLayout(
final PageContext formContext = pageContext.copyOf(content); pageContext.getParent(),
FORM_TITLE);
final boolean hasView = attribute.getOrientation() != null;
final PageContext formContext = pageContext.copyOf(content);
this.pageService.formBuilder(formContext)
.readonly(true) // TODO change this for next version final boolean hasView = attribute.getOrientation() != null;
.addField(FormBuilder.text(
Domain.CONFIGURATION_ATTRIBUTE.ATTR_NAME, this.pageService.formBuilder(formContext)
FORM_NAME_TEXT_KEY, .readonly(true) // TODO change this for next version
attribute::getName)) .addField(FormBuilder.text(
.addField(FormBuilder.text( Domain.CONFIGURATION_ATTRIBUTE.ATTR_NAME,
Domain.CONFIGURATION_ATTRIBUTE.ATTR_TYPE, FORM_NAME_TEXT_KEY,
FORM_TYPE_TEXT_KEY, attribute::getName))
() -> this.resourceService.getAttributeTypeName(attribute))) .addField(FormBuilder.text(
.addFieldIf( Domain.CONFIGURATION_ATTRIBUTE.ATTR_TYPE,
() -> hasView, FORM_TYPE_TEXT_KEY,
() -> FormBuilder.singleSelection( () -> this.resourceService.getAttributeTypeName(attribute)))
Domain.ORIENTATION.ATTR_VIEW_ID, .addFieldIf(
FORM_VIEW_TEXT_KEY, () -> hasView,
attribute.getViewModelId(), () -> FormBuilder.singleSelection(
() -> this.resourceService.getViewResources(templateKey.modelId))) Domain.ORIENTATION.ATTR_VIEW_ID,
.addFieldIf( FORM_VIEW_TEXT_KEY,
() -> hasView, attribute.getViewModelId(),
() -> FormBuilder.text( () -> this.resourceService.getViewResources(templateKey.modelId)))
Domain.ORIENTATION.ATTR_GROUP_ID, .addFieldIf(
FORM_GROUP_TEXT_KEY, () -> hasView,
attribute.getGroupId())) () -> FormBuilder.text(
.build(); Domain.ORIENTATION.ATTR_GROUP_ID,
FORM_GROUP_TEXT_KEY,
final Composite valSpace = new Composite(content, SWT.NONE); attribute.getGroupId()))
valSpace.setLayout(new GridLayout()); .build();
valSpace.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
final Composite valSpace = new Composite(content, SWT.NONE);
widgetFactory.labelLocalized( valSpace.setLayout(new GridLayout());
valSpace, valSpace.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
CustomVariant.TEXT_H2,
FORM_VALUE_TEXT_KEY); widgetFactory.label(content, StringUtils.EMPTY);
widgetFactory.labelLocalized(
widgetFactory.labelSeparator(valSpace); valSpace,
CustomVariant.TEXT_H3,
final Composite grid = new Composite(valSpace, SWT.NONE); FORM_VALUE_TEXT_KEY,
grid.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); FORM_VALUE_TOOLTIP_TEXT_KEY);
grid.setLayout(new GridLayout(6, true)); widgetFactory.labelSeparator(valSpace);
final PageContext valueContext = formContext.copyOf(grid); final Composite grid = new Composite(valSpace, SWT.NONE);
grid.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
final Orientation defaultOrientation = getDefaultOrientation(attribute); grid.setLayout(new GridLayout(6, true));
final AttributeMapping attributeMapping = this.examConfigurationService
.getAttributes(attribute, defaultOrientation) final PageContext valueContext = formContext.copyOf(grid);
.getOrThrow();
final ViewContext viewContext = this.examConfigurationService.createViewContext( final Orientation defaultOrientation = getDefaultOrientation(attribute);
valueContext, final AttributeMapping attributeMapping = this.examConfigurationService
configuration, .getAttributes(attribute, defaultOrientation)
new View(-1L, "template", 10, 0, templateId), .getOrThrow();
attributeMapping, final ViewContext viewContext = this.examConfigurationService.createViewContext(
1, false); valueContext,
configuration,
final InputFieldBuilder inputFieldBuilder = this.examConfigurationService.getInputFieldBuilder( new View(-1L, "template", 10, 0, templateId),
attribute.getConfigAttribute(), attributeMapping,
defaultOrientation); 1, false);
final InputField createInputField = inputFieldBuilder.createInputField( final InputFieldBuilder inputFieldBuilder = this.examConfigurationService.getInputFieldBuilder(
grid, attribute.getConfigAttribute(),
attribute.getConfigAttribute(), defaultOrientation);
viewContext);
final InputField createInputField = inputFieldBuilder.createInputField(
viewContext.registerInputField(createInputField); grid,
attribute.getConfigAttribute(),
this.examConfigurationService.initInputFieldValues( viewContext);
configuration.id,
Arrays.asList(viewContext)); viewContext.registerInputField(createInputField);
this.pageService.pageActionBuilder(formContext.clearEntityKeys()) this.examConfigurationService.initInputFieldValues(
configuration.id,
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_FORM_SET_DEFAULT) Collections.singletonList(viewContext));
.withEntityKey(attributeKey)
.withParentEntityKey(templateKey) this.pageService.pageActionBuilder(formContext.clearEntityKeys())
.withExec(this.examConfigurationService::resetToDefaults)
.ignoreMoveAwayFromEdit() .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_FORM_SET_DEFAULT)
.publishIf(() -> modifyGrant) .withEntityKey(attributeKey)
.withParentEntityKey(templateKey)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_REMOVE_VIEW) .withExec(this.examConfigurationService::resetToDefaults)
.withEntityKey(attributeKey) .ignoreMoveAwayFromEdit()
.withParentEntityKey(templateKey) .publishIf(() -> modifyGrant)
.withExec(this.examConfigurationService::removeFromView)
.ignoreMoveAwayFromEdit() .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_REMOVE_VIEW)
.publishIf(() -> modifyGrant && hasView) .withEntityKey(attributeKey)
.withParentEntityKey(templateKey)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_ATTACH_DEFAULT_VIEW) .withExec(this.examConfigurationService::removeFromView)
.withEntityKey(attributeKey) .ignoreMoveAwayFromEdit()
.withParentEntityKey(templateKey) .publishIf(() -> modifyGrant && hasView)
.withExec(this.examConfigurationService::attachToDefaultView)
.ignoreMoveAwayFromEdit() .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_ATTACH_DEFAULT_VIEW)
.publishIf(() -> modifyGrant && !hasView) .withEntityKey(attributeKey)
.withParentEntityKey(templateKey)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_FORM_EDIT_TEMPLATE) .withExec(this.examConfigurationService::attachToDefaultView)
.withEntityKey(templateKey) .ignoreMoveAwayFromEdit()
.ignoreMoveAwayFromEdit() .publishIf(() -> modifyGrant && !hasView)
.publish();
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_FORM_EDIT_TEMPLATE)
} catch (final Exception e) { .withEntityKey(templateKey)
pageContext.notifyUnexpectedError(e); .ignoreMoveAwayFromEdit()
} .publish();
}
} catch (final Exception e) {
private Orientation getDefaultOrientation(final TemplateAttribute attribute) { pageContext.notifyUnexpectedError(e);
return new Orientation( }
-1L, }
attribute.getConfigAttribute().id,
attribute.templateId, private Orientation getDefaultOrientation(final TemplateAttribute attribute) {
null, return new Orientation(
null, -1L,
0, attribute.getConfigAttribute().id,
0, attribute.templateId,
2, null,
1, null,
TitleOrientation.NONE); 0,
} 0,
2,
} 1,
TitleOrientation.NONE);
}
}

View file

@ -1,348 +1,362 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.content; package ch.ethz.seb.sebserver.gui.content;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationStatus; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationStatus;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationType; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationType;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.TemplateAttribute; import ch.ethz.seb.sebserver.gbl.model.sebconfig.TemplateAttribute;
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.form.FormBuilder; import ch.ethz.seb.sebserver.gui.form.FormBuilder;
import ch.ethz.seb.sebserver.gui.form.FormHandle; import ch.ethz.seb.sebserver.gui.form.FormHandle;
import ch.ethz.seb.sebserver.gui.service.ResourceService; import ch.ethz.seb.sebserver.gui.service.ResourceService;
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService; import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport; 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.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.PageContext; import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.PageService; import ch.ethz.seb.sebserver.gui.service.page.PageService;
import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder; import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction; import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigNode; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigNode;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetTemplateAttributePage; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetTemplateAttributePage;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.NewExamConfig; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.NewExamConfig;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfig; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfig;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.EntityGrantCheck; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.EntityGrantCheck;
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition; import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute; import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute;
import ch.ethz.seb.sebserver.gui.table.EntityTable; import ch.ethz.seb.sebserver.gui.table.EntityTable;
import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType; import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@Lazy @Lazy
@Component @Component
@GuiProfile @GuiProfile
public class ConfigTemplateForm implements TemplateComposer { public class ConfigTemplateForm implements TemplateComposer {
private static final LocTextKey FORM_TITLE_NEW = private static final LocTextKey FORM_TITLE_NEW =
new LocTextKey("sebserver.configtemplate.form.title.new"); new LocTextKey("sebserver.configtemplate.form.title.new");
private static final LocTextKey FORM_TITLE = private static final LocTextKey FORM_TITLE =
new LocTextKey("sebserver.configtemplate.form.title"); new LocTextKey("sebserver.configtemplate.form.title");
private static final LocTextKey FORM_NAME_TEXT_KEY = private static final LocTextKey FORM_NAME_TEXT_KEY =
new LocTextKey("sebserver.configtemplate.form.name"); new LocTextKey("sebserver.configtemplate.form.name");
private static final LocTextKey FORM_DESCRIPTION_TEXT_KEY = private static final LocTextKey FORM_DESCRIPTION_TEXT_KEY =
new LocTextKey("sebserver.configtemplate.form.description"); new LocTextKey("sebserver.configtemplate.form.description");
private static final LocTextKey ATTRIBUTES_LIST_TITLE_TEXT_KEY = private static final LocTextKey ATTRIBUTES_LIST_TITLE_TEXT_KEY =
new LocTextKey("sebserver.configtemplate.attrs.list.title"); new LocTextKey("sebserver.configtemplate.attrs.list.title");
private static final LocTextKey ATTRIBUTES_LIST_NAME_TEXT_KEY = private static final LocTextKey ATTRIBUTES_LIST_TITLE_TOOLTIP_TEXT_KEY =
new LocTextKey("sebserver.configtemplate.attrs.list.name"); new LocTextKey("sebserver.configtemplate.attrs.list.title" + Constants.TOOLTIP_TEXT_KEY_SUFFIX);
private static final LocTextKey ATTRIBUTES_LIST_VIEW_TEXT_KEY = private static final LocTextKey ATTRIBUTES_LIST_NAME_TEXT_KEY =
new LocTextKey("sebserver.configtemplate.attrs.list.view"); new LocTextKey("sebserver.configtemplate.attrs.list.name");
private static final LocTextKey ATTRIBUTES_LIST_GROUP_TEXT_KEY = private static final LocTextKey ATTRIBUTES_LIST_VIEW_TEXT_KEY =
new LocTextKey("sebserver.configtemplate.attrs.list.group"); new LocTextKey("sebserver.configtemplate.attrs.list.view");
private static final LocTextKey ATTRIBUTES_LIST_TYPE_TEXT_KEY = private static final LocTextKey ATTRIBUTES_LIST_GROUP_TEXT_KEY =
new LocTextKey("sebserver.configtemplate.attrs.list.type"); new LocTextKey("sebserver.configtemplate.attrs.list.group");
private static final LocTextKey EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY = private static final LocTextKey ATTRIBUTES_LIST_TYPE_TEXT_KEY =
new LocTextKey("sebserver.configtemplate.attr.info.pleaseSelect"); new LocTextKey("sebserver.configtemplate.attrs.list.type");
private static final LocTextKey EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY =
private final PageService pageService; new LocTextKey("sebserver.configtemplate.attr.info.pleaseSelect");
private final RestService restService;
private final CurrentUser currentUser; private final PageService pageService;
private final I18nSupport i18nSupport; private final RestService restService;
private final ResourceService resourceService; private final CurrentUser currentUser;
private final ExamConfigurationService examConfigurationService; private final I18nSupport i18nSupport;
private final ResourceService resourceService;
private final TableFilterAttribute nameFilter = private final ExamConfigurationService examConfigurationService;
new TableFilterAttribute(CriteriaType.TEXT, TemplateAttribute.FILTER_ATTR_NAME);
private final TableFilterAttribute groupFilter = private final TableFilterAttribute nameFilter =
new TableFilterAttribute(CriteriaType.TEXT, TemplateAttribute.FILTER_ATTR_GROUP); new TableFilterAttribute(CriteriaType.TEXT, TemplateAttribute.FILTER_ATTR_NAME);
private final TableFilterAttribute groupFilter =
protected ConfigTemplateForm( new TableFilterAttribute(CriteriaType.TEXT, TemplateAttribute.FILTER_ATTR_GROUP);
final PageService pageService,
final RestService restService, protected ConfigTemplateForm(
final CurrentUser currentUser, final PageService pageService,
final ExamConfigurationService examConfigurationService) { final RestService restService,
final CurrentUser currentUser,
this.pageService = pageService; final ExamConfigurationService examConfigurationService) {
this.restService = restService;
this.currentUser = currentUser; this.pageService = pageService;
this.i18nSupport = pageService.getI18nSupport(); this.restService = restService;
this.resourceService = pageService.getResourceService(); this.currentUser = currentUser;
this.examConfigurationService = examConfigurationService; this.i18nSupport = pageService.getI18nSupport();
this.resourceService = pageService.getResourceService();
} this.examConfigurationService = examConfigurationService;
@Override }
public void compose(final PageContext pageContext) {
@Override
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory(); public void compose(final PageContext pageContext) {
final ResourceService resourceService = this.pageService.getResourceService();
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
final UserInfo user = this.currentUser.get(); final ResourceService resourceService = this.pageService.getResourceService();
final EntityKey entityKey = pageContext.getEntityKey();
final boolean isNew = entityKey == null; final UserInfo user = this.currentUser.get();
final EntityKey entityKey = pageContext.getEntityKey();
// get data or create new. Handle error if happen final boolean isNew = entityKey == null;
final ConfigurationNode examConfig = (isNew)
? ConfigurationNode.createNewTemplate(user.institutionId) // get data or create new. Handle error if happen
: this.restService final ConfigurationNode examConfig = (isNew)
.getBuilder(GetExamConfigNode.class) ? ConfigurationNode.createNewTemplate(user.institutionId)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId) : this.restService
.call() .getBuilder(GetExamConfigNode.class)
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_NODE, error)) .withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.getOrThrow(); .call()
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_NODE, error))
final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(examConfig); .getOrThrow();
final boolean writeGrant = entityGrant.w();
final boolean modifyGrant = entityGrant.m(); final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(examConfig);
final boolean isReadonly = pageContext.isReadonly(); final boolean writeGrant = entityGrant.w();
final boolean modifyGrant = entityGrant.m();
// new PageContext with actual EntityKey final boolean isReadonly = pageContext.isReadonly();
final PageContext formContext = pageContext
.withEntityKey(examConfig.getEntityKey()); // new PageContext with actual EntityKey
final PageContext formContext = pageContext
// the default page layout with interactive title .withEntityKey(examConfig.getEntityKey());
final LocTextKey titleKey = (isNew)
? FORM_TITLE_NEW // the default page layout with interactive title
: FORM_TITLE; final LocTextKey titleKey = (isNew)
final Composite content = widgetFactory.defaultPageLayout( ? FORM_TITLE_NEW
formContext.getParent(), : FORM_TITLE;
titleKey); final Composite content = widgetFactory.defaultPageLayout(
formContext.getParent(),
// The SebClientConfig form titleKey);
final FormHandle<ConfigurationNode> formHandle = this.pageService.formBuilder(
formContext.copyOf(content)) // The SebClientConfig form
.readonly(isReadonly) final FormHandle<ConfigurationNode> formHandle = this.pageService.formBuilder(
.putStaticValueIf(() -> !isNew, formContext.copyOf(content))
Domain.CONFIGURATION_NODE.ATTR_ID, .readonly(isReadonly)
examConfig.getModelId()) .putStaticValueIf(() -> !isNew,
.putStaticValue( Domain.CONFIGURATION_NODE.ATTR_ID,
Domain.CONFIGURATION_NODE.ATTR_INSTITUTION_ID, examConfig.getModelId())
String.valueOf(examConfig.getInstitutionId())) .putStaticValue(
.putStaticValue( Domain.CONFIGURATION_NODE.ATTR_INSTITUTION_ID,
Domain.CONFIGURATION_NODE.ATTR_TYPE, String.valueOf(examConfig.getInstitutionId()))
ConfigurationType.TEMPLATE.name()) .putStaticValue(
.putStaticValue( Domain.CONFIGURATION_NODE.ATTR_TYPE,
Domain.CONFIGURATION_NODE.ATTR_STATUS, ConfigurationType.TEMPLATE.name())
ConfigurationStatus.IN_USE.name()) .putStaticValue(
.addField(FormBuilder.text( Domain.CONFIGURATION_NODE.ATTR_STATUS,
Domain.CONFIGURATION_NODE.ATTR_NAME, ConfigurationStatus.IN_USE.name())
FORM_NAME_TEXT_KEY, .addField(FormBuilder.text(
examConfig.name)) Domain.CONFIGURATION_NODE.ATTR_NAME,
.addField(FormBuilder.text( FORM_NAME_TEXT_KEY,
Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION, examConfig.name)
FORM_DESCRIPTION_TEXT_KEY, .mandatory(!isReadonly))
examConfig.description) .addField(FormBuilder.text(
.asArea()) Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION,
FORM_DESCRIPTION_TEXT_KEY,
.buildFor((isNew) examConfig.description)
? this.restService.getRestCall(NewExamConfig.class) .asArea())
: this.restService.getRestCall(SaveExamConfig.class));
.buildFor((isNew)
final PageActionBuilder pageActionBuilder = this.pageService ? this.restService.getRestCall(NewExamConfig.class)
.pageActionBuilder(formContext.clearEntityKeys()); : this.restService.getRestCall(SaveExamConfig.class));
if (isReadonly) { final PageActionBuilder pageActionBuilder = this.pageService
.pageActionBuilder(formContext.clearEntityKeys());
widgetFactory.label(content, "");
widgetFactory.labelLocalizedTitle( if (isReadonly) {
content,
ATTRIBUTES_LIST_TITLE_TEXT_KEY); widgetFactory.label(content, StringUtils.EMPTY);
widgetFactory.labelLocalized(
final TableFilterAttribute viewFilter = new TableFilterAttribute( content,
CriteriaType.SINGLE_SELECTION, WidgetFactory.CustomVariant.TEXT_H3,
TemplateAttribute.FILTER_ATTR_VIEW, ATTRIBUTES_LIST_TITLE_TEXT_KEY,
() -> this.resourceService.getViewResources(entityKey.modelId)); ATTRIBUTES_LIST_TITLE_TOOLTIP_TEXT_KEY);
final TableFilterAttribute typeFilter = new TableFilterAttribute( widgetFactory.labelSeparator(content);
CriteriaType.SINGLE_SELECTION,
TemplateAttribute.FILTER_ATTR_TYPE, final TableFilterAttribute viewFilter = new TableFilterAttribute(
() -> this.resourceService.getAttributeTypeResources()); CriteriaType.SINGLE_SELECTION,
TemplateAttribute.FILTER_ATTR_VIEW,
final EntityTable<TemplateAttribute> attrTable = () -> this.resourceService.getViewResources(entityKey.modelId));
this.pageService.entityTableBuilder( final TableFilterAttribute typeFilter = new TableFilterAttribute(
Domain.CONFIGURATION_NODE.TYPE_NAME + "_Template", CriteriaType.SINGLE_SELECTION,
this.restService.getRestCall(GetTemplateAttributePage.class)) TemplateAttribute.FILTER_ATTR_TYPE,
.withRestCallAdapter(restCall -> restCall.withURIVariable( this.resourceService::getAttributeTypeResources);
API.PARAM_PARENT_MODEL_ID,
entityKey.modelId)) final EntityTable<TemplateAttribute> attrTable =
.withPaging(15) this.pageService.entityTableBuilder(
.withColumn(new ColumnDefinition<>( Domain.CONFIGURATION_NODE.TYPE_NAME + "_Template",
Domain.CONFIGURATION_ATTRIBUTE.ATTR_NAME, this.restService.getRestCall(GetTemplateAttributePage.class))
ATTRIBUTES_LIST_NAME_TEXT_KEY, .withRestCallAdapter(restCall -> restCall.withURIVariable(
this::getAttributeName) API.PARAM_PARENT_MODEL_ID,
.withFilter(this.nameFilter) entityKey.modelId))
.sortable() .withPaging(15)
.widthProportion(3)) .withColumn(new ColumnDefinition<>(
.withColumn(new ColumnDefinition<TemplateAttribute>( Domain.CONFIGURATION_ATTRIBUTE.ATTR_NAME,
Domain.CONFIGURATION_ATTRIBUTE.ATTR_TYPE, ATTRIBUTES_LIST_NAME_TEXT_KEY,
ATTRIBUTES_LIST_TYPE_TEXT_KEY, this::getAttributeName)
resourceService::getAttributeTypeName) .withFilter(this.nameFilter)
.withFilter(typeFilter) .sortable()
.sortable() .widthProportion(3))
.widthProportion(1)) .withColumn(new ColumnDefinition<TemplateAttribute>(
.withColumn(new ColumnDefinition<>( Domain.CONFIGURATION_ATTRIBUTE.ATTR_TYPE,
Domain.ORIENTATION.ATTR_VIEW_ID, ATTRIBUTES_LIST_TYPE_TEXT_KEY,
ATTRIBUTES_LIST_VIEW_TEXT_KEY, resourceService::getAttributeTypeName)
resourceService.getViewNameFunction(entityKey.modelId)) .withFilter(typeFilter)
.withFilter(viewFilter) .sortable()
.sortable() .widthProportion(1))
.widthProportion(1)) .withColumn(new ColumnDefinition<>(
.withColumn(new ColumnDefinition<>( Domain.ORIENTATION.ATTR_VIEW_ID,
Domain.ORIENTATION.ATTR_GROUP_ID, ATTRIBUTES_LIST_VIEW_TEXT_KEY,
ATTRIBUTES_LIST_GROUP_TEXT_KEY, resourceService.getViewNameFunction(entityKey.modelId))
TemplateAttribute::getGroupId) .withFilter(viewFilter)
.withFilter(this.groupFilter) .sortable()
.sortable() .widthProportion(1))
.widthProportion(1)) .withColumn(new ColumnDefinition<>(
.withDefaultAction(pageActionBuilder Domain.ORIENTATION.ATTR_GROUP_ID,
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_EDIT) ATTRIBUTES_LIST_GROUP_TEXT_KEY,
.withParentEntityKey(entityKey) TemplateAttribute::getGroupId)
.create()) .withFilter(this.groupFilter)
.compose(pageContext.copyOf(content)); .sortable()
.widthProportion(1))
pageActionBuilder .withDefaultAction(pageActionBuilder
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_EDIT)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_EDIT) .withParentEntityKey(entityKey)
.withParentEntityKey(entityKey) .create())
.withSelect(
attrTable::getSelection, .withSelectionListener(this.pageService.getSelectionPublisher(
PageAction::applySingleSelectionAsEntityKey, pageContext,
EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY) ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_EDIT,
.publishIf(() -> attrTable.hasAnyContent()) ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_SET_DEFAULT,
ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_LIST_REMOVE_VIEW,
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_SET_DEFAULT) ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_LIST_ATTACH_DEFAULT_VIEW))
.withParentEntityKey(entityKey)
.withSelect( .compose(pageContext.copyOf(content));
attrTable::getSelection,
action -> this.resetToDefaults(action, attrTable), pageActionBuilder
EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY)
.noEventPropagation() .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_EDIT)
.publishIf(() -> attrTable.hasAnyContent()) .withParentEntityKey(entityKey)
.withSelect(
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_LIST_REMOVE_VIEW) attrTable::getSelection,
.withParentEntityKey(entityKey) PageAction::applySingleSelectionAsEntityKey,
.withSelect( EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY)
attrTable::getSelection, .publishIf(attrTable::hasAnyContent, false)
action -> this.removeFormView(action, attrTable),
EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY) .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_SET_DEFAULT)
.noEventPropagation() .withParentEntityKey(entityKey)
.publishIf(() -> attrTable.hasAnyContent()) .withSelect(
attrTable::getSelection,
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_LIST_ATTACH_DEFAULT_VIEW) action -> this.resetToDefaults(action, attrTable),
.withParentEntityKey(entityKey) EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY)
.withSelect( .noEventPropagation()
attrTable::getSelection, .publishIf(attrTable::hasAnyContent, false)
action -> this.attachView(action, attrTable),
EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY) .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_LIST_REMOVE_VIEW)
.noEventPropagation() .withParentEntityKey(entityKey)
.publishIf(() -> attrTable.hasAnyContent()); .withSelect(
} attrTable::getSelection,
action -> this.removeFormView(action, attrTable),
pageActionBuilder EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY)
.noEventPropagation()
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_NEW) .publishIf(attrTable::hasAnyContent, false)
.publishIf(() -> writeGrant && isReadonly)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_LIST_ATTACH_DEFAULT_VIEW)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_MODIFY) .withParentEntityKey(entityKey)
.withEntityKey(entityKey) .withSelect(
.publishIf(() -> modifyGrant && isReadonly) attrTable::getSelection,
action -> this.attachView(action, attrTable),
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_CREATE_CONFIG) EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY)
.withEntityKey(entityKey) .noEventPropagation()
.withExec(SebExamConfigCreationPopup.configCreationFunction( .publishIf(attrTable::hasAnyContent, false);
this.pageService, }
pageContext
.withAttribute( pageActionBuilder
PageContext.AttributeKeys.CREATE_FROM_TEMPLATE,
Constants.TRUE_STRING) .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_NEW)
.withAttribute( .publishIf(() -> writeGrant && isReadonly)
PageContext.AttributeKeys.COPY_AS_TEMPLATE,
Constants.FALSE_STRING))) .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_MODIFY)
.publishIf(() -> modifyGrant && isReadonly) .withEntityKey(entityKey)
.publishIf(() -> modifyGrant && isReadonly)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_SAVE)
.withEntityKey(entityKey) .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_CREATE_CONFIG)
.withExec(formHandle::processFormSave) .withEntityKey(entityKey)
.ignoreMoveAwayFromEdit() .withExec(SebExamConfigCreationPopup.configCreationFunction(
.publishIf(() -> !isReadonly) this.pageService,
pageContext
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_CANCEL_MODIFY) .withAttribute(
.withEntityKey(entityKey) PageContext.AttributeKeys.CREATE_FROM_TEMPLATE,
.withExec(this.pageService.backToCurrentFunction()) Constants.TRUE_STRING)
.publishIf(() -> !isReadonly); .withAttribute(
PageContext.AttributeKeys.COPY_AS_TEMPLATE,
} Constants.FALSE_STRING)))
.publishIf(() -> modifyGrant && isReadonly)
private String getAttributeName(final TemplateAttribute attribute) {
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_SAVE)
final String name = this.i18nSupport.getText( .withEntityKey(entityKey)
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.getName(), .withExec(formHandle::processFormSave)
""); .ignoreMoveAwayFromEdit()
if (StringUtils.isNotBlank(name)) { .publishIf(() -> !isReadonly)
return attribute.getName() + " (" + name + ")";
} else { .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_CANCEL_MODIFY)
return attribute.getName(); .withEntityKey(entityKey)
} .withExec(this.pageService.backToCurrentFunction())
} .publishIf(() -> !isReadonly);
private final PageAction resetToDefaults( }
final PageAction action,
final EntityTable<TemplateAttribute> attrTable) { private String getAttributeName(final TemplateAttribute attribute) {
final PageAction resetToDefaults = this.examConfigurationService.resetToDefaults(action); final String name = this.i18nSupport.getText(
// reload the list ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.getName(),
attrTable.applyFilter(); "");
return resetToDefaults; if (StringUtils.isNotBlank(name)) {
} return attribute.getName() + " (" + name + ")";
} else {
private final PageAction removeFormView( return attribute.getName();
final PageAction action, }
final EntityTable<TemplateAttribute> attrTable) { }
final PageAction removeFormView = this.examConfigurationService.removeFromView(action); private PageAction resetToDefaults(
// reload the list final PageAction action,
attrTable.applyFilter(); final EntityTable<TemplateAttribute> attrTable) {
return removeFormView;
} final PageAction resetToDefaults = this.examConfigurationService.resetToDefaults(action);
// reload the list
private final PageAction attachView( attrTable.applyFilter();
final PageAction action, return resetToDefaults;
final EntityTable<TemplateAttribute> attrTable) { }
final PageAction attachView = this.examConfigurationService.attachToDefaultView(action); private PageAction removeFormView(
// reload the list final PageAction action,
attrTable.applyFilter(); final EntityTable<TemplateAttribute> attrTable) {
return attachView;
} final PageAction removeFormView = this.examConfigurationService.removeFromView(action);
// reload the list
} attrTable.applyFilter();
return removeFormView;
}
private PageAction attachView(
final PageAction action,
final EntityTable<TemplateAttribute> attrTable) {
final PageAction attachView = this.examConfigurationService.attachToDefaultView(action);
// reload the list
attrTable.applyFilter();
return attachView;
}
}

View file

@ -1,155 +1,159 @@
/* /*
* Copyright (c) 2020 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2020 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.content; package ch.ethz.seb.sebserver.gui.content;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.Entity; import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationType; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationType;
import ch.ethz.seb.sebserver.gbl.model.user.UserRole; import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.service.ResourceService; import ch.ethz.seb.sebserver.gui.service.ResourceService;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.PageContext; import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.PageService; import ch.ethz.seb.sebserver.gui.service.page.PageService;
import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder; import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction; import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigNodePage; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigNodePage;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck;
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition; import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute; import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute;
import ch.ethz.seb.sebserver.gui.table.EntityTable; import ch.ethz.seb.sebserver.gui.table.EntityTable;
import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType; import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@Lazy @Lazy
@Component @Component
@GuiProfile @GuiProfile
public class ConfigTemplateList implements TemplateComposer { public class ConfigTemplateList implements TemplateComposer {
private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION = private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION =
new LocTextKey("sebserver.examconfig.list.action.no.modify.privilege"); new LocTextKey("sebserver.examconfig.list.action.no.modify.privilege");
private static final LocTextKey TITLE_TEMPLATE_TEXT_KEY = private static final LocTextKey TITLE_TEMPLATE_TEXT_KEY =
new LocTextKey("sebserver.configtemplate.list.title"); new LocTextKey("sebserver.configtemplate.list.title");
private static final LocTextKey EMPTY_TEMPLATE_LIST_TEXT_KEY = private static final LocTextKey EMPTY_TEMPLATE_LIST_TEXT_KEY =
new LocTextKey("sebserver.configtemplate.list.empty"); new LocTextKey("sebserver.configtemplate.list.empty");
private static final LocTextKey INSTITUTION_TEXT_KEY = private static final LocTextKey INSTITUTION_TEXT_KEY =
new LocTextKey("sebserver.examconfig.list.column.institution"); new LocTextKey("sebserver.examconfig.list.column.institution");
private static final LocTextKey NAME_TEXT_KEY = private static final LocTextKey NAME_TEXT_KEY =
new LocTextKey("sebserver.examconfig.list.column.name"); new LocTextKey("sebserver.examconfig.list.column.name");
private static final LocTextKey DESCRIPTION_TEXT_KEY = private static final LocTextKey DESCRIPTION_TEXT_KEY =
new LocTextKey("sebserver.examconfig.list.column.description"); new LocTextKey("sebserver.examconfig.list.column.description");
private static final LocTextKey EMPTY_TEMPLATE_SELECTION_TEXT_KEY = private static final LocTextKey EMPTY_TEMPLATE_SELECTION_TEXT_KEY =
new LocTextKey("sebserver.configtemplate.info.pleaseSelect"); new LocTextKey("sebserver.configtemplate.info.pleaseSelect");
private final PageService pageService; private final PageService pageService;
private final RestService restService; private final RestService restService;
private final CurrentUser currentUser; private final CurrentUser currentUser;
private final ResourceService resourceService; private final ResourceService resourceService;
private final int pageSize; private final int pageSize;
private final TableFilterAttribute institutionFilter; private final TableFilterAttribute institutionFilter;
private final TableFilterAttribute nameFilter = private final TableFilterAttribute nameFilter =
new TableFilterAttribute(CriteriaType.TEXT, Entity.FILTER_ATTR_NAME); new TableFilterAttribute(CriteriaType.TEXT, Entity.FILTER_ATTR_NAME);
private final TableFilterAttribute descFilter = private final TableFilterAttribute descFilter =
new TableFilterAttribute(CriteriaType.TEXT, ConfigurationNode.FILTER_ATTR_DESCRIPTION); new TableFilterAttribute(CriteriaType.TEXT, ConfigurationNode.FILTER_ATTR_DESCRIPTION);
protected ConfigTemplateList( protected ConfigTemplateList(
final PageService pageService, final PageService pageService,
final RestService restService, final RestService restService,
final CurrentUser currentUser, final CurrentUser currentUser,
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) { @Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
this.pageService = pageService; this.pageService = pageService;
this.restService = restService; this.restService = restService;
this.currentUser = currentUser; this.currentUser = currentUser;
this.resourceService = pageService.getResourceService(); this.resourceService = pageService.getResourceService();
this.pageSize = pageSize; this.pageSize = pageSize;
this.institutionFilter = new TableFilterAttribute( this.institutionFilter = new TableFilterAttribute(
CriteriaType.SINGLE_SELECTION, CriteriaType.SINGLE_SELECTION,
Entity.FILTER_ATTR_INSTITUTION, Entity.FILTER_ATTR_INSTITUTION,
this.resourceService::institutionResource); this.resourceService::institutionResource);
} }
@Override @Override
public void compose(final PageContext pageContext) { public void compose(final PageContext pageContext) {
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory(); final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
final Composite content = widgetFactory.defaultPageLayout( final Composite content = widgetFactory.defaultPageLayout(
pageContext.getParent(), pageContext.getParent(),
TITLE_TEMPLATE_TEXT_KEY); TITLE_TEMPLATE_TEXT_KEY);
final boolean isSEBAdmin = this.currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN); final boolean isSEBAdmin = this.currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN);
final PageActionBuilder pageActionBuilder = final PageActionBuilder pageActionBuilder =
this.pageService.pageActionBuilder(pageContext.clearEntityKeys()); this.pageService.pageActionBuilder(pageContext.clearEntityKeys());
final EntityTable<ConfigurationNode> templateTable = final EntityTable<ConfigurationNode> templateTable =
this.pageService.entityTableBuilder( this.pageService.entityTableBuilder(
TITLE_TEMPLATE_TEXT_KEY.name, TITLE_TEMPLATE_TEXT_KEY.name,
this.restService.getRestCall(GetExamConfigNodePage.class)) this.restService.getRestCall(GetExamConfigNodePage.class))
.withStaticFilter( .withStaticFilter(
Domain.CONFIGURATION_NODE.ATTR_TYPE, Domain.CONFIGURATION_NODE.ATTR_TYPE,
ConfigurationType.TEMPLATE.name()) ConfigurationType.TEMPLATE.name())
.withEmptyMessage(EMPTY_TEMPLATE_LIST_TEXT_KEY) .withEmptyMessage(EMPTY_TEMPLATE_LIST_TEXT_KEY)
.withPaging(this.pageSize) .withPaging(this.pageSize)
.withColumnIf( .withColumnIf(
() -> isSEBAdmin, () -> isSEBAdmin,
() -> new ColumnDefinition<>( () -> new ColumnDefinition<>(
Domain.LMS_SETUP.ATTR_INSTITUTION_ID, Domain.LMS_SETUP.ATTR_INSTITUTION_ID,
INSTITUTION_TEXT_KEY, INSTITUTION_TEXT_KEY,
this.resourceService::localizedExamConfigInstitutionName) this.resourceService::localizedExamConfigInstitutionName)
.withFilter(this.institutionFilter) .withFilter(this.institutionFilter)
.sortable()) .sortable())
.withColumn(new ColumnDefinition<>( .withColumn(new ColumnDefinition<>(
Domain.CONFIGURATION_NODE.ATTR_NAME, Domain.CONFIGURATION_NODE.ATTR_NAME,
NAME_TEXT_KEY, NAME_TEXT_KEY,
ConfigurationNode::getName) ConfigurationNode::getName)
.withFilter(this.nameFilter) .withFilter(this.nameFilter)
.sortable()) .sortable())
.withColumn(new ColumnDefinition<>( .withColumn(new ColumnDefinition<>(
Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION, Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION,
DESCRIPTION_TEXT_KEY, DESCRIPTION_TEXT_KEY,
ConfigurationNode::getDescription) ConfigurationNode::getDescription)
.withFilter(this.descFilter) .withFilter(this.descFilter)
.sortable()) .sortable())
.withDefaultAction(pageActionBuilder .withDefaultAction(pageActionBuilder
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_VIEW_FROM_LIST) .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_VIEW_FROM_LIST)
.create()) .create())
.compose(pageContext.copyOf(content));
.withSelectionListener(this.pageService.getSelectionPublisher(
final GrantCheck examConfigGrant = this.currentUser.grantCheck(EntityType.CONFIGURATION_NODE); pageContext,
pageActionBuilder ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_VIEW_FROM_LIST,
// Exam Configuration template actions... ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_MODIFY_FROM_LIST))
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_NEW)
.publishIf(examConfigGrant::iw) .compose(pageContext.copyOf(content));
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_VIEW_FROM_LIST) final GrantCheck examConfigGrant = this.currentUser.grantCheck(EntityType.CONFIGURATION_NODE);
.withSelect(templateTable::getSelection, PageAction::applySingleSelectionAsEntityKey, pageActionBuilder
EMPTY_TEMPLATE_SELECTION_TEXT_KEY) // Exam Configuration template actions...
.publishIf(() -> templateTable.hasAnyContent()) .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_NEW)
.publishIf(examConfigGrant::iw)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_MODIFY_FROM_LIST)
.withSelect( .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_VIEW_FROM_LIST)
templateTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION), .withSelect(templateTable::getSelection, PageAction::applySingleSelectionAsEntityKey,
PageAction::applySingleSelectionAsEntityKey, EMPTY_TEMPLATE_SELECTION_TEXT_KEY) EMPTY_TEMPLATE_SELECTION_TEXT_KEY)
.publishIf(() -> examConfigGrant.im() && templateTable.hasAnyContent()); .publishIf(templateTable::hasAnyContent, false)
} .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_MODIFY_FROM_LIST)
.withSelect(
} templateTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION),
PageAction::applySingleSelectionAsEntityKey, EMPTY_TEMPLATE_SELECTION_TEXT_KEY)
.publishIf(() -> examConfigGrant.im() && templateTable.hasAnyContent(), false);
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,172 +1,167 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.content; package ch.ethz.seb.sebserver.gui.content;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.institution.Institution; import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.form.FormBuilder; import ch.ethz.seb.sebserver.gui.form.FormBuilder;
import ch.ethz.seb.sebserver.gui.form.FormHandle; import ch.ethz.seb.sebserver.gui.form.FormHandle;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.PageContext; import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.PageService; import ch.ethz.seb.sebserver.gui.service.page.PageService;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.page.impl.DefaultPageLayout; import ch.ethz.seb.sebserver.gui.service.page.impl.DefaultPageLayout;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.ActivateInstitution; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.ActivateInstitution;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.DeactivateInstitution; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.DeactivateInstitution;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitution; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitution;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.NewInstitution; 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.remote.webservice.api.institution.SaveInstitution;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.EntityGrantCheck; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.EntityGrantCheck;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@Lazy @Lazy
@Component @Component
@GuiProfile @GuiProfile
public class InstitutionForm implements TemplateComposer { public class InstitutionForm implements TemplateComposer {
private static final LocTextKey TITLE_TEXT_KEY = private static final LocTextKey TITLE_TEXT_KEY =
new LocTextKey("sebserver.institution.form.title"); new LocTextKey("sebserver.institution.form.title");
private static final LocTextKey NEW_TITLE_TEXT_KEY = private static final LocTextKey NEW_TITLE_TEXT_KEY =
new LocTextKey("sebserver.institution.form.title.new"); new LocTextKey("sebserver.institution.form.title.new");
private static final LocTextKey FORM_LOGO_IMAGE_TEXT_KEY = private static final LocTextKey FORM_LOGO_IMAGE_TEXT_KEY =
new LocTextKey("sebserver.institution.form.logoImage"); new LocTextKey("sebserver.institution.form.logoImage");
private static final LocTextKey FORM_URL_SUFFIX_TEXT_KEY = private static final LocTextKey FORM_URL_SUFFIX_TEXT_KEY =
new LocTextKey("sebserver.institution.form.urlSuffix"); new LocTextKey("sebserver.institution.form.urlSuffix");
private static final LocTextKey FORM_NAME_TEXT_KEY = private static final LocTextKey FORM_NAME_TEXT_KEY =
new LocTextKey("sebserver.institution.form.name"); new LocTextKey("sebserver.institution.form.name");
private final PageService pageService; private final PageService pageService;
private final RestService restService; private final RestService restService;
private final CurrentUser currentUser; private final CurrentUser currentUser;
protected InstitutionForm( protected InstitutionForm(
final PageService pageService, final PageService pageService,
final RestService restService, final RestService restService,
final CurrentUser currentUser) { final CurrentUser currentUser) {
this.pageService = pageService; this.pageService = pageService;
this.restService = restService; this.restService = restService;
this.currentUser = currentUser; this.currentUser = currentUser;
} }
@Override @Override
public void compose(final PageContext pageContext) { public void compose(final PageContext pageContext) {
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory(); final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
final EntityKey entityKey = pageContext.getEntityKey(); final EntityKey entityKey = pageContext.getEntityKey();
final boolean isNew = entityKey == null; final boolean isNew = entityKey == null;
// get data or create new. Handle error if happen // get data or create new. Handle error if happen
final Institution institution = (isNew) final Institution institution = (isNew)
? Institution.createNew() ? Institution.createNew()
: this.restService : this.restService
.getBuilder(GetInstitution.class) .getBuilder(GetInstitution.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId) .withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call() .call()
.onError(error -> pageContext.notifyLoadError(EntityType.INSTITUTION, error)) .onError(error -> pageContext.notifyLoadError(EntityType.INSTITUTION, error))
.getOrThrow(); .getOrThrow();
final EntityGrantCheck instGrant = this.currentUser.entityGrantCheck(institution); final EntityGrantCheck instGrant = this.currentUser.entityGrantCheck(institution);
final boolean writeGrant = instGrant.w(); final boolean writeGrant = instGrant.w();
final boolean modifyGrant = instGrant.m(); final boolean modifyGrant = instGrant.m();
final boolean isReadonly = pageContext.isReadonly(); final boolean isReadonly = pageContext.isReadonly();
// new PageContext with actual EntityKey // new PageContext with actual EntityKey
final PageContext formContext = pageContext.withEntityKey(institution.getEntityKey()); final PageContext formContext = pageContext.withEntityKey(institution.getEntityKey());
// the default page layout with interactive title // the default page layout with interactive title
final LocTextKey titleKey = isNew final LocTextKey titleKey = isNew
? NEW_TITLE_TEXT_KEY ? NEW_TITLE_TEXT_KEY
: TITLE_TEXT_KEY; : TITLE_TEXT_KEY;
final Composite content = widgetFactory.defaultPageLayout( final Composite content = widgetFactory.defaultPageLayout(
formContext.getParent(), formContext.getParent(),
titleKey); titleKey);
// The Institution form // The Institution form
final FormHandle<Institution> formHandle = this.pageService.formBuilder( final FormHandle<Institution> formHandle = this.pageService.formBuilder(
formContext.copyOf(content)) formContext.copyOf(content))
.readonly(isReadonly) .readonly(isReadonly)
.putStaticValueIf(() -> !isNew, .putStaticValueIf(() -> !isNew,
Domain.INSTITUTION.ATTR_ID, Domain.INSTITUTION.ATTR_ID,
institution.getModelId()) institution.getModelId())
.addField(FormBuilder.text( .addField(FormBuilder.text(
Domain.INSTITUTION.ATTR_NAME, Domain.INSTITUTION.ATTR_NAME,
FORM_NAME_TEXT_KEY, FORM_NAME_TEXT_KEY,
institution.name) institution.name)
.mandatory(!isReadonly)) .mandatory(!isReadonly))
.addField(FormBuilder.text( .addField(FormBuilder.text(
Domain.INSTITUTION.ATTR_URL_SUFFIX, Domain.INSTITUTION.ATTR_URL_SUFFIX,
FORM_URL_SUFFIX_TEXT_KEY, FORM_URL_SUFFIX_TEXT_KEY,
institution.urlSuffix)) institution.urlSuffix))
.addField(FormBuilder.imageUpload( .addField(FormBuilder.imageUpload(
Domain.INSTITUTION.ATTR_LOGO_IMAGE, Domain.INSTITUTION.ATTR_LOGO_IMAGE,
FORM_LOGO_IMAGE_TEXT_KEY, FORM_LOGO_IMAGE_TEXT_KEY,
institution.logoImage) institution.logoImage)
.withMaxWidth(DefaultPageLayout.LOGO_IMAGE_MAX_WIDTH) .withMaxWidth(DefaultPageLayout.LOGO_IMAGE_MAX_WIDTH)
.withMaxHeight(DefaultPageLayout.LOGO_IMAGE_MAX_HEIGHT)) .withMaxHeight(DefaultPageLayout.LOGO_IMAGE_MAX_HEIGHT))
.buildFor((isNew) .buildFor((isNew)
? this.restService.getRestCall(NewInstitution.class) ? this.restService.getRestCall(NewInstitution.class)
: this.restService.getRestCall(SaveInstitution.class)); : this.restService.getRestCall(SaveInstitution.class));
// propagate content actions to action-pane // propagate content actions to action-pane
this.pageService.pageActionBuilder(formContext.clearEntityKeys()) this.pageService.pageActionBuilder(formContext.clearEntityKeys())
.newAction(ActionDefinition.INSTITUTION_NEW) .newAction(ActionDefinition.INSTITUTION_NEW)
.publishIf(() -> writeGrant && isReadonly) .publishIf(() -> writeGrant && isReadonly)
// Removed as discussed in SEBSERV-52 .newAction(ActionDefinition.INSTITUTION_MODIFY)
// .newAction(ActionDefinition.USER_ACCOUNT_NEW) .withEntityKey(entityKey)
// .withParentEntityKey(entityKey) .publishIf(() -> modifyGrant && isReadonly)
// .publishIf(() -> userWriteGrant && isReadonly && institution.isActive())
.newAction(ActionDefinition.INSTITUTION_DEACTIVATE)
.newAction(ActionDefinition.INSTITUTION_MODIFY) .withEntityKey(entityKey)
.withEntityKey(entityKey) .withSimpleRestCall(this.restService, DeactivateInstitution.class)
.publishIf(() -> modifyGrant && isReadonly) .withConfirm(this.pageService.confirmDeactivation(institution))
.publishIf(() -> writeGrant && isReadonly && institution.isActive())
.newAction(ActionDefinition.INSTITUTION_DEACTIVATE)
.withEntityKey(entityKey) .newAction(ActionDefinition.INSTITUTION_ACTIVATE)
.withSimpleRestCall(this.restService, DeactivateInstitution.class) .withEntityKey(entityKey)
.withConfirm(this.pageService.confirmDeactivation(institution)) .withSimpleRestCall(this.restService, ActivateInstitution.class)
.publishIf(() -> writeGrant && isReadonly && institution.isActive()) .publishIf(() -> writeGrant && isReadonly && !institution.isActive())
.newAction(ActionDefinition.INSTITUTION_ACTIVATE) .newAction(ActionDefinition.INSTITUTION_SAVE)
.withEntityKey(entityKey) .withEntityKey(entityKey)
.withSimpleRestCall(this.restService, ActivateInstitution.class) .withExec(formHandle::processFormSave)
.publishIf(() -> writeGrant && isReadonly && !institution.isActive()) .ignoreMoveAwayFromEdit()
.publishIf(() -> !isReadonly)
.newAction(ActionDefinition.INSTITUTION_SAVE)
.withEntityKey(entityKey) .newAction(ActionDefinition.INSTITUTION_SAVE_AND_ACTIVATE)
.withExec(formHandle::processFormSave) .withEntityKey(entityKey)
.ignoreMoveAwayFromEdit() .withExec(formHandle::saveAndActivate)
.publishIf(() -> !isReadonly) .ignoreMoveAwayFromEdit()
.publishIf(() -> !isReadonly && !institution.isActive())
.newAction(ActionDefinition.INSTITUTION_SAVE_AND_ACTIVATE)
.withEntityKey(entityKey) .newAction(ActionDefinition.INSTITUTION_CANCEL_MODIFY)
.withExec(formHandle::saveAndActivate) .withEntityKey(entityKey)
.ignoreMoveAwayFromEdit() .withExec(this.pageService.backToCurrentFunction())
.publishIf(() -> !isReadonly && !institution.isActive()) .publishIf(() -> !isReadonly);
}
.newAction(ActionDefinition.INSTITUTION_CANCEL_MODIFY)
.withEntityKey(entityKey) }
.withExec(this.pageService.backToCurrentFunction())
.publishIf(() -> !isReadonly);
}
}

View file

@ -1,158 +1,158 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.content; package ch.ethz.seb.sebserver.gui.content;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.Entity; import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.institution.Institution; import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.PageContext; import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.PageService; import ch.ethz.seb.sebserver.gui.service.page.PageService;
import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder; import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction; import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitutionPage; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitutionPage;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck;
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition; import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute; import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute;
import ch.ethz.seb.sebserver.gui.table.EntityTable; import ch.ethz.seb.sebserver.gui.table.EntityTable;
import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType; import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
@Lazy @Lazy
@Component @Component
@GuiProfile @GuiProfile
public class InstitutionList implements TemplateComposer { public class InstitutionList implements TemplateComposer {
private static final LocTextKey EMPTY_LIST_TEXT_KEY = private static final LocTextKey EMPTY_LIST_TEXT_KEY =
new LocTextKey("sebserver.institution.list.empty"); new LocTextKey("sebserver.institution.list.empty");
private static final LocTextKey TITLE_TEXT_KEY = private static final LocTextKey TITLE_TEXT_KEY =
new LocTextKey("sebserver.institution.list.title"); new LocTextKey("sebserver.institution.list.title");
private static final LocTextKey NAME_TEXT_KEY = private static final LocTextKey NAME_TEXT_KEY =
new LocTextKey("sebserver.institution.list.column.name"); new LocTextKey("sebserver.institution.list.column.name");
private static final LocTextKey URL_TEXT_KEY = private static final LocTextKey URL_TEXT_KEY =
new LocTextKey("sebserver.institution.list.column.urlSuffix"); new LocTextKey("sebserver.institution.list.column.urlSuffix");
private static final LocTextKey ACTIVE_TEXT_KEY = private static final LocTextKey ACTIVE_TEXT_KEY =
new LocTextKey("sebserver.institution.list.column.active"); new LocTextKey("sebserver.institution.list.column.active");
private static final LocTextKey EMPTY_SELECTION_TEXT_KEY = private static final LocTextKey EMPTY_SELECTION_TEXT_KEY =
new LocTextKey("sebserver.institution.info.pleaseSelect"); new LocTextKey("sebserver.institution.info.pleaseSelect");
private final TableFilterAttribute nameFilter = private final TableFilterAttribute nameFilter =
new TableFilterAttribute(CriteriaType.TEXT, Entity.FILTER_ATTR_NAME); new TableFilterAttribute(CriteriaType.TEXT, Entity.FILTER_ATTR_NAME);
private final TableFilterAttribute urlSuffixFilter = private final TableFilterAttribute urlSuffixFilter =
new TableFilterAttribute(CriteriaType.TEXT, Institution.FILTER_ATTR_URL_SUFFIX); new TableFilterAttribute(CriteriaType.TEXT, Institution.FILTER_ATTR_URL_SUFFIX);
private final TableFilterAttribute activityFilter; private final TableFilterAttribute activityFilter;
private final PageService pageService; private final PageService pageService;
private final RestService restService; private final RestService restService;
private final CurrentUser currentUser; private final CurrentUser currentUser;
private final int pageSize; private final int pageSize;
protected InstitutionList( protected InstitutionList(
final PageService pageService, final PageService pageService,
final RestService restService, final RestService restService,
final CurrentUser currentUser, final CurrentUser currentUser,
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) { @Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
this.pageService = pageService; this.pageService = pageService;
this.restService = restService; this.restService = restService;
this.currentUser = currentUser; this.currentUser = currentUser;
this.pageSize = pageSize; this.pageSize = pageSize;
this.activityFilter = new TableFilterAttribute( this.activityFilter = new TableFilterAttribute(
CriteriaType.SINGLE_SELECTION, CriteriaType.SINGLE_SELECTION,
Institution.FILTER_ATTR_ACTIVE, Institution.FILTER_ATTR_ACTIVE,
StringUtils.EMPTY, StringUtils.EMPTY,
this.pageService.getResourceService()::activityResources); this.pageService.getResourceService()::activityResources);
} }
@Override @Override
public void compose(final PageContext pageContext) { public void compose(final PageContext pageContext) {
final Composite content = this.pageService.getWidgetFactory().defaultPageLayout( final Composite content = this.pageService.getWidgetFactory().defaultPageLayout(
pageContext.getParent(), pageContext.getParent(),
TITLE_TEXT_KEY); TITLE_TEXT_KEY);
final PageActionBuilder pageActionBuilder = final PageActionBuilder pageActionBuilder =
this.pageService.pageActionBuilder(pageContext.clearEntityKeys()); this.pageService.pageActionBuilder(pageContext.clearEntityKeys());
// table // table
final EntityTable<Institution> table = final EntityTable<Institution> table =
this.pageService.entityTableBuilder(this.restService.getRestCall(GetInstitutionPage.class)) this.pageService.entityTableBuilder(this.restService.getRestCall(GetInstitutionPage.class))
.withEmptyMessage(EMPTY_LIST_TEXT_KEY) .withEmptyMessage(EMPTY_LIST_TEXT_KEY)
.withPaging(this.pageSize) .withPaging(this.pageSize)
.withColumn(new ColumnDefinition<>( .withColumn(new ColumnDefinition<>(
Domain.INSTITUTION.ATTR_NAME, Domain.INSTITUTION.ATTR_NAME,
NAME_TEXT_KEY, NAME_TEXT_KEY,
Institution::getName) Institution::getName)
.sortable() .sortable()
.withFilter(this.nameFilter)) .withFilter(this.nameFilter))
.withColumn(new ColumnDefinition<>( .withColumn(new ColumnDefinition<>(
Domain.INSTITUTION.ATTR_URL_SUFFIX, Domain.INSTITUTION.ATTR_URL_SUFFIX,
URL_TEXT_KEY, URL_TEXT_KEY,
Institution::getUrlSuffix) Institution::getUrlSuffix)
.sortable() .sortable()
.withFilter(this.urlSuffixFilter)) .withFilter(this.urlSuffixFilter))
.withColumn(new ColumnDefinition<>( .withColumn(new ColumnDefinition<>(
Domain.INSTITUTION.ATTR_ACTIVE, Domain.INSTITUTION.ATTR_ACTIVE,
ACTIVE_TEXT_KEY, ACTIVE_TEXT_KEY,
this.pageService.getResourceService().<Institution> localizedActivityFunction()) this.pageService.getResourceService().<Institution> localizedActivityFunction())
.sortable() .sortable()
.withFilter(this.activityFilter)) .withFilter(this.activityFilter))
.withDefaultAction(pageActionBuilder .withDefaultAction(pageActionBuilder
.newAction(ActionDefinition.INSTITUTION_VIEW_FROM_LIST) .newAction(ActionDefinition.INSTITUTION_VIEW_FROM_LIST)
.create()) .create())
.withSelectionListener(this.pageService.getSelectionPublisher( .withSelectionListener(this.pageService.getSelectionPublisher(
ActionDefinition.INSTITUTION_TOGGLE_ACTIVITY, ActionDefinition.INSTITUTION_TOGGLE_ACTIVITY,
ActionDefinition.INSTITUTION_ACTIVATE, ActionDefinition.INSTITUTION_ACTIVATE,
ActionDefinition.INSTITUTION_DEACTIVATE, ActionDefinition.INSTITUTION_DEACTIVATE,
pageContext, pageContext,
ActionDefinition.INSTITUTION_VIEW_FROM_LIST, ActionDefinition.INSTITUTION_VIEW_FROM_LIST,
ActionDefinition.INSTITUTION_MODIFY_FROM_LIST, ActionDefinition.INSTITUTION_MODIFY_FROM_LIST,
ActionDefinition.INSTITUTION_TOGGLE_ACTIVITY)) ActionDefinition.INSTITUTION_TOGGLE_ACTIVITY))
.compose(pageContext.copyOf(content)); .compose(pageContext.copyOf(content));
// propagate content actions to action-pane // propagate content actions to action-pane
final GrantCheck instGrant = this.currentUser.grantCheck(EntityType.INSTITUTION); final GrantCheck instGrant = this.currentUser.grantCheck(EntityType.INSTITUTION);
pageActionBuilder pageActionBuilder
.newAction(ActionDefinition.INSTITUTION_NEW) .newAction(ActionDefinition.INSTITUTION_NEW)
.publishIf(instGrant::w) .publishIf(instGrant::w)
.newAction(ActionDefinition.INSTITUTION_VIEW_FROM_LIST) .newAction(ActionDefinition.INSTITUTION_VIEW_FROM_LIST)
.withSelect( .withSelect(
table::getSelection, table::getSelection,
PageAction::applySingleSelectionAsEntityKey, PageAction::applySingleSelectionAsEntityKey,
EMPTY_SELECTION_TEXT_KEY) EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> table.hasAnyContent(), false) .publishIf(table::hasAnyContent, false)
.newAction(ActionDefinition.INSTITUTION_MODIFY_FROM_LIST) .newAction(ActionDefinition.INSTITUTION_MODIFY_FROM_LIST)
.withSelect( .withSelect(
table::getSelection, table::getSelection,
PageAction::applySingleSelectionAsEntityKey, PageAction::applySingleSelectionAsEntityKey,
EMPTY_SELECTION_TEXT_KEY) EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> instGrant.m() && table.hasAnyContent(), false) .publishIf(() -> instGrant.m() && table.hasAnyContent(), false)
.newAction(ActionDefinition.INSTITUTION_TOGGLE_ACTIVITY) .newAction(ActionDefinition.INSTITUTION_TOGGLE_ACTIVITY)
.withExec(this.pageService.activationToggleActionFunction(table, EMPTY_SELECTION_TEXT_KEY)) .withExec(this.pageService.activationToggleActionFunction(table, EMPTY_SELECTION_TEXT_KEY))
.withConfirm(this.pageService.confirmDeactivation(table)) .withConfirm(this.pageService.confirmDeactivation(table))
.publishIf(() -> instGrant.m() && table.hasAnyContent(), false); .publishIf(() -> instGrant.m() && table.hasAnyContent(), false);
} }
} }

View file

@ -1,205 +1,211 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.content; package ch.ethz.seb.sebserver.gui.content;
import org.eclipse.rap.rwt.RWT; import org.eclipse.rap.rwt.RWT;
import org.eclipse.rap.rwt.client.service.UrlLauncher; import org.eclipse.rap.rwt.client.service.UrlLauncher;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SebClientConfig; import ch.ethz.seb.sebserver.gbl.model.sebconfig.SebClientConfig;
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.form.FormBuilder; import ch.ethz.seb.sebserver.gui.form.FormBuilder;
import ch.ethz.seb.sebserver.gui.form.FormHandle; import ch.ethz.seb.sebserver.gui.form.FormHandle;
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport; 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.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.PageContext; import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.PageService; import ch.ethz.seb.sebserver.gui.service.page.PageService;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.remote.download.DownloadService; import ch.ethz.seb.sebserver.gui.service.remote.download.DownloadService;
import ch.ethz.seb.sebserver.gui.service.remote.download.SebClientConfigDownload; import ch.ethz.seb.sebserver.gui.service.remote.download.SebClientConfigDownload;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.ActivateClientConfig; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.ActivateClientConfig;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.DeactivateClientConfig; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.DeactivateClientConfig;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.GetClientConfig; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.GetClientConfig;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.NewClientConfig; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.NewClientConfig;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.SaveClientConfig; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.SaveClientConfig;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.EntityGrantCheck; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.EntityGrantCheck;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@Lazy @Lazy
@Component @Component
@GuiProfile @GuiProfile
public class SebClientConfigForm implements TemplateComposer { public class SebClientConfigForm implements TemplateComposer {
private static final LocTextKey FORM_TITLE_NEW = private static final LocTextKey FORM_TITLE_NEW =
new LocTextKey("sebserver.clientconfig.form.title.new"); new LocTextKey("sebserver.clientconfig.form.title.new");
private static final LocTextKey FORM_TITLE = private static final LocTextKey FORM_TITLE =
new LocTextKey("sebserver.clientconfig.form.title"); new LocTextKey("sebserver.clientconfig.form.title");
private static final LocTextKey FORM_NAME_TEXT_KEY = private static final LocTextKey FORM_NAME_TEXT_KEY =
new LocTextKey("sebserver.clientconfig.form.name"); new LocTextKey("sebserver.clientconfig.form.name");
private static final LocTextKey FORM_FALLBACK_URL_TEXT_KEY = private static final LocTextKey FORM_FALLBACK_URL_TEXT_KEY =
new LocTextKey("sebserver.clientconfig.form.fallback-url"); new LocTextKey("sebserver.clientconfig.form.fallback-url");
private static final LocTextKey FORM_DATE_TEXT_KEY = private static final LocTextKey FORM_DATE_TEXT_KEY =
new LocTextKey("sebserver.clientconfig.form.date"); new LocTextKey("sebserver.clientconfig.form.date");
private static final LocTextKey FORM_ENCRYPT_SECRET_TEXT_KEY = private static final LocTextKey FORM_ENCRYPT_SECRET_TEXT_KEY =
new LocTextKey("sebserver.clientconfig.form.encryptSecret"); new LocTextKey("sebserver.clientconfig.form.encryptSecret");
private static final LocTextKey FORM_CONFIRM_ENCRYPT_SECRET_TEXT_KEY = private static final LocTextKey FORM_CONFIRM_ENCRYPT_SECRET_TEXT_KEY =
new LocTextKey("sebserver.clientconfig.form.encryptSecret.confirm"); new LocTextKey("sebserver.clientconfig.form.encryptSecret.confirm");
private final PageService pageService; private final PageService pageService;
private final RestService restService; private final RestService restService;
private final CurrentUser currentUser; private final CurrentUser currentUser;
private final DownloadService downloadService; private final DownloadService downloadService;
private final String downloadFileName; private final String downloadFileName;
protected SebClientConfigForm( protected SebClientConfigForm(
final PageService pageService, final PageService pageService,
final RestService restService, final RestService restService,
final CurrentUser currentUser, final CurrentUser currentUser,
final DownloadService downloadService, final DownloadService downloadService,
@Value("${sebserver.gui.seb.client.config.download.filename}") final String downloadFileName) { @Value("${sebserver.gui.seb.client.config.download.filename}") final String downloadFileName) {
this.pageService = pageService; this.pageService = pageService;
this.restService = restService; this.restService = restService;
this.currentUser = currentUser; this.currentUser = currentUser;
this.downloadService = downloadService; this.downloadService = downloadService;
this.downloadFileName = downloadFileName; this.downloadFileName = downloadFileName;
} }
@Override @Override
public void compose(final PageContext pageContext) { public void compose(final PageContext pageContext) {
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory(); final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
final I18nSupport i18nSupport = this.pageService.getI18nSupport(); final I18nSupport i18nSupport = this.pageService.getI18nSupport();
final UserInfo user = this.currentUser.get(); final UserInfo user = this.currentUser.get();
final EntityKey entityKey = pageContext.getEntityKey(); final EntityKey entityKey = pageContext.getEntityKey();
final EntityKey parentEntityKey = pageContext.getParentEntityKey(); final EntityKey parentEntityKey = pageContext.getParentEntityKey();
final boolean isNew = entityKey == null; final boolean isNew = entityKey == null;
// get data or create new. Handle error if happen // get data or create new. Handle error if happen
final SebClientConfig clientConfig = (isNew) final SebClientConfig clientConfig = (isNew)
? SebClientConfig.createNew((parentEntityKey != null) ? SebClientConfig.createNew((parentEntityKey != null)
? Long.valueOf(parentEntityKey.modelId) ? Long.valueOf(parentEntityKey.modelId)
: user.institutionId) : user.institutionId)
: this.restService : this.restService
.getBuilder(GetClientConfig.class) .getBuilder(GetClientConfig.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId) .withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call() .call()
.onError(error -> pageContext.notifyLoadError(EntityType.SEB_CLIENT_CONFIGURATION, error)) .onError(error -> pageContext.notifyLoadError(EntityType.SEB_CLIENT_CONFIGURATION, error))
.getOrThrow(); .getOrThrow();
final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(clientConfig); final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(clientConfig);
final boolean writeGrant = entityGrant.w(); final boolean writeGrant = entityGrant.w();
final boolean modifyGrant = entityGrant.m(); final boolean modifyGrant = entityGrant.m();
final boolean isReadonly = pageContext.isReadonly(); final boolean isReadonly = pageContext.isReadonly();
// new PageContext with actual EntityKey // new PageContext with actual EntityKey
final PageContext formContext = pageContext.withEntityKey(clientConfig.getEntityKey()); final PageContext formContext = pageContext.withEntityKey(clientConfig.getEntityKey());
// the default page layout with interactive title // the default page layout with interactive title
final LocTextKey titleKey = (isNew) final LocTextKey titleKey = (isNew)
? FORM_TITLE_NEW ? FORM_TITLE_NEW
: FORM_TITLE; : FORM_TITLE;
final Composite content = widgetFactory.defaultPageLayout( final Composite content = widgetFactory.defaultPageLayout(
formContext.getParent(), formContext.getParent(),
titleKey); titleKey);
// The SebClientConfig form // The SebClientConfig form
final FormHandle<SebClientConfig> formHandle = this.pageService.formBuilder( final FormHandle<SebClientConfig> formHandle = this.pageService.formBuilder(
formContext.copyOf(content)) formContext.copyOf(content))
.readonly(isReadonly) .readonly(isReadonly)
.putStaticValueIf(() -> !isNew, .putStaticValueIf(() -> !isNew,
Domain.SEB_CLIENT_CONFIGURATION.ATTR_ID, Domain.SEB_CLIENT_CONFIGURATION.ATTR_ID,
clientConfig.getModelId()) clientConfig.getModelId())
.putStaticValue( .putStaticValue(
Domain.SEB_CLIENT_CONFIGURATION.ATTR_INSTITUTION_ID, Domain.SEB_CLIENT_CONFIGURATION.ATTR_INSTITUTION_ID,
String.valueOf(clientConfig.getInstitutionId())) String.valueOf(clientConfig.getInstitutionId()))
.addField(FormBuilder.text( .addField(FormBuilder.text(
Domain.SEB_CLIENT_CONFIGURATION.ATTR_NAME, Domain.SEB_CLIENT_CONFIGURATION.ATTR_NAME,
FORM_NAME_TEXT_KEY, FORM_NAME_TEXT_KEY,
clientConfig.name)) clientConfig.name))
.addField(FormBuilder.text( .addField(FormBuilder.text(
SebClientConfig.ATTR_FALLBACK_START_URL, SebClientConfig.ATTR_FALLBACK_START_URL,
FORM_FALLBACK_URL_TEXT_KEY, FORM_FALLBACK_URL_TEXT_KEY,
clientConfig.fallbackStartURL)) clientConfig.fallbackStartURL))
.addFieldIf(() -> !isNew, .addFieldIf(() -> !isNew,
() -> FormBuilder.text( () -> FormBuilder.text(
Domain.SEB_CLIENT_CONFIGURATION.ATTR_DATE, Domain.SEB_CLIENT_CONFIGURATION.ATTR_DATE,
FORM_DATE_TEXT_KEY, FORM_DATE_TEXT_KEY,
i18nSupport.formatDisplayDateWithTimeZone(clientConfig.date)) i18nSupport.formatDisplayDateWithTimeZone(clientConfig.date))
.readonly(true)) .readonly(true))
.addField(FormBuilder.text( .addField(FormBuilder.text(
Domain.SEB_CLIENT_CONFIGURATION.ATTR_ENCRYPT_SECRET, Domain.SEB_CLIENT_CONFIGURATION.ATTR_ENCRYPT_SECRET,
FORM_ENCRYPT_SECRET_TEXT_KEY) FORM_ENCRYPT_SECRET_TEXT_KEY)
.asPasswordField()) .asPasswordField())
.addField(FormBuilder.text( .addField(FormBuilder.text(
SebClientConfig.ATTR_CONFIRM_ENCRYPT_SECRET, SebClientConfig.ATTR_CONFIRM_ENCRYPT_SECRET,
FORM_CONFIRM_ENCRYPT_SECRET_TEXT_KEY) FORM_CONFIRM_ENCRYPT_SECRET_TEXT_KEY)
.asPasswordField()) .asPasswordField())
.buildFor((isNew) .buildFor((isNew)
? this.restService.getRestCall(NewClientConfig.class) ? this.restService.getRestCall(NewClientConfig.class)
: this.restService.getRestCall(SaveClientConfig.class)); : this.restService.getRestCall(SaveClientConfig.class));
final UrlLauncher urlLauncher = RWT.getClient().getService(UrlLauncher.class); final UrlLauncher urlLauncher = RWT.getClient().getService(UrlLauncher.class);
this.pageService.pageActionBuilder(formContext.clearEntityKeys()) this.pageService.pageActionBuilder(formContext.clearEntityKeys())
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_NEW) .newAction(ActionDefinition.SEB_CLIENT_CONFIG_NEW)
.publishIf(() -> writeGrant && isReadonly) .publishIf(() -> writeGrant && isReadonly)
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_MODIFY) .newAction(ActionDefinition.SEB_CLIENT_CONFIG_MODIFY)
.withEntityKey(entityKey) .withEntityKey(entityKey)
.publishIf(() -> modifyGrant && isReadonly) .publishIf(() -> modifyGrant && isReadonly)
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_EXPORT) .newAction(ActionDefinition.SEB_CLIENT_CONFIG_EXPORT)
.withEntityKey(entityKey) .withEntityKey(entityKey)
.withExec(action -> { .withExec(action -> {
final String downloadURL = this.downloadService.createDownloadURL( final String downloadURL = this.downloadService.createDownloadURL(
entityKey.modelId, entityKey.modelId,
SebClientConfigDownload.class, SebClientConfigDownload.class,
this.downloadFileName); this.downloadFileName);
urlLauncher.openURL(downloadURL); urlLauncher.openURL(downloadURL);
return action; return action;
}) })
.publishIf(() -> writeGrant && isReadonly && clientConfig.isActive()) .publishIf(() -> writeGrant && isReadonly && clientConfig.isActive())
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_DEACTIVATE) .newAction(ActionDefinition.SEB_CLIENT_CONFIG_DEACTIVATE)
.withEntityKey(entityKey) .withEntityKey(entityKey)
.withSimpleRestCall(this.restService, DeactivateClientConfig.class) .withSimpleRestCall(this.restService, DeactivateClientConfig.class)
.withConfirm(this.pageService.confirmDeactivation(clientConfig)) .withConfirm(this.pageService.confirmDeactivation(clientConfig))
.publishIf(() -> writeGrant && isReadonly && clientConfig.isActive()) .publishIf(() -> writeGrant && isReadonly && clientConfig.isActive())
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_ACTIVATE) .newAction(ActionDefinition.SEB_CLIENT_CONFIG_ACTIVATE)
.withEntityKey(entityKey) .withEntityKey(entityKey)
.withSimpleRestCall(this.restService, ActivateClientConfig.class) .withSimpleRestCall(this.restService, ActivateClientConfig.class)
.publishIf(() -> writeGrant && isReadonly && !clientConfig.isActive()) .publishIf(() -> writeGrant && isReadonly && !clientConfig.isActive())
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_SAVE) .newAction(ActionDefinition.SEB_CLIENT_CONFIG_SAVE)
.withEntityKey(entityKey) .withEntityKey(entityKey)
.withExec(formHandle::processFormSave) .withExec(formHandle::processFormSave)
.ignoreMoveAwayFromEdit() .ignoreMoveAwayFromEdit()
.publishIf(() -> !isReadonly) .publishIf(() -> !isReadonly)
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_CANCEL_MODIFY) .newAction(ActionDefinition.SEB_CLIENT_CONFIG_SAVE_AND_ACTIVATE)
.withEntityKey(entityKey) .withEntityKey(entityKey)
.withExec(this.pageService.backToCurrentFunction()) .withExec(formHandle::saveAndActivate)
.publishIf(() -> !isReadonly); .ignoreMoveAwayFromEdit()
} .publishIf(() -> !isReadonly && !clientConfig.isActive())
} .newAction(ActionDefinition.SEB_CLIENT_CONFIG_CANCEL_MODIFY)
.withEntityKey(entityKey)
.withExec(this.pageService.backToCurrentFunction())
.publishIf(() -> !isReadonly);
}
}

View file

@ -1,182 +1,199 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.content; package ch.ethz.seb.sebserver.gui.content;
import java.util.function.Function; import java.util.function.Function;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.joda.time.DateTimeZone; import org.joda.time.DateTimeZone;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.Entity; import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SebClientConfig; import ch.ethz.seb.sebserver.gbl.model.sebconfig.SebClientConfig;
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
import ch.ethz.seb.sebserver.gbl.model.user.UserRole; import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.service.ResourceService; import ch.ethz.seb.sebserver.gui.service.ResourceService;
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport; import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.PageContext; import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.PageService; import ch.ethz.seb.sebserver.gui.service.page.PageService;
import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder; import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction; import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.GetClientConfigPage; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig.GetClientConfigPage;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck;
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition; import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute; import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute;
import ch.ethz.seb.sebserver.gui.table.EntityTable; import ch.ethz.seb.sebserver.gui.table.EntityTable;
import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType; import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
@Lazy @Lazy
@Component @Component
@GuiProfile @GuiProfile
public class SebClientConfigList implements TemplateComposer { public class SebClientConfigList implements TemplateComposer {
private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION = private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION =
new LocTextKey("sebserver.clientconfig.list.action.no.modify.privilege"); new LocTextKey("sebserver.clientconfig.list.action.no.modify.privilege");
private static final LocTextKey EMPTY_LIST_TEXT_KEY = private static final LocTextKey EMPTY_LIST_TEXT_KEY =
new LocTextKey("sebserver.clientconfig.list.empty"); new LocTextKey("sebserver.clientconfig.list.empty");
private static final LocTextKey TITLE_TEXT_KEY = private static final LocTextKey TITLE_TEXT_KEY =
new LocTextKey("sebserver.clientconfig.list.title"); new LocTextKey("sebserver.clientconfig.list.title");
private static final LocTextKey INSTITUTION_TEXT_KEY = private static final LocTextKey INSTITUTION_TEXT_KEY =
new LocTextKey("sebserver.clientconfig.list.column.institution"); new LocTextKey("sebserver.clientconfig.list.column.institution");
private static final LocTextKey NAME_TEXT_KEY = private static final LocTextKey NAME_TEXT_KEY =
new LocTextKey("sebserver.clientconfig.list.column.name"); new LocTextKey("sebserver.clientconfig.list.column.name");
private static final LocTextKey ACTIVE_TEXT_KEY = private static final LocTextKey ACTIVE_TEXT_KEY =
new LocTextKey("sebserver.clientconfig.list.column.active"); new LocTextKey("sebserver.clientconfig.list.column.active");
private static final LocTextKey EMPTY_SELECTION_TEXT_KEY = private static final LocTextKey EMPTY_SELECTION_TEXT_KEY =
new LocTextKey("sebserver.clientconfig.info.pleaseSelect"); new LocTextKey("sebserver.clientconfig.info.pleaseSelect");
private final TableFilterAttribute institutionFilter; private final TableFilterAttribute institutionFilter;
private final TableFilterAttribute nameFilter = private final TableFilterAttribute nameFilter =
new TableFilterAttribute(CriteriaType.TEXT, Entity.FILTER_ATTR_NAME); new TableFilterAttribute(CriteriaType.TEXT, Entity.FILTER_ATTR_NAME);
private final TableFilterAttribute dateFilter = private final TableFilterAttribute dateFilter =
new TableFilterAttribute( new TableFilterAttribute(
CriteriaType.DATE, CriteriaType.DATE,
SebClientConfig.FILTER_ATTR_CREATION_DATE, SebClientConfig.FILTER_ATTR_CREATION_DATE,
DateTime.now(DateTimeZone.UTC) DateTime.now(DateTimeZone.UTC)
.minusYears(1) .minusYears(1)
.toString(Constants.DEFAULT_DATE_TIME_FORMAT)); .toString(Constants.DEFAULT_DATE_TIME_FORMAT));
private final TableFilterAttribute activityFilter; private final TableFilterAttribute activityFilter;
private final PageService pageService; private final PageService pageService;
private final RestService restService; private final RestService restService;
private final CurrentUser currentUser; private final CurrentUser currentUser;
private final ResourceService resourceService; private final ResourceService resourceService;
private final int pageSize; private final int pageSize;
protected SebClientConfigList( protected SebClientConfigList(
final PageService pageService, final PageService pageService,
final RestService restService, final RestService restService,
final CurrentUser currentUser, final CurrentUser currentUser,
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) { @Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
this.pageService = pageService; this.pageService = pageService;
this.restService = restService; this.restService = restService;
this.currentUser = currentUser; this.currentUser = currentUser;
this.resourceService = pageService.getResourceService(); this.resourceService = pageService.getResourceService();
this.pageSize = pageSize; this.pageSize = pageSize;
this.institutionFilter = new TableFilterAttribute( this.institutionFilter = new TableFilterAttribute(
CriteriaType.SINGLE_SELECTION, CriteriaType.SINGLE_SELECTION,
Entity.FILTER_ATTR_INSTITUTION, Entity.FILTER_ATTR_INSTITUTION,
this.resourceService::institutionResource); this.resourceService::institutionResource);
this.activityFilter = new TableFilterAttribute( this.activityFilter = new TableFilterAttribute(
CriteriaType.SINGLE_SELECTION, CriteriaType.SINGLE_SELECTION,
UserInfo.FILTER_ATTR_ACTIVE, UserInfo.FILTER_ATTR_ACTIVE,
this.resourceService::activityResources); this.resourceService::activityResources);
} }
@Override @Override
public void compose(final PageContext pageContext) { public void compose(final PageContext pageContext) {
final I18nSupport i18nSupport = this.pageService.getI18nSupport(); final I18nSupport i18nSupport = this.pageService.getI18nSupport();
final Composite content = this.pageService.getWidgetFactory().defaultPageLayout( final Composite content = this.pageService.getWidgetFactory().defaultPageLayout(
pageContext.getParent(), pageContext.getParent(),
TITLE_TEXT_KEY); TITLE_TEXT_KEY);
final boolean isSEBAdmin = this.currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN); final boolean isSEBAdmin = this.currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN);
final PageActionBuilder pageActionBuilder = final PageActionBuilder pageActionBuilder =
this.pageService.pageActionBuilder(pageContext.clearEntityKeys()); this.pageService.pageActionBuilder(pageContext.clearEntityKeys());
// table // table
final EntityTable<SebClientConfig> table = final EntityTable<SebClientConfig> table =
this.pageService.entityTableBuilder(this.restService.getRestCall(GetClientConfigPage.class)) this.pageService.entityTableBuilder(this.restService.getRestCall(GetClientConfigPage.class))
.withEmptyMessage(EMPTY_LIST_TEXT_KEY) .withEmptyMessage(EMPTY_LIST_TEXT_KEY)
.withPaging(this.pageSize) .withPaging(this.pageSize)
.withColumnIf( .withColumnIf(
() -> isSEBAdmin, () -> isSEBAdmin,
() -> new ColumnDefinition<>( () -> new ColumnDefinition<>(
Domain.LMS_SETUP.ATTR_INSTITUTION_ID, Domain.LMS_SETUP.ATTR_INSTITUTION_ID,
INSTITUTION_TEXT_KEY, INSTITUTION_TEXT_KEY,
clientConfigInstitutionNameFunction(this.resourceService)) clientConfigInstitutionNameFunction(this.resourceService))
.withFilter(this.institutionFilter)) .withFilter(this.institutionFilter))
.withColumn(new ColumnDefinition<>( .withColumn(new ColumnDefinition<>(
Domain.SEB_CLIENT_CONFIGURATION.ATTR_NAME, Domain.SEB_CLIENT_CONFIGURATION.ATTR_NAME,
NAME_TEXT_KEY, NAME_TEXT_KEY,
SebClientConfig::getName) SebClientConfig::getName)
.withFilter(this.nameFilter) .withFilter(this.nameFilter)
.sortable()) .sortable())
.withColumn(new ColumnDefinition<>( .withColumn(new ColumnDefinition<>(
Domain.SEB_CLIENT_CONFIGURATION.ATTR_DATE, Domain.SEB_CLIENT_CONFIGURATION.ATTR_DATE,
new LocTextKey( new LocTextKey(
"sebserver.clientconfig.list.column.date", "sebserver.clientconfig.list.column.date",
i18nSupport.getUsersTimeZoneTitleSuffix()), i18nSupport.getUsersTimeZoneTitleSuffix()),
SebClientConfig::getDate) SebClientConfig::getDate)
.withFilter(this.dateFilter) .withFilter(this.dateFilter)
.sortable()) .sortable())
.withColumn(new ColumnDefinition<>( .withColumn(new ColumnDefinition<>(
Domain.SEB_CLIENT_CONFIGURATION.ATTR_ACTIVE, Domain.SEB_CLIENT_CONFIGURATION.ATTR_ACTIVE,
ACTIVE_TEXT_KEY, ACTIVE_TEXT_KEY,
this.pageService.getResourceService().<SebClientConfig> localizedActivityFunction()) this.pageService.getResourceService().<SebClientConfig> localizedActivityFunction())
.withFilter(this.activityFilter) .withFilter(this.activityFilter)
.sortable()) .sortable())
.withDefaultAction(pageActionBuilder .withDefaultAction(pageActionBuilder
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_VIEW_FROM_LIST) .newAction(ActionDefinition.SEB_CLIENT_CONFIG_VIEW_FROM_LIST)
.create()) .create())
.compose(pageContext.copyOf(content));
.withSelectionListener(this.pageService.getSelectionPublisher(
final GrantCheck clientConfigGrant = this.currentUser.grantCheck(EntityType.SEB_CLIENT_CONFIGURATION); ActionDefinition.SEB_CLIENT_CONFIG_TOGGLE_ACTIVITY,
ActionDefinition.SEB_CLIENT_CONFIG_ACTIVATE,
pageActionBuilder ActionDefinition.SEB_CLIENT_CONFIG_DEACTIVATE,
pageContext,
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_NEW) ActionDefinition.SEB_CLIENT_CONFIG_VIEW_FROM_LIST,
.publishIf(clientConfigGrant::iw) ActionDefinition.SEB_CLIENT_CONFIG_MODIFY_FROM_LIST,
ActionDefinition.SEB_CLIENT_CONFIG_TOGGLE_ACTIVITY))
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_VIEW_FROM_LIST)
.withSelect(table::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) .compose(pageContext.copyOf(content));
.publishIf(() -> table.hasAnyContent())
final GrantCheck clientConfigGrant = this.currentUser.grantCheck(EntityType.SEB_CLIENT_CONFIGURATION);
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_MODIFY_FROM_LIST)
.withSelect( pageActionBuilder
table.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION),
PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) .newAction(ActionDefinition.SEB_CLIENT_CONFIG_NEW)
.publishIf(() -> clientConfigGrant.im() && table.hasAnyContent()); .publishIf(clientConfigGrant::iw)
} .newAction(ActionDefinition.SEB_CLIENT_CONFIG_VIEW_FROM_LIST)
.withSelect(table::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY)
private static Function<SebClientConfig, String> clientConfigInstitutionNameFunction( .publishIf(table::hasAnyContent, false)
final ResourceService resourceService) {
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_MODIFY_FROM_LIST)
return config -> resourceService.getInstitutionNameFunction() .withSelect(
.apply(String.valueOf(config.institutionId)); table.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION),
} PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> clientConfigGrant.im() && table.hasAnyContent(), false)
}
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_TOGGLE_ACTIVITY)
.withExec(this.pageService.activationToggleActionFunction(table, EMPTY_SELECTION_TEXT_KEY))
.withConfirm(this.pageService.confirmDeactivation(table))
.publishIf(() -> clientConfigGrant.im() && table.hasAnyContent(), false);
}
private static Function<SebClientConfig, String> clientConfigInstitutionNameFunction(
final ResourceService resourceService) {
return config -> resourceService.getInstitutionNameFunction()
.apply(String.valueOf(config.institutionId));
}
}

View file

@ -1,174 +1,178 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.content; package ch.ethz.seb.sebserver.gui.content;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.Entity; import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationType; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationType;
import ch.ethz.seb.sebserver.gbl.model.user.UserRole; import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.service.ResourceService; import ch.ethz.seb.sebserver.gui.service.ResourceService;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.PageContext; import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.PageService; import ch.ethz.seb.sebserver.gui.service.page.PageService;
import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder; import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction; import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigNodePage; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigNodePage;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck;
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition; import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute; import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute;
import ch.ethz.seb.sebserver.gui.table.EntityTable; import ch.ethz.seb.sebserver.gui.table.EntityTable;
import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType; import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@Lazy @Lazy
@Component @Component
@GuiProfile @GuiProfile
public class SebExamConfigList implements TemplateComposer { public class SebExamConfigList implements TemplateComposer {
private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION = private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION =
new LocTextKey("sebserver.examconfig.list.action.no.modify.privilege"); new LocTextKey("sebserver.examconfig.list.action.no.modify.privilege");
private static final LocTextKey EMPTY_CONFIG_LIST_TEXT_KEY = private static final LocTextKey EMPTY_CONFIG_LIST_TEXT_KEY =
new LocTextKey("sebserver.examconfig.list.empty"); new LocTextKey("sebserver.examconfig.list.empty");
private static final LocTextKey TITLE_CONFIGURATION_TEXT_KEY = private static final LocTextKey TITLE_CONFIGURATION_TEXT_KEY =
new LocTextKey("sebserver.examconfig.list.title"); new LocTextKey("sebserver.examconfig.list.title");
private static final LocTextKey INSTITUTION_TEXT_KEY = private static final LocTextKey INSTITUTION_TEXT_KEY =
new LocTextKey("sebserver.examconfig.list.column.institution"); new LocTextKey("sebserver.examconfig.list.column.institution");
private static final LocTextKey NAME_TEXT_KEY = private static final LocTextKey NAME_TEXT_KEY =
new LocTextKey("sebserver.examconfig.list.column.name"); new LocTextKey("sebserver.examconfig.list.column.name");
private static final LocTextKey DESCRIPTION_TEXT_KEY = private static final LocTextKey DESCRIPTION_TEXT_KEY =
new LocTextKey("sebserver.examconfig.list.column.description"); new LocTextKey("sebserver.examconfig.list.column.description");
private static final LocTextKey STATUS_TEXT_KEY = private static final LocTextKey STATUS_TEXT_KEY =
new LocTextKey("sebserver.examconfig.list.column.status"); new LocTextKey("sebserver.examconfig.list.column.status");
private static final LocTextKey EMPTY_SELECTION_TEXT_KEY = private static final LocTextKey EMPTY_SELECTION_TEXT_KEY =
new LocTextKey("sebserver.examconfig.info.pleaseSelect"); new LocTextKey("sebserver.examconfig.info.pleaseSelect");
private final TableFilterAttribute institutionFilter; private final TableFilterAttribute institutionFilter;
private final TableFilterAttribute nameFilter = private final TableFilterAttribute nameFilter =
new TableFilterAttribute(CriteriaType.TEXT, Entity.FILTER_ATTR_NAME); new TableFilterAttribute(CriteriaType.TEXT, Entity.FILTER_ATTR_NAME);
private final TableFilterAttribute descFilter = private final TableFilterAttribute descFilter =
new TableFilterAttribute(CriteriaType.TEXT, ConfigurationNode.FILTER_ATTR_DESCRIPTION); new TableFilterAttribute(CriteriaType.TEXT, ConfigurationNode.FILTER_ATTR_DESCRIPTION);
private final TableFilterAttribute statusFilter; private final TableFilterAttribute statusFilter;
private final PageService pageService; private final PageService pageService;
private final RestService restService; private final RestService restService;
private final CurrentUser currentUser; private final CurrentUser currentUser;
private final ResourceService resourceService; private final ResourceService resourceService;
private final int pageSize; private final int pageSize;
protected SebExamConfigList( protected SebExamConfigList(
final PageService pageService, final PageService pageService,
final RestService restService, final RestService restService,
final CurrentUser currentUser, final CurrentUser currentUser,
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) { @Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
this.pageService = pageService; this.pageService = pageService;
this.restService = restService; this.restService = restService;
this.currentUser = currentUser; this.currentUser = currentUser;
this.resourceService = pageService.getResourceService(); this.resourceService = pageService.getResourceService();
this.pageSize = pageSize; this.pageSize = pageSize;
this.institutionFilter = new TableFilterAttribute( this.institutionFilter = new TableFilterAttribute(
CriteriaType.SINGLE_SELECTION, CriteriaType.SINGLE_SELECTION,
Entity.FILTER_ATTR_INSTITUTION, Entity.FILTER_ATTR_INSTITUTION,
this.resourceService::institutionResource); this.resourceService::institutionResource);
this.statusFilter = new TableFilterAttribute( this.statusFilter = new TableFilterAttribute(
CriteriaType.SINGLE_SELECTION, CriteriaType.SINGLE_SELECTION,
ConfigurationNode.FILTER_ATTR_STATUS, ConfigurationNode.FILTER_ATTR_STATUS,
this.resourceService::examConfigStatusResources); this.resourceService::examConfigStatusResources);
} }
@Override @Override
public void compose(final PageContext pageContext) { public void compose(final PageContext pageContext) {
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory(); final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
final Composite content = widgetFactory.defaultPageLayout( final Composite content = widgetFactory.defaultPageLayout(
pageContext.getParent(), pageContext.getParent(),
TITLE_CONFIGURATION_TEXT_KEY); TITLE_CONFIGURATION_TEXT_KEY);
final boolean isSEBAdmin = this.currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN); final boolean isSEBAdmin = this.currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN);
final PageActionBuilder pageActionBuilder = final PageActionBuilder pageActionBuilder =
this.pageService.pageActionBuilder(pageContext.clearEntityKeys()); this.pageService.pageActionBuilder(pageContext.clearEntityKeys());
// exam configuration table // exam configuration table
final EntityTable<ConfigurationNode> configTable = final EntityTable<ConfigurationNode> configTable =
this.pageService.entityTableBuilder(this.restService.getRestCall(GetExamConfigNodePage.class)) this.pageService.entityTableBuilder(this.restService.getRestCall(GetExamConfigNodePage.class))
.withStaticFilter( .withStaticFilter(
Domain.CONFIGURATION_NODE.ATTR_TYPE, Domain.CONFIGURATION_NODE.ATTR_TYPE,
ConfigurationType.EXAM_CONFIG.name()) ConfigurationType.EXAM_CONFIG.name())
.withEmptyMessage(EMPTY_CONFIG_LIST_TEXT_KEY) .withEmptyMessage(EMPTY_CONFIG_LIST_TEXT_KEY)
.withPaging(this.pageSize) .withPaging(this.pageSize)
.withColumnIf( .withColumnIf(
() -> isSEBAdmin, () -> isSEBAdmin,
() -> new ColumnDefinition<>( () -> new ColumnDefinition<>(
Domain.LMS_SETUP.ATTR_INSTITUTION_ID, Domain.LMS_SETUP.ATTR_INSTITUTION_ID,
INSTITUTION_TEXT_KEY, INSTITUTION_TEXT_KEY,
this.resourceService::localizedExamConfigInstitutionName) this.resourceService::localizedExamConfigInstitutionName)
.withFilter(this.institutionFilter) .withFilter(this.institutionFilter)
.sortable()) .sortable())
.withColumn(new ColumnDefinition<>( .withColumn(new ColumnDefinition<>(
Domain.CONFIGURATION_NODE.ATTR_NAME, Domain.CONFIGURATION_NODE.ATTR_NAME,
NAME_TEXT_KEY, NAME_TEXT_KEY,
ConfigurationNode::getName) ConfigurationNode::getName)
.withFilter(this.nameFilter) .withFilter(this.nameFilter)
.sortable()) .sortable())
.withColumn(new ColumnDefinition<>( .withColumn(new ColumnDefinition<>(
Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION, Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION,
DESCRIPTION_TEXT_KEY, DESCRIPTION_TEXT_KEY,
ConfigurationNode::getDescription) ConfigurationNode::getDescription)
.withFilter(this.descFilter) .withFilter(this.descFilter)
.sortable()) .sortable())
.withColumn(new ColumnDefinition<ConfigurationNode>( .withColumn(new ColumnDefinition<ConfigurationNode>(
Domain.CONFIGURATION_NODE.ATTR_STATUS, Domain.CONFIGURATION_NODE.ATTR_STATUS,
STATUS_TEXT_KEY, STATUS_TEXT_KEY,
this.resourceService::localizedExamConfigStatusName) this.resourceService::localizedExamConfigStatusName)
.withFilter(this.statusFilter) .withFilter(this.statusFilter)
.sortable()) .sortable())
.withDefaultAction(pageActionBuilder .withDefaultAction(pageActionBuilder
.newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_PROP_FROM_LIST) .newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_PROP_FROM_LIST)
.create()) .create())
.compose(pageContext.copyOf(content));
.withSelectionListener(this.pageService.getSelectionPublisher(
final GrantCheck examConfigGrant = this.currentUser.grantCheck(EntityType.CONFIGURATION_NODE); pageContext,
pageActionBuilder ActionDefinition.SEB_EXAM_CONFIG_VIEW_PROP_FROM_LIST,
// Exam Configuration actions... ActionDefinition.SEB_EXAM_CONFIG_MODIFY_PROP_FROM_LIST))
.newAction(ActionDefinition.SEB_EXAM_CONFIG_NEW)
.publishIf(examConfigGrant::iw) .compose(pageContext.copyOf(content));
.newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_PROP_FROM_LIST) final GrantCheck examConfigGrant = this.currentUser.grantCheck(EntityType.CONFIGURATION_NODE);
.withSelect(configTable::getSelection, PageAction::applySingleSelectionAsEntityKey, pageActionBuilder
EMPTY_SELECTION_TEXT_KEY) // Exam Configuration actions...
.publishIf(() -> configTable.hasAnyContent()) .newAction(ActionDefinition.SEB_EXAM_CONFIG_NEW)
.publishIf(examConfigGrant::iw)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY_PROP_FROM_LIST)
.withSelect( .newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_PROP_FROM_LIST)
configTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION), .withSelect(configTable::getSelection, PageAction::applySingleSelectionAsEntityKey,
PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> examConfigGrant.im() && configTable.hasAnyContent()) .publishIf(configTable::hasAnyContent, false)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_IMPORT_TO_NEW_CONFIG) .newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY_PROP_FROM_LIST)
.withExec(SebExamConfigImportPopup.importFunction(this.pageService, true)) .withSelect(
.noEventPropagation() configTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION),
.publishIf(() -> examConfigGrant.im()) PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> examConfigGrant.im() && configTable.hasAnyContent(), false)
;
} .newAction(ActionDefinition.SEB_EXAM_CONFIG_IMPORT_TO_NEW_CONFIG)
.withExec(SebExamConfigImportPopup.importFunction(this.pageService, true))
} .noEventPropagation()
.publishIf(examConfigGrant::im);
}
}

View file

@ -1,413 +1,423 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.content; package ch.ethz.seb.sebserver.gui.content;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.Collections;
import java.util.List; import java.util.HashSet;
import java.util.function.Function; import java.util.List;
import java.util.function.Function;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.rap.rwt.client.service.UrlLauncher; import org.apache.commons.lang3.StringUtils;
import org.eclipse.swt.SWT; import org.eclipse.rap.rwt.RWT;
import org.eclipse.swt.widgets.Composite; import org.eclipse.rap.rwt.client.service.UrlLauncher;
import org.eclipse.swt.widgets.Text; import org.eclipse.swt.SWT;
import org.springframework.beans.factory.annotation.Value; import org.eclipse.swt.widgets.Composite;
import org.springframework.context.annotation.Lazy; import org.eclipse.swt.widgets.Label;
import org.springframework.stereotype.Component; import org.eclipse.swt.widgets.Text;
import org.springframework.beans.factory.annotation.Value;
import ch.ethz.seb.sebserver.gbl.Constants; import org.springframework.context.annotation.Lazy;
import ch.ethz.seb.sebserver.gbl.api.API; import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.model.exam.ExamConfigurationMap; import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.exam.QuizData; import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigKey; import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode; import ch.ethz.seb.sebserver.gbl.model.exam.ExamConfigurationMap;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationStatus; import ch.ethz.seb.sebserver.gbl.model.exam.QuizData;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationType; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigKey;
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationStatus;
import ch.ethz.seb.sebserver.gbl.util.Tuple; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationType;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
import ch.ethz.seb.sebserver.gui.form.FormBuilder; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.form.FormHandle; import ch.ethz.seb.sebserver.gbl.util.Tuple;
import ch.ethz.seb.sebserver.gui.service.ResourceService; import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; import ch.ethz.seb.sebserver.gui.form.FormBuilder;
import ch.ethz.seb.sebserver.gui.service.page.PageContext; import ch.ethz.seb.sebserver.gui.form.FormHandle;
import ch.ethz.seb.sebserver.gui.service.page.PageMessageException; import ch.ethz.seb.sebserver.gui.service.ResourceService;
import ch.ethz.seb.sebserver.gui.service.page.PageService; import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder; import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; import ch.ethz.seb.sebserver.gui.service.page.PageMessageException;
import ch.ethz.seb.sebserver.gui.service.page.impl.ModalInputDialog; import ch.ethz.seb.sebserver.gui.service.page.PageService;
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction; import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder;
import ch.ethz.seb.sebserver.gui.service.remote.download.DownloadService; import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.remote.download.SebExamConfigPlaintextDownload; import ch.ethz.seb.sebserver.gui.service.page.impl.ModalInputDialog;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExamConfigMappingNames; import ch.ethz.seb.sebserver.gui.service.remote.download.DownloadService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExamConfigMappingsPage; import ch.ethz.seb.sebserver.gui.service.remote.download.SebExamConfigPlaintextDownload;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.ExportConfigKey; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigNode; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExamConfigMappingNames;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.NewExamConfig; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExamConfigMappingsPage;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfig; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.ExportConfigKey;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigNode;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.EntityGrantCheck; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.NewExamConfig;
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfig;
import ch.ethz.seb.sebserver.gui.table.EntityTable; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.EntityGrantCheck;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant; import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
import ch.ethz.seb.sebserver.gui.table.EntityTable;
@Lazy import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@Component import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
@GuiProfile
public class SebExamConfigPropForm implements TemplateComposer { @Lazy
@Component
static final LocTextKey FORM_TITLE_NEW = @GuiProfile
new LocTextKey("sebserver.examconfig.form.title.new"); public class SebExamConfigPropForm implements TemplateComposer {
static final LocTextKey FORM_TITLE =
new LocTextKey("sebserver.examconfig.form.title"); static final LocTextKey FORM_TITLE_NEW =
static final LocTextKey FORM_NAME_TEXT_KEY = new LocTextKey("sebserver.examconfig.form.title.new");
new LocTextKey("sebserver.examconfig.form.name"); static final LocTextKey FORM_TITLE =
static final LocTextKey FORM_DESCRIPTION_TEXT_KEY = new LocTextKey("sebserver.examconfig.form.title");
new LocTextKey("sebserver.examconfig.form.description"); static final LocTextKey FORM_NAME_TEXT_KEY =
static final LocTextKey FORM_HISTORY_TEXT_KEY = new LocTextKey("sebserver.examconfig.form.name");
new LocTextKey("sebserver.examconfig.form.with-history"); static final LocTextKey FORM_DESCRIPTION_TEXT_KEY =
static final LocTextKey FORM_TEMPLATE_TEXT_KEY = new LocTextKey("sebserver.examconfig.form.description");
new LocTextKey("sebserver.examconfig.form.template"); static final LocTextKey FORM_HISTORY_TEXT_KEY =
static final LocTextKey FORM_STATUS_TEXT_KEY = new LocTextKey("sebserver.examconfig.form.with-history");
new LocTextKey("sebserver.examconfig.form.status"); static final LocTextKey FORM_TEMPLATE_TEXT_KEY =
static final LocTextKey FORM_IMPORT_TEXT_KEY = new LocTextKey("sebserver.examconfig.form.template");
new LocTextKey("sebserver.examconfig.action.import-config"); static final LocTextKey FORM_STATUS_TEXT_KEY =
static final LocTextKey FORM_IMPORT_SELECT_TEXT_KEY = new LocTextKey("sebserver.examconfig.form.status");
new LocTextKey("sebserver.examconfig.action.import-file-select"); static final LocTextKey FORM_IMPORT_TEXT_KEY =
static final LocTextKey FORM_IMPORT_PASSWORD_TEXT_KEY = new LocTextKey("sebserver.examconfig.action.import-config");
new LocTextKey("sebserver.examconfig.action.import-file-password"); static final LocTextKey FORM_IMPORT_SELECT_TEXT_KEY =
static final LocTextKey CONFIG_KEY_TITLE_TEXT_KEY = new LocTextKey("sebserver.examconfig.action.import-file-select");
new LocTextKey("sebserver.examconfig.form.config-key.title"); static final LocTextKey FORM_IMPORT_PASSWORD_TEXT_KEY =
static final LocTextKey FORM_IMPORT_CONFIRM_TEXT_KEY = new LocTextKey("sebserver.examconfig.action.import-file-password");
new LocTextKey("sebserver.examconfig.action.import-config.confirm"); static final LocTextKey CONFIG_KEY_TITLE_TEXT_KEY =
static final LocTextKey FORM_ATTACHED_EXAMS_TITLE_TEXT_KEY = new LocTextKey("sebserver.examconfig.form.config-key.title");
new LocTextKey("sebserver.examconfig.form.attched-to"); static final LocTextKey FORM_IMPORT_CONFIRM_TEXT_KEY =
new LocTextKey("sebserver.examconfig.action.import-config.confirm");
static final LocTextKey SAVE_CONFIRM_STATE_CHANGE_WHILE_ATTACHED = static final LocTextKey FORM_ATTACHED_EXAMS_TITLE_TEXT_KEY =
new LocTextKey("sebserver.examconfig.action.state-change.confirm"); new LocTextKey("sebserver.examconfig.form.attached-to");
static final LocTextKey FORM_ATTACHED_EXAMS_TITLE_TOOLTIP_TEXT_KEY =
private final PageService pageService; new LocTextKey("sebserver.examconfig.form.attached-to" + Constants.TOOLTIP_TEXT_KEY_SUFFIX);
private final RestService restService;
private final CurrentUser currentUser; static final LocTextKey SAVE_CONFIRM_STATE_CHANGE_WHILE_ATTACHED =
private final DownloadService downloadService; new LocTextKey("sebserver.examconfig.action.state-change.confirm");
private final String downloadFileName;
private final PageService pageService;
protected SebExamConfigPropForm( private final RestService restService;
final PageService pageService, private final CurrentUser currentUser;
final CurrentUser currentUser, private final DownloadService downloadService;
final DownloadService downloadService, private final String downloadFileName;
@Value("${sebserver.gui.seb.exam.config.download.filename}") final String downloadFileName) {
protected SebExamConfigPropForm(
this.pageService = pageService; final PageService pageService,
this.restService = pageService.getRestService(); final CurrentUser currentUser,
this.currentUser = currentUser; final DownloadService downloadService,
this.downloadService = downloadService; @Value("${sebserver.gui.seb.exam.config.download.filename}") final String downloadFileName) {
this.downloadFileName = downloadFileName;
} this.pageService = pageService;
this.restService = pageService.getRestService();
@Override this.currentUser = currentUser;
public void compose(final PageContext pageContext) { this.downloadService = downloadService;
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory(); this.downloadFileName = downloadFileName;
final ResourceService resourceService = this.pageService.getResourceService(); }
final UserInfo user = this.currentUser.get(); @Override
final EntityKey entityKey = pageContext.getEntityKey(); public void compose(final PageContext pageContext) {
final EntityKey parentEntityKey = pageContext.getParentEntityKey(); final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
final boolean isNew = entityKey == null; final ResourceService resourceService = this.pageService.getResourceService();
// get data or create new. Handle error if happen final UserInfo user = this.currentUser.get();
final ConfigurationNode examConfig = (isNew) final EntityKey entityKey = pageContext.getEntityKey();
? ConfigurationNode.createNewExamConfig(user.institutionId) final EntityKey parentEntityKey = pageContext.getParentEntityKey();
: this.restService final boolean isNew = entityKey == null;
.getBuilder(GetExamConfigNode.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId) // get data or create new. Handle error if happen
.call() final ConfigurationNode examConfig = (isNew)
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_NODE, error)) ? ConfigurationNode.createNewExamConfig(user.institutionId)
.getOrThrow(); : this.restService
.getBuilder(GetExamConfigNode.class)
final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(examConfig); .withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
final boolean writeGrant = entityGrant.w(); .call()
final boolean modifyGrant = entityGrant.m(); .onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_NODE, error))
final boolean isReadonly = pageContext.isReadonly(); .getOrThrow();
final boolean isAttachedToExam = !isNew && this.restService
.getBuilder(GetExamConfigMappingNames.class) final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(examConfig);
.withQueryParam(ExamConfigurationMap.FILTER_ATTR_CONFIG_ID, examConfig.getModelId()) final boolean writeGrant = entityGrant.w();
.call() final boolean modifyGrant = entityGrant.m();
.map(names -> names != null && !names.isEmpty()) final boolean isReadonly = pageContext.isReadonly();
.getOr(Boolean.FALSE); final boolean isAttachedToExam = !isNew && this.restService
.getBuilder(GetExamConfigMappingNames.class)
// new PageContext with actual EntityKey .withQueryParam(ExamConfigurationMap.FILTER_ATTR_CONFIG_ID, examConfig.getModelId())
final PageContext formContext = pageContext.withEntityKey(examConfig.getEntityKey()); .call()
.map(names -> names != null && !names.isEmpty())
// the default page layout with interactive title .getOr(Boolean.FALSE);
final LocTextKey titleKey = (isNew)
? FORM_TITLE_NEW // new PageContext with actual EntityKey
: FORM_TITLE; final PageContext formContext = pageContext.withEntityKey(examConfig.getEntityKey());
final Composite content = widgetFactory.defaultPageLayout(
formContext.getParent(), // the default page layout with interactive title
titleKey); final LocTextKey titleKey = (isNew)
? FORM_TITLE_NEW
final List<Tuple<String>> examConfigTemplateResources = resourceService.getExamConfigTemplateResources(); : FORM_TITLE;
final FormHandle<ConfigurationNode> formHandle = this.pageService.formBuilder( final Composite content = widgetFactory.defaultPageLayout(
formContext.copyOf(content)) formContext.getParent(),
.readonly(isReadonly) titleKey);
.putStaticValueIf(() -> !isNew,
Domain.CONFIGURATION_NODE.ATTR_ID, final List<Tuple<String>> examConfigTemplateResources = resourceService.getExamConfigTemplateResources();
examConfig.getModelId()) final FormHandle<ConfigurationNode> formHandle = this.pageService.formBuilder(
.putStaticValue( formContext.copyOf(content))
Domain.CONFIGURATION_NODE.ATTR_INSTITUTION_ID, .readonly(isReadonly)
String.valueOf(examConfig.getInstitutionId())) .putStaticValueIf(() -> !isNew,
.putStaticValue( Domain.CONFIGURATION_NODE.ATTR_ID,
Domain.CONFIGURATION_NODE.ATTR_TYPE, examConfig.getModelId())
ConfigurationType.EXAM_CONFIG.name()) .putStaticValue(
.addFieldIf( Domain.CONFIGURATION_NODE.ATTR_INSTITUTION_ID,
() -> !examConfigTemplateResources.isEmpty(), String.valueOf(examConfig.getInstitutionId()))
() -> FormBuilder.singleSelection( .putStaticValue(
Domain.CONFIGURATION_NODE.ATTR_TEMPLATE_ID, Domain.CONFIGURATION_NODE.ATTR_TYPE,
FORM_TEMPLATE_TEXT_KEY, ConfigurationType.EXAM_CONFIG.name())
(parentEntityKey != null) .addFieldIf(
? parentEntityKey.modelId () -> !examConfigTemplateResources.isEmpty(),
: String.valueOf(examConfig.templateId), () -> FormBuilder.singleSelection(
resourceService::getExamConfigTemplateResources) Domain.CONFIGURATION_NODE.ATTR_TEMPLATE_ID,
.readonly(!isNew)) FORM_TEMPLATE_TEXT_KEY,
.addField(FormBuilder.text( (parentEntityKey != null)
Domain.CONFIGURATION_NODE.ATTR_NAME, ? parentEntityKey.modelId
FORM_NAME_TEXT_KEY, : String.valueOf(examConfig.templateId),
examConfig.name)) resourceService::getExamConfigTemplateResources)
.addField(FormBuilder.text( .readonly(!isNew))
Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION, .addField(FormBuilder.text(
FORM_DESCRIPTION_TEXT_KEY, Domain.CONFIGURATION_NODE.ATTR_NAME,
examConfig.description) FORM_NAME_TEXT_KEY,
.asArea()) examConfig.name)
.mandatory(!isReadonly))
.addField(FormBuilder.singleSelection( .addField(FormBuilder.text(
Domain.CONFIGURATION_NODE.ATTR_STATUS, Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION,
FORM_STATUS_TEXT_KEY, FORM_DESCRIPTION_TEXT_KEY,
examConfig.status.name(), examConfig.description)
() -> resourceService.examConfigStatusResources(isAttachedToExam)) .asArea())
.withEmptyCellSeparation((isReadonly) ? false : true))
.buildFor((isNew) .addField(FormBuilder.singleSelection(
? this.restService.getRestCall(NewExamConfig.class) Domain.CONFIGURATION_NODE.ATTR_STATUS,
: this.restService.getRestCall(SaveExamConfig.class)); FORM_STATUS_TEXT_KEY,
examConfig.status.name(),
final boolean settingsReadonly = examConfig.status == ConfigurationStatus.IN_USE; () -> resourceService.examConfigStatusResources(isAttachedToExam))
final UrlLauncher urlLauncher = RWT.getClient().getService(UrlLauncher.class); .withEmptyCellSeparation(!isReadonly))
final PageContext actionContext = formContext.clearEntityKeys(); .buildFor((isNew)
final PageActionBuilder actionBuilder = this.pageService.pageActionBuilder(actionContext); ? this.restService.getRestCall(NewExamConfig.class)
actionBuilder : this.restService.getRestCall(SaveExamConfig.class));
.newAction(ActionDefinition.SEB_EXAM_CONFIG_NEW) final boolean settingsReadonly = examConfig.status == ConfigurationStatus.IN_USE;
.publishIf(() -> writeGrant && isReadonly) final UrlLauncher urlLauncher = RWT.getClient().getService(UrlLauncher.class);
final PageContext actionContext = formContext.clearEntityKeys();
.newAction(ActionDefinition.SEB_EXAM_CONFIG_PROP_MODIFY) final PageActionBuilder actionBuilder = this.pageService.pageActionBuilder(actionContext);
.withEntityKey(entityKey) actionBuilder
.publishIf(() -> modifyGrant && isReadonly)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_NEW)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW) .publishIf(() -> writeGrant && isReadonly)
.withEntityKey(entityKey)
.publishIf(() -> isReadonly) .newAction(ActionDefinition.SEB_EXAM_CONFIG_PROP_MODIFY)
.withEntityKey(entityKey)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY)
.withEntityKey(entityKey) .publishIf(() -> modifyGrant && isReadonly)
.publishIf(() -> modifyGrant && isReadonly && !settingsReadonly)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_EXPORT_PLAIN_XML) .withEntityKey(entityKey)
.withEntityKey(entityKey) .withAttribute(PageContext.AttributeKeys.READ_ONLY, String.valueOf(!modifyGrant))
.withExec(action -> { .publishIf(() -> modifyGrant && isReadonly)
final String downloadURL = this.downloadService.createDownloadURL(
entityKey.modelId, .newAction(ActionDefinition.SEB_EXAM_CONFIG_EXPORT_PLAIN_XML)
SebExamConfigPlaintextDownload.class, .withEntityKey(entityKey)
this.downloadFileName); .withExec(action -> {
urlLauncher.openURL(downloadURL); final String downloadURL = this.downloadService.createDownloadURL(
return action; entityKey.modelId,
}) SebExamConfigPlaintextDownload.class,
.noEventPropagation() this.downloadFileName);
.publishIf(() -> modifyGrant && isReadonly) urlLauncher.openURL(downloadURL);
return action;
.newAction(ActionDefinition.SEB_EXAM_CONFIG_GET_CONFIG_KEY) })
.withEntityKey(entityKey) .noEventPropagation()
.withExec(SebExamConfigPropForm.getConfigKeyFunction(this.pageService)) .publishIf(() -> modifyGrant && isReadonly)
.noEventPropagation()
.publishIf(() -> modifyGrant && isReadonly) .newAction(ActionDefinition.SEB_EXAM_CONFIG_GET_CONFIG_KEY)
.withEntityKey(entityKey)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_IMPORT_TO_EXISTING_CONFIG) .withExec(SebExamConfigPropForm.getConfigKeyFunction(this.pageService))
.withEntityKey(entityKey) .noEventPropagation()
.withExec(SebExamConfigImportPopup.importFunction(this.pageService, false)) .publishIf(() -> modifyGrant && isReadonly)
.noEventPropagation()
.publishIf(() -> modifyGrant && isReadonly && !isAttachedToExam) .newAction(ActionDefinition.SEB_EXAM_CONFIG_IMPORT_TO_EXISTING_CONFIG)
.withEntityKey(entityKey)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_COPY_CONFIG) .withExec(SebExamConfigImportPopup.importFunction(this.pageService, false))
.withEntityKey(entityKey) .noEventPropagation()
.withExec(SebExamConfigCreationPopup.configCreationFunction( .publishIf(() -> modifyGrant && isReadonly && !isAttachedToExam)
this.pageService,
actionContext .newAction(ActionDefinition.SEB_EXAM_CONFIG_COPY_CONFIG)
.withEntityKey(entityKey) .withEntityKey(entityKey)
.withAttribute( .withExec(SebExamConfigCreationPopup.configCreationFunction(
PageContext.AttributeKeys.COPY_AS_TEMPLATE, this.pageService,
Constants.FALSE_STRING) actionContext
.withAttribute( .withEntityKey(entityKey)
PageContext.AttributeKeys.CREATE_FROM_TEMPLATE, .withAttribute(
Constants.FALSE_STRING))) PageContext.AttributeKeys.COPY_AS_TEMPLATE,
.noEventPropagation() Constants.FALSE_STRING)
.publishIf(() -> modifyGrant && isReadonly) .withAttribute(
PageContext.AttributeKeys.CREATE_FROM_TEMPLATE,
.newAction(ActionDefinition.SEB_EXAM_CONFIG_COPY_CONFIG_AS_TEMPALTE) Constants.FALSE_STRING)))
.withEntityKey(entityKey) .noEventPropagation()
.withExec(SebExamConfigCreationPopup.configCreationFunction( .publishIf(() -> modifyGrant && isReadonly)
this.pageService,
pageContext.withAttribute( .newAction(ActionDefinition.SEB_EXAM_CONFIG_COPY_CONFIG_AS_TEMPALTE)
PageContext.AttributeKeys.COPY_AS_TEMPLATE, .withEntityKey(entityKey)
Constants.TRUE_STRING))) .withExec(SebExamConfigCreationPopup.configCreationFunction(
.noEventPropagation() this.pageService,
.publishIf(() -> modifyGrant && isReadonly) pageContext.withAttribute(
PageContext.AttributeKeys.COPY_AS_TEMPLATE,
.newAction(ActionDefinition.SEB_EXAM_CONFIG_PROP_SAVE) Constants.TRUE_STRING)))
.withEntityKey(entityKey) .noEventPropagation()
.withExec(formHandle::processFormSave) .publishIf(() -> modifyGrant && isReadonly)
.ignoreMoveAwayFromEdit()
.withConfirm(() -> stateChangeConfirm(isAttachedToExam, formHandle)) .newAction(ActionDefinition.SEB_EXAM_CONFIG_PROP_SAVE)
.publishIf(() -> !isReadonly) .withEntityKey(entityKey)
.withExec(formHandle::processFormSave)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_PROP_CANCEL_MODIFY) .ignoreMoveAwayFromEdit()
.withEntityKey(entityKey) .withConfirm(() -> stateChangeConfirm(isAttachedToExam, formHandle))
.withExec(this.pageService.backToCurrentFunction()) .publishIf(() -> !isReadonly)
.publishIf(() -> !isReadonly);
.newAction(ActionDefinition.SEB_EXAM_CONFIG_PROP_CANCEL_MODIFY)
if (isAttachedToExam && isReadonly) { .withEntityKey(entityKey)
.withExec(this.pageService.backToCurrentFunction())
widgetFactory.labelSeparator(content); .publishIf(() -> !isReadonly);
widgetFactory.labelLocalized(
content, if (isAttachedToExam && isReadonly) {
CustomVariant.TEXT_H3,
FORM_ATTACHED_EXAMS_TITLE_TEXT_KEY); widgetFactory.label(content, StringUtils.EMPTY);
widgetFactory.labelLocalized(
final EntityTable<ExamConfigurationMap> table = content,
this.pageService.entityTableBuilder(this.restService.getRestCall(GetExamConfigMappingsPage.class)) CustomVariant.TEXT_H3,
.withRestCallAdapter(restCall -> restCall.withQueryParam( FORM_ATTACHED_EXAMS_TITLE_TEXT_KEY,
ExamConfigurationMap.FILTER_ATTR_CONFIG_ID, examConfig.getModelId())) FORM_ATTACHED_EXAMS_TITLE_TOOLTIP_TEXT_KEY);
.withPaging(1) widgetFactory.labelSeparator(content);
.hideNavigation()
.withRowDecorator(ExamList.decorateOnExamMapConsistency(this.pageService)) final EntityTable<ExamConfigurationMap> table =
this.pageService.entityTableBuilder(this.restService.getRestCall(GetExamConfigMappingsPage.class))
.withColumn(new ColumnDefinition<>( .withRestCallAdapter(restCall -> restCall.withQueryParam(
QuizData.QUIZ_ATTR_NAME, ExamConfigurationMap.FILTER_ATTR_CONFIG_ID, examConfig.getModelId()))
ExamList.COLUMN_TITLE_NAME_KEY, .withPaging(1)
ExamConfigurationMap::getExamName)) .hideNavigation()
.withRowDecorator(ExamList.decorateOnExamMapConsistency(this.pageService))
.withColumn(new ColumnDefinition<>(
QuizData.QUIZ_ATTR_START_TIME, .withColumn(new ColumnDefinition<>(
new LocTextKey( QuizData.QUIZ_ATTR_NAME,
ExamList.EXAM_LIST_COLUMN_STARTTIME, ExamList.COLUMN_TITLE_NAME_KEY,
this.pageService.getI18nSupport().getUsersTimeZoneTitleSuffix()), ExamConfigurationMap::getExamName))
ExamConfigurationMap::getExamStartTime))
.withColumn(new ColumnDefinition<>(
.withColumn(new ColumnDefinition<ExamConfigurationMap>( QuizData.QUIZ_ATTR_START_TIME,
Domain.EXAM.ATTR_TYPE, new LocTextKey(
ExamList.COLUMN_TITLE_TYPE_KEY, ExamList.EXAM_LIST_COLUMN_STARTTIME,
resourceService::localizedExamTypeName)) this.pageService.getI18nSupport().getUsersTimeZoneTitleSuffix()),
ExamConfigurationMap::getExamStartTime))
.withDefaultAction(this::showExamAction)
.withColumn(new ColumnDefinition<>(
.compose(pageContext.copyOf(content)); Domain.EXAM.ATTR_TYPE,
ExamList.COLUMN_TITLE_TYPE_KEY,
actionBuilder resourceService::localizedExamTypeName))
.newAction(ActionDefinition.EXAM_VIEW_FROM_LIST) .withDefaultAction(this::showExamAction)
.withExec(pageAction -> {
final ExamConfigurationMap selectedExamMapping = getSelectedExamMapping(table); .withSelectionListener(this.pageService.getSelectionPublisher(
return pageAction.withEntityKey( pageContext,
new EntityKey(selectedExamMapping.examId, EntityType.EXAM)); ActionDefinition.EXAM_VIEW_FROM_LIST))
})
.publishIf(table::hasAnyContent); .compose(pageContext.copyOf(content));
}
} actionBuilder
private PageAction showExamAction(final EntityTable<ExamConfigurationMap> table) { .newAction(ActionDefinition.EXAM_VIEW_FROM_LIST)
return this.pageService.pageActionBuilder(table.getPageContext()) .withExec(pageAction -> {
.newAction(ActionDefinition.EXAM_VIEW_FROM_LIST) final ExamConfigurationMap selectedExamMapping = getSelectedExamMapping(table);
.withSelectionSupplier(() -> { return pageAction.withEntityKey(
final ExamConfigurationMap selectedROWData = getSelectedExamMapping(table); new EntityKey(selectedExamMapping.examId, EntityType.EXAM));
return new HashSet<>(Arrays.asList(new EntityKey(selectedROWData.examId, EntityType.EXAM))); })
}) .publishIf(table::hasAnyContent, false);
.withExec(PageAction::applySingleSelectionAsEntityKey) }
.create(); }
}
private PageAction showExamAction(final EntityTable<ExamConfigurationMap> table) {
private ExamConfigurationMap getSelectedExamMapping(final EntityTable<ExamConfigurationMap> table) { return this.pageService.pageActionBuilder(table.getPageContext())
final ExamConfigurationMap selectedROWData = table.getSingleSelectedROWData(); .newAction(ActionDefinition.EXAM_VIEW_FROM_LIST)
.withSelectionSupplier(() -> {
if (selectedROWData == null) { final ExamConfigurationMap selectedROWData = getSelectedExamMapping(table);
throw new PageMessageException(ExamList.EMPTY_SELECTION_TEXT_KEY); return new HashSet<>(Collections.singletonList(new EntityKey(selectedROWData.examId, EntityType.EXAM)));
} })
return selectedROWData; .withExec(PageAction::applySingleSelectionAsEntityKey)
} .create();
}
private LocTextKey stateChangeConfirm(
final boolean isAttachedToExam, private ExamConfigurationMap getSelectedExamMapping(final EntityTable<ExamConfigurationMap> table) {
final FormHandle<ConfigurationNode> formHandle) { final ExamConfigurationMap selectedROWData = table.getSingleSelectedROWData();
if (isAttachedToExam) { if (selectedROWData == null) {
final String fieldValue = formHandle throw new PageMessageException(ExamList.EMPTY_SELECTION_TEXT_KEY);
.getForm() }
.getFieldValue(Domain.CONFIGURATION_NODE.ATTR_STATUS); return selectedROWData;
}
if (fieldValue != null) {
final ConfigurationStatus state = ConfigurationStatus.valueOf(fieldValue); private LocTextKey stateChangeConfirm(
if (state != ConfigurationStatus.IN_USE) { final boolean isAttachedToExam,
return SAVE_CONFIRM_STATE_CHANGE_WHILE_ATTACHED; final FormHandle<ConfigurationNode> formHandle) {
}
} if (isAttachedToExam) {
} final String fieldValue = formHandle
.getForm()
return null; .getFieldValue(Domain.CONFIGURATION_NODE.ATTR_STATUS);
}
if (fieldValue != null) {
public static Function<PageAction, PageAction> getConfigKeyFunction(final PageService pageService) { final ConfigurationStatus state = ConfigurationStatus.valueOf(fieldValue);
final RestService restService = pageService.getResourceService().getRestService(); if (state != ConfigurationStatus.IN_USE) {
return action -> { return SAVE_CONFIRM_STATE_CHANGE_WHILE_ATTACHED;
final ConfigKey configKey = restService.getBuilder(ExportConfigKey.class) }
.withURIVariable(API.PARAM_MODEL_ID, action.getEntityKey().modelId) }
.call() }
.getOrThrow();
return null;
final WidgetFactory widgetFactory = pageService.getWidgetFactory(); }
final ModalInputDialog<Void> dialog = new ModalInputDialog<>(
action.pageContext().getParent().getShell(), public static Function<PageAction, PageAction> getConfigKeyFunction(final PageService pageService) {
widgetFactory); final RestService restService = pageService.getResourceService().getRestService();
return action -> {
dialog.setDialogWidth(500); final ConfigKey configKey = restService.getBuilder(ExportConfigKey.class)
.withURIVariable(API.PARAM_MODEL_ID, action.getEntityKey().modelId)
dialog.open( .call()
CONFIG_KEY_TITLE_TEXT_KEY, .getOrThrow();
action.pageContext(),
pc -> { final WidgetFactory widgetFactory = pageService.getWidgetFactory();
final Composite content = widgetFactory.defaultPageLayout( final ModalInputDialog<Void> dialog = new ModalInputDialog<>(
pc.getParent()); action.pageContext().getParent().getShell(),
widgetFactory);
widgetFactory.labelLocalized(
content, dialog.setDialogWidth(500);
CustomVariant.TEXT_H3,
CONFIG_KEY_TITLE_TEXT_KEY); dialog.open(
CONFIG_KEY_TITLE_TEXT_KEY,
final Text text = new Text(content, SWT.NONE); action.pageContext(),
text.setEditable(false); pc -> {
text.setText(configKey.key); final Composite content = widgetFactory.defaultPageLayout(
}); pc.getParent());
return action;
}; widgetFactory.labelLocalized(
} content,
CustomVariant.TEXT_H3,
} CONFIG_KEY_TITLE_TEXT_KEY);
final Text text = new Text(content, SWT.NONE);
text.setEditable(false);
text.setText(configKey.key);
});
return action;
};
}
}

View file

@ -1,239 +1,238 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.content; package ch.ethz.seb.sebserver.gui.content;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.eclipse.swt.SWT; import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.TabFolder; import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem; import org.eclipse.swt.widgets.TabItem;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.APIMessage; import ch.ethz.seb.sebserver.gbl.api.APIMessage;
import ch.ethz.seb.sebserver.gbl.api.APIMessageError; import ch.ethz.seb.sebserver.gbl.api.APIMessageError;
import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration; import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationStatus; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationStatus;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.View; import ch.ethz.seb.sebserver.gbl.model.sebconfig.View;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gbl.util.Utils; import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService; import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
import ch.ethz.seb.sebserver.gui.service.examconfig.impl.AttributeMapping; import ch.ethz.seb.sebserver.gui.service.examconfig.impl.AttributeMapping;
import ch.ethz.seb.sebserver.gui.service.examconfig.impl.ViewContext; import ch.ethz.seb.sebserver.gui.service.examconfig.impl.ViewContext;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.PageContext; import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.PageMessageException; import ch.ethz.seb.sebserver.gui.service.page.PageMessageException;
import ch.ethz.seb.sebserver.gui.service.page.PageService; import ch.ethz.seb.sebserver.gui.service.page.PageService;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetConfigurations; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetConfigurations;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigNode; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigNode;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfigHistory; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfigHistory;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SebExamConfigUndo; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SebExamConfigUndo;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@Lazy @Lazy
@Component @Component
@GuiProfile @GuiProfile
public class SebExamConfigSettingsForm implements TemplateComposer { public class SebExamConfigSettingsForm implements TemplateComposer {
private static final Logger log = LoggerFactory.getLogger(SebExamConfigSettingsForm.class); private static final Logger log = LoggerFactory.getLogger(SebExamConfigSettingsForm.class);
private static final String VIEW_TEXT_KEY_PREFIX = private static final String VIEW_TEXT_KEY_PREFIX =
"sebserver.examconfig.props.form.views."; "sebserver.examconfig.props.form.views.";
private static final String KEY_SAVE_TO_HISTORY_SUCCESS = private static final String KEY_SAVE_TO_HISTORY_SUCCESS =
"sebserver.examconfig.action.saveToHistory.success"; "sebserver.examconfig.action.saveToHistory.success";
private static final String KEY_UNDO_SUCCESS = private static final String KEY_UNDO_SUCCESS =
"sebserver.examconfig.action.undo.success"; "sebserver.examconfig.action.undo.success";
private static final LocTextKey TITLE_TEXT_KEY = private static final LocTextKey TITLE_TEXT_KEY =
new LocTextKey("sebserver.examconfig.props.from.title"); new LocTextKey("sebserver.examconfig.props.from.title");
private static final LocTextKey MESSAGE_SAVE_INTEGRITY_VIOLATION = private static final LocTextKey MESSAGE_SAVE_INTEGRITY_VIOLATION =
new LocTextKey("sebserver.examconfig.action.saveToHistory.integrity-violation"); new LocTextKey("sebserver.examconfig.action.saveToHistory.integrity-violation");
private final PageService pageService; private final PageService pageService;
private final RestService restService; private final RestService restService;
private final CurrentUser currentUser; private final CurrentUser currentUser;
private final ExamConfigurationService examConfigurationService; private final ExamConfigurationService examConfigurationService;
protected SebExamConfigSettingsForm( protected SebExamConfigSettingsForm(
final PageService pageService, final PageService pageService,
final RestService restService, final RestService restService,
final CurrentUser currentUser, final CurrentUser currentUser,
final ExamConfigurationService examConfigurationService) { final ExamConfigurationService examConfigurationService) {
this.pageService = pageService; this.pageService = pageService;
this.restService = restService; this.restService = restService;
this.currentUser = currentUser; this.currentUser = currentUser;
this.examConfigurationService = examConfigurationService; this.examConfigurationService = examConfigurationService;
} }
@Override @Override
public void compose(final PageContext pageContext) { public void compose(final PageContext pageContext) {
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory(); final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
final EntityKey entityKey = pageContext.getEntityKey(); final EntityKey entityKey = pageContext.getEntityKey();
final Composite content = widgetFactory.defaultPageLayout( final Composite content = widgetFactory.defaultPageLayout(
pageContext.getParent(), pageContext.getParent(),
TITLE_TEXT_KEY); TITLE_TEXT_KEY);
try { try {
final ConfigurationNode configNode = this.restService.getBuilder(GetExamConfigNode.class) final ConfigurationNode configNode = this.restService.getBuilder(GetExamConfigNode.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId) .withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call() .call()
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_NODE, error)) .onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_NODE, error))
.getOrThrow(); .getOrThrow();
final Configuration configuration = this.restService.getBuilder(GetConfigurations.class) final Configuration configuration = this.restService.getBuilder(GetConfigurations.class)
.withQueryParam(Configuration.FILTER_ATTR_CONFIGURATION_NODE_ID, configNode.getModelId()) .withQueryParam(Configuration.FILTER_ATTR_CONFIGURATION_NODE_ID, configNode.getModelId())
.withQueryParam(Configuration.FILTER_ATTR_FOLLOWUP, Constants.TRUE_STRING) .withQueryParam(Configuration.FILTER_ATTR_FOLLOWUP, Constants.TRUE_STRING)
.call() .call()
.map(Utils::toSingleton) .map(Utils::toSingleton)
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION, error)) .onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION, error))
.getOrThrow(); .getOrThrow();
final AttributeMapping attributes = this.examConfigurationService final AttributeMapping attributes = this.examConfigurationService
.getAttributes(configNode.templateId) .getAttributes(configNode.templateId)
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_ATTRIBUTE, error)) .onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_ATTRIBUTE, error))
.getOrThrow(); .getOrThrow();
final boolean readonly = pageContext.isReadonly() || configNode.status == ConfigurationStatus.IN_USE; final boolean readonly = pageContext.isReadonly() || configNode.status == ConfigurationStatus.IN_USE;
final List<View> views = this.examConfigurationService.getViews(attributes); final List<View> views = this.examConfigurationService.getViews(attributes);
final TabFolder tabFolder = widgetFactory.tabFolderLocalized(content); final TabFolder tabFolder = widgetFactory.tabFolderLocalized(content);
tabFolder.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); tabFolder.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
final List<ViewContext> viewContexts = new ArrayList<>(); final List<ViewContext> viewContexts = new ArrayList<>();
for (final View view : views) { for (final View view : views) {
final ViewContext viewContext = this.examConfigurationService.createViewContext( final ViewContext viewContext = this.examConfigurationService.createViewContext(
pageContext, pageContext,
configuration, configuration,
view, view,
attributes, attributes,
20, 20,
readonly); readonly);
viewContexts.add(viewContext); viewContexts.add(viewContext);
final Composite viewGrid = this.examConfigurationService.createViewGrid( final Composite viewGrid = this.examConfigurationService.createViewGrid(
tabFolder, tabFolder,
viewContext); viewContext);
final TabItem tabItem = widgetFactory.tabItemLocalized( final TabItem tabItem = widgetFactory.tabItemLocalized(
tabFolder, tabFolder,
new LocTextKey(VIEW_TEXT_KEY_PREFIX + view.name)); new LocTextKey(VIEW_TEXT_KEY_PREFIX + view.name));
tabItem.setControl(viewGrid); tabItem.setControl(viewGrid);
} }
// set selection if available // set selection if available
final String viewIndex = pageContext.getAttribute("VIEW_INDEX"); final String viewIndex = pageContext.getAttribute("VIEW_INDEX");
if (StringUtils.isNotBlank(viewIndex)) { if (StringUtils.isNotBlank(viewIndex)) {
try { try {
tabFolder.setSelection(Integer.parseInt(viewIndex)); tabFolder.setSelection(Integer.parseInt(viewIndex));
} catch (final NumberFormatException e) { } catch (final NumberFormatException e) {
log.warn("Failed to initialize view selection"); log.warn("Failed to initialize view selection");
} }
} }
this.examConfigurationService.initInputFieldValues(configuration.id, viewContexts); this.examConfigurationService.initInputFieldValues(configuration.id, viewContexts);
final GrantCheck examConfigGrant = this.currentUser.grantCheck(EntityType.CONFIGURATION_NODE); final GrantCheck examConfigGrant = this.currentUser.grantCheck(EntityType.CONFIGURATION_NODE);
this.pageService.pageActionBuilder(pageContext.clearEntityKeys()) this.pageService.pageActionBuilder(pageContext.clearEntityKeys())
.newAction(ActionDefinition.SEB_EXAM_CONFIG_SAVE_TO_HISTORY) .newAction(ActionDefinition.SEB_EXAM_CONFIG_SAVE_TO_HISTORY)
.withEntityKey(entityKey) .withEntityKey(entityKey)
.withExec(action -> { .withExec(action -> {
this.restService.getBuilder(SaveExamConfigHistory.class) this.restService.getBuilder(SaveExamConfigHistory.class)
.withURIVariable(API.PARAM_MODEL_ID, configuration.getModelId()) .withURIVariable(API.PARAM_MODEL_ID, configuration.getModelId())
.call() .call()
.onError(t -> notifyErrorOnSave(t, pageContext)); .onError(t -> notifyErrorOnSave(t, pageContext));
return action.withAttribute( return action.withAttribute(
"VIEW_INDEX", "VIEW_INDEX",
String.valueOf(tabFolder.getSelectionIndex())); String.valueOf(tabFolder.getSelectionIndex()));
}) })
.withSuccess(KEY_SAVE_TO_HISTORY_SUCCESS) .withSuccess(KEY_SAVE_TO_HISTORY_SUCCESS)
.ignoreMoveAwayFromEdit() .ignoreMoveAwayFromEdit()
.publishIf(() -> examConfigGrant.iw() && !readonly) .publishIf(() -> examConfigGrant.iw() && !readonly)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_UNDO) .newAction(ActionDefinition.SEB_EXAM_CONFIG_UNDO)
.withEntityKey(entityKey) .withEntityKey(entityKey)
.withExec(action -> { .withExec(action -> {
this.restService.getBuilder(SebExamConfigUndo.class) this.restService.getBuilder(SebExamConfigUndo.class)
.withURIVariable(API.PARAM_MODEL_ID, configuration.getModelId()) .withURIVariable(API.PARAM_MODEL_ID, configuration.getModelId())
.call() .call()
.getOrThrow(); .getOrThrow();
return action.withAttribute( return action.withAttribute(
"VIEW_INDEX", "VIEW_INDEX",
String.valueOf(tabFolder.getSelectionIndex())); String.valueOf(tabFolder.getSelectionIndex()));
}) })
.withSuccess(KEY_UNDO_SUCCESS) .withSuccess(KEY_UNDO_SUCCESS)
.ignoreMoveAwayFromEdit() .ignoreMoveAwayFromEdit()
.publishIf(() -> examConfigGrant.iw() && !readonly) .publishIf(() -> examConfigGrant.iw() && !readonly)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_COPY_CONFIG_AS_TEMPALTE) .newAction(ActionDefinition.SEB_EXAM_CONFIG_COPY_CONFIG_AS_TEMPALTE)
.withEntityKey(entityKey) .withEntityKey(entityKey)
.withExec(SebExamConfigCreationPopup.configCreationFunction( .withExec(SebExamConfigCreationPopup.configCreationFunction(
this.pageService, this.pageService,
pageContext pageContext
.withAttribute( .withAttribute(
PageContext.AttributeKeys.COPY_AS_TEMPLATE, PageContext.AttributeKeys.COPY_AS_TEMPLATE,
Constants.TRUE_STRING) Constants.TRUE_STRING)
.withAttribute( .withAttribute(
PageContext.AttributeKeys.CREATE_FROM_TEMPLATE, PageContext.AttributeKeys.CREATE_FROM_TEMPLATE,
Constants.FALSE_STRING))) Constants.FALSE_STRING)))
.noEventPropagation() .noEventPropagation()
.publishIf(() -> examConfigGrant.iw()) .publishIf(examConfigGrant::iw)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_PROP) .newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_PROP)
.withEntityKey(entityKey) .withEntityKey(entityKey)
.ignoreMoveAwayFromEdit() .ignoreMoveAwayFromEdit()
.publish(); .publish();
} catch (final RuntimeException e) { } catch (final RuntimeException e) {
pageContext.notifyUnexpectedError(e); pageContext.notifyUnexpectedError(e);
throw e; throw e;
} catch (final Exception e) { } catch (final Exception e) {
log.error("Unexpected error while trying to fetch exam configuration data and create views", e); log.error("Unexpected error while trying to fetch exam configuration data and create views", e);
pageContext.notifyError(SebExamConfigPropForm.FORM_TITLE, e); pageContext.notifyError(SebExamConfigPropForm.FORM_TITLE, e);
} }
} }
private void notifyErrorOnSave(final Exception error, final PageContext context) { private void notifyErrorOnSave(final Exception error, final PageContext context) {
if (error instanceof APIMessageError) { if (error instanceof APIMessageError) {
try { try {
final List<APIMessage> errorMessages = ((APIMessageError) error).getErrorMessages(); final List<APIMessage> errorMessages = ((APIMessageError) error).getErrorMessages();
final APIMessage apiMessage = errorMessages.get(0); final APIMessage apiMessage = errorMessages.get(0);
if (APIMessage.ErrorMessage.INTEGRITY_VALIDATION.isOf(apiMessage)) { if (APIMessage.ErrorMessage.INTEGRITY_VALIDATION.isOf(apiMessage)) {
throw new PageMessageException(MESSAGE_SAVE_INTEGRITY_VIOLATION); throw new PageMessageException(MESSAGE_SAVE_INTEGRITY_VIOLATION);
} else { } else {
throw error; throw error;
} }
} catch (final PageMessageException e) { } catch (final PageMessageException e) {
throw e; throw e;
} catch (final Exception e) { } catch (final Exception e) {
throw new RuntimeException(error); throw new RuntimeException(error);
} }
} }
} }
}
}

View file

@ -1,143 +1,147 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.content; package ch.ethz.seb.sebserver.gui.content;
import org.eclipse.swt.SWT; import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.MessageBox; import org.eclipse.swt.widgets.MessageBox;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.user.PasswordChange; import ch.ethz.seb.sebserver.gbl.model.user.PasswordChange;
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.form.FormBuilder; import ch.ethz.seb.sebserver.gui.form.FormBuilder;
import ch.ethz.seb.sebserver.gui.form.FormHandle; import ch.ethz.seb.sebserver.gui.form.FormHandle;
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport; 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.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.PageContext; import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.PageService; import ch.ethz.seb.sebserver.gui.service.page.PageService;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction; import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.ChangePassword; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.ChangePassword;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccount; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccount;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
import ch.ethz.seb.sebserver.gui.widget.Message; import ch.ethz.seb.sebserver.gui.widget.Message;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@Lazy @Lazy
@Component @Component
@GuiProfile @GuiProfile
/** The form to change an User-Account password. /** The form to change an User-Account password.
* If the current user is the owner of the User-Account the password is required and must * If the current user is the owner of the User-Account the password is required and must
* match the users current password. * match the users current password.
* If the current user is an administrator that has to reset another users password the * If the current user is an administrator that has to reset another users password the
* password that is also required must match the administrators current password. */ * password that is also required must match the administrators current password.
public class UserAccountChangePasswordForm implements TemplateComposer { **/
public class UserAccountChangePasswordForm implements TemplateComposer {
private static final String FORM_TITLE_KEY = "sebserver.useraccount.form.pwchange.title";
private static final LocTextKey FORM_PASSWORD_NEW_TEXT_KEY = private static final String FORM_TITLE_KEY = "sebserver.useraccount.form.pwchange.title";
new LocTextKey("sebserver.useraccount.form.password.new"); private static final LocTextKey FORM_PASSWORD_NEW_TEXT_KEY =
private static final LocTextKey FORM_PASSWORD_NEW_CONFIRM_TEXT_KEY = new LocTextKey("sebserver.useraccount.form.password.new");
new LocTextKey("sebserver.useraccount.form.password.new.confirm"); private static final LocTextKey FORM_PASSWORD_NEW_CONFIRM_TEXT_KEY =
private static final LocTextKey FORM_PASSWORD_TEXT_KEY = new LocTextKey("sebserver.useraccount.form.password.new.confirm");
new LocTextKey("sebserver.useraccount.form.password"); private static final LocTextKey FORM_PASSWORD_TEXT_KEY =
new LocTextKey("sebserver.useraccount.form.password");
private final PageService pageService;
private final RestService restService; private final PageService pageService;
private final CurrentUser currentUser; private final RestService restService;
private final I18nSupport i18nSupport; private final CurrentUser currentUser;
private final I18nSupport i18nSupport;
protected UserAccountChangePasswordForm(
final PageService pageService, protected UserAccountChangePasswordForm(
final RestService restService, final PageService pageService,
final CurrentUser currentUser) { final RestService restService,
final CurrentUser currentUser) {
this.pageService = pageService;
this.restService = restService; this.pageService = pageService;
this.currentUser = currentUser; this.restService = restService;
this.i18nSupport = pageService.getI18nSupport(); this.currentUser = currentUser;
} this.i18nSupport = pageService.getI18nSupport();
}
@Override
public void compose(final PageContext pageContext) { @Override
public void compose(final PageContext pageContext) {
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
final EntityKey entityKey = pageContext.getEntityKey(); final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
final EntityKey entityKey = pageContext.getEntityKey();
final UserInfo userInfo = this.restService
.getBuilder(GetUserAccount.class) final UserInfo userInfo = this.restService
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId) .getBuilder(GetUserAccount.class)
.call() .withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.onError(error -> pageContext.notifyLoadError(EntityType.USER, error)) .call()
.getOrThrow(); .onError(error -> pageContext.notifyLoadError(EntityType.USER, error))
.getOrThrow();
final Composite content = widgetFactory.defaultPageLayout(
pageContext.getParent(), final Composite content = widgetFactory.defaultPageLayout(
new LocTextKey(FORM_TITLE_KEY, userInfo.username)); pageContext.getParent(),
new LocTextKey(FORM_TITLE_KEY, userInfo.username));
final boolean ownAccount = this.currentUser.get().uuid.equals(entityKey.getModelId());
final boolean ownAccount = this.currentUser.get().uuid.equals(entityKey.getModelId());
// The Password Change form
final FormHandle<UserInfo> formHandle = this.pageService.formBuilder(pageContext.copyOf(content)) // The Password Change form
.readonly(false) final FormHandle<UserInfo> formHandle = this.pageService.formBuilder(pageContext.copyOf(content))
.putStaticValueIf(() -> entityKey != null, .readonly(false)
Domain.USER.ATTR_UUID, .putStaticValueIf(() -> entityKey != null,
entityKey.getModelId()) Domain.USER.ATTR_UUID,
.addField(FormBuilder.text( entityKey.getModelId())
PasswordChange.ATTR_NAME_PASSWORD, .addField(FormBuilder.text(
FORM_PASSWORD_TEXT_KEY) PasswordChange.ATTR_NAME_PASSWORD,
.asPasswordField()) FORM_PASSWORD_TEXT_KEY)
.addField(FormBuilder.text( .asPasswordField()
PasswordChange.ATTR_NAME_NEW_PASSWORD, .mandatory())
FORM_PASSWORD_NEW_TEXT_KEY) .addField(FormBuilder.text(
.asPasswordField()) PasswordChange.ATTR_NAME_NEW_PASSWORD,
.addFieldIf( FORM_PASSWORD_NEW_TEXT_KEY)
() -> entityKey != null, .asPasswordField()
() -> FormBuilder.text( .mandatory())
PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD, .addFieldIf(
FORM_PASSWORD_NEW_CONFIRM_TEXT_KEY) () -> entityKey != null,
.asPasswordField()) () -> FormBuilder.text(
.buildFor(this.restService.getRestCall(ChangePassword.class)); PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD,
FORM_PASSWORD_NEW_CONFIRM_TEXT_KEY)
this.pageService.pageActionBuilder(pageContext) .asPasswordField()
.mandatory())
.newAction(ActionDefinition.USER_ACCOUNT_CHANGE_PASSOWRD_SAVE) .buildFor(this.restService.getRestCall(ChangePassword.class));
.withExec(action -> {
final PageAction saveAction = formHandle.processFormSave(action); this.pageService.pageActionBuilder(pageContext)
if (ownAccount) {
// NOTE: in this case the user changed the password of the own account .newAction(ActionDefinition.USER_ACCOUNT_CHANGE_PASSWORD_SAVE)
// this should cause an logout with specified message that password change .withExec(action -> {
// was successful and the pointing the need of re login with the new password final PageAction saveAction = formHandle.processFormSave(action);
this.pageService.logout(pageContext); if (ownAccount) {
final MessageBox error = new Message( // NOTE: in this case the user changed the password of the own account
pageContext.getShell(), // this should cause an logout with specified message that password change
this.i18nSupport.getText("sebserver.login.password.change"), // was successful and the pointing the need of re login with the new password
this.i18nSupport.getText("sebserver.login.password.change.success"), this.pageService.logout(pageContext);
SWT.ICON_INFORMATION, final MessageBox error = new Message(
this.i18nSupport); pageContext.getShell(),
error.open(null); this.i18nSupport.getText("sebserver.login.password.change"),
} this.i18nSupport.getText("sebserver.login.password.change.success"),
return saveAction; SWT.ICON_INFORMATION,
}) this.i18nSupport);
.ignoreMoveAwayFromEdit() error.open(null);
.publish() }
return saveAction;
.newAction(ActionDefinition.USER_ACCOUNT_CANCEL_MODIFY) })
.withExec(this.pageService.backToCurrentFunction()) .ignoreMoveAwayFromEdit()
.publish(); .publish()
}
.newAction(ActionDefinition.USER_ACCOUNT_CANCEL_MODIFY)
} .withExec(this.pageService.backToCurrentFunction())
.publish();
}
}

View file

@ -1,279 +1,291 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.content; package ch.ethz.seb.sebserver.gui.content;
import java.util.function.BooleanSupplier; import java.util.function.BooleanSupplier;
import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.BooleanUtils;
import org.apache.tomcat.util.buf.StringUtils; import org.apache.tomcat.util.buf.StringUtils;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.api.authorization.Privilege; import ch.ethz.seb.sebserver.gbl.api.authorization.Privilege;
import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType; import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType;
import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.Domain.USER_ROLE; import ch.ethz.seb.sebserver.gbl.model.Domain.USER_ROLE;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.user.PasswordChange; import ch.ethz.seb.sebserver.gbl.model.user.PasswordChange;
import ch.ethz.seb.sebserver.gbl.model.user.UserAccount; import ch.ethz.seb.sebserver.gbl.model.user.UserAccount;
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
import ch.ethz.seb.sebserver.gbl.model.user.UserMod; import ch.ethz.seb.sebserver.gbl.model.user.UserMod;
import ch.ethz.seb.sebserver.gbl.model.user.UserRole; import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.form.FormBuilder; import ch.ethz.seb.sebserver.gui.form.FormBuilder;
import ch.ethz.seb.sebserver.gui.form.FormHandle; import ch.ethz.seb.sebserver.gui.form.FormHandle;
import ch.ethz.seb.sebserver.gui.service.ResourceService; import ch.ethz.seb.sebserver.gui.service.ResourceService;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.PageContext; import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.PageService; import ch.ethz.seb.sebserver.gui.service.page.PageService;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitution; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitution;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.ActivateUserAccount; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.ActivateUserAccount;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.DeactivateUserAccount; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.DeactivateUserAccount;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccount; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccount;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.NewUserAccount; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.NewUserAccount;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.SaveUserAccount; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.SaveUserAccount;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.EntityGrantCheck; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.EntityGrantCheck;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@Lazy @Lazy
@Component @Component
@GuiProfile @GuiProfile
public class UserAccountForm implements TemplateComposer { public class UserAccountForm implements TemplateComposer {
static final LocTextKey TITLE_TEXT_KEY = static final LocTextKey TITLE_TEXT_KEY =
new LocTextKey("sebserver.useraccount.form.title"); new LocTextKey("sebserver.useraccount.form.title");
static final LocTextKey NEW_TITLE_TEXT_KEY = static final LocTextKey NEW_TITLE_TEXT_KEY =
new LocTextKey("sebserver.useraccount.form.title.new"); new LocTextKey("sebserver.useraccount.form.title.new");
static final LocTextKey FORM_PASSWORD_CONFIRM_TEXT_KEY = static final LocTextKey FORM_PASSWORD_CONFIRM_TEXT_KEY =
new LocTextKey("sebserver.useraccount.form.password.confirm"); new LocTextKey("sebserver.useraccount.form.password.confirm");
static final LocTextKey FORM_PASSWORD_TEXT_KEY = static final LocTextKey FORM_PASSWORD_TEXT_KEY =
new LocTextKey("sebserver.useraccount.form.password"); new LocTextKey("sebserver.useraccount.form.password");
static final LocTextKey FORM_ROLES_TEXT_KEY = static final LocTextKey FORM_ROLES_TEXT_KEY =
new LocTextKey("sebserver.useraccount.form.roles"); new LocTextKey("sebserver.useraccount.form.roles");
static final LocTextKey FORM_TIMEZONE_TEXT_KEY = static final LocTextKey FORM_TIMEZONE_TEXT_KEY =
new LocTextKey("sebserver.useraccount.form.timezone"); new LocTextKey("sebserver.useraccount.form.timezone");
static final LocTextKey FORM_MAIL_TEXT_KEY = static final LocTextKey FORM_MAIL_TEXT_KEY =
new LocTextKey("sebserver.useraccount.form.mail"); new LocTextKey("sebserver.useraccount.form.mail");
static final LocTextKey FORM_USERNAME_TEXT_KEY = static final LocTextKey FORM_USERNAME_TEXT_KEY =
new LocTextKey("sebserver.useraccount.form.username"); new LocTextKey("sebserver.useraccount.form.username");
static final LocTextKey FORM_NAME_TEXT_KEY = static final LocTextKey FORM_NAME_TEXT_KEY =
new LocTextKey("sebserver.useraccount.form.name"); new LocTextKey("sebserver.useraccount.form.name");
static final LocTextKey FORM_SURNAME_TEXT_KEY = static final LocTextKey FORM_SURNAME_TEXT_KEY =
new LocTextKey("sebserver.useraccount.form.surname"); new LocTextKey("sebserver.useraccount.form.surname");
static final LocTextKey FORM_INSTITUTION_TEXT_KEY = static final LocTextKey FORM_INSTITUTION_TEXT_KEY =
new LocTextKey("sebserver.useraccount.form.institution"); new LocTextKey("sebserver.useraccount.form.institution");
static final LocTextKey FORM_CREATION_DATE_TEXT_KEY = static final LocTextKey FORM_CREATION_DATE_TEXT_KEY =
new LocTextKey("sebserver.useraccount.form.creationdate"); new LocTextKey("sebserver.useraccount.form.creationdate");
static final LocTextKey FORM_LANG_TEXT_KEY = static final LocTextKey FORM_LANG_TEXT_KEY =
new LocTextKey("sebserver.useraccount.form.language"); new LocTextKey("sebserver.useraccount.form.language");
private final PageService pageService; private final PageService pageService;
private final ResourceService resourceService; private final ResourceService resourceService;
private final boolean multilingual; private final boolean multilingual;
protected UserAccountForm( protected UserAccountForm(
final PageService pageService, final PageService pageService,
final ResourceService resourceService, final ResourceService resourceService,
@Value("${sebserver.gui.multilingual:false}") final Boolean multilingual) { @Value("${sebserver.gui.multilingual:false}") final Boolean multilingual) {
this.pageService = pageService; this.pageService = pageService;
this.resourceService = resourceService; this.resourceService = resourceService;
this.multilingual = BooleanUtils.toBoolean(multilingual); this.multilingual = BooleanUtils.toBoolean(multilingual);
} }
@Override @Override
public void compose(final PageContext pageContext) { public void compose(final PageContext pageContext) {
final CurrentUser currentUser = this.resourceService.getCurrentUser(); final CurrentUser currentUser = this.resourceService.getCurrentUser();
final RestService restService = this.resourceService.getRestService(); final RestService restService = this.resourceService.getRestService();
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory(); final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
final UserInfo user = currentUser.get(); final UserInfo user = currentUser.get();
final EntityKey entityKey = pageContext.getEntityKey(); final EntityKey entityKey = pageContext.getEntityKey();
final EntityKey parentEntityKey = pageContext.getParentEntityKey(); final EntityKey parentEntityKey = pageContext.getParentEntityKey();
final boolean readonly = pageContext.isReadonly(); final boolean readonly = pageContext.isReadonly();
final BooleanSupplier isNew = () -> entityKey == null; final BooleanSupplier isNew = () -> entityKey == null;
final BooleanSupplier isNotNew = () -> !isNew.getAsBoolean(); final BooleanSupplier isNotNew = () -> !isNew.getAsBoolean();
final BooleanSupplier isSEBAdmin = () -> user.hasRole(UserRole.SEB_SERVER_ADMIN); final BooleanSupplier isSEBAdmin = () -> user.hasRole(UserRole.SEB_SERVER_ADMIN);
// get data or create new. handle error if happen // get data or create new. handle error if happen
final UserAccount userAccount = isNew.getAsBoolean() final UserAccount userAccount = isNew.getAsBoolean()
? UserMod.createNew((parentEntityKey != null) ? UserMod.createNew((parentEntityKey != null)
? Long.valueOf(parentEntityKey.modelId) ? Long.valueOf(parentEntityKey.modelId)
: user.institutionId) : currentUser.get().institutionId)
: restService : restService
.getBuilder(GetUserAccount.class) .getBuilder(GetUserAccount.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId) .withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call() .call()
.onError(error -> pageContext.notifyLoadError(EntityType.USER, error)) .onError(error -> pageContext.notifyLoadError(EntityType.USER, error))
.getOrThrow(); .getOrThrow();
final boolean roleBasedEditGrant = Privilege.hasRoleBasedUserAccountEditGrant(userAccount, currentUser.get()); final boolean roleBasedEditGrant = Privilege.hasRoleBasedUserAccountEditGrant(userAccount, currentUser.get());
// new PageContext with actual EntityKey // new PageContext with actual EntityKey
final PageContext formContext = pageContext.withEntityKey(userAccount.getEntityKey()); final PageContext formContext = pageContext.withEntityKey(userAccount.getEntityKey());
final boolean ownAccount = user.uuid.equals(userAccount.getModelId()); final boolean ownAccount = user.uuid.equals(userAccount.getModelId());
final EntityGrantCheck userGrantCheck = currentUser.entityGrantCheck(userAccount); final EntityGrantCheck userGrantCheck = currentUser.entityGrantCheck(userAccount);
final boolean writeGrant = roleBasedEditGrant && userGrantCheck.w(); final boolean writeGrant = roleBasedEditGrant && userGrantCheck.w();
final boolean modifyGrant = roleBasedEditGrant && userGrantCheck.m(); final boolean modifyGrant = roleBasedEditGrant && userGrantCheck.m();
final boolean institutionalWriteGrant = currentUser.hasInstitutionalPrivilege( final boolean institutionalWriteGrant = currentUser.hasInstitutionalPrivilege(
PrivilegeType.WRITE, PrivilegeType.WRITE,
EntityType.USER); EntityType.USER);
final boolean institutionActive = restService.getBuilder(GetInstitution.class) final boolean institutionActive = userAccount.getInstitutionId() != null &&
.withURIVariable(API.PARAM_MODEL_ID, String.valueOf(userAccount.getInstitutionId())) restService.getBuilder(GetInstitution.class)
.call() .withURIVariable(API.PARAM_MODEL_ID, String.valueOf(userAccount.getInstitutionId()))
.map(inst -> inst.active) .call()
.getOr(false); .map(inst -> inst.active)
.getOr(false);
// the default page layout with title
final LocTextKey titleKey = isNotNew.getAsBoolean() // the default page layout with title
? TITLE_TEXT_KEY final LocTextKey titleKey = isNotNew.getAsBoolean()
: NEW_TITLE_TEXT_KEY; ? TITLE_TEXT_KEY
final Composite content = widgetFactory.defaultPageLayout( : NEW_TITLE_TEXT_KEY;
formContext.getParent(), final Composite content = widgetFactory.defaultPageLayout(
titleKey); formContext.getParent(),
titleKey);
// The UserAccount form
final FormHandle<UserInfo> formHandle = this.pageService.formBuilder( // The UserAccount form
formContext.copyOf(content)) final FormHandle<UserInfo> formHandle = this.pageService.formBuilder(
.readonly(readonly) formContext.copyOf(content))
.putStaticValueIf(isNotNew, .readonly(readonly)
Domain.USER.ATTR_UUID, .putStaticValueIf(isNotNew,
userAccount.getModelId()) Domain.USER.ATTR_UUID,
.putStaticValueIf(isNotNew, userAccount.getModelId())
Domain.USER.ATTR_INSTITUTION_ID, .putStaticValueIf(isNotNew,
String.valueOf(userAccount.getInstitutionId())) Domain.USER.ATTR_INSTITUTION_ID,
.putStaticValueIf( String.valueOf(userAccount.getInstitutionId()))
() -> !this.multilingual, .putStaticValueIf(
Domain.USER.ATTR_LANGUAGE, () -> !this.multilingual,
"en") Domain.USER.ATTR_LANGUAGE,
.addFieldIf( "en")
isSEBAdmin, .addFieldIf(
() -> FormBuilder.singleSelection( isSEBAdmin,
Domain.USER.ATTR_INSTITUTION_ID, () -> FormBuilder.singleSelection(
FORM_INSTITUTION_TEXT_KEY, Domain.USER.ATTR_INSTITUTION_ID,
String.valueOf(userAccount.getInstitutionId()), FORM_INSTITUTION_TEXT_KEY,
() -> this.resourceService.institutionResource()) String.valueOf(userAccount.getInstitutionId()),
.readonlyIf(isNotNew)) this.resourceService::institutionResource)
.addFieldIf( .readonlyIf(isNotNew)
() -> readonly, .mandatory(!readonly))
() -> FormBuilder.text( .addFieldIf(
Domain.USER.ATTR_CREATION_DATE, () -> readonly,
FORM_CREATION_DATE_TEXT_KEY, () -> FormBuilder.text(
this.pageService.getI18nSupport().formatDisplayDate(userAccount.getCreationDate())) Domain.USER.ATTR_CREATION_DATE,
.readonly(true)) FORM_CREATION_DATE_TEXT_KEY,
.addField(FormBuilder.text( this.pageService.getI18nSupport().formatDisplayDate(userAccount.getCreationDate()))
Domain.USER.ATTR_NAME, .readonly(true))
FORM_NAME_TEXT_KEY, .addField(FormBuilder.text(
userAccount.getName())) Domain.USER.ATTR_NAME,
.addField(FormBuilder.text( FORM_NAME_TEXT_KEY,
Domain.USER.ATTR_SURNAME, userAccount.getName())
FORM_SURNAME_TEXT_KEY, .mandatory(!readonly))
userAccount.getSurname())) .addField(FormBuilder.text(
.addField(FormBuilder.text( Domain.USER.ATTR_SURNAME,
Domain.USER.ATTR_USERNAME, FORM_SURNAME_TEXT_KEY,
FORM_USERNAME_TEXT_KEY, userAccount.getSurname())
userAccount.getUsername())) .mandatory(!readonly))
.addField(FormBuilder.text( .addField(FormBuilder.text(
Domain.USER.ATTR_EMAIL, Domain.USER.ATTR_USERNAME,
FORM_MAIL_TEXT_KEY, FORM_USERNAME_TEXT_KEY,
userAccount.getEmail())) userAccount.getUsername())
.addFieldIf( .mandatory(!readonly))
() -> this.multilingual, .addField(FormBuilder.text(
() -> FormBuilder.singleSelection( Domain.USER.ATTR_EMAIL,
Domain.USER.ATTR_LANGUAGE, FORM_MAIL_TEXT_KEY,
FORM_LANG_TEXT_KEY, userAccount.getEmail()))
userAccount.getLanguage().getLanguage(), .addFieldIf(
this.resourceService::languageResources)) () -> this.multilingual,
.addField(FormBuilder.singleSelection( () -> FormBuilder.singleSelection(
Domain.USER.ATTR_TIMEZONE, Domain.USER.ATTR_LANGUAGE,
FORM_TIMEZONE_TEXT_KEY, FORM_LANG_TEXT_KEY,
userAccount.getTimeZone().getID(), userAccount.getLanguage().getLanguage(),
this.resourceService::timeZoneResources)) this.resourceService::languageResources))
.addFieldIf( .addField(FormBuilder.singleSelection(
() -> modifyGrant, Domain.USER.ATTR_TIMEZONE,
() -> FormBuilder.multiCheckboxSelection( FORM_TIMEZONE_TEXT_KEY,
USER_ROLE.REFERENCE_NAME, userAccount.getTimeZone().getID(),
FORM_ROLES_TEXT_KEY, this.resourceService::timeZoneResources)
StringUtils.join(userAccount.getRoles(), Constants.LIST_SEPARATOR_CHAR), .mandatory(!readonly))
this.resourceService::userRoleResources) .addFieldIf(
.visibleIf(writeGrant)) () -> modifyGrant,
.addFieldIf( () -> FormBuilder.multiCheckboxSelection(
isNew, USER_ROLE.REFERENCE_NAME,
() -> FormBuilder.text( FORM_ROLES_TEXT_KEY,
PasswordChange.ATTR_NAME_NEW_PASSWORD, StringUtils.join(userAccount.getRoles(), Constants.LIST_SEPARATOR_CHAR),
FORM_PASSWORD_TEXT_KEY) this.resourceService::userRoleResources)
.asPasswordField()) .visibleIf(writeGrant)
.addFieldIf( .mandatory(!readonly))
isNew, .addFieldIf(
() -> FormBuilder.text( isNew,
PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD, () -> FormBuilder.text(
FORM_PASSWORD_CONFIRM_TEXT_KEY) PasswordChange.ATTR_NAME_NEW_PASSWORD,
.asPasswordField()) FORM_PASSWORD_TEXT_KEY)
.buildFor((entityKey == null) .asPasswordField()
? restService.getRestCall(NewUserAccount.class) .mandatory(!readonly))
: restService.getRestCall(SaveUserAccount.class)); .addFieldIf(
isNew,
// propagate content actions to action-pane () -> FormBuilder.text(
this.pageService.pageActionBuilder(formContext.clearEntityKeys()) PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD,
FORM_PASSWORD_CONFIRM_TEXT_KEY)
.newAction(ActionDefinition.USER_ACCOUNT_NEW) .asPasswordField()
.publishIf(() -> institutionalWriteGrant && readonly && institutionActive) .mandatory(!readonly))
.buildFor((entityKey == null)
.newAction(ActionDefinition.USER_ACCOUNT_MODIFY) ? restService.getRestCall(NewUserAccount.class)
.withEntityKey(entityKey) : restService.getRestCall(SaveUserAccount.class));
.publishIf(() -> modifyGrant && readonly && institutionActive)
// propagate content actions to action-pane
.newAction(ActionDefinition.USER_ACCOUNT_CHANGE_PASSOWRD) this.pageService.pageActionBuilder(formContext.clearEntityKeys())
.withEntityKey(entityKey)
.publishIf(() -> modifyGrant && readonly && institutionActive && userAccount.isActive()) .newAction(ActionDefinition.USER_ACCOUNT_NEW)
.publishIf(() -> institutionalWriteGrant && readonly && institutionActive)
.newAction(ActionDefinition.USER_ACCOUNT_DEACTIVATE)
.withEntityKey(entityKey) .newAction(ActionDefinition.USER_ACCOUNT_MODIFY)
.withSimpleRestCall(restService, DeactivateUserAccount.class) .withEntityKey(entityKey)
.withConfirm(this.pageService.confirmDeactivation(userAccount)) .publishIf(() -> modifyGrant && readonly && institutionActive)
.publishIf(() -> writeGrant && readonly && institutionActive && userAccount.isActive())
.newAction(ActionDefinition.USER_ACCOUNT_CHANGE_PASSWORD)
.newAction(ActionDefinition.USER_ACCOUNT_ACTIVATE) .withEntityKey(entityKey)
.withEntityKey(entityKey) .publishIf(() -> modifyGrant && readonly && institutionActive && userAccount.isActive())
.withSimpleRestCall(restService, ActivateUserAccount.class)
.publishIf(() -> writeGrant && readonly && institutionActive && !userAccount.isActive()) .newAction(ActionDefinition.USER_ACCOUNT_DEACTIVATE)
.withEntityKey(entityKey)
.newAction(ActionDefinition.USER_ACCOUNT_SAVE) .withSimpleRestCall(restService, DeactivateUserAccount.class)
.withEntityKey(entityKey) .withConfirm(this.pageService.confirmDeactivation(userAccount))
.withExec(action -> { .publishIf(() -> writeGrant && readonly && institutionActive && userAccount.isActive())
return formHandle.handleFormPost(formHandle.doAPIPost()
.map(userInfo -> { .newAction(ActionDefinition.USER_ACCOUNT_ACTIVATE)
if (ownAccount) { .withEntityKey(entityKey)
currentUser.refresh(userInfo); .withSimpleRestCall(restService, ActivateUserAccount.class)
} .publishIf(() -> writeGrant && readonly && institutionActive && !userAccount.isActive())
return userInfo;
}), .newAction(ActionDefinition.USER_ACCOUNT_SAVE)
action); .withEntityKey(entityKey)
}) .withExec(action -> formHandle.handleFormPost(formHandle.doAPIPost()
.ignoreMoveAwayFromEdit() .map(userInfo -> {
.publishIf(() -> !readonly) if (ownAccount) {
currentUser.refresh(userInfo);
.newAction(ActionDefinition.USER_ACCOUNT_CANCEL_MODIFY) }
.withExec(this.pageService.backToCurrentFunction()) return userInfo;
.publishIf(() -> !readonly); }),
} action))
.ignoreMoveAwayFromEdit()
} .publishIf(() -> !readonly)
.newAction(ActionDefinition.USER_ACCOUNT_SAVE_AND_ACTIVATE)
.withEntityKey(entityKey)
.withExec(formHandle::saveAndActivate)
.ignoreMoveAwayFromEdit()
.publishIf(() -> !readonly && !ownAccount && !userAccount.isActive())
.newAction(ActionDefinition.USER_ACCOUNT_CANCEL_MODIFY)
.withExec(this.pageService.backToCurrentFunction())
.publishIf(() -> !readonly);
}
}

View file

@ -1,236 +1,250 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.content; package ch.ethz.seb.sebserver.gui.content;
import java.util.function.BooleanSupplier; import ch.ethz.seb.sebserver.gbl.Constants;
import java.util.function.Function; import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import org.apache.commons.lang3.BooleanUtils; import ch.ethz.seb.sebserver.gbl.api.authorization.Privilege;
import org.eclipse.swt.widgets.Composite; import ch.ethz.seb.sebserver.gbl.model.Domain;
import org.springframework.beans.factory.annotation.Value; import ch.ethz.seb.sebserver.gbl.model.Entity;
import org.springframework.context.annotation.Lazy; import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
import org.springframework.stereotype.Component; import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gui.service.ResourceService;
import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gbl.api.authorization.Privilege; import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gui.service.page.PageMessageException;
import ch.ethz.seb.sebserver.gbl.model.Entity; import ch.ethz.seb.sebserver.gui.service.page.PageService;
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder;
import ch.ethz.seb.sebserver.gbl.model.user.UserRole; import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.ResourceService; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccount;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccountPage;
import ch.ethz.seb.sebserver.gui.service.page.PageContext; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
import ch.ethz.seb.sebserver.gui.service.page.PageMessageException; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck;
import ch.ethz.seb.sebserver.gui.service.page.PageService; import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder; import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; import ch.ethz.seb.sebserver.gui.table.EntityTable;
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction; import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccount; import org.apache.commons.lang3.BooleanUtils;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccountPage; import org.eclipse.swt.widgets.Composite;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; import org.springframework.beans.factory.annotation.Value;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck; import org.springframework.context.annotation.Lazy;
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition; import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute;
import ch.ethz.seb.sebserver.gui.table.EntityTable; import java.util.function.BooleanSupplier;
import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType; import java.util.function.Function;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@Lazy
@Lazy @Component
@Component @GuiProfile
@GuiProfile public class UserAccountList implements TemplateComposer {
public class UserAccountList implements TemplateComposer {
// localized text keys
// localized text keys private static final LocTextKey EMPTY_TEXT_KEY =
private static final LocTextKey EMPTY_TEXT_KEY = new LocTextKey("sebserver.useraccount.list.empty");
new LocTextKey("sebserver.useraccount.list.empty"); private static final LocTextKey INSTITUTION_TEXT_KEY =
private static final LocTextKey INSTITUTION_TEXT_KEY = new LocTextKey("sebserver.useraccount.list.column.institution");
new LocTextKey("sebserver.useraccount.list.column.institution"); private static final LocTextKey EMPTY_SELECTION_TEXT_KEY =
private static final LocTextKey EMPTY_SELECTION_TEXT_KEY = new LocTextKey("sebserver.useraccount.info.pleaseSelect");
new LocTextKey("sebserver.useraccount.info.pleaseSelect"); private static final LocTextKey ACTIVE_TEXT_KEY =
private static final LocTextKey ACTIVE_TEXT_KEY = new LocTextKey("sebserver.useraccount.list.column.active");
new LocTextKey("sebserver.useraccount.list.column.active"); private static final LocTextKey LANG_TEXT_KEY =
private static final LocTextKey LANG_TEXT_KEY = new LocTextKey("sebserver.useraccount.list.column.language");
new LocTextKey("sebserver.useraccount.list.column.language"); private static final LocTextKey MAIL_TEXT_KEY =
private static final LocTextKey MAIL_TEXT_KEY = new LocTextKey("sebserver.useraccount.list.column.email");
new LocTextKey("sebserver.useraccount.list.column.email"); private static final LocTextKey USER_NAME_TEXT_KEY =
private static final LocTextKey USER_NAME_TEXT_KEY = new LocTextKey("sebserver.useraccount.list.column.username");
new LocTextKey("sebserver.useraccount.list.column.username"); private static final LocTextKey NAME_TEXT_KEY =
private static final LocTextKey NAME_TEXT_KEY = new LocTextKey("sebserver.useraccount.list.column.name");
new LocTextKey("sebserver.useraccount.list.column.name"); private static final LocTextKey TITLE_TEXT_KEY =
private static final LocTextKey TITLE_TEXT_KEY = new LocTextKey("sebserver.useraccount.list.title");
new LocTextKey("sebserver.useraccount.list.title"); private static final LocTextKey NO_EDIT_RIGHT_MESSAGE =
private static final LocTextKey NO_EDIT_RIGHT_MESSAGE = new LocTextKey("sebserver.useraccount.info.notEditable");
new LocTextKey("sebserver.useraccount.info.notEditable");
// filter attribute models
// filter attribute models private final TableFilterAttribute institutionFilter;
private final TableFilterAttribute institutionFilter; private final TableFilterAttribute nameFilter =
private final TableFilterAttribute nameFilter = new TableFilterAttribute(CriteriaType.TEXT, Entity.FILTER_ATTR_NAME);
new TableFilterAttribute(CriteriaType.TEXT, Entity.FILTER_ATTR_NAME); private final TableFilterAttribute usernameFilter =
private final TableFilterAttribute usernameFilter = new TableFilterAttribute(CriteriaType.TEXT, UserInfo.FILTER_ATTR_USER_NAME);
new TableFilterAttribute(CriteriaType.TEXT, UserInfo.FILTER_ATTR_USER_NAME); private final TableFilterAttribute mailFilter =
private final TableFilterAttribute mailFilter = new TableFilterAttribute(CriteriaType.TEXT, UserInfo.FILTER_ATTR_EMAIL);
new TableFilterAttribute(CriteriaType.TEXT, UserInfo.FILTER_ATTR_EMAIL); private final TableFilterAttribute languageFilter;
private final TableFilterAttribute languageFilter; private final TableFilterAttribute activityFilter;
private final TableFilterAttribute activityFilter;
// dependencies
// dependencies private final PageService pageService;
private final PageService pageService; private final ResourceService resourceService;
private final ResourceService resourceService; private final int pageSize;
private final int pageSize; private final boolean multilingual;
private final boolean multilingual;
protected UserAccountList(
protected UserAccountList( final PageService pageService,
final PageService pageService, final ResourceService resourceService,
final ResourceService resourceService, @Value("${sebserver.gui.list.page.size:20}") final Integer pageSize,
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize, @Value("${sebserver.gui.multilingual:false}") final Boolean ml) {
@Value("${sebserver.gui.multilingual:false}") final Boolean ml) {
this.pageService = pageService;
this.pageService = pageService; this.resourceService = resourceService;
this.resourceService = resourceService; this.pageSize = pageSize;
this.pageSize = pageSize; this.multilingual = BooleanUtils.isTrue(ml);
this.multilingual = BooleanUtils.isTrue(ml);
this.institutionFilter = new TableFilterAttribute(
this.institutionFilter = new TableFilterAttribute( CriteriaType.SINGLE_SELECTION,
CriteriaType.SINGLE_SELECTION, Entity.FILTER_ATTR_INSTITUTION,
Entity.FILTER_ATTR_INSTITUTION, this.resourceService::institutionResource);
this.resourceService::institutionResource);
this.languageFilter = new TableFilterAttribute(
this.languageFilter = new TableFilterAttribute( CriteriaType.SINGLE_SELECTION,
CriteriaType.SINGLE_SELECTION, UserInfo.FILTER_ATTR_LANGUAGE,
UserInfo.FILTER_ATTR_LANGUAGE, this.resourceService::languageResources);
this.resourceService::languageResources);
this.activityFilter = new TableFilterAttribute(
this.activityFilter = new TableFilterAttribute( CriteriaType.SINGLE_SELECTION,
CriteriaType.SINGLE_SELECTION, UserInfo.FILTER_ATTR_ACTIVE,
UserInfo.FILTER_ATTR_ACTIVE, this.resourceService::activityResources);
this.resourceService::activityResources); }
}
@Override
@Override public void compose(final PageContext pageContext) {
public void compose(final PageContext pageContext) { final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory(); final CurrentUser currentUser = this.resourceService.getCurrentUser();
final CurrentUser currentUser = this.resourceService.getCurrentUser(); final RestService restService = this.resourceService.getRestService();
final RestService restService = this.resourceService.getRestService(); // content page layout with title
// content page layout with title final Composite content = widgetFactory.defaultPageLayout(
final Composite content = widgetFactory.defaultPageLayout( pageContext.getParent(),
pageContext.getParent(), TITLE_TEXT_KEY);
TITLE_TEXT_KEY);
final BooleanSupplier isSEBAdmin = () -> currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN);
final BooleanSupplier isSEBAdmin = () -> currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN); final PageActionBuilder actionBuilder = this.pageService.pageActionBuilder(pageContext.clearEntityKeys());
final PageActionBuilder actionBuilder = this.pageService.pageActionBuilder(pageContext.clearEntityKeys());
// table
// table final EntityTable<UserInfo> table = this.pageService.entityTableBuilder(
final EntityTable<UserInfo> table = this.pageService.entityTableBuilder( restService.getRestCall(GetUserAccountPage.class))
restService.getRestCall(GetUserAccountPage.class)) .withEmptyMessage(EMPTY_TEXT_KEY)
.withEmptyMessage(EMPTY_TEXT_KEY) .withPaging(this.pageSize)
.withPaging(this.pageSize)
.withColumnIf(
.withColumnIf( isSEBAdmin,
isSEBAdmin, () -> new ColumnDefinition<>(
() -> new ColumnDefinition<>( Domain.USER.ATTR_INSTITUTION_ID,
Domain.USER.ATTR_INSTITUTION_ID, INSTITUTION_TEXT_KEY,
INSTITUTION_TEXT_KEY, userInstitutionNameFunction(this.resourceService))
userInstitutionNameFunction(this.resourceService)) .withFilter(this.institutionFilter)
.withFilter(this.institutionFilter) .widthProportion(2))
.widthProportion(2))
.withColumn(new ColumnDefinition<>(
.withColumn(new ColumnDefinition<>( Domain.USER.ATTR_NAME,
Domain.USER.ATTR_NAME, NAME_TEXT_KEY,
NAME_TEXT_KEY, UserInfo::getName)
UserInfo::getName) .withFilter(this.nameFilter)
.withFilter(this.nameFilter) .sortable()
.sortable() .widthProportion(2))
.widthProportion(2))
.withColumn(new ColumnDefinition<>(
.withColumn(new ColumnDefinition<>( Domain.USER.ATTR_USERNAME,
Domain.USER.ATTR_USERNAME, USER_NAME_TEXT_KEY,
USER_NAME_TEXT_KEY, UserInfo::getUsername)
UserInfo::getUsername) .withFilter(this.usernameFilter)
.withFilter(this.usernameFilter) .sortable()
.sortable() .widthProportion(2))
.widthProportion(2))
.withColumn(new ColumnDefinition<>(
.withColumn(new ColumnDefinition<>( Domain.USER.ATTR_EMAIL,
Domain.USER.ATTR_EMAIL, MAIL_TEXT_KEY,
MAIL_TEXT_KEY, UserInfo::getEmail)
UserInfo::getEmail) .withFilter(this.mailFilter)
.withFilter(this.mailFilter) .sortable()
.sortable() .widthProportion(3))
.widthProportion(3))
.withColumnIf(() -> this.multilingual,
.withColumnIf(() -> this.multilingual, () -> new ColumnDefinition<>(
() -> new ColumnDefinition<>( Domain.USER.ATTR_LANGUAGE,
Domain.USER.ATTR_LANGUAGE, LANG_TEXT_KEY,
LANG_TEXT_KEY, this::getLocaleDisplayText)
this::getLocaleDisplayText) .withFilter(this.languageFilter)
.withFilter(this.languageFilter) .localized()
.localized() .sortable()
.sortable() .widthProportion(1))
.widthProportion(1))
.withColumn(new ColumnDefinition<>(
.withColumn(new ColumnDefinition<>( Domain.USER.ATTR_ACTIVE,
Domain.USER.ATTR_ACTIVE, ACTIVE_TEXT_KEY,
ACTIVE_TEXT_KEY, this.pageService.getResourceService().<UserInfo> localizedActivityFunction())
this.pageService.getResourceService().<UserInfo> localizedActivityFunction()) .sortable()
.sortable() .withFilter(this.activityFilter)
.withFilter(this.activityFilter) .widthProportion(1))
.widthProportion(1))
.withDefaultAction(actionBuilder
.withDefaultAction(actionBuilder .newAction(ActionDefinition.USER_ACCOUNT_VIEW_FROM_LIST)
.newAction(ActionDefinition.USER_ACCOUNT_VIEW_FROM_LIST) .create())
.create())
.compose(pageContext.copyOf(content)); .withSelectionListener(this.pageService.getSelectionPublisher(
ActionDefinition.USER_ACCOUNT_TOGGLE_ACTIVITY,
// propagate content actions to action-pane ActionDefinition.USER_ACCOUNT_ACTIVATE,
final GrantCheck userGrant = currentUser.grantCheck(EntityType.USER); ActionDefinition.USER_ACCOUNT_DEACTIVATE,
actionBuilder pageContext,
ActionDefinition.USER_ACCOUNT_VIEW_FROM_LIST,
.newAction(ActionDefinition.USER_ACCOUNT_NEW) ActionDefinition.USER_ACCOUNT_MODIFY_FROM_LIST,
.publishIf(userGrant::iw) ActionDefinition.USER_ACCOUNT_TOGGLE_ACTIVITY))
.newAction(ActionDefinition.USER_ACCOUNT_VIEW_FROM_LIST) .compose(pageContext.copyOf(content));
.withSelect(table::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> table.hasAnyContent()) // propagate content actions to action-pane
final GrantCheck userGrant = currentUser.grantCheck(EntityType.USER);
.newAction(ActionDefinition.USER_ACCOUNT_MODIFY_FROM_LIST) actionBuilder
.withSelect(table::getSelection, this::editAction, EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> userGrant.im() && table.hasAnyContent()); .newAction(ActionDefinition.USER_ACCOUNT_NEW)
} .publishIf(userGrant::iw)
private PageAction editAction(final PageAction pageAction) { .newAction(ActionDefinition.USER_ACCOUNT_VIEW_FROM_LIST)
if (!this.resourceService.getRestService() .withSelect(table::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY)
.getBuilder(GetUserAccount.class) .publishIf(table::hasAnyContent, false)
.withURIVariable(API.PARAM_MODEL_ID, pageAction.getSingleSelection().modelId)
.call() .newAction(ActionDefinition.USER_ACCOUNT_MODIFY_FROM_LIST)
.map(user -> Privilege.hasRoleBasedUserAccountEditGrant(user, .withSelect(table::getSelection, this::editAction, EMPTY_SELECTION_TEXT_KEY)
this.resourceService.getCurrentUser().get())) .publishIf(() -> userGrant.im() && table.hasAnyContent(), false)
.getOr(false)) {
throw new PageMessageException(NO_EDIT_RIGHT_MESSAGE); .newAction(ActionDefinition.USER_ACCOUNT_TOGGLE_ACTIVITY)
} .withExec(this.pageService.activationToggleActionFunction(table, EMPTY_SELECTION_TEXT_KEY))
.withConfirm(this.pageService.confirmDeactivation(table))
return PageAction.applySingleSelectionAsEntityKey(pageAction); .publishIf(() -> userGrant.m() && table.hasAnyContent(), false);
} }
private String getLocaleDisplayText(final UserInfo userInfo) { private PageAction editAction(final PageAction pageAction) {
return (userInfo.language != null) if (!this.resourceService.getRestService()
? userInfo.language.getDisplayLanguage(this.pageService.getI18nSupport().getUsersLanguageLocale()) .getBuilder(GetUserAccount.class)
: Constants.EMPTY_NOTE; .withURIVariable(API.PARAM_MODEL_ID, pageAction.getSingleSelection().modelId)
} .call()
.map(user -> Privilege.hasRoleBasedUserAccountEditGrant(user,
private static Function<UserInfo, String> userInstitutionNameFunction(final ResourceService resourceService) { this.resourceService.getCurrentUser().get()))
final Function<String, String> institutionNameFunction = resourceService.getInstitutionNameFunction(); .getOr(false)) {
return userInfo -> institutionNameFunction.apply(String.valueOf(userInfo.institutionId)); throw new PageMessageException(NO_EDIT_RIGHT_MESSAGE);
} }
} return PageAction.applySingleSelectionAsEntityKey(pageAction);
}
private String getLocaleDisplayText(final UserInfo userInfo) {
return (userInfo.language != null)
? userInfo.language.getDisplayLanguage(this.pageService.getI18nSupport().getUsersLanguageLocale())
: Constants.EMPTY_NOTE;
}
private static Function<UserInfo, String> userInstitutionNameFunction(final ResourceService resourceService) {
final Function<String, String> institutionNameFunction = resourceService.getInstitutionNameFunction();
return userInfo -> institutionNameFunction.apply(String.valueOf(userInfo.institutionId));
}
}

View file

@ -1,276 +1,279 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.content; package ch.ethz.seb.sebserver.gui.content;
import java.util.function.BooleanSupplier; import java.util.function.BooleanSupplier;
import java.util.function.Function; import java.util.function.Function;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.Entity; import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog; import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog;
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
import ch.ethz.seb.sebserver.gbl.model.user.UserRole; import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gbl.util.Utils; import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.form.FormBuilder; import ch.ethz.seb.sebserver.gui.form.FormBuilder;
import ch.ethz.seb.sebserver.gui.service.ResourceService; import ch.ethz.seb.sebserver.gui.service.ResourceService;
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport; import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.page.PageContext; import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.service.page.PageService; import ch.ethz.seb.sebserver.gui.service.page.PageService;
import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder; import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.page.impl.ModalInputDialog; import ch.ethz.seb.sebserver.gui.service.page.impl.ModalInputDialog;
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction; import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs.GetUserLogPage; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs.GetUserLogPage;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccount; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccount;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition; import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute; import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute;
import ch.ethz.seb.sebserver.gui.table.EntityTable; import ch.ethz.seb.sebserver.gui.table.EntityTable;
import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType; import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@Lazy @Lazy
@Component @Component
@GuiProfile @GuiProfile
public class UserActivityLogs implements TemplateComposer { public class UserActivityLogs implements TemplateComposer {
private static final LocTextKey DETAILS_TITLE_TEXT_KEY = private static final LocTextKey DETAILS_TITLE_TEXT_KEY =
new LocTextKey("sebserver.userlogs.details.title"); new LocTextKey("sebserver.userlogs.details.title");
private static final LocTextKey TITLE_TEXT_KEY = private static final LocTextKey TITLE_TEXT_KEY =
new LocTextKey("sebserver.userlogs.list.title"); new LocTextKey("sebserver.userlogs.list.title");
private static final LocTextKey EMPTY_TEXT_KEY = private static final LocTextKey EMPTY_TEXT_KEY =
new LocTextKey("sebserver.userlogs.list.empty"); new LocTextKey("sebserver.userlogs.list.empty");
private static final LocTextKey INSTITUTION_TEXT_KEY = private static final LocTextKey INSTITUTION_TEXT_KEY =
new LocTextKey("sebserver.userlogs.list.column.institution"); new LocTextKey("sebserver.userlogs.list.column.institution");
private static final LocTextKey USER_TEXT_KEY = private static final LocTextKey USER_TEXT_KEY =
new LocTextKey("sebserver.userlogs.list.column.user"); new LocTextKey("sebserver.userlogs.list.column.user");
private static final LocTextKey DATE_TEXT_KEY = private static final LocTextKey DATE_TEXT_KEY =
new LocTextKey("sebserver.userlogs.list.column.dateTime"); new LocTextKey("sebserver.userlogs.list.column.dateTime");
private static final LocTextKey DETAILS_DATE_TEXT_KEY = private static final LocTextKey DETAILS_DATE_TEXT_KEY =
new LocTextKey("sebserver.seblogs.details.dateTime"); new LocTextKey("sebserver.seblogs.details.dateTime");
private static final LocTextKey ACTIVITY_TEXT_KEY = private static final LocTextKey ACTIVITY_TEXT_KEY =
new LocTextKey("sebserver.userlogs.list.column.activityType"); new LocTextKey("sebserver.userlogs.list.column.activityType");
private static final LocTextKey ENTITY_TYPE_TEXT_KEY = private static final LocTextKey ENTITY_TYPE_TEXT_KEY =
new LocTextKey("sebserver.userlogs.list.column.entityType"); new LocTextKey("sebserver.userlogs.list.column.entityType");
private static final LocTextKey ENTITY_ID_TEXT_KEY = private static final LocTextKey ENTITY_ID_TEXT_KEY =
new LocTextKey("sebserver.userlogs.list.column.entityId"); new LocTextKey("sebserver.userlogs.list.column.entityId");
private static final LocTextKey MESSAGE_TEXT_KEY = private static final LocTextKey MESSAGE_TEXT_KEY =
new LocTextKey("sebserver.userlogs.list.column.message"); new LocTextKey("sebserver.userlogs.list.column.message");
private final static LocTextKey EMPTY_SELECTION_TEXT = private final static LocTextKey EMPTY_SELECTION_TEXT =
new LocTextKey("sebserver.userlogs.info.pleaseSelect"); new LocTextKey("sebserver.userlogs.info.pleaseSelect");
private final TableFilterAttribute institutionFilter; private final TableFilterAttribute institutionFilter;
private final TableFilterAttribute userNameFilter = private final TableFilterAttribute userNameFilter =
new TableFilterAttribute(CriteriaType.TEXT, UserActivityLog.FILTER_ATTR_USER_NAME); new TableFilterAttribute(CriteriaType.TEXT, UserActivityLog.FILTER_ATTR_USER_NAME);
private final TableFilterAttribute activityFilter; private final TableFilterAttribute activityFilter;
private final TableFilterAttribute entityFilter; private final TableFilterAttribute entityFilter;
private final PageService pageService; private final PageService pageService;
private final ResourceService resourceService; private final ResourceService resourceService;
private final I18nSupport i18nSupport; private final I18nSupport i18nSupport;
private final WidgetFactory widgetFactory; private final WidgetFactory widgetFactory;
private final int pageSize; private final int pageSize;
public UserActivityLogs( public UserActivityLogs(
final PageService pageService, final PageService pageService,
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) { @Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
this.pageService = pageService; this.pageService = pageService;
this.resourceService = pageService.getResourceService(); this.resourceService = pageService.getResourceService();
this.i18nSupport = this.resourceService.getI18nSupport(); this.i18nSupport = this.resourceService.getI18nSupport();
this.widgetFactory = pageService.getWidgetFactory(); this.widgetFactory = pageService.getWidgetFactory();
this.pageSize = pageSize; this.pageSize = pageSize;
this.institutionFilter = new TableFilterAttribute( this.institutionFilter = new TableFilterAttribute(
CriteriaType.SINGLE_SELECTION, CriteriaType.SINGLE_SELECTION,
Entity.FILTER_ATTR_INSTITUTION, Entity.FILTER_ATTR_INSTITUTION,
this.resourceService::institutionResource); this.resourceService::institutionResource);
this.activityFilter = new TableFilterAttribute( this.activityFilter = new TableFilterAttribute(
CriteriaType.SINGLE_SELECTION, CriteriaType.SINGLE_SELECTION,
UserActivityLog.FILTER_ATTR_ACTIVITY_TYPES, UserActivityLog.FILTER_ATTR_ACTIVITY_TYPES,
this.resourceService::userActivityTypeResources); this.resourceService::userActivityTypeResources);
this.entityFilter = new TableFilterAttribute( this.entityFilter = new TableFilterAttribute(
CriteriaType.SINGLE_SELECTION, CriteriaType.SINGLE_SELECTION,
UserActivityLog.FILTER_ATTR_ENTITY_TYPES, UserActivityLog.FILTER_ATTR_ENTITY_TYPES,
this.resourceService::entityTypeResources); this.resourceService::entityTypeResources);
} }
@Override @Override
public void compose(final PageContext pageContext) { public void compose(final PageContext pageContext) {
final CurrentUser currentUser = this.resourceService.getCurrentUser(); final CurrentUser currentUser = this.resourceService.getCurrentUser();
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory(); final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
final RestService restService = this.resourceService.getRestService(); final RestService restService = this.resourceService.getRestService();
// content page layout with title // content page layout with title
final Composite content = widgetFactory.defaultPageLayout( final Composite content = widgetFactory.defaultPageLayout(
pageContext.getParent(), pageContext.getParent(),
TITLE_TEXT_KEY); TITLE_TEXT_KEY);
final PageActionBuilder actionBuilder = this.pageService.pageActionBuilder( final PageActionBuilder actionBuilder = this.pageService.pageActionBuilder(
pageContext pageContext
.clearEntityKeys() .clearEntityKeys()
.clearAttributes()); .clearAttributes());
final BooleanSupplier isSebAdmin = final BooleanSupplier isSebAdmin =
() -> currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN); () -> currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN);
final Function<UserActivityLog, String> institutionNameFunction = final Function<UserActivityLog, String> institutionNameFunction =
this.resourceService.getInstitutionNameFunction() this.resourceService.getInstitutionNameFunction()
.compose(log -> { .compose(log -> {
try { try {
final UserInfo user = restService.getBuilder(GetUserAccount.class) final UserInfo user = restService.getBuilder(GetUserAccount.class)
.withURIVariable(API.PARAM_MODEL_ID, log.getUserUuid()) .withURIVariable(API.PARAM_MODEL_ID, log.getUserUuid())
.call().getOrThrow(); .call().getOrThrow();
return String.valueOf(user.getInstitutionId()); return String.valueOf(user.getInstitutionId());
} catch (final Exception e) { } catch (final Exception e) {
return Constants.EMPTY_NOTE; return Constants.EMPTY_NOTE;
} }
}); });
// table // table
final EntityTable<UserActivityLog> table = this.pageService.entityTableBuilder( final EntityTable<UserActivityLog> table = this.pageService.entityTableBuilder(
restService.getRestCall(GetUserLogPage.class)) restService.getRestCall(GetUserLogPage.class))
.withEmptyMessage(EMPTY_TEXT_KEY) .withEmptyMessage(EMPTY_TEXT_KEY)
.withPaging(this.pageSize) .withPaging(this.pageSize)
.withColumnIf( .withColumnIf(
isSebAdmin, isSebAdmin,
() -> new ColumnDefinition<>( () -> new ColumnDefinition<>(
UserActivityLog.FILTER_ATTR_INSTITUTION, UserActivityLog.FILTER_ATTR_INSTITUTION,
INSTITUTION_TEXT_KEY, INSTITUTION_TEXT_KEY,
institutionNameFunction) institutionNameFunction)
.withFilter(this.institutionFilter)) .withFilter(this.institutionFilter))
.withColumn(new ColumnDefinition<>( .withColumn(new ColumnDefinition<>(
UserActivityLog.ATTR_USER_NAME, UserActivityLog.ATTR_USER_NAME,
USER_TEXT_KEY, USER_TEXT_KEY,
UserActivityLog::getUsername) UserActivityLog::getUsername)
.withFilter(this.userNameFilter)) .withFilter(this.userNameFilter))
.withColumn(new ColumnDefinition<UserActivityLog>( .withColumn(new ColumnDefinition<UserActivityLog>(
Domain.USER_ACTIVITY_LOG.ATTR_ACTIVITY_TYPE, Domain.USER_ACTIVITY_LOG.ATTR_ACTIVITY_TYPE,
ACTIVITY_TEXT_KEY, ACTIVITY_TEXT_KEY,
this.resourceService::getUserActivityTypeName) this.resourceService::getUserActivityTypeName)
.withFilter(this.activityFilter) .withFilter(this.activityFilter)
.sortable()) .sortable())
.withColumn(new ColumnDefinition<UserActivityLog>( .withColumn(new ColumnDefinition<UserActivityLog>(
Domain.USER_ACTIVITY_LOG.ATTR_ENTITY_ID, Domain.USER_ACTIVITY_LOG.ATTR_ENTITY_ID,
ENTITY_TYPE_TEXT_KEY, ENTITY_TYPE_TEXT_KEY,
this.resourceService::getEntityTypeName) this.resourceService::getEntityTypeName)
.withFilter(this.entityFilter) .withFilter(this.entityFilter)
.sortable()) .sortable())
.withColumn(new ColumnDefinition<>( .withColumn(new ColumnDefinition<>(
Domain.USER_ACTIVITY_LOG.ATTR_TIMESTAMP, Domain.USER_ACTIVITY_LOG.ATTR_TIMESTAMP,
new LocTextKey(DATE_TEXT_KEY.name, this.i18nSupport.getUsersTimeZoneTitleSuffix()), new LocTextKey(DATE_TEXT_KEY.name, this.i18nSupport.getUsersTimeZoneTitleSuffix()),
this::getLogTime) this::getLogTime)
.withFilter(new TableFilterAttribute( .withFilter(new TableFilterAttribute(
CriteriaType.DATE_RANGE, CriteriaType.DATE_RANGE,
UserActivityLog.FILTER_ATTR_FROM_TO, UserActivityLog.FILTER_ATTR_FROM_TO,
Utils.toDateTimeUTC(Utils.getMillisecondsNow()) Utils.toDateTimeUTC(Utils.getMillisecondsNow())
.minusYears(1) .minusYears(1)
.toString())) .toString()))
.sortable()) .sortable())
.withDefaultAction(t -> actionBuilder .withDefaultAction(t -> actionBuilder
.newAction(ActionDefinition.LOGS_USER_ACTIVITY_SHOW_DETAILS) .newAction(ActionDefinition.LOGS_USER_ACTIVITY_SHOW_DETAILS)
.withExec(action -> this.showDetails(action, t.getSingleSelectedROWData())) .withExec(action -> this.showDetails(action, t.getSingleSelectedROWData()))
.noEventPropagation() .noEventPropagation()
.create()) .create())
.compose(pageContext.copyOf(content)); .withSelectionListener(this.pageService.getSelectionPublisher(
pageContext,
actionBuilder ActionDefinition.LOGS_USER_ACTIVITY_SHOW_DETAILS))
.newAction(ActionDefinition.LOGS_USER_ACTIVITY_SHOW_DETAILS) .compose(pageContext.copyOf(content));
.withSelect(
table::getSelection, actionBuilder
action -> this.showDetails(action, table.getSingleSelectedROWData()), .newAction(ActionDefinition.LOGS_USER_ACTIVITY_SHOW_DETAILS)
EMPTY_SELECTION_TEXT) .withSelect(
.noEventPropagation() table::getSelection,
.publishIf(table::hasAnyContent); action -> this.showDetails(action, table.getSingleSelectedROWData()),
EMPTY_SELECTION_TEXT)
} .noEventPropagation()
.publishIf(table::hasAnyContent, false);
private final String getLogTime(final UserActivityLog log) {
if (log == null || log.timestamp == null) { }
return Constants.EMPTY_NOTE;
} private String getLogTime(final UserActivityLog log) {
if (log == null || log.timestamp == null) {
return this.i18nSupport return Constants.EMPTY_NOTE;
.formatDisplayDateTime(Utils.toDateTimeUTC(log.timestamp)); }
}
return this.i18nSupport
private PageAction showDetails(final PageAction action, final UserActivityLog userActivityLog) { .formatDisplayDateTime(Utils.toDateTimeUTC(log.timestamp));
action.getSingleSelection(); }
final ModalInputDialog<Void> dialog = new ModalInputDialog<>( private PageAction showDetails(final PageAction action, final UserActivityLog userActivityLog) {
action.pageContext().getParent().getShell(), action.getSingleSelection();
this.widgetFactory);
dialog.setLargeDialogWidth(); final ModalInputDialog<Void> dialog = new ModalInputDialog<>(
dialog.open( action.pageContext().getParent().getShell(),
DETAILS_TITLE_TEXT_KEY, this.widgetFactory);
action.pageContext(), dialog.setLargeDialogWidth();
pc -> createDetailsForm(userActivityLog, pc)); dialog.open(
DETAILS_TITLE_TEXT_KEY,
return action; action.pageContext(),
} pc -> createDetailsForm(userActivityLog, pc));
private void createDetailsForm(final UserActivityLog userActivityLog, final PageContext pc) { return action;
}
final Composite parent = pc.getParent();
final Composite grid = this.widgetFactory.createPopupScrollComposite(parent); private void createDetailsForm(final UserActivityLog userActivityLog, final PageContext pc) {
this.pageService.formBuilder(pc.copyOf(grid)) final Composite parent = pc.getParent();
.withDefaultSpanInput(6) final Composite grid = this.widgetFactory.createPopupScrollComposite(parent);
.withEmptyCellSeparation(false)
.readonly(true) this.pageService.formBuilder(pc.copyOf(grid))
.addField(FormBuilder.text( .withDefaultSpanInput(6)
UserActivityLog.ATTR_USER_NAME, .withEmptyCellSeparation(false)
USER_TEXT_KEY, .readonly(true)
String.valueOf(userActivityLog.getUsername()))) .addField(FormBuilder.text(
.addField(FormBuilder.text( UserActivityLog.ATTR_USER_NAME,
Domain.USER_ACTIVITY_LOG.ATTR_ACTIVITY_TYPE, USER_TEXT_KEY,
ACTIVITY_TEXT_KEY, String.valueOf(userActivityLog.getUsername())))
this.resourceService.getUserActivityTypeName(userActivityLog))) .addField(FormBuilder.text(
.addField(FormBuilder.text( Domain.USER_ACTIVITY_LOG.ATTR_ACTIVITY_TYPE,
Domain.USER_ACTIVITY_LOG.ATTR_ENTITY_TYPE, ACTIVITY_TEXT_KEY,
ENTITY_TYPE_TEXT_KEY, this.resourceService.getUserActivityTypeName(userActivityLog)))
this.resourceService.getEntityTypeName(userActivityLog))) .addField(FormBuilder.text(
.addField(FormBuilder.text( Domain.USER_ACTIVITY_LOG.ATTR_ENTITY_TYPE,
Domain.USER_ACTIVITY_LOG.ATTR_ENTITY_ID, ENTITY_TYPE_TEXT_KEY,
ENTITY_ID_TEXT_KEY, this.resourceService.getEntityTypeName(userActivityLog)))
userActivityLog.entityId)) .addField(FormBuilder.text(
.addField(FormBuilder.text( Domain.USER_ACTIVITY_LOG.ATTR_ENTITY_ID,
Domain.USER_ACTIVITY_LOG.ATTR_TIMESTAMP, ENTITY_ID_TEXT_KEY,
DETAILS_DATE_TEXT_KEY, userActivityLog.entityId))
this.widgetFactory.getI18nSupport() .addField(FormBuilder.text(
.formatDisplayDateTime(Utils.toDateTimeUTC(userActivityLog.timestamp)) + " " + Domain.USER_ACTIVITY_LOG.ATTR_TIMESTAMP,
this.i18nSupport.getUsersTimeZoneTitleSuffix())) DETAILS_DATE_TEXT_KEY,
.addField(FormBuilder.text( this.widgetFactory.getI18nSupport()
Domain.USER_ACTIVITY_LOG.ATTR_MESSAGE, .formatDisplayDateTime(Utils.toDateTimeUTC(userActivityLog.timestamp)) + " " +
MESSAGE_TEXT_KEY, this.i18nSupport.getUsersTimeZoneTitleSuffix()))
String.valueOf(userActivityLog.message)) .addField(FormBuilder.text(
.asArea()) Domain.USER_ACTIVITY_LOG.ATTR_MESSAGE,
.build(); MESSAGE_TEXT_KEY,
} String.valueOf(userActivityLog.message))
.asArea())
} .build();
}
}

View file

@ -1,138 +1,137 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.content.activity; package ch.ethz.seb.sebserver.gui.content.activity;
import ch.ethz.seb.sebserver.gui.content.ConfigTemplateAttributeForm; import ch.ethz.seb.sebserver.gui.content.ConfigTemplateAttributeForm;
import ch.ethz.seb.sebserver.gui.content.ConfigTemplateForm; import ch.ethz.seb.sebserver.gui.content.ConfigTemplateForm;
import ch.ethz.seb.sebserver.gui.content.ConfigTemplateList; import ch.ethz.seb.sebserver.gui.content.ConfigTemplateList;
import ch.ethz.seb.sebserver.gui.content.ExamForm; import ch.ethz.seb.sebserver.gui.content.ExamForm;
import ch.ethz.seb.sebserver.gui.content.ExamList; import ch.ethz.seb.sebserver.gui.content.ExamList;
import ch.ethz.seb.sebserver.gui.content.IndicatorForm; import ch.ethz.seb.sebserver.gui.content.IndicatorForm;
import ch.ethz.seb.sebserver.gui.content.InstitutionForm; import ch.ethz.seb.sebserver.gui.content.InstitutionForm;
import ch.ethz.seb.sebserver.gui.content.InstitutionList; import ch.ethz.seb.sebserver.gui.content.InstitutionList;
import ch.ethz.seb.sebserver.gui.content.LmsSetupForm; import ch.ethz.seb.sebserver.gui.content.LmsSetupForm;
import ch.ethz.seb.sebserver.gui.content.LmsSetupList; import ch.ethz.seb.sebserver.gui.content.LmsSetupList;
import ch.ethz.seb.sebserver.gui.content.MonitoringClientConnection; import ch.ethz.seb.sebserver.gui.content.MonitoringClientConnection;
import ch.ethz.seb.sebserver.gui.content.MonitoringRunningExam; import ch.ethz.seb.sebserver.gui.content.MonitoringRunningExam;
import ch.ethz.seb.sebserver.gui.content.MonitoringRunningExamList; import ch.ethz.seb.sebserver.gui.content.MonitoringRunningExamList;
import ch.ethz.seb.sebserver.gui.content.QuizDiscoveryList; import ch.ethz.seb.sebserver.gui.content.QuizDiscoveryList;
import ch.ethz.seb.sebserver.gui.content.SebClientConfigForm; import ch.ethz.seb.sebserver.gui.content.SebClientConfigForm;
import ch.ethz.seb.sebserver.gui.content.SebClientConfigList; import ch.ethz.seb.sebserver.gui.content.SebClientConfigList;
import ch.ethz.seb.sebserver.gui.content.SebClientLogs; import ch.ethz.seb.sebserver.gui.content.SebClientLogs;
import ch.ethz.seb.sebserver.gui.content.SebExamConfigList; import ch.ethz.seb.sebserver.gui.content.SebExamConfigList;
import ch.ethz.seb.sebserver.gui.content.SebExamConfigPropForm; import ch.ethz.seb.sebserver.gui.content.SebExamConfigPropForm;
import ch.ethz.seb.sebserver.gui.content.SebExamConfigSettingsForm; import ch.ethz.seb.sebserver.gui.content.SebExamConfigSettingsForm;
import ch.ethz.seb.sebserver.gui.content.UserAccountChangePasswordForm; import ch.ethz.seb.sebserver.gui.content.UserAccountChangePasswordForm;
import ch.ethz.seb.sebserver.gui.content.UserAccountForm; import ch.ethz.seb.sebserver.gui.content.UserAccountForm;
import ch.ethz.seb.sebserver.gui.content.UserAccountList; import ch.ethz.seb.sebserver.gui.content.UserAccountList;
import ch.ethz.seb.sebserver.gui.content.UserActivityLogs; import ch.ethz.seb.sebserver.gui.content.UserActivityLogs;
import ch.ethz.seb.sebserver.gui.content.action.ActionPane; import ch.ethz.seb.sebserver.gui.content.action.ActionPane;
import ch.ethz.seb.sebserver.gui.service.page.Activity; import ch.ethz.seb.sebserver.gui.service.page.Activity;
import ch.ethz.seb.sebserver.gui.service.page.PageStateDefinition; import ch.ethz.seb.sebserver.gui.service.page.PageStateDefinition;
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
public enum PageStateDefinitionImpl implements PageStateDefinition { public enum PageStateDefinitionImpl implements PageStateDefinition {
INSTITUTION_LIST(Type.LIST_VIEW, InstitutionList.class, ActivityDefinition.INSTITUTION), INSTITUTION_LIST(Type.LIST_VIEW, InstitutionList.class, ActivityDefinition.INSTITUTION),
INSTITUTION_VIEW(Type.FORM_VIEW, InstitutionForm.class, ActivityDefinition.INSTITUTION), INSTITUTION_VIEW(Type.FORM_VIEW, InstitutionForm.class, ActivityDefinition.INSTITUTION),
INSTITUTION_EDIT(Type.FORM_EDIT, InstitutionForm.class, ActivityDefinition.INSTITUTION), INSTITUTION_EDIT(Type.FORM_EDIT, InstitutionForm.class, ActivityDefinition.INSTITUTION),
USER_ACCOUNT_LIST(Type.LIST_VIEW, UserAccountList.class, ActivityDefinition.USER_ACCOUNT), USER_ACCOUNT_LIST(Type.LIST_VIEW, UserAccountList.class, ActivityDefinition.USER_ACCOUNT),
USER_ACCOUNT_VIEW(Type.FORM_VIEW, UserAccountForm.class, ActivityDefinition.USER_ACCOUNT), USER_ACCOUNT_VIEW(Type.FORM_VIEW, UserAccountForm.class, ActivityDefinition.USER_ACCOUNT),
USER_ACCOUNT_EDIT(Type.FORM_EDIT, UserAccountForm.class, ActivityDefinition.USER_ACCOUNT), USER_ACCOUNT_EDIT(Type.FORM_EDIT, UserAccountForm.class, ActivityDefinition.USER_ACCOUNT),
USER_ACCOUNT_PASSWORD_CHANGE(Type.FORM_EDIT, UserAccountChangePasswordForm.class, ActivityDefinition.USER_ACCOUNT), USER_ACCOUNT_PASSWORD_CHANGE(Type.FORM_EDIT, UserAccountChangePasswordForm.class, ActivityDefinition.USER_ACCOUNT),
LMS_SETUP_LIST(Type.LIST_VIEW, LmsSetupList.class, ActivityDefinition.LMS_SETUP), LMS_SETUP_LIST(Type.LIST_VIEW, LmsSetupList.class, ActivityDefinition.LMS_SETUP),
LMS_SETUP_VIEW(Type.FORM_VIEW, LmsSetupForm.class, ActivityDefinition.LMS_SETUP), LMS_SETUP_VIEW(Type.FORM_VIEW, LmsSetupForm.class, ActivityDefinition.LMS_SETUP),
LMS_SETUP_EDIT(Type.FORM_EDIT, LmsSetupForm.class, ActivityDefinition.LMS_SETUP), LMS_SETUP_EDIT(Type.FORM_EDIT, LmsSetupForm.class, ActivityDefinition.LMS_SETUP),
QUIZ_LIST(Type.LIST_VIEW, QuizDiscoveryList.class, ActivityDefinition.QUIZ_DISCOVERY), QUIZ_LIST(Type.LIST_VIEW, QuizDiscoveryList.class, ActivityDefinition.QUIZ_DISCOVERY),
EXAM_LIST(Type.LIST_VIEW, ExamList.class, ActivityDefinition.EXAM), EXAM_LIST(Type.LIST_VIEW, ExamList.class, ActivityDefinition.EXAM),
EXAM_VIEW(Type.FORM_VIEW, ExamForm.class, ActivityDefinition.EXAM), EXAM_VIEW(Type.FORM_VIEW, ExamForm.class, ActivityDefinition.EXAM),
EXAM_EDIT(Type.FORM_EDIT, ExamForm.class, ActivityDefinition.EXAM), EXAM_EDIT(Type.FORM_EDIT, ExamForm.class, ActivityDefinition.EXAM),
INDICATOR_EDIT(Type.FORM_EDIT, IndicatorForm.class, ActivityDefinition.EXAM), INDICATOR_EDIT(Type.FORM_EDIT, IndicatorForm.class, ActivityDefinition.EXAM),
SEB_CLIENT_CONFIG_LIST(Type.LIST_VIEW, SebClientConfigList.class, ActivityDefinition.SEB_CLIENT_CONFIG), SEB_CLIENT_CONFIG_LIST(Type.LIST_VIEW, SebClientConfigList.class, ActivityDefinition.SEB_CLIENT_CONFIG),
SEB_CLIENT_CONFIG_VIEW(Type.FORM_VIEW, SebClientConfigForm.class, ActivityDefinition.SEB_CLIENT_CONFIG), SEB_CLIENT_CONFIG_VIEW(Type.FORM_VIEW, SebClientConfigForm.class, ActivityDefinition.SEB_CLIENT_CONFIG),
SEB_CLIENT_CONFIG_EDIT(Type.FORM_EDIT, SebClientConfigForm.class, ActivityDefinition.SEB_CLIENT_CONFIG), SEB_CLIENT_CONFIG_EDIT(Type.FORM_EDIT, SebClientConfigForm.class, ActivityDefinition.SEB_CLIENT_CONFIG),
SEB_EXAM_CONFIG_LIST(Type.LIST_VIEW, SebExamConfigList.class, ActivityDefinition.SEB_EXAM_CONFIG), SEB_EXAM_CONFIG_LIST(Type.LIST_VIEW, SebExamConfigList.class, ActivityDefinition.SEB_EXAM_CONFIG),
SEB_EXAM_CONFIG_PROP_VIEW(Type.FORM_VIEW, SebExamConfigPropForm.class, ActivityDefinition.SEB_EXAM_CONFIG), SEB_EXAM_CONFIG_PROP_VIEW(Type.FORM_VIEW, SebExamConfigPropForm.class, ActivityDefinition.SEB_EXAM_CONFIG),
SEB_EXAM_CONFIG_PROP_EDIT(Type.FORM_EDIT, SebExamConfigPropForm.class, ActivityDefinition.SEB_EXAM_CONFIG), SEB_EXAM_CONFIG_PROP_EDIT(Type.FORM_EDIT, SebExamConfigPropForm.class, ActivityDefinition.SEB_EXAM_CONFIG),
SEB_EXAM_CONFIG_EDIT(Type.FORM_IN_TIME_EDIT, SebExamConfigSettingsForm.class, ActivityDefinition.SEB_EXAM_CONFIG), SEB_EXAM_CONFIG_EDIT(Type.FORM_IN_TIME_EDIT, SebExamConfigSettingsForm.class, ActivityDefinition.SEB_EXAM_CONFIG),
SEB_EXAM_CONFIG_VIEW(Type.FORM_VIEW, SebExamConfigSettingsForm.class, ActivityDefinition.SEB_EXAM_CONFIG), SEB_EXAM_CONFIG_VIEW(Type.FORM_VIEW, SebExamConfigSettingsForm.class, ActivityDefinition.SEB_EXAM_CONFIG),
SEB_EXAM_CONFIG_TEMPLATE_LIST(Type.LIST_VIEW, ConfigTemplateList.class, SEB_EXAM_CONFIG_TEMPLATE_LIST(Type.LIST_VIEW, ConfigTemplateList.class,
ActivityDefinition.SEB_EXAM_CONFIG_TEMPLATE), ActivityDefinition.SEB_EXAM_CONFIG_TEMPLATE),
SEB_EXAM_CONFIG_TEMPLATE_VIEW(Type.FORM_VIEW, ConfigTemplateForm.class, SEB_EXAM_CONFIG_TEMPLATE_VIEW(Type.FORM_VIEW, ConfigTemplateForm.class,
ActivityDefinition.SEB_EXAM_CONFIG_TEMPLATE), ActivityDefinition.SEB_EXAM_CONFIG_TEMPLATE),
SEB_EXAM_CONFIG_TEMPLATE_EDIT(Type.FORM_EDIT, ConfigTemplateForm.class, SEB_EXAM_CONFIG_TEMPLATE_EDIT(Type.FORM_EDIT, ConfigTemplateForm.class,
ActivityDefinition.SEB_EXAM_CONFIG_TEMPLATE), ActivityDefinition.SEB_EXAM_CONFIG_TEMPLATE),
SEB_EXAM_CONFIG_TEMPLATE_ATTRIBUTE_EDIT(
SEB_EXAM_CONFIG_TEMPLATE_ATTRIBUTE_EDIT( Type.FORM_EDIT,
Type.FORM_EDIT, ConfigTemplateAttributeForm.class,
ConfigTemplateAttributeForm.class, ActivityDefinition.SEB_EXAM_CONFIG_TEMPLATE),
ActivityDefinition.SEB_EXAM_CONFIG),
MONITORING_RUNNING_EXAM_LIST(Type.LIST_VIEW, MonitoringRunningExamList.class, ActivityDefinition.MONITORING_EXAMS),
MONITORING_RUNNING_EXAM_LIST(Type.LIST_VIEW, MonitoringRunningExamList.class, ActivityDefinition.MONITORING_EXAMS), MONITORING_RUNNING_EXAM(Type.FORM_VIEW, MonitoringRunningExam.class, ActivityDefinition.MONITORING_EXAMS),
MONITORING_RUNNING_EXAM(Type.FORM_VIEW, MonitoringRunningExam.class, ActivityDefinition.MONITORING_EXAMS), MONITORING_CLIENT_CONNECTION(Type.FORM_VIEW, MonitoringClientConnection.class, ActivityDefinition.MONITORING_EXAMS),
MONITORING_CLIENT_CONNECTION(Type.FORM_VIEW, MonitoringClientConnection.class, ActivityDefinition.MONITORING_EXAMS),
USER_ACTIVITY_LOGS(Type.LIST_VIEW, UserActivityLogs.class, ActivityDefinition.USER_ACTIVITY_LOGS),
USER_ACTIVITY_LOGS(Type.LIST_VIEW, UserActivityLogs.class, ActivityDefinition.USER_ACTIVITY_LOGS), SEB_CLIENT_LOGS(Type.LIST_VIEW, SebClientLogs.class, ActivityDefinition.SEB_CLIENT_LOGS)
SEB_CLIENT_LOGS(Type.LIST_VIEW, SebClientLogs.class, ActivityDefinition.SEB_CLIENT_LOGS)
;
;
public final Type type;
public final Type type; public final Class<? extends TemplateComposer> contentPaneComposer;
public final Class<? extends TemplateComposer> contentPaneComposer; public final Class<? extends TemplateComposer> actionPaneComposer;
public final Class<? extends TemplateComposer> actionPaneComposer; public final Activity activityAnchor;
public final Activity activityAnchor;
private PageStateDefinitionImpl(
private PageStateDefinitionImpl( final Type type,
final Type type, final Class<? extends TemplateComposer> contentPaneComposer,
final Class<? extends TemplateComposer> contentPaneComposer, final Activity activityAnchor) {
final Activity activityAnchor) {
this(type, contentPaneComposer, ActionPane.class, activityAnchor);
this(type, contentPaneComposer, ActionPane.class, activityAnchor); }
}
private PageStateDefinitionImpl(
private PageStateDefinitionImpl( final Type type,
final Type type, final Class<? extends TemplateComposer> contentPaneComposer,
final Class<? extends TemplateComposer> contentPaneComposer, final Class<? extends TemplateComposer> actionPaneComposer,
final Class<? extends TemplateComposer> actionPaneComposer, final Activity activityAnchor) {
final Activity activityAnchor) {
this.type = type;
this.type = type; this.contentPaneComposer = contentPaneComposer;
this.contentPaneComposer = contentPaneComposer; this.actionPaneComposer = actionPaneComposer;
this.actionPaneComposer = actionPaneComposer; this.activityAnchor = activityAnchor;
this.activityAnchor = activityAnchor; }
}
@Override
@Override public Type type() {
public Type type() { return this.type;
return this.type; }
}
@Override
@Override public Class<? extends TemplateComposer> contentPaneComposer() {
public Class<? extends TemplateComposer> contentPaneComposer() { return this.contentPaneComposer;
return this.contentPaneComposer; }
}
@Override
@Override public Class<? extends TemplateComposer> actionPaneComposer() {
public Class<? extends TemplateComposer> actionPaneComposer() { return this.actionPaneComposer;
return this.actionPaneComposer; }
}
@Override
@Override public Activity activityAnchor() {
public Activity activityAnchor() { return this.activityAnchor;
return this.activityAnchor; }
}
}
}

View file

@ -1,181 +1,186 @@
/* /*
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.service.i18n; package ch.ethz.seb.sebserver.gui.service.i18n;
import java.util.Collection; import java.util.Collection;
import java.util.Locale; import java.util.Locale;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import ch.ethz.seb.sebserver.gbl.util.Utils; import ch.ethz.seb.sebserver.gbl.util.Utils;
public interface I18nSupport { public interface I18nSupport {
public static final String SUPPORTED_LANGUAGES_KEY = "sebserver.gui.supported.languages"; public static final String SUPPORTED_LANGUAGES_KEY = "sebserver.gui.supported.languages";
public static final String MULTILINGUAL_KEY = "sebserver.gui.multilingual"; public static final String MULTILINGUAL_KEY = "sebserver.gui.multilingual";
public static final String FORMAL_LOCALE_KEY = "sebserver.gui.date.displayformat"; public static final String FORMAL_LOCALE_KEY = "sebserver.gui.date.displayformat";
public static final String ATTR_CURRENT_SESSION_LOCALE = "CURRENT_SESSION_LOCALE"; public static final String ATTR_CURRENT_SESSION_LOCALE = "CURRENT_SESSION_LOCALE";
/** Get all supported languages as a collection of Locale /** Get all supported languages as a collection of Locale
* *
* @return all supported languages as a collection of Locale */ * @return all supported languages as a collection of Locale */
Collection<Locale> supportedLanguages(); Collection<Locale> supportedLanguages();
/** Get the current users language based Locale (from user info language selection) /** Get the current users language based Locale (from user info language selection)
* Or the default language Locale if the user has not defined any language * Or the default language Locale if the user has not defined any language
* *
* @return the current user language Locale to use in context */ * @return the current user language Locale to use in context */
Locale getUsersLanguageLocale(); Locale getUsersLanguageLocale();
/** Get the current users format based Locale (from user info format selection) /** Get the current users format based Locale (from user info format selection)
* Or the default format Locale if the user has not defined any language * Or the default format Locale if the user has not defined any language
* *
* @return the current user format Locale to use in context */ * @return the current user format Locale to use in context */
Locale getUsersFormatLocale(); Locale getUsersFormatLocale();
/** Format a DateTime to a text format to display. /** Format a DateTime to a text format to display.
* This uses the date-format defined by either the attribute 'sebserver.gui.date.displayformat' * This uses the date-format defined by either the attribute 'sebserver.gui.date.displayformat'
* or the Constants.DEFAULT_DISPLAY_DATE_FORMAT * or the Constants.DEFAULT_DISPLAY_DATE_FORMAT
* *
* Adds time-zone offset information if the currents user time-zone is different form UTC * Adds time-zone offset information if the currents user time-zone is different form UTC
* *
* @param date the DateTime instance * @param date the DateTime instance
* @return date formatted date String to display */ * @return date formatted date String to display */
String formatDisplayDate(DateTime date); String formatDisplayDate(DateTime date);
/** Format a DateTime to a text format to display with additional time zone name at the end. /** Format a DateTime to a text format to display with additional time zone name at the end.
* This uses the date-format defined by either the attribute 'sebserver.gui.date.displayformat' * This uses the date-format defined by either the attribute 'sebserver.gui.date.displayformat'
* or the Constants.DEFAULT_DISPLAY_DATE_FORMAT * or the Constants.DEFAULT_DISPLAY_DATE_FORMAT
* *
* Adds time-zone offset information if the currents user time-zone is different form UTC * Adds time-zone offset information if the currents user time-zone is different form UTC
* *
* @param date the DateTime instance * @param date the DateTime instance
* @return date formatted date String to display */ * @return date formatted date String to display */
default String formatDisplayDateWithTimeZone(final DateTime date) { default String formatDisplayDateWithTimeZone(final DateTime date) {
return formatDisplayDateTime(date) + " " + this.getUsersTimeZoneTitleSuffix(); return formatDisplayDateTime(date) + " " + this.getUsersTimeZoneTitleSuffix();
} }
/** Format a time-stamp (milliseconds) to a text format to display. /** Format a time-stamp (milliseconds) to a text format to display.
* This uses the date-format defined by either the attribute 'sebserver.gui.date.displayformat' * This uses the date-format defined by either the attribute 'sebserver.gui.date.displayformat'
* or the Constants.DEFAULT_DISPLAY_DATE_FORMAT * or the Constants.DEFAULT_DISPLAY_DATE_FORMAT
* *
* Adds time-zone information if the currents user time-zone is different form UTC * Adds time-zone information if the currents user time-zone is different form UTC
* *
* @param date the DateTime instance * @param date the DateTime instance
* @return date formatted date String to display */ * @return date formatted date String to display */
default String formatDisplayDate(final Long timestamp) { default String formatDisplayDate(final Long timestamp) {
return formatDisplayDate(Utils.toDateTimeUTC(timestamp)); return formatDisplayDate(Utils.toDateTimeUTC(timestamp));
} }
/** Format a DateTime to a text format to display. /** Format a DateTime to a text format to display.
* This uses the date-format defined by either the attribute 'sebserver.gui.datetime.displayformat' * This uses the date-format defined by either the attribute 'sebserver.gui.datetime.displayformat'
* or the Constants.DEFAULT_DISPLAY_DATE_TIME_FORMAT * or the Constants.DEFAULT_DISPLAY_DATE_TIME_FORMAT
* *
* Adds time-zone information if the currents user time-zone is different form UTC * Adds time-zone information if the currents user time-zone is different form UTC
* *
* @param date the DateTime instance * @param date the DateTime instance
* @return date formatted date time String to display */ * @return date formatted date time String to display */
String formatDisplayDateTime(DateTime date); String formatDisplayDateTime(DateTime date);
/** Format a time-stamp (milliseconds) to a text format to display. /** Format a time-stamp (milliseconds) to a text format to display.
* This uses the date-format defined by either the attribute 'sebserver.gui.datetime.displayformat' * This uses the date-format defined by either the attribute 'sebserver.gui.datetime.displayformat'
* or the Constants.DEFAULT_DISPLAY_DATE_TIME_FORMAT * or the Constants.DEFAULT_DISPLAY_DATE_TIME_FORMAT
* *
* Adds time-zone information if the currents user time-zone is different form UTC * Adds time-zone information if the currents user time-zone is different form UTC
* *
* @param date the DateTime instance * @param date the DateTime instance
* @return date formatted date time String to display */ * @return date formatted date time String to display */
default String formatDisplayDateTime(final Long timestamp) { default String formatDisplayDateTime(final Long timestamp) {
return formatDisplayDateTime(Utils.toDateTimeUTC(timestamp)); return formatDisplayDateTime(Utils.toDateTimeUTC(timestamp));
} }
/** Format a DateTime to a text format to display. /** Format a DateTime to a text format to display.
* This uses the date-format defined by either the attribute 'sebserver.gui.time.displayformat' * This uses the date-format defined by either the attribute 'sebserver.gui.time.displayformat'
* or the Constants.DEFAULT_DISPLAY_TIME_FORMAT * or the Constants.DEFAULT_DISPLAY_TIME_FORMAT
* *
* Adds time-zone information if the currents user time-zone is different form UTC * Adds time-zone information if the currents user time-zone is different form UTC
* *
* @param date the DateTime instance * @param date the DateTime instance
* @return date formatted time String to display */ * @return date formatted time String to display */
String formatDisplayTime(DateTime date); String formatDisplayTime(DateTime date);
/** Format a time-stamp (milliseconds) to a text format to display. /** Format a time-stamp (milliseconds) to a text format to display.
* This uses the date-format defined by either the attribute 'sebserver.gui.time.displayformat' * This uses the date-format defined by either the attribute 'sebserver.gui.time.displayformat'
* or the Constants.DEFAULT_DISPLAY_TIME_FORMAT * or the Constants.DEFAULT_DISPLAY_TIME_FORMAT
* *
* Adds time-zone information if the currents user time-zone is different form UTC * Adds time-zone information if the currents user time-zone is different form UTC
* *
* @param date the DateTime instance * @param date the DateTime instance
* @return date formatted time String to display */ * @return date formatted time String to display */
default String formatDisplayTime(final Long timestamp) { default String formatDisplayTime(final Long timestamp) {
return formatDisplayTime(Utils.toDateTimeUTC(timestamp)); return formatDisplayTime(Utils.toDateTimeUTC(timestamp));
} }
/** If the current user has another time zone then UTC this will return a tile suffix that describes /** If the current user has another time zone then UTC this will return a tile suffix that describes
* a date/time column title with adding (UTC|{usersTimeZone}) that can be added to the title. * a date/time column title with adding (UTC|{usersTimeZone}) that can be added to the title.
* *
* @return date/time column title suffix for current user */ * @return date/time column title suffix for current user */
String getUsersTimeZoneTitleSuffix(); String getUsersTimeZoneTitleSuffix();
/** Get localized text of specified key for currently set Locale. /** Get localized text of specified key for currently set Locale.
* *
* @param key LocTextKey instance * @param key LocTextKey instance
* @param def default text * @param def default text
* @return the text in current language parsed from localized text */ * @return the text in current language parsed from localized text */
default String getText(final LocTextKey key, final String def) { default String getText(final LocTextKey key, final String def) {
return getText(key.name, def, key.args); return getText(key.name, def, key.args);
} }
/** Get localized text of specified key for currently set Locale. /** Get localized text of specified key for currently set Locale.
* *
* @param key LocTextKey instance * @param key LocTextKey instance
* @return the text in current language parsed from localized text */ * @return the text in current language parsed from localized text */
default String getText(final LocTextKey key) { default String getText(final LocTextKey key) {
return getText(key.name, key.name, key.args); return getText(key.name, key.name, key.args);
} }
/** Get localized text of specified key for currently set Locale. /** Get localized text of specified key for currently set Locale.
* *
* @param key the key name of localized text * @param key the key name of localized text
* @param args additional arguments to parse the localized text * @param args additional arguments to parse the localized text
* @return the text in current language parsed from localized text */ * @return the text in current language parsed from localized text */
default String getText(final String key, final Object... args) { default String getText(final String key, final Object... args) {
return getText(key, key, args); return getText(key, key, args);
} }
/** Get localized text of specified key for currently set Locale. /** Get localized text of specified key for currently set Locale.
* *
* @param key the key name of localized text * @param key the key name of localized text
* @param def default text that is returned if no localized test with specified key was found * @param def default text that is returned if no localized test with specified key was found
* @param args additional arguments to parse the localized text * @param args additional arguments to parse the localized text
* @return the text in current language parsed from localized text */ * @return the text in current language parsed from localized text */
String getText(final String key, String def, Object... args); String getText(final String key, String def, Object... args);
/** Get localized text of specified key and Locale. /** Get localized text of specified key and Locale.
* *
* @param key the key name of localized text * @param key the key name of localized text
* @param locale the Locale * @param locale the Locale
* @param args additional arguments to parse the localized text * @param args additional arguments to parse the localized text
* @return the text in current language parsed from localized text */ * @return the text in current language parsed from localized text */
default String getText(final String key, final Locale locale, final Object... args) { default String getText(final String key, final Locale locale, final Object... args) {
return getText(key, locale, key, args); return getText(key, locale, key, args);
} }
/** Get localized text of specified key and Locale. /** Get localized text of specified key and Locale.
* *
* @param key the key name of localized text * @param key the key name of localized text
* @param locale the Locale * @param locale the Locale
* @param def default text that is returned if no localized test with specified key was found * @param def default text that is returned if no localized test with specified key was found
* @param args additional arguments to parse the localized text * @param args additional arguments to parse the localized text
* @return the text in current language parsed from localized text */ * @return the text in current language parsed from localized text */
String getText(String key, Locale locale, String def, Object... args); String getText(String key, Locale locale, String def, Object... args);
boolean hasText(LocTextKey locTextKey); /** Indicates if there is a localized text defined for a specified LocTextKey
*
} * @param locTextKey the LocTextKey instance
* @return true if there is a localized text defined for a specified LocTextKey, false otherwise
*/
boolean hasText(LocTextKey locTextKey);
}

View file

@ -1,296 +1,294 @@
/* /*
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.service.i18n.impl; package ch.ethz.seb.sebserver.gui.service.i18n.impl;
import java.util.Locale; import java.util.Locale;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.eclipse.rap.rwt.RWT; import org.eclipse.rap.rwt.RWT;
import org.eclipse.swt.SWT; import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.TabFolder; import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem; import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem; import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem; import org.eclipse.swt.widgets.TreeItem;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gbl.util.Utils; import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport; 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.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService; import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
import ch.ethz.seb.sebserver.gui.service.page.ComposerService; import ch.ethz.seb.sebserver.gui.service.page.ComposerService;
import ch.ethz.seb.sebserver.gui.service.page.PageContext; import ch.ethz.seb.sebserver.gui.service.page.PageContext;
import ch.ethz.seb.sebserver.gui.widget.ImageUploadSelection; import ch.ethz.seb.sebserver.gui.widget.ImageUploadSelection;
/** Service that supports page language change on the fly */ /** Service that supports page language change on the fly */
@Lazy @Lazy
@Service @Service
@GuiProfile @GuiProfile
public final class PolyglotPageServiceImpl implements PolyglotPageService { public final class PolyglotPageServiceImpl implements PolyglotPageService {
private final I18nSupport i18nSupport; private final I18nSupport i18nSupport;
public PolyglotPageServiceImpl(final I18nSupport i18nSupport) { public PolyglotPageServiceImpl(final I18nSupport i18nSupport) {
this.i18nSupport = i18nSupport; this.i18nSupport = i18nSupport;
} }
@Override @Override
public I18nSupport getI18nSupport() { public I18nSupport getI18nSupport() {
return this.i18nSupport; return this.i18nSupport;
} }
@Override @Override
public void setDefaultPageLocale(final Composite root) { public void setDefaultPageLocale(final Composite root) {
setPageLocale(root, this.i18nSupport.getUsersLanguageLocale()); setPageLocale(root, this.i18nSupport.getUsersLanguageLocale());
} }
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void setPageLocale(final Composite root, final Locale locale) { public void setPageLocale(final Composite root, final Locale locale) {
RWT.getUISession() RWT.getUISession()
.getHttpSession() .getHttpSession()
.setAttribute(I18nSupport.ATTR_CURRENT_SESSION_LOCALE, locale); .setAttribute(I18nSupport.ATTR_CURRENT_SESSION_LOCALE, locale);
ComposerService.traversePageTree( ComposerService.traversePageTree(
root, root,
comp -> comp.getData(POLYGLOT_WIDGET_FUNCTION_KEY) != null, comp -> comp.getData(POLYGLOT_WIDGET_FUNCTION_KEY) != null,
comp -> ((Consumer<Control>) comp.getData(POLYGLOT_WIDGET_FUNCTION_KEY)).accept(comp)); comp -> ((Consumer<Control>) comp.getData(POLYGLOT_WIDGET_FUNCTION_KEY)).accept(comp));
root.layout(true, true); root.layout(true, true);
} }
@Override @Override
public void injectI18n(final ImageUploadSelection imageUpload, final LocTextKey locTextKey) { public void injectI18n(final ImageUploadSelection imageUpload, final LocTextKey locTextKey) {
final Consumer<ImageUploadSelection> imageUploadFunction = iu -> { final Consumer<ImageUploadSelection> imageUploadFunction = iu -> {
if (locTextKey != null) { if (locTextKey != null) {
iu.setSelectionText(this.i18nSupport.getText(locTextKey)); iu.setSelectionText(this.i18nSupport.getText(locTextKey));
} }
}; };
imageUpload.setData(POLYGLOT_WIDGET_FUNCTION_KEY, imageUploadFunction); imageUpload.setData(POLYGLOT_WIDGET_FUNCTION_KEY, imageUploadFunction);
imageUploadFunction.accept(imageUpload); imageUploadFunction.accept(imageUpload);
} }
@Override @Override
public void injectI18n(final Label label, final LocTextKey locTextKey) { public void injectI18n(final Label label, final LocTextKey locTextKey) {
injectI18n(label, locTextKey, null); injectI18n(label, locTextKey, null);
} }
@Override @Override
public void injectI18n(final Label label, final LocTextKey locTextKey, final LocTextKey locToolTipKey) { public void injectI18n(final Label label, final LocTextKey locTextKey, final LocTextKey locToolTipKey) {
final Consumer<Label> labelFunction = labelFunction(locTextKey, locToolTipKey, this.i18nSupport); final Consumer<Label> labelFunction = labelFunction(locTextKey, locToolTipKey, this.i18nSupport);
label.setData(POLYGLOT_WIDGET_FUNCTION_KEY, labelFunction); label.setData(POLYGLOT_WIDGET_FUNCTION_KEY, labelFunction);
labelFunction.accept(label); labelFunction.accept(label);
} }
@Override @Override
public void injectI18n(final Group group, final LocTextKey locTextKey, final LocTextKey locTooltipKey) { public void injectI18n(final Group group, final LocTextKey locTextKey, final LocTextKey locTooltipKey) {
final Consumer<Group> groupFunction = groupFunction(locTextKey, locTooltipKey, this.i18nSupport); final Consumer<Group> groupFunction = groupFunction(locTextKey, locTooltipKey, this.i18nSupport);
group.setData(POLYGLOT_WIDGET_FUNCTION_KEY, groupFunction); group.setData(POLYGLOT_WIDGET_FUNCTION_KEY, groupFunction);
groupFunction.accept(group); groupFunction.accept(group);
} }
@Override @Override
public void injectI18n(final Button button, final LocTextKey locTextKey) { public void injectI18n(final Button button, final LocTextKey locTextKey) {
injectI18n(button, locTextKey, null); injectI18n(button, locTextKey, null);
} }
@Override @Override
public void injectI18n(final Button button, final LocTextKey locTextKey, final LocTextKey locToolTipKey) { public void injectI18n(final Button button, final LocTextKey locTextKey, final LocTextKey locToolTipKey) {
final Consumer<Button> buttonFunction = b -> { final Consumer<Button> buttonFunction = b -> {
if (locTextKey != null) { if (locTextKey != null) {
b.setText(this.i18nSupport.getText(locTextKey)); b.setText(this.i18nSupport.getText(locTextKey));
} }
if (locToolTipKey != null) { if (i18nSupport.hasText(locToolTipKey)) {
b.setToolTipText(Utils.formatLineBreaks(this.i18nSupport.getText(locToolTipKey))); b.setToolTipText(Utils.formatLineBreaks(this.i18nSupport.getText(locToolTipKey)));
} }
}; };
button.setData(POLYGLOT_WIDGET_FUNCTION_KEY, buttonFunction); button.setData(POLYGLOT_WIDGET_FUNCTION_KEY, buttonFunction);
buttonFunction.accept(button); buttonFunction.accept(button);
} }
@Override @Override
public void injectI18n(final Tree tree) { public void injectI18n(final Tree tree) {
tree.setData( tree.setData(
POLYGLOT_WIDGET_FUNCTION_KEY, POLYGLOT_WIDGET_FUNCTION_KEY,
(Consumer<Tree>) t -> updateLocale(t.getItems(), this.i18nSupport)); (Consumer<Tree>) t -> updateLocale(t.getItems(), this.i18nSupport));
} }
@Override @Override
public void injectI18n(final TreeItem treeItem, final LocTextKey locTextKey) { public void injectI18n(final TreeItem treeItem, final LocTextKey locTextKey) {
treeItem.setData(POLYGLOT_ITEM_TEXT_DATA_KEY, locTextKey); treeItem.setData(POLYGLOT_ITEM_TEXT_DATA_KEY, locTextKey);
treeItem.setText(this.i18nSupport.getText(locTextKey)); treeItem.setText(this.i18nSupport.getText(locTextKey));
} }
@Override @Override
public void injectI18n(final Table table) { public void injectI18n(final Table table) {
table.setData( table.setData(
POLYGLOT_WIDGET_FUNCTION_KEY, POLYGLOT_WIDGET_FUNCTION_KEY,
(Consumer<Table>) t -> { (Consumer<Table>) t -> {
updateLocale(t.getColumns(), this.i18nSupport); updateLocale(t.getColumns(), this.i18nSupport);
updateLocale(t.getItems(), this.i18nSupport); updateLocale(t.getItems(), this.i18nSupport);
}); });
} }
@Override @Override
public void injectI18n(final TabFolder tabFolder) { public void injectI18n(final TabFolder tabFolder) {
tabFolder.setData( tabFolder.setData(
POLYGLOT_WIDGET_FUNCTION_KEY, POLYGLOT_WIDGET_FUNCTION_KEY,
(Consumer<TabFolder>) t -> updateLocale(t.getItems(), this.i18nSupport)); (Consumer<TabFolder>) t -> updateLocale(t.getItems(), this.i18nSupport));
} }
@Override @Override
public void injectI18n(final TableColumn tableColumn, final LocTextKey locTextKey, final LocTextKey locTooltipKey) { public void injectI18n(final TableColumn tableColumn, final LocTextKey locTextKey, final LocTextKey locTooltipKey) {
tableColumn.setData(POLYGLOT_ITEM_TEXT_DATA_KEY, locTextKey); tableColumn.setData(POLYGLOT_ITEM_TEXT_DATA_KEY, locTextKey);
tableColumn.setText(this.i18nSupport.getText(locTextKey)); tableColumn.setText(this.i18nSupport.getText(locTextKey));
if (this.i18nSupport.hasText(locTooltipKey)) { if (this.i18nSupport.hasText(locTooltipKey)) {
tableColumn.setData(POLYGLOT_ITEM_TOOLTIP_DATA_KEY, locTooltipKey); tableColumn.setData(POLYGLOT_ITEM_TOOLTIP_DATA_KEY, locTooltipKey);
tableColumn.setToolTipText(Utils.formatLineBreaks(this.i18nSupport.getText(locTooltipKey))); tableColumn.setToolTipText(Utils.formatLineBreaks(this.i18nSupport.getText(locTooltipKey)));
} }
} }
@Override @Override
public void injectI18n(final TableItem tableItem, final LocTextKey... locTextKey) { public void injectI18n(final TableItem tableItem, final LocTextKey... locTextKey) {
if (locTextKey == null) { if (locTextKey == null) {
return; return;
} }
tableItem.setData(POLYGLOT_ITEM_TEXT_DATA_KEY, locTextKey); tableItem.setData(POLYGLOT_ITEM_TEXT_DATA_KEY, locTextKey);
for (int i = 0; i < locTextKey.length; i++) { for (int i = 0; i < locTextKey.length; i++) {
tableItem.setText(i, this.i18nSupport.getText(locTextKey[i])); tableItem.setText(i, this.i18nSupport.getText(locTextKey[i]));
} }
} }
@Override @Override
public void injectI18n(final TabItem tabItem, final LocTextKey locTextKey, final LocTextKey locTooltipKey) { public void injectI18n(final TabItem tabItem, final LocTextKey locTextKey, final LocTextKey locTooltipKey) {
tabItem.setData(POLYGLOT_ITEM_TEXT_DATA_KEY, locTextKey); tabItem.setData(POLYGLOT_ITEM_TEXT_DATA_KEY, locTextKey);
tabItem.setText(this.i18nSupport.getText(locTextKey)); tabItem.setText(this.i18nSupport.getText(locTextKey));
if (this.i18nSupport.hasText(locTooltipKey)) { if (this.i18nSupport.hasText(locTooltipKey)) {
tabItem.setData(POLYGLOT_ITEM_TOOLTIP_DATA_KEY, locTooltipKey); tabItem.setData(POLYGLOT_ITEM_TOOLTIP_DATA_KEY, locTooltipKey);
tabItem.setToolTipText(Utils.formatLineBreaks(this.i18nSupport.getText(locTooltipKey))); tabItem.setToolTipText(Utils.formatLineBreaks(this.i18nSupport.getText(locTooltipKey)));
} }
} }
@Override @Override
public void createLanguageSelector(final PageContext composerCtx) { public void createLanguageSelector(final PageContext composerCtx) {
for (final Locale locale : this.i18nSupport.supportedLanguages()) { for (final Locale locale : this.i18nSupport.supportedLanguages()) {
final Label languageSelection = new Label(composerCtx.getParent(), SWT.NONE); final Label languageSelection = new Label(composerCtx.getParent(), SWT.NONE);
languageSelection.setData( languageSelection.setData(
POLYGLOT_WIDGET_FUNCTION_KEY, POLYGLOT_WIDGET_FUNCTION_KEY,
(Consumer<Label>) label -> label.setVisible( (Consumer<Label>) label -> label.setVisible(
!this.i18nSupport.getUsersLanguageLocale() !this.i18nSupport.getUsersLanguageLocale()
.getLanguage() .getLanguage()
.equals(locale.getLanguage()))); .equals(locale.getLanguage())));
languageSelection.setData(RWT.CUSTOM_VARIANT, "header"); languageSelection.setData(RWT.CUSTOM_VARIANT, "header");
languageSelection.setText("| " + locale.getLanguage().toUpperCase(locale)); languageSelection.setText("| " + locale.getLanguage().toUpperCase(locale));
languageSelection.addListener(SWT.MouseDown, event -> { languageSelection.addListener(SWT.MouseDown, event -> this.setPageLocale(composerCtx.getRoot(), locale));
this.setPageLocale(composerCtx.getRoot(), locale); }
}); }
}
} private static Consumer<Label> labelFunction(
final LocTextKey locTextKey,
private static final Consumer<Label> labelFunction( final LocTextKey locToolTipKey,
final LocTextKey locTextKey, final I18nSupport i18nSupport) {
final LocTextKey locToolTipKey,
final I18nSupport i18nSupport) { return label -> {
if (locTextKey != null) {
return label -> { label.setText(i18nSupport.getText(locTextKey));
if (locTextKey != null) { }
label.setText(i18nSupport.getText(locTextKey)); if (i18nSupport.hasText(locToolTipKey)) {
} label.setToolTipText(Utils.formatLineBreaks(i18nSupport.getText(locToolTipKey)));
if (locToolTipKey != null) { }
label.setToolTipText(Utils.formatLineBreaks(i18nSupport.getText(locToolTipKey))); };
} }
};
} private static Consumer<Group> groupFunction(
final LocTextKey locTextKey,
private static final Consumer<Group> groupFunction( final LocTextKey locToolTipKey,
final LocTextKey locTextKey, final I18nSupport i18nSupport) {
final LocTextKey locToolTipKey,
final I18nSupport i18nSupport) { return group -> {
if (locTextKey != null) {
return group -> { group.setText(i18nSupport.getText(locTextKey));
if (locTextKey != null) { }
group.setText(i18nSupport.getText(locTextKey)); if (i18nSupport.hasText(locToolTipKey)) {
} group.setToolTipText(Utils.formatLineBreaks(i18nSupport.getText(locToolTipKey, StringUtils.EMPTY)));
if (locToolTipKey != null) { }
group.setToolTipText(Utils.formatLineBreaks(i18nSupport.getText(locToolTipKey, StringUtils.EMPTY))); };
} }
};
} private static void updateLocale(final TabItem[] items, final I18nSupport i18nSupport) {
if (items == null) {
private static final void updateLocale(final TabItem[] items, final I18nSupport i18nSupport) { return;
if (items == null) { }
return;
} for (final TabItem childItem : items) {
final LocTextKey locTextKey = (LocTextKey) childItem.getData(POLYGLOT_ITEM_TEXT_DATA_KEY);
for (final TabItem childItem : items) { if (locTextKey != null) {
final LocTextKey locTextKey = (LocTextKey) childItem.getData(POLYGLOT_ITEM_TEXT_DATA_KEY); childItem.setText(i18nSupport.getText(locTextKey));
if (locTextKey != null) { }
childItem.setText(i18nSupport.getText(locTextKey)); }
} }
}
} private static void updateLocale(final TreeItem[] items, final I18nSupport i18nSupport) {
if (items == null) {
private static final void updateLocale(final TreeItem[] items, final I18nSupport i18nSupport) { return;
if (items == null) { }
return;
} for (final TreeItem childItem : items) {
final LocTextKey locTextKey = (LocTextKey) childItem.getData(POLYGLOT_ITEM_TEXT_DATA_KEY);
for (final TreeItem childItem : items) { if (locTextKey != null) {
final LocTextKey locTextKey = (LocTextKey) childItem.getData(POLYGLOT_ITEM_TEXT_DATA_KEY); childItem.setText(i18nSupport.getText(locTextKey));
if (locTextKey != null) { }
childItem.setText(i18nSupport.getText(locTextKey)); updateLocale(childItem.getItems(), i18nSupport);
} }
updateLocale(childItem.getItems(), i18nSupport); }
}
} private static void updateLocale(final TableItem[] items, final I18nSupport i18nSupport) {
if (items == null) {
private static void updateLocale(final TableItem[] items, final I18nSupport i18nSupport) { return;
if (items == null) { }
return;
} for (final TableItem childItem : items) {
final LocTextKey[] locTextKey = (LocTextKey[]) childItem.getData(POLYGLOT_ITEM_TEXT_DATA_KEY);
for (final TableItem childItem : items) { if (locTextKey != null) {
final LocTextKey[] locTextKey = (LocTextKey[]) childItem.getData(POLYGLOT_ITEM_TEXT_DATA_KEY); for (int i = 0; i < locTextKey.length; i++) {
if (locTextKey != null) { if (locTextKey[i] != null) {
for (int i = 0; i < locTextKey.length; i++) { childItem.setText(i, i18nSupport.getText(locTextKey[i]));
if (locTextKey[i] != null) { }
childItem.setText(i, i18nSupport.getText(locTextKey[i])); }
} }
} }
} }
}
} private static void updateLocale(final TableColumn[] columns, final I18nSupport i18nSupport) {
if (columns == null) {
private static void updateLocale(final TableColumn[] columns, final I18nSupport i18nSupport) { return;
if (columns == null) { }
return;
} for (final TableColumn childItem : columns) {
final LocTextKey locTextKey = (LocTextKey) childItem.getData(POLYGLOT_ITEM_TEXT_DATA_KEY);
for (final TableColumn childItem : columns) { if (locTextKey != null) {
final LocTextKey locTextKey = (LocTextKey) childItem.getData(POLYGLOT_ITEM_TEXT_DATA_KEY); childItem.setText(i18nSupport.getText(locTextKey));
if (locTextKey != null) { }
childItem.setText(i18nSupport.getText(locTextKey)); }
} }
}
} }
}

View file

@ -1,134 +1,141 @@
/* /*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
* *
* This Source Code Form is subject to the terms of the Mozilla Public * 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 * 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/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.gui.widget; package ch.ethz.seb.sebserver.gui.widget;
import java.util.Arrays; import java.util.Arrays;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils; import ch.ethz.seb.sebserver.gbl.util.Tuple3;
import org.eclipse.swt.SWT; import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
import org.eclipse.swt.layout.GridData; import org.apache.commons.lang3.StringUtils;
import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Button; import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import ch.ethz.seb.sebserver.gbl.Constants; import org.eclipse.swt.widgets.Listener;
import ch.ethz.seb.sebserver.gbl.util.Tuple;
import ch.ethz.seb.sebserver.gbl.util.Utils; import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gui.service.page.PageService; import ch.ethz.seb.sebserver.gbl.util.Tuple;
import ch.ethz.seb.sebserver.gbl.util.Utils;
public final class MultiSelectionCheckbox extends Composite implements Selection { import ch.ethz.seb.sebserver.gui.service.page.PageService;
private static final long serialVersionUID = -8507565817745610126L; public final class MultiSelectionCheckbox extends Composite implements Selection {
private Listener listener = null; private static final long serialVersionUID = -8507565817745610126L;
private final Map<String, Button> checkboxes;
private Listener listener = null;
MultiSelectionCheckbox(final Composite parent) { private final Map<String, Button> checkboxes;
super(parent, SWT.NONE);
final GridLayout gridLayout = new GridLayout(1, true); MultiSelectionCheckbox(final Composite parent) {
gridLayout.verticalSpacing = 1; super(parent, SWT.NONE);
gridLayout.marginLeft = 0; final GridLayout gridLayout = new GridLayout(1, true);
gridLayout.marginHeight = 0; gridLayout.verticalSpacing = 1;
gridLayout.marginWidth = 0; gridLayout.marginLeft = 0;
setLayout(gridLayout); gridLayout.marginHeight = 0;
gridLayout.marginWidth = 0;
this.checkboxes = new LinkedHashMap<>(); setLayout(gridLayout);
}
this.checkboxes = new LinkedHashMap<>();
@Override }
public Type type() {
return Type.MULTI_CHECKBOX; @Override
} public Type type() {
return Type.MULTI_CHECKBOX;
@Override }
public void applyNewMapping(final List<Tuple<String>> mapping) {
final String selectionValue = getSelectionValue(); @Override
this.checkboxes.clear(); public void applyNewMapping(final List<Tuple<String>> mapping) {
PageService.clearComposite(this); final String selectionValue = getSelectionValue();
this.checkboxes.clear();
for (final Tuple<String> tuple : mapping) { PageService.clearComposite(this);
final Button button = new Button(this, SWT.CHECK);
button.setText(tuple._2); for (final Tuple<String> tuple : mapping) {
final GridData gridData = new GridData(SWT.FILL, SWT.CENTER, true, true); final Button button = new Button(this, SWT.CHECK);
button.setLayoutData(gridData); button.setText(tuple._2);
button.setData(OPTION_VALUE, tuple._1); final GridData gridData = new GridData(SWT.FILL, SWT.CENTER, true, true);
button.addListener(SWT.Selection, event -> { button.setLayoutData(gridData);
if (this.listener != null) { button.setData(OPTION_VALUE, tuple._1);
this.listener.handleEvent(event); button.addListener(SWT.Selection, event -> {
} if (this.listener != null) {
}); this.listener.handleEvent(event);
this.checkboxes.put(tuple._1, button); }
} });
this.checkboxes.put(tuple._1, button);
if (StringUtils.isNotBlank(selectionValue)) {
select(selectionValue); Tuple3<String> tuple3 = tuple.adaptTo(Tuple3.class);
} if (tuple3 != null && StringUtils.isNotBlank(tuple3._3)) {
} button.setToolTipText(tuple3._3);
}
@Override }
public void applyToolTipsForItems(final List<Tuple<String>> mapping) {
mapping if (StringUtils.isNotBlank(selectionValue)) {
.stream() select(selectionValue);
.filter(tuple -> StringUtils.isNotBlank(tuple._2)) }
.forEach(tuple -> { }
final Button button = this.checkboxes.get(tuple._1);
if (button != null) { @Override
button.setToolTipText(Utils.formatLineBreaks(tuple._2)); public void applyToolTipsForItems(final List<Tuple<String>> mapping) {
} mapping
}); .stream()
} .filter(tuple -> StringUtils.isNotBlank(tuple._2))
.forEach(tuple -> {
@Override final Button button = this.checkboxes.get(tuple._1);
public void select(final String keys) { if (button != null) {
clear(); button.setToolTipText(Utils.formatLineBreaks(tuple._2));
if (StringUtils.isBlank(keys)) { }
return; });
} }
Arrays.asList(StringUtils.split(keys, Constants.LIST_SEPARATOR)) @Override
.stream() public void select(final String keys) {
.forEach(key -> { clear();
final Button button = this.checkboxes.get(key); if (StringUtils.isBlank(keys)) {
if (button != null) { return;
button.setSelection(true); }
}
}); Arrays.asList(StringUtils.split(keys, Constants.LIST_SEPARATOR))
} .stream()
.forEach(key -> {
@Override final Button button = this.checkboxes.get(key);
public String getSelectionValue() { if (button != null) {
return StringUtils.joinWith( button.setSelection(true);
Constants.LIST_SEPARATOR, }
this.checkboxes });
.values() }
.stream()
.filter(button -> button.getSelection()) @Override
.map(button -> (String) button.getData(OPTION_VALUE)) public String getSelectionValue() {
.collect(Collectors.toList()).toArray()); return StringUtils.joinWith(
} Constants.LIST_SEPARATOR,
this.checkboxes
@Override .values()
public void clear() { .stream()
this.checkboxes .filter(button -> button.getSelection())
.values() .map(button -> (String) button.getData(OPTION_VALUE))
.stream() .collect(Collectors.toList()).toArray());
.forEach(button -> button.setSelection(false)); }
}
@Override
@Override public void clear() {
public void setSelectionListener(final Listener listener) { this.checkboxes
this.listener = listener; .values()
} .stream()
.forEach(button -> button.setSelection(false));
} }
@Override
public void setSelectionListener(final Listener listener) {
this.listener = listener;
}
}

View file

@ -59,6 +59,8 @@ sebserver.overall.types.entityType.INSTITUTION=Institution
sebserver.overall.types.entityType.SEB_CLIENT_CONFIGURATION=Client Configuration sebserver.overall.types.entityType.SEB_CLIENT_CONFIGURATION=Client Configuration
sebserver.overall.types.entityType.LMS_SETUP=LMS Setup sebserver.overall.types.entityType.LMS_SETUP=LMS Setup
sebserver.overall.types.entityType.USER=User Account sebserver.overall.types.entityType.USER=User Account
sebserver.overall.types.entityType.CLIENT_INSTRUCTION=SEB Client Instruction
sebserver.overall.types.entityType.EXAM_SEB_RESTRICTION=SEB Exam Restriction
sebserver.overall.activity.title.serveradmin=SEB Server Administration sebserver.overall.activity.title.serveradmin=SEB Server Administration
sebserver.overall.activity.title.sebconfig=SEB Configuration sebserver.overall.activity.title.sebconfig=SEB Configuration
@ -174,18 +176,27 @@ sebserver.institution.form.logoImage.unsupportedFileType=The selected file is no
sebserver.useraccount.list.actions= sebserver.useraccount.list.actions=
sebserver.useraccount.role.SEB_SERVER_ADMIN=SEB Server Administrator sebserver.useraccount.role.SEB_SERVER_ADMIN=SEB Server Administrator
sebserver.useraccount.role.SEB_SERVER_ADMIN.tooltip=A SEB server administrator has overall read privileges</br>and is able to create new institutions and user accounts
sebserver.useraccount.role.INSTITUTIONAL_ADMIN=Institutional Administrator sebserver.useraccount.role.INSTITUTIONAL_ADMIN=Institutional Administrator
sebserver.useraccount.role.INSTITUTIONAL_ADMIN.tooltip=An institutional administrator has overall read privileges on the assigned institution</br>and is able to edit the institution and create new user accounts for the institution.</br>Furthermore an institutional administrator is able to create new LMS bindings and SEB client configurations for the institution.
sebserver.useraccount.role.EXAM_ADMIN=Exam Administrator sebserver.useraccount.role.EXAM_ADMIN=Exam Administrator
sebserver.useraccount.role.EXAM_ADMIN.tooltip=An exam administrator has overall read privileges for the institution but cannot see or manage other user accounts.</br>An exam administrator is able to create new SEB configurations and import and setup exams.
sebserver.useraccount.role.EXAM_SUPPORTER=Exam Supporter sebserver.useraccount.role.EXAM_SUPPORTER=Exam Supporter
sebserver.useraccount.role.EXAM_SUPPORTER.tooltip=An exam supporter can only see and edit the own user account</br> and monitor exams for that he/she was attached by an exam administrator.
sebserver.useraccount.list.empty=No user account has been found. Please adapt the filter or create a new user account sebserver.useraccount.list.empty=No user account has been found. Please adapt the filter or create a new user account
sebserver.useraccount.list.title=User Accounts sebserver.useraccount.list.title=User Accounts
sebserver.useraccount.list.column.institution=Institution sebserver.useraccount.list.column.institution=Institution
sebserver.useraccount.list.column.institution.tooltip=The institution of the user account.</br></br>Use the filter above to specify the institution.</br>{0}
sebserver.useraccount.list.column.name=First Name sebserver.useraccount.list.column.name=First Name
sebserver.useraccount.list.column.name.tooltip=The first name of the user.</br></br>Use the filter above to narrow down a specific first name.</br>{0}
sebserver.useraccount.list.column.username=User Name sebserver.useraccount.list.column.username=User Name
sebserver.useraccount.list.column.username.tooltip=The internal user name of the user.</br></br>Use the filter above to narrow down a specific user name.</br>{0}
sebserver.useraccount.list.column.email=Mail sebserver.useraccount.list.column.email=Mail
sebserver.useraccount.list.column.email.tooltip=The e-mail address of the user.</br></br>Use the filter above to narrow down a specific e-mail address.</br>{0}
sebserver.useraccount.list.column.language=Language sebserver.useraccount.list.column.language=Language
sebserver.useraccount.list.column.active=Active sebserver.useraccount.list.column.active=Active
sebserver.useraccount.list.column.active.tooltip=The activity of the user.</br></br>Use the filter above to specify the activity.</br>{0}
sebserver.useraccount.action.list=User Account sebserver.useraccount.action.list=User Account
sebserver.useraccount.action.form=User Account of {0} sebserver.useraccount.action.form=User Account of {0}
@ -206,19 +217,32 @@ sebserver.useraccount.info.notEditable=You have no edit rights for this User Acc
sebserver.useraccount.form.title=User Account sebserver.useraccount.form.title=User Account
sebserver.useraccount.form.title.new=Add User Account sebserver.useraccount.form.title.new=Add User Account
sebserver.useraccount.form.institution=Institution sebserver.useraccount.form.institution=Institution
sebserver.useraccount.form.institution.tooltip=The institution the user belongs to.
sebserver.useraccount.form.creationdate=Creation Date sebserver.useraccount.form.creationdate=Creation Date
sebserver.useraccount.form.creationdate.tooltip=The date when the user-account was first created.
sebserver.useraccount.form.name=First Name sebserver.useraccount.form.name=First Name
sebserver.useraccount.form.name.tooltip=The first name of the user.
sebserver.useraccount.form.surname=Surname sebserver.useraccount.form.surname=Surname
sebserver.useraccount.form.surname.tooltip=The last- or surname of the user.
sebserver.useraccount.form.username=Username sebserver.useraccount.form.username=Username
sebserver.useraccount.form.username.tooltip=The internal user name of the account.
sebserver.useraccount.form.mail=E-Mail sebserver.useraccount.form.mail=E-Mail
sebserver.useraccount.form.mail.tooltip=The e-mail address of the user.
sebserver.useraccount.form.language=Language sebserver.useraccount.form.language=Language
sebserver.useraccount.form.language.tooltip=The users language.
sebserver.useraccount.form.timezone=Time Zone sebserver.useraccount.form.timezone=Time Zone
sebserver.useraccount.form.timezone.tooltip=The time-zone of the user.</br></br>Note that this also defines the exact time and date that is displayed to the user.
sebserver.useraccount.form.roles=User Roles sebserver.useraccount.form.roles=User Roles
sebserver.useraccount.form.roles.tooltip=Select the roles for the user.</br>A user can have more then one role but must have at least one.</br></br>Please use the tooltip on the role name for more information about a specific role.
sebserver.useraccount.form.password=Password sebserver.useraccount.form.password=Password
sebserver.useraccount.form.password.tooltip=The password of the user account
sebserver.useraccount.form.password.confirm=Confirm Password sebserver.useraccount.form.password.confirm=Confirm Password
sebserver.useraccount.form.password.confirm.tooltip=Please confirm the password
sebserver.useraccount.form.pwchange.title=Change Password : {0} sebserver.useraccount.form.pwchange.title=Change Password : {0}
sebserver.useraccount.form.password.new=New Password sebserver.useraccount.form.password.new=New Password
sebserver.useraccount.form.password.new.tooltip=The new password for the user account
sebserver.useraccount.form.password.new.confirm=Confirm New Password sebserver.useraccount.form.password.new.confirm=Confirm New Password
sebserver.useraccount.form.password.new.confirm.tooltip=Please confirm the password
################################ ################################
# LMS Setup # LMS Setup
@ -465,19 +489,28 @@ sebserver.clientconfig.list.empty=There is currently no SEB-Client configuration
sebserver.clientconfig.list.title=SEB Client Configurations sebserver.clientconfig.list.title=SEB Client Configurations
sebserver.clientconfig.list.actions= sebserver.clientconfig.list.actions=
sebserver.clientconfig.list.column.institution=Institution sebserver.clientconfig.list.column.institution=Institution
sebserver.clientconfig.list.column.institution.tooltip=The institution of the SEB client configuration.</br></br>Use the filter above to specify the institution.</br>{0}
sebserver.clientconfig.list.column.name=Name sebserver.clientconfig.list.column.name=Name
sebserver.clientconfig.list.column.name.tooltip=The name of the SEB client configuration.</br></br>Use the filter above to narrow down a specific name.</br>{0}
sebserver.clientconfig.list.column.date=Creation Date {0} sebserver.clientconfig.list.column.date=Creation Date {0}
sebserver.clientconfig.list.column.date.tooltip=The date when the SEB client configuration was first created.</br></br>Use the filter above to specify a from-date.</br>{0}
sebserver.clientconfig.list.column.active=Active sebserver.clientconfig.list.column.active=Active
sebserver.clientconfig.list.column.active.tooltip=The activity of SEB client configuration.</br></br>Use the filter above to specify the activity.</br>{0}
sebserver.clientconfig.info.pleaseSelect=Please select first a Client Configuration from the list sebserver.clientconfig.info.pleaseSelect=Please select first a Client Configuration from the list
sebserver.clientconfig.list.action.no.modify.privilege=No Access: A SEB Client Configuration from other institution cannot be modified. sebserver.clientconfig.list.action.no.modify.privilege=No Access: A SEB Client Configuration from other institution cannot be modified.
sebserver.clientconfig.form.title.new=Add Client Configuration sebserver.clientconfig.form.title.new=Add Client Configuration
sebserver.clientconfig.form.title=SEB Client Configuration sebserver.clientconfig.form.title=SEB Client Configuration
sebserver.clientconfig.form.name=Name sebserver.clientconfig.form.name=Name
sebserver.clientconfig.form.name.tooltip=The name of the SEB Client Configuration.</br>Can be any name that not already exists for another SEB Client Configuration
sebserver.clientconfig.form.fallback-url=Fallback Start URL sebserver.clientconfig.form.fallback-url=Fallback Start URL
sebserver.clientconfig.form.fallback-url.tooltip=A fallback URL that tells the SEB where to go when the SEB Server service is unavailable.
sebserver.clientconfig.form.date=Creation Date sebserver.clientconfig.form.date=Creation Date
sebserver.clientconfig.form.date.tooltip=The date when the SEB client configuration was first created.
sebserver.clientconfig.form.encryptSecret=Configuration Password sebserver.clientconfig.form.encryptSecret=Configuration Password
sebserver.clientconfig.form.encryptSecret.tooltip=Define a password if the SEB client configuration shall be password-encrypted
sebserver.clientconfig.form.encryptSecret.confirm=Confirm Password sebserver.clientconfig.form.encryptSecret.confirm=Confirm Password
sebserver.clientconfig.form.encryptSecret.confirm.tooltip=Please retype the given password for configrmation
sebserver.clientconfig.action.list.new=Add Configuration sebserver.clientconfig.action.list.new=Add Configuration
sebserver.clientconfig.action.list.view=View Configuration sebserver.clientconfig.action.list.view=View Configuration
@ -494,9 +527,13 @@ sebserver.clientconfig.action.deactivate=Deactivate Configuration
sebserver.examconfig.action.list=Exam Configuration sebserver.examconfig.action.list=Exam Configuration
sebserver.examconfig.list.title=Exam Configurations sebserver.examconfig.list.title=Exam Configurations
sebserver.examconfig.list.column.institution=Institution sebserver.examconfig.list.column.institution=Institution
sebserver.examconfig.list.column.institution.tooltip=The institution of the SEB exam configuration.</br></br>Use the filter above to specify the institution.</br>{0}
sebserver.examconfig.list.column.name=Name sebserver.examconfig.list.column.name=Name
sebserver.examconfig.list.column.name.tooltip=The name of the SEB exam configuration.</br></br>Use the filter above to narrow down a specific name.</br>{0}
sebserver.examconfig.list.column.description=Description sebserver.examconfig.list.column.description=Description
sebserver.examconfig.list.column.description.tooltip=The description of the SEB exam configuration.</br></br>Use the filter above to find configurations that contains specific words or phrases within the description.</br>{0}
sebserver.examconfig.list.column.status=Status sebserver.examconfig.list.column.status=Status
sebserver.examconfig.list.column.status.tooltip=The status of the SEB exam configuration.</br></br>Use the filter above to specify a status.</br>{0}
sebserver.examconfig.list.actions= sebserver.examconfig.list.actions=
@ -506,10 +543,9 @@ sebserver.examconfig.list.action.no.modify.privilege=No Access: An Exam Configur
sebserver.examconfig.action.list.new=Add Exam Configuration sebserver.examconfig.action.list.new=Add Exam Configuration
sebserver.examconfig.action.list.view=View Configuration sebserver.examconfig.action.list.view=View Configuration
sebserver.examconfig.action.list.modify=Edit Settings sebserver.examconfig.action.list.modify=Configuration Settings
sebserver.examconfig.action.list.modify.properties=Edit Configuration sebserver.examconfig.action.list.modify.properties=Edit Configuration
sebserver.examconfig.action.view=View Settings sebserver.examconfig.action.modify=Configuration Settings
sebserver.examconfig.action.modify=Edit Settings
sebserver.examconfig.action.modify.properties=Edit Configuration sebserver.examconfig.action.modify.properties=Edit Configuration
sebserver.examconfig.action.view.properties=View Configuration sebserver.examconfig.action.view.properties=View Configuration
sebserver.examconfig.action.save=Save sebserver.examconfig.action.save=Save
@ -534,12 +570,17 @@ sebserver.examconfig.action.state-change.confirm=This configuration is already a
sebserver.examconfig.form.title.new=Add Exam Configuration sebserver.examconfig.form.title.new=Add Exam Configuration
sebserver.examconfig.form.title=Exam Configuration sebserver.examconfig.form.title=Exam Configuration
sebserver.examconfig.form.name=Name sebserver.examconfig.form.name=Name
sebserver.examconfig.form.name.tooltip=The name of the SEB exam configuration.
sebserver.examconfig.form.description=Description sebserver.examconfig.form.description=Description
sebserver.examconfig.form.description.tooltip=The description text of the SEB exam configuration.
sebserver.examconfig.form.with-history=With History sebserver.examconfig.form.with-history=With History
sebserver.examconfig.form.template=Template sebserver.examconfig.form.template=Template
sebserver.examconfig.form.template.tooltip=The template this SEB exam configuration depends on.
sebserver.examconfig.form.status=Status sebserver.examconfig.form.status=Status
sebserver.examconfig.form.status.tooltip=The status of this SEB exam configuration.</br></br>Under Construction marks a SEB exam configuration to not be able to attach to an exam so far.</br></br>Ready to use marks an SEB exam configuration to be able to attach to an exam.</br></br>In Use marks a SEB exam configuration is already been used from one or more exam(s)
sebserver.examconfig.form.config-key.title=Config Key sebserver.examconfig.form.config-key.title=Config Key
sebserver.examconfig.form.attched-to=Attached To Exam sebserver.examconfig.form.attached-to=Attached To Exam
sebserver.examconfig.form.attached-to.tooltip=This SEB exam configuration is currently attached to the following exams.</br></br>Select an exam from the list and use the "View Exam" or Double-Click on the list to go to a specific exam.
sebserver.examconfig.status.CONSTRUCTION=Under Construction sebserver.examconfig.status.CONSTRUCTION=Under Construction
sebserver.examconfig.status.READY_TO_USE=Ready To Use sebserver.examconfig.status.READY_TO_USE=Ready To Use
@ -1037,7 +1078,9 @@ sebserver.configtemplate.action.create-config.dialog=Exam Configuration
sebserver.configtemplate.form.title.new=Add Template sebserver.configtemplate.form.title.new=Add Template
sebserver.configtemplate.form.title=Configuration Template sebserver.configtemplate.form.title=Configuration Template
sebserver.configtemplate.form.name=Name sebserver.configtemplate.form.name=Name
sebserver.configtemplate.form.name.tooltip=The name of the SEB exam configuration template
sebserver.configtemplate.form.description=Description sebserver.configtemplate.form.description=Description
sebserver.configtemplate.form.description.tooltip=The description of the SEB exam configuration template
sebserver.configtemplate.action.save=Save Template sebserver.configtemplate.action.save=Save Template
sebserver.configtemplate.attr.type.TEXT_FIELD=Text Field sebserver.configtemplate.attr.type.TEXT_FIELD=Text Field
@ -1058,10 +1101,15 @@ sebserver.configtemplate.attr.type.INLINE_TABLE=Table
sebserver.configtemplate.attr.type.COMPOSITE_TABLE=Table sebserver.configtemplate.attr.type.COMPOSITE_TABLE=Table
sebserver.configtemplate.attrs.list.title=Configuration Attributes sebserver.configtemplate.attrs.list.title=Configuration Attributes
sebserver.configtemplate.attrs.list.title.tooltip=Table of all SEB exam configuration attributes of this template
sebserver.configtemplate.attrs.list.name=Name sebserver.configtemplate.attrs.list.name=Name
sebserver.configtemplate.attrs.list.name.tooltip=The technical name of the SEB exam configuration attribute with the display name in brackets if available.</br></br>{0}
sebserver.configtemplate.attrs.list.view=View sebserver.configtemplate.attrs.list.view=View
sebserver.configtemplate.attrs.list.view.tooltip=The view/tab where the SEB exam configuration attribute belongs to.</br></br>{0}
sebserver.configtemplate.attrs.list.group=Group sebserver.configtemplate.attrs.list.group=Group
sebserver.configtemplate.attrs.list.group.tooltip=The group on the view/tab where the SEB exam configuration attribute belongs to.</br></br>{0}
sebserver.configtemplate.attrs.list.type=Type sebserver.configtemplate.attrs.list.type=Type
sebserver.configtemplate.attrs.list.type.tooltip=The type of the SEB exam configuration attribute.</br></br>{0}
sebserver.configtemplate.attr.list.actions= sebserver.configtemplate.attr.list.actions=
sebserver.configtemplate.attr.list.actions.modify=Edit Attribute sebserver.configtemplate.attr.list.actions.modify=Edit Attribute
@ -1072,10 +1120,15 @@ sebserver.configtemplate.attr.info.pleaseSelect=Please select first an Attribute
sebserver.configtemplate.attr.form.title=Template Attribute sebserver.configtemplate.attr.form.title=Template Attribute
sebserver.configtemplate.attr.form.name=Name sebserver.configtemplate.attr.form.name=Name
sebserver.configtemplate.attr.form.name.tooltip=The technical name of the SEB exam configuration attribute with the display name in brackets if available.
sebserver.configtemplate.attr.form.type=Type sebserver.configtemplate.attr.form.type=Type
sebserver.configtemplate.attr.form.type.tooltip=The type of the SEB exam configuration attribute.
sebserver.configtemplate.attr.form.view=View sebserver.configtemplate.attr.form.view=View
sebserver.configtemplate.attr.form.view.tooltip=The view/tab where the SEB exam configuration attribute belongs to.
sebserver.configtemplate.attr.form.group=Group sebserver.configtemplate.attr.form.group=Group
sebserver.configtemplate.attr.form.group.tooltip=The group on the view/tab where the SEB exam configuration attribute belongs to.
sebserver.configtemplate.attr.form.value=Template Attribute Value sebserver.configtemplate.attr.form.value=Template Attribute Value
sebserver.configtemplate.attr.form.value.tooltip=The SEB exam configuration attribute value that can be set as default for this template
sebserver.configtemplate.attr.action.setdefault=Set Default Values sebserver.configtemplate.attr.action.setdefault=Set Default Values
sebserver.configtemplate.attr.action.template=View Template sebserver.configtemplate.attr.action.template=View Template
@ -1165,10 +1218,15 @@ sebserver.logs.activity.seblogs.details=Show Details
sebserver.userlogs.list.title=User Activity Logs sebserver.userlogs.list.title=User Activity Logs
sebserver.userlogs.list.column.institution=Institution sebserver.userlogs.list.column.institution=Institution
sebserver.userlogs.list.column.institution.tooltip=The institution of the user activity log.</br></br>Use the filter above to specify the institution.</br>{0}
sebserver.userlogs.list.column.user=User sebserver.userlogs.list.column.user=User
sebserver.userlogs.list.column.user.tooltip=The user account of the user activity log.</br></br>Use the filter above to specify a user account.</br>{0}
sebserver.userlogs.list.column.dateTime=Date {0} sebserver.userlogs.list.column.dateTime=Date {0}
sebserver.userlogs.list.column.dateTime.tooltip=The date when the user activity log happened.</br></br>Use the filter above to specify a from- and to-date range.</br>{0}
sebserver.userlogs.list.column.activityType=User Activity sebserver.userlogs.list.column.activityType=User Activity
sebserver.userlogs.list.column.entityType=Entity Type sebserver.userlogs.list.column.activityType.tooltip=The type of the user activity.</br></br>Use the filter above to specify a activity type.</br>{0}
sebserver.userlogs.list.column.entityType=Domain Type
sebserver.userlogs.list.column.entityType.tooltip=The domain type of the user activity.</br></br>Use the filter above to specify a domain type.</br>{0}
sebserver.userlogs.list.column.entityId=Entity-ID sebserver.userlogs.list.column.entityId=Entity-ID
sebserver.userlogs.list.column.message=Message sebserver.userlogs.list.column.message=Message

Binary file not shown.

Before

Width:  |  Height:  |  Size: 678 B

After

Width:  |  Height:  |  Size: 1.7 KiB