code cleanup and docu

This commit is contained in:
anhefti 2020-03-09 14:01:49 +01:00
parent e3b1ead068
commit d93ae0b5ed
7 changed files with 157 additions and 145 deletions

View file

@ -89,7 +89,7 @@ The main content usually consist of a list or a form.
Lists
^^^^^^
A list shows all the objects of a particular activity in a table page. If the list contains as for one page, a page navigation is shown at the bottom of the list with the information of the current page and the number of pages along with a page navigation that can be used to navigate forward and backward thought the list pages.
A list shows all the objects of a particular activity in a table page. A list has paging and if a list has more objects than it fit on one page, a page navigation is shown at the bottom of the list with the information of the current page and the number of pages along with a page navigation that can be used to navigate forward and backward thought the list pages.
Almost all lists have the ability to filter the content by certain column filter that are right above the corresponding columns. To filter a list one can use the column filter input to narrow down a specific collection of content. Accordingly to the value type of the column, there are different types of filter:
- Selection, to select one instance of a defined collection of values (drop-down).
@ -101,16 +101,29 @@ Almost all lists have the ability to filter the content by certain column filter
:align: center
:target: https://raw.githubusercontent.com/SafeExamBrowser/seb-server/master/docs/images/overview/list.png
A list can also be sorted by a column by clicking in the column header and the order of sorting can be changed by clicking again on the same column header. Depending on the column type, not all columns has the sort functionality.
Most columns have a short tool-tip description that pops up while the mouse pointer stays over the column header for a moment.
A list can be sorted within a column by clicking in the column header. The order of sorting can be changed by clicking again on the same column header of the sorted column. If sorting functionality is available for a column depends on the column type. There are a few columns that do not have a sort functionality yet.
Most columns have a short tool-tip description that pops up while the mouse pointer stays over the column header for a moment. A column tool-tip usually also explains how to use the column-related filter
Forms
^^^^^^
Forms are used for object specific data input or presentation, like HTML Forms usually do. Forms appear in three different ways within the SEB Server GUI:
- When a object is first created in edit mode
- When an object is modified also in edit mode
- And when an object is just shown, in read-only mode
The following images shows the same form, once in read-only mode and once edit mode
.. image:: images/overview/form_readonly.png
:align: Form in read-only mode
:align: center
:target: https://raw.githubusercontent.com/SafeExamBrowser/seb-server/master/docs/images/overview/form_readonly.png
.. image:: images/overview/form_edit.png
:align: Form in edit mode
:align: center
:target: https://raw.githubusercontent.com/SafeExamBrowser/seb-server/master/docs/images/overview/form_edit.png
There usually there is a tool-tip on a form field element that is activated either by going over and stay on the form field label or the input section. If a form field is mandatory to either create or save an object, this is marked within a little red arrow just to the right of the form field label. There may be more validation take place on saving the object. If a input needs a special form that is not given by the current input, the form-field will be marked with a red border and a thin red explanation text is shown right below the input field. After correct the missing or wrong input and save again, the SEB Server will accept and process the changes.
If the user navigates away from a form in edit mode, the GUI will inform about possible data loss and asks for proceed or abort.

View file

