From 977ada8947e5c70df316b232b04b4bcb7cae02d7 Mon Sep 17 00:00:00 2001 From: anhefti Date: Mon, 1 Feb 2021 14:13:44 +0100 Subject: [PATCH] SEBSERV-145 new attributes in Connection Configuration gui and back-end --- .../gbl/model/sebconfig/SEBClientConfig.java | 24 +- .../gui/content/SEBClientConfigForm.java | 488 +++++++++--------- .../sebserver/gui/widget/WidgetFactory.java | 11 + .../impl/ClientConfigServiceImpl.java | 209 +++++--- 4 files changed, 416 insertions(+), 316 deletions(-) diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/SEBClientConfig.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/SEBClientConfig.java index af73c7ed..a65a729b 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/SEBClientConfig.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/SEBClientConfig.java @@ -61,7 +61,7 @@ public final class SEBClientConfig implements GrantEntity, Activatable { "VMware View", "vmware-view.exe", "VMware\\VMware Horizon View Client", - "--LoginAsCurrentUser true\n--serverurl view.example.com\n--desktopLayout fullscreen\n--desktopProtocol PCOIP\n--desktopName \"let-vdi-1-exam"); + "--LoginAsCurrentUser true\n--desktopLayout fullscreen\n--desktopProtocol PCOIP"); public final String title; public final String defaultExecutable; @@ -355,28 +355,6 @@ public final class SEBClientConfig implements GrantEntity, Activatable { return this.active; } -// @Override -// public String toString() { -// final StringBuilder sb = new StringBuilder("SEBClientConfig{"); -// sb.append("id=").append(this.id); -// sb.append(", institutionId=").append(this.institutionId); -// sb.append(", name='").append(this.name).append('\''); -// sb.append(", configPurpose=").append(this.configPurpose); -// sb.append(", fallback=").append(this.fallback); -// sb.append(", fallbackStartURL='").append(this.fallbackStartURL).append('\''); -// sb.append(", fallbackTimeout=").append(this.fallbackTimeout); -// sb.append(", fallbackAttempts=").append(this.fallbackAttempts); -// sb.append(", fallbackAttemptInterval=").append(this.fallbackAttemptInterval); -// sb.append(", fallbackPassword=").append(this.fallbackPassword); -// sb.append(", fallbackPasswordConfirm=").append(this.fallbackPasswordConfirm); -// sb.append(", date=").append(this.date); -// sb.append(", encryptSecret=").append(this.encryptSecret); -// sb.append(", encryptSecretConfirm=").append(this.encryptSecretConfirm); -// sb.append(", active=").append(this.active); -// sb.append('}'); -// return sb.toString(); -// } - @Override public String toString() { final StringBuilder builder = new StringBuilder(); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBClientConfigForm.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBClientConfigForm.java index 8a1a4efe..713012e6 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBClientConfigForm.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/SEBClientConfigForm.java @@ -8,17 +8,17 @@ package ch.ethz.seb.sebserver.gui.content; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; +import java.io.IOException; import org.apache.commons.lang3.BooleanUtils; 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.Button; import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Listener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; @@ -32,7 +32,9 @@ import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig; import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig.VDIType; import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; +import ch.ethz.seb.sebserver.gbl.util.Cryptor; import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; +import ch.ethz.seb.sebserver.gui.form.Form; 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; @@ -51,7 +53,6 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.clientconfig. 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.Selection; import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; @Lazy @@ -59,6 +60,8 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; @GuiProfile public class SEBClientConfigForm implements TemplateComposer { + private static final Logger log = LoggerFactory.getLogger(SEBClientConfigForm.class); + private static final LocTextKey FORM_TITLE_NEW = new LocTextKey("sebserver.clientconfig.form.title.new"); private static final LocTextKey FORM_TITLE = @@ -106,20 +109,6 @@ public class SEBClientConfigForm implements TemplateComposer { private static final LocTextKey FORM_CONFIRM_ENCRYPT_SECRET_TEXT_KEY = new LocTextKey("sebserver.clientconfig.form.encryptSecret.confirm"); - private static final Set VDI_ATTRIBUTES = new HashSet<>(Arrays.asList( - SEBClientConfig.ATTR_VDI_EXECUTABLE, - SEBClientConfig.ATTR_VDI_PATH, - SEBClientConfig.ATTR_VDI_ARGUMENTS)); - private static final Set FALLBACK_ATTRIBUTES = new HashSet<>(Arrays.asList( - SEBClientConfig.ATTR_FALLBACK_START_URL, - SEBClientConfig.ATTR_FALLBACK_ATTEMPT_INTERVAL, - SEBClientConfig.ATTR_FALLBACK_ATTEMPTS, - SEBClientConfig.ATTR_FALLBACK_TIMEOUT, - SEBClientConfig.ATTR_FALLBACK_PASSWORD, - SEBClientConfig.ATTR_FALLBACK_PASSWORD_CONFIRM, - SEBClientConfig.ATTR_QUIT_PASSWORD, - SEBClientConfig.ATTR_QUIT_PASSWORD_CONFIRM)); - private static final String DEFAULT_PING_INTERVAL = String.valueOf(1000); private static final String FALLBACK_DEFAULT_TIME = String.valueOf(30 * Constants.SECOND_IN_MILLIS); private static final String FALLBACK_DEFAULT_ATTEMPTS = String.valueOf(5); @@ -130,14 +119,17 @@ public class SEBClientConfigForm implements TemplateComposer { private final CurrentUser currentUser; private final DownloadService downloadService; private final String downloadFileName; + private final Cryptor cryptor; protected SEBClientConfigForm( final PageService pageService, final DownloadService downloadService, + final Cryptor cryptor, @Value("${sebserver.gui.seb.client.config.download.filename}") final String downloadFileName) { this.pageService = pageService; this.restService = pageService.getRestService(); + this.cryptor = cryptor; this.currentUser = pageService.getCurrentUser(); this.downloadService = downloadService; this.downloadFileName = downloadFileName; @@ -146,7 +138,6 @@ public class SEBClientConfigForm implements TemplateComposer { @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(); @@ -182,220 +173,10 @@ public class SEBClientConfigForm implements TemplateComposer { formContext.getParent(), titleKey); - // The SEBClientConfig form - final FormHandle 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())) + final Composite formContent = widgetFactory.voidComposite(content); - .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_NAME, - FORM_NAME_TEXT_KEY, - clientConfig.name) - .mandatory(!isReadonly)) - - .addField(FormBuilder.singleSelection( - SEBClientConfig.ATTR_CONFIG_PURPOSE, - CLIENT_PURPOSE_TEXT_KEY, - clientConfig.configPurpose != null - ? clientConfig.configPurpose.name() - : SEBClientConfig.ConfigPurpose.START_EXAM.name(), - () -> this.pageService.getResourceService().sebClientConfigPurposeResources()) - .mandatory(!isReadonly)) - - .withDefaultSpanInput(3) - .addField(FormBuilder.password( - Domain.SEB_CLIENT_CONFIGURATION.ATTR_ENCRYPT_SECRET, - FORM_ENCRYPT_SECRET_TEXT_KEY, - clientConfig.getEncryptSecret())) - - .withDefaultSpanEmptyCell(3) - .addFieldIf( - () -> !isReadonly, - () -> FormBuilder.password( - SEBClientConfig.ATTR_ENCRYPT_SECRET_CONFIRM, - FORM_CONFIRM_ENCRYPT_SECRET_TEXT_KEY, - clientConfig.getEncryptSecret())) - - .withDefaultSpanInput(1) - .addField(FormBuilder.text( - SEBClientConfig.ATTR_PING_INTERVAL, - PING_TEXT_KEY, - clientConfig.sebServerPingTime != null - ? String.valueOf(clientConfig.sebServerPingTime) - : DEFAULT_PING_INTERVAL) - .asNumber(this::checkNaturalNumber) - .mandatory(!isReadonly)) - .withDefaultSpanEmptyCell(4) - .withDefaultSpanInput(2) - .addField(FormBuilder.singleSelection( - SEBClientConfig.ATTR_VDI_TYPE, - VDI_TYPE_TEXT_KEY, - clientConfig.vdiType != null - ? clientConfig.vdiType.name() - : SEBClientConfig.VDIType.NO.name(), - () -> this.pageService.getResourceService().vdiTypeResources()) - .mandatory(!isReadonly)) - .withDefaultSpanEmptyCell(3) - .withDefaultSpanInput(3) - .addField(FormBuilder.text( - SEBClientConfig.ATTR_VDI_EXECUTABLE, - VDI_EXEC_TEXT_KEY, - clientConfig.vdiExecutable) - .mandatory(!isReadonly)) - .withDefaultSpanEmptyCell(2) - - .withDefaultSpanInput(4) - .addField(FormBuilder.text( - SEBClientConfig.ATTR_VDI_PATH, - VDI_PATH_TEXT_KEY, - clientConfig.vdiPath) - .mandatory(!isReadonly)) - .withDefaultSpanEmptyCell(1) - - .withDefaultSpanInput(4) - .addField(FormBuilder.text( - SEBClientConfig.ATTR_VDI_ARGUMENTS, - VDI_ARGS_TEXT_KEY, - clientConfig.vdiArguments) - .asArea() - .mandatory(!isReadonly)) - .withDefaultSpanEmptyCell(1) - - .addField(FormBuilder.checkbox( - SEBClientConfig.ATTR_FALLBACK, - FALLBACK_TEXT_KEY, - clientConfig.fallback != null - ? clientConfig.fallback.toString() - : Constants.FALSE_STRING)) - - .withDefaultSpanInput(5) - .addField(FormBuilder.text( - SEBClientConfig.ATTR_FALLBACK_START_URL, - FALLBACK_URL_TEXT_KEY, - clientConfig.fallbackStartURL) - .mandatory(!isReadonly)) - - .withDefaultSpanEmptyCell(1) - .withDefaultSpanInput(2) - .addField(FormBuilder.text( - SEBClientConfig.ATTR_FALLBACK_ATTEMPTS, - FALLBACK_ATTEMPTS_TEXT_KEY, - clientConfig.fallbackAttempts != null - ? String.valueOf(clientConfig.fallbackAttempts) - : FALLBACK_DEFAULT_ATTEMPTS) - .asNumber(this::checkNaturalNumber) - .mandatory(!isReadonly)) - - .withDefaultSpanEmptyCell(0) - .withEmptyCellSeparation(false) - .withDefaultSpanLabel(1) - .addField(FormBuilder.text( - SEBClientConfig.ATTR_FALLBACK_ATTEMPT_INTERVAL, - FALLBACK_ATTEMPT_INTERVAL_TEXT_KEY, - clientConfig.fallbackAttemptInterval != null - ? String.valueOf(clientConfig.fallbackAttemptInterval) - : FALLBACK_DEFAULT_ATTEMPT_INTERVAL) - .asNumber(this::checkNaturalNumber) - .mandatory(!isReadonly)) - - .withEmptyCellSeparation(true) - .withDefaultSpanEmptyCell(1) - .withDefaultSpanLabel(2) - .addField(FormBuilder.text( - SEBClientConfig.ATTR_FALLBACK_TIMEOUT, - FALLBACK_TIMEOUT_TEXT_KEY, - clientConfig.fallbackTimeout != null - ? String.valueOf(clientConfig.fallbackTimeout) - : FALLBACK_DEFAULT_TIME) - .asNumber(this::checkNaturalNumber) - .mandatory(!isReadonly)) - - .withEmptyCellSeparation(true) - .withDefaultSpanEmptyCell(4) - .withDefaultSpanInput(2) - .withDefaultSpanLabel(2) - .addField(FormBuilder.password( - SEBClientConfig.ATTR_FALLBACK_PASSWORD, - FALLBACK_PASSWORD_TEXT_KEY, - clientConfig.getFallbackPassword())) - - .withEmptyCellSeparation(false) - .withDefaultSpanLabel(1) - .addField(FormBuilder.password( - SEBClientConfig.ATTR_QUIT_PASSWORD, - QUIT_PASSWORD_TEXT_KEY, - clientConfig.getQuitPassword())) - - .withEmptyCellSeparation(true) - .withDefaultSpanEmptyCell(1) - .withDefaultSpanInput(2) - .withDefaultSpanLabel(2) - .addFieldIf( - () -> !isReadonly, - () -> FormBuilder.password( - SEBClientConfig.ATTR_FALLBACK_PASSWORD_CONFIRM, - FALLBACK_PASSWORD_CONFIRM_TEXT_KEY, - clientConfig.getFallbackPasswordConfirm())) - - .withEmptyCellSeparation(false) - .withDefaultSpanLabel(1) - .addFieldIf( - () -> !isReadonly, - () -> FormBuilder.password( - SEBClientConfig.ATTR_QUIT_PASSWORD_CONFIRM, - QUIT_PASSWORD_CONFIRM_TEXT_KEY, - clientConfig.getQuitPasswordConfirm())) - - .buildFor((isNew) - ? this.restService.getRestCall(NewClientConfig.class) - : this.restService.getRestCall(SaveClientConfig.class)); - - formHandle.process( - FALLBACK_ATTRIBUTES::contains, - ffa -> ffa.setVisible(BooleanUtils.isTrue(clientConfig.fallback))); - - formHandle.process( - VDI_ATTRIBUTES::contains, - ffa -> ffa.setVisible(BooleanUtils.isTrue(clientConfig.vdiType != VDIType.NO))); - - if (!isReadonly) { - formHandle.getForm().getFieldInput(SEBClientConfig.ATTR_FALLBACK) - .addListener(SWT.Selection, event -> formHandle.process( - FALLBACK_ATTRIBUTES::contains, - ffa -> { - final boolean selected = ((Button) event.widget).getSelection(); - ffa.setVisible(selected); - if (!selected && ffa.hasError()) { - ffa.resetError(); - ffa.setStringValue(StringUtils.EMPTY); - } - })); - formHandle.getForm().getFieldInput(SEBClientConfig.ATTR_VDI_TYPE) - .addListener(SWT.Selection, event -> formHandle.process( - VDI_ATTRIBUTES::contains, - ffa -> { - final boolean show = - !VDIType.NO.name().equals(((Selection) event.widget).getSelectionValue()); - ffa.setVisible(show); - if (!show && ffa.hasError()) { - ffa.resetError(); - ffa.setStringValue(StringUtils.EMPTY); - } - })); - } + final FormHandleAnchor formHandleAnchor = new FormHandleAnchor(); + buildForm(clientConfig, formContext, formContent, formHandleAnchor); final UrlLauncher urlLauncher = RWT.getClient().getService(UrlLauncher.class); this.pageService.pageActionBuilder(formContext.clearEntityKeys()) @@ -432,13 +213,13 @@ public class SEBClientConfigForm implements TemplateComposer { .newAction(ActionDefinition.SEB_CLIENT_CONFIG_SAVE) .withEntityKey(entityKey) - .withExec(formHandle::processFormSave) + .withExec(action -> formHandleAnchor.formHandle.processFormSave(action)) .ignoreMoveAwayFromEdit() .publishIf(() -> !isReadonly) .newAction(ActionDefinition.SEB_CLIENT_CONFIG_SAVE_AND_ACTIVATE) .withEntityKey(entityKey) - .withExec(formHandle::saveAndActivate) + .withExec(action -> formHandleAnchor.formHandle.saveAndActivate(action)) .ignoreMoveAwayFromEdit() .publishIf(() -> !isReadonly && !clientConfig.isActive()) @@ -448,6 +229,237 @@ public class SEBClientConfigForm implements TemplateComposer { .publishIf(() -> !isReadonly); } + private void buildForm( + final SEBClientConfig clientConfig, + final PageContext formContext, + final Composite formContent, + final FormHandleAnchor formHandleAnchor) { + + final I18nSupport i18nSupport = this.pageService.getI18nSupport(); + final boolean isReadonly = formContext.isReadonly(); + final EntityKey entityKey = formContext.getEntityKey(); + final boolean isNew = entityKey == null; + final boolean showVDIAttrs = clientConfig.vdiType == VDIType.VM_WARE; + final boolean showFallbackAttrs = BooleanUtils.isTrue(clientConfig.fallback); + + PageService.clearComposite(formContent); + + final FormBuilder formBuilder = this.pageService.formBuilder( + formContext.copyOf(formContent)) + .readonly(isReadonly) + .putStaticValueIf(() -> !isNew, + Domain.SEB_CLIENT_CONFIGURATION.ATTR_ID, + clientConfig.getModelId()) + .putStaticValue( + Domain.SEB_CLIENT_CONFIGURATION.ATTR_INSTITUTION_ID, + String.valueOf(clientConfig.getInstitutionId())) + + .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_NAME, + FORM_NAME_TEXT_KEY, + clientConfig.name) + .mandatory(!isReadonly)) + + .withDefaultSpanInput(3) + .addField(FormBuilder.singleSelection( + SEBClientConfig.ATTR_CONFIG_PURPOSE, + CLIENT_PURPOSE_TEXT_KEY, + clientConfig.configPurpose != null + ? clientConfig.configPurpose.name() + : SEBClientConfig.ConfigPurpose.START_EXAM.name(), + () -> this.pageService.getResourceService().sebClientConfigPurposeResources()) + .mandatory(!isReadonly)) + .withDefaultSpanEmptyCell(3) + + .withDefaultSpanInput(3) + .addField(FormBuilder.password( + Domain.SEB_CLIENT_CONFIGURATION.ATTR_ENCRYPT_SECRET, + FORM_ENCRYPT_SECRET_TEXT_KEY, + (formHandleAnchor.formHandle == null) + ? clientConfig.getEncryptSecret() + : this.cryptor.encrypt(clientConfig.getEncryptSecret()))) + + .withDefaultSpanEmptyCell(3) + .addFieldIf( + () -> !isReadonly, + () -> FormBuilder.password( + SEBClientConfig.ATTR_ENCRYPT_SECRET_CONFIRM, + FORM_CONFIRM_ENCRYPT_SECRET_TEXT_KEY, + (formHandleAnchor.formHandle == null) + ? clientConfig.getEncryptSecret() + : this.cryptor.encrypt(clientConfig.getEncryptSecretConfirm()))) + + .withDefaultSpanInput(2) + .addField(FormBuilder.text( + SEBClientConfig.ATTR_PING_INTERVAL, + PING_TEXT_KEY, + clientConfig.sebServerPingTime != null + ? String.valueOf(clientConfig.sebServerPingTime) + : DEFAULT_PING_INTERVAL) + .asNumber(this::checkNaturalNumber) + .mandatory(!isReadonly)) + .withDefaultSpanEmptyCell(3) + + // VDI + + .withDefaultSpanInput(2) + .addField(FormBuilder.singleSelection( + SEBClientConfig.ATTR_VDI_TYPE, + VDI_TYPE_TEXT_KEY, + clientConfig.vdiType != null + ? clientConfig.vdiType.name() + : SEBClientConfig.VDIType.NO.name(), + () -> this.pageService.getResourceService().vdiTypeResources()) + .mandatory(!isReadonly)) + .withDefaultSpanEmptyCell(3); + + // VDI Attributes + + if (showVDIAttrs) { + formBuilder.withDefaultSpanInput(2) + .addField(FormBuilder.text( + SEBClientConfig.ATTR_VDI_EXECUTABLE, + VDI_EXEC_TEXT_KEY, + clientConfig.vdiExecutable) + .mandatory(!isReadonly)) + .withDefaultSpanEmptyCell(3) + + .withDefaultSpanInput(4) + .addField(FormBuilder.text( + SEBClientConfig.ATTR_VDI_PATH, + VDI_PATH_TEXT_KEY, + clientConfig.vdiPath) + .mandatory(!isReadonly)) + .withDefaultSpanEmptyCell(1) + + .withDefaultSpanInput(4) + .addField(FormBuilder.text( + SEBClientConfig.ATTR_VDI_ARGUMENTS, + VDI_ARGS_TEXT_KEY, + clientConfig.vdiArguments) + .asArea() + .mandatory(!isReadonly)) + .withDefaultSpanEmptyCell(1); + } + + // Fallback + + formBuilder.addField(FormBuilder.checkbox( + SEBClientConfig.ATTR_FALLBACK, + FALLBACK_TEXT_KEY, + clientConfig.fallback != null + ? clientConfig.fallback.toString() + : Constants.FALSE_STRING)); + + // Fallback Attributes + + if (showFallbackAttrs) { + formBuilder.withDefaultSpanInput(5) + .addField(FormBuilder.text( + SEBClientConfig.ATTR_FALLBACK_START_URL, + FALLBACK_URL_TEXT_KEY, + clientConfig.fallbackStartURL) + .mandatory(!isReadonly)) + + .withDefaultSpanEmptyCell(1) + .withDefaultSpanInput(2) + .addField(FormBuilder.text( + SEBClientConfig.ATTR_FALLBACK_ATTEMPTS, + FALLBACK_ATTEMPTS_TEXT_KEY, + clientConfig.fallbackAttempts != null + ? String.valueOf(clientConfig.fallbackAttempts) + : FALLBACK_DEFAULT_ATTEMPTS) + .asNumber(this::checkNaturalNumber) + .mandatory(!isReadonly)) + + .withDefaultSpanEmptyCell(4) + .addField(FormBuilder.text( + SEBClientConfig.ATTR_FALLBACK_ATTEMPT_INTERVAL, + FALLBACK_ATTEMPT_INTERVAL_TEXT_KEY, + clientConfig.fallbackAttemptInterval != null + ? String.valueOf(clientConfig.fallbackAttemptInterval) + : FALLBACK_DEFAULT_ATTEMPT_INTERVAL) + .asNumber(this::checkNaturalNumber) + .mandatory(!isReadonly)) + + .withDefaultSpanEmptyCell(4) + .withDefaultSpanLabel(2) + .addField(FormBuilder.text( + SEBClientConfig.ATTR_FALLBACK_TIMEOUT, + FALLBACK_TIMEOUT_TEXT_KEY, + clientConfig.fallbackTimeout != null + ? String.valueOf(clientConfig.fallbackTimeout) + : FALLBACK_DEFAULT_TIME) + .asNumber(this::checkNaturalNumber) + .mandatory(!isReadonly)) + + .withDefaultSpanEmptyCell(4) + .withDefaultSpanInput(3) + .withDefaultSpanLabel(2) + .addField(FormBuilder.password( + SEBClientConfig.ATTR_FALLBACK_PASSWORD, + FALLBACK_PASSWORD_TEXT_KEY, + clientConfig.getFallbackPassword())) + .withDefaultSpanEmptyCell(2) + .addFieldIf( + () -> !isReadonly, + () -> FormBuilder.password( + SEBClientConfig.ATTR_FALLBACK_PASSWORD_CONFIRM, + FALLBACK_PASSWORD_CONFIRM_TEXT_KEY, + clientConfig.getFallbackPasswordConfirm())) + + .addField(FormBuilder.password( + SEBClientConfig.ATTR_QUIT_PASSWORD, + QUIT_PASSWORD_TEXT_KEY, + clientConfig.getQuitPassword())) + + .withDefaultSpanEmptyCell(2) + .withDefaultSpanInput(3) + .withDefaultSpanLabel(2) + + .addFieldIf( + () -> !isReadonly, + () -> FormBuilder.password( + SEBClientConfig.ATTR_QUIT_PASSWORD_CONFIRM, + QUIT_PASSWORD_CONFIRM_TEXT_KEY, + clientConfig.getQuitPasswordConfirm())); + } + + formHandleAnchor.formHandle = formBuilder.buildFor((isNew) + ? this.restService.getRestCall(NewClientConfig.class) + : this.restService.getRestCall(SaveClientConfig.class)); + + final Listener selectionListener = event -> { + try { + + final Form formBinding = formHandleAnchor.formHandle.getForm(); + final String formAsJson = formBinding.getFormAsJson(); + final SEBClientConfig newClientConfig = this.pageService.getJSONMapper() + .readValue(formAsJson, SEBClientConfig.class); + buildForm(newClientConfig, formContext, formContent, formHandleAnchor); + } catch (final IOException e) { + log.error("Failed to create new SEBClientConfig from form data: ", e); + } + }; + + if (!isReadonly) { + formHandleAnchor.formHandle.getForm().getFieldInput(SEBClientConfig.ATTR_FALLBACK) + .addListener(SWT.Selection, selectionListener); + formHandleAnchor.formHandle.getForm().getFieldInput(SEBClientConfig.ATTR_VDI_TYPE) + .addListener(SWT.Selection, selectionListener); + } + + formContent.layout(); + PageService.updateScrolledComposite(formContent); + } + private void checkNaturalNumber(final String value) { if (StringUtils.isBlank(value)) { return; @@ -458,4 +470,10 @@ public class SEBClientConfigForm implements TemplateComposer { } } + private static final class FormHandleAnchor { + + FormHandle formHandle; + + } + } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/widget/WidgetFactory.java b/src/main/java/ch/ethz/seb/sebserver/gui/widget/WidgetFactory.java index 685d3612..fb8d8fcc 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/widget/WidgetFactory.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/widget/WidgetFactory.java @@ -230,6 +230,17 @@ public class WidgetFactory { return this.i18nSupport; } + public Composite voidComposite(final Composite parent) { + final Composite content = new Composite(parent, SWT.NONE); + final GridLayout contentLayout = new GridLayout(); + contentLayout.marginLeft = 0; + contentLayout.marginHeight = 0; + content.setLayout(contentLayout); + final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true); + content.setLayoutData(gridData); + return content; + } + public Composite defaultPageLayout(final Composite parent) { final Composite content = new Composite(parent, SWT.NONE); final GridLayout contentLayout = new GridLayout(); diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/ClientConfigServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/ClientConfigServiceImpl.java index b24e3b6a..babbcd63 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/ClientConfigServiceImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/ClientConfigServiceImpl.java @@ -48,6 +48,7 @@ import ch.ethz.seb.sebserver.gbl.client.ClientCredentialService; import ch.ethz.seb.sebserver.gbl.client.ClientCredentials; import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig; import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig.ConfigPurpose; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig.VDIType; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.gbl.util.Utils; @@ -67,38 +68,91 @@ public class ClientConfigServiceImpl implements ClientConfigService { private static final Logger log = LoggerFactory.getLogger(ClientConfigServiceImpl.class); + //@formatter:off private static final String SEB_CLIENT_CONFIG_EXAM_PROP_NAME = "exam"; private static final String SEB_CLIENT_CONFIG_TEMPLATE_XML = " %n" + - " sebMode%n" + - " 1%n" + - " sebConfigPurpose%n" + - " %s%n" + - " sebServerFallback%n" + - " <%s />%n" + - "%s" + - " sebServerURL%n" + - " %s%n" + - " sebServerConfiguration%n" + - " %n" + - " institution%n" + - " %s%n%s" + - " clientName%n" + - " %s%n" + - " clientSecret%n" + - " %s%n" + - " apiDiscovery%n" + - " %s%n" + - " %n" + - " %n"; + " sebMode%n" + + " %s%n" + // sebMode value + " sebConfigPurpose%n" + + " %s%n" + // sebConfigPurpose value + " sebServerFallback%n" + + " <%s />%n" + + "%s" + // fallback addition + " sebServerURL%n" + + " %s%n" + // sebServerURL value + " sebServerConfiguration%n" + + " %n" + + " institution%n" + + " %s%n%s" + // institution value + " clientName%n" + + " %s%n" + // client name value + " clientSecret%n" + + " %s%n" + // client secret value + " apiDiscovery%n" + + " %s%n" + // apiDiscovery value + " %n" + + "%s" + // VDI additions + " %n"; private final static String SEB_CLIENT_CONFIG_INTEGER_TEMPLATE = " %s%n" + - " %s%n"; + " %s%n"; private final static String SEB_CLIENT_CONFIG_STRING_TEMPLATE = " %s%n" + - " %s%n"; + " %s%n"; + + private final static String SEB_CLIENT_CONFIG_VDI_TEMPLATE = + " enableSebBrowser%n" + + " %n" + + " permittedProcesses%n" + + " %n" + + " %n" + + " active%n" + + " %n" + + " allowUserToChooseApp%n" + + " %n" + + " allowedExecutables%n" + + " %n" + + " arguments%n" + + " %n" + + "%s" + // VDI argument additions + " %n" + + " autohide%n" + + " %n" + + " autostart%n" + + " %n" + + " description%n" + + " VDI View%n" + + " executable%n" + + " %s%n" + // VDI executable value + " iconInTaskbar%n" + + " %n" + + " identifier%n" + + " %n" + + " path%n" + + " %s%n" + // VDI path value + " runInBackground%n" + + " %n" + + " strongKill%n" + + " %n" + + " title%n" + + " VDI View%n" + + " windowHandlingProcess%n" + + " " + + ; + + private final static String SEB_CLIENT_CONFIG_VDI_ATTRIBUTE_TEMPLATE = + " %n" + + " active%n "+ + " %n" + + " argument%n" + + " %s%n" + + " "; + + //@formatter:on private final SEBClientConfigDAO sebClientConfigDAO; private final ClientCredentialService clientCredentialService; @@ -221,8 +275,81 @@ public class ClientConfigServiceImpl implements ClientConfigService { private String extractXMLContent(final SEBClientConfig config, final Long examId) { + final String fallbackAddition = getFallbackAddition(config); + final String vdiAddition = getVDIAddition(config); + final boolean hasVDI = config.vdiType != VDIType.NO; + + String examIdAddition = ""; + if (examId != null) { + examIdAddition = String.format( + SEB_CLIENT_CONFIG_STRING_TEMPLATE, + SEB_CLIENT_CONFIG_EXAM_PROP_NAME, + examId); + } + + final ClientCredentials sebClientCredentials = this.sebClientConfigDAO + .getSEBClientCredentials(config.getModelId()) + .getOrThrow(); + final CharSequence plainClientId = sebClientCredentials.clientId; + final CharSequence plainClientSecret = this.clientCredentialService + .getPlainClientSecret(sebClientCredentials); + + final String plainTextConfig = String.format( + SEB_CLIENT_CONFIG_TEMPLATE_XML, + hasVDI ? "1" : "2", + config.configPurpose.ordinal(), + (StringUtils.isNotBlank(config.fallbackStartURL)) + ? "true" + : "false", + fallbackAddition, + this.webserviceInfo.getExternalServerURL(), + config.institutionId, + examIdAddition, + plainClientId, + plainClientSecret, + this.webserviceInfo.getDiscoveryEndpoint(), + vdiAddition); + + if (log.isDebugEnabled()) { + log.debug("SEB client configuration export:\n {}", plainTextConfig); + } + + return plainTextConfig; + } + + private String getVDIAddition(final SEBClientConfig config) { + String vdiAddition = ""; + if (config.vdiType != VDIType.NO) { + vdiAddition = String.format( + SEB_CLIENT_CONFIG_VDI_TEMPLATE, + getVDIArguments(config), + config.vdiExecutable, + config.vdiPath); + } + return vdiAddition; + } + + private String getVDIArguments(final SEBClientConfig config) { + String arguments = ""; + if (StringUtils.isNotBlank(config.vdiArguments)) { + final String[] args = StringUtils.split(config.vdiArguments, "\n"); + for (int i = 0; i < 0; i++) { + arguments += getVDIArgument(args[i]); + } + } + return arguments; + } + + private String getVDIArgument(final String attributeValue) { + return String.format( + SEB_CLIENT_CONFIG_VDI_ATTRIBUTE_TEMPLATE, + attributeValue); + } + + private String getFallbackAddition(final SEBClientConfig config) { String fallbackAddition = ""; if (BooleanUtils.isTrue(config.fallback)) { + fallbackAddition += String.format( SEB_CLIENT_CONFIG_STRING_TEMPLATE, SEBClientConfig.ATTR_FALLBACK_START_URL, @@ -259,41 +386,7 @@ public class ClientConfigServiceImpl implements ClientConfigService { Utils.hash_SHA_256_Base_16(decrypt)); } } - - String examIdAddition = ""; - if (examId != null) { - examIdAddition = String.format( - SEB_CLIENT_CONFIG_STRING_TEMPLATE, - SEB_CLIENT_CONFIG_EXAM_PROP_NAME, - examId); - } - - final ClientCredentials sebClientCredentials = this.sebClientConfigDAO - .getSEBClientCredentials(config.getModelId()) - .getOrThrow(); - final CharSequence plainClientId = sebClientCredentials.clientId; - final CharSequence plainClientSecret = this.clientCredentialService - .getPlainClientSecret(sebClientCredentials); - - final String plainTextConfig = String.format( - SEB_CLIENT_CONFIG_TEMPLATE_XML, - config.configPurpose.ordinal(), - (StringUtils.isNotBlank(config.fallbackStartURL)) - ? "true" - : "false", - fallbackAddition, - this.webserviceInfo.getExternalServerURL(), - config.institutionId, - examIdAddition, - plainClientId, - plainClientSecret, - this.webserviceInfo.getDiscoveryEndpoint()); - - if (log.isDebugEnabled()) { - log.debug("SEB client configuration export:\n {}", plainTextConfig); - } - - return plainTextConfig; + return fallbackAddition; } @Override