registration page
This commit is contained in:
parent
ed8387216b
commit
2f64cf92e0
27 changed files with 615 additions and 31 deletions
|
@ -80,7 +80,9 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter implements E
|
||||||
.ignoring()
|
.ignoring()
|
||||||
.antMatchers("/error")
|
.antMatchers("/error")
|
||||||
.antMatchers(this.examAPIDiscoveryEndpoint)
|
.antMatchers(this.examAPIDiscoveryEndpoint)
|
||||||
.antMatchers(this.adminAPIEndpoint + API.INFO_ENDPOINT + API.LOGO_PATH_SEGMENT + "/**");
|
.antMatchers(this.adminAPIEndpoint + API.INFO_ENDPOINT + API.LOGO_PATH_SEGMENT + "/**")
|
||||||
|
.antMatchers(this.adminAPIEndpoint + API.INFO_ENDPOINT + API.INFO_INST_PATH_SEGMENT + "/**")
|
||||||
|
.antMatchers(this.adminAPIEndpoint + API.REGISTER_ENDPOINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping("/error")
|
@RequestMapping("/error")
|
||||||
|
|
|
@ -23,6 +23,9 @@ import ch.ethz.seb.sebserver.gbl.api.authorization.Privilege;
|
||||||
/** Global Constants used in SEB Server web-service as well as in web-gui component */
|
/** Global Constants used in SEB Server web-service as well as in web-gui component */
|
||||||
public final class Constants {
|
public final class Constants {
|
||||||
|
|
||||||
|
public static final String DEFAULT_LANG_CODE = "en";
|
||||||
|
public static final String DEFAULT_TIME_ZONE_CODE = "UTC";
|
||||||
|
|
||||||
public static final int SEB_FILE_HEADER_SIZE = 4;
|
public static final int SEB_FILE_HEADER_SIZE = 4;
|
||||||
public static final int JN_CRYPTOR_ITERATIONS = 10000;
|
public static final int JN_CRYPTOR_ITERATIONS = 10000;
|
||||||
public static final int JN_CRYPTOR_VERSION_HEADER_SIZE = 1;
|
public static final int JN_CRYPTOR_VERSION_HEADER_SIZE = 1;
|
||||||
|
|
|
@ -46,8 +46,13 @@ public final class API {
|
||||||
public static final String SELF_PATH_SEGMENT = "/self";
|
public static final String SELF_PATH_SEGMENT = "/self";
|
||||||
|
|
||||||
public static final String INFO_ENDPOINT = "/info";
|
public static final String INFO_ENDPOINT = "/info";
|
||||||
|
public static final String INFO_PARAM_INST_SUFFIX = "urlSuffix";
|
||||||
|
public static final String INFO_INST_PATH_SEGMENT = "/institution";
|
||||||
|
public static final String INFO_INST_ENDPOINT = INFO_INST_PATH_SEGMENT + "/{" + INFO_PARAM_INST_SUFFIX + "}";
|
||||||
public static final String LOGO_PATH_SEGMENT = "/logo";
|
public static final String LOGO_PATH_SEGMENT = "/logo";
|
||||||
public static final String INSTITUTIONAL_LOGO_PATH = LOGO_PATH_SEGMENT + "/{urlSuffix}";
|
|
||||||
|
public static final String INSTITUTIONAL_LOGO_PATH = LOGO_PATH_SEGMENT + "/{" + INFO_PARAM_INST_SUFFIX + "}";
|
||||||
|
public static final String REGISTER_ENDPOINT = "/register";
|
||||||
|
|
||||||
public static final String NAMES_PATH_SEGMENT = "/names";
|
public static final String NAMES_PATH_SEGMENT = "/names";
|
||||||
|
|
||||||
|
|
|
@ -436,6 +436,10 @@ public final class Utils {
|
||||||
return toCharArray(CharBuffer.wrap(chars));
|
return toCharArray(CharBuffer.wrap(chars));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void clear(final CharSequence charSequence) {
|
||||||
|
clearCharArray(toCharArray(charSequence));
|
||||||
|
}
|
||||||
|
|
||||||
public static String toString(final CharSequence charSequence) {
|
public static String toString(final CharSequence charSequence) {
|
||||||
if (charSequence == null) {
|
if (charSequence == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -38,8 +38,6 @@ public class GuiWebsecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
public static final RequestMatcher PUBLIC_URLS = new OrRequestMatcher(
|
public static final RequestMatcher PUBLIC_URLS = new OrRequestMatcher(
|
||||||
// OAuth entry-points
|
// OAuth entry-points
|
||||||
new AntPathRequestMatcher(API.OAUTH_REVOKE_TOKEN_ENDPOINT),
|
new AntPathRequestMatcher(API.OAUTH_REVOKE_TOKEN_ENDPOINT),
|
||||||
// GUI entry-point
|
|
||||||
// new AntPathRequestMatcher(guiEntryPoint),
|
|
||||||
// RAP/RWT resources has to be accessible
|
// RAP/RWT resources has to be accessible
|
||||||
new AntPathRequestMatcher("/rwt-resources/**"),
|
new AntPathRequestMatcher("/rwt-resources/**"),
|
||||||
// project specific static resources
|
// project specific static resources
|
||||||
|
|
|
@ -20,6 +20,7 @@ import javax.servlet.http.HttpServletResponse;
|
||||||
import org.apache.commons.codec.Charsets;
|
import org.apache.commons.codec.Charsets;
|
||||||
import org.apache.commons.codec.binary.Base64InputStream;
|
import org.apache.commons.codec.binary.Base64InputStream;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.eclipse.rap.rwt.RWT;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
@ -40,12 +41,16 @@ import org.springframework.web.client.RestTemplate;
|
||||||
import ch.ethz.seb.sebserver.ClientHttpRequestFactoryService;
|
import ch.ethz.seb.sebserver.ClientHttpRequestFactoryService;
|
||||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.WebserviceURIService;
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.WebserviceURIService;
|
||||||
import ch.ethz.seb.sebserver.gui.widget.ImageUploadSelection;
|
import ch.ethz.seb.sebserver.gui.widget.ImageUploadSelection;
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
@Component
|
@Component
|
||||||
final class InstitutionalAuthenticationEntryPoint implements AuthenticationEntryPoint {
|
@GuiProfile
|
||||||
|
public final class InstitutionalAuthenticationEntryPoint implements AuthenticationEntryPoint {
|
||||||
|
|
||||||
|
private static final String INST_SUFFIX_ATTRIBUTE = "instSuffix";
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(InstitutionalAuthenticationEntryPoint.class);
|
private static final Logger log = LoggerFactory.getLogger(InstitutionalAuthenticationEntryPoint.class);
|
||||||
|
|
||||||
|
@ -111,7 +116,7 @@ final class InstitutionalAuthenticationEntryPoint implements AuthenticationEntry
|
||||||
final String logoImageBase64 = requestLogoImage(institutionalEndpoint);
|
final String logoImageBase64 = requestLogoImage(institutionalEndpoint);
|
||||||
if (StringUtils.isNotBlank(logoImageBase64)) {
|
if (StringUtils.isNotBlank(logoImageBase64)) {
|
||||||
request.getSession().setAttribute(API.PARAM_LOGO_IMAGE, logoImageBase64);
|
request.getSession().setAttribute(API.PARAM_LOGO_IMAGE, logoImageBase64);
|
||||||
request.getSession().setAttribute("themeId", "sms");
|
request.getSession().setAttribute(INST_SUFFIX_ATTRIBUTE, institutionalEndpoint);
|
||||||
forwardToEntryPoint(request, response, this.guiEntryPoint);
|
forwardToEntryPoint(request, response, this.guiEntryPoint);
|
||||||
} else {
|
} else {
|
||||||
request.getSession().removeAttribute(API.PARAM_LOGO_IMAGE);
|
request.getSession().removeAttribute(API.PARAM_LOGO_IMAGE);
|
||||||
|
@ -132,19 +137,31 @@ final class InstitutionalAuthenticationEntryPoint implements AuthenticationEntry
|
||||||
dispatcher.forward(request, response);
|
dispatcher.forward(request, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String extractInstitutionalEndpoint(final HttpServletRequest request) {
|
public static String extractInstitutionalEndpoint(final HttpServletRequest request) {
|
||||||
final String requestURI = request.getRequestURI();
|
final String requestURI = request.getRequestURI();
|
||||||
|
|
||||||
if (log.isDebugEnabled()) {
|
if (log.isDebugEnabled()) {
|
||||||
log.debug("Trying to verify insitution from requested entrypoint url: {}", requestURI);
|
log.debug("Trying to verify insitution from requested entrypoint url: {}", requestURI);
|
||||||
}
|
}
|
||||||
|
|
||||||
final String instPrefix = requestURI.replaceAll("/", "");
|
try {
|
||||||
if (StringUtils.isBlank(instPrefix)) {
|
return requestURI.substring(
|
||||||
|
requestURI.lastIndexOf(Constants.SLASH) + 1,
|
||||||
|
requestURI.length());
|
||||||
|
} catch (final Exception e) {
|
||||||
|
log.error("Fauled to extract institutional URL suffix: {}", e.getMessage());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return instPrefix;
|
public static String extractInstitutionalEndpoint() {
|
||||||
|
try {
|
||||||
|
final Object attribute = RWT.getUISession().getHttpSession().getAttribute(INST_SUFFIX_ATTRIBUTE);
|
||||||
|
return (attribute != null) ? String.valueOf(attribute) : null;
|
||||||
|
} catch (final Exception e) {
|
||||||
|
log.warn("Failed to extract institutional endpoint form user session: {}", e.getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String requestLogoImage(final String institutionalEndpoint) {
|
private String requestLogoImage(final String institutionalEndpoint) {
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.gui.content;
|
package ch.ethz.seb.sebserver.gui.content;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.eclipse.rap.rwt.RWT;
|
import org.eclipse.rap.rwt.RWT;
|
||||||
import org.eclipse.swt.SWT;
|
import org.eclipse.swt.SWT;
|
||||||
|
@ -20,6 +21,7 @@ import org.eclipse.swt.widgets.MessageBox;
|
||||||
import org.eclipse.swt.widgets.Text;
|
import org.eclipse.swt.widgets.Text;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@ -28,6 +30,7 @@ import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||||
|
import ch.ethz.seb.sebserver.gui.service.page.impl.DefaultRegisterPage;
|
||||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder;
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder;
|
||||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.SEBServerAuthorizationContext;
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.SEBServerAuthorizationContext;
|
||||||
import ch.ethz.seb.sebserver.gui.widget.Message;
|
import ch.ethz.seb.sebserver.gui.widget.Message;
|
||||||
|
@ -44,12 +47,20 @@ public class LoginPage implements TemplateComposer {
|
||||||
private final AuthorizationContextHolder authorizationContextHolder;
|
private final AuthorizationContextHolder authorizationContextHolder;
|
||||||
private final WidgetFactory widgetFactory;
|
private final WidgetFactory widgetFactory;
|
||||||
private final I18nSupport i18nSupport;
|
private final I18nSupport i18nSupport;
|
||||||
|
private final DefaultRegisterPage defaultRegisterPage;
|
||||||
|
private final boolean registreringEnabled;
|
||||||
|
|
||||||
|
public LoginPage(
|
||||||
|
final PageService pageService,
|
||||||
|
final DefaultRegisterPage defaultRegisterPage,
|
||||||
|
@Value("${sebserver.gui.self-registering:false}") final Boolean registreringEnabled) {
|
||||||
|
|
||||||
public LoginPage(final PageService pageService) {
|
|
||||||
this.pageService = pageService;
|
this.pageService = pageService;
|
||||||
this.authorizationContextHolder = pageService.getAuthorizationContextHolder();
|
this.authorizationContextHolder = pageService.getAuthorizationContextHolder();
|
||||||
this.widgetFactory = pageService.getWidgetFactory();
|
this.widgetFactory = pageService.getWidgetFactory();
|
||||||
this.i18nSupport = pageService.getI18nSupport();
|
this.i18nSupport = pageService.getI18nSupport();
|
||||||
|
this.defaultRegisterPage = defaultRegisterPage;
|
||||||
|
this.registreringEnabled = BooleanUtils.toBoolean(registreringEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -61,7 +72,7 @@ public class LoginPage implements TemplateComposer {
|
||||||
rowLayout.marginWidth = 20;
|
rowLayout.marginWidth = 20;
|
||||||
rowLayout.marginRight = 100;
|
rowLayout.marginRight = 100;
|
||||||
loginGroup.setLayout(rowLayout);
|
loginGroup.setLayout(rowLayout);
|
||||||
loginGroup.setData(RWT.CUSTOM_VARIANT, "login");
|
loginGroup.setData(RWT.CUSTOM_VARIANT, WidgetFactory.CustomVariant.LOGIN.key);
|
||||||
|
|
||||||
final Label name = this.widgetFactory.labelLocalized(loginGroup, "sebserver.login.username");
|
final Label name = this.widgetFactory.labelLocalized(loginGroup, "sebserver.login.username");
|
||||||
name.setLayoutData(new GridData(300, -1));
|
name.setLayoutData(new GridData(300, -1));
|
||||||
|
@ -75,15 +86,19 @@ public class LoginPage implements TemplateComposer {
|
||||||
final Text loginPassword = this.widgetFactory.passwordInput(loginGroup);
|
final Text loginPassword = this.widgetFactory.passwordInput(loginGroup);
|
||||||
loginPassword.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
|
loginPassword.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
|
||||||
|
|
||||||
final Button button = this.widgetFactory.buttonLocalized(loginGroup, "sebserver.login.login");
|
|
||||||
gridData = new GridData(SWT.LEFT, SWT.TOP, false, false);
|
|
||||||
gridData.verticalIndent = 10;
|
|
||||||
button.setLayoutData(gridData);
|
|
||||||
|
|
||||||
final SEBServerAuthorizationContext authorizationContext = this.authorizationContextHolder
|
final SEBServerAuthorizationContext authorizationContext = this.authorizationContextHolder
|
||||||
.getAuthorizationContext(RWT.getUISession().getHttpSession());
|
.getAuthorizationContext(RWT.getUISession().getHttpSession());
|
||||||
|
|
||||||
button.addListener(SWT.Selection, event -> {
|
final Composite buttons = new Composite(loginGroup, SWT.NONE);
|
||||||
|
buttons.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
|
||||||
|
buttons.setLayout(new GridLayout(2, false));
|
||||||
|
buttons.setData(RWT.CUSTOM_VARIANT, WidgetFactory.CustomVariant.LOGIN_BACK.key);
|
||||||
|
|
||||||
|
final Button loginButton = this.widgetFactory.buttonLocalized(buttons, "sebserver.login.login");
|
||||||
|
gridData = new GridData(SWT.LEFT, SWT.TOP, false, false);
|
||||||
|
gridData.verticalIndent = 10;
|
||||||
|
loginButton.setLayoutData(gridData);
|
||||||
|
loginButton.addListener(SWT.Selection, event -> {
|
||||||
login(
|
login(
|
||||||
pageContext,
|
pageContext,
|
||||||
loginName.getText(),
|
loginName.getText(),
|
||||||
|
@ -117,6 +132,15 @@ public class LoginPage implements TemplateComposer {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (this.registreringEnabled) {
|
||||||
|
final Button registerButton = this.widgetFactory.buttonLocalized(buttons, "sebserver.login.register");
|
||||||
|
gridData = new GridData(SWT.LEFT, SWT.TOP, false, false);
|
||||||
|
gridData.verticalIndent = 10;
|
||||||
|
registerButton.setLayoutData(gridData);
|
||||||
|
registerButton.addListener(SWT.Selection, event -> {
|
||||||
|
pageContext.forwardToPage(this.defaultRegisterPage);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void login(
|
private void login(
|
||||||
|
|
|
@ -0,0 +1,204 @@
|
||||||
|
/*
|
||||||
|
* 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 java.util.List;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
|
import org.eclipse.rap.rwt.RWT;
|
||||||
|
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.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.ClientHttpRequestFactoryService;
|
||||||
|
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.EntityName;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.user.PasswordChange;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
||||||
|
import ch.ethz.seb.sebserver.gui.InstitutionalAuthenticationEntryPoint;
|
||||||
|
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.TemplateComposer;
|
||||||
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitutionInfo;
|
||||||
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.WebserviceURIService;
|
||||||
|
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
@Component
|
||||||
|
@GuiProfile
|
||||||
|
public class RegisterPage implements TemplateComposer {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(RegisterPage.class);
|
||||||
|
|
||||||
|
static final LocTextKey TITLE_TEXT_KEY =
|
||||||
|
new LocTextKey("sebserver.login.register.form.title");
|
||||||
|
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_INSTITUTION_TEXT_KEY =
|
||||||
|
new LocTextKey("sebserver.useraccount.form.institution");
|
||||||
|
static final LocTextKey FORM_LANG_TEXT_KEY =
|
||||||
|
new LocTextKey("sebserver.useraccount.form.language");
|
||||||
|
|
||||||
|
private final PageService pageService;
|
||||||
|
private final ResourceService resourceService;
|
||||||
|
private final WidgetFactory widgetFactory;
|
||||||
|
private final I18nSupport i18nSupport;
|
||||||
|
private final WebserviceURIService webserviceURIService;
|
||||||
|
private final RestTemplate restTemplate;
|
||||||
|
private final boolean multilingual;
|
||||||
|
|
||||||
|
protected RegisterPage(
|
||||||
|
final PageService pageService,
|
||||||
|
final WebserviceURIService webserviceURIService,
|
||||||
|
final ClientHttpRequestFactoryService clientHttpRequestFactoryService,
|
||||||
|
@Value("${sebserver.gui.multilingual:false}") final Boolean multilingual) {
|
||||||
|
|
||||||
|
this.pageService = pageService;
|
||||||
|
this.resourceService = pageService.getResourceService();
|
||||||
|
this.widgetFactory = pageService.getWidgetFactory();
|
||||||
|
this.i18nSupport = pageService.getI18nSupport();
|
||||||
|
this.webserviceURIService = webserviceURIService;
|
||||||
|
this.multilingual = BooleanUtils.toBoolean(multilingual);
|
||||||
|
|
||||||
|
this.restTemplate = new RestTemplate();
|
||||||
|
|
||||||
|
final ClientHttpRequestFactory clientHttpRequestFactory = clientHttpRequestFactoryService
|
||||||
|
.getClientHttpRequestFactory()
|
||||||
|
.getOrThrow();
|
||||||
|
|
||||||
|
this.restTemplate.setRequestFactory(clientHttpRequestFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void compose(final PageContext pageContext) {
|
||||||
|
|
||||||
|
final String institutionId = InstitutionalAuthenticationEntryPoint
|
||||||
|
.extractInstitutionalEndpoint();
|
||||||
|
|
||||||
|
final List<EntityName> institutions = this.pageService
|
||||||
|
.getRestService()
|
||||||
|
.getBuilder(GetInstitutionInfo.class)
|
||||||
|
.withRestTemplate(this.restTemplate)
|
||||||
|
.withURIVariable(API.INFO_PARAM_INST_SUFFIX, institutionId)
|
||||||
|
.call()
|
||||||
|
.getOrThrow();
|
||||||
|
|
||||||
|
final boolean definedInstitution = institutions.size() == 1;
|
||||||
|
final Supplier<List<Tuple<String>>> instResources = () -> institutions
|
||||||
|
.stream()
|
||||||
|
.map(entityName -> new Tuple<>(entityName.modelId, entityName.name))
|
||||||
|
.sorted(ResourceService.RESOURCE_COMPARATOR)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
final Composite content = this.widgetFactory.defaultPageLayout(
|
||||||
|
pageContext.getParent(),
|
||||||
|
TITLE_TEXT_KEY);
|
||||||
|
content.setData(RWT.CUSTOM_VARIANT, WidgetFactory.CustomVariant.LOGIN.key);
|
||||||
|
|
||||||
|
// The UserAccount form
|
||||||
|
final FormBuilder formBuilder = this.pageService.formBuilder(
|
||||||
|
pageContext.copyOf(content))
|
||||||
|
.readonly(false)
|
||||||
|
.putStaticValueIf(
|
||||||
|
() -> !this.multilingual,
|
||||||
|
Domain.USER.ATTR_LANGUAGE,
|
||||||
|
"en")
|
||||||
|
.addField(FormBuilder.singleSelection(
|
||||||
|
Domain.USER.ATTR_INSTITUTION_ID,
|
||||||
|
FORM_INSTITUTION_TEXT_KEY,
|
||||||
|
(definedInstitution) ? institutions.get(0).modelId : null,
|
||||||
|
instResources)
|
||||||
|
.readonly(definedInstitution))
|
||||||
|
.addField(FormBuilder.text(
|
||||||
|
Domain.USER.ATTR_NAME,
|
||||||
|
FORM_NAME_TEXT_KEY))
|
||||||
|
.addField(FormBuilder.text(
|
||||||
|
Domain.USER.ATTR_USERNAME,
|
||||||
|
FORM_USERNAME_TEXT_KEY))
|
||||||
|
.addField(FormBuilder.text(
|
||||||
|
Domain.USER.ATTR_EMAIL,
|
||||||
|
FORM_MAIL_TEXT_KEY))
|
||||||
|
.addFieldIf(
|
||||||
|
() -> this.multilingual,
|
||||||
|
() -> FormBuilder.singleSelection(
|
||||||
|
Domain.USER.ATTR_LANGUAGE,
|
||||||
|
FORM_LANG_TEXT_KEY,
|
||||||
|
Constants.DEFAULT_LANG_CODE,
|
||||||
|
this.resourceService::languageResources))
|
||||||
|
.addField(FormBuilder.singleSelection(
|
||||||
|
Domain.USER.ATTR_TIMEZONE,
|
||||||
|
FORM_TIMEZONE_TEXT_KEY,
|
||||||
|
Constants.DEFAULT_TIME_ZONE_CODE,
|
||||||
|
this.resourceService::timeZoneResources))
|
||||||
|
.addField(FormBuilder.text(
|
||||||
|
PasswordChange.ATTR_NAME_NEW_PASSWORD,
|
||||||
|
FORM_PASSWORD_TEXT_KEY)
|
||||||
|
.asPasswordField())
|
||||||
|
.addField(FormBuilder.text(
|
||||||
|
PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD,
|
||||||
|
FORM_PASSWORD_CONFIRM_TEXT_KEY)
|
||||||
|
.asPasswordField());
|
||||||
|
|
||||||
|
//formBuilder.formParent.setData(RWT.CUSTOM_VARIANT, WidgetFactory.CustomVariant.LOGIN_BACK.key);
|
||||||
|
formBuilder.build();
|
||||||
|
|
||||||
|
final Composite buttons = new Composite(content, SWT.NONE);
|
||||||
|
buttons.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
|
||||||
|
buttons.setLayout(new GridLayout(2, false));
|
||||||
|
buttons.setData(RWT.CUSTOM_VARIANT, WidgetFactory.CustomVariant.LOGIN_BACK.key);
|
||||||
|
|
||||||
|
final Button registerButton = this.widgetFactory.buttonLocalized(buttons, "sebserver.login.register");
|
||||||
|
GridData gridData = new GridData(SWT.LEFT, SWT.TOP, false, false);
|
||||||
|
gridData.verticalIndent = 10;
|
||||||
|
registerButton.setLayoutData(gridData);
|
||||||
|
registerButton.addListener(SWT.Selection, event -> {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
final Button cancelButton = this.widgetFactory.buttonLocalized(buttons, "sebserver.overall.action.cancel");
|
||||||
|
gridData = new GridData(SWT.LEFT, SWT.TOP, false, false);
|
||||||
|
gridData.verticalIndent = 10;
|
||||||
|
cancelButton.setLayoutData(gridData);
|
||||||
|
cancelButton.addListener(SWT.Selection, event -> {
|
||||||
|
pageContext.forwardToLoginPage();
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -10,8 +10,10 @@ package ch.ethz.seb.sebserver.gui.content;
|
||||||
|
|
||||||
import java.util.function.BooleanSupplier;
|
import java.util.function.BooleanSupplier;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
import org.apache.tomcat.util.buf.StringUtils;
|
import org.apache.tomcat.util.buf.StringUtils;
|
||||||
import org.eclipse.swt.widgets.Composite;
|
import org.eclipse.swt.widgets.Composite;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@ -74,16 +76,21 @@ public class UserAccountForm implements TemplateComposer {
|
||||||
new LocTextKey("sebserver.useraccount.form.name");
|
new LocTextKey("sebserver.useraccount.form.name");
|
||||||
static final LocTextKey FORM_INSTITUTION_TEXT_KEY =
|
static final LocTextKey FORM_INSTITUTION_TEXT_KEY =
|
||||||
new LocTextKey("sebserver.useraccount.form.institution");
|
new LocTextKey("sebserver.useraccount.form.institution");
|
||||||
|
static final LocTextKey FORM_LANG_TEXT_KEY =
|
||||||
|
new LocTextKey("sebserver.useraccount.form.language");
|
||||||
|
|
||||||
private final PageService pageService;
|
private final PageService pageService;
|
||||||
private final ResourceService resourceService;
|
private final ResourceService resourceService;
|
||||||
|
private final boolean multilingual;
|
||||||
|
|
||||||
protected UserAccountForm(
|
protected UserAccountForm(
|
||||||
final PageService pageService,
|
final PageService pageService,
|
||||||
final ResourceService resourceService) {
|
final ResourceService resourceService,
|
||||||
|
@Value("${sebserver.gui.multilingual:false}") final Boolean multilingual) {
|
||||||
|
|
||||||
this.pageService = pageService;
|
this.pageService = pageService;
|
||||||
this.resourceService = resourceService;
|
this.resourceService = resourceService;
|
||||||
|
this.multilingual = BooleanUtils.toBoolean(multilingual);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -149,7 +156,8 @@ public class UserAccountForm implements TemplateComposer {
|
||||||
.putStaticValueIf(isNotNew,
|
.putStaticValueIf(isNotNew,
|
||||||
Domain.USER.ATTR_INSTITUTION_ID,
|
Domain.USER.ATTR_INSTITUTION_ID,
|
||||||
String.valueOf(userAccount.getInstitutionId()))
|
String.valueOf(userAccount.getInstitutionId()))
|
||||||
.putStaticValue(
|
.putStaticValueIf(
|
||||||
|
() -> !this.multilingual,
|
||||||
Domain.USER.ATTR_LANGUAGE,
|
Domain.USER.ATTR_LANGUAGE,
|
||||||
"en")
|
"en")
|
||||||
.addFieldIf(
|
.addFieldIf(
|
||||||
|
@ -172,12 +180,13 @@ public class UserAccountForm implements TemplateComposer {
|
||||||
Domain.USER.ATTR_EMAIL,
|
Domain.USER.ATTR_EMAIL,
|
||||||
FORM_MAIL_TEXT_KEY,
|
FORM_MAIL_TEXT_KEY,
|
||||||
userAccount.getEmail()))
|
userAccount.getEmail()))
|
||||||
// .addField(FormBuilder.singleSelection(
|
.addFieldIf(
|
||||||
// Domain.USER.ATTR_LANGUAGE,
|
() -> this.multilingual,
|
||||||
// "sebserver.useraccount.form.language",
|
() -> FormBuilder.singleSelection(
|
||||||
// userAccount.getLanguage().getLanguage(),
|
Domain.USER.ATTR_LANGUAGE,
|
||||||
// this.resourceService::languageResources)
|
FORM_LANG_TEXT_KEY,
|
||||||
// .readonly(true))
|
userAccount.getLanguage().getLanguage(),
|
||||||
|
this.resourceService::languageResources))
|
||||||
.addField(FormBuilder.singleSelection(
|
.addField(FormBuilder.singleSelection(
|
||||||
Domain.USER.ATTR_TIMEZONE,
|
Domain.USER.ATTR_TIMEZONE,
|
||||||
FORM_TIMEZONE_TEXT_KEY,
|
FORM_TIMEZONE_TEXT_KEY,
|
||||||
|
|
|
@ -11,6 +11,7 @@ package ch.ethz.seb.sebserver.gui.service.page.impl;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||||
import ch.ethz.seb.sebserver.gui.content.LoginPage;
|
import ch.ethz.seb.sebserver.gui.content.LoginPage;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
|
import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
|
||||||
|
@ -21,6 +22,7 @@ import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||||
* SEBLogin template */
|
* SEBLogin template */
|
||||||
@Lazy
|
@Lazy
|
||||||
@Component
|
@Component
|
||||||
|
@GuiProfile
|
||||||
public class DefaultLoginPage implements PageDefinition {
|
public class DefaultLoginPage implements PageDefinition {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -11,6 +11,7 @@ package ch.ethz.seb.sebserver.gui.service.page.impl;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||||
import ch.ethz.seb.sebserver.gui.content.MainPage;
|
import ch.ethz.seb.sebserver.gui.content.MainPage;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
|
import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
|
||||||
|
@ -21,6 +22,7 @@ import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||||
* SEBMainPage template */
|
* SEBMainPage template */
|
||||||
@Lazy
|
@Lazy
|
||||||
@Component
|
@Component
|
||||||
|
@GuiProfile
|
||||||
public class DefaultMainPage implements PageDefinition {
|
public class DefaultMainPage implements PageDefinition {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* 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.service.page.impl;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||||
|
import ch.ethz.seb.sebserver.gui.content.RegisterPage;
|
||||||
|
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||||
|
import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
|
||||||
|
import ch.ethz.seb.sebserver.gui.service.page.PageDefinition;
|
||||||
|
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
@Component
|
||||||
|
@GuiProfile
|
||||||
|
public class DefaultRegisterPage implements PageDefinition {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends TemplateComposer> composer() {
|
||||||
|
return DefaultPageLayout.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageContext applyPageContext(final PageContext pageContext) {
|
||||||
|
return pageContext.withAttribute(
|
||||||
|
AttributeKeys.PAGE_TEMPLATE_COMPOSER_NAME,
|
||||||
|
RegisterPage.class.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -59,6 +59,7 @@ public abstract class RestCall<T> {
|
||||||
GET_DEPENDENCIES,
|
GET_DEPENDENCIES,
|
||||||
GET_LIST,
|
GET_LIST,
|
||||||
NEW,
|
NEW,
|
||||||
|
REGISTER,
|
||||||
SAVE,
|
SAVE,
|
||||||
DELETE,
|
DELETE,
|
||||||
ACTIVATION_ACTIVATE,
|
ACTIVATION_ACTIVATE,
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* 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.service.remote.webservice.api.institution;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.EntityName;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||||
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
@Component
|
||||||
|
@GuiProfile
|
||||||
|
public class GetInstitutionInfo extends RestCall<List<EntityName>> {
|
||||||
|
|
||||||
|
public GetInstitutionInfo() {
|
||||||
|
super(new TypeKey<>(
|
||||||
|
CallType.GET_NAMES,
|
||||||
|
EntityType.INSTITUTION,
|
||||||
|
new TypeReference<List<EntityName>>() {
|
||||||
|
}),
|
||||||
|
HttpMethod.GET,
|
||||||
|
MediaType.APPLICATION_FORM_URLENCODED,
|
||||||
|
API.INFO_ENDPOINT + API.INFO_INST_ENDPOINT);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* 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.service.remote.webservice.api.useraccount;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||||
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
@Component
|
||||||
|
@GuiProfile
|
||||||
|
public class RegisterNewUser extends RestCall<UserInfo> {
|
||||||
|
|
||||||
|
public RegisterNewUser() {
|
||||||
|
super(new TypeKey<>(
|
||||||
|
CallType.REGISTER,
|
||||||
|
EntityType.USER,
|
||||||
|
new TypeReference<UserInfo>() {
|
||||||
|
}),
|
||||||
|
HttpMethod.POST,
|
||||||
|
MediaType.APPLICATION_FORM_URLENCODED,
|
||||||
|
API.REGISTER_ENDPOINT);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -19,6 +19,7 @@ import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||||
@GuiProfile
|
@GuiProfile
|
||||||
public class WebserviceURIService {
|
public class WebserviceURIService {
|
||||||
|
|
||||||
|
private final String servletContextPath;
|
||||||
private final String webserviceServerAddress;
|
private final String webserviceServerAddress;
|
||||||
private final UriComponentsBuilder webserviceURIBuilder;
|
private final UriComponentsBuilder webserviceURIBuilder;
|
||||||
|
|
||||||
|
@ -26,12 +27,15 @@ public class WebserviceURIService {
|
||||||
@Value("${sebserver.gui.webservice.protocol}") final String webserviceProtocol,
|
@Value("${sebserver.gui.webservice.protocol}") final String webserviceProtocol,
|
||||||
@Value("${sebserver.gui.webservice.address}") final String webserviceServerAdress,
|
@Value("${sebserver.gui.webservice.address}") final String webserviceServerAdress,
|
||||||
@Value("${sebserver.gui.webservice.port}") final String webserviceServerPort,
|
@Value("${sebserver.gui.webservice.port}") final String webserviceServerPort,
|
||||||
|
@Value("${server.servlet.context-path}") final String servletContextPath,
|
||||||
@Value("${sebserver.gui.webservice.apipath}") final String webserviceAPIPath) {
|
@Value("${sebserver.gui.webservice.apipath}") final String webserviceAPIPath) {
|
||||||
|
|
||||||
|
this.servletContextPath = servletContextPath;
|
||||||
this.webserviceServerAddress = webserviceProtocol + "://" + webserviceServerAdress + ":" + webserviceServerPort;
|
this.webserviceServerAddress = webserviceProtocol + "://" + webserviceServerAdress + ":" + webserviceServerPort;
|
||||||
this.webserviceURIBuilder = UriComponentsBuilder
|
this.webserviceURIBuilder = UriComponentsBuilder
|
||||||
.fromHttpUrl(webserviceProtocol + "://" + webserviceServerAdress)
|
.fromHttpUrl(webserviceProtocol + "://" + webserviceServerAdress)
|
||||||
.port(webserviceServerPort)
|
.port(webserviceServerPort)
|
||||||
|
.path(servletContextPath)
|
||||||
.path(webserviceAPIPath);
|
.path(webserviceAPIPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,12 +49,14 @@ public class WebserviceURIService {
|
||||||
|
|
||||||
public String getOAuthTokenURI() {
|
public String getOAuthTokenURI() {
|
||||||
return UriComponentsBuilder.fromHttpUrl(this.webserviceServerAddress)
|
return UriComponentsBuilder.fromHttpUrl(this.webserviceServerAddress)
|
||||||
|
.path(this.servletContextPath)
|
||||||
.path(API.OAUTH_TOKEN_ENDPOINT)
|
.path(API.OAUTH_TOKEN_ENDPOINT)
|
||||||
.toUriString();
|
.toUriString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getOAuthRevokeTokenURI() {
|
public String getOAuthRevokeTokenURI() {
|
||||||
return UriComponentsBuilder.fromHttpUrl(this.webserviceServerAddress)
|
return UriComponentsBuilder.fromHttpUrl(this.webserviceServerAddress)
|
||||||
|
.path(this.servletContextPath)
|
||||||
.path(API.OAUTH_REVOKE_TOKEN_ENDPOINT)
|
.path(API.OAUTH_REVOKE_TOKEN_ENDPOINT)
|
||||||
.toUriString();
|
.toUriString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,7 +152,10 @@ public class WidgetFactory {
|
||||||
CONFIG_INPUT_READONLY("inputreadonly"),
|
CONFIG_INPUT_READONLY("inputreadonly"),
|
||||||
|
|
||||||
DARK_COLOR_LABEL("colordark"),
|
DARK_COLOR_LABEL("colordark"),
|
||||||
LIGHT_COLOR_LABEL("colorlight")
|
LIGHT_COLOR_LABEL("colorlight"),
|
||||||
|
|
||||||
|
LOGIN("login"),
|
||||||
|
LOGIN_BACK("login-back")
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,9 @@
|
||||||
package ch.ethz.seb.sebserver.webservice.weblayer.api;
|
package ch.ethz.seb.sebserver.webservice.weblayer.api;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
@ -18,6 +20,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.authorization.Privilege;
|
import ch.ethz.seb.sebserver.gbl.api.authorization.Privilege;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationService;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationService;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.InstitutionDAO;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.InstitutionDAO;
|
||||||
|
@ -51,12 +54,28 @@ public class InfoController {
|
||||||
.all(null, true)
|
.all(null, true)
|
||||||
.getOrThrow()
|
.getOrThrow()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(inst -> inst.urlSuffix != null && urlSuffix.endsWith(inst.urlSuffix))
|
.filter(inst -> inst.urlSuffix != null && urlSuffix.equals(inst.urlSuffix))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.map(inst -> inst.logoImage)
|
.map(inst -> inst.logoImage)
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequestMapping(
|
||||||
|
path = API.INFO_INST_ENDPOINT,
|
||||||
|
method = RequestMethod.GET,
|
||||||
|
produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
public Collection<EntityKey> getInstitutionInfo(@PathVariable(required = false) 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 -> inst.getEntityKey())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
@RequestMapping(
|
@RequestMapping(
|
||||||
path = API.PRIVILEGES_PATH_SEGMENT,
|
path = API.PRIVILEGES_PATH_SEGMENT,
|
||||||
method = RequestMethod.GET,
|
method = RequestMethod.GET,
|
||||||
|
|
|
@ -0,0 +1,152 @@
|
||||||
|
/*
|
||||||
|
* 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.webservice.weblayer.api;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.joda.time.DateTimeZone;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
import org.springframework.validation.FieldError;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.WebSecurityConfig;
|
||||||
|
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.APIMessage.APIMessageException;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.user.PasswordChange;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.user.UserMod;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.client.ClientCredentialService;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.InstitutionDAO;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserDAO;
|
||||||
|
|
||||||
|
@WebServiceProfile
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("${sebserver.webservice.api.admin.endpoint}" + API.REGISTER_ENDPOINT)
|
||||||
|
public class RegisterUserController {
|
||||||
|
|
||||||
|
private final InstitutionDAO institutionDAO;
|
||||||
|
private final UserActivityLogDAO userActivityLogDAO;
|
||||||
|
private final UserDAO userDAO;
|
||||||
|
private final ClientCredentialService clientCredentialService;
|
||||||
|
|
||||||
|
protected RegisterUserController(
|
||||||
|
final InstitutionDAO institutionDAO,
|
||||||
|
final UserActivityLogDAO userActivityLogDAO,
|
||||||
|
final UserDAO userDAO,
|
||||||
|
final ClientCredentialService clientCredentialService,
|
||||||
|
@Qualifier(WebSecurityConfig.USER_PASSWORD_ENCODER_BEAN_NAME) final PasswordEncoder userPasswordEncoder) {
|
||||||
|
|
||||||
|
this.institutionDAO = institutionDAO;
|
||||||
|
this.userActivityLogDAO = userActivityLogDAO;
|
||||||
|
this.userDAO = userDAO;
|
||||||
|
this.clientCredentialService = clientCredentialService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(
|
||||||
|
method = RequestMethod.POST,
|
||||||
|
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
|
||||||
|
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||||
|
public UserInfo registerNewUser(
|
||||||
|
@RequestParam(name = Domain.USER.ATTR_INSTITUTION_ID, required = true) final String institutionId,
|
||||||
|
@RequestParam(name = Domain.USER.ATTR_NAME, required = true) final String name,
|
||||||
|
@RequestParam(name = Domain.USER.ATTR_USERNAME, required = true) final String username,
|
||||||
|
@RequestParam(name = Domain.USER.ATTR_EMAIL, required = false) final String email,
|
||||||
|
@RequestParam(
|
||||||
|
name = Domain.USER.ATTR_LANGUAGE,
|
||||||
|
required = false,
|
||||||
|
defaultValue = Constants.DEFAULT_LANG_CODE) final String lang,
|
||||||
|
@RequestParam(
|
||||||
|
name = Domain.USER.ATTR_TIMEZONE,
|
||||||
|
required = false,
|
||||||
|
defaultValue = Constants.DEFAULT_TIME_ZONE_CODE) final String timezone,
|
||||||
|
@RequestParam(name = PasswordChange.ATTR_NAME_NEW_PASSWORD, required = true) final String pwd,
|
||||||
|
@RequestParam(name = PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD, required = true) final String rpwd) {
|
||||||
|
|
||||||
|
final Collection<APIMessage> errors = new ArrayList<>();
|
||||||
|
|
||||||
|
// check institution info
|
||||||
|
Long instId = null;
|
||||||
|
if (StringUtils.isNotBlank(institutionId)) {
|
||||||
|
try {
|
||||||
|
instId = Long.parseLong(institutionId);
|
||||||
|
} catch (final Exception e) {
|
||||||
|
instId = this.institutionDAO
|
||||||
|
.all(null, true)
|
||||||
|
.getOrThrow()
|
||||||
|
.stream()
|
||||||
|
.filter(inst -> inst.urlSuffix != null && institutionId.equals(inst.urlSuffix))
|
||||||
|
.findFirst()
|
||||||
|
.map(inst -> inst.id)
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instId == null) {
|
||||||
|
errors.add(APIMessage.fieldValidationError(
|
||||||
|
new FieldError(
|
||||||
|
"user",
|
||||||
|
Domain.USER.ATTR_INSTITUTION_ID,
|
||||||
|
"user:institutionId:notNull")));
|
||||||
|
}
|
||||||
|
|
||||||
|
// check password-match
|
||||||
|
final CharSequence rawPWD = this.clientCredentialService.decrypt(pwd);
|
||||||
|
final CharSequence rawRPWD = this.clientCredentialService.decrypt(rpwd);
|
||||||
|
if (!rawPWD.equals(rawRPWD)) {
|
||||||
|
errors.add(APIMessage.fieldValidationError(
|
||||||
|
new FieldError(
|
||||||
|
"passwordChange",
|
||||||
|
PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD,
|
||||||
|
"user:confirmNewPassword:password.mismatch")));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!errors.isEmpty()) {
|
||||||
|
throw new APIMessageException(errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
final UserMod user = new UserMod(
|
||||||
|
null,
|
||||||
|
instId,
|
||||||
|
name,
|
||||||
|
username,
|
||||||
|
rawPWD,
|
||||||
|
rawRPWD,
|
||||||
|
email,
|
||||||
|
Locale.forLanguageTag(lang),
|
||||||
|
DateTimeZone.forID(timezone),
|
||||||
|
new HashSet<>(Arrays.asList(UserRole.EXAM_SUPPORTER.name())));
|
||||||
|
|
||||||
|
return this.userDAO.createNew(user)
|
||||||
|
.flatMap(this.userActivityLogDAO::logCreate)
|
||||||
|
.map(u -> {
|
||||||
|
Utils.clear(rawPWD);
|
||||||
|
Utils.clear(rawRPWD);
|
||||||
|
return u;
|
||||||
|
})
|
||||||
|
.getOrThrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
server.address=localhost
|
server.address=localhost
|
||||||
server.port=8080
|
server.port=8080
|
||||||
server.servlet.context-path=/
|
|
||||||
|
|
||||||
sebserver.gui.entrypoint=/gui
|
sebserver.gui.entrypoint=/gui
|
||||||
sebserver.gui.webservice.protocol=http
|
sebserver.gui.webservice.protocol=http
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
server.address=localhost
|
server.address=localhost
|
||||||
server.port=8090
|
server.port=8090
|
||||||
server.servlet.context-path=/
|
|
||||||
|
|
||||||
logging.file=log/sebserver.log
|
logging.file=log/sebserver.log
|
||||||
|
|
||||||
|
|
|
@ -110,6 +110,7 @@ sebserver.webservice.lms.address.alias=
|
||||||
##########################################################
|
##########################################################
|
||||||
### SEB Server GUI configuration
|
### SEB Server GUI configuration
|
||||||
|
|
||||||
|
sebserver.gui.self-registering=true
|
||||||
sebserver.gui.multilingual=false
|
sebserver.gui.multilingual=false
|
||||||
sebserver.gui.supported.languages=en
|
sebserver.gui.supported.languages=en
|
||||||
sebserver.gui.entrypoint=/gui
|
sebserver.gui.entrypoint=/gui
|
||||||
|
|
|
@ -107,6 +107,10 @@ sebserver.logout.invalid-session.message=You have been signed out because of a u
|
||||||
sebserver.login.password.change=Information
|
sebserver.login.password.change=Information
|
||||||
sebserver.login.password.change.success=The password was successfully changed. Please sign in with your new password
|
sebserver.login.password.change.success=The password was successfully changed. Please sign in with your new password
|
||||||
|
|
||||||
|
sebserver.login.register=Register
|
||||||
|
sebserver.login.register.form.title=Register As New User
|
||||||
|
|
||||||
|
|
||||||
################################
|
################################
|
||||||
# Main Page
|
# Main Page
|
||||||
################################
|
################################
|
||||||
|
|
|
@ -120,6 +120,10 @@ Label.colorlight {
|
||||||
padding: 2px 5px 2px 5px;
|
padding: 2px 5px 2px 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Composite {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
Composite.bordered {
|
Composite.bordered {
|
||||||
border: 2px;
|
border: 2px;
|
||||||
}
|
}
|
||||||
|
@ -177,6 +181,12 @@ Composite.login {
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Composite.login-back {
|
||||||
|
background-color: #EAECEE;
|
||||||
|
margin: 0px 0 0 0;
|
||||||
|
padding: 0px 0px 0px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
Composite.error {
|
Composite.error {
|
||||||
border: 1px solid #aa0000;
|
border: 1px solid #aa0000;
|
||||||
border-radius: 1px;
|
border-radius: 1px;
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 165 B After Width: | Height: | Size: 175 B |
BIN
src/main/resources/static/images/save_alt.png
Normal file
BIN
src/main/resources/static/images/save_alt.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 165 B |
|
@ -74,7 +74,7 @@ public abstract class GuiIntegrationTest {
|
||||||
|
|
||||||
final HttpSession sessionMock = Mockito.mock(HttpSession.class);
|
final HttpSession sessionMock = Mockito.mock(HttpSession.class);
|
||||||
final WebserviceURIService webserviceURIService = new WebserviceURIService(
|
final WebserviceURIService webserviceURIService = new WebserviceURIService(
|
||||||
"http", "localhost", "8080", this.endpoint);
|
"http", "localhost", "8080", "/", this.endpoint);
|
||||||
|
|
||||||
final ClientHttpRequestFactoryService clientHttpRequestFactoryService = Mockito
|
final ClientHttpRequestFactoryService clientHttpRequestFactoryService = Mockito
|
||||||
.mock(ClientHttpRequestFactoryService.class);
|
.mock(ClientHttpRequestFactoryService.class);
|
||||||
|
|
Loading…
Add table
Reference in a new issue