@ -133,7 +133,7 @@ public final class InstitutionalAuthenticationEntryPoint implements Authenticati
institutionalEndpoint)
.getBody();
if (!institutions.isEmpty()) {
if (institutions != null && !institutions.isEmpty()) {
request.getSession().setAttribute(
INST_SUFFIX_ATTRIBUTE,
StringUtils.isNotBlank(institutionalEndpoint)

View file

@ -42,10 +42,7 @@ public class ThresholdListBuilder extends FieldBuilder<Collection<Threshold>> {
@Override
void build(final FormBuilder builder) {
final Control titleLabel = createTitleLabel(builder.formParent, builder, this);
if (builder.readonly || this.readonly) {
// No read-only view needed for this so far?
} else {
if (!(builder.readonly || this.readonly)) {
final Composite fieldGrid = createFieldGrid(builder.formParent, this.spanInput);
final ThresholdList thresholdList = builder.widgetFactory.thresholdList(

View file

@ -11,6 +11,7 @@ package ch.ethz.seb.sebserver.gui.service.session;
import java.util.Collection;
import java.util.EnumMap;
import org.apache.commons.lang3.BooleanUtils;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.widgets.Display;
import org.slf4j.Logger;
@ -122,7 +123,8 @@ public class ClientConnectionDetails {
if (this.connectionData != null && connectionData != null) {
this.statusChanged =
this.connectionData.clientConnection.status != connectionData.clientConnection.status ||
this.connectionData.missingPing != connectionData.missingPing;
BooleanUtils.toBoolean(this.connectionData.missingPing) !=
BooleanUtils.toBoolean(connectionData.missingPing);
}
this.connectionData = connectionData;
}

View file

@ -32,7 +32,7 @@ public class PasswordInput extends Composite {
private final Composite inputAnchor;
private final Label visibilityButton;
private Text passwordInput = null;
private Text passwordInputField = null;
private boolean isPlainText = true;
private boolean isEditable = true;
@ -71,10 +71,10 @@ public class PasswordInput extends Composite {
}
private void changePasswordView() {
final String value = (this.passwordInput != null) ? this.passwordInput.getText() : null;
final String value = (this.passwordInputField != null) ? this.passwordInputField.getText() : null;
final boolean buildPassword = this.isPlainText;
if (this.passwordInput != null) {
if (this.passwordInputField != null) {
PageService.clearComposite(this.inputAnchor);
}
@ -103,7 +103,7 @@ public class PasswordInput extends Composite {
this.visibilityButton.setImage(WidgetFactory.ImageIcon.VISIBILITY_OFF.getImage(getDisplay()));
}
this.passwordInput = passwordInput;
this.passwordInputField = passwordInput;
this.isPlainText = !this.isPlainText;
super.layout(true, true);
@ -111,7 +111,7 @@ public class PasswordInput extends Composite {
private void changeEvent(final int eventType, final Event event) {
if (!this.visibilityButton.isEnabled() && !StringUtils.endsWith(
this.passwordInput.getText(),
this.passwordInputField.getText(),
Constants.IMPORTED_PASSWORD_MARKER)) {
this.visibilityButton.setEnabled(true);
@ -120,8 +120,8 @@ public class PasswordInput extends Composite {
}
public void setValue(final CharSequence value) {
if (this.passwordInput != null) {
this.passwordInput.setText(value != null ? value.toString() : StringUtils.EMPTY);
if (this.passwordInputField != null) {
this.passwordInputField.setText(value != null ? value.toString() : StringUtils.EMPTY);
if (StringUtils.endsWith(value, Constants.IMPORTED_PASSWORD_MARKER)) {
this.visibilityButton.setEnabled(false);
}
@ -129,8 +129,8 @@ public class PasswordInput extends Composite {
}
public CharSequence getValue() {
if (this.passwordInput != null) {
return this.passwordInput.getText();
if (this.passwordInputField != null) {
return this.passwordInputField.getText();
}
return null;

View file

@ -68,36 +68,36 @@ public class ClientConfigServiceImpl implements ClientConfigService {
private static final Logger log = LoggerFactory.getLogger(ClientConfigServiceImpl.class);
private static final String SEB_CLIENT_CONFIG_TEMPLATE_XML =
" <dict>\r\n" +
" <key>sebMode</key>\r\n" +
" <integer>1</integer>\r\n" +
" <key>sebConfigPurpose</key>\r\n" +
" <integer>%s</integer>\r\n" +
" <key>sebServerFallback</key>\r\n" +
" <%s />\r\n" +
" <dict>%n" +
" <key>sebMode</key>%n" +
" <integer>1</integer>%n" +
" <key>sebConfigPurpose</key>%n" +
" <integer>%s</integer>%n" +
" <key>sebServerFallback</key>%n" +
" <%s />%n" +
"%s" +
" <key>sebServerURL</key>\r\n" +
" <string>%s</string>\r\n" +
" <key>sebServerConfiguration</key>\r\n" +
" <dict>\r\n" +
" <key>institution</key>\r\n" +
" <string>%s</string>\r\n" +
" <key>clientName</key>\r\n" +
" <string>%s</string>\r\n" +
" <key>clientSecret</key>\r\n" +
" <string>%s</string>\r\n" +
" <key>apiDiscovery</key>\r\n" +
" <string>%s</string>\r\n" +
" </dict>\r\n" +
" </dict>\r\n";
" <key>sebServerURL</key>%n" +
" <string>%s</string>%n" +
" <key>sebServerConfiguration</key>%n" +
" <dict>%n" +
" <key>institution</key>%n" +
" <string>%s</string>%n" +
" <key>clientName</key>%n" +
" <string>%s</string>%n" +
" <key>clientSecret</key>%n" +
" <string>%s</string>%n" +
" <key>apiDiscovery</key>%n" +
" <string>%s</string>%n" +
" </dict>%n" +
" </dict>%n";
private final static String SEB_CLIENT_CONFIG_INTEGER_TEMPLATE =
" <key>%s</key>\r\n" +
" <integer>%s</integer>\r\n";
" <key>%s</key>%n" +
" <integer>%s</integer>%n";
private final static String SEB_CLIENT_CONFIG_STRING_TEMPLATE =
" <key>%s</key>\r\n" +
" <string>%s</string>\r\n";
" <key>%s</key>%n" +
" <string>%s</string>%n";
private final InstitutionDAO institutionDAO;
private final SebClientConfigDAO sebClientConfigDAO;
@ -338,7 +338,7 @@ public class ClientConfigServiceImpl implements ClientConfigService {
String.valueOf(Constants.COLON) +
plainClientSecret;
final String encoded = Base64.getEncoder()
.encodeToString(basicAuth.getBytes());
.encodeToString(basicAuth.getBytes(StandardCharsets.UTF_8));
headers.add(HttpHeaders.AUTHORIZATION, "Basic " + encoded);
final HttpEntity<String> entity = new HttpEntity<>(

View file

@ -1,101 +1,101 @@
/*
* 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.webservice.weblayer.api;
import java.util.Collection;
import java.util.stream.Collectors;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.authorization.Privilege;
import ch.ethz.seb.sebserver.gbl.model.EntityName;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationService;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.InstitutionDAO;
@WebServiceProfile
@RestController
@RequestMapping("${sebserver.webservice.api.admin.endpoint}" + API.INFO_ENDPOINT)
public class InfoController {
private final InstitutionDAO institutionDAO;
private final AuthorizationService authorizationGrantService;
protected InfoController(
final InstitutionDAO institutionDAO,
final AuthorizationService authorizationGrantService) {
this.institutionDAO = institutionDAO;
this.authorizationGrantService = authorizationGrantService;
}
@RequestMapping(
path = API.INSTITUTIONAL_LOGO_PATH,
method = RequestMethod.GET,
produces = MediaType.IMAGE_PNG_VALUE + ";base64")
public String logo(@PathVariable final String urlSuffix) {
if (urlSuffix == null) {
return null;
}
return this.institutionDAO
.all(null, true)
.getOrThrow()
.stream()
.filter(inst -> inst.urlSuffix != null && urlSuffix.equals(inst.urlSuffix))
.findFirst()
.map(inst -> inst.logoImage)
.orElse(null);
}
@RequestMapping(
path = API.INFO_INST_PATH_SEGMENT,
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public Collection<EntityName> getInstitutionInfo() {
return this.institutionDAO
.all(null, true)
.getOrThrow()
.stream()
.filter(inst -> BooleanUtils.isTrue(inst.active))
.map(inst -> new EntityName(inst.getEntityKey(), inst.name))
.collect(Collectors.toList());
}
@RequestMapping(
path = API.INFO_INST_ENDPOINT,
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public Collection<EntityName> getInstitutionInfo(@PathVariable final String urlSuffix) {
return this.institutionDAO
.all(null, true)
.getOrThrow()
.stream()
.filter(inst -> BooleanUtils.isTrue(inst.active) &&
inst.urlSuffix != null &&
urlSuffix.equals(inst.urlSuffix))
.map(inst -> new EntityName(inst.getEntityKey(), inst.name))
.collect(Collectors.toList());
}
@RequestMapping(
path = API.PRIVILEGES_PATH_SEGMENT,
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public Collection<Privilege> privileges() {
return this.authorizationGrantService.getAllPrivileges();
}
}
/*
* 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.webservice.weblayer.api;
import java.util.Collection;
import java.util.stream.Collectors;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.authorization.Privilege;
import ch.ethz.seb.sebserver.gbl.model.EntityName;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationService;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.InstitutionDAO;
@WebServiceProfile
@RestController
@RequestMapping("${sebserver.webservice.api.admin.endpoint}" + API.INFO_ENDPOINT)
public class InfoController {
private final InstitutionDAO institutionDAO;
private final AuthorizationService authorizationGrantService;
protected InfoController(
final InstitutionDAO institutionDAO,
final AuthorizationService authorizationGrantService) {
this.institutionDAO = institutionDAO;
this.authorizationGrantService = authorizationGrantService;
}
@RequestMapping(
path = API.INSTITUTIONAL_LOGO_PATH,
method = RequestMethod.GET,
produces = MediaType.IMAGE_PNG_VALUE + ";base64")
public String logo(@PathVariable final String urlSuffix) {
if (urlSuffix == null) {
return null;
}
return this.institutionDAO
.all(null, true)
.getOrThrow()
.stream()
.filter(inst -> urlSuffix.equals(inst.urlSuffix))
.findFirst()
.map(inst -> inst.logoImage)
.orElse(null);
}
@RequestMapping(
path = API.INFO_INST_PATH_SEGMENT,
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public Collection<EntityName> getInstitutionInfo() {
return this.institutionDAO
.all(null, true)
.getOrThrow()
.stream()
.filter(inst -> BooleanUtils.isTrue(inst.active))
.map(inst -> new EntityName(inst.getEntityKey(), inst.name))
.collect(Collectors.toList());
}
@RequestMapping(
path = API.INFO_INST_ENDPOINT,
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public Collection<EntityName> getInstitutionInfo(@PathVariable final String urlSuffix) {
return this.institutionDAO
.all(null, true)
.getOrThrow()
.stream()
.filter(inst -> BooleanUtils.isTrue(inst.active) &&
inst.urlSuffix != null &&
urlSuffix.equals(inst.urlSuffix))
.map(inst -> new EntityName(inst.getEntityKey(), inst.name))
.collect(Collectors.toList());
}
@RequestMapping(
path = API.PRIVILEGES_PATH_SEGMENT,
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public Collection<Privilege> privileges() {
return this.authorizationGrantService.getAllPrivileges();
}
}