GUI improvements
This commit is contained in:
parent
8ea0def877
commit
25485b1fd4
28 changed files with 7160 additions and 6921 deletions
|
@ -1,136 +1,137 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gbl;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.eclipse.swt.graphics.RGB;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||
import ch.ethz.seb.sebserver.gbl.api.authorization.Privilege;
|
||||
|
||||
/** Global Constants used in SEB Server web-service as well as in web-gui component */
|
||||
public final class Constants {
|
||||
|
||||
public static final String DEFAULT_LANG_CODE = "en";
|
||||
public static final String DEFAULT_TIME_ZONE_CODE = "UTC";
|
||||
|
||||
public static final int SEB_FILE_HEADER_SIZE = 4;
|
||||
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 long SECOND_IN_MILLIS = 1000;
|
||||
public static final long MINUTE_IN_MILLIS = 60 * SECOND_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 CURLY_BRACE_CLOSE = '}';
|
||||
public static final Character SQUARE_BRACE_OPEN = '[';
|
||||
public static final Character SQUARE_BRACE_CLOSE = ']';
|
||||
public static final Character COLON = ':';
|
||||
public static final Character SEMICOLON = ';';
|
||||
public static final Character PERCENTAGE = '%';
|
||||
public static final Character SLASH = '/';
|
||||
public static final Character BACKSLASH = '\\';
|
||||
public static final Character QUOTE = '\'';
|
||||
public static final Character DOUBLE_QUOTE = '"';
|
||||
public static final Character COMMA = ',';
|
||||
public static final Character PIPE = '|';
|
||||
public static final Character AMPERSAND = '&';
|
||||
public static final Character EQUALITY_SIGN = '=';
|
||||
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 LIST_SEPARATOR = COMMA.toString();
|
||||
public static final String EMBEDDED_LIST_SEPARATOR = PIPE.toString();
|
||||
public static final String NO_NAME = "NONE";
|
||||
public static final String EMPTY_NOTE = "--";
|
||||
public static final String FORM_URL_ENCODED_SEPARATOR = AMPERSAND.toString();
|
||||
public static final String FORM_URL_ENCODED_NAME_VALUE_SEPARATOR = EQUALITY_SIGN.toString();
|
||||
public static final String URL_PORT_SEPARATOR = COLON.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_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_TIME_FORMAT = "HH:mm:ss";
|
||||
|
||||
public static final DateTimeFormatter STANDARD_DATE_TIME_FORMATTER = DateTimeFormat
|
||||
.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_DOCTYPE_HEADER =
|
||||
"<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">";
|
||||
public static final String XML_PLIST_START_V1 =
|
||||
"<plist version=\"1.0\">";
|
||||
public static final String XML_PLIST_END =
|
||||
"</plist>";
|
||||
public static final String XML_DICT_START =
|
||||
"<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_ARRAY_NAME = "array";
|
||||
public static final String XML_PLIST_KEY_NAME = "key";
|
||||
public static final String XML_PLIST_BOOLEAN_TRUE = "true";
|
||||
public static final String XML_PLIST_BOOLEAN_FALSE = "false";
|
||||
public static final String XML_PLIST_STRING = "string";
|
||||
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_REFRESH_TOKEN = "refresh_token";
|
||||
public static final String OAUTH2_GRANT_TYPE_CLIENT_CREDENTIALS = "client_credentials";
|
||||
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_3 = 3;
|
||||
|
||||
public static final int GZIP_HEADER_LENGTH = 4;
|
||||
public static final int GZIP_ID1 = 0x1F;
|
||||
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 TypeReference<Collection<APIMessage>> TYPE_REFERENCE_API_MESSAGE =
|
||||
new TypeReferenceAPIMessage();
|
||||
public static final ParameterizedTypeReference<Collection<Privilege>> TYPE_REFERENCE_PRIVILEGES =
|
||||
new TypeReferencePrivileges();
|
||||
|
||||
public static final class TypeReferenceAPIMessage extends TypeReference<Collection<APIMessage>> {
|
||||
}
|
||||
|
||||
public static final class TypeReferencePrivileges extends ParameterizedTypeReference<Collection<Privilege>> {
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gbl;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.eclipse.swt.graphics.RGB;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||
import ch.ethz.seb.sebserver.gbl.api.authorization.Privilege;
|
||||
|
||||
/** Global Constants used in SEB Server web-service as well as in web-gui component */
|
||||
public final class Constants {
|
||||
|
||||
public static final String DEFAULT_LANG_CODE = "en";
|
||||
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 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 long SECOND_IN_MILLIS = 1000;
|
||||
public static final long MINUTE_IN_MILLIS = 60 * SECOND_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 CURLY_BRACE_CLOSE = '}';
|
||||
public static final Character SQUARE_BRACE_OPEN = '[';
|
||||
public static final Character SQUARE_BRACE_CLOSE = ']';
|
||||
public static final Character COLON = ':';
|
||||
public static final Character SEMICOLON = ';';
|
||||
public static final Character PERCENTAGE = '%';
|
||||
public static final Character SLASH = '/';
|
||||
public static final Character BACKSLASH = '\\';
|
||||
public static final Character QUOTE = '\'';
|
||||
public static final Character DOUBLE_QUOTE = '"';
|
||||
public static final Character COMMA = ',';
|
||||
public static final Character PIPE = '|';
|
||||
public static final Character AMPERSAND = '&';
|
||||
public static final Character EQUALITY_SIGN = '=';
|
||||
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 LIST_SEPARATOR = COMMA.toString();
|
||||
public static final String EMBEDDED_LIST_SEPARATOR = PIPE.toString();
|
||||
public static final String NO_NAME = "NONE";
|
||||
public static final String EMPTY_NOTE = "--";
|
||||
public static final String FORM_URL_ENCODED_SEPARATOR = AMPERSAND.toString();
|
||||
public static final String FORM_URL_ENCODED_NAME_VALUE_SEPARATOR = EQUALITY_SIGN.toString();
|
||||
public static final String URL_PORT_SEPARATOR = COLON.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_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_TIME_FORMAT = "HH:mm:ss";
|
||||
|
||||
public static final DateTimeFormatter STANDARD_DATE_TIME_FORMATTER = DateTimeFormat
|
||||
.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_DOCTYPE_HEADER =
|
||||
"<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">";
|
||||
public static final String XML_PLIST_START_V1 =
|
||||
"<plist version=\"1.0\">";
|
||||
public static final String XML_PLIST_END =
|
||||
"</plist>";
|
||||
public static final String XML_DICT_START =
|
||||
"<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_ARRAY_NAME = "array";
|
||||
public static final String XML_PLIST_KEY_NAME = "key";
|
||||
public static final String XML_PLIST_BOOLEAN_TRUE = "true";
|
||||
public static final String XML_PLIST_BOOLEAN_FALSE = "false";
|
||||
public static final String XML_PLIST_STRING = "string";
|
||||
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_REFRESH_TOKEN = "refresh_token";
|
||||
public static final String OAUTH2_GRANT_TYPE_CLIENT_CREDENTIALS = "client_credentials";
|
||||
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_3 = 3;
|
||||
|
||||
public static final int GZIP_HEADER_LENGTH = 4;
|
||||
public static final int GZIP_ID1 = 0x1F;
|
||||
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 TypeReference<Collection<APIMessage>> TYPE_REFERENCE_API_MESSAGE =
|
||||
new TypeReferenceAPIMessage();
|
||||
public static final ParameterizedTypeReference<Collection<Privilege>> TYPE_REFERENCE_PRIVILEGES =
|
||||
new TypeReferencePrivileges();
|
||||
|
||||
public static final class TypeReferenceAPIMessage extends TypeReference<Collection<APIMessage>> {
|
||||
}
|
||||
|
||||
public static final class TypeReferencePrivileges extends ParameterizedTypeReference<Collection<Privilege>> {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,360 +1,361 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gbl.model.user;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
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.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
|
||||
/** The user info domain model contains primary user information
|
||||
*
|
||||
* This domain model is annotated and fully serializable and deserializable
|
||||
* to and from JSON within the Jackson library.
|
||||
*
|
||||
* This domain model is immutable and thread-save */
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public final class UserInfo implements UserAccount, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 2526446136264377808L;
|
||||
|
||||
public static final String FILTER_ATTR_USER_NAME = "username";
|
||||
public static final String FILTER_ATTR_EMAIL = "email";
|
||||
public static final String FILTER_ATTR_LANGUAGE = "language";
|
||||
public static final String FILTER_ATTR_ROLE = "role";
|
||||
|
||||
/** The user's UUID */
|
||||
@JsonProperty(USER.ATTR_UUID)
|
||||
public final String uuid;
|
||||
|
||||
/** The foreign key identifier to the institution where the User belongs to */
|
||||
@NotNull
|
||||
@JsonProperty(USER.ATTR_INSTITUTION_ID)
|
||||
public final Long institutionId;
|
||||
|
||||
@JsonProperty(USER.ATTR_CREATION_DATE)
|
||||
public final DateTime creationDate;
|
||||
|
||||
/** First name of the user */
|
||||
@NotNull(message = "user:name:notNull")
|
||||
@Size(min = 3, max = 255, message = "user:name:size:{min}:{max}:${validatedValue}")
|
||||
@JsonProperty(USER.ATTR_NAME)
|
||||
public final String name;
|
||||
|
||||
/** Surname of the user */
|
||||
@Size(max = 255, message = "user:surname:size:{min}:{max}:${validatedValue}")
|
||||
@JsonProperty(USER.ATTR_SURNAME)
|
||||
public final String surname;
|
||||
|
||||
/** The internal user name */
|
||||
@NotNull(message = "user:username:notNull")
|
||||
@Size(min = 3, max = 255, message = "user:username:size:{min}:{max}:${validatedValue}")
|
||||
@JsonProperty(USER.ATTR_USERNAME)
|
||||
public final String username;
|
||||
|
||||
/** E-mail address of the user */
|
||||
@Email(message = "user:email:email:_:_:${validatedValue}")
|
||||
@JsonProperty(USER.ATTR_EMAIL)
|
||||
public final String email;
|
||||
|
||||
/** Indicates whether this user is still active or not */
|
||||
@NotNull
|
||||
@JsonProperty(USER.ATTR_ACTIVE)
|
||||
public final Boolean active;
|
||||
|
||||
/** The users locale */
|
||||
@NotNull(message = "user:language:notNull")
|
||||
@JsonProperty(USER.ATTR_LANGUAGE)
|
||||
public final Locale language;
|
||||
|
||||
/** The users time zone */
|
||||
@NotNull(message = "user:timeZone:notNull")
|
||||
@JsonProperty(USER.ATTR_TIMEZONE)
|
||||
public final DateTimeZone timeZone;
|
||||
|
||||
/** The users roles in a unmodifiable set. Is never null */
|
||||
@NotNull(message = "user:userRoles:notNull")
|
||||
@NotEmpty(message = "user:userRoles:notNull")
|
||||
@JsonProperty(USER_ROLE.REFERENCE_NAME)
|
||||
public final Set<String> roles;
|
||||
|
||||
@JsonCreator
|
||||
public UserInfo(
|
||||
@JsonProperty(USER.ATTR_UUID) final String uuid,
|
||||
@JsonProperty(USER.ATTR_INSTITUTION_ID) final Long institutionId,
|
||||
@JsonProperty(USER.ATTR_CREATION_DATE) final DateTime creationDate,
|
||||
@JsonProperty(USER.ATTR_NAME) final String name,
|
||||
@JsonProperty(USER.ATTR_SURNAME) final String surname,
|
||||
@JsonProperty(USER.ATTR_USERNAME) final String username,
|
||||
@JsonProperty(USER.ATTR_EMAIL) final String email,
|
||||
@JsonProperty(USER.ATTR_ACTIVE) final Boolean active,
|
||||
@JsonProperty(USER.ATTR_LANGUAGE) final Locale language,
|
||||
@JsonProperty(USER.ATTR_TIMEZONE) final DateTimeZone timeZone,
|
||||
@JsonProperty(USER_ROLE.REFERENCE_NAME) final Set<String> roles) {
|
||||
|
||||
this.uuid = uuid;
|
||||
this.institutionId = institutionId;
|
||||
this.creationDate = creationDate;
|
||||
this.name = name;
|
||||
this.surname = surname;
|
||||
this.username = username;
|
||||
this.email = email;
|
||||
this.active = BooleanUtils.isTrue(active);
|
||||
this.language = language;
|
||||
this.timeZone = timeZone;
|
||||
this.roles = Utils.immutableSetOf(roles);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityType entityType() {
|
||||
return EntityType.USER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModelId() {
|
||||
return this.uuid;
|
||||
}
|
||||
|
||||
public String getUuid() {
|
||||
return this.uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateTime getCreationDate() {
|
||||
return this.creationDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getInstitutionId() {
|
||||
return this.institutionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOwnerId() {
|
||||
return this.uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSurname() {
|
||||
return this.surname;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEmail() {
|
||||
return this.email;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getActive() {
|
||||
return this.active;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return this.active;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale getLanguage() {
|
||||
return this.language;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateTimeZone getTimeZone() {
|
||||
return this.timeZone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getRoles() {
|
||||
return this.roles;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public EnumSet<UserRole> getUserRoles() {
|
||||
return EnumSet.copyOf(
|
||||
getRoles().stream()
|
||||
.map(r -> UserRole.valueOf(r))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
public boolean hasRole(final UserRole userRole) {
|
||||
if (userRole == null) {
|
||||
return false;
|
||||
}
|
||||
return this.roles.contains(userRole.name());
|
||||
}
|
||||
|
||||
public boolean hasAnyRole(final UserRole... userRole) {
|
||||
if (userRole == null) {
|
||||
return false;
|
||||
}
|
||||
return CollectionUtils.containsAny(getUserRoles(), Arrays.asList(userRole));
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public EntityKey getEntityKey() {
|
||||
if (StringUtils.isBlank(this.uuid)) {
|
||||
return null;
|
||||
}
|
||||
return new EntityKey(this.uuid, entityType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((this.uuid == null) ? 0 : this.uuid.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
final UserInfo other = (UserInfo) obj;
|
||||
if (this.uuid == null) {
|
||||
if (other.uuid != null)
|
||||
return false;
|
||||
} else if (!this.uuid.equals(other.uuid))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append("UserInfo [uuid=");
|
||||
builder.append(this.uuid);
|
||||
builder.append(", institutionId=");
|
||||
builder.append(this.institutionId);
|
||||
builder.append(", creationDate=");
|
||||
builder.append(this.creationDate);
|
||||
builder.append(", name=");
|
||||
builder.append(this.name);
|
||||
builder.append(", surname=");
|
||||
builder.append(this.surname);
|
||||
builder.append(", username=");
|
||||
builder.append(this.username);
|
||||
builder.append(", email=");
|
||||
builder.append(this.email);
|
||||
builder.append(", active=");
|
||||
builder.append(this.active);
|
||||
builder.append(", language=");
|
||||
builder.append(this.language);
|
||||
builder.append(", timeZone=");
|
||||
builder.append(this.timeZone);
|
||||
builder.append(", roles=");
|
||||
builder.append(this.roles);
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/** Use this to create a copy of a given UserInfo instance.
|
||||
*
|
||||
* @param userInfo UserInfo instance to copy
|
||||
* @return copied UserInfo instance */
|
||||
public static final UserInfo of(final UserInfo userInfo) {
|
||||
return new UserInfo(
|
||||
userInfo.getUuid(),
|
||||
userInfo.getInstitutionId(),
|
||||
userInfo.creationDate,
|
||||
userInfo.getName(),
|
||||
userInfo.getUsername(),
|
||||
userInfo.getSurname(),
|
||||
userInfo.getEmail(),
|
||||
userInfo.getActive(),
|
||||
userInfo.getLanguage(),
|
||||
userInfo.getTimeZone(),
|
||||
userInfo.roles);
|
||||
}
|
||||
|
||||
/** 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 surname new surname 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 email new email or null if the email of given userInfo should be taken
|
||||
* @param language new language or null if the language of given userInfo should be taken
|
||||
* @param timeZone new timeZone or null if the timeZone of given userInfo should be taken
|
||||
* @param roles new timeZone or null if the roles of given userInfo should be taken
|
||||
* @return copied UserInfo instance with the given attributes */
|
||||
public static final UserInfo of(
|
||||
final UserInfo userInfo,
|
||||
final String name,
|
||||
final String username,
|
||||
final String surname,
|
||||
final String email,
|
||||
final Locale language,
|
||||
final DateTimeZone timeZone,
|
||||
final String... roles) {
|
||||
|
||||
return new UserInfo(
|
||||
userInfo.getUuid(),
|
||||
userInfo.getInstitutionId(),
|
||||
userInfo.creationDate,
|
||||
(name != null) ? name : userInfo.getName(),
|
||||
(surname != null) ? surname : userInfo.getSurname(),
|
||||
(username != null) ? username : userInfo.getUsername(),
|
||||
(email != null) ? email : userInfo.getEmail(),
|
||||
userInfo.getActive(),
|
||||
(language != null) ? language : userInfo.getLanguage(),
|
||||
(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 final UserInfo withRoles(final UserInfo userInfo, final String... roles) {
|
||||
return of(userInfo, null, null, null, null, null, null, roles);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gbl.model.user;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
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.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
|
||||
/** The user info domain model contains primary user information
|
||||
*
|
||||
* This domain model is annotated and fully serializable and deserializable
|
||||
* to and from JSON within the Jackson library.
|
||||
*
|
||||
* This domain model is immutable and thread-save */
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public final class UserInfo implements UserAccount, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 2526446136264377808L;
|
||||
|
||||
public static final String FILTER_ATTR_USER_NAME = "username";
|
||||
public static final String FILTER_ATTR_EMAIL = "email";
|
||||
public static final String FILTER_ATTR_LANGUAGE = "language";
|
||||
public static final String FILTER_ATTR_ROLE = "role";
|
||||
|
||||
/** The user's UUID */
|
||||
@JsonProperty(USER.ATTR_UUID)
|
||||
public final String uuid;
|
||||
|
||||
/** The foreign key identifier to the institution where the User belongs to */
|
||||
@NotNull(message = "user:institutionId:notNull")
|
||||
@JsonProperty(USER.ATTR_INSTITUTION_ID)
|
||||
public final Long institutionId;
|
||||
|
||||
@JsonProperty(USER.ATTR_CREATION_DATE)
|
||||
public final DateTime creationDate;
|
||||
|
||||
/** First name of the user */
|
||||
@NotNull(message = "user:name:notNull")
|
||||
@Size(max = 255, message = "user:name:size:{min}:{max}:${validatedValue}")
|
||||
@JsonProperty(USER.ATTR_NAME)
|
||||
public final String name;
|
||||
|
||||
/** Surname of the user */
|
||||
@NotNull(message = "user:surname:notNull")
|
||||
@Size(max = 255, message = "user:surname:size:{min}:{max}:${validatedValue}")
|
||||
@JsonProperty(USER.ATTR_SURNAME)
|
||||
public final String surname;
|
||||
|
||||
/** The internal user name */
|
||||
@NotNull(message = "user:username:notNull")
|
||||
@Size(min = 3, max = 255, message = "user:username:size:{min}:{max}:${validatedValue}")
|
||||
@JsonProperty(USER.ATTR_USERNAME)
|
||||
public final String username;
|
||||
|
||||
/** E-mail address of the user */
|
||||
@Email(message = "user:email:email:_:_:${validatedValue}")
|
||||
@JsonProperty(USER.ATTR_EMAIL)
|
||||
public final String email;
|
||||
|
||||
/** Indicates whether this user is still active or not */
|
||||
@NotNull
|
||||
@JsonProperty(USER.ATTR_ACTIVE)
|
||||
public final Boolean active;
|
||||
|
||||
/** The users locale */
|
||||
@NotNull(message = "user:language:notNull")
|
||||
@JsonProperty(USER.ATTR_LANGUAGE)
|
||||
public final Locale language;
|
||||
|
||||
/** The users time zone */
|
||||
@NotNull(message = "user:timeZone:notNull")
|
||||
@JsonProperty(USER.ATTR_TIMEZONE)
|
||||
public final DateTimeZone timeZone;
|
||||
|
||||
/** The users roles in a unmodifiable set. Is never null */
|
||||
@NotNull(message = "user:userRoles:notNull")
|
||||
@NotEmpty(message = "user:userRoles:notNull")
|
||||
@JsonProperty(USER_ROLE.REFERENCE_NAME)
|
||||
public final Set<String> roles;
|
||||
|
||||
@JsonCreator
|
||||
public UserInfo(
|
||||
@JsonProperty(USER.ATTR_UUID) final String uuid,
|
||||
@JsonProperty(USER.ATTR_INSTITUTION_ID) final Long institutionId,
|
||||
@JsonProperty(USER.ATTR_CREATION_DATE) final DateTime creationDate,
|
||||
@JsonProperty(USER.ATTR_NAME) final String name,
|
||||
@JsonProperty(USER.ATTR_SURNAME) final String surname,
|
||||
@JsonProperty(USER.ATTR_USERNAME) final String username,
|
||||
@JsonProperty(USER.ATTR_EMAIL) final String email,
|
||||
@JsonProperty(USER.ATTR_ACTIVE) final Boolean active,
|
||||
@JsonProperty(USER.ATTR_LANGUAGE) final Locale language,
|
||||
@JsonProperty(USER.ATTR_TIMEZONE) final DateTimeZone timeZone,
|
||||
@JsonProperty(USER_ROLE.REFERENCE_NAME) final Set<String> roles) {
|
||||
|
||||
this.uuid = uuid;
|
||||
this.institutionId = institutionId;
|
||||
this.creationDate = creationDate;
|
||||
this.name = name;
|
||||
this.surname = surname;
|
||||
this.username = username;
|
||||
this.email = email;
|
||||
this.active = BooleanUtils.isTrue(active);
|
||||
this.language = language;
|
||||
this.timeZone = timeZone;
|
||||
this.roles = Utils.immutableSetOf(roles);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityType entityType() {
|
||||
return EntityType.USER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModelId() {
|
||||
return this.uuid;
|
||||
}
|
||||
|
||||
public String getUuid() {
|
||||
return this.uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateTime getCreationDate() {
|
||||
return this.creationDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getInstitutionId() {
|
||||
return this.institutionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOwnerId() {
|
||||
return this.uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSurname() {
|
||||
return this.surname;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEmail() {
|
||||
return this.email;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getActive() {
|
||||
return this.active;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return this.active;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale getLanguage() {
|
||||
return this.language;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateTimeZone getTimeZone() {
|
||||
return this.timeZone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getRoles() {
|
||||
return this.roles;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public EnumSet<UserRole> getUserRoles() {
|
||||
return EnumSet.copyOf(
|
||||
getRoles().stream()
|
||||
.map(UserRole::valueOf)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
public boolean hasRole(final UserRole userRole) {
|
||||
if (userRole == null) {
|
||||
return false;
|
||||
}
|
||||
return this.roles.contains(userRole.name());
|
||||
}
|
||||
|
||||
public boolean hasAnyRole(final UserRole... userRole) {
|
||||
if (userRole == null) {
|
||||
return false;
|
||||
}
|
||||
return CollectionUtils.containsAny(getUserRoles(), Arrays.asList(userRole));
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public EntityKey getEntityKey() {
|
||||
if (StringUtils.isBlank(this.uuid)) {
|
||||
return null;
|
||||
}
|
||||
return new EntityKey(this.uuid, entityType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((this.uuid == null) ? 0 : this.uuid.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
final UserInfo other = (UserInfo) obj;
|
||||
if (this.uuid == null) {
|
||||
if (other.uuid != null)
|
||||
return false;
|
||||
} else if (!this.uuid.equals(other.uuid))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append("UserInfo [uuid=");
|
||||
builder.append(this.uuid);
|
||||
builder.append(", institutionId=");
|
||||
builder.append(this.institutionId);
|
||||
builder.append(", creationDate=");
|
||||
builder.append(this.creationDate);
|
||||
builder.append(", name=");
|
||||
builder.append(this.name);
|
||||
builder.append(", surname=");
|
||||
builder.append(this.surname);
|
||||
builder.append(", username=");
|
||||
builder.append(this.username);
|
||||
builder.append(", email=");
|
||||
builder.append(this.email);
|
||||
builder.append(", active=");
|
||||
builder.append(this.active);
|
||||
builder.append(", language=");
|
||||
builder.append(this.language);
|
||||
builder.append(", timeZone=");
|
||||
builder.append(this.timeZone);
|
||||
builder.append(", roles=");
|
||||
builder.append(this.roles);
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/** Use this to create a copy of a given UserInfo instance.
|
||||
*
|
||||
* @param userInfo UserInfo instance to copy
|
||||
* @return copied UserInfo instance */
|
||||
public static UserInfo of(final UserInfo userInfo) {
|
||||
return new UserInfo(
|
||||
userInfo.getUuid(),
|
||||
userInfo.getInstitutionId(),
|
||||
userInfo.creationDate,
|
||||
userInfo.getName(),
|
||||
userInfo.getUsername(),
|
||||
userInfo.getSurname(),
|
||||
userInfo.getEmail(),
|
||||
userInfo.getActive(),
|
||||
userInfo.getLanguage(),
|
||||
userInfo.getTimeZone(),
|
||||
userInfo.roles);
|
||||
}
|
||||
|
||||
/** 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 surname new surname 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 email new email or null if the email of given userInfo should be taken
|
||||
* @param language new language or null if the language of given userInfo should be taken
|
||||
* @param timeZone new timeZone or null if the timeZone of given userInfo should be taken
|
||||
* @param roles new timeZone or null if the roles of given userInfo should be taken
|
||||
* @return copied UserInfo instance with the given attributes */
|
||||
public static UserInfo of(
|
||||
final UserInfo userInfo,
|
||||
final String name,
|
||||
final String username,
|
||||
final String surname,
|
||||
final String email,
|
||||
final Locale language,
|
||||
final DateTimeZone timeZone,
|
||||
final String... roles) {
|
||||
|
||||
return new UserInfo(
|
||||
userInfo.getUuid(),
|
||||
userInfo.getInstitutionId(),
|
||||
userInfo.creationDate,
|
||||
(name != null) ? name : userInfo.getName(),
|
||||
(surname != null) ? surname : userInfo.getSurname(),
|
||||
(username != null) ? username : userInfo.getUsername(),
|
||||
(email != null) ? email : userInfo.getEmail(),
|
||||
userInfo.getActive(),
|
||||
(language != null) ? language : userInfo.getLanguage(),
|
||||
(timeZone != null) ? timeZone : userInfo.getTimeZone(),
|
||||
(roles != null) ? new HashSet<>(Arrays.asList(roles)) : userInfo.roles);
|
||||
}
|
||||
|
||||
public static UserInfo withEMail(final UserInfo userInfo, final String email) {
|
||||
return of(userInfo, null, null, null, email, null, null, (String[]) null);
|
||||
}
|
||||
|
||||
public static UserInfo withRoles(final UserInfo userInfo, final String... roles) {
|
||||
return of(userInfo, null, null, null, null, null, null, roles);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,284 +1,285 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gbl.model.user;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
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_ROLE;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public final class UserMod implements UserAccount {
|
||||
|
||||
@JsonProperty(USER.ATTR_UUID)
|
||||
public final String uuid;
|
||||
|
||||
/** The foreign key identifier to the institution where the User belongs to */
|
||||
@NotNull(message = "user:institutionId:notNull")
|
||||
@JsonProperty(USER.ATTR_INSTITUTION_ID)
|
||||
public final Long institutionId;
|
||||
|
||||
/** first (or full) name of the user */
|
||||
@NotNull(message = "user:name:notNull")
|
||||
@Size(min = 3, max = 255, message = "user:name:size:{min}:{max}:${validatedValue}")
|
||||
@JsonProperty(USER.ATTR_NAME)
|
||||
public final String name;
|
||||
|
||||
/** surname of the user */
|
||||
@Size(max = 255, message = "user:surname:size:{min}:{max}:${validatedValue}")
|
||||
@JsonProperty(USER.ATTR_SURNAME)
|
||||
public final String surname;
|
||||
|
||||
/** The internal user name */
|
||||
@NotNull(message = "user:username:notNull")
|
||||
@Size(min = 3, max = 255, message = "user:username:size:{min}:{max}:${validatedValue}")
|
||||
@JsonProperty(USER.ATTR_USERNAME)
|
||||
public final String username;
|
||||
|
||||
/** E-mail address of the user */
|
||||
@Email(message = "user:email:email:_:_:${validatedValue}")
|
||||
@JsonProperty(USER.ATTR_EMAIL)
|
||||
public final String email;
|
||||
|
||||
/** The users locale */
|
||||
@NotNull(message = "user:language:notNull")
|
||||
@JsonProperty(USER.ATTR_LANGUAGE)
|
||||
public final Locale language;
|
||||
|
||||
/** The users time zone */
|
||||
@NotNull(message = "user:timeZone:notNull")
|
||||
@JsonProperty(USER.ATTR_TIMEZONE)
|
||||
public final DateTimeZone timeZone;
|
||||
|
||||
/** The users roles in a unmodifiable set */
|
||||
@NotNull(message = "user:userRoles:notNull")
|
||||
@NotEmpty(message = "user:userRoles:notNull")
|
||||
@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}")
|
||||
@JsonProperty(PasswordChange.ATTR_NAME_NEW_PASSWORD)
|
||||
private final CharSequence newPassword;
|
||||
|
||||
@NotNull(message = "user:confirmNewPassword:notNull")
|
||||
@JsonProperty(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD)
|
||||
private final CharSequence confirmNewPassword;
|
||||
|
||||
@JsonCreator
|
||||
public UserMod(
|
||||
@JsonProperty(USER.ATTR_UUID) final String uuid,
|
||||
@JsonProperty(USER.ATTR_INSTITUTION_ID) final Long institutionId,
|
||||
@JsonProperty(USER.ATTR_NAME) final String name,
|
||||
@JsonProperty(USER.ATTR_SURNAME) final String surname,
|
||||
@JsonProperty(USER.ATTR_USERNAME) final String username,
|
||||
@JsonProperty(PasswordChange.ATTR_NAME_NEW_PASSWORD) final CharSequence newPassword,
|
||||
@JsonProperty(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD) final CharSequence confirmNewPassword,
|
||||
@JsonProperty(USER.ATTR_EMAIL) final String email,
|
||||
@JsonProperty(USER.ATTR_LANGUAGE) final Locale language,
|
||||
@JsonProperty(USER.ATTR_TIMEZONE) final DateTimeZone timeZone,
|
||||
@JsonProperty(USER_ROLE.REFERENCE_NAME) final Set<String> roles) {
|
||||
|
||||
this.uuid = uuid;
|
||||
this.institutionId = institutionId;
|
||||
this.newPassword = newPassword;
|
||||
this.confirmNewPassword = confirmNewPassword;
|
||||
this.name = name;
|
||||
this.surname = surname;
|
||||
this.username = username;
|
||||
this.email = email;
|
||||
this.language = (language != null) ? language : Locale.ENGLISH;
|
||||
this.timeZone = (timeZone != null) ? timeZone : DateTimeZone.UTC;
|
||||
this.roles = (roles != null)
|
||||
? Collections.unmodifiableSet(roles)
|
||||
: Collections.emptySet();
|
||||
}
|
||||
|
||||
public UserMod(final String modelId, final POSTMapper postAttrMapper) {
|
||||
this.uuid = modelId;
|
||||
this.institutionId = postAttrMapper.getLong(USER.ATTR_INSTITUTION_ID);
|
||||
this.newPassword = postAttrMapper.getString(PasswordChange.ATTR_NAME_NEW_PASSWORD);
|
||||
this.confirmNewPassword = postAttrMapper.getString(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD);
|
||||
this.name = postAttrMapper.getString(USER.ATTR_NAME);
|
||||
this.surname = postAttrMapper.getString(USER.ATTR_SURNAME);
|
||||
this.username = postAttrMapper.getString(USER.ATTR_USERNAME);
|
||||
this.email = postAttrMapper.getString(USER.ATTR_EMAIL);
|
||||
this.language = postAttrMapper.getLocale(USER.ATTR_LANGUAGE);
|
||||
this.timeZone = postAttrMapper.getDateTimeZone(USER.ATTR_TIMEZONE);
|
||||
this.roles = postAttrMapper.getStringSet(USER_ROLE.REFERENCE_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModelId() {
|
||||
return this.uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityType entityType() {
|
||||
return EntityType.USER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getInstitutionId() {
|
||||
return this.institutionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateTime getCreationDate() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOwnerId() {
|
||||
return this.uuid;
|
||||
}
|
||||
|
||||
public CharSequence getNewPassword() {
|
||||
return this.newPassword;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSurname() {
|
||||
return this.surname;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEmail() {
|
||||
return this.email;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale getLanguage() {
|
||||
return this.language;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateTimeZone getTimeZone() {
|
||||
return this.timeZone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getRoles() {
|
||||
return this.roles;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public EnumSet<UserRole> getUserRoles() {
|
||||
final List<UserRole> roles = getRoles()
|
||||
.stream()
|
||||
.map(r -> UserRole.valueOf(r))
|
||||
.collect(Collectors.toList());
|
||||
if (roles.isEmpty()) {
|
||||
return EnumSet.noneOf(UserRole.class);
|
||||
}
|
||||
return EnumSet.copyOf(roles);
|
||||
}
|
||||
|
||||
public CharSequence getRetypedNewPassword() {
|
||||
return this.confirmNewPassword;
|
||||
}
|
||||
|
||||
public boolean passwordChangeRequest() {
|
||||
return this.newPassword != null;
|
||||
}
|
||||
|
||||
public boolean newPasswordMatch() {
|
||||
return passwordChangeRequest() && this.newPassword.equals(this.confirmNewPassword);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getActive() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public EntityKey getEntityKey() {
|
||||
if (StringUtils.isBlank(this.uuid)) {
|
||||
return null;
|
||||
}
|
||||
return new EntityKey(this.uuid, entityType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append("UserMod [uuid=");
|
||||
builder.append(this.uuid);
|
||||
builder.append(", institutionId=");
|
||||
builder.append(this.institutionId);
|
||||
builder.append(", name=");
|
||||
builder.append(this.name);
|
||||
builder.append(", surname=");
|
||||
builder.append(this.surname);
|
||||
builder.append(", username=");
|
||||
builder.append(this.username);
|
||||
builder.append(", email=");
|
||||
builder.append(this.email);
|
||||
builder.append(", language=");
|
||||
builder.append(this.language);
|
||||
builder.append(", timeZone=");
|
||||
builder.append(this.timeZone);
|
||||
builder.append(", roles=");
|
||||
builder.append(this.roles);
|
||||
builder.append(", newPassword=");
|
||||
builder.append(this.newPassword);
|
||||
builder.append(", confirmNewPassword=");
|
||||
builder.append(this.confirmNewPassword);
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public static UserMod createNew(final Long institutionId) {
|
||||
return new UserMod(
|
||||
UUID.randomUUID().toString(),
|
||||
institutionId,
|
||||
null, null, null, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gbl.model.user;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
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_ROLE;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public final class UserMod implements UserAccount {
|
||||
|
||||
@JsonProperty(USER.ATTR_UUID)
|
||||
public final String uuid;
|
||||
|
||||
/** The foreign key identifier to the institution where the User belongs to */
|
||||
@NotNull(message = "user:institutionId:notNull")
|
||||
@JsonProperty(USER.ATTR_INSTITUTION_ID)
|
||||
public final Long institutionId;
|
||||
|
||||
/** first (or full) name of the user */
|
||||
@NotNull(message = "user:name:notNull")
|
||||
@Size(max = 255, message = "user:name:size:{min}:{max}:${validatedValue}")
|
||||
@JsonProperty(USER.ATTR_NAME)
|
||||
public final String name;
|
||||
|
||||
/** surname of the user */
|
||||
@NotNull(message = "user:surname:notNull")
|
||||
@Size(max = 255, message = "user:surname:size:{min}:{max}:${validatedValue}")
|
||||
@JsonProperty(USER.ATTR_SURNAME)
|
||||
public final String surname;
|
||||
|
||||
/** The internal user name */
|
||||
@NotNull(message = "user:username:notNull")
|
||||
@Size(min = 3, max = 255, message = "user:username:size:{min}:{max}:${validatedValue}")
|
||||
@JsonProperty(USER.ATTR_USERNAME)
|
||||
public final String username;
|
||||
|
||||
/** E-mail address of the user */
|
||||
@Email(message = "user:email:email:_:_:${validatedValue}")
|
||||
@JsonProperty(USER.ATTR_EMAIL)
|
||||
public final String email;
|
||||
|
||||
/** The users locale */
|
||||
@NotNull(message = "user:language:notNull")
|
||||
@JsonProperty(USER.ATTR_LANGUAGE)
|
||||
public final Locale language;
|
||||
|
||||
/** The users time zone */
|
||||
@NotNull(message = "user:timeZone:notNull")
|
||||
@JsonProperty(USER.ATTR_TIMEZONE)
|
||||
public final DateTimeZone timeZone;
|
||||
|
||||
/** The users roles in a unmodifiable set */
|
||||
@NotNull(message = "user:userRoles:notNull")
|
||||
@NotEmpty(message = "user:userRoles:notNull")
|
||||
@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}")
|
||||
@JsonProperty(PasswordChange.ATTR_NAME_NEW_PASSWORD)
|
||||
private final CharSequence newPassword;
|
||||
|
||||
@NotNull(message = "user:confirmNewPassword:notNull")
|
||||
@JsonProperty(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD)
|
||||
private final CharSequence confirmNewPassword;
|
||||
|
||||
@JsonCreator
|
||||
public UserMod(
|
||||
@JsonProperty(USER.ATTR_UUID) final String uuid,
|
||||
@JsonProperty(USER.ATTR_INSTITUTION_ID) final Long institutionId,
|
||||
@JsonProperty(USER.ATTR_NAME) final String name,
|
||||
@JsonProperty(USER.ATTR_SURNAME) final String surname,
|
||||
@JsonProperty(USER.ATTR_USERNAME) final String username,
|
||||
@JsonProperty(PasswordChange.ATTR_NAME_NEW_PASSWORD) final CharSequence newPassword,
|
||||
@JsonProperty(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD) final CharSequence confirmNewPassword,
|
||||
@JsonProperty(USER.ATTR_EMAIL) final String email,
|
||||
@JsonProperty(USER.ATTR_LANGUAGE) final Locale language,
|
||||
@JsonProperty(USER.ATTR_TIMEZONE) final DateTimeZone timeZone,
|
||||
@JsonProperty(USER_ROLE.REFERENCE_NAME) final Set<String> roles) {
|
||||
|
||||
this.uuid = uuid;
|
||||
this.institutionId = institutionId;
|
||||
this.newPassword = newPassword;
|
||||
this.confirmNewPassword = confirmNewPassword;
|
||||
this.name = name;
|
||||
this.surname = surname;
|
||||
this.username = username;
|
||||
this.email = email;
|
||||
this.language = (language != null) ? language : Locale.ENGLISH;
|
||||
this.timeZone = (timeZone != null) ? timeZone : DateTimeZone.UTC;
|
||||
this.roles = (roles != null)
|
||||
? Collections.unmodifiableSet(roles)
|
||||
: Collections.emptySet();
|
||||
}
|
||||
|
||||
public UserMod(final String modelId, final POSTMapper postAttrMapper) {
|
||||
this.uuid = modelId;
|
||||
this.institutionId = postAttrMapper.getLong(USER.ATTR_INSTITUTION_ID);
|
||||
this.newPassword = postAttrMapper.getString(PasswordChange.ATTR_NAME_NEW_PASSWORD);
|
||||
this.confirmNewPassword = postAttrMapper.getString(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD);
|
||||
this.name = postAttrMapper.getString(USER.ATTR_NAME);
|
||||
this.surname = postAttrMapper.getString(USER.ATTR_SURNAME);
|
||||
this.username = postAttrMapper.getString(USER.ATTR_USERNAME);
|
||||
this.email = postAttrMapper.getString(USER.ATTR_EMAIL);
|
||||
this.language = postAttrMapper.getLocale(USER.ATTR_LANGUAGE);
|
||||
this.timeZone = postAttrMapper.getDateTimeZone(USER.ATTR_TIMEZONE);
|
||||
this.roles = postAttrMapper.getStringSet(USER_ROLE.REFERENCE_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModelId() {
|
||||
return this.uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityType entityType() {
|
||||
return EntityType.USER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getInstitutionId() {
|
||||
return this.institutionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateTime getCreationDate() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOwnerId() {
|
||||
return this.uuid;
|
||||
}
|
||||
|
||||
public CharSequence getNewPassword() {
|
||||
return this.newPassword;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSurname() {
|
||||
return this.surname;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEmail() {
|
||||
return this.email;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale getLanguage() {
|
||||
return this.language;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateTimeZone getTimeZone() {
|
||||
return this.timeZone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getRoles() {
|
||||
return this.roles;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public EnumSet<UserRole> getUserRoles() {
|
||||
final List<UserRole> roles = getRoles()
|
||||
.stream()
|
||||
.map(r -> UserRole.valueOf(r))
|
||||
.collect(Collectors.toList());
|
||||
if (roles.isEmpty()) {
|
||||
return EnumSet.noneOf(UserRole.class);
|
||||
}
|
||||
return EnumSet.copyOf(roles);
|
||||
}
|
||||
|
||||
public CharSequence getRetypedNewPassword() {
|
||||
return this.confirmNewPassword;
|
||||
}
|
||||
|
||||
public boolean passwordChangeRequest() {
|
||||
return this.newPassword != null;
|
||||
}
|
||||
|
||||
public boolean newPasswordMatch() {
|
||||
return passwordChangeRequest() && this.newPassword.equals(this.confirmNewPassword);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getActive() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public EntityKey getEntityKey() {
|
||||
if (StringUtils.isBlank(this.uuid)) {
|
||||
return null;
|
||||
}
|
||||
return new EntityKey(this.uuid, entityType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append("UserMod [uuid=");
|
||||
builder.append(this.uuid);
|
||||
builder.append(", institutionId=");
|
||||
builder.append(this.institutionId);
|
||||
builder.append(", name=");
|
||||
builder.append(this.name);
|
||||
builder.append(", surname=");
|
||||
builder.append(this.surname);
|
||||
builder.append(", username=");
|
||||
builder.append(this.username);
|
||||
builder.append(", email=");
|
||||
builder.append(this.email);
|
||||
builder.append(", language=");
|
||||
builder.append(this.language);
|
||||
builder.append(", timeZone=");
|
||||
builder.append(this.timeZone);
|
||||
builder.append(", roles=");
|
||||
builder.append(this.roles);
|
||||
builder.append(", newPassword=");
|
||||
builder.append(this.newPassword);
|
||||
builder.append(", confirmNewPassword=");
|
||||
builder.append(this.confirmNewPassword);
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public static UserMod createNew(final Long institutionId) {
|
||||
return new UserMod(
|
||||
UUID.randomUUID().toString(),
|
||||
institutionId,
|
||||
null, null, null, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,70 +1,79 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gbl.util;
|
||||
|
||||
/** A tuple of two elements of the same type */
|
||||
public class Tuple<T> {
|
||||
|
||||
/** The first element of the tuple */
|
||||
public final T _1;
|
||||
/** The second element of the tuple */
|
||||
public final T _2;
|
||||
|
||||
public Tuple(final T _1, final T _2) {
|
||||
super();
|
||||
this._1 = _1;
|
||||
this._2 = _2;
|
||||
}
|
||||
|
||||
public T get_1() {
|
||||
return this._1;
|
||||
}
|
||||
|
||||
public T get_2() {
|
||||
return this._2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((this._1 == null) ? 0 : this._1.hashCode());
|
||||
result = prime * result + ((this._2 == null) ? 0 : this._2.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
@SuppressWarnings("rawtypes")
|
||||
final Tuple other = (Tuple) obj;
|
||||
if (this._1 == null) {
|
||||
if (other._1 != null)
|
||||
return false;
|
||||
} else if (!this._1.equals(other._1))
|
||||
return false;
|
||||
if (this._2 == null) {
|
||||
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 + ")";
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gbl.util;
|
||||
|
||||
/** A tuple of two elements of the same type */
|
||||
public class Tuple<T> {
|
||||
|
||||
/** The first element of the tuple */
|
||||
public final T _1;
|
||||
/** The second element of the tuple */
|
||||
public final T _2;
|
||||
|
||||
public Tuple(final T _1, final T _2) {
|
||||
super();
|
||||
this._1 = _1;
|
||||
this._2 = _2;
|
||||
}
|
||||
|
||||
public T get_1() {
|
||||
return this._1;
|
||||
}
|
||||
|
||||
public T get_2() {
|
||||
return this._2;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <TT extends Tuple<T>> TT adaptTo(Class<TT> type) {
|
||||
if (type.equals(this.getClass())) {
|
||||
return (TT) this;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((this._1 == null) ? 0 : this._1.hashCode());
|
||||
result = prime * result + ((this._2 == null) ? 0 : this._2.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
@SuppressWarnings("rawtypes")
|
||||
final Tuple other = (Tuple) obj;
|
||||
if (this._1 == null) {
|
||||
if (other._1 != null)
|
||||
return false;
|
||||
} else if (!this._1.equals(other._1))
|
||||
return false;
|
||||
if (this._2 == null) {
|
||||
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 + ")";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
41
src/main/java/ch/ethz/seb/sebserver/gbl/util/Tuple3.java
Normal file
41
src/main/java/ch/ethz/seb/sebserver/gbl/util/Tuple3.java
Normal 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;
|
||||
}
|
||||
}
|
|
@ -1,253 +1,257 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.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.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
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.ConfigurationNode;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.TemplateAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.TitleOrientation;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.View;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.form.FormBuilder;
|
||||
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.InputField;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
|
||||
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.i18n.LocTextKey;
|
||||
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.TemplateComposer;
|
||||
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.GetExamConfigNode;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetTemplateAttribute;
|
||||
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.widget.WidgetFactory;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class ConfigTemplateAttributeForm implements TemplateComposer {
|
||||
|
||||
private static final LocTextKey FORM_TITLE =
|
||||
new LocTextKey("sebserver.configtemplate.attr.form.title");
|
||||
private static final LocTextKey FORM_NAME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.attr.form.name");
|
||||
private static final LocTextKey FORM_TYPE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.attr.form.type");
|
||||
private static final LocTextKey FORM_VIEW_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.attr.form.view");
|
||||
private static final LocTextKey FORM_GROUP_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.attr.form.group");
|
||||
private static final LocTextKey FORM_VALUE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.attr.form.value");
|
||||
|
||||
private final PageService pageService;
|
||||
private final RestService restService;
|
||||
private final CurrentUser currentUser;
|
||||
private final ResourceService resourceService;
|
||||
private final ExamConfigurationService examConfigurationService;
|
||||
|
||||
protected ConfigTemplateAttributeForm(
|
||||
final PageService pageService,
|
||||
final RestService restService,
|
||||
final CurrentUser currentUser,
|
||||
final ExamConfigurationService examConfigurationService) {
|
||||
|
||||
this.pageService = pageService;
|
||||
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();
|
||||
|
||||
final EntityKey attributeKey = pageContext.getEntityKey();
|
||||
final EntityKey templateKey = pageContext.getParentEntityKey();
|
||||
final Long templateId = Long.valueOf(templateKey.modelId);
|
||||
|
||||
try {
|
||||
|
||||
final ConfigurationNode template = this.restService
|
||||
.getBuilder(GetExamConfigNode.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, templateKey.modelId)
|
||||
.call()
|
||||
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_NODE, error))
|
||||
.getOrThrow();
|
||||
|
||||
final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(template);
|
||||
final boolean modifyGrant = entityGrant.m();
|
||||
|
||||
// the attribute
|
||||
final TemplateAttribute attribute = this.restService.getBuilder(GetTemplateAttribute.class)
|
||||
.withURIVariable(API.PARAM_PARENT_MODEL_ID, templateKey.modelId)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, attributeKey.modelId)
|
||||
.call()
|
||||
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_NODE, error))
|
||||
.getOrThrow();
|
||||
|
||||
// the follow-up configuration
|
||||
final Configuration configuration = this.restService.getBuilder(GetConfigurations.class)
|
||||
.withQueryParam(Configuration.FILTER_ATTR_CONFIGURATION_NODE_ID, templateKey.getModelId())
|
||||
.withQueryParam(Configuration.FILTER_ATTR_FOLLOWUP, Constants.TRUE_STRING)
|
||||
.call()
|
||||
.map(Utils::toSingleton)
|
||||
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION, error))
|
||||
.getOrThrow();
|
||||
|
||||
// the default page layout with title
|
||||
final Composite content = widgetFactory.defaultPageLayout(
|
||||
pageContext.getParent(),
|
||||
FORM_TITLE);
|
||||
|
||||
final PageContext formContext = pageContext.copyOf(content);
|
||||
|
||||
final boolean hasView = attribute.getOrientation() != null;
|
||||
|
||||
this.pageService.formBuilder(formContext)
|
||||
.readonly(true) // TODO change this for next version
|
||||
.addField(FormBuilder.text(
|
||||
Domain.CONFIGURATION_ATTRIBUTE.ATTR_NAME,
|
||||
FORM_NAME_TEXT_KEY,
|
||||
attribute::getName))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.CONFIGURATION_ATTRIBUTE.ATTR_TYPE,
|
||||
FORM_TYPE_TEXT_KEY,
|
||||
() -> this.resourceService.getAttributeTypeName(attribute)))
|
||||
.addFieldIf(
|
||||
() -> hasView,
|
||||
() -> FormBuilder.singleSelection(
|
||||
Domain.ORIENTATION.ATTR_VIEW_ID,
|
||||
FORM_VIEW_TEXT_KEY,
|
||||
attribute.getViewModelId(),
|
||||
() -> this.resourceService.getViewResources(templateKey.modelId)))
|
||||
.addFieldIf(
|
||||
() -> hasView,
|
||||
() -> FormBuilder.text(
|
||||
Domain.ORIENTATION.ATTR_GROUP_ID,
|
||||
FORM_GROUP_TEXT_KEY,
|
||||
attribute.getGroupId()))
|
||||
.build();
|
||||
|
||||
final Composite valSpace = new Composite(content, SWT.NONE);
|
||||
valSpace.setLayout(new GridLayout());
|
||||
valSpace.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
|
||||
|
||||
widgetFactory.labelLocalized(
|
||||
valSpace,
|
||||
CustomVariant.TEXT_H2,
|
||||
FORM_VALUE_TEXT_KEY);
|
||||
|
||||
widgetFactory.labelSeparator(valSpace);
|
||||
|
||||
final Composite grid = new Composite(valSpace, SWT.NONE);
|
||||
grid.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
|
||||
grid.setLayout(new GridLayout(6, true));
|
||||
|
||||
final PageContext valueContext = formContext.copyOf(grid);
|
||||
|
||||
final Orientation defaultOrientation = getDefaultOrientation(attribute);
|
||||
final AttributeMapping attributeMapping = this.examConfigurationService
|
||||
.getAttributes(attribute, defaultOrientation)
|
||||
.getOrThrow();
|
||||
final ViewContext viewContext = this.examConfigurationService.createViewContext(
|
||||
valueContext,
|
||||
configuration,
|
||||
new View(-1L, "template", 10, 0, templateId),
|
||||
attributeMapping,
|
||||
1, false);
|
||||
|
||||
final InputFieldBuilder inputFieldBuilder = this.examConfigurationService.getInputFieldBuilder(
|
||||
attribute.getConfigAttribute(),
|
||||
defaultOrientation);
|
||||
|
||||
final InputField createInputField = inputFieldBuilder.createInputField(
|
||||
grid,
|
||||
attribute.getConfigAttribute(),
|
||||
viewContext);
|
||||
|
||||
viewContext.registerInputField(createInputField);
|
||||
|
||||
this.examConfigurationService.initInputFieldValues(
|
||||
configuration.id,
|
||||
Arrays.asList(viewContext));
|
||||
|
||||
this.pageService.pageActionBuilder(formContext.clearEntityKeys())
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_FORM_SET_DEFAULT)
|
||||
.withEntityKey(attributeKey)
|
||||
.withParentEntityKey(templateKey)
|
||||
.withExec(this.examConfigurationService::resetToDefaults)
|
||||
.ignoreMoveAwayFromEdit()
|
||||
.publishIf(() -> modifyGrant)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_REMOVE_VIEW)
|
||||
.withEntityKey(attributeKey)
|
||||
.withParentEntityKey(templateKey)
|
||||
.withExec(this.examConfigurationService::removeFromView)
|
||||
.ignoreMoveAwayFromEdit()
|
||||
.publishIf(() -> modifyGrant && hasView)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_ATTACH_DEFAULT_VIEW)
|
||||
.withEntityKey(attributeKey)
|
||||
.withParentEntityKey(templateKey)
|
||||
.withExec(this.examConfigurationService::attachToDefaultView)
|
||||
.ignoreMoveAwayFromEdit()
|
||||
.publishIf(() -> modifyGrant && !hasView)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_FORM_EDIT_TEMPLATE)
|
||||
.withEntityKey(templateKey)
|
||||
.ignoreMoveAwayFromEdit()
|
||||
.publish();
|
||||
|
||||
} catch (final Exception e) {
|
||||
pageContext.notifyUnexpectedError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Orientation getDefaultOrientation(final TemplateAttribute attribute) {
|
||||
return new Orientation(
|
||||
-1L,
|
||||
attribute.getConfigAttribute().id,
|
||||
attribute.templateId,
|
||||
null,
|
||||
null,
|
||||
0,
|
||||
0,
|
||||
2,
|
||||
1,
|
||||
TitleOrientation.NONE);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.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.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
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.ConfigurationNode;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.TemplateAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.TitleOrientation;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.View;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.form.FormBuilder;
|
||||
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.InputField;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
|
||||
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.i18n.LocTextKey;
|
||||
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.TemplateComposer;
|
||||
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.GetExamConfigNode;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetTemplateAttribute;
|
||||
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.widget.WidgetFactory;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class ConfigTemplateAttributeForm implements TemplateComposer {
|
||||
|
||||
private static final LocTextKey FORM_TITLE =
|
||||
new LocTextKey("sebserver.configtemplate.attr.form.title");
|
||||
private static final LocTextKey FORM_NAME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.attr.form.name");
|
||||
private static final LocTextKey FORM_TYPE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.attr.form.type");
|
||||
private static final LocTextKey FORM_VIEW_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.attr.form.view");
|
||||
private static final LocTextKey FORM_GROUP_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.attr.form.group");
|
||||
private static final LocTextKey FORM_VALUE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.attr.form.value");
|
||||
private static final LocTextKey FORM_VALUE_TOOLTIP_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.attr.form.value" + Constants.TOOLTIP_TEXT_KEY_SUFFIX);
|
||||
|
||||
private final PageService pageService;
|
||||
private final RestService restService;
|
||||
private final CurrentUser currentUser;
|
||||
private final ResourceService resourceService;
|
||||
private final ExamConfigurationService examConfigurationService;
|
||||
|
||||
protected ConfigTemplateAttributeForm(
|
||||
final PageService pageService,
|
||||
final RestService restService,
|
||||
final CurrentUser currentUser,
|
||||
final ExamConfigurationService examConfigurationService) {
|
||||
|
||||
this.pageService = pageService;
|
||||
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();
|
||||
|
||||
final EntityKey attributeKey = pageContext.getEntityKey();
|
||||
final EntityKey templateKey = pageContext.getParentEntityKey();
|
||||
final Long templateId = Long.valueOf(templateKey.modelId);
|
||||
|
||||
try {
|
||||
|
||||
final ConfigurationNode template = this.restService
|
||||
.getBuilder(GetExamConfigNode.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, templateKey.modelId)
|
||||
.call()
|
||||
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_NODE, error))
|
||||
.getOrThrow();
|
||||
|
||||
final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(template);
|
||||
final boolean modifyGrant = entityGrant.m();
|
||||
|
||||
// the attribute
|
||||
final TemplateAttribute attribute = this.restService.getBuilder(GetTemplateAttribute.class)
|
||||
.withURIVariable(API.PARAM_PARENT_MODEL_ID, templateKey.modelId)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, attributeKey.modelId)
|
||||
.call()
|
||||
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_NODE, error))
|
||||
.getOrThrow();
|
||||
|
||||
// the follow-up configuration
|
||||
final Configuration configuration = this.restService.getBuilder(GetConfigurations.class)
|
||||
.withQueryParam(Configuration.FILTER_ATTR_CONFIGURATION_NODE_ID, templateKey.getModelId())
|
||||
.withQueryParam(Configuration.FILTER_ATTR_FOLLOWUP, Constants.TRUE_STRING)
|
||||
.call()
|
||||
.map(Utils::toSingleton)
|
||||
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION, error))
|
||||
.getOrThrow();
|
||||
|
||||
// the default page layout with title
|
||||
final Composite content = widgetFactory.defaultPageLayout(
|
||||
pageContext.getParent(),
|
||||
FORM_TITLE);
|
||||
|
||||
final PageContext formContext = pageContext.copyOf(content);
|
||||
|
||||
final boolean hasView = attribute.getOrientation() != null;
|
||||
|
||||
this.pageService.formBuilder(formContext)
|
||||
.readonly(true) // TODO change this for next version
|
||||
.addField(FormBuilder.text(
|
||||
Domain.CONFIGURATION_ATTRIBUTE.ATTR_NAME,
|
||||
FORM_NAME_TEXT_KEY,
|
||||
attribute::getName))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.CONFIGURATION_ATTRIBUTE.ATTR_TYPE,
|
||||
FORM_TYPE_TEXT_KEY,
|
||||
() -> this.resourceService.getAttributeTypeName(attribute)))
|
||||
.addFieldIf(
|
||||
() -> hasView,
|
||||
() -> FormBuilder.singleSelection(
|
||||
Domain.ORIENTATION.ATTR_VIEW_ID,
|
||||
FORM_VIEW_TEXT_KEY,
|
||||
attribute.getViewModelId(),
|
||||
() -> this.resourceService.getViewResources(templateKey.modelId)))
|
||||
.addFieldIf(
|
||||
() -> hasView,
|
||||
() -> FormBuilder.text(
|
||||
Domain.ORIENTATION.ATTR_GROUP_ID,
|
||||
FORM_GROUP_TEXT_KEY,
|
||||
attribute.getGroupId()))
|
||||
.build();
|
||||
|
||||
final Composite valSpace = new Composite(content, SWT.NONE);
|
||||
valSpace.setLayout(new GridLayout());
|
||||
valSpace.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
|
||||
|
||||
widgetFactory.label(content, StringUtils.EMPTY);
|
||||
widgetFactory.labelLocalized(
|
||||
valSpace,
|
||||
CustomVariant.TEXT_H3,
|
||||
FORM_VALUE_TEXT_KEY,
|
||||
FORM_VALUE_TOOLTIP_TEXT_KEY);
|
||||
widgetFactory.labelSeparator(valSpace);
|
||||
|
||||
final Composite grid = new Composite(valSpace, SWT.NONE);
|
||||
grid.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
|
||||
grid.setLayout(new GridLayout(6, true));
|
||||
|
||||
final PageContext valueContext = formContext.copyOf(grid);
|
||||
|
||||
final Orientation defaultOrientation = getDefaultOrientation(attribute);
|
||||
final AttributeMapping attributeMapping = this.examConfigurationService
|
||||
.getAttributes(attribute, defaultOrientation)
|
||||
.getOrThrow();
|
||||
final ViewContext viewContext = this.examConfigurationService.createViewContext(
|
||||
valueContext,
|
||||
configuration,
|
||||
new View(-1L, "template", 10, 0, templateId),
|
||||
attributeMapping,
|
||||
1, false);
|
||||
|
||||
final InputFieldBuilder inputFieldBuilder = this.examConfigurationService.getInputFieldBuilder(
|
||||
attribute.getConfigAttribute(),
|
||||
defaultOrientation);
|
||||
|
||||
final InputField createInputField = inputFieldBuilder.createInputField(
|
||||
grid,
|
||||
attribute.getConfigAttribute(),
|
||||
viewContext);
|
||||
|
||||
viewContext.registerInputField(createInputField);
|
||||
|
||||
this.examConfigurationService.initInputFieldValues(
|
||||
configuration.id,
|
||||
Collections.singletonList(viewContext));
|
||||
|
||||
this.pageService.pageActionBuilder(formContext.clearEntityKeys())
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_FORM_SET_DEFAULT)
|
||||
.withEntityKey(attributeKey)
|
||||
.withParentEntityKey(templateKey)
|
||||
.withExec(this.examConfigurationService::resetToDefaults)
|
||||
.ignoreMoveAwayFromEdit()
|
||||
.publishIf(() -> modifyGrant)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_REMOVE_VIEW)
|
||||
.withEntityKey(attributeKey)
|
||||
.withParentEntityKey(templateKey)
|
||||
.withExec(this.examConfigurationService::removeFromView)
|
||||
.ignoreMoveAwayFromEdit()
|
||||
.publishIf(() -> modifyGrant && hasView)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_ATTACH_DEFAULT_VIEW)
|
||||
.withEntityKey(attributeKey)
|
||||
.withParentEntityKey(templateKey)
|
||||
.withExec(this.examConfigurationService::attachToDefaultView)
|
||||
.ignoreMoveAwayFromEdit()
|
||||
.publishIf(() -> modifyGrant && !hasView)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_FORM_EDIT_TEMPLATE)
|
||||
.withEntityKey(templateKey)
|
||||
.ignoreMoveAwayFromEdit()
|
||||
.publish();
|
||||
|
||||
} catch (final Exception e) {
|
||||
pageContext.notifyUnexpectedError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Orientation getDefaultOrientation(final TemplateAttribute attribute) {
|
||||
return new Orientation(
|
||||
-1L,
|
||||
attribute.getConfigAttribute().id,
|
||||
attribute.templateId,
|
||||
null,
|
||||
null,
|
||||
0,
|
||||
0,
|
||||
2,
|
||||
1,
|
||||
TitleOrientation.NONE);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,348 +1,362 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
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.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
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.ConfigurationStatus;
|
||||
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.user.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.form.FormBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.form.FormHandle;
|
||||
import ch.ethz.seb.sebserver.gui.service.ResourceService;
|
||||
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.LocTextKey;
|
||||
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.PageActionBuilder;
|
||||
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.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.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.SaveExamConfig;
|
||||
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.table.ColumnDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute;
|
||||
import ch.ethz.seb.sebserver.gui.table.EntityTable;
|
||||
import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class ConfigTemplateForm implements TemplateComposer {
|
||||
|
||||
private static final LocTextKey FORM_TITLE_NEW =
|
||||
new LocTextKey("sebserver.configtemplate.form.title.new");
|
||||
private static final LocTextKey FORM_TITLE =
|
||||
new LocTextKey("sebserver.configtemplate.form.title");
|
||||
private static final LocTextKey FORM_NAME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.form.name");
|
||||
private static final LocTextKey FORM_DESCRIPTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.form.description");
|
||||
private static final LocTextKey ATTRIBUTES_LIST_TITLE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.attrs.list.title");
|
||||
private static final LocTextKey ATTRIBUTES_LIST_NAME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.attrs.list.name");
|
||||
private static final LocTextKey ATTRIBUTES_LIST_VIEW_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.attrs.list.view");
|
||||
private static final LocTextKey ATTRIBUTES_LIST_GROUP_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.attrs.list.group");
|
||||
private static final LocTextKey ATTRIBUTES_LIST_TYPE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.attrs.list.type");
|
||||
private static final LocTextKey EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.attr.info.pleaseSelect");
|
||||
|
||||
private final PageService pageService;
|
||||
private final RestService restService;
|
||||
private final CurrentUser currentUser;
|
||||
private final I18nSupport i18nSupport;
|
||||
private final ResourceService resourceService;
|
||||
private final ExamConfigurationService examConfigurationService;
|
||||
|
||||
private final TableFilterAttribute nameFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, TemplateAttribute.FILTER_ATTR_NAME);
|
||||
private final TableFilterAttribute groupFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, TemplateAttribute.FILTER_ATTR_GROUP);
|
||||
|
||||
protected ConfigTemplateForm(
|
||||
final PageService pageService,
|
||||
final RestService restService,
|
||||
final CurrentUser currentUser,
|
||||
final ExamConfigurationService examConfigurationService) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.restService = restService;
|
||||
this.currentUser = currentUser;
|
||||
this.i18nSupport = pageService.getI18nSupport();
|
||||
this.resourceService = pageService.getResourceService();
|
||||
this.examConfigurationService = examConfigurationService;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
|
||||
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
|
||||
final ResourceService resourceService = this.pageService.getResourceService();
|
||||
|
||||
final UserInfo user = this.currentUser.get();
|
||||
final EntityKey entityKey = pageContext.getEntityKey();
|
||||
final boolean isNew = entityKey == null;
|
||||
|
||||
// get data or create new. Handle error if happen
|
||||
final ConfigurationNode examConfig = (isNew)
|
||||
? ConfigurationNode.createNewTemplate(user.institutionId)
|
||||
: this.restService
|
||||
.getBuilder(GetExamConfigNode.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
||||
.call()
|
||||
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_NODE, error))
|
||||
.getOrThrow();
|
||||
|
||||
final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(examConfig);
|
||||
final boolean writeGrant = entityGrant.w();
|
||||
final boolean modifyGrant = entityGrant.m();
|
||||
final boolean isReadonly = pageContext.isReadonly();
|
||||
|
||||
// new PageContext with actual EntityKey
|
||||
final PageContext formContext = pageContext
|
||||
.withEntityKey(examConfig.getEntityKey());
|
||||
|
||||
// the default page layout with interactive title
|
||||
final LocTextKey titleKey = (isNew)
|
||||
? FORM_TITLE_NEW
|
||||
: FORM_TITLE;
|
||||
final Composite content = widgetFactory.defaultPageLayout(
|
||||
formContext.getParent(),
|
||||
titleKey);
|
||||
|
||||
// The SebClientConfig form
|
||||
final FormHandle<ConfigurationNode> formHandle = this.pageService.formBuilder(
|
||||
formContext.copyOf(content))
|
||||
.readonly(isReadonly)
|
||||
.putStaticValueIf(() -> !isNew,
|
||||
Domain.CONFIGURATION_NODE.ATTR_ID,
|
||||
examConfig.getModelId())
|
||||
.putStaticValue(
|
||||
Domain.CONFIGURATION_NODE.ATTR_INSTITUTION_ID,
|
||||
String.valueOf(examConfig.getInstitutionId()))
|
||||
.putStaticValue(
|
||||
Domain.CONFIGURATION_NODE.ATTR_TYPE,
|
||||
ConfigurationType.TEMPLATE.name())
|
||||
.putStaticValue(
|
||||
Domain.CONFIGURATION_NODE.ATTR_STATUS,
|
||||
ConfigurationStatus.IN_USE.name())
|
||||
.addField(FormBuilder.text(
|
||||
Domain.CONFIGURATION_NODE.ATTR_NAME,
|
||||
FORM_NAME_TEXT_KEY,
|
||||
examConfig.name))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION,
|
||||
FORM_DESCRIPTION_TEXT_KEY,
|
||||
examConfig.description)
|
||||
.asArea())
|
||||
|
||||
.buildFor((isNew)
|
||||
? this.restService.getRestCall(NewExamConfig.class)
|
||||
: this.restService.getRestCall(SaveExamConfig.class));
|
||||
|
||||
final PageActionBuilder pageActionBuilder = this.pageService
|
||||
.pageActionBuilder(formContext.clearEntityKeys());
|
||||
|
||||
if (isReadonly) {
|
||||
|
||||
widgetFactory.label(content, "");
|
||||
widgetFactory.labelLocalizedTitle(
|
||||
content,
|
||||
ATTRIBUTES_LIST_TITLE_TEXT_KEY);
|
||||
|
||||
final TableFilterAttribute viewFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
TemplateAttribute.FILTER_ATTR_VIEW,
|
||||
() -> this.resourceService.getViewResources(entityKey.modelId));
|
||||
final TableFilterAttribute typeFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
TemplateAttribute.FILTER_ATTR_TYPE,
|
||||
() -> this.resourceService.getAttributeTypeResources());
|
||||
|
||||
final EntityTable<TemplateAttribute> attrTable =
|
||||
this.pageService.entityTableBuilder(
|
||||
Domain.CONFIGURATION_NODE.TYPE_NAME + "_Template",
|
||||
this.restService.getRestCall(GetTemplateAttributePage.class))
|
||||
.withRestCallAdapter(restCall -> restCall.withURIVariable(
|
||||
API.PARAM_PARENT_MODEL_ID,
|
||||
entityKey.modelId))
|
||||
.withPaging(15)
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.CONFIGURATION_ATTRIBUTE.ATTR_NAME,
|
||||
ATTRIBUTES_LIST_NAME_TEXT_KEY,
|
||||
this::getAttributeName)
|
||||
.withFilter(this.nameFilter)
|
||||
.sortable()
|
||||
.widthProportion(3))
|
||||
.withColumn(new ColumnDefinition<TemplateAttribute>(
|
||||
Domain.CONFIGURATION_ATTRIBUTE.ATTR_TYPE,
|
||||
ATTRIBUTES_LIST_TYPE_TEXT_KEY,
|
||||
resourceService::getAttributeTypeName)
|
||||
.withFilter(typeFilter)
|
||||
.sortable()
|
||||
.widthProportion(1))
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.ORIENTATION.ATTR_VIEW_ID,
|
||||
ATTRIBUTES_LIST_VIEW_TEXT_KEY,
|
||||
resourceService.getViewNameFunction(entityKey.modelId))
|
||||
.withFilter(viewFilter)
|
||||
.sortable()
|
||||
.widthProportion(1))
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.ORIENTATION.ATTR_GROUP_ID,
|
||||
ATTRIBUTES_LIST_GROUP_TEXT_KEY,
|
||||
TemplateAttribute::getGroupId)
|
||||
.withFilter(this.groupFilter)
|
||||
.sortable()
|
||||
.widthProportion(1))
|
||||
.withDefaultAction(pageActionBuilder
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_EDIT)
|
||||
.withParentEntityKey(entityKey)
|
||||
.create())
|
||||
.compose(pageContext.copyOf(content));
|
||||
|
||||
pageActionBuilder
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_EDIT)
|
||||
.withParentEntityKey(entityKey)
|
||||
.withSelect(
|
||||
attrTable::getSelection,
|
||||
PageAction::applySingleSelectionAsEntityKey,
|
||||
EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY)
|
||||
.publishIf(() -> attrTable.hasAnyContent())
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_SET_DEFAULT)
|
||||
.withParentEntityKey(entityKey)
|
||||
.withSelect(
|
||||
attrTable::getSelection,
|
||||
action -> this.resetToDefaults(action, attrTable),
|
||||
EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY)
|
||||
.noEventPropagation()
|
||||
.publishIf(() -> attrTable.hasAnyContent())
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_LIST_REMOVE_VIEW)
|
||||
.withParentEntityKey(entityKey)
|
||||
.withSelect(
|
||||
attrTable::getSelection,
|
||||
action -> this.removeFormView(action, attrTable),
|
||||
EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY)
|
||||
.noEventPropagation()
|
||||
.publishIf(() -> attrTable.hasAnyContent())
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_LIST_ATTACH_DEFAULT_VIEW)
|
||||
.withParentEntityKey(entityKey)
|
||||
.withSelect(
|
||||
attrTable::getSelection,
|
||||
action -> this.attachView(action, attrTable),
|
||||
EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY)
|
||||
.noEventPropagation()
|
||||
.publishIf(() -> attrTable.hasAnyContent());
|
||||
}
|
||||
|
||||
pageActionBuilder
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_NEW)
|
||||
.publishIf(() -> writeGrant && isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_MODIFY)
|
||||
.withEntityKey(entityKey)
|
||||
.publishIf(() -> modifyGrant && isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_CREATE_CONFIG)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(SebExamConfigCreationPopup.configCreationFunction(
|
||||
this.pageService,
|
||||
pageContext
|
||||
.withAttribute(
|
||||
PageContext.AttributeKeys.CREATE_FROM_TEMPLATE,
|
||||
Constants.TRUE_STRING)
|
||||
.withAttribute(
|
||||
PageContext.AttributeKeys.COPY_AS_TEMPLATE,
|
||||
Constants.FALSE_STRING)))
|
||||
.publishIf(() -> modifyGrant && isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_SAVE)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(formHandle::processFormSave)
|
||||
.ignoreMoveAwayFromEdit()
|
||||
.publishIf(() -> !isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_CANCEL_MODIFY)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(this.pageService.backToCurrentFunction())
|
||||
.publishIf(() -> !isReadonly);
|
||||
|
||||
}
|
||||
|
||||
private String getAttributeName(final TemplateAttribute attribute) {
|
||||
|
||||
final String name = this.i18nSupport.getText(
|
||||
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.getName(),
|
||||
"");
|
||||
if (StringUtils.isNotBlank(name)) {
|
||||
return attribute.getName() + " (" + name + ")";
|
||||
} else {
|
||||
return attribute.getName();
|
||||
}
|
||||
}
|
||||
|
||||
private final PageAction resetToDefaults(
|
||||
final PageAction action,
|
||||
final EntityTable<TemplateAttribute> attrTable) {
|
||||
|
||||
final PageAction resetToDefaults = this.examConfigurationService.resetToDefaults(action);
|
||||
// reload the list
|
||||
attrTable.applyFilter();
|
||||
return resetToDefaults;
|
||||
}
|
||||
|
||||
private final PageAction removeFormView(
|
||||
final PageAction action,
|
||||
final EntityTable<TemplateAttribute> attrTable) {
|
||||
|
||||
final PageAction removeFormView = this.examConfigurationService.removeFromView(action);
|
||||
// reload the list
|
||||
attrTable.applyFilter();
|
||||
return removeFormView;
|
||||
}
|
||||
|
||||
private final PageAction attachView(
|
||||
final PageAction action,
|
||||
final EntityTable<TemplateAttribute> attrTable) {
|
||||
|
||||
final PageAction attachView = this.examConfigurationService.attachToDefaultView(action);
|
||||
// reload the list
|
||||
attrTable.applyFilter();
|
||||
return attachView;
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
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.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
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.ConfigurationStatus;
|
||||
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.user.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.form.FormBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.form.FormHandle;
|
||||
import ch.ethz.seb.sebserver.gui.service.ResourceService;
|
||||
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.LocTextKey;
|
||||
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.PageActionBuilder;
|
||||
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.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.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.SaveExamConfig;
|
||||
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.table.ColumnDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute;
|
||||
import ch.ethz.seb.sebserver.gui.table.EntityTable;
|
||||
import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class ConfigTemplateForm implements TemplateComposer {
|
||||
|
||||
private static final LocTextKey FORM_TITLE_NEW =
|
||||
new LocTextKey("sebserver.configtemplate.form.title.new");
|
||||
private static final LocTextKey FORM_TITLE =
|
||||
new LocTextKey("sebserver.configtemplate.form.title");
|
||||
private static final LocTextKey FORM_NAME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.form.name");
|
||||
private static final LocTextKey FORM_DESCRIPTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.form.description");
|
||||
private static final LocTextKey ATTRIBUTES_LIST_TITLE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.attrs.list.title");
|
||||
private static final LocTextKey ATTRIBUTES_LIST_TITLE_TOOLTIP_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.attrs.list.title" + Constants.TOOLTIP_TEXT_KEY_SUFFIX);
|
||||
private static final LocTextKey ATTRIBUTES_LIST_NAME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.attrs.list.name");
|
||||
private static final LocTextKey ATTRIBUTES_LIST_VIEW_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.attrs.list.view");
|
||||
private static final LocTextKey ATTRIBUTES_LIST_GROUP_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.attrs.list.group");
|
||||
private static final LocTextKey ATTRIBUTES_LIST_TYPE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.attrs.list.type");
|
||||
private static final LocTextKey EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.attr.info.pleaseSelect");
|
||||
|
||||
private final PageService pageService;
|
||||
private final RestService restService;
|
||||
private final CurrentUser currentUser;
|
||||
private final I18nSupport i18nSupport;
|
||||
private final ResourceService resourceService;
|
||||
private final ExamConfigurationService examConfigurationService;
|
||||
|
||||
private final TableFilterAttribute nameFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, TemplateAttribute.FILTER_ATTR_NAME);
|
||||
private final TableFilterAttribute groupFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, TemplateAttribute.FILTER_ATTR_GROUP);
|
||||
|
||||
protected ConfigTemplateForm(
|
||||
final PageService pageService,
|
||||
final RestService restService,
|
||||
final CurrentUser currentUser,
|
||||
final ExamConfigurationService examConfigurationService) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.restService = restService;
|
||||
this.currentUser = currentUser;
|
||||
this.i18nSupport = pageService.getI18nSupport();
|
||||
this.resourceService = pageService.getResourceService();
|
||||
this.examConfigurationService = examConfigurationService;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
|
||||
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
|
||||
final ResourceService resourceService = this.pageService.getResourceService();
|
||||
|
||||
final UserInfo user = this.currentUser.get();
|
||||
final EntityKey entityKey = pageContext.getEntityKey();
|
||||
final boolean isNew = entityKey == null;
|
||||
|
||||
// get data or create new. Handle error if happen
|
||||
final ConfigurationNode examConfig = (isNew)
|
||||
? ConfigurationNode.createNewTemplate(user.institutionId)
|
||||
: this.restService
|
||||
.getBuilder(GetExamConfigNode.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
||||
.call()
|
||||
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_NODE, error))
|
||||
.getOrThrow();
|
||||
|
||||
final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(examConfig);
|
||||
final boolean writeGrant = entityGrant.w();
|
||||
final boolean modifyGrant = entityGrant.m();
|
||||
final boolean isReadonly = pageContext.isReadonly();
|
||||
|
||||
// new PageContext with actual EntityKey
|
||||
final PageContext formContext = pageContext
|
||||
.withEntityKey(examConfig.getEntityKey());
|
||||
|
||||
// the default page layout with interactive title
|
||||
final LocTextKey titleKey = (isNew)
|
||||
? FORM_TITLE_NEW
|
||||
: FORM_TITLE;
|
||||
final Composite content = widgetFactory.defaultPageLayout(
|
||||
formContext.getParent(),
|
||||
titleKey);
|
||||
|
||||
// The SebClientConfig form
|
||||
final FormHandle<ConfigurationNode> formHandle = this.pageService.formBuilder(
|
||||
formContext.copyOf(content))
|
||||
.readonly(isReadonly)
|
||||
.putStaticValueIf(() -> !isNew,
|
||||
Domain.CONFIGURATION_NODE.ATTR_ID,
|
||||
examConfig.getModelId())
|
||||
.putStaticValue(
|
||||
Domain.CONFIGURATION_NODE.ATTR_INSTITUTION_ID,
|
||||
String.valueOf(examConfig.getInstitutionId()))
|
||||
.putStaticValue(
|
||||
Domain.CONFIGURATION_NODE.ATTR_TYPE,
|
||||
ConfigurationType.TEMPLATE.name())
|
||||
.putStaticValue(
|
||||
Domain.CONFIGURATION_NODE.ATTR_STATUS,
|
||||
ConfigurationStatus.IN_USE.name())
|
||||
.addField(FormBuilder.text(
|
||||
Domain.CONFIGURATION_NODE.ATTR_NAME,
|
||||
FORM_NAME_TEXT_KEY,
|
||||
examConfig.name)
|
||||
.mandatory(!isReadonly))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION,
|
||||
FORM_DESCRIPTION_TEXT_KEY,
|
||||
examConfig.description)
|
||||
.asArea())
|
||||
|
||||
.buildFor((isNew)
|
||||
? this.restService.getRestCall(NewExamConfig.class)
|
||||
: this.restService.getRestCall(SaveExamConfig.class));
|
||||
|
||||
final PageActionBuilder pageActionBuilder = this.pageService
|
||||
.pageActionBuilder(formContext.clearEntityKeys());
|
||||
|
||||
if (isReadonly) {
|
||||
|
||||
widgetFactory.label(content, StringUtils.EMPTY);
|
||||
widgetFactory.labelLocalized(
|
||||
content,
|
||||
WidgetFactory.CustomVariant.TEXT_H3,
|
||||
ATTRIBUTES_LIST_TITLE_TEXT_KEY,
|
||||
ATTRIBUTES_LIST_TITLE_TOOLTIP_TEXT_KEY);
|
||||
widgetFactory.labelSeparator(content);
|
||||
|
||||
final TableFilterAttribute viewFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
TemplateAttribute.FILTER_ATTR_VIEW,
|
||||
() -> this.resourceService.getViewResources(entityKey.modelId));
|
||||
final TableFilterAttribute typeFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
TemplateAttribute.FILTER_ATTR_TYPE,
|
||||
this.resourceService::getAttributeTypeResources);
|
||||
|
||||
final EntityTable<TemplateAttribute> attrTable =
|
||||
this.pageService.entityTableBuilder(
|
||||
Domain.CONFIGURATION_NODE.TYPE_NAME + "_Template",
|
||||
this.restService.getRestCall(GetTemplateAttributePage.class))
|
||||
.withRestCallAdapter(restCall -> restCall.withURIVariable(
|
||||
API.PARAM_PARENT_MODEL_ID,
|
||||
entityKey.modelId))
|
||||
.withPaging(15)
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.CONFIGURATION_ATTRIBUTE.ATTR_NAME,
|
||||
ATTRIBUTES_LIST_NAME_TEXT_KEY,
|
||||
this::getAttributeName)
|
||||
.withFilter(this.nameFilter)
|
||||
.sortable()
|
||||
.widthProportion(3))
|
||||
.withColumn(new ColumnDefinition<TemplateAttribute>(
|
||||
Domain.CONFIGURATION_ATTRIBUTE.ATTR_TYPE,
|
||||
ATTRIBUTES_LIST_TYPE_TEXT_KEY,
|
||||
resourceService::getAttributeTypeName)
|
||||
.withFilter(typeFilter)
|
||||
.sortable()
|
||||
.widthProportion(1))
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.ORIENTATION.ATTR_VIEW_ID,
|
||||
ATTRIBUTES_LIST_VIEW_TEXT_KEY,
|
||||
resourceService.getViewNameFunction(entityKey.modelId))
|
||||
.withFilter(viewFilter)
|
||||
.sortable()
|
||||
.widthProportion(1))
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.ORIENTATION.ATTR_GROUP_ID,
|
||||
ATTRIBUTES_LIST_GROUP_TEXT_KEY,
|
||||
TemplateAttribute::getGroupId)
|
||||
.withFilter(this.groupFilter)
|
||||
.sortable()
|
||||
.widthProportion(1))
|
||||
.withDefaultAction(pageActionBuilder
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_EDIT)
|
||||
.withParentEntityKey(entityKey)
|
||||
.create())
|
||||
|
||||
.withSelectionListener(this.pageService.getSelectionPublisher(
|
||||
pageContext,
|
||||
ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_EDIT,
|
||||
ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_SET_DEFAULT,
|
||||
ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_LIST_REMOVE_VIEW,
|
||||
ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_LIST_ATTACH_DEFAULT_VIEW))
|
||||
|
||||
.compose(pageContext.copyOf(content));
|
||||
|
||||
pageActionBuilder
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_EDIT)
|
||||
.withParentEntityKey(entityKey)
|
||||
.withSelect(
|
||||
attrTable::getSelection,
|
||||
PageAction::applySingleSelectionAsEntityKey,
|
||||
EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY)
|
||||
.publishIf(attrTable::hasAnyContent, false)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_SET_DEFAULT)
|
||||
.withParentEntityKey(entityKey)
|
||||
.withSelect(
|
||||
attrTable::getSelection,
|
||||
action -> this.resetToDefaults(action, attrTable),
|
||||
EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY)
|
||||
.noEventPropagation()
|
||||
.publishIf(attrTable::hasAnyContent, false)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_LIST_REMOVE_VIEW)
|
||||
.withParentEntityKey(entityKey)
|
||||
.withSelect(
|
||||
attrTable::getSelection,
|
||||
action -> this.removeFormView(action, attrTable),
|
||||
EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY)
|
||||
.noEventPropagation()
|
||||
.publishIf(attrTable::hasAnyContent, false)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_LIST_ATTACH_DEFAULT_VIEW)
|
||||
.withParentEntityKey(entityKey)
|
||||
.withSelect(
|
||||
attrTable::getSelection,
|
||||
action -> this.attachView(action, attrTable),
|
||||
EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY)
|
||||
.noEventPropagation()
|
||||
.publishIf(attrTable::hasAnyContent, false);
|
||||
}
|
||||
|
||||
pageActionBuilder
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_NEW)
|
||||
.publishIf(() -> writeGrant && isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_MODIFY)
|
||||
.withEntityKey(entityKey)
|
||||
.publishIf(() -> modifyGrant && isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_CREATE_CONFIG)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(SebExamConfigCreationPopup.configCreationFunction(
|
||||
this.pageService,
|
||||
pageContext
|
||||
.withAttribute(
|
||||
PageContext.AttributeKeys.CREATE_FROM_TEMPLATE,
|
||||
Constants.TRUE_STRING)
|
||||
.withAttribute(
|
||||
PageContext.AttributeKeys.COPY_AS_TEMPLATE,
|
||||
Constants.FALSE_STRING)))
|
||||
.publishIf(() -> modifyGrant && isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_SAVE)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(formHandle::processFormSave)
|
||||
.ignoreMoveAwayFromEdit()
|
||||
.publishIf(() -> !isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_CANCEL_MODIFY)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(this.pageService.backToCurrentFunction())
|
||||
.publishIf(() -> !isReadonly);
|
||||
|
||||
}
|
||||
|
||||
private String getAttributeName(final TemplateAttribute attribute) {
|
||||
|
||||
final String name = this.i18nSupport.getText(
|
||||
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.getName(),
|
||||
"");
|
||||
if (StringUtils.isNotBlank(name)) {
|
||||
return attribute.getName() + " (" + name + ")";
|
||||
} else {
|
||||
return attribute.getName();
|
||||
}
|
||||
}
|
||||
|
||||
private PageAction resetToDefaults(
|
||||
final PageAction action,
|
||||
final EntityTable<TemplateAttribute> attrTable) {
|
||||
|
||||
final PageAction resetToDefaults = this.examConfigurationService.resetToDefaults(action);
|
||||
// reload the list
|
||||
attrTable.applyFilter();
|
||||
return resetToDefaults;
|
||||
}
|
||||
|
||||
private PageAction removeFormView(
|
||||
final PageAction action,
|
||||
final EntityTable<TemplateAttribute> attrTable) {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,155 +1,159 @@
|
|||
/*
|
||||
* 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.gui.content;
|
||||
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
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.model.Entity;
|
||||
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.user.UserRole;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.service.ResourceService;
|
||||
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.PageService;
|
||||
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.impl.PageAction;
|
||||
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.auth.CurrentUser;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute;
|
||||
import ch.ethz.seb.sebserver.gui.table.EntityTable;
|
||||
import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class ConfigTemplateList implements TemplateComposer {
|
||||
|
||||
private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION =
|
||||
new LocTextKey("sebserver.examconfig.list.action.no.modify.privilege");
|
||||
private static final LocTextKey TITLE_TEMPLATE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.list.title");
|
||||
private static final LocTextKey EMPTY_TEMPLATE_LIST_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.list.empty");
|
||||
private static final LocTextKey INSTITUTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.list.column.institution");
|
||||
private static final LocTextKey NAME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.list.column.name");
|
||||
private static final LocTextKey DESCRIPTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.list.column.description");
|
||||
private static final LocTextKey EMPTY_TEMPLATE_SELECTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.info.pleaseSelect");
|
||||
|
||||
private final PageService pageService;
|
||||
private final RestService restService;
|
||||
private final CurrentUser currentUser;
|
||||
private final ResourceService resourceService;
|
||||
private final int pageSize;
|
||||
|
||||
private final TableFilterAttribute institutionFilter;
|
||||
private final TableFilterAttribute nameFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, Entity.FILTER_ATTR_NAME);
|
||||
private final TableFilterAttribute descFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, ConfigurationNode.FILTER_ATTR_DESCRIPTION);
|
||||
|
||||
protected ConfigTemplateList(
|
||||
final PageService pageService,
|
||||
final RestService restService,
|
||||
final CurrentUser currentUser,
|
||||
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.restService = restService;
|
||||
this.currentUser = currentUser;
|
||||
this.resourceService = pageService.getResourceService();
|
||||
this.pageSize = pageSize;
|
||||
|
||||
this.institutionFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
Entity.FILTER_ATTR_INSTITUTION,
|
||||
this.resourceService::institutionResource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
|
||||
final Composite content = widgetFactory.defaultPageLayout(
|
||||
pageContext.getParent(),
|
||||
TITLE_TEMPLATE_TEXT_KEY);
|
||||
|
||||
final boolean isSEBAdmin = this.currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN);
|
||||
final PageActionBuilder pageActionBuilder =
|
||||
this.pageService.pageActionBuilder(pageContext.clearEntityKeys());
|
||||
|
||||
final EntityTable<ConfigurationNode> templateTable =
|
||||
this.pageService.entityTableBuilder(
|
||||
TITLE_TEMPLATE_TEXT_KEY.name,
|
||||
this.restService.getRestCall(GetExamConfigNodePage.class))
|
||||
.withStaticFilter(
|
||||
Domain.CONFIGURATION_NODE.ATTR_TYPE,
|
||||
ConfigurationType.TEMPLATE.name())
|
||||
.withEmptyMessage(EMPTY_TEMPLATE_LIST_TEXT_KEY)
|
||||
.withPaging(this.pageSize)
|
||||
.withColumnIf(
|
||||
() -> isSEBAdmin,
|
||||
() -> new ColumnDefinition<>(
|
||||
Domain.LMS_SETUP.ATTR_INSTITUTION_ID,
|
||||
INSTITUTION_TEXT_KEY,
|
||||
this.resourceService::localizedExamConfigInstitutionName)
|
||||
.withFilter(this.institutionFilter)
|
||||
.sortable())
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.CONFIGURATION_NODE.ATTR_NAME,
|
||||
NAME_TEXT_KEY,
|
||||
ConfigurationNode::getName)
|
||||
.withFilter(this.nameFilter)
|
||||
.sortable())
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION,
|
||||
DESCRIPTION_TEXT_KEY,
|
||||
ConfigurationNode::getDescription)
|
||||
.withFilter(this.descFilter)
|
||||
.sortable())
|
||||
.withDefaultAction(pageActionBuilder
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_VIEW_FROM_LIST)
|
||||
.create())
|
||||
.compose(pageContext.copyOf(content));
|
||||
|
||||
final GrantCheck examConfigGrant = this.currentUser.grantCheck(EntityType.CONFIGURATION_NODE);
|
||||
pageActionBuilder
|
||||
// Exam Configuration template actions...
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_NEW)
|
||||
.publishIf(examConfigGrant::iw)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_VIEW_FROM_LIST)
|
||||
.withSelect(templateTable::getSelection, PageAction::applySingleSelectionAsEntityKey,
|
||||
EMPTY_TEMPLATE_SELECTION_TEXT_KEY)
|
||||
.publishIf(() -> templateTable.hasAnyContent())
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_MODIFY_FROM_LIST)
|
||||
.withSelect(
|
||||
templateTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION),
|
||||
PageAction::applySingleSelectionAsEntityKey, EMPTY_TEMPLATE_SELECTION_TEXT_KEY)
|
||||
.publishIf(() -> examConfigGrant.im() && templateTable.hasAnyContent());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.gui.content;
|
||||
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
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.model.Entity;
|
||||
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.user.UserRole;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.service.ResourceService;
|
||||
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.PageService;
|
||||
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.impl.PageAction;
|
||||
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.auth.CurrentUser;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute;
|
||||
import ch.ethz.seb.sebserver.gui.table.EntityTable;
|
||||
import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class ConfigTemplateList implements TemplateComposer {
|
||||
|
||||
private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION =
|
||||
new LocTextKey("sebserver.examconfig.list.action.no.modify.privilege");
|
||||
private static final LocTextKey TITLE_TEMPLATE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.list.title");
|
||||
private static final LocTextKey EMPTY_TEMPLATE_LIST_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.list.empty");
|
||||
private static final LocTextKey INSTITUTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.list.column.institution");
|
||||
private static final LocTextKey NAME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.list.column.name");
|
||||
private static final LocTextKey DESCRIPTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.list.column.description");
|
||||
private static final LocTextKey EMPTY_TEMPLATE_SELECTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.configtemplate.info.pleaseSelect");
|
||||
|
||||
private final PageService pageService;
|
||||
private final RestService restService;
|
||||
private final CurrentUser currentUser;
|
||||
private final ResourceService resourceService;
|
||||
private final int pageSize;
|
||||
|
||||
private final TableFilterAttribute institutionFilter;
|
||||
private final TableFilterAttribute nameFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, Entity.FILTER_ATTR_NAME);
|
||||
private final TableFilterAttribute descFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, ConfigurationNode.FILTER_ATTR_DESCRIPTION);
|
||||
|
||||
protected ConfigTemplateList(
|
||||
final PageService pageService,
|
||||
final RestService restService,
|
||||
final CurrentUser currentUser,
|
||||
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.restService = restService;
|
||||
this.currentUser = currentUser;
|
||||
this.resourceService = pageService.getResourceService();
|
||||
this.pageSize = pageSize;
|
||||
|
||||
this.institutionFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
Entity.FILTER_ATTR_INSTITUTION,
|
||||
this.resourceService::institutionResource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
|
||||
final Composite content = widgetFactory.defaultPageLayout(
|
||||
pageContext.getParent(),
|
||||
TITLE_TEMPLATE_TEXT_KEY);
|
||||
|
||||
final boolean isSEBAdmin = this.currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN);
|
||||
final PageActionBuilder pageActionBuilder =
|
||||
this.pageService.pageActionBuilder(pageContext.clearEntityKeys());
|
||||
|
||||
final EntityTable<ConfigurationNode> templateTable =
|
||||
this.pageService.entityTableBuilder(
|
||||
TITLE_TEMPLATE_TEXT_KEY.name,
|
||||
this.restService.getRestCall(GetExamConfigNodePage.class))
|
||||
.withStaticFilter(
|
||||
Domain.CONFIGURATION_NODE.ATTR_TYPE,
|
||||
ConfigurationType.TEMPLATE.name())
|
||||
.withEmptyMessage(EMPTY_TEMPLATE_LIST_TEXT_KEY)
|
||||
.withPaging(this.pageSize)
|
||||
.withColumnIf(
|
||||
() -> isSEBAdmin,
|
||||
() -> new ColumnDefinition<>(
|
||||
Domain.LMS_SETUP.ATTR_INSTITUTION_ID,
|
||||
INSTITUTION_TEXT_KEY,
|
||||
this.resourceService::localizedExamConfigInstitutionName)
|
||||
.withFilter(this.institutionFilter)
|
||||
.sortable())
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.CONFIGURATION_NODE.ATTR_NAME,
|
||||
NAME_TEXT_KEY,
|
||||
ConfigurationNode::getName)
|
||||
.withFilter(this.nameFilter)
|
||||
.sortable())
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION,
|
||||
DESCRIPTION_TEXT_KEY,
|
||||
ConfigurationNode::getDescription)
|
||||
.withFilter(this.descFilter)
|
||||
.sortable())
|
||||
.withDefaultAction(pageActionBuilder
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_VIEW_FROM_LIST)
|
||||
.create())
|
||||
|
||||
.withSelectionListener(this.pageService.getSelectionPublisher(
|
||||
pageContext,
|
||||
ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_VIEW_FROM_LIST,
|
||||
ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_MODIFY_FROM_LIST))
|
||||
|
||||
.compose(pageContext.copyOf(content));
|
||||
|
||||
final GrantCheck examConfigGrant = this.currentUser.grantCheck(EntityType.CONFIGURATION_NODE);
|
||||
pageActionBuilder
|
||||
// Exam Configuration template actions...
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_NEW)
|
||||
.publishIf(examConfigGrant::iw)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_VIEW_FROM_LIST)
|
||||
.withSelect(templateTable::getSelection, PageAction::applySingleSelectionAsEntityKey,
|
||||
EMPTY_TEMPLATE_SELECTION_TEXT_KEY)
|
||||
.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
|
@ -1,172 +1,167 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.form.FormBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.form.FormHandle;
|
||||
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.PageService;
|
||||
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.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.DeactivateInstitution;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitution;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.NewInstitution;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.SaveInstitution;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.EntityGrantCheck;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class InstitutionForm implements TemplateComposer {
|
||||
|
||||
private static final LocTextKey TITLE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.institution.form.title");
|
||||
private static final LocTextKey NEW_TITLE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.institution.form.title.new");
|
||||
|
||||
private static final LocTextKey FORM_LOGO_IMAGE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.institution.form.logoImage");
|
||||
private static final LocTextKey FORM_URL_SUFFIX_TEXT_KEY =
|
||||
new LocTextKey("sebserver.institution.form.urlSuffix");
|
||||
private static final LocTextKey FORM_NAME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.institution.form.name");
|
||||
|
||||
private final PageService pageService;
|
||||
private final RestService restService;
|
||||
private final CurrentUser currentUser;
|
||||
|
||||
protected InstitutionForm(
|
||||
final PageService pageService,
|
||||
final RestService restService,
|
||||
final CurrentUser currentUser) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.restService = restService;
|
||||
this.currentUser = currentUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
|
||||
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
|
||||
final EntityKey entityKey = pageContext.getEntityKey();
|
||||
final boolean isNew = entityKey == null;
|
||||
// get data or create new. Handle error if happen
|
||||
final Institution institution = (isNew)
|
||||
? Institution.createNew()
|
||||
: this.restService
|
||||
.getBuilder(GetInstitution.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
||||
.call()
|
||||
.onError(error -> pageContext.notifyLoadError(EntityType.INSTITUTION, error))
|
||||
.getOrThrow();
|
||||
|
||||
final EntityGrantCheck instGrant = this.currentUser.entityGrantCheck(institution);
|
||||
final boolean writeGrant = instGrant.w();
|
||||
final boolean modifyGrant = instGrant.m();
|
||||
final boolean isReadonly = pageContext.isReadonly();
|
||||
|
||||
// new PageContext with actual EntityKey
|
||||
final PageContext formContext = pageContext.withEntityKey(institution.getEntityKey());
|
||||
|
||||
// the default page layout with interactive title
|
||||
final LocTextKey titleKey = isNew
|
||||
? NEW_TITLE_TEXT_KEY
|
||||
: TITLE_TEXT_KEY;
|
||||
final Composite content = widgetFactory.defaultPageLayout(
|
||||
formContext.getParent(),
|
||||
titleKey);
|
||||
|
||||
// The Institution form
|
||||
final FormHandle<Institution> formHandle = this.pageService.formBuilder(
|
||||
formContext.copyOf(content))
|
||||
.readonly(isReadonly)
|
||||
.putStaticValueIf(() -> !isNew,
|
||||
Domain.INSTITUTION.ATTR_ID,
|
||||
institution.getModelId())
|
||||
.addField(FormBuilder.text(
|
||||
Domain.INSTITUTION.ATTR_NAME,
|
||||
FORM_NAME_TEXT_KEY,
|
||||
institution.name)
|
||||
.mandatory(!isReadonly))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.INSTITUTION.ATTR_URL_SUFFIX,
|
||||
FORM_URL_SUFFIX_TEXT_KEY,
|
||||
institution.urlSuffix))
|
||||
.addField(FormBuilder.imageUpload(
|
||||
Domain.INSTITUTION.ATTR_LOGO_IMAGE,
|
||||
FORM_LOGO_IMAGE_TEXT_KEY,
|
||||
institution.logoImage)
|
||||
.withMaxWidth(DefaultPageLayout.LOGO_IMAGE_MAX_WIDTH)
|
||||
.withMaxHeight(DefaultPageLayout.LOGO_IMAGE_MAX_HEIGHT))
|
||||
.buildFor((isNew)
|
||||
? this.restService.getRestCall(NewInstitution.class)
|
||||
: this.restService.getRestCall(SaveInstitution.class));
|
||||
|
||||
// propagate content actions to action-pane
|
||||
this.pageService.pageActionBuilder(formContext.clearEntityKeys())
|
||||
|
||||
.newAction(ActionDefinition.INSTITUTION_NEW)
|
||||
.publishIf(() -> writeGrant && isReadonly)
|
||||
|
||||
// Removed as discussed in SEBSERV-52
|
||||
// .newAction(ActionDefinition.USER_ACCOUNT_NEW)
|
||||
// .withParentEntityKey(entityKey)
|
||||
// .publishIf(() -> userWriteGrant && isReadonly && institution.isActive())
|
||||
|
||||
.newAction(ActionDefinition.INSTITUTION_MODIFY)
|
||||
.withEntityKey(entityKey)
|
||||
.publishIf(() -> modifyGrant && isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.INSTITUTION_DEACTIVATE)
|
||||
.withEntityKey(entityKey)
|
||||
.withSimpleRestCall(this.restService, DeactivateInstitution.class)
|
||||
.withConfirm(this.pageService.confirmDeactivation(institution))
|
||||
.publishIf(() -> writeGrant && isReadonly && institution.isActive())
|
||||
|
||||
.newAction(ActionDefinition.INSTITUTION_ACTIVATE)
|
||||
.withEntityKey(entityKey)
|
||||
.withSimpleRestCall(this.restService, ActivateInstitution.class)
|
||||
.publishIf(() -> writeGrant && isReadonly && !institution.isActive())
|
||||
|
||||
.newAction(ActionDefinition.INSTITUTION_SAVE)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(formHandle::processFormSave)
|
||||
.ignoreMoveAwayFromEdit()
|
||||
.publishIf(() -> !isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.INSTITUTION_SAVE_AND_ACTIVATE)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(formHandle::saveAndActivate)
|
||||
.ignoreMoveAwayFromEdit()
|
||||
.publishIf(() -> !isReadonly && !institution.isActive())
|
||||
|
||||
.newAction(ActionDefinition.INSTITUTION_CANCEL_MODIFY)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(this.pageService.backToCurrentFunction())
|
||||
.publishIf(() -> !isReadonly);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.form.FormBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.form.FormHandle;
|
||||
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.PageService;
|
||||
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.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.DeactivateInstitution;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitution;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.NewInstitution;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.SaveInstitution;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.EntityGrantCheck;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class InstitutionForm implements TemplateComposer {
|
||||
|
||||
private static final LocTextKey TITLE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.institution.form.title");
|
||||
private static final LocTextKey NEW_TITLE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.institution.form.title.new");
|
||||
|
||||
private static final LocTextKey FORM_LOGO_IMAGE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.institution.form.logoImage");
|
||||
private static final LocTextKey FORM_URL_SUFFIX_TEXT_KEY =
|
||||
new LocTextKey("sebserver.institution.form.urlSuffix");
|
||||
private static final LocTextKey FORM_NAME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.institution.form.name");
|
||||
|
||||
private final PageService pageService;
|
||||
private final RestService restService;
|
||||
private final CurrentUser currentUser;
|
||||
|
||||
protected InstitutionForm(
|
||||
final PageService pageService,
|
||||
final RestService restService,
|
||||
final CurrentUser currentUser) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.restService = restService;
|
||||
this.currentUser = currentUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
|
||||
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
|
||||
final EntityKey entityKey = pageContext.getEntityKey();
|
||||
final boolean isNew = entityKey == null;
|
||||
// get data or create new. Handle error if happen
|
||||
final Institution institution = (isNew)
|
||||
? Institution.createNew()
|
||||
: this.restService
|
||||
.getBuilder(GetInstitution.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
||||
.call()
|
||||
.onError(error -> pageContext.notifyLoadError(EntityType.INSTITUTION, error))
|
||||
.getOrThrow();
|
||||
|
||||
final EntityGrantCheck instGrant = this.currentUser.entityGrantCheck(institution);
|
||||
final boolean writeGrant = instGrant.w();
|
||||
final boolean modifyGrant = instGrant.m();
|
||||
final boolean isReadonly = pageContext.isReadonly();
|
||||
|
||||
// new PageContext with actual EntityKey
|
||||
final PageContext formContext = pageContext.withEntityKey(institution.getEntityKey());
|
||||
|
||||
// the default page layout with interactive title
|
||||
final LocTextKey titleKey = isNew
|
||||
? NEW_TITLE_TEXT_KEY
|
||||
: TITLE_TEXT_KEY;
|
||||
final Composite content = widgetFactory.defaultPageLayout(
|
||||
formContext.getParent(),
|
||||
titleKey);
|
||||
|
||||
// The Institution form
|
||||
final FormHandle<Institution> formHandle = this.pageService.formBuilder(
|
||||
formContext.copyOf(content))
|
||||
.readonly(isReadonly)
|
||||
.putStaticValueIf(() -> !isNew,
|
||||
Domain.INSTITUTION.ATTR_ID,
|
||||
institution.getModelId())
|
||||
.addField(FormBuilder.text(
|
||||
Domain.INSTITUTION.ATTR_NAME,
|
||||
FORM_NAME_TEXT_KEY,
|
||||
institution.name)
|
||||
.mandatory(!isReadonly))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.INSTITUTION.ATTR_URL_SUFFIX,
|
||||
FORM_URL_SUFFIX_TEXT_KEY,
|
||||
institution.urlSuffix))
|
||||
.addField(FormBuilder.imageUpload(
|
||||
Domain.INSTITUTION.ATTR_LOGO_IMAGE,
|
||||
FORM_LOGO_IMAGE_TEXT_KEY,
|
||||
institution.logoImage)
|
||||
.withMaxWidth(DefaultPageLayout.LOGO_IMAGE_MAX_WIDTH)
|
||||
.withMaxHeight(DefaultPageLayout.LOGO_IMAGE_MAX_HEIGHT))
|
||||
.buildFor((isNew)
|
||||
? this.restService.getRestCall(NewInstitution.class)
|
||||
: this.restService.getRestCall(SaveInstitution.class));
|
||||
|
||||
// propagate content actions to action-pane
|
||||
this.pageService.pageActionBuilder(formContext.clearEntityKeys())
|
||||
|
||||
.newAction(ActionDefinition.INSTITUTION_NEW)
|
||||
.publishIf(() -> writeGrant && isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.INSTITUTION_MODIFY)
|
||||
.withEntityKey(entityKey)
|
||||
.publishIf(() -> modifyGrant && isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.INSTITUTION_DEACTIVATE)
|
||||
.withEntityKey(entityKey)
|
||||
.withSimpleRestCall(this.restService, DeactivateInstitution.class)
|
||||
.withConfirm(this.pageService.confirmDeactivation(institution))
|
||||
.publishIf(() -> writeGrant && isReadonly && institution.isActive())
|
||||
|
||||
.newAction(ActionDefinition.INSTITUTION_ACTIVATE)
|
||||
.withEntityKey(entityKey)
|
||||
.withSimpleRestCall(this.restService, ActivateInstitution.class)
|
||||
.publishIf(() -> writeGrant && isReadonly && !institution.isActive())
|
||||
|
||||
.newAction(ActionDefinition.INSTITUTION_SAVE)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(formHandle::processFormSave)
|
||||
.ignoreMoveAwayFromEdit()
|
||||
.publishIf(() -> !isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.INSTITUTION_SAVE_AND_ACTIVATE)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(formHandle::saveAndActivate)
|
||||
.ignoreMoveAwayFromEdit()
|
||||
.publishIf(() -> !isReadonly && !institution.isActive())
|
||||
|
||||
.newAction(ActionDefinition.INSTITUTION_CANCEL_MODIFY)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(this.pageService.backToCurrentFunction())
|
||||
.publishIf(() -> !isReadonly);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,158 +1,158 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
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.model.Entity;
|
||||
import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
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.PageService;
|
||||
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.impl.PageAction;
|
||||
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.auth.CurrentUser;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute;
|
||||
import ch.ethz.seb.sebserver.gui.table.EntityTable;
|
||||
import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class InstitutionList implements TemplateComposer {
|
||||
|
||||
private static final LocTextKey EMPTY_LIST_TEXT_KEY =
|
||||
new LocTextKey("sebserver.institution.list.empty");
|
||||
private static final LocTextKey TITLE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.institution.list.title");
|
||||
private static final LocTextKey NAME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.institution.list.column.name");
|
||||
private static final LocTextKey URL_TEXT_KEY =
|
||||
new LocTextKey("sebserver.institution.list.column.urlSuffix");
|
||||
private static final LocTextKey ACTIVE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.institution.list.column.active");
|
||||
private static final LocTextKey EMPTY_SELECTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.institution.info.pleaseSelect");
|
||||
|
||||
private final TableFilterAttribute nameFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, Entity.FILTER_ATTR_NAME);
|
||||
private final TableFilterAttribute urlSuffixFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, Institution.FILTER_ATTR_URL_SUFFIX);
|
||||
private final TableFilterAttribute activityFilter;
|
||||
|
||||
private final PageService pageService;
|
||||
private final RestService restService;
|
||||
private final CurrentUser currentUser;
|
||||
private final int pageSize;
|
||||
|
||||
protected InstitutionList(
|
||||
final PageService pageService,
|
||||
final RestService restService,
|
||||
final CurrentUser currentUser,
|
||||
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.restService = restService;
|
||||
this.currentUser = currentUser;
|
||||
this.pageSize = pageSize;
|
||||
|
||||
this.activityFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
Institution.FILTER_ATTR_ACTIVE,
|
||||
StringUtils.EMPTY,
|
||||
this.pageService.getResourceService()::activityResources);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
final Composite content = this.pageService.getWidgetFactory().defaultPageLayout(
|
||||
pageContext.getParent(),
|
||||
TITLE_TEXT_KEY);
|
||||
|
||||
final PageActionBuilder pageActionBuilder =
|
||||
this.pageService.pageActionBuilder(pageContext.clearEntityKeys());
|
||||
|
||||
// table
|
||||
final EntityTable<Institution> table =
|
||||
this.pageService.entityTableBuilder(this.restService.getRestCall(GetInstitutionPage.class))
|
||||
.withEmptyMessage(EMPTY_LIST_TEXT_KEY)
|
||||
.withPaging(this.pageSize)
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.INSTITUTION.ATTR_NAME,
|
||||
NAME_TEXT_KEY,
|
||||
Institution::getName)
|
||||
.sortable()
|
||||
.withFilter(this.nameFilter))
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.INSTITUTION.ATTR_URL_SUFFIX,
|
||||
URL_TEXT_KEY,
|
||||
Institution::getUrlSuffix)
|
||||
.sortable()
|
||||
.withFilter(this.urlSuffixFilter))
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.INSTITUTION.ATTR_ACTIVE,
|
||||
ACTIVE_TEXT_KEY,
|
||||
this.pageService.getResourceService().<Institution> localizedActivityFunction())
|
||||
.sortable()
|
||||
.withFilter(this.activityFilter))
|
||||
.withDefaultAction(pageActionBuilder
|
||||
.newAction(ActionDefinition.INSTITUTION_VIEW_FROM_LIST)
|
||||
.create())
|
||||
.withSelectionListener(this.pageService.getSelectionPublisher(
|
||||
ActionDefinition.INSTITUTION_TOGGLE_ACTIVITY,
|
||||
ActionDefinition.INSTITUTION_ACTIVATE,
|
||||
ActionDefinition.INSTITUTION_DEACTIVATE,
|
||||
pageContext,
|
||||
ActionDefinition.INSTITUTION_VIEW_FROM_LIST,
|
||||
ActionDefinition.INSTITUTION_MODIFY_FROM_LIST,
|
||||
ActionDefinition.INSTITUTION_TOGGLE_ACTIVITY))
|
||||
.compose(pageContext.copyOf(content));
|
||||
|
||||
// propagate content actions to action-pane
|
||||
final GrantCheck instGrant = this.currentUser.grantCheck(EntityType.INSTITUTION);
|
||||
|
||||
pageActionBuilder
|
||||
|
||||
.newAction(ActionDefinition.INSTITUTION_NEW)
|
||||
.publishIf(instGrant::w)
|
||||
|
||||
.newAction(ActionDefinition.INSTITUTION_VIEW_FROM_LIST)
|
||||
.withSelect(
|
||||
table::getSelection,
|
||||
PageAction::applySingleSelectionAsEntityKey,
|
||||
EMPTY_SELECTION_TEXT_KEY)
|
||||
.publishIf(() -> table.hasAnyContent(), false)
|
||||
|
||||
.newAction(ActionDefinition.INSTITUTION_MODIFY_FROM_LIST)
|
||||
.withSelect(
|
||||
table::getSelection,
|
||||
PageAction::applySingleSelectionAsEntityKey,
|
||||
EMPTY_SELECTION_TEXT_KEY)
|
||||
.publishIf(() -> instGrant.m() && table.hasAnyContent(), false)
|
||||
|
||||
.newAction(ActionDefinition.INSTITUTION_TOGGLE_ACTIVITY)
|
||||
.withExec(this.pageService.activationToggleActionFunction(table, EMPTY_SELECTION_TEXT_KEY))
|
||||
.withConfirm(this.pageService.confirmDeactivation(table))
|
||||
.publishIf(() -> instGrant.m() && table.hasAnyContent(), false);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
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.model.Entity;
|
||||
import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
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.PageService;
|
||||
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.impl.PageAction;
|
||||
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.auth.CurrentUser;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute;
|
||||
import ch.ethz.seb.sebserver.gui.table.EntityTable;
|
||||
import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class InstitutionList implements TemplateComposer {
|
||||
|
||||
private static final LocTextKey EMPTY_LIST_TEXT_KEY =
|
||||
new LocTextKey("sebserver.institution.list.empty");
|
||||
private static final LocTextKey TITLE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.institution.list.title");
|
||||
private static final LocTextKey NAME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.institution.list.column.name");
|
||||
private static final LocTextKey URL_TEXT_KEY =
|
||||
new LocTextKey("sebserver.institution.list.column.urlSuffix");
|
||||
private static final LocTextKey ACTIVE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.institution.list.column.active");
|
||||
private static final LocTextKey EMPTY_SELECTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.institution.info.pleaseSelect");
|
||||
|
||||
private final TableFilterAttribute nameFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, Entity.FILTER_ATTR_NAME);
|
||||
private final TableFilterAttribute urlSuffixFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, Institution.FILTER_ATTR_URL_SUFFIX);
|
||||
private final TableFilterAttribute activityFilter;
|
||||
|
||||
private final PageService pageService;
|
||||
private final RestService restService;
|
||||
private final CurrentUser currentUser;
|
||||
private final int pageSize;
|
||||
|
||||
protected InstitutionList(
|
||||
final PageService pageService,
|
||||
final RestService restService,
|
||||
final CurrentUser currentUser,
|
||||
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.restService = restService;
|
||||
this.currentUser = currentUser;
|
||||
this.pageSize = pageSize;
|
||||
|
||||
this.activityFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
Institution.FILTER_ATTR_ACTIVE,
|
||||
StringUtils.EMPTY,
|
||||
this.pageService.getResourceService()::activityResources);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
final Composite content = this.pageService.getWidgetFactory().defaultPageLayout(
|
||||
pageContext.getParent(),
|
||||
TITLE_TEXT_KEY);
|
||||
|
||||
final PageActionBuilder pageActionBuilder =
|
||||
this.pageService.pageActionBuilder(pageContext.clearEntityKeys());
|
||||
|
||||
// table
|
||||
final EntityTable<Institution> table =
|
||||
this.pageService.entityTableBuilder(this.restService.getRestCall(GetInstitutionPage.class))
|
||||
.withEmptyMessage(EMPTY_LIST_TEXT_KEY)
|
||||
.withPaging(this.pageSize)
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.INSTITUTION.ATTR_NAME,
|
||||
NAME_TEXT_KEY,
|
||||
Institution::getName)
|
||||
.sortable()
|
||||
.withFilter(this.nameFilter))
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.INSTITUTION.ATTR_URL_SUFFIX,
|
||||
URL_TEXT_KEY,
|
||||
Institution::getUrlSuffix)
|
||||
.sortable()
|
||||
.withFilter(this.urlSuffixFilter))
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.INSTITUTION.ATTR_ACTIVE,
|
||||
ACTIVE_TEXT_KEY,
|
||||
this.pageService.getResourceService().<Institution> localizedActivityFunction())
|
||||
.sortable()
|
||||
.withFilter(this.activityFilter))
|
||||
.withDefaultAction(pageActionBuilder
|
||||
.newAction(ActionDefinition.INSTITUTION_VIEW_FROM_LIST)
|
||||
.create())
|
||||
.withSelectionListener(this.pageService.getSelectionPublisher(
|
||||
ActionDefinition.INSTITUTION_TOGGLE_ACTIVITY,
|
||||
ActionDefinition.INSTITUTION_ACTIVATE,
|
||||
ActionDefinition.INSTITUTION_DEACTIVATE,
|
||||
pageContext,
|
||||
ActionDefinition.INSTITUTION_VIEW_FROM_LIST,
|
||||
ActionDefinition.INSTITUTION_MODIFY_FROM_LIST,
|
||||
ActionDefinition.INSTITUTION_TOGGLE_ACTIVITY))
|
||||
.compose(pageContext.copyOf(content));
|
||||
|
||||
// propagate content actions to action-pane
|
||||
final GrantCheck instGrant = this.currentUser.grantCheck(EntityType.INSTITUTION);
|
||||
|
||||
pageActionBuilder
|
||||
|
||||
.newAction(ActionDefinition.INSTITUTION_NEW)
|
||||
.publishIf(instGrant::w)
|
||||
|
||||
.newAction(ActionDefinition.INSTITUTION_VIEW_FROM_LIST)
|
||||
.withSelect(
|
||||
table::getSelection,
|
||||
PageAction::applySingleSelectionAsEntityKey,
|
||||
EMPTY_SELECTION_TEXT_KEY)
|
||||
.publishIf(table::hasAnyContent, false)
|
||||
|
||||
.newAction(ActionDefinition.INSTITUTION_MODIFY_FROM_LIST)
|
||||
.withSelect(
|
||||
table::getSelection,
|
||||
PageAction::applySingleSelectionAsEntityKey,
|
||||
EMPTY_SELECTION_TEXT_KEY)
|
||||
.publishIf(() -> instGrant.m() && table.hasAnyContent(), false)
|
||||
|
||||
.newAction(ActionDefinition.INSTITUTION_TOGGLE_ACTIVITY)
|
||||
.withExec(this.pageService.activationToggleActionFunction(table, EMPTY_SELECTION_TEXT_KEY))
|
||||
.withConfirm(this.pageService.confirmDeactivation(table))
|
||||
.publishIf(() -> instGrant.m() && table.hasAnyContent(), false);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,205 +1,211 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import org.eclipse.rap.rwt.RWT;
|
||||
import org.eclipse.rap.rwt.client.service.UrlLauncher;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SebClientConfig;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.form.FormBuilder;
|
||||
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.LocTextKey;
|
||||
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.TemplateComposer;
|
||||
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.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.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.NewClientConfig;
|
||||
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.EntityGrantCheck;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class SebClientConfigForm implements TemplateComposer {
|
||||
|
||||
private static final LocTextKey FORM_TITLE_NEW =
|
||||
new LocTextKey("sebserver.clientconfig.form.title.new");
|
||||
private static final LocTextKey FORM_TITLE =
|
||||
new LocTextKey("sebserver.clientconfig.form.title");
|
||||
private static final LocTextKey FORM_NAME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.clientconfig.form.name");
|
||||
private static final LocTextKey FORM_FALLBACK_URL_TEXT_KEY =
|
||||
new LocTextKey("sebserver.clientconfig.form.fallback-url");
|
||||
private static final LocTextKey FORM_DATE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.clientconfig.form.date");
|
||||
private static final LocTextKey FORM_ENCRYPT_SECRET_TEXT_KEY =
|
||||
new LocTextKey("sebserver.clientconfig.form.encryptSecret");
|
||||
private static final LocTextKey FORM_CONFIRM_ENCRYPT_SECRET_TEXT_KEY =
|
||||
new LocTextKey("sebserver.clientconfig.form.encryptSecret.confirm");
|
||||
|
||||
private final PageService pageService;
|
||||
private final RestService restService;
|
||||
private final CurrentUser currentUser;
|
||||
private final DownloadService downloadService;
|
||||
private final String downloadFileName;
|
||||
|
||||
protected SebClientConfigForm(
|
||||
final PageService pageService,
|
||||
final RestService restService,
|
||||
final CurrentUser currentUser,
|
||||
final DownloadService downloadService,
|
||||
@Value("${sebserver.gui.seb.client.config.download.filename}") final String downloadFileName) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.restService = restService;
|
||||
this.currentUser = currentUser;
|
||||
this.downloadService = downloadService;
|
||||
this.downloadFileName = downloadFileName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
|
||||
final I18nSupport i18nSupport = this.pageService.getI18nSupport();
|
||||
|
||||
final UserInfo user = this.currentUser.get();
|
||||
final EntityKey entityKey = pageContext.getEntityKey();
|
||||
final EntityKey parentEntityKey = pageContext.getParentEntityKey();
|
||||
|
||||
final boolean isNew = entityKey == null;
|
||||
|
||||
// get data or create new. Handle error if happen
|
||||
final SebClientConfig clientConfig = (isNew)
|
||||
? SebClientConfig.createNew((parentEntityKey != null)
|
||||
? Long.valueOf(parentEntityKey.modelId)
|
||||
: user.institutionId)
|
||||
: this.restService
|
||||
.getBuilder(GetClientConfig.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
||||
.call()
|
||||
.onError(error -> pageContext.notifyLoadError(EntityType.SEB_CLIENT_CONFIGURATION, error))
|
||||
.getOrThrow();
|
||||
|
||||
final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(clientConfig);
|
||||
final boolean writeGrant = entityGrant.w();
|
||||
final boolean modifyGrant = entityGrant.m();
|
||||
final boolean isReadonly = pageContext.isReadonly();
|
||||
|
||||
// new PageContext with actual EntityKey
|
||||
final PageContext formContext = pageContext.withEntityKey(clientConfig.getEntityKey());
|
||||
|
||||
// the default page layout with interactive title
|
||||
final LocTextKey titleKey = (isNew)
|
||||
? FORM_TITLE_NEW
|
||||
: FORM_TITLE;
|
||||
final Composite content = widgetFactory.defaultPageLayout(
|
||||
formContext.getParent(),
|
||||
titleKey);
|
||||
|
||||
// The SebClientConfig form
|
||||
final FormHandle<SebClientConfig> formHandle = this.pageService.formBuilder(
|
||||
formContext.copyOf(content))
|
||||
.readonly(isReadonly)
|
||||
.putStaticValueIf(() -> !isNew,
|
||||
Domain.SEB_CLIENT_CONFIGURATION.ATTR_ID,
|
||||
clientConfig.getModelId())
|
||||
.putStaticValue(
|
||||
Domain.SEB_CLIENT_CONFIGURATION.ATTR_INSTITUTION_ID,
|
||||
String.valueOf(clientConfig.getInstitutionId()))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.SEB_CLIENT_CONFIGURATION.ATTR_NAME,
|
||||
FORM_NAME_TEXT_KEY,
|
||||
clientConfig.name))
|
||||
.addField(FormBuilder.text(
|
||||
SebClientConfig.ATTR_FALLBACK_START_URL,
|
||||
FORM_FALLBACK_URL_TEXT_KEY,
|
||||
clientConfig.fallbackStartURL))
|
||||
.addFieldIf(() -> !isNew,
|
||||
() -> FormBuilder.text(
|
||||
Domain.SEB_CLIENT_CONFIGURATION.ATTR_DATE,
|
||||
FORM_DATE_TEXT_KEY,
|
||||
i18nSupport.formatDisplayDateWithTimeZone(clientConfig.date))
|
||||
.readonly(true))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.SEB_CLIENT_CONFIGURATION.ATTR_ENCRYPT_SECRET,
|
||||
FORM_ENCRYPT_SECRET_TEXT_KEY)
|
||||
.asPasswordField())
|
||||
.addField(FormBuilder.text(
|
||||
SebClientConfig.ATTR_CONFIRM_ENCRYPT_SECRET,
|
||||
FORM_CONFIRM_ENCRYPT_SECRET_TEXT_KEY)
|
||||
.asPasswordField())
|
||||
.buildFor((isNew)
|
||||
? this.restService.getRestCall(NewClientConfig.class)
|
||||
: this.restService.getRestCall(SaveClientConfig.class));
|
||||
|
||||
final UrlLauncher urlLauncher = RWT.getClient().getService(UrlLauncher.class);
|
||||
this.pageService.pageActionBuilder(formContext.clearEntityKeys())
|
||||
|
||||
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_NEW)
|
||||
.publishIf(() -> writeGrant && isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_MODIFY)
|
||||
.withEntityKey(entityKey)
|
||||
.publishIf(() -> modifyGrant && isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_EXPORT)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(action -> {
|
||||
final String downloadURL = this.downloadService.createDownloadURL(
|
||||
entityKey.modelId,
|
||||
SebClientConfigDownload.class,
|
||||
this.downloadFileName);
|
||||
urlLauncher.openURL(downloadURL);
|
||||
return action;
|
||||
})
|
||||
.publishIf(() -> writeGrant && isReadonly && clientConfig.isActive())
|
||||
|
||||
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_DEACTIVATE)
|
||||
.withEntityKey(entityKey)
|
||||
.withSimpleRestCall(this.restService, DeactivateClientConfig.class)
|
||||
.withConfirm(this.pageService.confirmDeactivation(clientConfig))
|
||||
.publishIf(() -> writeGrant && isReadonly && clientConfig.isActive())
|
||||
|
||||
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_ACTIVATE)
|
||||
.withEntityKey(entityKey)
|
||||
.withSimpleRestCall(this.restService, ActivateClientConfig.class)
|
||||
.publishIf(() -> writeGrant && isReadonly && !clientConfig.isActive())
|
||||
|
||||
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_SAVE)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(formHandle::processFormSave)
|
||||
.ignoreMoveAwayFromEdit()
|
||||
.publishIf(() -> !isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_CANCEL_MODIFY)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(this.pageService.backToCurrentFunction())
|
||||
.publishIf(() -> !isReadonly);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import org.eclipse.rap.rwt.RWT;
|
||||
import org.eclipse.rap.rwt.client.service.UrlLauncher;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SebClientConfig;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.form.FormBuilder;
|
||||
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.LocTextKey;
|
||||
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.TemplateComposer;
|
||||
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.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.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.NewClientConfig;
|
||||
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.EntityGrantCheck;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class SebClientConfigForm implements TemplateComposer {
|
||||
|
||||
private static final LocTextKey FORM_TITLE_NEW =
|
||||
new LocTextKey("sebserver.clientconfig.form.title.new");
|
||||
private static final LocTextKey FORM_TITLE =
|
||||
new LocTextKey("sebserver.clientconfig.form.title");
|
||||
private static final LocTextKey FORM_NAME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.clientconfig.form.name");
|
||||
private static final LocTextKey FORM_FALLBACK_URL_TEXT_KEY =
|
||||
new LocTextKey("sebserver.clientconfig.form.fallback-url");
|
||||
private static final LocTextKey FORM_DATE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.clientconfig.form.date");
|
||||
private static final LocTextKey FORM_ENCRYPT_SECRET_TEXT_KEY =
|
||||
new LocTextKey("sebserver.clientconfig.form.encryptSecret");
|
||||
private static final LocTextKey FORM_CONFIRM_ENCRYPT_SECRET_TEXT_KEY =
|
||||
new LocTextKey("sebserver.clientconfig.form.encryptSecret.confirm");
|
||||
|
||||
private final PageService pageService;
|
||||
private final RestService restService;
|
||||
private final CurrentUser currentUser;
|
||||
private final DownloadService downloadService;
|
||||
private final String downloadFileName;
|
||||
|
||||
protected SebClientConfigForm(
|
||||
final PageService pageService,
|
||||
final RestService restService,
|
||||
final CurrentUser currentUser,
|
||||
final DownloadService downloadService,
|
||||
@Value("${sebserver.gui.seb.client.config.download.filename}") final String downloadFileName) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.restService = restService;
|
||||
this.currentUser = currentUser;
|
||||
this.downloadService = downloadService;
|
||||
this.downloadFileName = downloadFileName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
|
||||
final I18nSupport i18nSupport = this.pageService.getI18nSupport();
|
||||
|
||||
final UserInfo user = this.currentUser.get();
|
||||
final EntityKey entityKey = pageContext.getEntityKey();
|
||||
final EntityKey parentEntityKey = pageContext.getParentEntityKey();
|
||||
|
||||
final boolean isNew = entityKey == null;
|
||||
|
||||
// get data or create new. Handle error if happen
|
||||
final SebClientConfig clientConfig = (isNew)
|
||||
? SebClientConfig.createNew((parentEntityKey != null)
|
||||
? Long.valueOf(parentEntityKey.modelId)
|
||||
: user.institutionId)
|
||||
: this.restService
|
||||
.getBuilder(GetClientConfig.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
||||
.call()
|
||||
.onError(error -> pageContext.notifyLoadError(EntityType.SEB_CLIENT_CONFIGURATION, error))
|
||||
.getOrThrow();
|
||||
|
||||
final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(clientConfig);
|
||||
final boolean writeGrant = entityGrant.w();
|
||||
final boolean modifyGrant = entityGrant.m();
|
||||
final boolean isReadonly = pageContext.isReadonly();
|
||||
|
||||
// new PageContext with actual EntityKey
|
||||
final PageContext formContext = pageContext.withEntityKey(clientConfig.getEntityKey());
|
||||
|
||||
// the default page layout with interactive title
|
||||
final LocTextKey titleKey = (isNew)
|
||||
? FORM_TITLE_NEW
|
||||
: FORM_TITLE;
|
||||
final Composite content = widgetFactory.defaultPageLayout(
|
||||
formContext.getParent(),
|
||||
titleKey);
|
||||
|
||||
// The SebClientConfig form
|
||||
final FormHandle<SebClientConfig> formHandle = this.pageService.formBuilder(
|
||||
formContext.copyOf(content))
|
||||
.readonly(isReadonly)
|
||||
.putStaticValueIf(() -> !isNew,
|
||||
Domain.SEB_CLIENT_CONFIGURATION.ATTR_ID,
|
||||
clientConfig.getModelId())
|
||||
.putStaticValue(
|
||||
Domain.SEB_CLIENT_CONFIGURATION.ATTR_INSTITUTION_ID,
|
||||
String.valueOf(clientConfig.getInstitutionId()))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.SEB_CLIENT_CONFIGURATION.ATTR_NAME,
|
||||
FORM_NAME_TEXT_KEY,
|
||||
clientConfig.name))
|
||||
.addField(FormBuilder.text(
|
||||
SebClientConfig.ATTR_FALLBACK_START_URL,
|
||||
FORM_FALLBACK_URL_TEXT_KEY,
|
||||
clientConfig.fallbackStartURL))
|
||||
.addFieldIf(() -> !isNew,
|
||||
() -> FormBuilder.text(
|
||||
Domain.SEB_CLIENT_CONFIGURATION.ATTR_DATE,
|
||||
FORM_DATE_TEXT_KEY,
|
||||
i18nSupport.formatDisplayDateWithTimeZone(clientConfig.date))
|
||||
.readonly(true))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.SEB_CLIENT_CONFIGURATION.ATTR_ENCRYPT_SECRET,
|
||||
FORM_ENCRYPT_SECRET_TEXT_KEY)
|
||||
.asPasswordField())
|
||||
.addField(FormBuilder.text(
|
||||
SebClientConfig.ATTR_CONFIRM_ENCRYPT_SECRET,
|
||||
FORM_CONFIRM_ENCRYPT_SECRET_TEXT_KEY)
|
||||
.asPasswordField())
|
||||
.buildFor((isNew)
|
||||
? this.restService.getRestCall(NewClientConfig.class)
|
||||
: this.restService.getRestCall(SaveClientConfig.class));
|
||||
|
||||
final UrlLauncher urlLauncher = RWT.getClient().getService(UrlLauncher.class);
|
||||
this.pageService.pageActionBuilder(formContext.clearEntityKeys())
|
||||
|
||||
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_NEW)
|
||||
.publishIf(() -> writeGrant && isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_MODIFY)
|
||||
.withEntityKey(entityKey)
|
||||
.publishIf(() -> modifyGrant && isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_EXPORT)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(action -> {
|
||||
final String downloadURL = this.downloadService.createDownloadURL(
|
||||
entityKey.modelId,
|
||||
SebClientConfigDownload.class,
|
||||
this.downloadFileName);
|
||||
urlLauncher.openURL(downloadURL);
|
||||
return action;
|
||||
})
|
||||
.publishIf(() -> writeGrant && isReadonly && clientConfig.isActive())
|
||||
|
||||
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_DEACTIVATE)
|
||||
.withEntityKey(entityKey)
|
||||
.withSimpleRestCall(this.restService, DeactivateClientConfig.class)
|
||||
.withConfirm(this.pageService.confirmDeactivation(clientConfig))
|
||||
.publishIf(() -> writeGrant && isReadonly && clientConfig.isActive())
|
||||
|
||||
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_ACTIVATE)
|
||||
.withEntityKey(entityKey)
|
||||
.withSimpleRestCall(this.restService, ActivateClientConfig.class)
|
||||
.publishIf(() -> writeGrant && isReadonly && !clientConfig.isActive())
|
||||
|
||||
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_SAVE)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(formHandle::processFormSave)
|
||||
.ignoreMoveAwayFromEdit()
|
||||
.publishIf(() -> !isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_SAVE_AND_ACTIVATE)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(formHandle::saveAndActivate)
|
||||
.ignoreMoveAwayFromEdit()
|
||||
.publishIf(() -> !isReadonly && !clientConfig.isActive())
|
||||
|
||||
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_CANCEL_MODIFY)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(this.pageService.backToCurrentFunction())
|
||||
.publishIf(() -> !isReadonly);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,182 +1,199 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SebClientConfig;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
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.LocTextKey;
|
||||
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.PageActionBuilder;
|
||||
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.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.auth.CurrentUser;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute;
|
||||
import ch.ethz.seb.sebserver.gui.table.EntityTable;
|
||||
import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class SebClientConfigList implements TemplateComposer {
|
||||
|
||||
private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION =
|
||||
new LocTextKey("sebserver.clientconfig.list.action.no.modify.privilege");
|
||||
private static final LocTextKey EMPTY_LIST_TEXT_KEY =
|
||||
new LocTextKey("sebserver.clientconfig.list.empty");
|
||||
private static final LocTextKey TITLE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.clientconfig.list.title");
|
||||
private static final LocTextKey INSTITUTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.clientconfig.list.column.institution");
|
||||
private static final LocTextKey NAME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.clientconfig.list.column.name");
|
||||
private static final LocTextKey ACTIVE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.clientconfig.list.column.active");
|
||||
private static final LocTextKey EMPTY_SELECTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.clientconfig.info.pleaseSelect");
|
||||
|
||||
private final TableFilterAttribute institutionFilter;
|
||||
private final TableFilterAttribute nameFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, Entity.FILTER_ATTR_NAME);
|
||||
private final TableFilterAttribute dateFilter =
|
||||
new TableFilterAttribute(
|
||||
CriteriaType.DATE,
|
||||
SebClientConfig.FILTER_ATTR_CREATION_DATE,
|
||||
DateTime.now(DateTimeZone.UTC)
|
||||
.minusYears(1)
|
||||
.toString(Constants.DEFAULT_DATE_TIME_FORMAT));
|
||||
private final TableFilterAttribute activityFilter;
|
||||
|
||||
private final PageService pageService;
|
||||
private final RestService restService;
|
||||
private final CurrentUser currentUser;
|
||||
private final ResourceService resourceService;
|
||||
private final int pageSize;
|
||||
|
||||
protected SebClientConfigList(
|
||||
final PageService pageService,
|
||||
final RestService restService,
|
||||
final CurrentUser currentUser,
|
||||
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.restService = restService;
|
||||
this.currentUser = currentUser;
|
||||
this.resourceService = pageService.getResourceService();
|
||||
this.pageSize = pageSize;
|
||||
|
||||
this.institutionFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
Entity.FILTER_ATTR_INSTITUTION,
|
||||
this.resourceService::institutionResource);
|
||||
|
||||
this.activityFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
UserInfo.FILTER_ATTR_ACTIVE,
|
||||
this.resourceService::activityResources);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
|
||||
final I18nSupport i18nSupport = this.pageService.getI18nSupport();
|
||||
final Composite content = this.pageService.getWidgetFactory().defaultPageLayout(
|
||||
pageContext.getParent(),
|
||||
TITLE_TEXT_KEY);
|
||||
|
||||
final boolean isSEBAdmin = this.currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN);
|
||||
final PageActionBuilder pageActionBuilder =
|
||||
this.pageService.pageActionBuilder(pageContext.clearEntityKeys());
|
||||
|
||||
// table
|
||||
final EntityTable<SebClientConfig> table =
|
||||
this.pageService.entityTableBuilder(this.restService.getRestCall(GetClientConfigPage.class))
|
||||
.withEmptyMessage(EMPTY_LIST_TEXT_KEY)
|
||||
.withPaging(this.pageSize)
|
||||
.withColumnIf(
|
||||
() -> isSEBAdmin,
|
||||
() -> new ColumnDefinition<>(
|
||||
Domain.LMS_SETUP.ATTR_INSTITUTION_ID,
|
||||
INSTITUTION_TEXT_KEY,
|
||||
clientConfigInstitutionNameFunction(this.resourceService))
|
||||
.withFilter(this.institutionFilter))
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.SEB_CLIENT_CONFIGURATION.ATTR_NAME,
|
||||
NAME_TEXT_KEY,
|
||||
SebClientConfig::getName)
|
||||
.withFilter(this.nameFilter)
|
||||
.sortable())
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.SEB_CLIENT_CONFIGURATION.ATTR_DATE,
|
||||
new LocTextKey(
|
||||
"sebserver.clientconfig.list.column.date",
|
||||
i18nSupport.getUsersTimeZoneTitleSuffix()),
|
||||
SebClientConfig::getDate)
|
||||
.withFilter(this.dateFilter)
|
||||
.sortable())
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.SEB_CLIENT_CONFIGURATION.ATTR_ACTIVE,
|
||||
ACTIVE_TEXT_KEY,
|
||||
this.pageService.getResourceService().<SebClientConfig> localizedActivityFunction())
|
||||
.withFilter(this.activityFilter)
|
||||
.sortable())
|
||||
.withDefaultAction(pageActionBuilder
|
||||
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_VIEW_FROM_LIST)
|
||||
.create())
|
||||
.compose(pageContext.copyOf(content));
|
||||
|
||||
final GrantCheck clientConfigGrant = this.currentUser.grantCheck(EntityType.SEB_CLIENT_CONFIGURATION);
|
||||
|
||||
pageActionBuilder
|
||||
|
||||
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_NEW)
|
||||
.publishIf(clientConfigGrant::iw)
|
||||
|
||||
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_VIEW_FROM_LIST)
|
||||
.withSelect(table::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY)
|
||||
.publishIf(() -> table.hasAnyContent())
|
||||
|
||||
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_MODIFY_FROM_LIST)
|
||||
.withSelect(
|
||||
table.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION),
|
||||
PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY)
|
||||
.publishIf(() -> clientConfigGrant.im() && table.hasAnyContent());
|
||||
|
||||
}
|
||||
|
||||
private static Function<SebClientConfig, String> clientConfigInstitutionNameFunction(
|
||||
final ResourceService resourceService) {
|
||||
|
||||
return config -> resourceService.getInstitutionNameFunction()
|
||||
.apply(String.valueOf(config.institutionId));
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SebClientConfig;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
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.LocTextKey;
|
||||
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.PageActionBuilder;
|
||||
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.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.auth.CurrentUser;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute;
|
||||
import ch.ethz.seb.sebserver.gui.table.EntityTable;
|
||||
import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class SebClientConfigList implements TemplateComposer {
|
||||
|
||||
private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION =
|
||||
new LocTextKey("sebserver.clientconfig.list.action.no.modify.privilege");
|
||||
private static final LocTextKey EMPTY_LIST_TEXT_KEY =
|
||||
new LocTextKey("sebserver.clientconfig.list.empty");
|
||||
private static final LocTextKey TITLE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.clientconfig.list.title");
|
||||
private static final LocTextKey INSTITUTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.clientconfig.list.column.institution");
|
||||
private static final LocTextKey NAME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.clientconfig.list.column.name");
|
||||
private static final LocTextKey ACTIVE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.clientconfig.list.column.active");
|
||||
private static final LocTextKey EMPTY_SELECTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.clientconfig.info.pleaseSelect");
|
||||
|
||||
private final TableFilterAttribute institutionFilter;
|
||||
private final TableFilterAttribute nameFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, Entity.FILTER_ATTR_NAME);
|
||||
private final TableFilterAttribute dateFilter =
|
||||
new TableFilterAttribute(
|
||||
CriteriaType.DATE,
|
||||
SebClientConfig.FILTER_ATTR_CREATION_DATE,
|
||||
DateTime.now(DateTimeZone.UTC)
|
||||
.minusYears(1)
|
||||
.toString(Constants.DEFAULT_DATE_TIME_FORMAT));
|
||||
private final TableFilterAttribute activityFilter;
|
||||
|
||||
private final PageService pageService;
|
||||
private final RestService restService;
|
||||
private final CurrentUser currentUser;
|
||||
private final ResourceService resourceService;
|
||||
private final int pageSize;
|
||||
|
||||
protected SebClientConfigList(
|
||||
final PageService pageService,
|
||||
final RestService restService,
|
||||
final CurrentUser currentUser,
|
||||
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.restService = restService;
|
||||
this.currentUser = currentUser;
|
||||
this.resourceService = pageService.getResourceService();
|
||||
this.pageSize = pageSize;
|
||||
|
||||
this.institutionFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
Entity.FILTER_ATTR_INSTITUTION,
|
||||
this.resourceService::institutionResource);
|
||||
|
||||
this.activityFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
UserInfo.FILTER_ATTR_ACTIVE,
|
||||
this.resourceService::activityResources);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
|
||||
final I18nSupport i18nSupport = this.pageService.getI18nSupport();
|
||||
final Composite content = this.pageService.getWidgetFactory().defaultPageLayout(
|
||||
pageContext.getParent(),
|
||||
TITLE_TEXT_KEY);
|
||||
|
||||
final boolean isSEBAdmin = this.currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN);
|
||||
final PageActionBuilder pageActionBuilder =
|
||||
this.pageService.pageActionBuilder(pageContext.clearEntityKeys());
|
||||
|
||||
// table
|
||||
final EntityTable<SebClientConfig> table =
|
||||
this.pageService.entityTableBuilder(this.restService.getRestCall(GetClientConfigPage.class))
|
||||
.withEmptyMessage(EMPTY_LIST_TEXT_KEY)
|
||||
.withPaging(this.pageSize)
|
||||
.withColumnIf(
|
||||
() -> isSEBAdmin,
|
||||
() -> new ColumnDefinition<>(
|
||||
Domain.LMS_SETUP.ATTR_INSTITUTION_ID,
|
||||
INSTITUTION_TEXT_KEY,
|
||||
clientConfigInstitutionNameFunction(this.resourceService))
|
||||
.withFilter(this.institutionFilter))
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.SEB_CLIENT_CONFIGURATION.ATTR_NAME,
|
||||
NAME_TEXT_KEY,
|
||||
SebClientConfig::getName)
|
||||
.withFilter(this.nameFilter)
|
||||
.sortable())
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.SEB_CLIENT_CONFIGURATION.ATTR_DATE,
|
||||
new LocTextKey(
|
||||
"sebserver.clientconfig.list.column.date",
|
||||
i18nSupport.getUsersTimeZoneTitleSuffix()),
|
||||
SebClientConfig::getDate)
|
||||
.withFilter(this.dateFilter)
|
||||
.sortable())
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.SEB_CLIENT_CONFIGURATION.ATTR_ACTIVE,
|
||||
ACTIVE_TEXT_KEY,
|
||||
this.pageService.getResourceService().<SebClientConfig> localizedActivityFunction())
|
||||
.withFilter(this.activityFilter)
|
||||
.sortable())
|
||||
.withDefaultAction(pageActionBuilder
|
||||
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_VIEW_FROM_LIST)
|
||||
.create())
|
||||
|
||||
.withSelectionListener(this.pageService.getSelectionPublisher(
|
||||
ActionDefinition.SEB_CLIENT_CONFIG_TOGGLE_ACTIVITY,
|
||||
ActionDefinition.SEB_CLIENT_CONFIG_ACTIVATE,
|
||||
ActionDefinition.SEB_CLIENT_CONFIG_DEACTIVATE,
|
||||
pageContext,
|
||||
ActionDefinition.SEB_CLIENT_CONFIG_VIEW_FROM_LIST,
|
||||
ActionDefinition.SEB_CLIENT_CONFIG_MODIFY_FROM_LIST,
|
||||
ActionDefinition.SEB_CLIENT_CONFIG_TOGGLE_ACTIVITY))
|
||||
|
||||
.compose(pageContext.copyOf(content));
|
||||
|
||||
final GrantCheck clientConfigGrant = this.currentUser.grantCheck(EntityType.SEB_CLIENT_CONFIGURATION);
|
||||
|
||||
pageActionBuilder
|
||||
|
||||
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_NEW)
|
||||
.publishIf(clientConfigGrant::iw)
|
||||
|
||||
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_VIEW_FROM_LIST)
|
||||
.withSelect(table::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY)
|
||||
.publishIf(table::hasAnyContent, false)
|
||||
|
||||
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_MODIFY_FROM_LIST)
|
||||
.withSelect(
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,174 +1,178 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
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.model.Entity;
|
||||
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.user.UserRole;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.service.ResourceService;
|
||||
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.PageService;
|
||||
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.impl.PageAction;
|
||||
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.auth.CurrentUser;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute;
|
||||
import ch.ethz.seb.sebserver.gui.table.EntityTable;
|
||||
import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class SebExamConfigList implements TemplateComposer {
|
||||
|
||||
private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION =
|
||||
new LocTextKey("sebserver.examconfig.list.action.no.modify.privilege");
|
||||
private static final LocTextKey EMPTY_CONFIG_LIST_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.list.empty");
|
||||
private static final LocTextKey TITLE_CONFIGURATION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.list.title");
|
||||
private static final LocTextKey INSTITUTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.list.column.institution");
|
||||
private static final LocTextKey NAME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.list.column.name");
|
||||
private static final LocTextKey DESCRIPTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.list.column.description");
|
||||
private static final LocTextKey STATUS_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.list.column.status");
|
||||
private static final LocTextKey EMPTY_SELECTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.info.pleaseSelect");
|
||||
|
||||
private final TableFilterAttribute institutionFilter;
|
||||
private final TableFilterAttribute nameFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, Entity.FILTER_ATTR_NAME);
|
||||
private final TableFilterAttribute descFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, ConfigurationNode.FILTER_ATTR_DESCRIPTION);
|
||||
private final TableFilterAttribute statusFilter;
|
||||
|
||||
private final PageService pageService;
|
||||
private final RestService restService;
|
||||
private final CurrentUser currentUser;
|
||||
private final ResourceService resourceService;
|
||||
private final int pageSize;
|
||||
|
||||
protected SebExamConfigList(
|
||||
final PageService pageService,
|
||||
final RestService restService,
|
||||
final CurrentUser currentUser,
|
||||
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.restService = restService;
|
||||
this.currentUser = currentUser;
|
||||
this.resourceService = pageService.getResourceService();
|
||||
this.pageSize = pageSize;
|
||||
|
||||
this.institutionFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
Entity.FILTER_ATTR_INSTITUTION,
|
||||
this.resourceService::institutionResource);
|
||||
|
||||
this.statusFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
ConfigurationNode.FILTER_ATTR_STATUS,
|
||||
this.resourceService::examConfigStatusResources);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
|
||||
final Composite content = widgetFactory.defaultPageLayout(
|
||||
pageContext.getParent(),
|
||||
TITLE_CONFIGURATION_TEXT_KEY);
|
||||
|
||||
final boolean isSEBAdmin = this.currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN);
|
||||
final PageActionBuilder pageActionBuilder =
|
||||
this.pageService.pageActionBuilder(pageContext.clearEntityKeys());
|
||||
|
||||
// exam configuration table
|
||||
final EntityTable<ConfigurationNode> configTable =
|
||||
this.pageService.entityTableBuilder(this.restService.getRestCall(GetExamConfigNodePage.class))
|
||||
.withStaticFilter(
|
||||
Domain.CONFIGURATION_NODE.ATTR_TYPE,
|
||||
ConfigurationType.EXAM_CONFIG.name())
|
||||
.withEmptyMessage(EMPTY_CONFIG_LIST_TEXT_KEY)
|
||||
.withPaging(this.pageSize)
|
||||
.withColumnIf(
|
||||
() -> isSEBAdmin,
|
||||
() -> new ColumnDefinition<>(
|
||||
Domain.LMS_SETUP.ATTR_INSTITUTION_ID,
|
||||
INSTITUTION_TEXT_KEY,
|
||||
this.resourceService::localizedExamConfigInstitutionName)
|
||||
.withFilter(this.institutionFilter)
|
||||
.sortable())
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.CONFIGURATION_NODE.ATTR_NAME,
|
||||
NAME_TEXT_KEY,
|
||||
ConfigurationNode::getName)
|
||||
.withFilter(this.nameFilter)
|
||||
.sortable())
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION,
|
||||
DESCRIPTION_TEXT_KEY,
|
||||
ConfigurationNode::getDescription)
|
||||
.withFilter(this.descFilter)
|
||||
.sortable())
|
||||
.withColumn(new ColumnDefinition<ConfigurationNode>(
|
||||
Domain.CONFIGURATION_NODE.ATTR_STATUS,
|
||||
STATUS_TEXT_KEY,
|
||||
this.resourceService::localizedExamConfigStatusName)
|
||||
.withFilter(this.statusFilter)
|
||||
.sortable())
|
||||
.withDefaultAction(pageActionBuilder
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_PROP_FROM_LIST)
|
||||
.create())
|
||||
.compose(pageContext.copyOf(content));
|
||||
|
||||
final GrantCheck examConfigGrant = this.currentUser.grantCheck(EntityType.CONFIGURATION_NODE);
|
||||
pageActionBuilder
|
||||
// Exam Configuration actions...
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_NEW)
|
||||
.publishIf(examConfigGrant::iw)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_PROP_FROM_LIST)
|
||||
.withSelect(configTable::getSelection, PageAction::applySingleSelectionAsEntityKey,
|
||||
EMPTY_SELECTION_TEXT_KEY)
|
||||
.publishIf(() -> configTable.hasAnyContent())
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY_PROP_FROM_LIST)
|
||||
.withSelect(
|
||||
configTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION),
|
||||
PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY)
|
||||
.publishIf(() -> examConfigGrant.im() && configTable.hasAnyContent())
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_IMPORT_TO_NEW_CONFIG)
|
||||
.withExec(SebExamConfigImportPopup.importFunction(this.pageService, true))
|
||||
.noEventPropagation()
|
||||
.publishIf(() -> examConfigGrant.im())
|
||||
|
||||
;
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
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.model.Entity;
|
||||
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.user.UserRole;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.service.ResourceService;
|
||||
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.PageService;
|
||||
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.impl.PageAction;
|
||||
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.auth.CurrentUser;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute;
|
||||
import ch.ethz.seb.sebserver.gui.table.EntityTable;
|
||||
import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class SebExamConfigList implements TemplateComposer {
|
||||
|
||||
private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION =
|
||||
new LocTextKey("sebserver.examconfig.list.action.no.modify.privilege");
|
||||
private static final LocTextKey EMPTY_CONFIG_LIST_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.list.empty");
|
||||
private static final LocTextKey TITLE_CONFIGURATION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.list.title");
|
||||
private static final LocTextKey INSTITUTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.list.column.institution");
|
||||
private static final LocTextKey NAME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.list.column.name");
|
||||
private static final LocTextKey DESCRIPTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.list.column.description");
|
||||
private static final LocTextKey STATUS_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.list.column.status");
|
||||
private static final LocTextKey EMPTY_SELECTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.info.pleaseSelect");
|
||||
|
||||
private final TableFilterAttribute institutionFilter;
|
||||
private final TableFilterAttribute nameFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, Entity.FILTER_ATTR_NAME);
|
||||
private final TableFilterAttribute descFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, ConfigurationNode.FILTER_ATTR_DESCRIPTION);
|
||||
private final TableFilterAttribute statusFilter;
|
||||
|
||||
private final PageService pageService;
|
||||
private final RestService restService;
|
||||
private final CurrentUser currentUser;
|
||||
private final ResourceService resourceService;
|
||||
private final int pageSize;
|
||||
|
||||
protected SebExamConfigList(
|
||||
final PageService pageService,
|
||||
final RestService restService,
|
||||
final CurrentUser currentUser,
|
||||
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.restService = restService;
|
||||
this.currentUser = currentUser;
|
||||
this.resourceService = pageService.getResourceService();
|
||||
this.pageSize = pageSize;
|
||||
|
||||
this.institutionFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
Entity.FILTER_ATTR_INSTITUTION,
|
||||
this.resourceService::institutionResource);
|
||||
|
||||
this.statusFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
ConfigurationNode.FILTER_ATTR_STATUS,
|
||||
this.resourceService::examConfigStatusResources);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
|
||||
final Composite content = widgetFactory.defaultPageLayout(
|
||||
pageContext.getParent(),
|
||||
TITLE_CONFIGURATION_TEXT_KEY);
|
||||
|
||||
final boolean isSEBAdmin = this.currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN);
|
||||
final PageActionBuilder pageActionBuilder =
|
||||
this.pageService.pageActionBuilder(pageContext.clearEntityKeys());
|
||||
|
||||
// exam configuration table
|
||||
final EntityTable<ConfigurationNode> configTable =
|
||||
this.pageService.entityTableBuilder(this.restService.getRestCall(GetExamConfigNodePage.class))
|
||||
.withStaticFilter(
|
||||
Domain.CONFIGURATION_NODE.ATTR_TYPE,
|
||||
ConfigurationType.EXAM_CONFIG.name())
|
||||
.withEmptyMessage(EMPTY_CONFIG_LIST_TEXT_KEY)
|
||||
.withPaging(this.pageSize)
|
||||
.withColumnIf(
|
||||
() -> isSEBAdmin,
|
||||
() -> new ColumnDefinition<>(
|
||||
Domain.LMS_SETUP.ATTR_INSTITUTION_ID,
|
||||
INSTITUTION_TEXT_KEY,
|
||||
this.resourceService::localizedExamConfigInstitutionName)
|
||||
.withFilter(this.institutionFilter)
|
||||
.sortable())
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.CONFIGURATION_NODE.ATTR_NAME,
|
||||
NAME_TEXT_KEY,
|
||||
ConfigurationNode::getName)
|
||||
.withFilter(this.nameFilter)
|
||||
.sortable())
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION,
|
||||
DESCRIPTION_TEXT_KEY,
|
||||
ConfigurationNode::getDescription)
|
||||
.withFilter(this.descFilter)
|
||||
.sortable())
|
||||
.withColumn(new ColumnDefinition<ConfigurationNode>(
|
||||
Domain.CONFIGURATION_NODE.ATTR_STATUS,
|
||||
STATUS_TEXT_KEY,
|
||||
this.resourceService::localizedExamConfigStatusName)
|
||||
.withFilter(this.statusFilter)
|
||||
.sortable())
|
||||
.withDefaultAction(pageActionBuilder
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_PROP_FROM_LIST)
|
||||
.create())
|
||||
|
||||
.withSelectionListener(this.pageService.getSelectionPublisher(
|
||||
pageContext,
|
||||
ActionDefinition.SEB_EXAM_CONFIG_VIEW_PROP_FROM_LIST,
|
||||
ActionDefinition.SEB_EXAM_CONFIG_MODIFY_PROP_FROM_LIST))
|
||||
|
||||
.compose(pageContext.copyOf(content));
|
||||
|
||||
final GrantCheck examConfigGrant = this.currentUser.grantCheck(EntityType.CONFIGURATION_NODE);
|
||||
pageActionBuilder
|
||||
// Exam Configuration actions...
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_NEW)
|
||||
.publishIf(examConfigGrant::iw)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_PROP_FROM_LIST)
|
||||
.withSelect(configTable::getSelection, PageAction::applySingleSelectionAsEntityKey,
|
||||
EMPTY_SELECTION_TEXT_KEY)
|
||||
.publishIf(configTable::hasAnyContent, false)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY_PROP_FROM_LIST)
|
||||
.withSelect(
|
||||
configTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION),
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,413 +1,423 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
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.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Text;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.ExamConfigurationMap;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.QuizData;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigKey;
|
||||
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.ConfigurationType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.form.FormBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.form.FormHandle;
|
||||
import ch.ethz.seb.sebserver.gui.service.ResourceService;
|
||||
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.PageMessageException;
|
||||
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.TemplateComposer;
|
||||
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.remote.download.DownloadService;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.download.SebExamConfigPlaintextDownload;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExamConfigMappingNames;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExamConfigMappingsPage;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.ExportConfigKey;
|
||||
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.NewExamConfig;
|
||||
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.EntityGrantCheck;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.table.EntityTable;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class SebExamConfigPropForm implements TemplateComposer {
|
||||
|
||||
static final LocTextKey FORM_TITLE_NEW =
|
||||
new LocTextKey("sebserver.examconfig.form.title.new");
|
||||
static final LocTextKey FORM_TITLE =
|
||||
new LocTextKey("sebserver.examconfig.form.title");
|
||||
static final LocTextKey FORM_NAME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.form.name");
|
||||
static final LocTextKey FORM_DESCRIPTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.form.description");
|
||||
static final LocTextKey FORM_HISTORY_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.form.with-history");
|
||||
static final LocTextKey FORM_TEMPLATE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.form.template");
|
||||
static final LocTextKey FORM_STATUS_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.form.status");
|
||||
static final LocTextKey FORM_IMPORT_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.action.import-config");
|
||||
static final LocTextKey FORM_IMPORT_SELECT_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.action.import-file-select");
|
||||
static final LocTextKey FORM_IMPORT_PASSWORD_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.action.import-file-password");
|
||||
static final LocTextKey CONFIG_KEY_TITLE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.form.config-key.title");
|
||||
static final LocTextKey FORM_IMPORT_CONFIRM_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.action.import-config.confirm");
|
||||
static final LocTextKey FORM_ATTACHED_EXAMS_TITLE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.form.attched-to");
|
||||
|
||||
static final LocTextKey SAVE_CONFIRM_STATE_CHANGE_WHILE_ATTACHED =
|
||||
new LocTextKey("sebserver.examconfig.action.state-change.confirm");
|
||||
|
||||
private final PageService pageService;
|
||||
private final RestService restService;
|
||||
private final CurrentUser currentUser;
|
||||
private final DownloadService downloadService;
|
||||
private final String downloadFileName;
|
||||
|
||||
protected SebExamConfigPropForm(
|
||||
final PageService pageService,
|
||||
final CurrentUser currentUser,
|
||||
final DownloadService downloadService,
|
||||
@Value("${sebserver.gui.seb.exam.config.download.filename}") final String downloadFileName) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.restService = pageService.getRestService();
|
||||
this.currentUser = currentUser;
|
||||
this.downloadService = downloadService;
|
||||
this.downloadFileName = downloadFileName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
|
||||
final ResourceService resourceService = this.pageService.getResourceService();
|
||||
|
||||
final UserInfo user = this.currentUser.get();
|
||||
final EntityKey entityKey = pageContext.getEntityKey();
|
||||
final EntityKey parentEntityKey = pageContext.getParentEntityKey();
|
||||
final boolean isNew = entityKey == null;
|
||||
|
||||
// get data or create new. Handle error if happen
|
||||
final ConfigurationNode examConfig = (isNew)
|
||||
? ConfigurationNode.createNewExamConfig(user.institutionId)
|
||||
: this.restService
|
||||
.getBuilder(GetExamConfigNode.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
||||
.call()
|
||||
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_NODE, error))
|
||||
.getOrThrow();
|
||||
|
||||
final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(examConfig);
|
||||
final boolean writeGrant = entityGrant.w();
|
||||
final boolean modifyGrant = entityGrant.m();
|
||||
final boolean isReadonly = pageContext.isReadonly();
|
||||
final boolean isAttachedToExam = !isNew && this.restService
|
||||
.getBuilder(GetExamConfigMappingNames.class)
|
||||
.withQueryParam(ExamConfigurationMap.FILTER_ATTR_CONFIG_ID, examConfig.getModelId())
|
||||
.call()
|
||||
.map(names -> names != null && !names.isEmpty())
|
||||
.getOr(Boolean.FALSE);
|
||||
|
||||
// new PageContext with actual EntityKey
|
||||
final PageContext formContext = pageContext.withEntityKey(examConfig.getEntityKey());
|
||||
|
||||
// the default page layout with interactive title
|
||||
final LocTextKey titleKey = (isNew)
|
||||
? FORM_TITLE_NEW
|
||||
: FORM_TITLE;
|
||||
final Composite content = widgetFactory.defaultPageLayout(
|
||||
formContext.getParent(),
|
||||
titleKey);
|
||||
|
||||
final List<Tuple<String>> examConfigTemplateResources = resourceService.getExamConfigTemplateResources();
|
||||
final FormHandle<ConfigurationNode> formHandle = this.pageService.formBuilder(
|
||||
formContext.copyOf(content))
|
||||
.readonly(isReadonly)
|
||||
.putStaticValueIf(() -> !isNew,
|
||||
Domain.CONFIGURATION_NODE.ATTR_ID,
|
||||
examConfig.getModelId())
|
||||
.putStaticValue(
|
||||
Domain.CONFIGURATION_NODE.ATTR_INSTITUTION_ID,
|
||||
String.valueOf(examConfig.getInstitutionId()))
|
||||
.putStaticValue(
|
||||
Domain.CONFIGURATION_NODE.ATTR_TYPE,
|
||||
ConfigurationType.EXAM_CONFIG.name())
|
||||
.addFieldIf(
|
||||
() -> !examConfigTemplateResources.isEmpty(),
|
||||
() -> FormBuilder.singleSelection(
|
||||
Domain.CONFIGURATION_NODE.ATTR_TEMPLATE_ID,
|
||||
FORM_TEMPLATE_TEXT_KEY,
|
||||
(parentEntityKey != null)
|
||||
? parentEntityKey.modelId
|
||||
: String.valueOf(examConfig.templateId),
|
||||
resourceService::getExamConfigTemplateResources)
|
||||
.readonly(!isNew))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.CONFIGURATION_NODE.ATTR_NAME,
|
||||
FORM_NAME_TEXT_KEY,
|
||||
examConfig.name))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION,
|
||||
FORM_DESCRIPTION_TEXT_KEY,
|
||||
examConfig.description)
|
||||
.asArea())
|
||||
|
||||
.addField(FormBuilder.singleSelection(
|
||||
Domain.CONFIGURATION_NODE.ATTR_STATUS,
|
||||
FORM_STATUS_TEXT_KEY,
|
||||
examConfig.status.name(),
|
||||
() -> resourceService.examConfigStatusResources(isAttachedToExam))
|
||||
.withEmptyCellSeparation((isReadonly) ? false : true))
|
||||
.buildFor((isNew)
|
||||
? this.restService.getRestCall(NewExamConfig.class)
|
||||
: this.restService.getRestCall(SaveExamConfig.class));
|
||||
|
||||
final boolean settingsReadonly = examConfig.status == ConfigurationStatus.IN_USE;
|
||||
final UrlLauncher urlLauncher = RWT.getClient().getService(UrlLauncher.class);
|
||||
final PageContext actionContext = formContext.clearEntityKeys();
|
||||
final PageActionBuilder actionBuilder = this.pageService.pageActionBuilder(actionContext);
|
||||
actionBuilder
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_NEW)
|
||||
.publishIf(() -> writeGrant && isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_PROP_MODIFY)
|
||||
.withEntityKey(entityKey)
|
||||
.publishIf(() -> modifyGrant && isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW)
|
||||
.withEntityKey(entityKey)
|
||||
.publishIf(() -> isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY)
|
||||
.withEntityKey(entityKey)
|
||||
.publishIf(() -> modifyGrant && isReadonly && !settingsReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_EXPORT_PLAIN_XML)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(action -> {
|
||||
final String downloadURL = this.downloadService.createDownloadURL(
|
||||
entityKey.modelId,
|
||||
SebExamConfigPlaintextDownload.class,
|
||||
this.downloadFileName);
|
||||
urlLauncher.openURL(downloadURL);
|
||||
return action;
|
||||
})
|
||||
.noEventPropagation()
|
||||
.publishIf(() -> modifyGrant && isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_GET_CONFIG_KEY)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(SebExamConfigPropForm.getConfigKeyFunction(this.pageService))
|
||||
.noEventPropagation()
|
||||
.publishIf(() -> modifyGrant && isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_IMPORT_TO_EXISTING_CONFIG)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(SebExamConfigImportPopup.importFunction(this.pageService, false))
|
||||
.noEventPropagation()
|
||||
.publishIf(() -> modifyGrant && isReadonly && !isAttachedToExam)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_COPY_CONFIG)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(SebExamConfigCreationPopup.configCreationFunction(
|
||||
this.pageService,
|
||||
actionContext
|
||||
.withEntityKey(entityKey)
|
||||
.withAttribute(
|
||||
PageContext.AttributeKeys.COPY_AS_TEMPLATE,
|
||||
Constants.FALSE_STRING)
|
||||
.withAttribute(
|
||||
PageContext.AttributeKeys.CREATE_FROM_TEMPLATE,
|
||||
Constants.FALSE_STRING)))
|
||||
.noEventPropagation()
|
||||
.publishIf(() -> modifyGrant && isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_COPY_CONFIG_AS_TEMPALTE)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(SebExamConfigCreationPopup.configCreationFunction(
|
||||
this.pageService,
|
||||
pageContext.withAttribute(
|
||||
PageContext.AttributeKeys.COPY_AS_TEMPLATE,
|
||||
Constants.TRUE_STRING)))
|
||||
.noEventPropagation()
|
||||
.publishIf(() -> modifyGrant && isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_PROP_SAVE)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(formHandle::processFormSave)
|
||||
.ignoreMoveAwayFromEdit()
|
||||
.withConfirm(() -> stateChangeConfirm(isAttachedToExam, formHandle))
|
||||
.publishIf(() -> !isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_PROP_CANCEL_MODIFY)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(this.pageService.backToCurrentFunction())
|
||||
.publishIf(() -> !isReadonly);
|
||||
|
||||
if (isAttachedToExam && isReadonly) {
|
||||
|
||||
widgetFactory.labelSeparator(content);
|
||||
widgetFactory.labelLocalized(
|
||||
content,
|
||||
CustomVariant.TEXT_H3,
|
||||
FORM_ATTACHED_EXAMS_TITLE_TEXT_KEY);
|
||||
|
||||
final EntityTable<ExamConfigurationMap> table =
|
||||
this.pageService.entityTableBuilder(this.restService.getRestCall(GetExamConfigMappingsPage.class))
|
||||
.withRestCallAdapter(restCall -> restCall.withQueryParam(
|
||||
ExamConfigurationMap.FILTER_ATTR_CONFIG_ID, examConfig.getModelId()))
|
||||
.withPaging(1)
|
||||
.hideNavigation()
|
||||
.withRowDecorator(ExamList.decorateOnExamMapConsistency(this.pageService))
|
||||
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
QuizData.QUIZ_ATTR_NAME,
|
||||
ExamList.COLUMN_TITLE_NAME_KEY,
|
||||
ExamConfigurationMap::getExamName))
|
||||
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
QuizData.QUIZ_ATTR_START_TIME,
|
||||
new LocTextKey(
|
||||
ExamList.EXAM_LIST_COLUMN_STARTTIME,
|
||||
this.pageService.getI18nSupport().getUsersTimeZoneTitleSuffix()),
|
||||
ExamConfigurationMap::getExamStartTime))
|
||||
|
||||
.withColumn(new ColumnDefinition<ExamConfigurationMap>(
|
||||
Domain.EXAM.ATTR_TYPE,
|
||||
ExamList.COLUMN_TITLE_TYPE_KEY,
|
||||
resourceService::localizedExamTypeName))
|
||||
|
||||
.withDefaultAction(this::showExamAction)
|
||||
|
||||
.compose(pageContext.copyOf(content));
|
||||
|
||||
actionBuilder
|
||||
|
||||
.newAction(ActionDefinition.EXAM_VIEW_FROM_LIST)
|
||||
.withExec(pageAction -> {
|
||||
final ExamConfigurationMap selectedExamMapping = getSelectedExamMapping(table);
|
||||
return pageAction.withEntityKey(
|
||||
new EntityKey(selectedExamMapping.examId, EntityType.EXAM));
|
||||
})
|
||||
.publishIf(table::hasAnyContent);
|
||||
}
|
||||
}
|
||||
|
||||
private PageAction showExamAction(final EntityTable<ExamConfigurationMap> table) {
|
||||
return this.pageService.pageActionBuilder(table.getPageContext())
|
||||
.newAction(ActionDefinition.EXAM_VIEW_FROM_LIST)
|
||||
.withSelectionSupplier(() -> {
|
||||
final ExamConfigurationMap selectedROWData = getSelectedExamMapping(table);
|
||||
return new HashSet<>(Arrays.asList(new EntityKey(selectedROWData.examId, EntityType.EXAM)));
|
||||
})
|
||||
.withExec(PageAction::applySingleSelectionAsEntityKey)
|
||||
.create();
|
||||
}
|
||||
|
||||
private ExamConfigurationMap getSelectedExamMapping(final EntityTable<ExamConfigurationMap> table) {
|
||||
final ExamConfigurationMap selectedROWData = table.getSingleSelectedROWData();
|
||||
|
||||
if (selectedROWData == null) {
|
||||
throw new PageMessageException(ExamList.EMPTY_SELECTION_TEXT_KEY);
|
||||
}
|
||||
return selectedROWData;
|
||||
}
|
||||
|
||||
private LocTextKey stateChangeConfirm(
|
||||
final boolean isAttachedToExam,
|
||||
final FormHandle<ConfigurationNode> formHandle) {
|
||||
|
||||
if (isAttachedToExam) {
|
||||
final String fieldValue = formHandle
|
||||
.getForm()
|
||||
.getFieldValue(Domain.CONFIGURATION_NODE.ATTR_STATUS);
|
||||
|
||||
if (fieldValue != null) {
|
||||
final ConfigurationStatus state = ConfigurationStatus.valueOf(fieldValue);
|
||||
if (state != ConfigurationStatus.IN_USE) {
|
||||
return SAVE_CONFIRM_STATE_CHANGE_WHILE_ATTACHED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Function<PageAction, PageAction> getConfigKeyFunction(final PageService pageService) {
|
||||
final RestService restService = pageService.getResourceService().getRestService();
|
||||
return action -> {
|
||||
final ConfigKey configKey = restService.getBuilder(ExportConfigKey.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, action.getEntityKey().modelId)
|
||||
.call()
|
||||
.getOrThrow();
|
||||
|
||||
final WidgetFactory widgetFactory = pageService.getWidgetFactory();
|
||||
final ModalInputDialog<Void> dialog = new ModalInputDialog<>(
|
||||
action.pageContext().getParent().getShell(),
|
||||
widgetFactory);
|
||||
|
||||
dialog.setDialogWidth(500);
|
||||
|
||||
dialog.open(
|
||||
CONFIG_KEY_TITLE_TEXT_KEY,
|
||||
action.pageContext(),
|
||||
pc -> {
|
||||
final Composite content = widgetFactory.defaultPageLayout(
|
||||
pc.getParent());
|
||||
|
||||
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;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.rap.rwt.RWT;
|
||||
import org.eclipse.rap.rwt.client.service.UrlLauncher;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.Text;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.ExamConfigurationMap;
|
||||
import ch.ethz.seb.sebserver.gbl.model.exam.QuizData;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigKey;
|
||||
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.ConfigurationType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.form.FormBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.form.FormHandle;
|
||||
import ch.ethz.seb.sebserver.gui.service.ResourceService;
|
||||
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.PageMessageException;
|
||||
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.TemplateComposer;
|
||||
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.remote.download.DownloadService;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.download.SebExamConfigPlaintextDownload;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExamConfigMappingNames;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExamConfigMappingsPage;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.ExportConfigKey;
|
||||
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.NewExamConfig;
|
||||
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.EntityGrantCheck;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.table.EntityTable;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class SebExamConfigPropForm implements TemplateComposer {
|
||||
|
||||
static final LocTextKey FORM_TITLE_NEW =
|
||||
new LocTextKey("sebserver.examconfig.form.title.new");
|
||||
static final LocTextKey FORM_TITLE =
|
||||
new LocTextKey("sebserver.examconfig.form.title");
|
||||
static final LocTextKey FORM_NAME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.form.name");
|
||||
static final LocTextKey FORM_DESCRIPTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.form.description");
|
||||
static final LocTextKey FORM_HISTORY_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.form.with-history");
|
||||
static final LocTextKey FORM_TEMPLATE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.form.template");
|
||||
static final LocTextKey FORM_STATUS_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.form.status");
|
||||
static final LocTextKey FORM_IMPORT_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.action.import-config");
|
||||
static final LocTextKey FORM_IMPORT_SELECT_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.action.import-file-select");
|
||||
static final LocTextKey FORM_IMPORT_PASSWORD_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.action.import-file-password");
|
||||
static final LocTextKey CONFIG_KEY_TITLE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.form.config-key.title");
|
||||
static final LocTextKey FORM_IMPORT_CONFIRM_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.action.import-config.confirm");
|
||||
static final LocTextKey FORM_ATTACHED_EXAMS_TITLE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.form.attached-to");
|
||||
static final LocTextKey FORM_ATTACHED_EXAMS_TITLE_TOOLTIP_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.form.attached-to" + Constants.TOOLTIP_TEXT_KEY_SUFFIX);
|
||||
|
||||
static final LocTextKey SAVE_CONFIRM_STATE_CHANGE_WHILE_ATTACHED =
|
||||
new LocTextKey("sebserver.examconfig.action.state-change.confirm");
|
||||
|
||||
private final PageService pageService;
|
||||
private final RestService restService;
|
||||
private final CurrentUser currentUser;
|
||||
private final DownloadService downloadService;
|
||||
private final String downloadFileName;
|
||||
|
||||
protected SebExamConfigPropForm(
|
||||
final PageService pageService,
|
||||
final CurrentUser currentUser,
|
||||
final DownloadService downloadService,
|
||||
@Value("${sebserver.gui.seb.exam.config.download.filename}") final String downloadFileName) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.restService = pageService.getRestService();
|
||||
this.currentUser = currentUser;
|
||||
this.downloadService = downloadService;
|
||||
this.downloadFileName = downloadFileName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
|
||||
final ResourceService resourceService = this.pageService.getResourceService();
|
||||
|
||||
final UserInfo user = this.currentUser.get();
|
||||
final EntityKey entityKey = pageContext.getEntityKey();
|
||||
final EntityKey parentEntityKey = pageContext.getParentEntityKey();
|
||||
final boolean isNew = entityKey == null;
|
||||
|
||||
// get data or create new. Handle error if happen
|
||||
final ConfigurationNode examConfig = (isNew)
|
||||
? ConfigurationNode.createNewExamConfig(user.institutionId)
|
||||
: this.restService
|
||||
.getBuilder(GetExamConfigNode.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
||||
.call()
|
||||
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_NODE, error))
|
||||
.getOrThrow();
|
||||
|
||||
final EntityGrantCheck entityGrant = this.currentUser.entityGrantCheck(examConfig);
|
||||
final boolean writeGrant = entityGrant.w();
|
||||
final boolean modifyGrant = entityGrant.m();
|
||||
final boolean isReadonly = pageContext.isReadonly();
|
||||
final boolean isAttachedToExam = !isNew && this.restService
|
||||
.getBuilder(GetExamConfigMappingNames.class)
|
||||
.withQueryParam(ExamConfigurationMap.FILTER_ATTR_CONFIG_ID, examConfig.getModelId())
|
||||
.call()
|
||||
.map(names -> names != null && !names.isEmpty())
|
||||
.getOr(Boolean.FALSE);
|
||||
|
||||
// new PageContext with actual EntityKey
|
||||
final PageContext formContext = pageContext.withEntityKey(examConfig.getEntityKey());
|
||||
|
||||
// the default page layout with interactive title
|
||||
final LocTextKey titleKey = (isNew)
|
||||
? FORM_TITLE_NEW
|
||||
: FORM_TITLE;
|
||||
final Composite content = widgetFactory.defaultPageLayout(
|
||||
formContext.getParent(),
|
||||
titleKey);
|
||||
|
||||
final List<Tuple<String>> examConfigTemplateResources = resourceService.getExamConfigTemplateResources();
|
||||
final FormHandle<ConfigurationNode> formHandle = this.pageService.formBuilder(
|
||||
formContext.copyOf(content))
|
||||
.readonly(isReadonly)
|
||||
.putStaticValueIf(() -> !isNew,
|
||||
Domain.CONFIGURATION_NODE.ATTR_ID,
|
||||
examConfig.getModelId())
|
||||
.putStaticValue(
|
||||
Domain.CONFIGURATION_NODE.ATTR_INSTITUTION_ID,
|
||||
String.valueOf(examConfig.getInstitutionId()))
|
||||
.putStaticValue(
|
||||
Domain.CONFIGURATION_NODE.ATTR_TYPE,
|
||||
ConfigurationType.EXAM_CONFIG.name())
|
||||
.addFieldIf(
|
||||
() -> !examConfigTemplateResources.isEmpty(),
|
||||
() -> FormBuilder.singleSelection(
|
||||
Domain.CONFIGURATION_NODE.ATTR_TEMPLATE_ID,
|
||||
FORM_TEMPLATE_TEXT_KEY,
|
||||
(parentEntityKey != null)
|
||||
? parentEntityKey.modelId
|
||||
: String.valueOf(examConfig.templateId),
|
||||
resourceService::getExamConfigTemplateResources)
|
||||
.readonly(!isNew))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.CONFIGURATION_NODE.ATTR_NAME,
|
||||
FORM_NAME_TEXT_KEY,
|
||||
examConfig.name)
|
||||
.mandatory(!isReadonly))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION,
|
||||
FORM_DESCRIPTION_TEXT_KEY,
|
||||
examConfig.description)
|
||||
.asArea())
|
||||
|
||||
.addField(FormBuilder.singleSelection(
|
||||
Domain.CONFIGURATION_NODE.ATTR_STATUS,
|
||||
FORM_STATUS_TEXT_KEY,
|
||||
examConfig.status.name(),
|
||||
() -> resourceService.examConfigStatusResources(isAttachedToExam))
|
||||
.withEmptyCellSeparation(!isReadonly))
|
||||
.buildFor((isNew)
|
||||
? this.restService.getRestCall(NewExamConfig.class)
|
||||
: this.restService.getRestCall(SaveExamConfig.class));
|
||||
|
||||
final boolean settingsReadonly = examConfig.status == ConfigurationStatus.IN_USE;
|
||||
final UrlLauncher urlLauncher = RWT.getClient().getService(UrlLauncher.class);
|
||||
final PageContext actionContext = formContext.clearEntityKeys();
|
||||
final PageActionBuilder actionBuilder = this.pageService.pageActionBuilder(actionContext);
|
||||
actionBuilder
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_NEW)
|
||||
.publishIf(() -> writeGrant && isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_PROP_MODIFY)
|
||||
.withEntityKey(entityKey)
|
||||
|
||||
.publishIf(() -> modifyGrant && isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY)
|
||||
.withEntityKey(entityKey)
|
||||
.withAttribute(PageContext.AttributeKeys.READ_ONLY, String.valueOf(!modifyGrant))
|
||||
.publishIf(() -> modifyGrant && isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_EXPORT_PLAIN_XML)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(action -> {
|
||||
final String downloadURL = this.downloadService.createDownloadURL(
|
||||
entityKey.modelId,
|
||||
SebExamConfigPlaintextDownload.class,
|
||||
this.downloadFileName);
|
||||
urlLauncher.openURL(downloadURL);
|
||||
return action;
|
||||
})
|
||||
.noEventPropagation()
|
||||
.publishIf(() -> modifyGrant && isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_GET_CONFIG_KEY)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(SebExamConfigPropForm.getConfigKeyFunction(this.pageService))
|
||||
.noEventPropagation()
|
||||
.publishIf(() -> modifyGrant && isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_IMPORT_TO_EXISTING_CONFIG)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(SebExamConfigImportPopup.importFunction(this.pageService, false))
|
||||
.noEventPropagation()
|
||||
.publishIf(() -> modifyGrant && isReadonly && !isAttachedToExam)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_COPY_CONFIG)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(SebExamConfigCreationPopup.configCreationFunction(
|
||||
this.pageService,
|
||||
actionContext
|
||||
.withEntityKey(entityKey)
|
||||
.withAttribute(
|
||||
PageContext.AttributeKeys.COPY_AS_TEMPLATE,
|
||||
Constants.FALSE_STRING)
|
||||
.withAttribute(
|
||||
PageContext.AttributeKeys.CREATE_FROM_TEMPLATE,
|
||||
Constants.FALSE_STRING)))
|
||||
.noEventPropagation()
|
||||
.publishIf(() -> modifyGrant && isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_COPY_CONFIG_AS_TEMPALTE)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(SebExamConfigCreationPopup.configCreationFunction(
|
||||
this.pageService,
|
||||
pageContext.withAttribute(
|
||||
PageContext.AttributeKeys.COPY_AS_TEMPLATE,
|
||||
Constants.TRUE_STRING)))
|
||||
.noEventPropagation()
|
||||
.publishIf(() -> modifyGrant && isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_PROP_SAVE)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(formHandle::processFormSave)
|
||||
.ignoreMoveAwayFromEdit()
|
||||
.withConfirm(() -> stateChangeConfirm(isAttachedToExam, formHandle))
|
||||
.publishIf(() -> !isReadonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_PROP_CANCEL_MODIFY)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(this.pageService.backToCurrentFunction())
|
||||
.publishIf(() -> !isReadonly);
|
||||
|
||||
if (isAttachedToExam && isReadonly) {
|
||||
|
||||
widgetFactory.label(content, StringUtils.EMPTY);
|
||||
widgetFactory.labelLocalized(
|
||||
content,
|
||||
CustomVariant.TEXT_H3,
|
||||
FORM_ATTACHED_EXAMS_TITLE_TEXT_KEY,
|
||||
FORM_ATTACHED_EXAMS_TITLE_TOOLTIP_TEXT_KEY);
|
||||
widgetFactory.labelSeparator(content);
|
||||
|
||||
final EntityTable<ExamConfigurationMap> table =
|
||||
this.pageService.entityTableBuilder(this.restService.getRestCall(GetExamConfigMappingsPage.class))
|
||||
.withRestCallAdapter(restCall -> restCall.withQueryParam(
|
||||
ExamConfigurationMap.FILTER_ATTR_CONFIG_ID, examConfig.getModelId()))
|
||||
.withPaging(1)
|
||||
.hideNavigation()
|
||||
.withRowDecorator(ExamList.decorateOnExamMapConsistency(this.pageService))
|
||||
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
QuizData.QUIZ_ATTR_NAME,
|
||||
ExamList.COLUMN_TITLE_NAME_KEY,
|
||||
ExamConfigurationMap::getExamName))
|
||||
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
QuizData.QUIZ_ATTR_START_TIME,
|
||||
new LocTextKey(
|
||||
ExamList.EXAM_LIST_COLUMN_STARTTIME,
|
||||
this.pageService.getI18nSupport().getUsersTimeZoneTitleSuffix()),
|
||||
ExamConfigurationMap::getExamStartTime))
|
||||
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.EXAM.ATTR_TYPE,
|
||||
ExamList.COLUMN_TITLE_TYPE_KEY,
|
||||
resourceService::localizedExamTypeName))
|
||||
|
||||
.withDefaultAction(this::showExamAction)
|
||||
|
||||
.withSelectionListener(this.pageService.getSelectionPublisher(
|
||||
pageContext,
|
||||
ActionDefinition.EXAM_VIEW_FROM_LIST))
|
||||
|
||||
.compose(pageContext.copyOf(content));
|
||||
|
||||
actionBuilder
|
||||
|
||||
.newAction(ActionDefinition.EXAM_VIEW_FROM_LIST)
|
||||
.withExec(pageAction -> {
|
||||
final ExamConfigurationMap selectedExamMapping = getSelectedExamMapping(table);
|
||||
return pageAction.withEntityKey(
|
||||
new EntityKey(selectedExamMapping.examId, EntityType.EXAM));
|
||||
})
|
||||
.publishIf(table::hasAnyContent, false);
|
||||
}
|
||||
}
|
||||
|
||||
private PageAction showExamAction(final EntityTable<ExamConfigurationMap> table) {
|
||||
return this.pageService.pageActionBuilder(table.getPageContext())
|
||||
.newAction(ActionDefinition.EXAM_VIEW_FROM_LIST)
|
||||
.withSelectionSupplier(() -> {
|
||||
final ExamConfigurationMap selectedROWData = getSelectedExamMapping(table);
|
||||
return new HashSet<>(Collections.singletonList(new EntityKey(selectedROWData.examId, EntityType.EXAM)));
|
||||
})
|
||||
.withExec(PageAction::applySingleSelectionAsEntityKey)
|
||||
.create();
|
||||
}
|
||||
|
||||
private ExamConfigurationMap getSelectedExamMapping(final EntityTable<ExamConfigurationMap> table) {
|
||||
final ExamConfigurationMap selectedROWData = table.getSingleSelectedROWData();
|
||||
|
||||
if (selectedROWData == null) {
|
||||
throw new PageMessageException(ExamList.EMPTY_SELECTION_TEXT_KEY);
|
||||
}
|
||||
return selectedROWData;
|
||||
}
|
||||
|
||||
private LocTextKey stateChangeConfirm(
|
||||
final boolean isAttachedToExam,
|
||||
final FormHandle<ConfigurationNode> formHandle) {
|
||||
|
||||
if (isAttachedToExam) {
|
||||
final String fieldValue = formHandle
|
||||
.getForm()
|
||||
.getFieldValue(Domain.CONFIGURATION_NODE.ATTR_STATUS);
|
||||
|
||||
if (fieldValue != null) {
|
||||
final ConfigurationStatus state = ConfigurationStatus.valueOf(fieldValue);
|
||||
if (state != ConfigurationStatus.IN_USE) {
|
||||
return SAVE_CONFIRM_STATE_CHANGE_WHILE_ATTACHED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Function<PageAction, PageAction> getConfigKeyFunction(final PageService pageService) {
|
||||
final RestService restService = pageService.getResourceService().getRestService();
|
||||
return action -> {
|
||||
final ConfigKey configKey = restService.getBuilder(ExportConfigKey.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, action.getEntityKey().modelId)
|
||||
.call()
|
||||
.getOrThrow();
|
||||
|
||||
final WidgetFactory widgetFactory = pageService.getWidgetFactory();
|
||||
final ModalInputDialog<Void> dialog = new ModalInputDialog<>(
|
||||
action.pageContext().getParent().getShell(),
|
||||
widgetFactory);
|
||||
|
||||
dialog.setDialogWidth(500);
|
||||
|
||||
dialog.open(
|
||||
CONFIG_KEY_TITLE_TEXT_KEY,
|
||||
action.pageContext(),
|
||||
pc -> {
|
||||
final Composite content = widgetFactory.defaultPageLayout(
|
||||
pc.getParent());
|
||||
|
||||
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;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,239 +1,238 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.TabFolder;
|
||||
import org.eclipse.swt.widgets.TabItem;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
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.api.APIMessage;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessageError;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
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.ConfigurationNode;
|
||||
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.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
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.impl.AttributeMapping;
|
||||
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.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageMessageException;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||
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.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.SebExamConfigUndo;
|
||||
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.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class SebExamConfigSettingsForm implements TemplateComposer {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(SebExamConfigSettingsForm.class);
|
||||
|
||||
private static final String VIEW_TEXT_KEY_PREFIX =
|
||||
"sebserver.examconfig.props.form.views.";
|
||||
private static final String KEY_SAVE_TO_HISTORY_SUCCESS =
|
||||
"sebserver.examconfig.action.saveToHistory.success";
|
||||
private static final String KEY_UNDO_SUCCESS =
|
||||
"sebserver.examconfig.action.undo.success";
|
||||
private static final LocTextKey TITLE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.props.from.title");
|
||||
|
||||
private static final LocTextKey MESSAGE_SAVE_INTEGRITY_VIOLATION =
|
||||
new LocTextKey("sebserver.examconfig.action.saveToHistory.integrity-violation");
|
||||
|
||||
private final PageService pageService;
|
||||
private final RestService restService;
|
||||
private final CurrentUser currentUser;
|
||||
private final ExamConfigurationService examConfigurationService;
|
||||
|
||||
protected SebExamConfigSettingsForm(
|
||||
final PageService pageService,
|
||||
final RestService restService,
|
||||
final CurrentUser currentUser,
|
||||
final ExamConfigurationService examConfigurationService) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.restService = restService;
|
||||
this.currentUser = currentUser;
|
||||
this.examConfigurationService = examConfigurationService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
|
||||
|
||||
final EntityKey entityKey = pageContext.getEntityKey();
|
||||
|
||||
final Composite content = widgetFactory.defaultPageLayout(
|
||||
pageContext.getParent(),
|
||||
TITLE_TEXT_KEY);
|
||||
|
||||
try {
|
||||
|
||||
final ConfigurationNode configNode = this.restService.getBuilder(GetExamConfigNode.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
||||
.call()
|
||||
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_NODE, error))
|
||||
.getOrThrow();
|
||||
|
||||
final Configuration configuration = this.restService.getBuilder(GetConfigurations.class)
|
||||
.withQueryParam(Configuration.FILTER_ATTR_CONFIGURATION_NODE_ID, configNode.getModelId())
|
||||
.withQueryParam(Configuration.FILTER_ATTR_FOLLOWUP, Constants.TRUE_STRING)
|
||||
.call()
|
||||
.map(Utils::toSingleton)
|
||||
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION, error))
|
||||
.getOrThrow();
|
||||
|
||||
final AttributeMapping attributes = this.examConfigurationService
|
||||
.getAttributes(configNode.templateId)
|
||||
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_ATTRIBUTE, error))
|
||||
.getOrThrow();
|
||||
|
||||
final boolean readonly = pageContext.isReadonly() || configNode.status == ConfigurationStatus.IN_USE;
|
||||
final List<View> views = this.examConfigurationService.getViews(attributes);
|
||||
final TabFolder tabFolder = widgetFactory.tabFolderLocalized(content);
|
||||
tabFolder.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
|
||||
|
||||
final List<ViewContext> viewContexts = new ArrayList<>();
|
||||
for (final View view : views) {
|
||||
final ViewContext viewContext = this.examConfigurationService.createViewContext(
|
||||
pageContext,
|
||||
configuration,
|
||||
view,
|
||||
attributes,
|
||||
20,
|
||||
readonly);
|
||||
viewContexts.add(viewContext);
|
||||
|
||||
final Composite viewGrid = this.examConfigurationService.createViewGrid(
|
||||
tabFolder,
|
||||
viewContext);
|
||||
|
||||
final TabItem tabItem = widgetFactory.tabItemLocalized(
|
||||
tabFolder,
|
||||
new LocTextKey(VIEW_TEXT_KEY_PREFIX + view.name));
|
||||
tabItem.setControl(viewGrid);
|
||||
}
|
||||
|
||||
// set selection if available
|
||||
final String viewIndex = pageContext.getAttribute("VIEW_INDEX");
|
||||
if (StringUtils.isNotBlank(viewIndex)) {
|
||||
try {
|
||||
tabFolder.setSelection(Integer.parseInt(viewIndex));
|
||||
} catch (final NumberFormatException e) {
|
||||
log.warn("Failed to initialize view selection");
|
||||
}
|
||||
}
|
||||
|
||||
this.examConfigurationService.initInputFieldValues(configuration.id, viewContexts);
|
||||
|
||||
final GrantCheck examConfigGrant = this.currentUser.grantCheck(EntityType.CONFIGURATION_NODE);
|
||||
this.pageService.pageActionBuilder(pageContext.clearEntityKeys())
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_SAVE_TO_HISTORY)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(action -> {
|
||||
this.restService.getBuilder(SaveExamConfigHistory.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, configuration.getModelId())
|
||||
.call()
|
||||
.onError(t -> notifyErrorOnSave(t, pageContext));
|
||||
return action.withAttribute(
|
||||
"VIEW_INDEX",
|
||||
String.valueOf(tabFolder.getSelectionIndex()));
|
||||
})
|
||||
.withSuccess(KEY_SAVE_TO_HISTORY_SUCCESS)
|
||||
.ignoreMoveAwayFromEdit()
|
||||
.publishIf(() -> examConfigGrant.iw() && !readonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_UNDO)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(action -> {
|
||||
this.restService.getBuilder(SebExamConfigUndo.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, configuration.getModelId())
|
||||
.call()
|
||||
.getOrThrow();
|
||||
return action.withAttribute(
|
||||
"VIEW_INDEX",
|
||||
String.valueOf(tabFolder.getSelectionIndex()));
|
||||
})
|
||||
.withSuccess(KEY_UNDO_SUCCESS)
|
||||
.ignoreMoveAwayFromEdit()
|
||||
.publishIf(() -> examConfigGrant.iw() && !readonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_COPY_CONFIG_AS_TEMPALTE)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(SebExamConfigCreationPopup.configCreationFunction(
|
||||
this.pageService,
|
||||
pageContext
|
||||
.withAttribute(
|
||||
PageContext.AttributeKeys.COPY_AS_TEMPLATE,
|
||||
Constants.TRUE_STRING)
|
||||
.withAttribute(
|
||||
PageContext.AttributeKeys.CREATE_FROM_TEMPLATE,
|
||||
Constants.FALSE_STRING)))
|
||||
.noEventPropagation()
|
||||
.publishIf(() -> examConfigGrant.iw())
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_PROP)
|
||||
.withEntityKey(entityKey)
|
||||
.ignoreMoveAwayFromEdit()
|
||||
.publish();
|
||||
|
||||
} catch (final RuntimeException e) {
|
||||
pageContext.notifyUnexpectedError(e);
|
||||
throw e;
|
||||
} catch (final Exception e) {
|
||||
log.error("Unexpected error while trying to fetch exam configuration data and create views", e);
|
||||
pageContext.notifyError(SebExamConfigPropForm.FORM_TITLE, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyErrorOnSave(final Exception error, final PageContext context) {
|
||||
if (error instanceof APIMessageError) {
|
||||
try {
|
||||
final List<APIMessage> errorMessages = ((APIMessageError) error).getErrorMessages();
|
||||
final APIMessage apiMessage = errorMessages.get(0);
|
||||
if (APIMessage.ErrorMessage.INTEGRITY_VALIDATION.isOf(apiMessage)) {
|
||||
throw new PageMessageException(MESSAGE_SAVE_INTEGRITY_VIOLATION);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
} catch (final PageMessageException e) {
|
||||
throw e;
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.TabFolder;
|
||||
import org.eclipse.swt.widgets.TabItem;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
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.api.APIMessage;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessageError;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
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.ConfigurationNode;
|
||||
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.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
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.impl.AttributeMapping;
|
||||
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.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageMessageException;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||
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.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.SebExamConfigUndo;
|
||||
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.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class SebExamConfigSettingsForm implements TemplateComposer {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(SebExamConfigSettingsForm.class);
|
||||
|
||||
private static final String VIEW_TEXT_KEY_PREFIX =
|
||||
"sebserver.examconfig.props.form.views.";
|
||||
private static final String KEY_SAVE_TO_HISTORY_SUCCESS =
|
||||
"sebserver.examconfig.action.saveToHistory.success";
|
||||
private static final String KEY_UNDO_SUCCESS =
|
||||
"sebserver.examconfig.action.undo.success";
|
||||
private static final LocTextKey TITLE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.examconfig.props.from.title");
|
||||
|
||||
private static final LocTextKey MESSAGE_SAVE_INTEGRITY_VIOLATION =
|
||||
new LocTextKey("sebserver.examconfig.action.saveToHistory.integrity-violation");
|
||||
|
||||
private final PageService pageService;
|
||||
private final RestService restService;
|
||||
private final CurrentUser currentUser;
|
||||
private final ExamConfigurationService examConfigurationService;
|
||||
|
||||
protected SebExamConfigSettingsForm(
|
||||
final PageService pageService,
|
||||
final RestService restService,
|
||||
final CurrentUser currentUser,
|
||||
final ExamConfigurationService examConfigurationService) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.restService = restService;
|
||||
this.currentUser = currentUser;
|
||||
this.examConfigurationService = examConfigurationService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
|
||||
|
||||
final EntityKey entityKey = pageContext.getEntityKey();
|
||||
|
||||
final Composite content = widgetFactory.defaultPageLayout(
|
||||
pageContext.getParent(),
|
||||
TITLE_TEXT_KEY);
|
||||
|
||||
try {
|
||||
|
||||
final ConfigurationNode configNode = this.restService.getBuilder(GetExamConfigNode.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
||||
.call()
|
||||
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_NODE, error))
|
||||
.getOrThrow();
|
||||
|
||||
final Configuration configuration = this.restService.getBuilder(GetConfigurations.class)
|
||||
.withQueryParam(Configuration.FILTER_ATTR_CONFIGURATION_NODE_ID, configNode.getModelId())
|
||||
.withQueryParam(Configuration.FILTER_ATTR_FOLLOWUP, Constants.TRUE_STRING)
|
||||
.call()
|
||||
.map(Utils::toSingleton)
|
||||
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION, error))
|
||||
.getOrThrow();
|
||||
|
||||
final AttributeMapping attributes = this.examConfigurationService
|
||||
.getAttributes(configNode.templateId)
|
||||
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION_ATTRIBUTE, error))
|
||||
.getOrThrow();
|
||||
|
||||
final boolean readonly = pageContext.isReadonly() || configNode.status == ConfigurationStatus.IN_USE;
|
||||
final List<View> views = this.examConfigurationService.getViews(attributes);
|
||||
final TabFolder tabFolder = widgetFactory.tabFolderLocalized(content);
|
||||
tabFolder.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
|
||||
|
||||
final List<ViewContext> viewContexts = new ArrayList<>();
|
||||
for (final View view : views) {
|
||||
final ViewContext viewContext = this.examConfigurationService.createViewContext(
|
||||
pageContext,
|
||||
configuration,
|
||||
view,
|
||||
attributes,
|
||||
20,
|
||||
readonly);
|
||||
viewContexts.add(viewContext);
|
||||
|
||||
final Composite viewGrid = this.examConfigurationService.createViewGrid(
|
||||
tabFolder,
|
||||
viewContext);
|
||||
|
||||
final TabItem tabItem = widgetFactory.tabItemLocalized(
|
||||
tabFolder,
|
||||
new LocTextKey(VIEW_TEXT_KEY_PREFIX + view.name));
|
||||
tabItem.setControl(viewGrid);
|
||||
}
|
||||
|
||||
// set selection if available
|
||||
final String viewIndex = pageContext.getAttribute("VIEW_INDEX");
|
||||
if (StringUtils.isNotBlank(viewIndex)) {
|
||||
try {
|
||||
tabFolder.setSelection(Integer.parseInt(viewIndex));
|
||||
} catch (final NumberFormatException e) {
|
||||
log.warn("Failed to initialize view selection");
|
||||
}
|
||||
}
|
||||
|
||||
this.examConfigurationService.initInputFieldValues(configuration.id, viewContexts);
|
||||
|
||||
final GrantCheck examConfigGrant = this.currentUser.grantCheck(EntityType.CONFIGURATION_NODE);
|
||||
this.pageService.pageActionBuilder(pageContext.clearEntityKeys())
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_SAVE_TO_HISTORY)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(action -> {
|
||||
this.restService.getBuilder(SaveExamConfigHistory.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, configuration.getModelId())
|
||||
.call()
|
||||
.onError(t -> notifyErrorOnSave(t, pageContext));
|
||||
return action.withAttribute(
|
||||
"VIEW_INDEX",
|
||||
String.valueOf(tabFolder.getSelectionIndex()));
|
||||
})
|
||||
.withSuccess(KEY_SAVE_TO_HISTORY_SUCCESS)
|
||||
.ignoreMoveAwayFromEdit()
|
||||
.publishIf(() -> examConfigGrant.iw() && !readonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_UNDO)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(action -> {
|
||||
this.restService.getBuilder(SebExamConfigUndo.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, configuration.getModelId())
|
||||
.call()
|
||||
.getOrThrow();
|
||||
return action.withAttribute(
|
||||
"VIEW_INDEX",
|
||||
String.valueOf(tabFolder.getSelectionIndex()));
|
||||
})
|
||||
.withSuccess(KEY_UNDO_SUCCESS)
|
||||
.ignoreMoveAwayFromEdit()
|
||||
.publishIf(() -> examConfigGrant.iw() && !readonly)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_COPY_CONFIG_AS_TEMPALTE)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(SebExamConfigCreationPopup.configCreationFunction(
|
||||
this.pageService,
|
||||
pageContext
|
||||
.withAttribute(
|
||||
PageContext.AttributeKeys.COPY_AS_TEMPLATE,
|
||||
Constants.TRUE_STRING)
|
||||
.withAttribute(
|
||||
PageContext.AttributeKeys.CREATE_FROM_TEMPLATE,
|
||||
Constants.FALSE_STRING)))
|
||||
.noEventPropagation()
|
||||
.publishIf(examConfigGrant::iw)
|
||||
|
||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_PROP)
|
||||
.withEntityKey(entityKey)
|
||||
.ignoreMoveAwayFromEdit()
|
||||
.publish();
|
||||
|
||||
} catch (final RuntimeException e) {
|
||||
pageContext.notifyUnexpectedError(e);
|
||||
throw e;
|
||||
} catch (final Exception e) {
|
||||
log.error("Unexpected error while trying to fetch exam configuration data and create views", e);
|
||||
pageContext.notifyError(SebExamConfigPropForm.FORM_TITLE, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyErrorOnSave(final Exception error, final PageContext context) {
|
||||
if (error instanceof APIMessageError) {
|
||||
try {
|
||||
final List<APIMessage> errorMessages = ((APIMessageError) error).getErrorMessages();
|
||||
final APIMessage apiMessage = errorMessages.get(0);
|
||||
if (APIMessage.ErrorMessage.INTEGRITY_VALIDATION.isOf(apiMessage)) {
|
||||
throw new PageMessageException(MESSAGE_SAVE_INTEGRITY_VIOLATION);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
} catch (final PageMessageException e) {
|
||||
throw e;
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,143 +1,147 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.MessageBox;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
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.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.form.FormBuilder;
|
||||
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.LocTextKey;
|
||||
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.TemplateComposer;
|
||||
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.useraccount.ChangePassword;
|
||||
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.widget.Message;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
/** 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
|
||||
* match the users current password.
|
||||
* 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. */
|
||||
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 =
|
||||
new LocTextKey("sebserver.useraccount.form.password.new");
|
||||
private static final LocTextKey FORM_PASSWORD_NEW_CONFIRM_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.form.password.new.confirm");
|
||||
private static final LocTextKey FORM_PASSWORD_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.form.password");
|
||||
|
||||
private final PageService pageService;
|
||||
private final RestService restService;
|
||||
private final CurrentUser currentUser;
|
||||
private final I18nSupport i18nSupport;
|
||||
|
||||
protected UserAccountChangePasswordForm(
|
||||
final PageService pageService,
|
||||
final RestService restService,
|
||||
final CurrentUser currentUser) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.restService = restService;
|
||||
this.currentUser = currentUser;
|
||||
this.i18nSupport = pageService.getI18nSupport();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
|
||||
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
|
||||
final EntityKey entityKey = pageContext.getEntityKey();
|
||||
|
||||
final UserInfo userInfo = this.restService
|
||||
.getBuilder(GetUserAccount.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
||||
.call()
|
||||
.onError(error -> pageContext.notifyLoadError(EntityType.USER, error))
|
||||
.getOrThrow();
|
||||
|
||||
final Composite content = widgetFactory.defaultPageLayout(
|
||||
pageContext.getParent(),
|
||||
new LocTextKey(FORM_TITLE_KEY, userInfo.username));
|
||||
|
||||
final boolean ownAccount = this.currentUser.get().uuid.equals(entityKey.getModelId());
|
||||
|
||||
// The Password Change form
|
||||
final FormHandle<UserInfo> formHandle = this.pageService.formBuilder(pageContext.copyOf(content))
|
||||
.readonly(false)
|
||||
.putStaticValueIf(() -> entityKey != null,
|
||||
Domain.USER.ATTR_UUID,
|
||||
entityKey.getModelId())
|
||||
.addField(FormBuilder.text(
|
||||
PasswordChange.ATTR_NAME_PASSWORD,
|
||||
FORM_PASSWORD_TEXT_KEY)
|
||||
.asPasswordField())
|
||||
.addField(FormBuilder.text(
|
||||
PasswordChange.ATTR_NAME_NEW_PASSWORD,
|
||||
FORM_PASSWORD_NEW_TEXT_KEY)
|
||||
.asPasswordField())
|
||||
.addFieldIf(
|
||||
() -> entityKey != null,
|
||||
() -> FormBuilder.text(
|
||||
PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD,
|
||||
FORM_PASSWORD_NEW_CONFIRM_TEXT_KEY)
|
||||
.asPasswordField())
|
||||
.buildFor(this.restService.getRestCall(ChangePassword.class));
|
||||
|
||||
this.pageService.pageActionBuilder(pageContext)
|
||||
|
||||
.newAction(ActionDefinition.USER_ACCOUNT_CHANGE_PASSOWRD_SAVE)
|
||||
.withExec(action -> {
|
||||
final PageAction saveAction = formHandle.processFormSave(action);
|
||||
if (ownAccount) {
|
||||
// NOTE: in this case the user changed the password of the own account
|
||||
// this should cause an logout with specified message that password change
|
||||
// was successful and the pointing the need of re login with the new password
|
||||
this.pageService.logout(pageContext);
|
||||
final MessageBox error = new Message(
|
||||
pageContext.getShell(),
|
||||
this.i18nSupport.getText("sebserver.login.password.change"),
|
||||
this.i18nSupport.getText("sebserver.login.password.change.success"),
|
||||
SWT.ICON_INFORMATION,
|
||||
this.i18nSupport);
|
||||
error.open(null);
|
||||
}
|
||||
return saveAction;
|
||||
})
|
||||
.ignoreMoveAwayFromEdit()
|
||||
.publish()
|
||||
|
||||
.newAction(ActionDefinition.USER_ACCOUNT_CANCEL_MODIFY)
|
||||
.withExec(this.pageService.backToCurrentFunction())
|
||||
.publish();
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.MessageBox;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
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.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.form.FormBuilder;
|
||||
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.LocTextKey;
|
||||
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.TemplateComposer;
|
||||
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.useraccount.ChangePassword;
|
||||
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.widget.Message;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
/** 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
|
||||
* match the users current password.
|
||||
* 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.
|
||||
**/
|
||||
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 =
|
||||
new LocTextKey("sebserver.useraccount.form.password.new");
|
||||
private static final LocTextKey FORM_PASSWORD_NEW_CONFIRM_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.form.password.new.confirm");
|
||||
private static final LocTextKey FORM_PASSWORD_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.form.password");
|
||||
|
||||
private final PageService pageService;
|
||||
private final RestService restService;
|
||||
private final CurrentUser currentUser;
|
||||
private final I18nSupport i18nSupport;
|
||||
|
||||
protected UserAccountChangePasswordForm(
|
||||
final PageService pageService,
|
||||
final RestService restService,
|
||||
final CurrentUser currentUser) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.restService = restService;
|
||||
this.currentUser = currentUser;
|
||||
this.i18nSupport = pageService.getI18nSupport();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
|
||||
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
|
||||
final EntityKey entityKey = pageContext.getEntityKey();
|
||||
|
||||
final UserInfo userInfo = this.restService
|
||||
.getBuilder(GetUserAccount.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
||||
.call()
|
||||
.onError(error -> pageContext.notifyLoadError(EntityType.USER, error))
|
||||
.getOrThrow();
|
||||
|
||||
final Composite content = widgetFactory.defaultPageLayout(
|
||||
pageContext.getParent(),
|
||||
new LocTextKey(FORM_TITLE_KEY, userInfo.username));
|
||||
|
||||
final boolean ownAccount = this.currentUser.get().uuid.equals(entityKey.getModelId());
|
||||
|
||||
// The Password Change form
|
||||
final FormHandle<UserInfo> formHandle = this.pageService.formBuilder(pageContext.copyOf(content))
|
||||
.readonly(false)
|
||||
.putStaticValueIf(() -> entityKey != null,
|
||||
Domain.USER.ATTR_UUID,
|
||||
entityKey.getModelId())
|
||||
.addField(FormBuilder.text(
|
||||
PasswordChange.ATTR_NAME_PASSWORD,
|
||||
FORM_PASSWORD_TEXT_KEY)
|
||||
.asPasswordField()
|
||||
.mandatory())
|
||||
.addField(FormBuilder.text(
|
||||
PasswordChange.ATTR_NAME_NEW_PASSWORD,
|
||||
FORM_PASSWORD_NEW_TEXT_KEY)
|
||||
.asPasswordField()
|
||||
.mandatory())
|
||||
.addFieldIf(
|
||||
() -> entityKey != null,
|
||||
() -> FormBuilder.text(
|
||||
PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD,
|
||||
FORM_PASSWORD_NEW_CONFIRM_TEXT_KEY)
|
||||
.asPasswordField()
|
||||
.mandatory())
|
||||
.buildFor(this.restService.getRestCall(ChangePassword.class));
|
||||
|
||||
this.pageService.pageActionBuilder(pageContext)
|
||||
|
||||
.newAction(ActionDefinition.USER_ACCOUNT_CHANGE_PASSWORD_SAVE)
|
||||
.withExec(action -> {
|
||||
final PageAction saveAction = formHandle.processFormSave(action);
|
||||
if (ownAccount) {
|
||||
// NOTE: in this case the user changed the password of the own account
|
||||
// this should cause an logout with specified message that password change
|
||||
// was successful and the pointing the need of re login with the new password
|
||||
this.pageService.logout(pageContext);
|
||||
final MessageBox error = new Message(
|
||||
pageContext.getShell(),
|
||||
this.i18nSupport.getText("sebserver.login.password.change"),
|
||||
this.i18nSupport.getText("sebserver.login.password.change.success"),
|
||||
SWT.ICON_INFORMATION,
|
||||
this.i18nSupport);
|
||||
error.open(null);
|
||||
}
|
||||
return saveAction;
|
||||
})
|
||||
.ignoreMoveAwayFromEdit()
|
||||
.publish()
|
||||
|
||||
.newAction(ActionDefinition.USER_ACCOUNT_CANCEL_MODIFY)
|
||||
.withExec(this.pageService.backToCurrentFunction())
|
||||
.publish();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,279 +1,291 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.tomcat.util.buf.StringUtils;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
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.PrivilegeType;
|
||||
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.EntityKey;
|
||||
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.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserMod;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.form.FormBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.form.FormHandle;
|
||||
import ch.ethz.seb.sebserver.gui.service.ResourceService;
|
||||
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.PageService;
|
||||
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.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.DeactivateUserAccount;
|
||||
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.SaveUserAccount;
|
||||
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.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class UserAccountForm implements TemplateComposer {
|
||||
|
||||
static final LocTextKey TITLE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.form.title");
|
||||
static final LocTextKey NEW_TITLE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.form.title.new");
|
||||
|
||||
static final LocTextKey FORM_PASSWORD_CONFIRM_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.form.password.confirm");
|
||||
static final LocTextKey FORM_PASSWORD_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.form.password");
|
||||
static final LocTextKey FORM_ROLES_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.form.roles");
|
||||
static final LocTextKey FORM_TIMEZONE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.form.timezone");
|
||||
static final LocTextKey FORM_MAIL_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.form.mail");
|
||||
static final LocTextKey FORM_USERNAME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.form.username");
|
||||
static final LocTextKey FORM_NAME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.form.name");
|
||||
static final LocTextKey FORM_SURNAME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.form.surname");
|
||||
static final LocTextKey FORM_INSTITUTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.form.institution");
|
||||
static final LocTextKey FORM_CREATION_DATE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.form.creationdate");
|
||||
static final LocTextKey FORM_LANG_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.form.language");
|
||||
|
||||
private final PageService pageService;
|
||||
private final ResourceService resourceService;
|
||||
private final boolean multilingual;
|
||||
|
||||
protected UserAccountForm(
|
||||
final PageService pageService,
|
||||
final ResourceService resourceService,
|
||||
@Value("${sebserver.gui.multilingual:false}") final Boolean multilingual) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.resourceService = resourceService;
|
||||
this.multilingual = BooleanUtils.toBoolean(multilingual);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
final CurrentUser currentUser = this.resourceService.getCurrentUser();
|
||||
final RestService restService = this.resourceService.getRestService();
|
||||
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
|
||||
|
||||
final UserInfo user = currentUser.get();
|
||||
final EntityKey entityKey = pageContext.getEntityKey();
|
||||
final EntityKey parentEntityKey = pageContext.getParentEntityKey();
|
||||
final boolean readonly = pageContext.isReadonly();
|
||||
|
||||
final BooleanSupplier isNew = () -> entityKey == null;
|
||||
final BooleanSupplier isNotNew = () -> !isNew.getAsBoolean();
|
||||
final BooleanSupplier isSEBAdmin = () -> user.hasRole(UserRole.SEB_SERVER_ADMIN);
|
||||
|
||||
// get data or create new. handle error if happen
|
||||
final UserAccount userAccount = isNew.getAsBoolean()
|
||||
? UserMod.createNew((parentEntityKey != null)
|
||||
? Long.valueOf(parentEntityKey.modelId)
|
||||
: user.institutionId)
|
||||
: restService
|
||||
.getBuilder(GetUserAccount.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
||||
.call()
|
||||
.onError(error -> pageContext.notifyLoadError(EntityType.USER, error))
|
||||
.getOrThrow();
|
||||
|
||||
final boolean roleBasedEditGrant = Privilege.hasRoleBasedUserAccountEditGrant(userAccount, currentUser.get());
|
||||
// new PageContext with actual EntityKey
|
||||
final PageContext formContext = pageContext.withEntityKey(userAccount.getEntityKey());
|
||||
final boolean ownAccount = user.uuid.equals(userAccount.getModelId());
|
||||
final EntityGrantCheck userGrantCheck = currentUser.entityGrantCheck(userAccount);
|
||||
|
||||
final boolean writeGrant = roleBasedEditGrant && userGrantCheck.w();
|
||||
final boolean modifyGrant = roleBasedEditGrant && userGrantCheck.m();
|
||||
final boolean institutionalWriteGrant = currentUser.hasInstitutionalPrivilege(
|
||||
PrivilegeType.WRITE,
|
||||
EntityType.USER);
|
||||
|
||||
final boolean institutionActive = restService.getBuilder(GetInstitution.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, String.valueOf(userAccount.getInstitutionId()))
|
||||
.call()
|
||||
.map(inst -> inst.active)
|
||||
.getOr(false);
|
||||
|
||||
// the default page layout with title
|
||||
final LocTextKey titleKey = isNotNew.getAsBoolean()
|
||||
? TITLE_TEXT_KEY
|
||||
: NEW_TITLE_TEXT_KEY;
|
||||
final Composite content = widgetFactory.defaultPageLayout(
|
||||
formContext.getParent(),
|
||||
titleKey);
|
||||
|
||||
// The UserAccount form
|
||||
final FormHandle<UserInfo> formHandle = this.pageService.formBuilder(
|
||||
formContext.copyOf(content))
|
||||
.readonly(readonly)
|
||||
.putStaticValueIf(isNotNew,
|
||||
Domain.USER.ATTR_UUID,
|
||||
userAccount.getModelId())
|
||||
.putStaticValueIf(isNotNew,
|
||||
Domain.USER.ATTR_INSTITUTION_ID,
|
||||
String.valueOf(userAccount.getInstitutionId()))
|
||||
.putStaticValueIf(
|
||||
() -> !this.multilingual,
|
||||
Domain.USER.ATTR_LANGUAGE,
|
||||
"en")
|
||||
.addFieldIf(
|
||||
isSEBAdmin,
|
||||
() -> FormBuilder.singleSelection(
|
||||
Domain.USER.ATTR_INSTITUTION_ID,
|
||||
FORM_INSTITUTION_TEXT_KEY,
|
||||
String.valueOf(userAccount.getInstitutionId()),
|
||||
() -> this.resourceService.institutionResource())
|
||||
.readonlyIf(isNotNew))
|
||||
.addFieldIf(
|
||||
() -> readonly,
|
||||
() -> FormBuilder.text(
|
||||
Domain.USER.ATTR_CREATION_DATE,
|
||||
FORM_CREATION_DATE_TEXT_KEY,
|
||||
this.pageService.getI18nSupport().formatDisplayDate(userAccount.getCreationDate()))
|
||||
.readonly(true))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.USER.ATTR_NAME,
|
||||
FORM_NAME_TEXT_KEY,
|
||||
userAccount.getName()))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.USER.ATTR_SURNAME,
|
||||
FORM_SURNAME_TEXT_KEY,
|
||||
userAccount.getSurname()))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.USER.ATTR_USERNAME,
|
||||
FORM_USERNAME_TEXT_KEY,
|
||||
userAccount.getUsername()))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.USER.ATTR_EMAIL,
|
||||
FORM_MAIL_TEXT_KEY,
|
||||
userAccount.getEmail()))
|
||||
.addFieldIf(
|
||||
() -> this.multilingual,
|
||||
() -> FormBuilder.singleSelection(
|
||||
Domain.USER.ATTR_LANGUAGE,
|
||||
FORM_LANG_TEXT_KEY,
|
||||
userAccount.getLanguage().getLanguage(),
|
||||
this.resourceService::languageResources))
|
||||
.addField(FormBuilder.singleSelection(
|
||||
Domain.USER.ATTR_TIMEZONE,
|
||||
FORM_TIMEZONE_TEXT_KEY,
|
||||
userAccount.getTimeZone().getID(),
|
||||
this.resourceService::timeZoneResources))
|
||||
.addFieldIf(
|
||||
() -> modifyGrant,
|
||||
() -> FormBuilder.multiCheckboxSelection(
|
||||
USER_ROLE.REFERENCE_NAME,
|
||||
FORM_ROLES_TEXT_KEY,
|
||||
StringUtils.join(userAccount.getRoles(), Constants.LIST_SEPARATOR_CHAR),
|
||||
this.resourceService::userRoleResources)
|
||||
.visibleIf(writeGrant))
|
||||
.addFieldIf(
|
||||
isNew,
|
||||
() -> FormBuilder.text(
|
||||
PasswordChange.ATTR_NAME_NEW_PASSWORD,
|
||||
FORM_PASSWORD_TEXT_KEY)
|
||||
.asPasswordField())
|
||||
.addFieldIf(
|
||||
isNew,
|
||||
() -> FormBuilder.text(
|
||||
PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD,
|
||||
FORM_PASSWORD_CONFIRM_TEXT_KEY)
|
||||
.asPasswordField())
|
||||
.buildFor((entityKey == null)
|
||||
? restService.getRestCall(NewUserAccount.class)
|
||||
: restService.getRestCall(SaveUserAccount.class));
|
||||
|
||||
// propagate content actions to action-pane
|
||||
this.pageService.pageActionBuilder(formContext.clearEntityKeys())
|
||||
|
||||
.newAction(ActionDefinition.USER_ACCOUNT_NEW)
|
||||
.publishIf(() -> institutionalWriteGrant && readonly && institutionActive)
|
||||
|
||||
.newAction(ActionDefinition.USER_ACCOUNT_MODIFY)
|
||||
.withEntityKey(entityKey)
|
||||
.publishIf(() -> modifyGrant && readonly && institutionActive)
|
||||
|
||||
.newAction(ActionDefinition.USER_ACCOUNT_CHANGE_PASSOWRD)
|
||||
.withEntityKey(entityKey)
|
||||
.publishIf(() -> modifyGrant && readonly && institutionActive && userAccount.isActive())
|
||||
|
||||
.newAction(ActionDefinition.USER_ACCOUNT_DEACTIVATE)
|
||||
.withEntityKey(entityKey)
|
||||
.withSimpleRestCall(restService, DeactivateUserAccount.class)
|
||||
.withConfirm(this.pageService.confirmDeactivation(userAccount))
|
||||
.publishIf(() -> writeGrant && readonly && institutionActive && userAccount.isActive())
|
||||
|
||||
.newAction(ActionDefinition.USER_ACCOUNT_ACTIVATE)
|
||||
.withEntityKey(entityKey)
|
||||
.withSimpleRestCall(restService, ActivateUserAccount.class)
|
||||
.publishIf(() -> writeGrant && readonly && institutionActive && !userAccount.isActive())
|
||||
|
||||
.newAction(ActionDefinition.USER_ACCOUNT_SAVE)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(action -> {
|
||||
return formHandle.handleFormPost(formHandle.doAPIPost()
|
||||
.map(userInfo -> {
|
||||
if (ownAccount) {
|
||||
currentUser.refresh(userInfo);
|
||||
}
|
||||
return userInfo;
|
||||
}),
|
||||
action);
|
||||
})
|
||||
.ignoreMoveAwayFromEdit()
|
||||
.publishIf(() -> !readonly)
|
||||
|
||||
.newAction(ActionDefinition.USER_ACCOUNT_CANCEL_MODIFY)
|
||||
.withExec(this.pageService.backToCurrentFunction())
|
||||
.publishIf(() -> !readonly);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.tomcat.util.buf.StringUtils;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
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.PrivilegeType;
|
||||
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.EntityKey;
|
||||
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.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserMod;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.form.FormBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.form.FormHandle;
|
||||
import ch.ethz.seb.sebserver.gui.service.ResourceService;
|
||||
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.PageService;
|
||||
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.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.DeactivateUserAccount;
|
||||
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.SaveUserAccount;
|
||||
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.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class UserAccountForm implements TemplateComposer {
|
||||
|
||||
static final LocTextKey TITLE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.form.title");
|
||||
static final LocTextKey NEW_TITLE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.form.title.new");
|
||||
|
||||
static final LocTextKey FORM_PASSWORD_CONFIRM_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.form.password.confirm");
|
||||
static final LocTextKey FORM_PASSWORD_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.form.password");
|
||||
static final LocTextKey FORM_ROLES_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.form.roles");
|
||||
static final LocTextKey FORM_TIMEZONE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.form.timezone");
|
||||
static final LocTextKey FORM_MAIL_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.form.mail");
|
||||
static final LocTextKey FORM_USERNAME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.form.username");
|
||||
static final LocTextKey FORM_NAME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.form.name");
|
||||
static final LocTextKey FORM_SURNAME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.form.surname");
|
||||
static final LocTextKey FORM_INSTITUTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.form.institution");
|
||||
static final LocTextKey FORM_CREATION_DATE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.form.creationdate");
|
||||
static final LocTextKey FORM_LANG_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.form.language");
|
||||
|
||||
private final PageService pageService;
|
||||
private final ResourceService resourceService;
|
||||
private final boolean multilingual;
|
||||
|
||||
protected UserAccountForm(
|
||||
final PageService pageService,
|
||||
final ResourceService resourceService,
|
||||
@Value("${sebserver.gui.multilingual:false}") final Boolean multilingual) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.resourceService = resourceService;
|
||||
this.multilingual = BooleanUtils.toBoolean(multilingual);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
final CurrentUser currentUser = this.resourceService.getCurrentUser();
|
||||
final RestService restService = this.resourceService.getRestService();
|
||||
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
|
||||
|
||||
final UserInfo user = currentUser.get();
|
||||
final EntityKey entityKey = pageContext.getEntityKey();
|
||||
final EntityKey parentEntityKey = pageContext.getParentEntityKey();
|
||||
final boolean readonly = pageContext.isReadonly();
|
||||
|
||||
final BooleanSupplier isNew = () -> entityKey == null;
|
||||
final BooleanSupplier isNotNew = () -> !isNew.getAsBoolean();
|
||||
final BooleanSupplier isSEBAdmin = () -> user.hasRole(UserRole.SEB_SERVER_ADMIN);
|
||||
|
||||
// get data or create new. handle error if happen
|
||||
final UserAccount userAccount = isNew.getAsBoolean()
|
||||
? UserMod.createNew((parentEntityKey != null)
|
||||
? Long.valueOf(parentEntityKey.modelId)
|
||||
: currentUser.get().institutionId)
|
||||
: restService
|
||||
.getBuilder(GetUserAccount.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
||||
.call()
|
||||
.onError(error -> pageContext.notifyLoadError(EntityType.USER, error))
|
||||
.getOrThrow();
|
||||
|
||||
final boolean roleBasedEditGrant = Privilege.hasRoleBasedUserAccountEditGrant(userAccount, currentUser.get());
|
||||
// new PageContext with actual EntityKey
|
||||
final PageContext formContext = pageContext.withEntityKey(userAccount.getEntityKey());
|
||||
final boolean ownAccount = user.uuid.equals(userAccount.getModelId());
|
||||
final EntityGrantCheck userGrantCheck = currentUser.entityGrantCheck(userAccount);
|
||||
|
||||
final boolean writeGrant = roleBasedEditGrant && userGrantCheck.w();
|
||||
final boolean modifyGrant = roleBasedEditGrant && userGrantCheck.m();
|
||||
final boolean institutionalWriteGrant = currentUser.hasInstitutionalPrivilege(
|
||||
PrivilegeType.WRITE,
|
||||
EntityType.USER);
|
||||
|
||||
final boolean institutionActive = userAccount.getInstitutionId() != null &&
|
||||
restService.getBuilder(GetInstitution.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, String.valueOf(userAccount.getInstitutionId()))
|
||||
.call()
|
||||
.map(inst -> inst.active)
|
||||
.getOr(false);
|
||||
|
||||
// the default page layout with title
|
||||
final LocTextKey titleKey = isNotNew.getAsBoolean()
|
||||
? TITLE_TEXT_KEY
|
||||
: NEW_TITLE_TEXT_KEY;
|
||||
final Composite content = widgetFactory.defaultPageLayout(
|
||||
formContext.getParent(),
|
||||
titleKey);
|
||||
|
||||
// The UserAccount form
|
||||
final FormHandle<UserInfo> formHandle = this.pageService.formBuilder(
|
||||
formContext.copyOf(content))
|
||||
.readonly(readonly)
|
||||
.putStaticValueIf(isNotNew,
|
||||
Domain.USER.ATTR_UUID,
|
||||
userAccount.getModelId())
|
||||
.putStaticValueIf(isNotNew,
|
||||
Domain.USER.ATTR_INSTITUTION_ID,
|
||||
String.valueOf(userAccount.getInstitutionId()))
|
||||
.putStaticValueIf(
|
||||
() -> !this.multilingual,
|
||||
Domain.USER.ATTR_LANGUAGE,
|
||||
"en")
|
||||
.addFieldIf(
|
||||
isSEBAdmin,
|
||||
() -> FormBuilder.singleSelection(
|
||||
Domain.USER.ATTR_INSTITUTION_ID,
|
||||
FORM_INSTITUTION_TEXT_KEY,
|
||||
String.valueOf(userAccount.getInstitutionId()),
|
||||
this.resourceService::institutionResource)
|
||||
.readonlyIf(isNotNew)
|
||||
.mandatory(!readonly))
|
||||
.addFieldIf(
|
||||
() -> readonly,
|
||||
() -> FormBuilder.text(
|
||||
Domain.USER.ATTR_CREATION_DATE,
|
||||
FORM_CREATION_DATE_TEXT_KEY,
|
||||
this.pageService.getI18nSupport().formatDisplayDate(userAccount.getCreationDate()))
|
||||
.readonly(true))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.USER.ATTR_NAME,
|
||||
FORM_NAME_TEXT_KEY,
|
||||
userAccount.getName())
|
||||
.mandatory(!readonly))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.USER.ATTR_SURNAME,
|
||||
FORM_SURNAME_TEXT_KEY,
|
||||
userAccount.getSurname())
|
||||
.mandatory(!readonly))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.USER.ATTR_USERNAME,
|
||||
FORM_USERNAME_TEXT_KEY,
|
||||
userAccount.getUsername())
|
||||
.mandatory(!readonly))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.USER.ATTR_EMAIL,
|
||||
FORM_MAIL_TEXT_KEY,
|
||||
userAccount.getEmail()))
|
||||
.addFieldIf(
|
||||
() -> this.multilingual,
|
||||
() -> FormBuilder.singleSelection(
|
||||
Domain.USER.ATTR_LANGUAGE,
|
||||
FORM_LANG_TEXT_KEY,
|
||||
userAccount.getLanguage().getLanguage(),
|
||||
this.resourceService::languageResources))
|
||||
.addField(FormBuilder.singleSelection(
|
||||
Domain.USER.ATTR_TIMEZONE,
|
||||
FORM_TIMEZONE_TEXT_KEY,
|
||||
userAccount.getTimeZone().getID(),
|
||||
this.resourceService::timeZoneResources)
|
||||
.mandatory(!readonly))
|
||||
.addFieldIf(
|
||||
() -> modifyGrant,
|
||||
() -> FormBuilder.multiCheckboxSelection(
|
||||
USER_ROLE.REFERENCE_NAME,
|
||||
FORM_ROLES_TEXT_KEY,
|
||||
StringUtils.join(userAccount.getRoles(), Constants.LIST_SEPARATOR_CHAR),
|
||||
this.resourceService::userRoleResources)
|
||||
.visibleIf(writeGrant)
|
||||
.mandatory(!readonly))
|
||||
.addFieldIf(
|
||||
isNew,
|
||||
() -> FormBuilder.text(
|
||||
PasswordChange.ATTR_NAME_NEW_PASSWORD,
|
||||
FORM_PASSWORD_TEXT_KEY)
|
||||
.asPasswordField()
|
||||
.mandatory(!readonly))
|
||||
.addFieldIf(
|
||||
isNew,
|
||||
() -> FormBuilder.text(
|
||||
PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD,
|
||||
FORM_PASSWORD_CONFIRM_TEXT_KEY)
|
||||
.asPasswordField()
|
||||
.mandatory(!readonly))
|
||||
.buildFor((entityKey == null)
|
||||
? restService.getRestCall(NewUserAccount.class)
|
||||
: restService.getRestCall(SaveUserAccount.class));
|
||||
|
||||
// propagate content actions to action-pane
|
||||
this.pageService.pageActionBuilder(formContext.clearEntityKeys())
|
||||
|
||||
.newAction(ActionDefinition.USER_ACCOUNT_NEW)
|
||||
.publishIf(() -> institutionalWriteGrant && readonly && institutionActive)
|
||||
|
||||
.newAction(ActionDefinition.USER_ACCOUNT_MODIFY)
|
||||
.withEntityKey(entityKey)
|
||||
.publishIf(() -> modifyGrant && readonly && institutionActive)
|
||||
|
||||
.newAction(ActionDefinition.USER_ACCOUNT_CHANGE_PASSWORD)
|
||||
.withEntityKey(entityKey)
|
||||
.publishIf(() -> modifyGrant && readonly && institutionActive && userAccount.isActive())
|
||||
|
||||
.newAction(ActionDefinition.USER_ACCOUNT_DEACTIVATE)
|
||||
.withEntityKey(entityKey)
|
||||
.withSimpleRestCall(restService, DeactivateUserAccount.class)
|
||||
.withConfirm(this.pageService.confirmDeactivation(userAccount))
|
||||
.publishIf(() -> writeGrant && readonly && institutionActive && userAccount.isActive())
|
||||
|
||||
.newAction(ActionDefinition.USER_ACCOUNT_ACTIVATE)
|
||||
.withEntityKey(entityKey)
|
||||
.withSimpleRestCall(restService, ActivateUserAccount.class)
|
||||
.publishIf(() -> writeGrant && readonly && institutionActive && !userAccount.isActive())
|
||||
|
||||
.newAction(ActionDefinition.USER_ACCOUNT_SAVE)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(action -> formHandle.handleFormPost(formHandle.doAPIPost()
|
||||
.map(userInfo -> {
|
||||
if (ownAccount) {
|
||||
currentUser.refresh(userInfo);
|
||||
}
|
||||
return userInfo;
|
||||
}),
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,236 +1,250 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.authorization.Privilege;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.service.ResourceService;
|
||||
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.PageMessageException;
|
||||
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.TemplateComposer;
|
||||
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.useraccount.GetUserAccount;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccountPage;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute;
|
||||
import ch.ethz.seb.sebserver.gui.table.EntityTable;
|
||||
import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class UserAccountList implements TemplateComposer {
|
||||
|
||||
// localized text keys
|
||||
private static final LocTextKey EMPTY_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.list.empty");
|
||||
private static final LocTextKey INSTITUTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.list.column.institution");
|
||||
private static final LocTextKey EMPTY_SELECTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.info.pleaseSelect");
|
||||
private static final LocTextKey ACTIVE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.list.column.active");
|
||||
private static final LocTextKey LANG_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.list.column.language");
|
||||
private static final LocTextKey MAIL_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.list.column.email");
|
||||
private static final LocTextKey USER_NAME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.list.column.username");
|
||||
private static final LocTextKey NAME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.list.column.name");
|
||||
private static final LocTextKey TITLE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.list.title");
|
||||
private static final LocTextKey NO_EDIT_RIGHT_MESSAGE =
|
||||
new LocTextKey("sebserver.useraccount.info.notEditable");
|
||||
|
||||
// filter attribute models
|
||||
private final TableFilterAttribute institutionFilter;
|
||||
private final TableFilterAttribute nameFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, Entity.FILTER_ATTR_NAME);
|
||||
private final TableFilterAttribute usernameFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, UserInfo.FILTER_ATTR_USER_NAME);
|
||||
private final TableFilterAttribute mailFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, UserInfo.FILTER_ATTR_EMAIL);
|
||||
private final TableFilterAttribute languageFilter;
|
||||
private final TableFilterAttribute activityFilter;
|
||||
|
||||
// dependencies
|
||||
private final PageService pageService;
|
||||
private final ResourceService resourceService;
|
||||
private final int pageSize;
|
||||
private final boolean multilingual;
|
||||
|
||||
protected UserAccountList(
|
||||
final PageService pageService,
|
||||
final ResourceService resourceService,
|
||||
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize,
|
||||
@Value("${sebserver.gui.multilingual:false}") final Boolean ml) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.resourceService = resourceService;
|
||||
this.pageSize = pageSize;
|
||||
this.multilingual = BooleanUtils.isTrue(ml);
|
||||
|
||||
this.institutionFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
Entity.FILTER_ATTR_INSTITUTION,
|
||||
this.resourceService::institutionResource);
|
||||
|
||||
this.languageFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
UserInfo.FILTER_ATTR_LANGUAGE,
|
||||
this.resourceService::languageResources);
|
||||
|
||||
this.activityFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
UserInfo.FILTER_ATTR_ACTIVE,
|
||||
this.resourceService::activityResources);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
|
||||
final CurrentUser currentUser = this.resourceService.getCurrentUser();
|
||||
final RestService restService = this.resourceService.getRestService();
|
||||
// content page layout with title
|
||||
final Composite content = widgetFactory.defaultPageLayout(
|
||||
pageContext.getParent(),
|
||||
TITLE_TEXT_KEY);
|
||||
|
||||
final BooleanSupplier isSEBAdmin = () -> currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN);
|
||||
final PageActionBuilder actionBuilder = this.pageService.pageActionBuilder(pageContext.clearEntityKeys());
|
||||
|
||||
// table
|
||||
final EntityTable<UserInfo> table = this.pageService.entityTableBuilder(
|
||||
restService.getRestCall(GetUserAccountPage.class))
|
||||
.withEmptyMessage(EMPTY_TEXT_KEY)
|
||||
.withPaging(this.pageSize)
|
||||
|
||||
.withColumnIf(
|
||||
isSEBAdmin,
|
||||
() -> new ColumnDefinition<>(
|
||||
Domain.USER.ATTR_INSTITUTION_ID,
|
||||
INSTITUTION_TEXT_KEY,
|
||||
userInstitutionNameFunction(this.resourceService))
|
||||
.withFilter(this.institutionFilter)
|
||||
.widthProportion(2))
|
||||
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.USER.ATTR_NAME,
|
||||
NAME_TEXT_KEY,
|
||||
UserInfo::getName)
|
||||
.withFilter(this.nameFilter)
|
||||
.sortable()
|
||||
.widthProportion(2))
|
||||
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.USER.ATTR_USERNAME,
|
||||
USER_NAME_TEXT_KEY,
|
||||
UserInfo::getUsername)
|
||||
.withFilter(this.usernameFilter)
|
||||
.sortable()
|
||||
.widthProportion(2))
|
||||
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.USER.ATTR_EMAIL,
|
||||
MAIL_TEXT_KEY,
|
||||
UserInfo::getEmail)
|
||||
.withFilter(this.mailFilter)
|
||||
.sortable()
|
||||
.widthProportion(3))
|
||||
|
||||
.withColumnIf(() -> this.multilingual,
|
||||
() -> new ColumnDefinition<>(
|
||||
Domain.USER.ATTR_LANGUAGE,
|
||||
LANG_TEXT_KEY,
|
||||
this::getLocaleDisplayText)
|
||||
.withFilter(this.languageFilter)
|
||||
.localized()
|
||||
.sortable()
|
||||
.widthProportion(1))
|
||||
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.USER.ATTR_ACTIVE,
|
||||
ACTIVE_TEXT_KEY,
|
||||
this.pageService.getResourceService().<UserInfo> localizedActivityFunction())
|
||||
.sortable()
|
||||
.withFilter(this.activityFilter)
|
||||
.widthProportion(1))
|
||||
|
||||
.withDefaultAction(actionBuilder
|
||||
.newAction(ActionDefinition.USER_ACCOUNT_VIEW_FROM_LIST)
|
||||
.create())
|
||||
.compose(pageContext.copyOf(content));
|
||||
|
||||
// propagate content actions to action-pane
|
||||
final GrantCheck userGrant = currentUser.grantCheck(EntityType.USER);
|
||||
actionBuilder
|
||||
|
||||
.newAction(ActionDefinition.USER_ACCOUNT_NEW)
|
||||
.publishIf(userGrant::iw)
|
||||
|
||||
.newAction(ActionDefinition.USER_ACCOUNT_VIEW_FROM_LIST)
|
||||
.withSelect(table::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY)
|
||||
.publishIf(() -> table.hasAnyContent())
|
||||
|
||||
.newAction(ActionDefinition.USER_ACCOUNT_MODIFY_FROM_LIST)
|
||||
.withSelect(table::getSelection, this::editAction, EMPTY_SELECTION_TEXT_KEY)
|
||||
.publishIf(() -> userGrant.im() && table.hasAnyContent());
|
||||
}
|
||||
|
||||
private PageAction editAction(final PageAction pageAction) {
|
||||
if (!this.resourceService.getRestService()
|
||||
.getBuilder(GetUserAccount.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, pageAction.getSingleSelection().modelId)
|
||||
.call()
|
||||
.map(user -> Privilege.hasRoleBasedUserAccountEditGrant(user,
|
||||
this.resourceService.getCurrentUser().get()))
|
||||
.getOr(false)) {
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.authorization.Privilege;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.service.ResourceService;
|
||||
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.PageMessageException;
|
||||
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.TemplateComposer;
|
||||
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.useraccount.GetUserAccount;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccountPage;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute;
|
||||
import ch.ethz.seb.sebserver.gui.table.EntityTable;
|
||||
import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class UserAccountList implements TemplateComposer {
|
||||
|
||||
// localized text keys
|
||||
private static final LocTextKey EMPTY_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.list.empty");
|
||||
private static final LocTextKey INSTITUTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.list.column.institution");
|
||||
private static final LocTextKey EMPTY_SELECTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.info.pleaseSelect");
|
||||
private static final LocTextKey ACTIVE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.list.column.active");
|
||||
private static final LocTextKey LANG_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.list.column.language");
|
||||
private static final LocTextKey MAIL_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.list.column.email");
|
||||
private static final LocTextKey USER_NAME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.list.column.username");
|
||||
private static final LocTextKey NAME_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.list.column.name");
|
||||
private static final LocTextKey TITLE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.useraccount.list.title");
|
||||
private static final LocTextKey NO_EDIT_RIGHT_MESSAGE =
|
||||
new LocTextKey("sebserver.useraccount.info.notEditable");
|
||||
|
||||
// filter attribute models
|
||||
private final TableFilterAttribute institutionFilter;
|
||||
private final TableFilterAttribute nameFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, Entity.FILTER_ATTR_NAME);
|
||||
private final TableFilterAttribute usernameFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, UserInfo.FILTER_ATTR_USER_NAME);
|
||||
private final TableFilterAttribute mailFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, UserInfo.FILTER_ATTR_EMAIL);
|
||||
private final TableFilterAttribute languageFilter;
|
||||
private final TableFilterAttribute activityFilter;
|
||||
|
||||
// dependencies
|
||||
private final PageService pageService;
|
||||
private final ResourceService resourceService;
|
||||
private final int pageSize;
|
||||
private final boolean multilingual;
|
||||
|
||||
protected UserAccountList(
|
||||
final PageService pageService,
|
||||
final ResourceService resourceService,
|
||||
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize,
|
||||
@Value("${sebserver.gui.multilingual:false}") final Boolean ml) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.resourceService = resourceService;
|
||||
this.pageSize = pageSize;
|
||||
this.multilingual = BooleanUtils.isTrue(ml);
|
||||
|
||||
this.institutionFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
Entity.FILTER_ATTR_INSTITUTION,
|
||||
this.resourceService::institutionResource);
|
||||
|
||||
this.languageFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
UserInfo.FILTER_ATTR_LANGUAGE,
|
||||
this.resourceService::languageResources);
|
||||
|
||||
this.activityFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
UserInfo.FILTER_ATTR_ACTIVE,
|
||||
this.resourceService::activityResources);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
|
||||
final CurrentUser currentUser = this.resourceService.getCurrentUser();
|
||||
final RestService restService = this.resourceService.getRestService();
|
||||
// content page layout with title
|
||||
final Composite content = widgetFactory.defaultPageLayout(
|
||||
pageContext.getParent(),
|
||||
TITLE_TEXT_KEY);
|
||||
|
||||
final BooleanSupplier isSEBAdmin = () -> currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN);
|
||||
final PageActionBuilder actionBuilder = this.pageService.pageActionBuilder(pageContext.clearEntityKeys());
|
||||
|
||||
// table
|
||||
final EntityTable<UserInfo> table = this.pageService.entityTableBuilder(
|
||||
restService.getRestCall(GetUserAccountPage.class))
|
||||
.withEmptyMessage(EMPTY_TEXT_KEY)
|
||||
.withPaging(this.pageSize)
|
||||
|
||||
.withColumnIf(
|
||||
isSEBAdmin,
|
||||
() -> new ColumnDefinition<>(
|
||||
Domain.USER.ATTR_INSTITUTION_ID,
|
||||
INSTITUTION_TEXT_KEY,
|
||||
userInstitutionNameFunction(this.resourceService))
|
||||
.withFilter(this.institutionFilter)
|
||||
.widthProportion(2))
|
||||
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.USER.ATTR_NAME,
|
||||
NAME_TEXT_KEY,
|
||||
UserInfo::getName)
|
||||
.withFilter(this.nameFilter)
|
||||
.sortable()
|
||||
.widthProportion(2))
|
||||
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.USER.ATTR_USERNAME,
|
||||
USER_NAME_TEXT_KEY,
|
||||
UserInfo::getUsername)
|
||||
.withFilter(this.usernameFilter)
|
||||
.sortable()
|
||||
.widthProportion(2))
|
||||
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.USER.ATTR_EMAIL,
|
||||
MAIL_TEXT_KEY,
|
||||
UserInfo::getEmail)
|
||||
.withFilter(this.mailFilter)
|
||||
.sortable()
|
||||
.widthProportion(3))
|
||||
|
||||
.withColumnIf(() -> this.multilingual,
|
||||
() -> new ColumnDefinition<>(
|
||||
Domain.USER.ATTR_LANGUAGE,
|
||||
LANG_TEXT_KEY,
|
||||
this::getLocaleDisplayText)
|
||||
.withFilter(this.languageFilter)
|
||||
.localized()
|
||||
.sortable()
|
||||
.widthProportion(1))
|
||||
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.USER.ATTR_ACTIVE,
|
||||
ACTIVE_TEXT_KEY,
|
||||
this.pageService.getResourceService().<UserInfo> localizedActivityFunction())
|
||||
.sortable()
|
||||
.withFilter(this.activityFilter)
|
||||
.widthProportion(1))
|
||||
|
||||
.withDefaultAction(actionBuilder
|
||||
.newAction(ActionDefinition.USER_ACCOUNT_VIEW_FROM_LIST)
|
||||
.create())
|
||||
|
||||
.withSelectionListener(this.pageService.getSelectionPublisher(
|
||||
ActionDefinition.USER_ACCOUNT_TOGGLE_ACTIVITY,
|
||||
ActionDefinition.USER_ACCOUNT_ACTIVATE,
|
||||
ActionDefinition.USER_ACCOUNT_DEACTIVATE,
|
||||
pageContext,
|
||||
ActionDefinition.USER_ACCOUNT_VIEW_FROM_LIST,
|
||||
ActionDefinition.USER_ACCOUNT_MODIFY_FROM_LIST,
|
||||
ActionDefinition.USER_ACCOUNT_TOGGLE_ACTIVITY))
|
||||
|
||||
.compose(pageContext.copyOf(content));
|
||||
|
||||
// propagate content actions to action-pane
|
||||
final GrantCheck userGrant = currentUser.grantCheck(EntityType.USER);
|
||||
actionBuilder
|
||||
|
||||
.newAction(ActionDefinition.USER_ACCOUNT_NEW)
|
||||
.publishIf(userGrant::iw)
|
||||
|
||||
.newAction(ActionDefinition.USER_ACCOUNT_VIEW_FROM_LIST)
|
||||
.withSelect(table::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY)
|
||||
.publishIf(table::hasAnyContent, false)
|
||||
|
||||
.newAction(ActionDefinition.USER_ACCOUNT_MODIFY_FROM_LIST)
|
||||
.withSelect(table::getSelection, this::editAction, EMPTY_SELECTION_TEXT_KEY)
|
||||
.publishIf(() -> userGrant.im() && table.hasAnyContent(), false)
|
||||
|
||||
.newAction(ActionDefinition.USER_ACCOUNT_TOGGLE_ACTIVITY)
|
||||
.withExec(this.pageService.activationToggleActionFunction(table, EMPTY_SELECTION_TEXT_KEY))
|
||||
.withConfirm(this.pageService.confirmDeactivation(table))
|
||||
.publishIf(() -> userGrant.m() && table.hasAnyContent(), false);
|
||||
}
|
||||
|
||||
private PageAction editAction(final PageAction pageAction) {
|
||||
if (!this.resourceService.getRestService()
|
||||
.getBuilder(GetUserAccount.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, pageAction.getSingleSelection().modelId)
|
||||
.call()
|
||||
.map(user -> Privilege.hasRoleBasedUserAccountEditGrant(user,
|
||||
this.resourceService.getCurrentUser().get()))
|
||||
.getOr(false)) {
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,276 +1,279 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
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.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.form.FormBuilder;
|
||||
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.LocTextKey;
|
||||
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.PageActionBuilder;
|
||||
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.PageAction;
|
||||
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.useraccount.GetUserAccount;
|
||||
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.TableFilterAttribute;
|
||||
import ch.ethz.seb.sebserver.gui.table.EntityTable;
|
||||
import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class UserActivityLogs implements TemplateComposer {
|
||||
|
||||
private static final LocTextKey DETAILS_TITLE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.userlogs.details.title");
|
||||
private static final LocTextKey TITLE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.userlogs.list.title");
|
||||
private static final LocTextKey EMPTY_TEXT_KEY =
|
||||
new LocTextKey("sebserver.userlogs.list.empty");
|
||||
private static final LocTextKey INSTITUTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.userlogs.list.column.institution");
|
||||
private static final LocTextKey USER_TEXT_KEY =
|
||||
new LocTextKey("sebserver.userlogs.list.column.user");
|
||||
private static final LocTextKey DATE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.userlogs.list.column.dateTime");
|
||||
private static final LocTextKey DETAILS_DATE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.seblogs.details.dateTime");
|
||||
private static final LocTextKey ACTIVITY_TEXT_KEY =
|
||||
new LocTextKey("sebserver.userlogs.list.column.activityType");
|
||||
private static final LocTextKey ENTITY_TYPE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.userlogs.list.column.entityType");
|
||||
private static final LocTextKey ENTITY_ID_TEXT_KEY =
|
||||
new LocTextKey("sebserver.userlogs.list.column.entityId");
|
||||
private static final LocTextKey MESSAGE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.userlogs.list.column.message");
|
||||
private final static LocTextKey EMPTY_SELECTION_TEXT =
|
||||
new LocTextKey("sebserver.userlogs.info.pleaseSelect");
|
||||
|
||||
private final TableFilterAttribute institutionFilter;
|
||||
private final TableFilterAttribute userNameFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, UserActivityLog.FILTER_ATTR_USER_NAME);
|
||||
private final TableFilterAttribute activityFilter;
|
||||
private final TableFilterAttribute entityFilter;
|
||||
|
||||
private final PageService pageService;
|
||||
private final ResourceService resourceService;
|
||||
private final I18nSupport i18nSupport;
|
||||
private final WidgetFactory widgetFactory;
|
||||
private final int pageSize;
|
||||
|
||||
public UserActivityLogs(
|
||||
final PageService pageService,
|
||||
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.resourceService = pageService.getResourceService();
|
||||
this.i18nSupport = this.resourceService.getI18nSupport();
|
||||
this.widgetFactory = pageService.getWidgetFactory();
|
||||
this.pageSize = pageSize;
|
||||
|
||||
this.institutionFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
Entity.FILTER_ATTR_INSTITUTION,
|
||||
this.resourceService::institutionResource);
|
||||
|
||||
this.activityFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
UserActivityLog.FILTER_ATTR_ACTIVITY_TYPES,
|
||||
this.resourceService::userActivityTypeResources);
|
||||
|
||||
this.entityFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
UserActivityLog.FILTER_ATTR_ENTITY_TYPES,
|
||||
this.resourceService::entityTypeResources);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
final CurrentUser currentUser = this.resourceService.getCurrentUser();
|
||||
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
|
||||
final RestService restService = this.resourceService.getRestService();
|
||||
// content page layout with title
|
||||
final Composite content = widgetFactory.defaultPageLayout(
|
||||
pageContext.getParent(),
|
||||
TITLE_TEXT_KEY);
|
||||
|
||||
final PageActionBuilder actionBuilder = this.pageService.pageActionBuilder(
|
||||
pageContext
|
||||
.clearEntityKeys()
|
||||
.clearAttributes());
|
||||
|
||||
final BooleanSupplier isSebAdmin =
|
||||
() -> currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN);
|
||||
|
||||
final Function<UserActivityLog, String> institutionNameFunction =
|
||||
this.resourceService.getInstitutionNameFunction()
|
||||
.compose(log -> {
|
||||
try {
|
||||
final UserInfo user = restService.getBuilder(GetUserAccount.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, log.getUserUuid())
|
||||
.call().getOrThrow();
|
||||
return String.valueOf(user.getInstitutionId());
|
||||
} catch (final Exception e) {
|
||||
return Constants.EMPTY_NOTE;
|
||||
}
|
||||
});
|
||||
|
||||
// table
|
||||
final EntityTable<UserActivityLog> table = this.pageService.entityTableBuilder(
|
||||
restService.getRestCall(GetUserLogPage.class))
|
||||
.withEmptyMessage(EMPTY_TEXT_KEY)
|
||||
.withPaging(this.pageSize)
|
||||
|
||||
.withColumnIf(
|
||||
isSebAdmin,
|
||||
() -> new ColumnDefinition<>(
|
||||
UserActivityLog.FILTER_ATTR_INSTITUTION,
|
||||
INSTITUTION_TEXT_KEY,
|
||||
institutionNameFunction)
|
||||
.withFilter(this.institutionFilter))
|
||||
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
UserActivityLog.ATTR_USER_NAME,
|
||||
USER_TEXT_KEY,
|
||||
UserActivityLog::getUsername)
|
||||
.withFilter(this.userNameFilter))
|
||||
|
||||
.withColumn(new ColumnDefinition<UserActivityLog>(
|
||||
Domain.USER_ACTIVITY_LOG.ATTR_ACTIVITY_TYPE,
|
||||
ACTIVITY_TEXT_KEY,
|
||||
this.resourceService::getUserActivityTypeName)
|
||||
.withFilter(this.activityFilter)
|
||||
.sortable())
|
||||
|
||||
.withColumn(new ColumnDefinition<UserActivityLog>(
|
||||
Domain.USER_ACTIVITY_LOG.ATTR_ENTITY_ID,
|
||||
ENTITY_TYPE_TEXT_KEY,
|
||||
this.resourceService::getEntityTypeName)
|
||||
.withFilter(this.entityFilter)
|
||||
.sortable())
|
||||
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.USER_ACTIVITY_LOG.ATTR_TIMESTAMP,
|
||||
new LocTextKey(DATE_TEXT_KEY.name, this.i18nSupport.getUsersTimeZoneTitleSuffix()),
|
||||
this::getLogTime)
|
||||
.withFilter(new TableFilterAttribute(
|
||||
CriteriaType.DATE_RANGE,
|
||||
UserActivityLog.FILTER_ATTR_FROM_TO,
|
||||
Utils.toDateTimeUTC(Utils.getMillisecondsNow())
|
||||
.minusYears(1)
|
||||
.toString()))
|
||||
.sortable())
|
||||
|
||||
.withDefaultAction(t -> actionBuilder
|
||||
.newAction(ActionDefinition.LOGS_USER_ACTIVITY_SHOW_DETAILS)
|
||||
.withExec(action -> this.showDetails(action, t.getSingleSelectedROWData()))
|
||||
.noEventPropagation()
|
||||
.create())
|
||||
|
||||
.compose(pageContext.copyOf(content));
|
||||
|
||||
actionBuilder
|
||||
.newAction(ActionDefinition.LOGS_USER_ACTIVITY_SHOW_DETAILS)
|
||||
.withSelect(
|
||||
table::getSelection,
|
||||
action -> this.showDetails(action, table.getSingleSelectedROWData()),
|
||||
EMPTY_SELECTION_TEXT)
|
||||
.noEventPropagation()
|
||||
.publishIf(table::hasAnyContent);
|
||||
|
||||
}
|
||||
|
||||
private final String getLogTime(final UserActivityLog log) {
|
||||
if (log == null || log.timestamp == null) {
|
||||
return Constants.EMPTY_NOTE;
|
||||
}
|
||||
|
||||
return this.i18nSupport
|
||||
.formatDisplayDateTime(Utils.toDateTimeUTC(log.timestamp));
|
||||
}
|
||||
|
||||
private PageAction showDetails(final PageAction action, final UserActivityLog userActivityLog) {
|
||||
action.getSingleSelection();
|
||||
|
||||
final ModalInputDialog<Void> dialog = new ModalInputDialog<>(
|
||||
action.pageContext().getParent().getShell(),
|
||||
this.widgetFactory);
|
||||
dialog.setLargeDialogWidth();
|
||||
dialog.open(
|
||||
DETAILS_TITLE_TEXT_KEY,
|
||||
action.pageContext(),
|
||||
pc -> createDetailsForm(userActivityLog, pc));
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
private void createDetailsForm(final UserActivityLog userActivityLog, final PageContext pc) {
|
||||
|
||||
final Composite parent = pc.getParent();
|
||||
final Composite grid = this.widgetFactory.createPopupScrollComposite(parent);
|
||||
|
||||
this.pageService.formBuilder(pc.copyOf(grid))
|
||||
.withDefaultSpanInput(6)
|
||||
.withEmptyCellSeparation(false)
|
||||
.readonly(true)
|
||||
.addField(FormBuilder.text(
|
||||
UserActivityLog.ATTR_USER_NAME,
|
||||
USER_TEXT_KEY,
|
||||
String.valueOf(userActivityLog.getUsername())))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.USER_ACTIVITY_LOG.ATTR_ACTIVITY_TYPE,
|
||||
ACTIVITY_TEXT_KEY,
|
||||
this.resourceService.getUserActivityTypeName(userActivityLog)))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.USER_ACTIVITY_LOG.ATTR_ENTITY_TYPE,
|
||||
ENTITY_TYPE_TEXT_KEY,
|
||||
this.resourceService.getEntityTypeName(userActivityLog)))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.USER_ACTIVITY_LOG.ATTR_ENTITY_ID,
|
||||
ENTITY_ID_TEXT_KEY,
|
||||
userActivityLog.entityId))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.USER_ACTIVITY_LOG.ATTR_TIMESTAMP,
|
||||
DETAILS_DATE_TEXT_KEY,
|
||||
this.widgetFactory.getI18nSupport()
|
||||
.formatDisplayDateTime(Utils.toDateTimeUTC(userActivityLog.timestamp)) + " " +
|
||||
this.i18nSupport.getUsersTimeZoneTitleSuffix()))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.USER_ACTIVITY_LOG.ATTR_MESSAGE,
|
||||
MESSAGE_TEXT_KEY,
|
||||
String.valueOf(userActivityLog.message))
|
||||
.asArea())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
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.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.form.FormBuilder;
|
||||
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.LocTextKey;
|
||||
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.PageActionBuilder;
|
||||
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.PageAction;
|
||||
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.useraccount.GetUserAccount;
|
||||
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.TableFilterAttribute;
|
||||
import ch.ethz.seb.sebserver.gui.table.EntityTable;
|
||||
import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class UserActivityLogs implements TemplateComposer {
|
||||
|
||||
private static final LocTextKey DETAILS_TITLE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.userlogs.details.title");
|
||||
private static final LocTextKey TITLE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.userlogs.list.title");
|
||||
private static final LocTextKey EMPTY_TEXT_KEY =
|
||||
new LocTextKey("sebserver.userlogs.list.empty");
|
||||
private static final LocTextKey INSTITUTION_TEXT_KEY =
|
||||
new LocTextKey("sebserver.userlogs.list.column.institution");
|
||||
private static final LocTextKey USER_TEXT_KEY =
|
||||
new LocTextKey("sebserver.userlogs.list.column.user");
|
||||
private static final LocTextKey DATE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.userlogs.list.column.dateTime");
|
||||
private static final LocTextKey DETAILS_DATE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.seblogs.details.dateTime");
|
||||
private static final LocTextKey ACTIVITY_TEXT_KEY =
|
||||
new LocTextKey("sebserver.userlogs.list.column.activityType");
|
||||
private static final LocTextKey ENTITY_TYPE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.userlogs.list.column.entityType");
|
||||
private static final LocTextKey ENTITY_ID_TEXT_KEY =
|
||||
new LocTextKey("sebserver.userlogs.list.column.entityId");
|
||||
private static final LocTextKey MESSAGE_TEXT_KEY =
|
||||
new LocTextKey("sebserver.userlogs.list.column.message");
|
||||
private final static LocTextKey EMPTY_SELECTION_TEXT =
|
||||
new LocTextKey("sebserver.userlogs.info.pleaseSelect");
|
||||
|
||||
private final TableFilterAttribute institutionFilter;
|
||||
private final TableFilterAttribute userNameFilter =
|
||||
new TableFilterAttribute(CriteriaType.TEXT, UserActivityLog.FILTER_ATTR_USER_NAME);
|
||||
private final TableFilterAttribute activityFilter;
|
||||
private final TableFilterAttribute entityFilter;
|
||||
|
||||
private final PageService pageService;
|
||||
private final ResourceService resourceService;
|
||||
private final I18nSupport i18nSupport;
|
||||
private final WidgetFactory widgetFactory;
|
||||
private final int pageSize;
|
||||
|
||||
public UserActivityLogs(
|
||||
final PageService pageService,
|
||||
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
|
||||
|
||||
this.pageService = pageService;
|
||||
this.resourceService = pageService.getResourceService();
|
||||
this.i18nSupport = this.resourceService.getI18nSupport();
|
||||
this.widgetFactory = pageService.getWidgetFactory();
|
||||
this.pageSize = pageSize;
|
||||
|
||||
this.institutionFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
Entity.FILTER_ATTR_INSTITUTION,
|
||||
this.resourceService::institutionResource);
|
||||
|
||||
this.activityFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
UserActivityLog.FILTER_ATTR_ACTIVITY_TYPES,
|
||||
this.resourceService::userActivityTypeResources);
|
||||
|
||||
this.entityFilter = new TableFilterAttribute(
|
||||
CriteriaType.SINGLE_SELECTION,
|
||||
UserActivityLog.FILTER_ATTR_ENTITY_TYPES,
|
||||
this.resourceService::entityTypeResources);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
final CurrentUser currentUser = this.resourceService.getCurrentUser();
|
||||
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
|
||||
final RestService restService = this.resourceService.getRestService();
|
||||
// content page layout with title
|
||||
final Composite content = widgetFactory.defaultPageLayout(
|
||||
pageContext.getParent(),
|
||||
TITLE_TEXT_KEY);
|
||||
|
||||
final PageActionBuilder actionBuilder = this.pageService.pageActionBuilder(
|
||||
pageContext
|
||||
.clearEntityKeys()
|
||||
.clearAttributes());
|
||||
|
||||
final BooleanSupplier isSebAdmin =
|
||||
() -> currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN);
|
||||
|
||||
final Function<UserActivityLog, String> institutionNameFunction =
|
||||
this.resourceService.getInstitutionNameFunction()
|
||||
.compose(log -> {
|
||||
try {
|
||||
final UserInfo user = restService.getBuilder(GetUserAccount.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, log.getUserUuid())
|
||||
.call().getOrThrow();
|
||||
return String.valueOf(user.getInstitutionId());
|
||||
} catch (final Exception e) {
|
||||
return Constants.EMPTY_NOTE;
|
||||
}
|
||||
});
|
||||
|
||||
// table
|
||||
final EntityTable<UserActivityLog> table = this.pageService.entityTableBuilder(
|
||||
restService.getRestCall(GetUserLogPage.class))
|
||||
.withEmptyMessage(EMPTY_TEXT_KEY)
|
||||
.withPaging(this.pageSize)
|
||||
|
||||
.withColumnIf(
|
||||
isSebAdmin,
|
||||
() -> new ColumnDefinition<>(
|
||||
UserActivityLog.FILTER_ATTR_INSTITUTION,
|
||||
INSTITUTION_TEXT_KEY,
|
||||
institutionNameFunction)
|
||||
.withFilter(this.institutionFilter))
|
||||
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
UserActivityLog.ATTR_USER_NAME,
|
||||
USER_TEXT_KEY,
|
||||
UserActivityLog::getUsername)
|
||||
.withFilter(this.userNameFilter))
|
||||
|
||||
.withColumn(new ColumnDefinition<UserActivityLog>(
|
||||
Domain.USER_ACTIVITY_LOG.ATTR_ACTIVITY_TYPE,
|
||||
ACTIVITY_TEXT_KEY,
|
||||
this.resourceService::getUserActivityTypeName)
|
||||
.withFilter(this.activityFilter)
|
||||
.sortable())
|
||||
|
||||
.withColumn(new ColumnDefinition<UserActivityLog>(
|
||||
Domain.USER_ACTIVITY_LOG.ATTR_ENTITY_ID,
|
||||
ENTITY_TYPE_TEXT_KEY,
|
||||
this.resourceService::getEntityTypeName)
|
||||
.withFilter(this.entityFilter)
|
||||
.sortable())
|
||||
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.USER_ACTIVITY_LOG.ATTR_TIMESTAMP,
|
||||
new LocTextKey(DATE_TEXT_KEY.name, this.i18nSupport.getUsersTimeZoneTitleSuffix()),
|
||||
this::getLogTime)
|
||||
.withFilter(new TableFilterAttribute(
|
||||
CriteriaType.DATE_RANGE,
|
||||
UserActivityLog.FILTER_ATTR_FROM_TO,
|
||||
Utils.toDateTimeUTC(Utils.getMillisecondsNow())
|
||||
.minusYears(1)
|
||||
.toString()))
|
||||
.sortable())
|
||||
|
||||
.withDefaultAction(t -> actionBuilder
|
||||
.newAction(ActionDefinition.LOGS_USER_ACTIVITY_SHOW_DETAILS)
|
||||
.withExec(action -> this.showDetails(action, t.getSingleSelectedROWData()))
|
||||
.noEventPropagation()
|
||||
.create())
|
||||
|
||||
.withSelectionListener(this.pageService.getSelectionPublisher(
|
||||
pageContext,
|
||||
ActionDefinition.LOGS_USER_ACTIVITY_SHOW_DETAILS))
|
||||
.compose(pageContext.copyOf(content));
|
||||
|
||||
actionBuilder
|
||||
.newAction(ActionDefinition.LOGS_USER_ACTIVITY_SHOW_DETAILS)
|
||||
.withSelect(
|
||||
table::getSelection,
|
||||
action -> this.showDetails(action, table.getSingleSelectedROWData()),
|
||||
EMPTY_SELECTION_TEXT)
|
||||
.noEventPropagation()
|
||||
.publishIf(table::hasAnyContent, false);
|
||||
|
||||
}
|
||||
|
||||
private String getLogTime(final UserActivityLog log) {
|
||||
if (log == null || log.timestamp == null) {
|
||||
return Constants.EMPTY_NOTE;
|
||||
}
|
||||
|
||||
return this.i18nSupport
|
||||
.formatDisplayDateTime(Utils.toDateTimeUTC(log.timestamp));
|
||||
}
|
||||
|
||||
private PageAction showDetails(final PageAction action, final UserActivityLog userActivityLog) {
|
||||
action.getSingleSelection();
|
||||
|
||||
final ModalInputDialog<Void> dialog = new ModalInputDialog<>(
|
||||
action.pageContext().getParent().getShell(),
|
||||
this.widgetFactory);
|
||||
dialog.setLargeDialogWidth();
|
||||
dialog.open(
|
||||
DETAILS_TITLE_TEXT_KEY,
|
||||
action.pageContext(),
|
||||
pc -> createDetailsForm(userActivityLog, pc));
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
private void createDetailsForm(final UserActivityLog userActivityLog, final PageContext pc) {
|
||||
|
||||
final Composite parent = pc.getParent();
|
||||
final Composite grid = this.widgetFactory.createPopupScrollComposite(parent);
|
||||
|
||||
this.pageService.formBuilder(pc.copyOf(grid))
|
||||
.withDefaultSpanInput(6)
|
||||
.withEmptyCellSeparation(false)
|
||||
.readonly(true)
|
||||
.addField(FormBuilder.text(
|
||||
UserActivityLog.ATTR_USER_NAME,
|
||||
USER_TEXT_KEY,
|
||||
String.valueOf(userActivityLog.getUsername())))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.USER_ACTIVITY_LOG.ATTR_ACTIVITY_TYPE,
|
||||
ACTIVITY_TEXT_KEY,
|
||||
this.resourceService.getUserActivityTypeName(userActivityLog)))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.USER_ACTIVITY_LOG.ATTR_ENTITY_TYPE,
|
||||
ENTITY_TYPE_TEXT_KEY,
|
||||
this.resourceService.getEntityTypeName(userActivityLog)))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.USER_ACTIVITY_LOG.ATTR_ENTITY_ID,
|
||||
ENTITY_ID_TEXT_KEY,
|
||||
userActivityLog.entityId))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.USER_ACTIVITY_LOG.ATTR_TIMESTAMP,
|
||||
DETAILS_DATE_TEXT_KEY,
|
||||
this.widgetFactory.getI18nSupport()
|
||||
.formatDisplayDateTime(Utils.toDateTimeUTC(userActivityLog.timestamp)) + " " +
|
||||
this.i18nSupport.getUsersTimeZoneTitleSuffix()))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.USER_ACTIVITY_LOG.ATTR_MESSAGE,
|
||||
MESSAGE_TEXT_KEY,
|
||||
String.valueOf(userActivityLog.message))
|
||||
.asArea())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,138 +1,137 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content.activity;
|
||||
|
||||
import ch.ethz.seb.sebserver.gui.content.ConfigTemplateAttributeForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.ConfigTemplateForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.ConfigTemplateList;
|
||||
import ch.ethz.seb.sebserver.gui.content.ExamForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.ExamList;
|
||||
import ch.ethz.seb.sebserver.gui.content.IndicatorForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.InstitutionForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.InstitutionList;
|
||||
import ch.ethz.seb.sebserver.gui.content.LmsSetupForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.LmsSetupList;
|
||||
import ch.ethz.seb.sebserver.gui.content.MonitoringClientConnection;
|
||||
import ch.ethz.seb.sebserver.gui.content.MonitoringRunningExam;
|
||||
import ch.ethz.seb.sebserver.gui.content.MonitoringRunningExamList;
|
||||
import ch.ethz.seb.sebserver.gui.content.QuizDiscoveryList;
|
||||
import ch.ethz.seb.sebserver.gui.content.SebClientConfigForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.SebClientConfigList;
|
||||
import ch.ethz.seb.sebserver.gui.content.SebClientLogs;
|
||||
import ch.ethz.seb.sebserver.gui.content.SebExamConfigList;
|
||||
import ch.ethz.seb.sebserver.gui.content.SebExamConfigPropForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.SebExamConfigSettingsForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.UserAccountChangePasswordForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.UserAccountForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.UserAccountList;
|
||||
import ch.ethz.seb.sebserver.gui.content.UserActivityLogs;
|
||||
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.PageStateDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||
|
||||
public enum PageStateDefinitionImpl implements PageStateDefinition {
|
||||
|
||||
INSTITUTION_LIST(Type.LIST_VIEW, InstitutionList.class, ActivityDefinition.INSTITUTION),
|
||||
INSTITUTION_VIEW(Type.FORM_VIEW, 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_VIEW(Type.FORM_VIEW, 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),
|
||||
|
||||
LMS_SETUP_LIST(Type.LIST_VIEW, LmsSetupList.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),
|
||||
|
||||
QUIZ_LIST(Type.LIST_VIEW, QuizDiscoveryList.class, ActivityDefinition.QUIZ_DISCOVERY),
|
||||
|
||||
EXAM_LIST(Type.LIST_VIEW, ExamList.class, ActivityDefinition.EXAM),
|
||||
EXAM_VIEW(Type.FORM_VIEW, ExamForm.class, ActivityDefinition.EXAM),
|
||||
EXAM_EDIT(Type.FORM_EDIT, ExamForm.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_VIEW(Type.FORM_VIEW, 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_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_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_TEMPLATE_LIST(Type.LIST_VIEW, ConfigTemplateList.class,
|
||||
ActivityDefinition.SEB_EXAM_CONFIG_TEMPLATE),
|
||||
SEB_EXAM_CONFIG_TEMPLATE_VIEW(Type.FORM_VIEW, ConfigTemplateForm.class,
|
||||
ActivityDefinition.SEB_EXAM_CONFIG_TEMPLATE),
|
||||
SEB_EXAM_CONFIG_TEMPLATE_EDIT(Type.FORM_EDIT, ConfigTemplateForm.class,
|
||||
ActivityDefinition.SEB_EXAM_CONFIG_TEMPLATE),
|
||||
|
||||
SEB_EXAM_CONFIG_TEMPLATE_ATTRIBUTE_EDIT(
|
||||
Type.FORM_EDIT,
|
||||
ConfigTemplateAttributeForm.class,
|
||||
ActivityDefinition.SEB_EXAM_CONFIG),
|
||||
|
||||
MONITORING_RUNNING_EXAM_LIST(Type.LIST_VIEW, MonitoringRunningExamList.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),
|
||||
|
||||
USER_ACTIVITY_LOGS(Type.LIST_VIEW, UserActivityLogs.class, ActivityDefinition.USER_ACTIVITY_LOGS),
|
||||
SEB_CLIENT_LOGS(Type.LIST_VIEW, SebClientLogs.class, ActivityDefinition.SEB_CLIENT_LOGS)
|
||||
|
||||
;
|
||||
|
||||
public final Type type;
|
||||
public final Class<? extends TemplateComposer> contentPaneComposer;
|
||||
public final Class<? extends TemplateComposer> actionPaneComposer;
|
||||
public final Activity activityAnchor;
|
||||
|
||||
private PageStateDefinitionImpl(
|
||||
final Type type,
|
||||
final Class<? extends TemplateComposer> contentPaneComposer,
|
||||
final Activity activityAnchor) {
|
||||
|
||||
this(type, contentPaneComposer, ActionPane.class, activityAnchor);
|
||||
}
|
||||
|
||||
private PageStateDefinitionImpl(
|
||||
final Type type,
|
||||
final Class<? extends TemplateComposer> contentPaneComposer,
|
||||
final Class<? extends TemplateComposer> actionPaneComposer,
|
||||
final Activity activityAnchor) {
|
||||
|
||||
this.type = type;
|
||||
this.contentPaneComposer = contentPaneComposer;
|
||||
this.actionPaneComposer = actionPaneComposer;
|
||||
this.activityAnchor = activityAnchor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type type() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends TemplateComposer> contentPaneComposer() {
|
||||
return this.contentPaneComposer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends TemplateComposer> actionPaneComposer() {
|
||||
return this.actionPaneComposer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Activity activityAnchor() {
|
||||
return this.activityAnchor;
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content.activity;
|
||||
|
||||
import ch.ethz.seb.sebserver.gui.content.ConfigTemplateAttributeForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.ConfigTemplateForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.ConfigTemplateList;
|
||||
import ch.ethz.seb.sebserver.gui.content.ExamForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.ExamList;
|
||||
import ch.ethz.seb.sebserver.gui.content.IndicatorForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.InstitutionForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.InstitutionList;
|
||||
import ch.ethz.seb.sebserver.gui.content.LmsSetupForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.LmsSetupList;
|
||||
import ch.ethz.seb.sebserver.gui.content.MonitoringClientConnection;
|
||||
import ch.ethz.seb.sebserver.gui.content.MonitoringRunningExam;
|
||||
import ch.ethz.seb.sebserver.gui.content.MonitoringRunningExamList;
|
||||
import ch.ethz.seb.sebserver.gui.content.QuizDiscoveryList;
|
||||
import ch.ethz.seb.sebserver.gui.content.SebClientConfigForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.SebClientConfigList;
|
||||
import ch.ethz.seb.sebserver.gui.content.SebClientLogs;
|
||||
import ch.ethz.seb.sebserver.gui.content.SebExamConfigList;
|
||||
import ch.ethz.seb.sebserver.gui.content.SebExamConfigPropForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.SebExamConfigSettingsForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.UserAccountChangePasswordForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.UserAccountForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.UserAccountList;
|
||||
import ch.ethz.seb.sebserver.gui.content.UserActivityLogs;
|
||||
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.PageStateDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||
|
||||
public enum PageStateDefinitionImpl implements PageStateDefinition {
|
||||
|
||||
INSTITUTION_LIST(Type.LIST_VIEW, InstitutionList.class, ActivityDefinition.INSTITUTION),
|
||||
INSTITUTION_VIEW(Type.FORM_VIEW, 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_VIEW(Type.FORM_VIEW, 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),
|
||||
|
||||
LMS_SETUP_LIST(Type.LIST_VIEW, LmsSetupList.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),
|
||||
|
||||
QUIZ_LIST(Type.LIST_VIEW, QuizDiscoveryList.class, ActivityDefinition.QUIZ_DISCOVERY),
|
||||
|
||||
EXAM_LIST(Type.LIST_VIEW, ExamList.class, ActivityDefinition.EXAM),
|
||||
EXAM_VIEW(Type.FORM_VIEW, ExamForm.class, ActivityDefinition.EXAM),
|
||||
EXAM_EDIT(Type.FORM_EDIT, ExamForm.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_VIEW(Type.FORM_VIEW, 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_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_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_TEMPLATE_LIST(Type.LIST_VIEW, ConfigTemplateList.class,
|
||||
ActivityDefinition.SEB_EXAM_CONFIG_TEMPLATE),
|
||||
SEB_EXAM_CONFIG_TEMPLATE_VIEW(Type.FORM_VIEW, ConfigTemplateForm.class,
|
||||
ActivityDefinition.SEB_EXAM_CONFIG_TEMPLATE),
|
||||
SEB_EXAM_CONFIG_TEMPLATE_EDIT(Type.FORM_EDIT, ConfigTemplateForm.class,
|
||||
ActivityDefinition.SEB_EXAM_CONFIG_TEMPLATE),
|
||||
SEB_EXAM_CONFIG_TEMPLATE_ATTRIBUTE_EDIT(
|
||||
Type.FORM_EDIT,
|
||||
ConfigTemplateAttributeForm.class,
|
||||
ActivityDefinition.SEB_EXAM_CONFIG_TEMPLATE),
|
||||
|
||||
MONITORING_RUNNING_EXAM_LIST(Type.LIST_VIEW, MonitoringRunningExamList.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),
|
||||
|
||||
USER_ACTIVITY_LOGS(Type.LIST_VIEW, UserActivityLogs.class, ActivityDefinition.USER_ACTIVITY_LOGS),
|
||||
SEB_CLIENT_LOGS(Type.LIST_VIEW, SebClientLogs.class, ActivityDefinition.SEB_CLIENT_LOGS)
|
||||
|
||||
;
|
||||
|
||||
public final Type type;
|
||||
public final Class<? extends TemplateComposer> contentPaneComposer;
|
||||
public final Class<? extends TemplateComposer> actionPaneComposer;
|
||||
public final Activity activityAnchor;
|
||||
|
||||
private PageStateDefinitionImpl(
|
||||
final Type type,
|
||||
final Class<? extends TemplateComposer> contentPaneComposer,
|
||||
final Activity activityAnchor) {
|
||||
|
||||
this(type, contentPaneComposer, ActionPane.class, activityAnchor);
|
||||
}
|
||||
|
||||
private PageStateDefinitionImpl(
|
||||
final Type type,
|
||||
final Class<? extends TemplateComposer> contentPaneComposer,
|
||||
final Class<? extends TemplateComposer> actionPaneComposer,
|
||||
final Activity activityAnchor) {
|
||||
|
||||
this.type = type;
|
||||
this.contentPaneComposer = contentPaneComposer;
|
||||
this.actionPaneComposer = actionPaneComposer;
|
||||
this.activityAnchor = activityAnchor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type type() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends TemplateComposer> contentPaneComposer() {
|
||||
return this.contentPaneComposer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends TemplateComposer> actionPaneComposer() {
|
||||
return this.actionPaneComposer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Activity activityAnchor() {
|
||||
return this.activityAnchor;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,181 +1,186 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.i18n;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
|
||||
public interface I18nSupport {
|
||||
|
||||
public static final String SUPPORTED_LANGUAGES_KEY = "sebserver.gui.supported.languages";
|
||||
public static final String MULTILINGUAL_KEY = "sebserver.gui.multilingual";
|
||||
public static final String FORMAL_LOCALE_KEY = "sebserver.gui.date.displayformat";
|
||||
public static final String ATTR_CURRENT_SESSION_LOCALE = "CURRENT_SESSION_LOCALE";
|
||||
|
||||
/** Get all supported languages as a collection of Locale
|
||||
*
|
||||
* @return all supported languages as a collection of Locale */
|
||||
Collection<Locale> supportedLanguages();
|
||||
|
||||
/** 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
|
||||
*
|
||||
* @return the current user language Locale to use in context */
|
||||
Locale getUsersLanguageLocale();
|
||||
|
||||
/** 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
|
||||
*
|
||||
* @return the current user format Locale to use in context */
|
||||
Locale getUsersFormatLocale();
|
||||
|
||||
/** Format a DateTime to a text format to display.
|
||||
* This uses the date-format defined by either the attribute 'sebserver.gui.date.displayformat'
|
||||
* or the Constants.DEFAULT_DISPLAY_DATE_FORMAT
|
||||
*
|
||||
* Adds time-zone offset information if the currents user time-zone is different form UTC
|
||||
*
|
||||
* @param date the DateTime instance
|
||||
* @return date formatted date String to display */
|
||||
String formatDisplayDate(DateTime date);
|
||||
|
||||
/** 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'
|
||||
* or the Constants.DEFAULT_DISPLAY_DATE_FORMAT
|
||||
*
|
||||
* Adds time-zone offset information if the currents user time-zone is different form UTC
|
||||
*
|
||||
* @param date the DateTime instance
|
||||
* @return date formatted date String to display */
|
||||
default String formatDisplayDateWithTimeZone(final DateTime date) {
|
||||
return formatDisplayDateTime(date) + " " + this.getUsersTimeZoneTitleSuffix();
|
||||
}
|
||||
|
||||
/** 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'
|
||||
* or the Constants.DEFAULT_DISPLAY_DATE_FORMAT
|
||||
*
|
||||
* Adds time-zone information if the currents user time-zone is different form UTC
|
||||
*
|
||||
* @param date the DateTime instance
|
||||
* @return date formatted date String to display */
|
||||
default String formatDisplayDate(final Long timestamp) {
|
||||
return formatDisplayDate(Utils.toDateTimeUTC(timestamp));
|
||||
}
|
||||
|
||||
/** Format a DateTime to a text format to display.
|
||||
* This uses the date-format defined by either the attribute 'sebserver.gui.datetime.displayformat'
|
||||
* or the Constants.DEFAULT_DISPLAY_DATE_TIME_FORMAT
|
||||
*
|
||||
* Adds time-zone information if the currents user time-zone is different form UTC
|
||||
*
|
||||
* @param date the DateTime instance
|
||||
* @return date formatted date time String to display */
|
||||
String formatDisplayDateTime(DateTime date);
|
||||
|
||||
/** 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'
|
||||
* or the Constants.DEFAULT_DISPLAY_DATE_TIME_FORMAT
|
||||
*
|
||||
* Adds time-zone information if the currents user time-zone is different form UTC
|
||||
*
|
||||
* @param date the DateTime instance
|
||||
* @return date formatted date time String to display */
|
||||
default String formatDisplayDateTime(final Long timestamp) {
|
||||
return formatDisplayDateTime(Utils.toDateTimeUTC(timestamp));
|
||||
}
|
||||
|
||||
/** Format a DateTime to a text format to display.
|
||||
* This uses the date-format defined by either the attribute 'sebserver.gui.time.displayformat'
|
||||
* or the Constants.DEFAULT_DISPLAY_TIME_FORMAT
|
||||
*
|
||||
* Adds time-zone information if the currents user time-zone is different form UTC
|
||||
*
|
||||
* @param date the DateTime instance
|
||||
* @return date formatted time String to display */
|
||||
String formatDisplayTime(DateTime date);
|
||||
|
||||
/** 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'
|
||||
* or the Constants.DEFAULT_DISPLAY_TIME_FORMAT
|
||||
*
|
||||
* Adds time-zone information if the currents user time-zone is different form UTC
|
||||
*
|
||||
* @param date the DateTime instance
|
||||
* @return date formatted time String to display */
|
||||
default String formatDisplayTime(final Long timestamp) {
|
||||
return formatDisplayTime(Utils.toDateTimeUTC(timestamp));
|
||||
}
|
||||
|
||||
/** 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.
|
||||
*
|
||||
* @return date/time column title suffix for current user */
|
||||
String getUsersTimeZoneTitleSuffix();
|
||||
|
||||
/** Get localized text of specified key for currently set Locale.
|
||||
*
|
||||
* @param key LocTextKey instance
|
||||
* @param def default text
|
||||
* @return the text in current language parsed from localized text */
|
||||
default String getText(final LocTextKey key, final String def) {
|
||||
return getText(key.name, def, key.args);
|
||||
}
|
||||
|
||||
/** Get localized text of specified key for currently set Locale.
|
||||
*
|
||||
* @param key LocTextKey instance
|
||||
* @return the text in current language parsed from localized text */
|
||||
default String getText(final LocTextKey key) {
|
||||
return getText(key.name, key.name, key.args);
|
||||
}
|
||||
|
||||
/** Get localized text of specified key for currently set Locale.
|
||||
*
|
||||
* @param key the key name of localized text
|
||||
* @param args additional arguments to parse the localized text
|
||||
* @return the text in current language parsed from localized text */
|
||||
default String getText(final String key, final Object... args) {
|
||||
return getText(key, key, args);
|
||||
}
|
||||
|
||||
/** Get localized text of specified key for currently set Locale.
|
||||
*
|
||||
* @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 args additional arguments to parse the localized text
|
||||
* @return the text in current language parsed from localized text */
|
||||
String getText(final String key, String def, Object... args);
|
||||
|
||||
/** Get localized text of specified key and Locale.
|
||||
*
|
||||
* @param key the key name of localized text
|
||||
* @param locale the Locale
|
||||
* @param args additional arguments to parse the localized text
|
||||
* @return the text in current language parsed from localized text */
|
||||
default String getText(final String key, final Locale locale, final Object... args) {
|
||||
return getText(key, locale, key, args);
|
||||
}
|
||||
|
||||
/** Get localized text of specified key and Locale.
|
||||
*
|
||||
* @param key the key name of localized text
|
||||
* @param locale the Locale
|
||||
* @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
|
||||
* @return the text in current language parsed from localized text */
|
||||
String getText(String key, Locale locale, String def, Object... args);
|
||||
|
||||
boolean hasText(LocTextKey locTextKey);
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.i18n;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
|
||||
public interface I18nSupport {
|
||||
|
||||
public static final String SUPPORTED_LANGUAGES_KEY = "sebserver.gui.supported.languages";
|
||||
public static final String MULTILINGUAL_KEY = "sebserver.gui.multilingual";
|
||||
public static final String FORMAL_LOCALE_KEY = "sebserver.gui.date.displayformat";
|
||||
public static final String ATTR_CURRENT_SESSION_LOCALE = "CURRENT_SESSION_LOCALE";
|
||||
|
||||
/** Get all supported languages as a collection of Locale
|
||||
*
|
||||
* @return all supported languages as a collection of Locale */
|
||||
Collection<Locale> supportedLanguages();
|
||||
|
||||
/** 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
|
||||
*
|
||||
* @return the current user language Locale to use in context */
|
||||
Locale getUsersLanguageLocale();
|
||||
|
||||
/** 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
|
||||
*
|
||||
* @return the current user format Locale to use in context */
|
||||
Locale getUsersFormatLocale();
|
||||
|
||||
/** Format a DateTime to a text format to display.
|
||||
* This uses the date-format defined by either the attribute 'sebserver.gui.date.displayformat'
|
||||
* or the Constants.DEFAULT_DISPLAY_DATE_FORMAT
|
||||
*
|
||||
* Adds time-zone offset information if the currents user time-zone is different form UTC
|
||||
*
|
||||
* @param date the DateTime instance
|
||||
* @return date formatted date String to display */
|
||||
String formatDisplayDate(DateTime date);
|
||||
|
||||
/** 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'
|
||||
* or the Constants.DEFAULT_DISPLAY_DATE_FORMAT
|
||||
*
|
||||
* Adds time-zone offset information if the currents user time-zone is different form UTC
|
||||
*
|
||||
* @param date the DateTime instance
|
||||
* @return date formatted date String to display */
|
||||
default String formatDisplayDateWithTimeZone(final DateTime date) {
|
||||
return formatDisplayDateTime(date) + " " + this.getUsersTimeZoneTitleSuffix();
|
||||
}
|
||||
|
||||
/** 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'
|
||||
* or the Constants.DEFAULT_DISPLAY_DATE_FORMAT
|
||||
*
|
||||
* Adds time-zone information if the currents user time-zone is different form UTC
|
||||
*
|
||||
* @param date the DateTime instance
|
||||
* @return date formatted date String to display */
|
||||
default String formatDisplayDate(final Long timestamp) {
|
||||
return formatDisplayDate(Utils.toDateTimeUTC(timestamp));
|
||||
}
|
||||
|
||||
/** Format a DateTime to a text format to display.
|
||||
* This uses the date-format defined by either the attribute 'sebserver.gui.datetime.displayformat'
|
||||
* or the Constants.DEFAULT_DISPLAY_DATE_TIME_FORMAT
|
||||
*
|
||||
* Adds time-zone information if the currents user time-zone is different form UTC
|
||||
*
|
||||
* @param date the DateTime instance
|
||||
* @return date formatted date time String to display */
|
||||
String formatDisplayDateTime(DateTime date);
|
||||
|
||||
/** 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'
|
||||
* or the Constants.DEFAULT_DISPLAY_DATE_TIME_FORMAT
|
||||
*
|
||||
* Adds time-zone information if the currents user time-zone is different form UTC
|
||||
*
|
||||
* @param date the DateTime instance
|
||||
* @return date formatted date time String to display */
|
||||
default String formatDisplayDateTime(final Long timestamp) {
|
||||
return formatDisplayDateTime(Utils.toDateTimeUTC(timestamp));
|
||||
}
|
||||
|
||||
/** Format a DateTime to a text format to display.
|
||||
* This uses the date-format defined by either the attribute 'sebserver.gui.time.displayformat'
|
||||
* or the Constants.DEFAULT_DISPLAY_TIME_FORMAT
|
||||
*
|
||||
* Adds time-zone information if the currents user time-zone is different form UTC
|
||||
*
|
||||
* @param date the DateTime instance
|
||||
* @return date formatted time String to display */
|
||||
String formatDisplayTime(DateTime date);
|
||||
|
||||
/** 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'
|
||||
* or the Constants.DEFAULT_DISPLAY_TIME_FORMAT
|
||||
*
|
||||
* Adds time-zone information if the currents user time-zone is different form UTC
|
||||
*
|
||||
* @param date the DateTime instance
|
||||
* @return date formatted time String to display */
|
||||
default String formatDisplayTime(final Long timestamp) {
|
||||
return formatDisplayTime(Utils.toDateTimeUTC(timestamp));
|
||||
}
|
||||
|
||||
/** 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.
|
||||
*
|
||||
* @return date/time column title suffix for current user */
|
||||
String getUsersTimeZoneTitleSuffix();
|
||||
|
||||
/** Get localized text of specified key for currently set Locale.
|
||||
*
|
||||
* @param key LocTextKey instance
|
||||
* @param def default text
|
||||
* @return the text in current language parsed from localized text */
|
||||
default String getText(final LocTextKey key, final String def) {
|
||||
return getText(key.name, def, key.args);
|
||||
}
|
||||
|
||||
/** Get localized text of specified key for currently set Locale.
|
||||
*
|
||||
* @param key LocTextKey instance
|
||||
* @return the text in current language parsed from localized text */
|
||||
default String getText(final LocTextKey key) {
|
||||
return getText(key.name, key.name, key.args);
|
||||
}
|
||||
|
||||
/** Get localized text of specified key for currently set Locale.
|
||||
*
|
||||
* @param key the key name of localized text
|
||||
* @param args additional arguments to parse the localized text
|
||||
* @return the text in current language parsed from localized text */
|
||||
default String getText(final String key, final Object... args) {
|
||||
return getText(key, key, args);
|
||||
}
|
||||
|
||||
/** Get localized text of specified key for currently set Locale.
|
||||
*
|
||||
* @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 args additional arguments to parse the localized text
|
||||
* @return the text in current language parsed from localized text */
|
||||
String getText(final String key, String def, Object... args);
|
||||
|
||||
/** Get localized text of specified key and Locale.
|
||||
*
|
||||
* @param key the key name of localized text
|
||||
* @param locale the Locale
|
||||
* @param args additional arguments to parse the localized text
|
||||
* @return the text in current language parsed from localized text */
|
||||
default String getText(final String key, final Locale locale, final Object... args) {
|
||||
return getText(key, locale, key, args);
|
||||
}
|
||||
|
||||
/** Get localized text of specified key and Locale.
|
||||
*
|
||||
* @param key the key name of localized text
|
||||
* @param locale the Locale
|
||||
* @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
|
||||
* @return the text in current language parsed from localized text */
|
||||
String getText(String key, Locale locale, String def, Object... args);
|
||||
|
||||
/** 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);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,296 +1,294 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.i18n.impl;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.rap.rwt.RWT;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.widgets.Button;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Control;
|
||||
import org.eclipse.swt.widgets.Group;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.TabFolder;
|
||||
import org.eclipse.swt.widgets.TabItem;
|
||||
import org.eclipse.swt.widgets.Table;
|
||||
import org.eclipse.swt.widgets.TableColumn;
|
||||
import org.eclipse.swt.widgets.TableItem;
|
||||
import org.eclipse.swt.widgets.Tree;
|
||||
import org.eclipse.swt.widgets.TreeItem;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
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.LocTextKey;
|
||||
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.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.widget.ImageUploadSelection;
|
||||
|
||||
/** Service that supports page language change on the fly */
|
||||
@Lazy
|
||||
@Service
|
||||
@GuiProfile
|
||||
public final class PolyglotPageServiceImpl implements PolyglotPageService {
|
||||
|
||||
private final I18nSupport i18nSupport;
|
||||
|
||||
public PolyglotPageServiceImpl(final I18nSupport i18nSupport) {
|
||||
this.i18nSupport = i18nSupport;
|
||||
}
|
||||
|
||||
@Override
|
||||
public I18nSupport getI18nSupport() {
|
||||
return this.i18nSupport;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultPageLocale(final Composite root) {
|
||||
setPageLocale(root, this.i18nSupport.getUsersLanguageLocale());
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setPageLocale(final Composite root, final Locale locale) {
|
||||
RWT.getUISession()
|
||||
.getHttpSession()
|
||||
.setAttribute(I18nSupport.ATTR_CURRENT_SESSION_LOCALE, locale);
|
||||
|
||||
ComposerService.traversePageTree(
|
||||
root,
|
||||
comp -> comp.getData(POLYGLOT_WIDGET_FUNCTION_KEY) != null,
|
||||
comp -> ((Consumer<Control>) comp.getData(POLYGLOT_WIDGET_FUNCTION_KEY)).accept(comp));
|
||||
|
||||
root.layout(true, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectI18n(final ImageUploadSelection imageUpload, final LocTextKey locTextKey) {
|
||||
final Consumer<ImageUploadSelection> imageUploadFunction = iu -> {
|
||||
if (locTextKey != null) {
|
||||
iu.setSelectionText(this.i18nSupport.getText(locTextKey));
|
||||
}
|
||||
};
|
||||
imageUpload.setData(POLYGLOT_WIDGET_FUNCTION_KEY, imageUploadFunction);
|
||||
imageUploadFunction.accept(imageUpload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectI18n(final Label label, final LocTextKey locTextKey) {
|
||||
injectI18n(label, locTextKey, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectI18n(final Label label, final LocTextKey locTextKey, final LocTextKey locToolTipKey) {
|
||||
final Consumer<Label> labelFunction = labelFunction(locTextKey, locToolTipKey, this.i18nSupport);
|
||||
label.setData(POLYGLOT_WIDGET_FUNCTION_KEY, labelFunction);
|
||||
labelFunction.accept(label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectI18n(final Group group, final LocTextKey locTextKey, final LocTextKey locTooltipKey) {
|
||||
final Consumer<Group> groupFunction = groupFunction(locTextKey, locTooltipKey, this.i18nSupport);
|
||||
group.setData(POLYGLOT_WIDGET_FUNCTION_KEY, groupFunction);
|
||||
groupFunction.accept(group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectI18n(final Button button, final LocTextKey locTextKey) {
|
||||
injectI18n(button, locTextKey, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectI18n(final Button button, final LocTextKey locTextKey, final LocTextKey locToolTipKey) {
|
||||
final Consumer<Button> buttonFunction = b -> {
|
||||
if (locTextKey != null) {
|
||||
b.setText(this.i18nSupport.getText(locTextKey));
|
||||
}
|
||||
if (locToolTipKey != null) {
|
||||
b.setToolTipText(Utils.formatLineBreaks(this.i18nSupport.getText(locToolTipKey)));
|
||||
}
|
||||
};
|
||||
button.setData(POLYGLOT_WIDGET_FUNCTION_KEY, buttonFunction);
|
||||
buttonFunction.accept(button);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectI18n(final Tree tree) {
|
||||
tree.setData(
|
||||
POLYGLOT_WIDGET_FUNCTION_KEY,
|
||||
(Consumer<Tree>) t -> updateLocale(t.getItems(), this.i18nSupport));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectI18n(final TreeItem treeItem, final LocTextKey locTextKey) {
|
||||
treeItem.setData(POLYGLOT_ITEM_TEXT_DATA_KEY, locTextKey);
|
||||
treeItem.setText(this.i18nSupport.getText(locTextKey));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectI18n(final Table table) {
|
||||
table.setData(
|
||||
POLYGLOT_WIDGET_FUNCTION_KEY,
|
||||
(Consumer<Table>) t -> {
|
||||
updateLocale(t.getColumns(), this.i18nSupport);
|
||||
updateLocale(t.getItems(), this.i18nSupport);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectI18n(final TabFolder tabFolder) {
|
||||
tabFolder.setData(
|
||||
POLYGLOT_WIDGET_FUNCTION_KEY,
|
||||
(Consumer<TabFolder>) t -> updateLocale(t.getItems(), this.i18nSupport));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectI18n(final TableColumn tableColumn, final LocTextKey locTextKey, final LocTextKey locTooltipKey) {
|
||||
tableColumn.setData(POLYGLOT_ITEM_TEXT_DATA_KEY, locTextKey);
|
||||
tableColumn.setText(this.i18nSupport.getText(locTextKey));
|
||||
|
||||
if (this.i18nSupport.hasText(locTooltipKey)) {
|
||||
tableColumn.setData(POLYGLOT_ITEM_TOOLTIP_DATA_KEY, locTooltipKey);
|
||||
tableColumn.setToolTipText(Utils.formatLineBreaks(this.i18nSupport.getText(locTooltipKey)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectI18n(final TableItem tableItem, final LocTextKey... locTextKey) {
|
||||
if (locTextKey == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
tableItem.setData(POLYGLOT_ITEM_TEXT_DATA_KEY, locTextKey);
|
||||
for (int i = 0; i < locTextKey.length; i++) {
|
||||
tableItem.setText(i, this.i18nSupport.getText(locTextKey[i]));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectI18n(final TabItem tabItem, final LocTextKey locTextKey, final LocTextKey locTooltipKey) {
|
||||
tabItem.setData(POLYGLOT_ITEM_TEXT_DATA_KEY, locTextKey);
|
||||
tabItem.setText(this.i18nSupport.getText(locTextKey));
|
||||
|
||||
if (this.i18nSupport.hasText(locTooltipKey)) {
|
||||
tabItem.setData(POLYGLOT_ITEM_TOOLTIP_DATA_KEY, locTooltipKey);
|
||||
tabItem.setToolTipText(Utils.formatLineBreaks(this.i18nSupport.getText(locTooltipKey)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createLanguageSelector(final PageContext composerCtx) {
|
||||
for (final Locale locale : this.i18nSupport.supportedLanguages()) {
|
||||
final Label languageSelection = new Label(composerCtx.getParent(), SWT.NONE);
|
||||
languageSelection.setData(
|
||||
POLYGLOT_WIDGET_FUNCTION_KEY,
|
||||
(Consumer<Label>) label -> label.setVisible(
|
||||
!this.i18nSupport.getUsersLanguageLocale()
|
||||
.getLanguage()
|
||||
.equals(locale.getLanguage())));
|
||||
languageSelection.setData(RWT.CUSTOM_VARIANT, "header");
|
||||
languageSelection.setText("| " + locale.getLanguage().toUpperCase(locale));
|
||||
languageSelection.addListener(SWT.MouseDown, event -> {
|
||||
this.setPageLocale(composerCtx.getRoot(), locale);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static final Consumer<Label> labelFunction(
|
||||
final LocTextKey locTextKey,
|
||||
final LocTextKey locToolTipKey,
|
||||
final I18nSupport i18nSupport) {
|
||||
|
||||
return label -> {
|
||||
if (locTextKey != null) {
|
||||
label.setText(i18nSupport.getText(locTextKey));
|
||||
}
|
||||
if (locToolTipKey != null) {
|
||||
label.setToolTipText(Utils.formatLineBreaks(i18nSupport.getText(locToolTipKey)));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static final Consumer<Group> groupFunction(
|
||||
final LocTextKey locTextKey,
|
||||
final LocTextKey locToolTipKey,
|
||||
final I18nSupport i18nSupport) {
|
||||
|
||||
return group -> {
|
||||
if (locTextKey != null) {
|
||||
group.setText(i18nSupport.getText(locTextKey));
|
||||
}
|
||||
if (locToolTipKey != null) {
|
||||
group.setToolTipText(Utils.formatLineBreaks(i18nSupport.getText(locToolTipKey, StringUtils.EMPTY)));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static final void updateLocale(final TabItem[] items, final I18nSupport i18nSupport) {
|
||||
if (items == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (final TabItem childItem : items) {
|
||||
final LocTextKey locTextKey = (LocTextKey) childItem.getData(POLYGLOT_ITEM_TEXT_DATA_KEY);
|
||||
if (locTextKey != null) {
|
||||
childItem.setText(i18nSupport.getText(locTextKey));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final void updateLocale(final TreeItem[] items, final I18nSupport i18nSupport) {
|
||||
if (items == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (final TreeItem childItem : items) {
|
||||
final LocTextKey locTextKey = (LocTextKey) childItem.getData(POLYGLOT_ITEM_TEXT_DATA_KEY);
|
||||
if (locTextKey != null) {
|
||||
childItem.setText(i18nSupport.getText(locTextKey));
|
||||
}
|
||||
updateLocale(childItem.getItems(), i18nSupport);
|
||||
}
|
||||
}
|
||||
|
||||
private static void updateLocale(final TableItem[] items, final I18nSupport i18nSupport) {
|
||||
if (items == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (final TableItem childItem : items) {
|
||||
final LocTextKey[] locTextKey = (LocTextKey[]) childItem.getData(POLYGLOT_ITEM_TEXT_DATA_KEY);
|
||||
if (locTextKey != null) {
|
||||
for (int i = 0; i < locTextKey.length; 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) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (final TableColumn childItem : columns) {
|
||||
final LocTextKey locTextKey = (LocTextKey) childItem.getData(POLYGLOT_ITEM_TEXT_DATA_KEY);
|
||||
if (locTextKey != null) {
|
||||
childItem.setText(i18nSupport.getText(locTextKey));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.i18n.impl;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.rap.rwt.RWT;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.widgets.Button;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Control;
|
||||
import org.eclipse.swt.widgets.Group;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.TabFolder;
|
||||
import org.eclipse.swt.widgets.TabItem;
|
||||
import org.eclipse.swt.widgets.Table;
|
||||
import org.eclipse.swt.widgets.TableColumn;
|
||||
import org.eclipse.swt.widgets.TableItem;
|
||||
import org.eclipse.swt.widgets.Tree;
|
||||
import org.eclipse.swt.widgets.TreeItem;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
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.LocTextKey;
|
||||
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.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.widget.ImageUploadSelection;
|
||||
|
||||
/** Service that supports page language change on the fly */
|
||||
@Lazy
|
||||
@Service
|
||||
@GuiProfile
|
||||
public final class PolyglotPageServiceImpl implements PolyglotPageService {
|
||||
|
||||
private final I18nSupport i18nSupport;
|
||||
|
||||
public PolyglotPageServiceImpl(final I18nSupport i18nSupport) {
|
||||
this.i18nSupport = i18nSupport;
|
||||
}
|
||||
|
||||
@Override
|
||||
public I18nSupport getI18nSupport() {
|
||||
return this.i18nSupport;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultPageLocale(final Composite root) {
|
||||
setPageLocale(root, this.i18nSupport.getUsersLanguageLocale());
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setPageLocale(final Composite root, final Locale locale) {
|
||||
RWT.getUISession()
|
||||
.getHttpSession()
|
||||
.setAttribute(I18nSupport.ATTR_CURRENT_SESSION_LOCALE, locale);
|
||||
|
||||
ComposerService.traversePageTree(
|
||||
root,
|
||||
comp -> comp.getData(POLYGLOT_WIDGET_FUNCTION_KEY) != null,
|
||||
comp -> ((Consumer<Control>) comp.getData(POLYGLOT_WIDGET_FUNCTION_KEY)).accept(comp));
|
||||
|
||||
root.layout(true, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectI18n(final ImageUploadSelection imageUpload, final LocTextKey locTextKey) {
|
||||
final Consumer<ImageUploadSelection> imageUploadFunction = iu -> {
|
||||
if (locTextKey != null) {
|
||||
iu.setSelectionText(this.i18nSupport.getText(locTextKey));
|
||||
}
|
||||
};
|
||||
imageUpload.setData(POLYGLOT_WIDGET_FUNCTION_KEY, imageUploadFunction);
|
||||
imageUploadFunction.accept(imageUpload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectI18n(final Label label, final LocTextKey locTextKey) {
|
||||
injectI18n(label, locTextKey, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectI18n(final Label label, final LocTextKey locTextKey, final LocTextKey locToolTipKey) {
|
||||
final Consumer<Label> labelFunction = labelFunction(locTextKey, locToolTipKey, this.i18nSupport);
|
||||
label.setData(POLYGLOT_WIDGET_FUNCTION_KEY, labelFunction);
|
||||
labelFunction.accept(label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectI18n(final Group group, final LocTextKey locTextKey, final LocTextKey locTooltipKey) {
|
||||
final Consumer<Group> groupFunction = groupFunction(locTextKey, locTooltipKey, this.i18nSupport);
|
||||
group.setData(POLYGLOT_WIDGET_FUNCTION_KEY, groupFunction);
|
||||
groupFunction.accept(group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectI18n(final Button button, final LocTextKey locTextKey) {
|
||||
injectI18n(button, locTextKey, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectI18n(final Button button, final LocTextKey locTextKey, final LocTextKey locToolTipKey) {
|
||||
final Consumer<Button> buttonFunction = b -> {
|
||||
if (locTextKey != null) {
|
||||
b.setText(this.i18nSupport.getText(locTextKey));
|
||||
}
|
||||
if (i18nSupport.hasText(locToolTipKey)) {
|
||||
b.setToolTipText(Utils.formatLineBreaks(this.i18nSupport.getText(locToolTipKey)));
|
||||
}
|
||||
};
|
||||
button.setData(POLYGLOT_WIDGET_FUNCTION_KEY, buttonFunction);
|
||||
buttonFunction.accept(button);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectI18n(final Tree tree) {
|
||||
tree.setData(
|
||||
POLYGLOT_WIDGET_FUNCTION_KEY,
|
||||
(Consumer<Tree>) t -> updateLocale(t.getItems(), this.i18nSupport));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectI18n(final TreeItem treeItem, final LocTextKey locTextKey) {
|
||||
treeItem.setData(POLYGLOT_ITEM_TEXT_DATA_KEY, locTextKey);
|
||||
treeItem.setText(this.i18nSupport.getText(locTextKey));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectI18n(final Table table) {
|
||||
table.setData(
|
||||
POLYGLOT_WIDGET_FUNCTION_KEY,
|
||||
(Consumer<Table>) t -> {
|
||||
updateLocale(t.getColumns(), this.i18nSupport);
|
||||
updateLocale(t.getItems(), this.i18nSupport);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectI18n(final TabFolder tabFolder) {
|
||||
tabFolder.setData(
|
||||
POLYGLOT_WIDGET_FUNCTION_KEY,
|
||||
(Consumer<TabFolder>) t -> updateLocale(t.getItems(), this.i18nSupport));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectI18n(final TableColumn tableColumn, final LocTextKey locTextKey, final LocTextKey locTooltipKey) {
|
||||
tableColumn.setData(POLYGLOT_ITEM_TEXT_DATA_KEY, locTextKey);
|
||||
tableColumn.setText(this.i18nSupport.getText(locTextKey));
|
||||
|
||||
if (this.i18nSupport.hasText(locTooltipKey)) {
|
||||
tableColumn.setData(POLYGLOT_ITEM_TOOLTIP_DATA_KEY, locTooltipKey);
|
||||
tableColumn.setToolTipText(Utils.formatLineBreaks(this.i18nSupport.getText(locTooltipKey)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectI18n(final TableItem tableItem, final LocTextKey... locTextKey) {
|
||||
if (locTextKey == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
tableItem.setData(POLYGLOT_ITEM_TEXT_DATA_KEY, locTextKey);
|
||||
for (int i = 0; i < locTextKey.length; i++) {
|
||||
tableItem.setText(i, this.i18nSupport.getText(locTextKey[i]));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectI18n(final TabItem tabItem, final LocTextKey locTextKey, final LocTextKey locTooltipKey) {
|
||||
tabItem.setData(POLYGLOT_ITEM_TEXT_DATA_KEY, locTextKey);
|
||||
tabItem.setText(this.i18nSupport.getText(locTextKey));
|
||||
|
||||
if (this.i18nSupport.hasText(locTooltipKey)) {
|
||||
tabItem.setData(POLYGLOT_ITEM_TOOLTIP_DATA_KEY, locTooltipKey);
|
||||
tabItem.setToolTipText(Utils.formatLineBreaks(this.i18nSupport.getText(locTooltipKey)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createLanguageSelector(final PageContext composerCtx) {
|
||||
for (final Locale locale : this.i18nSupport.supportedLanguages()) {
|
||||
final Label languageSelection = new Label(composerCtx.getParent(), SWT.NONE);
|
||||
languageSelection.setData(
|
||||
POLYGLOT_WIDGET_FUNCTION_KEY,
|
||||
(Consumer<Label>) label -> label.setVisible(
|
||||
!this.i18nSupport.getUsersLanguageLocale()
|
||||
.getLanguage()
|
||||
.equals(locale.getLanguage())));
|
||||
languageSelection.setData(RWT.CUSTOM_VARIANT, "header");
|
||||
languageSelection.setText("| " + locale.getLanguage().toUpperCase(locale));
|
||||
languageSelection.addListener(SWT.MouseDown, event -> this.setPageLocale(composerCtx.getRoot(), locale));
|
||||
}
|
||||
}
|
||||
|
||||
private static Consumer<Label> labelFunction(
|
||||
final LocTextKey locTextKey,
|
||||
final LocTextKey locToolTipKey,
|
||||
final I18nSupport i18nSupport) {
|
||||
|
||||
return label -> {
|
||||
if (locTextKey != null) {
|
||||
label.setText(i18nSupport.getText(locTextKey));
|
||||
}
|
||||
if (i18nSupport.hasText(locToolTipKey)) {
|
||||
label.setToolTipText(Utils.formatLineBreaks(i18nSupport.getText(locToolTipKey)));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static Consumer<Group> groupFunction(
|
||||
final LocTextKey locTextKey,
|
||||
final LocTextKey locToolTipKey,
|
||||
final I18nSupport i18nSupport) {
|
||||
|
||||
return group -> {
|
||||
if (locTextKey != null) {
|
||||
group.setText(i18nSupport.getText(locTextKey));
|
||||
}
|
||||
if (i18nSupport.hasText(locToolTipKey)) {
|
||||
group.setToolTipText(Utils.formatLineBreaks(i18nSupport.getText(locToolTipKey, StringUtils.EMPTY)));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static void updateLocale(final TabItem[] items, final I18nSupport i18nSupport) {
|
||||
if (items == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (final TabItem childItem : items) {
|
||||
final LocTextKey locTextKey = (LocTextKey) childItem.getData(POLYGLOT_ITEM_TEXT_DATA_KEY);
|
||||
if (locTextKey != null) {
|
||||
childItem.setText(i18nSupport.getText(locTextKey));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void updateLocale(final TreeItem[] items, final I18nSupport i18nSupport) {
|
||||
if (items == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (final TreeItem childItem : items) {
|
||||
final LocTextKey locTextKey = (LocTextKey) childItem.getData(POLYGLOT_ITEM_TEXT_DATA_KEY);
|
||||
if (locTextKey != null) {
|
||||
childItem.setText(i18nSupport.getText(locTextKey));
|
||||
}
|
||||
updateLocale(childItem.getItems(), i18nSupport);
|
||||
}
|
||||
}
|
||||
|
||||
private static void updateLocale(final TableItem[] items, final I18nSupport i18nSupport) {
|
||||
if (items == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (final TableItem childItem : items) {
|
||||
final LocTextKey[] locTextKey = (LocTextKey[]) childItem.getData(POLYGLOT_ITEM_TEXT_DATA_KEY);
|
||||
if (locTextKey != null) {
|
||||
for (int i = 0; i < locTextKey.length; 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) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (final TableColumn childItem : columns) {
|
||||
final LocTextKey locTextKey = (LocTextKey) childItem.getData(POLYGLOT_ITEM_TEXT_DATA_KEY);
|
||||
if (locTextKey != null) {
|
||||
childItem.setText(i18nSupport.getText(locTextKey));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,134 +1,141 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.widget;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Button;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Listener;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||
|
||||
public final class MultiSelectionCheckbox extends Composite implements Selection {
|
||||
|
||||
private static final long serialVersionUID = -8507565817745610126L;
|
||||
|
||||
private Listener listener = null;
|
||||
private final Map<String, Button> checkboxes;
|
||||
|
||||
MultiSelectionCheckbox(final Composite parent) {
|
||||
super(parent, SWT.NONE);
|
||||
final GridLayout gridLayout = new GridLayout(1, true);
|
||||
gridLayout.verticalSpacing = 1;
|
||||
gridLayout.marginLeft = 0;
|
||||
gridLayout.marginHeight = 0;
|
||||
gridLayout.marginWidth = 0;
|
||||
setLayout(gridLayout);
|
||||
|
||||
this.checkboxes = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type type() {
|
||||
return Type.MULTI_CHECKBOX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyNewMapping(final List<Tuple<String>> mapping) {
|
||||
final String selectionValue = getSelectionValue();
|
||||
this.checkboxes.clear();
|
||||
PageService.clearComposite(this);
|
||||
|
||||
for (final Tuple<String> tuple : mapping) {
|
||||
final Button button = new Button(this, SWT.CHECK);
|
||||
button.setText(tuple._2);
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.CENTER, true, true);
|
||||
button.setLayoutData(gridData);
|
||||
button.setData(OPTION_VALUE, tuple._1);
|
||||
button.addListener(SWT.Selection, event -> {
|
||||
if (this.listener != null) {
|
||||
this.listener.handleEvent(event);
|
||||
}
|
||||
});
|
||||
this.checkboxes.put(tuple._1, button);
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(selectionValue)) {
|
||||
select(selectionValue);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyToolTipsForItems(final List<Tuple<String>> mapping) {
|
||||
mapping
|
||||
.stream()
|
||||
.filter(tuple -> StringUtils.isNotBlank(tuple._2))
|
||||
.forEach(tuple -> {
|
||||
final Button button = this.checkboxes.get(tuple._1);
|
||||
if (button != null) {
|
||||
button.setToolTipText(Utils.formatLineBreaks(tuple._2));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void select(final String keys) {
|
||||
clear();
|
||||
if (StringUtils.isBlank(keys)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Arrays.asList(StringUtils.split(keys, Constants.LIST_SEPARATOR))
|
||||
.stream()
|
||||
.forEach(key -> {
|
||||
final Button button = this.checkboxes.get(key);
|
||||
if (button != null) {
|
||||
button.setSelection(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSelectionValue() {
|
||||
return StringUtils.joinWith(
|
||||
Constants.LIST_SEPARATOR,
|
||||
this.checkboxes
|
||||
.values()
|
||||
.stream()
|
||||
.filter(button -> button.getSelection())
|
||||
.map(button -> (String) button.getData(OPTION_VALUE))
|
||||
.collect(Collectors.toList()).toArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
this.checkboxes
|
||||
.values()
|
||||
.stream()
|
||||
.forEach(button -> button.setSelection(false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelectionListener(final Listener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.widget;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.util.Tuple3;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Button;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Listener;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||
|
||||
public final class MultiSelectionCheckbox extends Composite implements Selection {
|
||||
|
||||
private static final long serialVersionUID = -8507565817745610126L;
|
||||
|
||||
private Listener listener = null;
|
||||
private final Map<String, Button> checkboxes;
|
||||
|
||||
MultiSelectionCheckbox(final Composite parent) {
|
||||
super(parent, SWT.NONE);
|
||||
final GridLayout gridLayout = new GridLayout(1, true);
|
||||
gridLayout.verticalSpacing = 1;
|
||||
gridLayout.marginLeft = 0;
|
||||
gridLayout.marginHeight = 0;
|
||||
gridLayout.marginWidth = 0;
|
||||
setLayout(gridLayout);
|
||||
|
||||
this.checkboxes = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type type() {
|
||||
return Type.MULTI_CHECKBOX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyNewMapping(final List<Tuple<String>> mapping) {
|
||||
final String selectionValue = getSelectionValue();
|
||||
this.checkboxes.clear();
|
||||
PageService.clearComposite(this);
|
||||
|
||||
for (final Tuple<String> tuple : mapping) {
|
||||
final Button button = new Button(this, SWT.CHECK);
|
||||
button.setText(tuple._2);
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.CENTER, true, true);
|
||||
button.setLayoutData(gridData);
|
||||
button.setData(OPTION_VALUE, tuple._1);
|
||||
button.addListener(SWT.Selection, event -> {
|
||||
if (this.listener != null) {
|
||||
this.listener.handleEvent(event);
|
||||
}
|
||||
});
|
||||
this.checkboxes.put(tuple._1, button);
|
||||
|
||||
Tuple3<String> tuple3 = tuple.adaptTo(Tuple3.class);
|
||||
if (tuple3 != null && StringUtils.isNotBlank(tuple3._3)) {
|
||||
button.setToolTipText(tuple3._3);
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(selectionValue)) {
|
||||
select(selectionValue);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyToolTipsForItems(final List<Tuple<String>> mapping) {
|
||||
mapping
|
||||
.stream()
|
||||
.filter(tuple -> StringUtils.isNotBlank(tuple._2))
|
||||
.forEach(tuple -> {
|
||||
final Button button = this.checkboxes.get(tuple._1);
|
||||
if (button != null) {
|
||||
button.setToolTipText(Utils.formatLineBreaks(tuple._2));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void select(final String keys) {
|
||||
clear();
|
||||
if (StringUtils.isBlank(keys)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Arrays.asList(StringUtils.split(keys, Constants.LIST_SEPARATOR))
|
||||
.stream()
|
||||
.forEach(key -> {
|
||||
final Button button = this.checkboxes.get(key);
|
||||
if (button != null) {
|
||||
button.setSelection(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSelectionValue() {
|
||||
return StringUtils.joinWith(
|
||||
Constants.LIST_SEPARATOR,
|
||||
this.checkboxes
|
||||
.values()
|
||||
.stream()
|
||||
.filter(button -> button.getSelection())
|
||||
.map(button -> (String) button.getData(OPTION_VALUE))
|
||||
.collect(Collectors.toList()).toArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
this.checkboxes
|
||||
.values()
|
||||
.stream()
|
||||
.forEach(button -> button.setSelection(false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelectionListener(final Listener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -59,6 +59,8 @@ sebserver.overall.types.entityType.INSTITUTION=Institution
|
|||
sebserver.overall.types.entityType.SEB_CLIENT_CONFIGURATION=Client Configuration
|
||||
sebserver.overall.types.entityType.LMS_SETUP=LMS Setup
|
||||
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.sebconfig=SEB Configuration
|
||||
|
@ -174,18 +176,27 @@ sebserver.institution.form.logoImage.unsupportedFileType=The selected file is no
|
|||
|
||||
sebserver.useraccount.list.actions=
|
||||
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.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.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.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.title=User Accounts
|
||||
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.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.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.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.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.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.new=Add User Account
|
||||
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.tooltip=The date when the user-account was first created.
|
||||
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.tooltip=The last- or surname of the user.
|
||||
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.tooltip=The e-mail address of the user.
|
||||
sebserver.useraccount.form.language=Language
|
||||
sebserver.useraccount.form.language.tooltip=The users language.
|
||||
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.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.tooltip=The password of the user account
|
||||
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.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.tooltip=Please confirm the password
|
||||
|
||||
################################
|
||||
# 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.actions=
|
||||
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.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.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.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.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=SEB Client Configuration
|
||||
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.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.tooltip=The date when the SEB client configuration was first created.
|
||||
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.tooltip=Please retype the given password for configrmation
|
||||
|
||||
sebserver.clientconfig.action.list.new=Add 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.list.title=Exam Configurations
|
||||
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.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.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.tooltip=The status of the SEB exam configuration.</br></br>Use the filter above to specify a status.</br>{0}
|
||||
|
||||
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.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.view=View Settings
|
||||
sebserver.examconfig.action.modify=Edit Settings
|
||||
sebserver.examconfig.action.modify=Configuration Settings
|
||||
sebserver.examconfig.action.modify.properties=Edit Configuration
|
||||
sebserver.examconfig.action.view.properties=View Configuration
|
||||
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=Exam Configuration
|
||||
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.tooltip=The description text of the SEB exam configuration.
|
||||
sebserver.examconfig.form.with-history=With History
|
||||
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.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.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.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=Configuration Template
|
||||
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.tooltip=The description of the SEB exam configuration template
|
||||
sebserver.configtemplate.action.save=Save Template
|
||||
|
||||
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.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.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.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.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.tooltip=The type of the SEB exam configuration attribute.</br></br>{0}
|
||||
|
||||
sebserver.configtemplate.attr.list.actions=
|
||||
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.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.tooltip=The type of the SEB exam configuration attribute.
|
||||
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.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.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.template=View Template
|
||||
|
@ -1165,10 +1218,15 @@ sebserver.logs.activity.seblogs.details=Show Details
|
|||
|
||||
sebserver.userlogs.list.title=User Activity Logs
|
||||
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.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.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.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.message=Message
|
||||
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 678 B After Width: | Height: | Size: 1.7 KiB |
Loading…
Reference in a new issue