SEBSERV-30 LmsSetup list and form; fixed tests and code cleanup
This commit is contained in:
parent
e799a0214f
commit
b74c711ebb
55 changed files with 1196 additions and 317 deletions
|
@ -20,6 +20,8 @@ public final class Constants {
|
|||
public static final String FORM_URL_ENCODED_SEPARATOR = "&";
|
||||
public static final String FORM_URL_ENCODED_NAME_VALUE_SEPARATOR = "=";
|
||||
|
||||
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
/** Date-Time formatter without milliseconds using UTC time-zone. Pattern is yyyy-MM-dd HH:mm:ss */
|
||||
public static final DateTimeFormatter DATE_TIME_PATTERN_UTC_NO_MILLIS = DateTimeFormat
|
||||
.forPattern("yyyy-MM-dd HH:mm:ss")
|
||||
|
|
|
@ -37,6 +37,10 @@ public final class API {
|
|||
public static final String INSTITUTION_ENDPOINT = "/institution";
|
||||
|
||||
public static final String LMS_SETUP_ENDPOINT = "/lms_setup";
|
||||
public static final String SEB_CONFIG_EXPORT_PATH_SEGMENT = "/sebconfig";
|
||||
public static final String LMS_SETUP_TEST_PATH_SEGMENT = "/test";
|
||||
public static final String SEB_CONFIG_EXPORT_ENDPOINT = LMS_SETUP_ENDPOINT + "/sebconfig";
|
||||
public static final String LMS_SETUP_TEST_ENDPOINT = LMS_SETUP_ENDPOINT + "/test";
|
||||
|
||||
public static final String USER_ACCOUNT_ENDPOINT = "/useraccount";
|
||||
|
||||
|
|
|
@ -117,4 +117,8 @@ public final class Institution implements GrantEntity, Activatable {
|
|||
+ ", active=" + this.active + "]";
|
||||
}
|
||||
|
||||
public static Institution createNew() {
|
||||
return new Institution(null, null, null, null, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -50,11 +50,11 @@ public final class LmsSetup implements GrantEntity, Activatable {
|
|||
public final LmsType lmsType;
|
||||
|
||||
@JsonProperty(LMS_SETUP.ATTR_LMS_CLIENTNAME)
|
||||
@Size(min = 3, max = 255, message = "lmsSetup:lmsAuthName:size:{min}:{max}:${validatedValue}")
|
||||
@Size(min = 3, max = 255, message = "lmsSetup:lmsClientname:size:{min}:{max}:${validatedValue}")
|
||||
public final String lmsAuthName;
|
||||
|
||||
@JsonProperty(LMS_SETUP.ATTR_LMS_CLIENTSECRET)
|
||||
@Size(min = 8, max = 255, message = "lmsSetup:lmsAuthSecret:size:{min}:{max}:${validatedValue}")
|
||||
@Size(min = 8, max = 255, message = "lmsSetup:lmsClientsecret:size:{min}:{max}:${validatedValue}")
|
||||
public final String lmsAuthSecret;
|
||||
|
||||
@JsonProperty(LMS_SETUP.ATTR_LMS_URL)
|
||||
|
@ -64,11 +64,9 @@ public final class LmsSetup implements GrantEntity, Activatable {
|
|||
public final String lmsRestApiToken;
|
||||
|
||||
@JsonProperty(LMS_SETUP.ATTR_SEB_CLIENTNAME)
|
||||
@Size(min = 3, max = 255, message = "lmsSetup:sebAuthName:size:{min}:{max}:${validatedValue}")
|
||||
public final String sebAuthName;
|
||||
|
||||
@JsonProperty(LMS_SETUP.ATTR_SEB_CLIENTSECRET)
|
||||
@Size(min = 8, max = 255, message = "lmsSetup:sebAuthSecret:size:{min}:{max}:${validatedValue}")
|
||||
public final String sebAuthSecret;
|
||||
|
||||
/** Indicates whether this LmsSetup is active or not */
|
||||
|
@ -203,4 +201,8 @@ public final class LmsSetup implements GrantEntity, Activatable {
|
|||
lmsSetup.name);
|
||||
}
|
||||
|
||||
public static LmsSetup createNew(final Long institutionId) {
|
||||
return new LmsSetup(null, institutionId, null, null, null, null, null, null, null, null, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import java.util.Collections;
|
|||
import java.util.EnumSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
|
@ -112,19 +113,6 @@ public final class UserMod implements UserAccount {
|
|||
: Collections.emptySet();
|
||||
}
|
||||
|
||||
public UserMod(final UserInfo userInfo, final String newPassword, final String confirmNewPassword) {
|
||||
this.uuid = userInfo.uuid;
|
||||
this.institutionId = userInfo.institutionId;
|
||||
this.newPassword = newPassword;
|
||||
this.confirmNewPassword = confirmNewPassword;
|
||||
this.name = userInfo.name;
|
||||
this.username = userInfo.username;
|
||||
this.email = userInfo.email;
|
||||
this.language = userInfo.language;
|
||||
this.timeZone = userInfo.timeZone;
|
||||
this.roles = userInfo.roles;
|
||||
}
|
||||
|
||||
public UserMod(final String modelId, final POSTMapper postAttrMapper) {
|
||||
this.uuid = modelId;
|
||||
this.institutionId = postAttrMapper.getLong(USER.ATTR_INSTITUTION_ID);
|
||||
|
@ -138,19 +126,6 @@ public final class UserMod implements UserAccount {
|
|||
this.roles = postAttrMapper.getStringSet(USER_ROLE.REFERENCE_NAME);
|
||||
}
|
||||
|
||||
public UserMod(final String modelId, final Long institutionId) {
|
||||
this.uuid = modelId;
|
||||
this.institutionId = institutionId;
|
||||
this.newPassword = null;
|
||||
this.confirmNewPassword = null;
|
||||
this.name = null;
|
||||
this.username = null;
|
||||
this.email = null;
|
||||
this.language = Locale.ENGLISH;
|
||||
this.timeZone = DateTimeZone.UTC;
|
||||
this.roles = Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModelId() {
|
||||
return this.uuid;
|
||||
|
@ -257,4 +232,11 @@ public final class UserMod implements UserAccount {
|
|||
+ ", newPassword=" + this.newPassword + ", retypedNewPassword=" + this.confirmNewPassword + "]";
|
||||
}
|
||||
|
||||
public static UserMod createNew(final Long institutionId) {
|
||||
return new UserMod(
|
||||
UUID.randomUUID().toString(),
|
||||
institutionId,
|
||||
null, null, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,12 +21,14 @@ import org.eclipse.rap.rwt.application.ApplicationConfiguration;
|
|||
import org.eclipse.rap.rwt.application.EntryPoint;
|
||||
import org.eclipse.rap.rwt.application.EntryPointFactory;
|
||||
import org.eclipse.rap.rwt.client.WebClient;
|
||||
import org.eclipse.rap.rwt.service.ServiceManager;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.DownloadService;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.SEBServerAuthorizationContext;
|
||||
|
||||
|
@ -63,6 +65,8 @@ public class RAPConfiguration implements ApplicationConfiguration {
|
|||
|
||||
private static final EntryPointFactory RAPSpringEntryPointFactory = new EntryPointFactory() {
|
||||
|
||||
private boolean serviceInistialized = false;
|
||||
|
||||
@Override
|
||||
public EntryPoint create() {
|
||||
return new AbstractEntryPoint() {
|
||||
|
@ -83,6 +87,7 @@ public class RAPConfiguration implements ApplicationConfiguration {
|
|||
}
|
||||
|
||||
final WebApplicationContext webApplicationContext = getWebApplicationContext(httpSession);
|
||||
initSpringBasedRAPServices(webApplicationContext);
|
||||
|
||||
final EntryPointService entryPointService = webApplicationContext
|
||||
.getBean(EntryPointService.class);
|
||||
|
@ -93,9 +98,19 @@ public class RAPConfiguration implements ApplicationConfiguration {
|
|||
entryPointService.loadLoginPage(parent);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
private void initSpringBasedRAPServices(final WebApplicationContext webApplicationContext) {
|
||||
if (!this.serviceInistialized) {
|
||||
final ServiceManager manager = RWT.getServiceManager();
|
||||
final DownloadService downloadService = webApplicationContext.getBean(DownloadService.class);
|
||||
manager.registerServiceHandler(DownloadService.DOWNLOAD_SERVICE_NAME, downloadService);
|
||||
this.serviceInistialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAuthenticated(
|
||||
final HttpSession httpSession,
|
||||
final WebApplicationContext webApplicationContext) {
|
||||
|
|
|
@ -66,7 +66,7 @@ public class InstitutionForm implements TemplateComposer {
|
|||
final boolean isNew = entityKey == null;
|
||||
// get data or create new. Handle error if happen
|
||||
final Institution institution = (entityKey == null)
|
||||
? new Institution(null, null, null, null, false)
|
||||
? Institution.createNew()
|
||||
: this.restService
|
||||
.getBuilder(GetInstitution.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
||||
|
@ -143,13 +143,13 @@ public class InstitutionForm implements TemplateComposer {
|
|||
|
||||
.createAction(ActionDefinition.INSTITUTION_DEACTIVATE)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(Action.activation(this.restService, false))
|
||||
.withExec(this.restService::activation)
|
||||
.withConfirm(PageUtils.confirmDeactivation(institution, this.restService))
|
||||
.publishIf(() -> writeGrant && isReadonly && institution.isActive())
|
||||
|
||||
.createAction(ActionDefinition.INSTITUTION_ACTIVATE)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(Action.activation(this.restService, true))
|
||||
.withExec(this.restService::activation)
|
||||
.publishIf(() -> writeGrant && isReadonly && !institution.isActive())
|
||||
|
||||
.createAction(ActionDefinition.INSTITUTION_SAVE)
|
||||
|
|
|
@ -79,6 +79,7 @@ public class InstitutionList implements TemplateComposer {
|
|||
// propagate content actions to action-pane
|
||||
final GrantCheck instGrant = this.currentUser.grantCheck(EntityType.INSTITUTION);
|
||||
final GrantCheck userGrant = this.currentUser.grantCheck(EntityType.USER);
|
||||
final LocTextKey emptySelectionText = new LocTextKey("sebserver.institution.info.pleaseSelect");
|
||||
pageContext.clearEntityKeys()
|
||||
|
||||
.createAction(ActionDefinition.INSTITUTION_NEW)
|
||||
|
@ -88,11 +89,11 @@ public class InstitutionList implements TemplateComposer {
|
|||
.publishIf(userGrant::w)
|
||||
|
||||
.createAction(ActionDefinition.INSTITUTION_VIEW_FROM_LIST)
|
||||
.withSelect(table::getSelection, Action.applySingleSelection("sebserver.institution.info.pleaseSelect"))
|
||||
.withSelect(table::getSelection, Action::applySingleSelection, emptySelectionText)
|
||||
.publishIf(() -> table.hasAnyContent())
|
||||
|
||||
.createAction(ActionDefinition.INSTITUTION_MODIFY_FROM_LIST)
|
||||
.withSelect(table::getSelection, Action.applySingleSelection("sebserver.institution.info.pleaseSelect"))
|
||||
.withSelect(table::getSelection, Action::applySingleSelection, emptySelectionText)
|
||||
.publishIf(() -> instGrant.m() && table.hasAnyContent());
|
||||
;
|
||||
|
||||
|
|
|
@ -8,34 +8,221 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
import org.eclipse.rap.rwt.RWT;
|
||||
import org.eclipse.rap.rwt.client.service.UrlLauncher;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
|
||||
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup.LmsType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.form.FormBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.form.FormHandle;
|
||||
import ch.ethz.seb.sebserver.gui.form.PageFormService;
|
||||
import ch.ethz.seb.sebserver.gui.service.ResourceService;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageUtils;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.action.Action;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.SebClientConfigDownload;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitution;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.GetLmsSetup;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.NewLmsSetup;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.SaveLmsSetup;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.EntityGrantCheck;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class LmsSetupForm implements TemplateComposer {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(LmsSetupForm.class);
|
||||
|
||||
private final PageFormService pageFormService;
|
||||
private final ResourceService resourceService;
|
||||
private final SebClientConfigDownload sebClientConfigDownload;
|
||||
|
||||
protected LmsSetupForm(
|
||||
final PageFormService pageFormService,
|
||||
final ResourceService resourceService) {
|
||||
final ResourceService resourceService,
|
||||
final SebClientConfigDownload sebClientConfigDownload) {
|
||||
|
||||
this.pageFormService = pageFormService;
|
||||
this.resourceService = resourceService;
|
||||
this.sebClientConfigDownload = sebClientConfigDownload;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
// TODO Auto-generated method stub
|
||||
final CurrentUser currentUser = this.resourceService.getCurrentUser();
|
||||
final RestService restService = this.resourceService.getRestService();
|
||||
final WidgetFactory widgetFactory = this.pageFormService.getWidgetFactory();
|
||||
|
||||
final UserInfo user = currentUser.get();
|
||||
final EntityKey entityKey = pageContext.getEntityKey();
|
||||
final EntityKey parentEntityKey = pageContext.getParentEntityKey();
|
||||
final boolean readonly = pageContext.isReadonly();
|
||||
|
||||
final BooleanSupplier isNew = () -> entityKey == null;
|
||||
final BooleanSupplier isNotNew = () -> !isNew.getAsBoolean();
|
||||
final BooleanSupplier isSEBAdmin = () -> user.hasRole(UserRole.SEB_SERVER_ADMIN);
|
||||
|
||||
// get data or create new. handle error if happen
|
||||
final LmsSetup lmsSetup = isNew.getAsBoolean()
|
||||
? LmsSetup.createNew((parentEntityKey != null)
|
||||
? Long.valueOf(parentEntityKey.modelId)
|
||||
: user.institutionId)
|
||||
: restService
|
||||
.getBuilder(GetLmsSetup.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
||||
.call()
|
||||
.get(pageContext::notifyError);
|
||||
|
||||
if (lmsSetup == null) {
|
||||
log.error(
|
||||
"Failed to get LmsSetup. "
|
||||
+ "Error was notified to the User. "
|
||||
+ "See previous logs for more infomation");
|
||||
return;
|
||||
}
|
||||
|
||||
// new PageContext with actual EntityKey
|
||||
final PageContext formContext = pageContext.withEntityKey(lmsSetup.getEntityKey());
|
||||
// the default page layout with title
|
||||
final LocTextKey titleKey = new LocTextKey(
|
||||
isNotNew.getAsBoolean()
|
||||
? "sebserver.lmssetup.form.title"
|
||||
: "sebserver.lmssetup.form.title.new");
|
||||
final Composite content = widgetFactory.defaultPageLayout(
|
||||
formContext.getParent(),
|
||||
titleKey);
|
||||
|
||||
final EntityGrantCheck userGrantCheck = currentUser.entityGrantCheck(lmsSetup);
|
||||
final boolean writeGrant = userGrantCheck.w();
|
||||
final boolean modifyGrant = userGrantCheck.m();
|
||||
final boolean istitutionActive = restService.getBuilder(GetInstitution.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, String.valueOf(lmsSetup.getInstitutionId()))
|
||||
.call()
|
||||
.map(inst -> inst.active)
|
||||
.getOr(false);
|
||||
|
||||
// The UserAccount form
|
||||
final LmsType lmsType = lmsSetup.getLmsType();
|
||||
final FormHandle<LmsSetup> formHandle = this.pageFormService.getBuilder(
|
||||
formContext.copyOf(content), 4)
|
||||
.readonly(readonly)
|
||||
.putStaticValueIf(isNotNew,
|
||||
Domain.LMS_SETUP.ATTR_ID,
|
||||
lmsSetup.getModelId())
|
||||
.putStaticValueIf(isNotNew,
|
||||
Domain.LMS_SETUP.ATTR_INSTITUTION_ID,
|
||||
String.valueOf(lmsSetup.getInstitutionId()))
|
||||
.addField(FormBuilder.singleSelection(
|
||||
Domain.LMS_SETUP.ATTR_INSTITUTION_ID,
|
||||
"sebserver.lmssetup.form.institution",
|
||||
String.valueOf(lmsSetup.getInstitutionId()),
|
||||
() -> this.resourceService.institutionResource())
|
||||
.withCondition(isSEBAdmin)
|
||||
.readonlyIf(isNotNew))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.LMS_SETUP.ATTR_NAME,
|
||||
"sebserver.lmssetup.form.name",
|
||||
lmsSetup.getName()))
|
||||
.addField(FormBuilder.singleSelection(
|
||||
Domain.LMS_SETUP.ATTR_LMS_TYPE,
|
||||
"sebserver.lmssetup.form.type",
|
||||
(lmsType != null) ? lmsType.name() : null,
|
||||
this.resourceService::lmsTypeResources)
|
||||
.readonlyIf(isNotNew))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.LMS_SETUP.ATTR_SEB_CLIENTNAME,
|
||||
"sebserver.lmssetup.form.clientname.seb",
|
||||
lmsSetup.getSebAuthName())
|
||||
.readonlyIf(isNotNew))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.LMS_SETUP.ATTR_SEB_CLIENTSECRET,
|
||||
"sebserver.lmssetup.form.secret.seb")
|
||||
.asPasswordField()
|
||||
.withCondition(isNew))
|
||||
|
||||
.addField(FormBuilder.text(
|
||||
Domain.LMS_SETUP.ATTR_LMS_URL,
|
||||
"sebserver.lmssetup.form.url",
|
||||
lmsSetup.getLmsApiUrl())
|
||||
.withCondition(() -> isNotNew.getAsBoolean() && lmsType != LmsType.MOCKUP))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.LMS_SETUP.ATTR_LMS_CLIENTNAME,
|
||||
"sebserver.lmssetup.form.clientname.lms",
|
||||
lmsSetup.getLmsAuthName())
|
||||
.withCondition(() -> isNotNew.getAsBoolean() && lmsType != LmsType.MOCKUP))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.LMS_SETUP.ATTR_LMS_CLIENTSECRET,
|
||||
"sebserver.lmssetup.form.secret.lms")
|
||||
.asPasswordField()
|
||||
.withCondition(() -> isNotNew.getAsBoolean() && lmsType != LmsType.MOCKUP))
|
||||
|
||||
.buildFor((entityKey == null)
|
||||
? restService.getRestCall(NewLmsSetup.class)
|
||||
: restService.getRestCall(SaveLmsSetup.class));
|
||||
|
||||
;
|
||||
|
||||
// propagate content actions to action-pane
|
||||
final UrlLauncher urlLauncher = RWT.getClient().getService(UrlLauncher.class);
|
||||
formContext.clearEntityKeys()
|
||||
|
||||
.createAction(ActionDefinition.LMS_SETUP_NEW)
|
||||
.publishIf(() -> writeGrant && readonly && istitutionActive)
|
||||
|
||||
.createAction(ActionDefinition.LMS_SETUP_MODIFY)
|
||||
.withEntityKey(entityKey)
|
||||
.publishIf(() -> modifyGrant && readonly && istitutionActive)
|
||||
|
||||
.createAction(ActionDefinition.LMS_SETUP_EXPORT_SEB_CONFIG)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(action -> {
|
||||
final String downloadURL = this.sebClientConfigDownload.downloadSEBClientConfigURL(
|
||||
entityKey.modelId);
|
||||
urlLauncher.openURL(downloadURL);
|
||||
return action;
|
||||
})
|
||||
.publishIf(() -> writeGrant && readonly && lmsSetup.isActive())
|
||||
|
||||
.createAction(ActionDefinition.LMS_SETUP_DEACTIVATE)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(restService::activation)
|
||||
.withConfirm(PageUtils.confirmDeactivation(lmsSetup, restService))
|
||||
.publishIf(() -> writeGrant && readonly && istitutionActive && lmsSetup.isActive())
|
||||
|
||||
.createAction(ActionDefinition.LMS_SETUP_ACTIVATE)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(restService::activation)
|
||||
.publishIf(() -> writeGrant && readonly && istitutionActive && !lmsSetup.isActive())
|
||||
|
||||
.createAction(ActionDefinition.LMS_SETUP_SAVE)
|
||||
.withExec(formHandle::postChanges)
|
||||
.publishIf(() -> !readonly)
|
||||
|
||||
.createAction(ActionDefinition.LMS_SETUP_CANCEL_MODIFY)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(Action::onEmptyEntityKeyGoToActivityHome)
|
||||
.withConfirm("sebserver.overall.action.modify.cancel.confirm")
|
||||
.publishIf(() -> !readonly);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -16,18 +16,21 @@ import org.springframework.context.annotation.Lazy;
|
|||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.service.ResourceService;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.action.Action;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.GetLmsSetups;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute;
|
||||
import ch.ethz.seb.sebserver.gui.table.EntityTable;
|
||||
|
@ -57,7 +60,6 @@ public class LmsSetupList implements TemplateComposer {
|
|||
public void compose(final PageContext pageContext) {
|
||||
final CurrentUser currentUser = this.resourceService.getCurrentUser();
|
||||
final RestService restService = this.resourceService.getRestService();
|
||||
final I18nSupport i18nSupport = this.widgetFactory.getI18nSupport();
|
||||
|
||||
// content page layout with title
|
||||
final Composite content = this.widgetFactory.defaultPageLayout(
|
||||
|
@ -107,6 +109,22 @@ public class LmsSetupList implements TemplateComposer {
|
|||
true))
|
||||
.compose(content);
|
||||
|
||||
// propagate content actions to action-pane
|
||||
final GrantCheck userGrant = currentUser.grantCheck(EntityType.LMS_SETUP);
|
||||
final LocTextKey emptySelectionText = new LocTextKey("sebserver.lmssetup.info.pleaseSelect");
|
||||
pageContext.clearEntityKeys()
|
||||
|
||||
.createAction(ActionDefinition.LMS_SETUP_NEW)
|
||||
.publishIf(userGrant::w)
|
||||
|
||||
.createAction(ActionDefinition.LMS_SETUP_VIEW_FROM_LIST)
|
||||
.withSelect(table::getSelection, Action::applySingleSelection, emptySelectionText)
|
||||
.publishIf(() -> table.hasAnyContent())
|
||||
|
||||
.createAction(ActionDefinition.LMS_SETUP_MODIFY_FROM_LIST)
|
||||
.withSelect(table::getSelection, Action::applySingleSelection, emptySelectionText)
|
||||
.publishIf(() -> userGrant.m() && table.hasAnyContent());
|
||||
|
||||
}
|
||||
|
||||
private String lmsSetupTypeName(final LmsSetup lmsSetup) {
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
import org.apache.tomcat.util.buf.StringUtils;
|
||||
|
@ -73,20 +72,19 @@ public class UserAccountForm implements TemplateComposer {
|
|||
final WidgetFactory widgetFactory = this.pageFormService.getWidgetFactory();
|
||||
|
||||
final UserInfo user = currentUser.get();
|
||||
|
||||
final EntityKey entityKey = pageContext.getEntityKey();
|
||||
final EntityKey parentEntityKey = pageContext.getParentEntityKey();
|
||||
final boolean readonly = pageContext.isReadonly();
|
||||
|
||||
final BooleanSupplier isNew = () -> entityKey == null;
|
||||
final BooleanSupplier isNotNew = () -> !isNew.getAsBoolean();
|
||||
final BooleanSupplier isSEBAdmin = () -> user.hasRole(UserRole.SEB_SERVER_ADMIN);
|
||||
final boolean readonly = pageContext.isReadonly();
|
||||
|
||||
// get data or create new. handle error if happen
|
||||
final UserAccount userAccount = isNew.getAsBoolean()
|
||||
? new UserMod(
|
||||
UUID.randomUUID().toString(),
|
||||
(parentEntityKey != null)
|
||||
? Long.valueOf(parentEntityKey.modelId)
|
||||
: user.institutionId)
|
||||
? UserMod.createNew((parentEntityKey != null)
|
||||
? Long.valueOf(parentEntityKey.modelId)
|
||||
: user.institutionId)
|
||||
: restService
|
||||
.getBuilder(GetUserAccount.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
||||
|
@ -101,20 +99,19 @@ public class UserAccountForm implements TemplateComposer {
|
|||
return;
|
||||
}
|
||||
|
||||
// new PageContext with actual EntityKey
|
||||
final PageContext formContext = pageContext.withEntityKey(userAccount.getEntityKey());
|
||||
|
||||
final boolean ownAccount = user.uuid.equals(userAccount.getModelId());
|
||||
final EntityGrantCheck userGrantCheck = currentUser.entityGrantCheck(userAccount);
|
||||
final boolean writeGrant = userGrantCheck.w();
|
||||
final boolean modifyGrant = userGrantCheck.m();
|
||||
// modifying an UserAccount is not possible if the root institution is inactive
|
||||
final boolean istitutionActive = restService.getBuilder(GetInstitution.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, String.valueOf(userAccount.getInstitutionId()))
|
||||
.call()
|
||||
.map(inst -> inst.active)
|
||||
.getOr(false);
|
||||
|
||||
// new PageContext with actual EntityKey
|
||||
final PageContext formContext = pageContext.withEntityKey(userAccount.getEntityKey());
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("UserAccount Form for user {}", userAccount.getName());
|
||||
}
|
||||
|
@ -190,7 +187,6 @@ public class UserAccountForm implements TemplateComposer {
|
|||
: restService.getRestCall(SaveUserAccount.class));
|
||||
|
||||
// propagate content actions to action-pane
|
||||
|
||||
formContext.clearEntityKeys()
|
||||
|
||||
.createAction(ActionDefinition.USER_ACCOUNT_NEW)
|
||||
|
@ -205,12 +201,14 @@ public class UserAccountForm implements TemplateComposer {
|
|||
.publishIf(() -> modifyGrant && readonly && istitutionActive && userAccount.isActive())
|
||||
|
||||
.createAction(ActionDefinition.USER_ACCOUNT_DEACTIVATE)
|
||||
.withExec(Action.activation(restService, false))
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(restService::activation)
|
||||
.withConfirm(PageUtils.confirmDeactivation(userAccount, restService))
|
||||
.publishIf(() -> writeGrant && readonly && istitutionActive && userAccount.isActive())
|
||||
|
||||
.createAction(ActionDefinition.USER_ACCOUNT_ACTIVATE)
|
||||
.withExec(Action.activation(restService, true))
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(restService::activation)
|
||||
.publishIf(() -> writeGrant && readonly && istitutionActive && !userAccount.isActive())
|
||||
|
||||
.createAction(ActionDefinition.USER_ACCOUNT_SAVE)
|
||||
|
@ -225,6 +223,7 @@ public class UserAccountForm implements TemplateComposer {
|
|||
.publishIf(() -> !readonly)
|
||||
|
||||
.createAction(ActionDefinition.USER_ACCOUNT_CANCEL_MODIFY)
|
||||
.withEntityKey(entityKey)
|
||||
.withExec(Action::onEmptyEntityKeyGoToActivityHome)
|
||||
.withConfirm("sebserver.overall.action.modify.cancel.confirm")
|
||||
.publishIf(() -> !readonly);
|
||||
|
|
|
@ -119,17 +119,18 @@ public class UserAccountList implements TemplateComposer {
|
|||
|
||||
// propagate content actions to action-pane
|
||||
final GrantCheck userGrant = currentUser.grantCheck(EntityType.USER);
|
||||
final LocTextKey emptySelectionText = new LocTextKey("sebserver.useraccount.info.pleaseSelect");
|
||||
pageContext.clearEntityKeys()
|
||||
|
||||
.createAction(ActionDefinition.USER_ACCOUNT_NEW)
|
||||
.publishIf(userGrant::w)
|
||||
|
||||
.createAction(ActionDefinition.USER_ACCOUNT_VIEW_FROM_LIST)
|
||||
.withSelect(table::getSelection, Action.applySingleSelection("sebserver.useraccount.info.pleaseSelect"))
|
||||
.withSelect(table::getSelection, Action::applySingleSelection, emptySelectionText)
|
||||
.publishIf(() -> table.hasAnyContent())
|
||||
|
||||
.createAction(ActionDefinition.USER_ACCOUNT_MODIFY_FROM_LIST)
|
||||
.withSelect(table::getSelection, Action.applySingleSelection("sebserver.useraccount.info.pleaseSelect"))
|
||||
.withSelect(table::getSelection, Action::applySingleSelection, emptySelectionText)
|
||||
.publishIf(() -> userGrant.m() && table.hasAnyContent());
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,13 @@ import ch.ethz.seb.sebserver.gui.content.UserAccountForm;
|
|||
import ch.ethz.seb.sebserver.gui.content.UserAccountList;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.ActivateInstitution;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.DeactivateInstitution;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.ActivateLmsSetup;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.DeactivateLmsSetup;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.ActivateUserAccount;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.DeactivateUserAccount;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon;
|
||||
|
||||
/** Enumeration of static action data for each action within the SEB Server GUI */
|
||||
|
@ -64,11 +71,13 @@ public enum ActionDefinition {
|
|||
new LocTextKey("sebserver.institution.action.activate"),
|
||||
ImageIcon.INACTIVE,
|
||||
InstitutionForm.class,
|
||||
ActivateInstitution.class,
|
||||
INSTITUTION_VIEW_LIST),
|
||||
INSTITUTION_DEACTIVATE(
|
||||
new LocTextKey("sebserver.institution.action.deactivate"),
|
||||
ImageIcon.ACTIVE,
|
||||
InstitutionForm.class,
|
||||
DeactivateInstitution.class,
|
||||
INSTITUTION_VIEW_LIST),
|
||||
INSTITUTION_DELETE(
|
||||
new LocTextKey("sebserver.institution.action.modify"),
|
||||
|
@ -117,11 +126,13 @@ public enum ActionDefinition {
|
|||
new LocTextKey("sebserver.useraccount.action.activate"),
|
||||
ImageIcon.INACTIVE,
|
||||
UserAccountForm.class,
|
||||
ActivateUserAccount.class,
|
||||
USER_ACCOUNT_VIEW_LIST),
|
||||
USER_ACCOUNT_DEACTIVATE(
|
||||
new LocTextKey("sebserver.useraccount.action.deactivate"),
|
||||
ImageIcon.ACTIVE,
|
||||
UserAccountForm.class,
|
||||
DeactivateUserAccount.class,
|
||||
USER_ACCOUNT_VIEW_LIST),
|
||||
USER_ACCOUNT_DELETE(
|
||||
new LocTextKey("sebserver.useraccount.action.modify"),
|
||||
|
@ -140,18 +151,66 @@ public enum ActionDefinition {
|
|||
USER_ACCOUNT_VIEW_LIST),
|
||||
|
||||
LMS_SETUP_VIEW_LIST(
|
||||
new LocTextKey("sebserver.lmssetup.list.title"),
|
||||
new LocTextKey("sebserver.lmssetup.action.list"),
|
||||
LmsSetupList.class),
|
||||
LMS_SETUP_VIEW_FORM(
|
||||
new LocTextKey("sebserver.useraccount.action.form"),
|
||||
new LocTextKey("sebserver.lmssetup.action.form"),
|
||||
LmsSetupForm.class,
|
||||
USER_ACCOUNT_VIEW_LIST),
|
||||
LMS_SETUP_VIEW_LIST),
|
||||
LMS_SETUP_NEW(
|
||||
new LocTextKey("sebserver.lmssetup.action.new"),
|
||||
ImageIcon.NEW,
|
||||
LmsSetupForm.class,
|
||||
LMS_SETUP_VIEW_LIST, false),
|
||||
LMS_SETUP_VIEW_FROM_LIST(
|
||||
new LocTextKey("sebserver.lmssetup.action.list.view"),
|
||||
ImageIcon.SHOW,
|
||||
LmsSetupForm.class,
|
||||
LMS_SETUP_VIEW_LIST),
|
||||
LMS_SETUP_MODIFY_FROM_LIST(
|
||||
new LocTextKey("sebserver.lmssetup.action.list.modify"),
|
||||
ImageIcon.EDIT,
|
||||
LmsSetupForm.class,
|
||||
LMS_SETUP_VIEW_LIST, false),
|
||||
LMS_SETUP_MODIFY(
|
||||
new LocTextKey("sebserver.lmssetup.action.modify"),
|
||||
ImageIcon.EDIT,
|
||||
LmsSetupForm.class,
|
||||
LMS_SETUP_VIEW_LIST, false),
|
||||
LMS_SETUP_EXPORT_SEB_CONFIG(
|
||||
new LocTextKey("sebserver.lmssetup.action.export.sebconfig"),
|
||||
ImageIcon.SAVE,
|
||||
LmsSetupForm.class,
|
||||
LMS_SETUP_VIEW_LIST),
|
||||
LMS_SETUP_CANCEL_MODIFY(
|
||||
new LocTextKey("sebserver.overall.action.modify.cancel"),
|
||||
ImageIcon.CANCEL,
|
||||
LmsSetupForm.class,
|
||||
LMS_SETUP_VIEW_LIST),
|
||||
LMS_SETUP_SAVE(
|
||||
new LocTextKey("sebserver.lmssetup.action.save"),
|
||||
ImageIcon.SAVE,
|
||||
LmsSetupForm.class,
|
||||
LMS_SETUP_VIEW_LIST),
|
||||
LMS_SETUP_ACTIVATE(
|
||||
new LocTextKey("sebserver.lmssetup.action.activate"),
|
||||
ImageIcon.INACTIVE,
|
||||
LmsSetupForm.class,
|
||||
ActivateLmsSetup.class,
|
||||
LMS_SETUP_VIEW_LIST),
|
||||
LMS_SETUP_DEACTIVATE(
|
||||
new LocTextKey("sebserver.lmssetup.action.deactivate"),
|
||||
ImageIcon.ACTIVE,
|
||||
LmsSetupForm.class,
|
||||
DeactivateLmsSetup.class,
|
||||
LMS_SETUP_VIEW_LIST),
|
||||
;
|
||||
|
||||
public final LocTextKey title;
|
||||
public final ImageIcon icon;
|
||||
public final Class<? extends TemplateComposer> contentPaneComposer;
|
||||
public final Class<? extends TemplateComposer> actionPaneComposer;
|
||||
public final Class<? extends RestCall<?>> restCallType;
|
||||
public final ActionDefinition activityAlias;
|
||||
public final String category;
|
||||
public final boolean readonly;
|
||||
|
@ -160,13 +219,7 @@ public enum ActionDefinition {
|
|||
final LocTextKey title,
|
||||
final Class<? extends TemplateComposer> contentPaneComposer) {
|
||||
|
||||
this.title = title;
|
||||
this.icon = null;
|
||||
this.contentPaneComposer = contentPaneComposer;
|
||||
this.actionPaneComposer = ActionPane.class;
|
||||
this.activityAlias = null;
|
||||
this.category = null;
|
||||
this.readonly = true;
|
||||
this(title, null, contentPaneComposer, ActionPane.class, null, null, null, true);
|
||||
}
|
||||
|
||||
private ActionDefinition(
|
||||
|
@ -174,13 +227,7 @@ public enum ActionDefinition {
|
|||
final Class<? extends TemplateComposer> contentPaneComposer,
|
||||
final ActionDefinition activityAlias) {
|
||||
|
||||
this.title = title;
|
||||
this.icon = null;
|
||||
this.contentPaneComposer = contentPaneComposer;
|
||||
this.actionPaneComposer = ActionPane.class;
|
||||
this.activityAlias = activityAlias;
|
||||
this.category = null;
|
||||
this.readonly = true;
|
||||
this(title, null, contentPaneComposer, ActionPane.class, null, activityAlias, null, true);
|
||||
}
|
||||
|
||||
private ActionDefinition(
|
||||
|
@ -189,13 +236,17 @@ public enum ActionDefinition {
|
|||
final Class<? extends TemplateComposer> contentPaneComposer,
|
||||
final ActionDefinition activityAlias) {
|
||||
|
||||
this.title = title;
|
||||
this.icon = icon;
|
||||
this.contentPaneComposer = contentPaneComposer;
|
||||
this.actionPaneComposer = ActionPane.class;
|
||||
this.activityAlias = activityAlias;
|
||||
this.category = null;
|
||||
this.readonly = true;
|
||||
this(title, icon, contentPaneComposer, ActionPane.class, null, activityAlias, null, true);
|
||||
}
|
||||
|
||||
private ActionDefinition(
|
||||
final LocTextKey title,
|
||||
final ImageIcon icon,
|
||||
final Class<? extends TemplateComposer> contentPaneComposer,
|
||||
final Class<? extends RestCall<?>> restCallType,
|
||||
final ActionDefinition activityAlias) {
|
||||
|
||||
this(title, icon, contentPaneComposer, ActionPane.class, restCallType, activityAlias, null, true);
|
||||
}
|
||||
|
||||
private ActionDefinition(
|
||||
|
@ -205,12 +256,26 @@ public enum ActionDefinition {
|
|||
final ActionDefinition activityAlias,
|
||||
final boolean readonly) {
|
||||
|
||||
this(title, icon, contentPaneComposer, ActionPane.class, null, activityAlias, null, readonly);
|
||||
}
|
||||
|
||||
private ActionDefinition(
|
||||
final LocTextKey title,
|
||||
final ImageIcon icon,
|
||||
final Class<? extends TemplateComposer> contentPaneComposer,
|
||||
final Class<? extends TemplateComposer> actionPaneComposer,
|
||||
final Class<? extends RestCall<?>> restCallType,
|
||||
final ActionDefinition activityAlias,
|
||||
final String category,
|
||||
final boolean readonly) {
|
||||
|
||||
this.title = title;
|
||||
this.icon = icon;
|
||||
this.contentPaneComposer = contentPaneComposer;
|
||||
this.actionPaneComposer = ActionPane.class;
|
||||
this.actionPaneComposer = actionPaneComposer;
|
||||
this.restCallType = restCallType;
|
||||
this.activityAlias = activityAlias;
|
||||
this.category = null;
|
||||
this.category = category;
|
||||
this.readonly = readonly;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
|
|||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
|
||||
|
||||
public class FormBuilder {
|
||||
|
||||
|
@ -212,10 +213,10 @@ public class FormBuilder {
|
|||
|
||||
Label labelLocalized(final Composite parent, final String locTextKey, final int hspan) {
|
||||
final Label label = this.widgetFactory.labelLocalized(parent, locTextKey);
|
||||
final GridData gridData = new GridData(SWT.RIGHT, SWT.TOP, true, false, hspan, 1);
|
||||
final GridData gridData = new GridData(SWT.LEFT, SWT.TOP, true, false, hspan, 1);
|
||||
gridData.verticalIndent = 4;
|
||||
label.setLayoutData(gridData);
|
||||
label.setData(RWT.CUSTOM_VARIANT, "head");
|
||||
label.setData(RWT.CUSTOM_VARIANT, CustomVariant.TITLE_LABEL.key);
|
||||
return label;
|
||||
}
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ public final class SelectionFieldBuilder extends FieldBuilder {
|
|||
if (this.multi) {
|
||||
final Composite composite = new Composite(builder.formParent, SWT.NONE);
|
||||
final GridLayout gridLayout = new GridLayout(1, true);
|
||||
gridLayout.verticalSpacing = 1;
|
||||
gridLayout.horizontalSpacing = 0;
|
||||
gridLayout.marginLeft = 0;
|
||||
gridLayout.marginHeight = 0;
|
||||
gridLayout.marginWidth = 0;
|
||||
|
@ -119,7 +119,7 @@ public final class SelectionFieldBuilder extends FieldBuilder {
|
|||
|
||||
private Label buildReadonlyLabel(final Composite composite, final String valueKey, final int hspan) {
|
||||
final Label label = new Label(composite, SWT.NONE);
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.CENTER, true, false, hspan, 1);
|
||||
final GridData gridData = new GridData(SWT.LEFT, SWT.CENTER, true, false, hspan, 1);
|
||||
gridData.verticalIndent = 0;
|
||||
gridData.horizontalIndent = 0;
|
||||
label.setLayoutData(gridData);
|
||||
|
|
|
@ -11,18 +11,23 @@ package ch.ethz.seb.sebserver.gui.service.i18n.impl;
|
|||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Locale;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.rap.rwt.RWT;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
|
||||
|
@ -40,24 +45,44 @@ public class I18nSupportImpl implements I18nSupport {
|
|||
private final CurrentUser currentUser;
|
||||
private final MessageSource messageSource;
|
||||
private final Locale defaultLocale = Locale.ENGLISH;
|
||||
private final Collection<Locale> supportedLanguages;
|
||||
|
||||
public I18nSupportImpl(
|
||||
final CurrentUser currentUser,
|
||||
final MessageSource messageSource,
|
||||
@Value("${sebserver.gui.date.displayformat}") final String displayDateFormat) {
|
||||
final Environment environment) {
|
||||
|
||||
this.currentUser = currentUser;
|
||||
this.messageSource = messageSource;
|
||||
this.displayDateFormatter = DateTimeFormat
|
||||
.forPattern(displayDateFormat)
|
||||
.forPattern(environment.getProperty(
|
||||
"sebserver.gui.date.displayformat",
|
||||
Constants.DEFAULT_DATE_FORMAT))
|
||||
.withZoneUTC();
|
||||
}
|
||||
|
||||
private static final Collection<Locale> SUPPORTED_LANGUAGES = Arrays.asList(Locale.ENGLISH, Locale.GERMAN);
|
||||
final boolean multilingual = BooleanUtils.toBoolean(environment.getProperty(
|
||||
"sebserver.gui.multilingual",
|
||||
"false"));
|
||||
if (multilingual) {
|
||||
final String languagesString = environment.getProperty(
|
||||
"sebserver.gui.languages",
|
||||
Locale.ENGLISH.getLanguage());
|
||||
|
||||
this.supportedLanguages = Utils.immutableCollectionOf(
|
||||
Arrays.asList(StringUtils.split(languagesString, Constants.LIST_SEPARATOR))
|
||||
.stream()
|
||||
.map(s -> Locale.forLanguageTag(s))
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
} else {
|
||||
this.supportedLanguages = Utils.immutableCollectionOf(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Locale> supportedLanguages() {
|
||||
return SUPPORTED_LANGUAGES;
|
||||
return this.supportedLanguages;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -8,16 +8,36 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.gui.service.page;
|
||||
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
|
||||
public class PageMessageException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = -6967378384991469166L;
|
||||
|
||||
private final LocTextKey textKey;
|
||||
|
||||
public PageMessageException(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
this.textKey = new LocTextKey(message);
|
||||
}
|
||||
|
||||
public PageMessageException(final String message) {
|
||||
super(message);
|
||||
this.textKey = new LocTextKey(message);
|
||||
}
|
||||
|
||||
public PageMessageException(final LocTextKey message, final Throwable cause) {
|
||||
super(message.name, cause);
|
||||
this.textKey = message;
|
||||
}
|
||||
|
||||
public PageMessageException(final LocTextKey message) {
|
||||
super(message.name);
|
||||
this.textKey = message;
|
||||
}
|
||||
|
||||
public LocTextKey getMessageKey() {
|
||||
return this.textKey;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,11 +13,9 @@ import java.util.function.BooleanSupplier;
|
|||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
|
@ -28,9 +26,6 @@ import ch.ethz.seb.sebserver.gui.service.page.PageMessageException;
|
|||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionPublishEvent;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCallError;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.ActivateInstitution;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.DeactivateInstitution;
|
||||
|
||||
public final class Action implements Runnable {
|
||||
|
||||
|
@ -39,9 +34,9 @@ public final class Action implements Runnable {
|
|||
public final ActionDefinition definition;
|
||||
Supplier<LocTextKey> confirm;
|
||||
LocTextKey successMessage;
|
||||
boolean updateOnSelection;
|
||||
|
||||
Supplier<Set<EntityKey>> selectionSupplier;
|
||||
LocTextKey noSelectionMessage;
|
||||
|
||||
private final PageContext originalPageContext;
|
||||
private PageContext pageContext;
|
||||
|
@ -104,9 +99,14 @@ public final class Action implements Runnable {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Action withSelect(final Supplier<Set<EntityKey>> selectionSupplier, final Function<Action, Action> exec) {
|
||||
public Action withSelect(
|
||||
final Supplier<Set<EntityKey>> selectionSupplier,
|
||||
final Function<Action, Action> exec,
|
||||
final LocTextKey noSelectionMessage) {
|
||||
|
||||
this.selectionSupplier = selectionSupplier;
|
||||
this.exec = exec;
|
||||
this.noSelectionMessage = noSelectionMessage;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -125,11 +125,6 @@ public final class Action implements Runnable {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Action withUpdateOnSelection() {
|
||||
this.updateOnSelection = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Action resetEntityKey() {
|
||||
this.pageContext = this.pageContext.withEntityKey(null);
|
||||
return this;
|
||||
|
@ -193,8 +188,8 @@ public final class Action implements Runnable {
|
|||
return this.originalPageContext;
|
||||
}
|
||||
|
||||
public EntityKey getSingleSelection(final String messageOnEmptySelection) {
|
||||
final Set<EntityKey> selection = getMultiSelection(messageOnEmptySelection);
|
||||
public EntityKey getSingleSelection() {
|
||||
final Set<EntityKey> selection = getMultiSelection();
|
||||
if (selection != null) {
|
||||
return selection.iterator().next();
|
||||
}
|
||||
|
@ -202,12 +197,12 @@ public final class Action implements Runnable {
|
|||
return null;
|
||||
}
|
||||
|
||||
public Set<EntityKey> getMultiSelection(final String messageOnEmptySelection) {
|
||||
public Set<EntityKey> getMultiSelection() {
|
||||
if (this.selectionSupplier != null) {
|
||||
final Set<EntityKey> selection = this.selectionSupplier.get();
|
||||
if (selection.isEmpty()) {
|
||||
if (StringUtils.isNoneBlank(messageOnEmptySelection)) {
|
||||
throw new PageMessageException(messageOnEmptySelection);
|
||||
if (this.noSelectionMessage != null) {
|
||||
throw new PageMessageException(this.noSelectionMessage);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -216,26 +211,15 @@ public final class Action implements Runnable {
|
|||
return selection;
|
||||
}
|
||||
|
||||
if (StringUtils.isNoneBlank(messageOnEmptySelection)) {
|
||||
throw new PageMessageException(messageOnEmptySelection);
|
||||
if (this.noSelectionMessage != null) {
|
||||
throw new PageMessageException(this.noSelectionMessage);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Function<Action, Action> applySingleSelection(final String messageOnEmptySelection) {
|
||||
return action -> action.withEntityKey(action.getSingleSelection(messageOnEmptySelection));
|
||||
}
|
||||
|
||||
public static Function<Action, Action> activation(final RestService restService, final boolean activate) {
|
||||
return action -> restService
|
||||
.getBuilder((activate) ? ActivateInstitution.class : DeactivateInstitution.class)
|
||||
.withURIVariable(
|
||||
API.PARAM_MODEL_ID,
|
||||
action.pageContext().getAttribute(AttributeKeys.ENTITY_ID))
|
||||
.call()
|
||||
.map(report -> action)
|
||||
.getOrThrow();
|
||||
public static Action applySingleSelection(final Action action) {
|
||||
return action.withEntityKey(action.getSingleSelection());
|
||||
}
|
||||
|
||||
public static Action onEmptyEntityKeyGoToActivityHome(final Action action) {
|
||||
|
|
|
@ -12,6 +12,7 @@ import java.io.ByteArrayInputStream;
|
|||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64InputStream;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.rap.rwt.RWT;
|
||||
import org.eclipse.swt.SWT;
|
||||
|
@ -25,8 +26,8 @@ import org.eclipse.swt.widgets.Label;
|
|||
import org.eclipse.swt.widgets.MessageBox;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
|
@ -50,17 +51,19 @@ public class DefaultPageLayout implements TemplateComposer {
|
|||
private final PolyglotPageService polyglotPageService;
|
||||
private final AuthorizationContextHolder authorizationContextHolder;
|
||||
private final String sebServerVersion;
|
||||
private final boolean multilingual;
|
||||
|
||||
public DefaultPageLayout(
|
||||
final WidgetFactory widgetFactory,
|
||||
final PolyglotPageService polyglotPageService,
|
||||
final AuthorizationContextHolder authorizationContextHolder,
|
||||
@Value("${sebserver.version}") final String sebServerVersion) {
|
||||
final Environment environment) {
|
||||
|
||||
this.widgetFactory = widgetFactory;
|
||||
this.polyglotPageService = polyglotPageService;
|
||||
this.authorizationContextHolder = authorizationContextHolder;
|
||||
this.sebServerVersion = sebServerVersion;
|
||||
this.sebServerVersion = environment.getProperty("sebserver.version", "--");
|
||||
this.multilingual = BooleanUtils.toBoolean(environment.getProperty("sebserver.gui.multilingual", "false"));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -182,7 +185,9 @@ public class DefaultPageLayout implements TemplateComposer {
|
|||
rowLayout.marginRight = 70;
|
||||
langSupport.setLayout(rowLayout);
|
||||
|
||||
this.widgetFactory.createLanguageSelector(pageContext.copyOf(langSupport));
|
||||
if (this.multilingual) {
|
||||
this.widgetFactory.createLanguageSelector(pageContext.copyOf(langSupport));
|
||||
}
|
||||
}
|
||||
|
||||
private void composeContent(final PageContext pageContext) {
|
||||
|
|
|
@ -289,7 +289,7 @@ public class PageContextImpl implements PageContext {
|
|||
final MessageBox messageBox = new Message(
|
||||
getShell(),
|
||||
this.i18nSupport.getText("sebserver.page.message"),
|
||||
this.i18nSupport.getText(pme.getMessage()),
|
||||
this.i18nSupport.getText(pme.getMessageKey()),
|
||||
SWT.NONE);
|
||||
messageBox.setMarkupEnabled(true);
|
||||
messageBox.open(null);
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.remote;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.rap.rwt.service.ServiceHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
|
||||
@Lazy
|
||||
@Service
|
||||
@GuiProfile
|
||||
public class DownloadService implements ServiceHandler {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(DownloadService.class);
|
||||
|
||||
public static final String DOWNLOAD_SERVICE_NAME = "DOWNLOAD_SERVICE";
|
||||
public static final String HANDLER_NAME_PARAMETER = "download-handler-name";
|
||||
|
||||
private final Map<String, DownloadServiceHandler> handler;
|
||||
|
||||
protected DownloadService(final Collection<DownloadServiceHandler> handler) {
|
||||
this.handler = handler
|
||||
.stream()
|
||||
.collect(Collectors.toMap(h -> h.getName(), Function.identity()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void service(
|
||||
final HttpServletRequest request,
|
||||
final HttpServletResponse response) throws IOException, ServletException {
|
||||
|
||||
log.debug("Received download service request: {}", request.getRequestURI());
|
||||
|
||||
final String handlerName = request.getParameter(HANDLER_NAME_PARAMETER);
|
||||
if (StringUtils.isBlank(handlerName)) {
|
||||
log.error("Missing request parameter {}. Ignoring download service request",
|
||||
HANDLER_NAME_PARAMETER);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.handler.containsKey(handlerName)) {
|
||||
log.error("Missing DownloadServiceHandler with name {}. Ignoring download service request",
|
||||
handlerName);
|
||||
return;
|
||||
}
|
||||
|
||||
this.handler
|
||||
.get(handlerName)
|
||||
.processDownload(request, response);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.remote;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
public interface DownloadServiceHandler {
|
||||
|
||||
String getName();
|
||||
|
||||
void processDownload(final HttpServletRequest request, final HttpServletResponse response);
|
||||
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.remote;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.rap.rwt.RWT;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.ExportSEBConfig;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class SebClientConfigDownload implements DownloadServiceHandler {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(SebClientConfigDownload.class);
|
||||
|
||||
// TODO must this be configurable?
|
||||
public static final String SEB_CLIENT_CONFIG_FILE_NAME = "SebClientSettings.seb";
|
||||
|
||||
private final RestService restService;
|
||||
|
||||
protected SebClientConfigDownload(final RestService restService) {
|
||||
this.restService = restService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return SEB_CLIENT_CONFIG_FILE_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processDownload(final HttpServletRequest request, final HttpServletResponse response) {
|
||||
try {
|
||||
|
||||
log.debug("download requested... trying to get needed parameter from request");
|
||||
|
||||
final String modelId = request.getParameter(API.PARAM_MODEL_ID);
|
||||
if (StringUtils.isBlank(modelId)) {
|
||||
log.error("No needed modelId parameter found within HttpServletRequest. Download request is ignored");
|
||||
return;
|
||||
}
|
||||
|
||||
log.debug("Found modelId: {} for {} download. Trying to request webservice...", modelId,
|
||||
SEB_CLIENT_CONFIG_FILE_NAME);
|
||||
|
||||
final byte[] configFile = this.restService.getBuilder(ExportSEBConfig.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, modelId)
|
||||
.call()
|
||||
.getOrThrow();
|
||||
|
||||
if (configFile == null) {
|
||||
log.error("No or empty SEB Client configuration received from webservice. Download request is ignored");
|
||||
return;
|
||||
}
|
||||
|
||||
log.debug("Sucessfully get SEB Client configuration from webservice. File size: {}", configFile.length);
|
||||
|
||||
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
|
||||
response.setContentLength(configFile.length);
|
||||
response.setHeader(
|
||||
HttpHeaders.CONTENT_DISPOSITION,
|
||||
"attachment; filename=\"" + SEB_CLIENT_CONFIG_FILE_NAME + "\"");
|
||||
|
||||
log.debug("Write the SEB Client configuration to response output");
|
||||
|
||||
response.getOutputStream().write(configFile);
|
||||
|
||||
} catch (final Exception e) {
|
||||
log.error(
|
||||
"Unexpected error while trying to start SEB Client configuration download. The download is ignored. Cause: ",
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
public String downloadSEBClientConfigURL(final String modelId) {
|
||||
final StringBuilder url = new StringBuilder()
|
||||
.append(RWT.getServiceManager()
|
||||
.getServiceHandlerUrl(DownloadService.DOWNLOAD_SERVICE_NAME))
|
||||
.append(Constants.FORM_URL_ENCODED_SEPARATOR)
|
||||
.append(API.PARAM_MODEL_ID)
|
||||
.append(Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR)
|
||||
.append(modelId)
|
||||
.append(Constants.FORM_URL_ENCODED_SEPARATOR)
|
||||
.append(DownloadService.HANDLER_NAME_PARAMETER)
|
||||
.append(Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR)
|
||||
.append(SebClientConfigDownload.SEB_CLIENT_CONFIG_FILE_NAME);
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -33,14 +33,15 @@ import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
|||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Page;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService.SortOrder;
|
||||
|
||||
public abstract class RestCall<T> {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(RestCall.class);
|
||||
|
||||
private RestService restService;
|
||||
private JSONMapper jsonMapper;
|
||||
protected RestService restService;
|
||||
protected JSONMapper jsonMapper;
|
||||
protected final TypeReference<T> typeRef;
|
||||
protected final HttpMethod httpMethod;
|
||||
protected final MediaType contentType;
|
||||
|
@ -226,14 +227,14 @@ public abstract class RestCall<T> {
|
|||
return RestCall.this.exchange(this);
|
||||
}
|
||||
|
||||
protected String buildURI() {
|
||||
public String buildURI() {
|
||||
return RestCall.this.restService.getWebserviceURIBuilder()
|
||||
.path(RestCall.this.path)
|
||||
.queryParams(this.queryParams)
|
||||
.toUriString();
|
||||
}
|
||||
|
||||
protected HttpEntity<?> buildRequestEntity() {
|
||||
public HttpEntity<?> buildRequestEntity() {
|
||||
if (this.body != null) {
|
||||
return new HttpEntity<>(this.body, this.httpHeaders);
|
||||
} else {
|
||||
|
@ -241,6 +242,10 @@ public abstract class RestCall<T> {
|
|||
}
|
||||
}
|
||||
|
||||
public Map<String, String> getURIVariables() {
|
||||
return Utils.immutableMapOf(this.uriVariables);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RestCallBuilder [httpHeaders=" + this.httpHeaders + ", body=" + this.body + ", queryParams="
|
||||
|
|
|
@ -17,8 +17,11 @@ import org.springframework.stereotype.Service;
|
|||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.action.Action;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.WebserviceURIService;
|
||||
|
||||
|
@ -72,4 +75,18 @@ public class RestService {
|
|||
return restCall.newBuilder();
|
||||
}
|
||||
|
||||
public Action activation(final Action action) {
|
||||
if (action.definition.restCallType == null) {
|
||||
throw new IllegalArgumentException("ActionDefinition needs to define a restCallType to use this action");
|
||||
}
|
||||
|
||||
return this.getBuilder(action.definition.restCallType)
|
||||
.withURIVariable(
|
||||
API.PARAM_MODEL_ID,
|
||||
action.pageContext().getAttribute(AttributeKeys.ENTITY_ID))
|
||||
.call()
|
||||
.map(report -> action)
|
||||
.getOrThrow();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup;
|
||||
|
||||
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.model.EntityProcessingReport;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class ActivateLmsSetup extends RestCall<EntityProcessingReport> {
|
||||
|
||||
protected ActivateLmsSetup() {
|
||||
super(
|
||||
new TypeReference<EntityProcessingReport>() {
|
||||
},
|
||||
HttpMethod.POST,
|
||||
MediaType.APPLICATION_FORM_URLENCODED,
|
||||
API.LMS_SETUP_ENDPOINT + API.PATH_VAR_ACTIVE);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup;
|
||||
|
||||
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.model.EntityProcessingReport;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class DeactivateLmsSetup extends RestCall<EntityProcessingReport> {
|
||||
|
||||
protected DeactivateLmsSetup() {
|
||||
super(
|
||||
new TypeReference<EntityProcessingReport>() {
|
||||
},
|
||||
HttpMethod.POST,
|
||||
MediaType.APPLICATION_FORM_URLENCODED,
|
||||
API.LMS_SETUP_ENDPOINT + API.PATH_VAR_INACTIVE);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup;
|
||||
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
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.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class ExportSEBConfig extends RestCall<byte[]> {
|
||||
|
||||
protected ExportSEBConfig() {
|
||||
super(
|
||||
new TypeReference<byte[]>() {
|
||||
},
|
||||
HttpMethod.GET,
|
||||
MediaType.APPLICATION_FORM_URLENCODED,
|
||||
API.SEB_CONFIG_EXPORT_ENDPOINT + API.MODEL_ID_VAR_PATH_SEGMENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<byte[]> exchange(final RestCallBuilder builder) {
|
||||
try {
|
||||
final ResponseEntity<byte[]> responseEntity = this.restService
|
||||
.getWebserviceAPIRestTemplate()
|
||||
.exchange(
|
||||
builder.buildURI(),
|
||||
this.httpMethod,
|
||||
builder.buildRequestEntity(),
|
||||
byte[].class,
|
||||
builder.getURIVariables());
|
||||
|
||||
if (responseEntity.getStatusCode() == HttpStatus.OK) {
|
||||
return Result.of(responseEntity.getBody());
|
||||
}
|
||||
|
||||
return Result.ofRuntimeError(
|
||||
"Error while trying to export SEB Config from webservice. Response: " + responseEntity);
|
||||
} catch (final Throwable t) {
|
||||
return Result.ofError(t);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup;
|
||||
|
||||
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.model.institution.LmsSetup;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class NewLmsSetup extends RestCall<LmsSetup> {
|
||||
|
||||
protected NewLmsSetup() {
|
||||
super(
|
||||
new TypeReference<LmsSetup>() {
|
||||
},
|
||||
HttpMethod.POST,
|
||||
MediaType.APPLICATION_FORM_URLENCODED,
|
||||
API.LMS_SETUP_ENDPOINT);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup;
|
||||
|
||||
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.model.institution.LmsSetup;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class SaveLmsSetup extends RestCall<LmsSetup> {
|
||||
|
||||
protected SaveLmsSetup() {
|
||||
super(
|
||||
new TypeReference<LmsSetup>() {
|
||||
},
|
||||
HttpMethod.PUT,
|
||||
MediaType.APPLICATION_JSON_UTF8,
|
||||
API.LMS_SETUP_ENDPOINT);
|
||||
}
|
||||
}
|
|
@ -109,9 +109,13 @@ public class TableNavigator {
|
|||
final Label forward = new Label(parent, SWT.NONE);
|
||||
forward.setText(">");
|
||||
forward.setData(RWT.CUSTOM_VARIANT, "action");
|
||||
forward.addListener(SWT.MouseDown, event -> {
|
||||
this.entityTable.selectPage(pageNumber + 1);
|
||||
});
|
||||
if (visible) {
|
||||
forward.addListener(SWT.MouseDown, event -> {
|
||||
this.entityTable.selectPage(pageNumber + 1);
|
||||
});
|
||||
} else {
|
||||
forward.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void createBackwardLabel(
|
||||
|
|
|
@ -106,6 +106,7 @@ public class WidgetFactory {
|
|||
SELECTION_READONLY("selectionReadonly"),
|
||||
|
||||
FOOTER("footer"),
|
||||
TITLE_LABEL("head")
|
||||
|
||||
;
|
||||
|
||||
|
|
|
@ -8,10 +8,14 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.webservice;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
|
@ -19,11 +23,15 @@ import org.springframework.context.annotation.Bean;
|
|||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.security.oauth2.provider.token.TokenStore;
|
||||
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
|
||||
// TODO check if DataSourceAutoConfiguration and TokenStore bean definition is really needed here
|
||||
// or if it is possible to move them to the WebServiceSecurityConfig.
|
||||
// test with starting web and gui separately as well as together
|
||||
@Configuration
|
||||
@WebServiceProfile
|
||||
@Import(DataSourceAutoConfiguration.class)
|
||||
|
@ -31,10 +39,26 @@ public class WebServiceInit implements ApplicationListener<ApplicationReadyEvent
|
|||
|
||||
private static final Logger log = LoggerFactory.getLogger(WebServiceInit.class);
|
||||
|
||||
@Autowired
|
||||
private Environment environment;
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(final ApplicationReadyEvent event) {
|
||||
log.info("Initialize SEB-Server Web-Service Component");
|
||||
|
||||
try {
|
||||
log.info("----> config server address: {}", this.environment.getProperty("server.address"));
|
||||
log.info("----> config server port: {}", this.environment.getProperty("server.port"));
|
||||
|
||||
log.info("----> local host address: {}", InetAddress.getLocalHost().getHostAddress());
|
||||
log.info("----> local host name: {}", InetAddress.getLocalHost().getHostName());
|
||||
|
||||
log.info("----> remote host address: {}", InetAddress.getLoopbackAddress().getHostAddress());
|
||||
log.info("----> remote host address: {}", InetAddress.getLoopbackAddress().getHostName());
|
||||
} catch (final UnknownHostException e) {
|
||||
log.error("Unknown Host: ", e);
|
||||
}
|
||||
|
||||
// TODO whatever has to be initialized for the web-service component right after startup comes here
|
||||
|
||||
}
|
||||
|
|
|
@ -148,10 +148,8 @@ public class LmsSetupDAOImpl implements LmsSetupDAO {
|
|||
? this.internalEncryptionService.encrypt(lmsSetup.lmsAuthSecret)
|
||||
: null,
|
||||
lmsSetup.lmsRestApiToken,
|
||||
lmsSetup.sebAuthName,
|
||||
(StringUtils.isNotBlank(lmsSetup.sebAuthSecret))
|
||||
? this.clientPasswordEncoder.encode(lmsSetup.sebAuthSecret)
|
||||
: null,
|
||||
null,
|
||||
null,
|
||||
null);
|
||||
|
||||
this.lmsSetupRecordMapper.updateByPrimaryKeySelective(newRecord);
|
||||
|
@ -173,10 +171,14 @@ public class LmsSetupDAOImpl implements LmsSetupDAO {
|
|||
(lmsSetup.lmsType != null) ? lmsSetup.lmsType.name() : null,
|
||||
lmsSetup.lmsApiUrl,
|
||||
lmsSetup.lmsAuthName,
|
||||
lmsSetup.lmsAuthSecret,
|
||||
(StringUtils.isNotBlank(lmsSetup.lmsAuthSecret))
|
||||
? this.internalEncryptionService.encrypt(lmsSetup.lmsAuthSecret)
|
||||
: null,
|
||||
lmsSetup.lmsRestApiToken,
|
||||
lmsSetup.sebAuthName,
|
||||
lmsSetup.sebAuthSecret,
|
||||
(StringUtils.isNotBlank(lmsSetup.sebAuthSecret))
|
||||
? this.internalEncryptionService.encrypt(lmsSetup.sebAuthSecret)
|
||||
: null,
|
||||
BooleanUtils.toInteger(false));
|
||||
|
||||
this.lmsSetupRecordMapper.insert(newRecord);
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
@ -97,7 +99,13 @@ public class LmsAPIServiceImpl implements LmsAPIService {
|
|||
// To Clarify : How the file should be encrypted (use case) maybe we need another encryption-secret for this that can be given by
|
||||
// an administrator on SEB start configuration creation time
|
||||
|
||||
return Result.ofTODO();
|
||||
return Result.tryCatch(() -> {
|
||||
try {
|
||||
return new ByteArrayInputStream("TODO".getBytes("UTF-8"));
|
||||
} catch (final UnsupportedEncodingException e) {
|
||||
throw new RuntimeException("cause: ", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,7 +28,6 @@ import org.springframework.http.HttpStatus;
|
|||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
|
@ -46,7 +45,7 @@ import org.springframework.security.web.AuthenticationEntryPoint;
|
|||
import ch.ethz.seb.sebserver.WebSecurityConfig;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.webservice.weblayer.oauth.WebClientDetailsService;
|
||||
import ch.ethz.seb.sebserver.webservice.weblayer.oauth.WebResourceServerConfiguration;
|
||||
import ch.ethz.seb.sebserver.webservice.weblayer.oauth.WebserviceResourceConfiguration;
|
||||
|
||||
/** This is the main web-security Spring configuration for SEB-Server webservice API
|
||||
*
|
||||
|
@ -65,13 +64,13 @@ import ch.ethz.seb.sebserver.webservice.weblayer.oauth.WebResourceServerConfigur
|
|||
* and is by default set to "/exam-api/**" */
|
||||
@WebServiceProfile
|
||||
@Configuration
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
//@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
@EnableWebSecurity
|
||||
@Order(5)
|
||||
@Import(DataSourceAutoConfiguration.class)
|
||||
public class ClientSessionWebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
public class WebServiceSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ClientSessionWebSecurityConfig.class);
|
||||
private static final Logger log = LoggerFactory.getLogger(WebServiceSecurityConfig.class);
|
||||
|
||||
/** Spring bean name of single AuthenticationManager bean */
|
||||
public static final String AUTHENTICATION_MANAGER = "AUTHENTICATION_MANAGER";
|
||||
|
@ -157,7 +156,7 @@ public class ClientSessionWebSecurityConfig extends WebSecurityConfigurerAdapter
|
|||
|
||||
// NOTE: We need two different class types here to support Spring configuration for different
|
||||
// ResourceServerConfiguration. There is a class type now for the Admin API as well as for the Exam API
|
||||
private static final class AdminAPIResourceServerConfiguration extends WebResourceServerConfiguration {
|
||||
private static final class AdminAPIResourceServerConfiguration extends WebserviceResourceConfiguration {
|
||||
|
||||
public AdminAPIResourceServerConfiguration(
|
||||
final TokenStore tokenStore,
|
||||
|
@ -180,7 +179,7 @@ public class ClientSessionWebSecurityConfig extends WebSecurityConfigurerAdapter
|
|||
|
||||
// NOTE: We need two different class types here to support Spring configuration for different
|
||||
// ResourceServerConfiguration. There is a class type now for the Admin API as well as for the Exam API
|
||||
private static final class ExamAPIClientResourceServerConfiguration extends WebResourceServerConfiguration {
|
||||
private static final class ExamAPIClientResourceServerConfiguration extends WebserviceResourceConfiguration {
|
||||
|
||||
public ExamAPIClientResourceServerConfiguration(
|
||||
final TokenStore tokenStore,
|
|
@ -139,8 +139,12 @@ public abstract class ActivatableEntityController<T extends GrantEntity, M exten
|
|||
|
||||
return this.entityDAO.byModelId(modelId)
|
||||
.flatMap(this.authorization::checkWrite)
|
||||
.flatMap(this::validForSave)
|
||||
.flatMap(this::validForActivation)
|
||||
.flatMap(entity -> this.bulkActionService.createReport(bulkAction));
|
||||
}
|
||||
|
||||
protected Result<T> validForActivation(final T entity) {
|
||||
return Result.of(entity);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -248,9 +248,8 @@ public abstract class EntityController<T extends GrantEntity, M extends GrantEnt
|
|||
|
||||
final M requestModel = this.createNew(postMap);
|
||||
|
||||
return this.beanValidationService.validateBean(requestModel)
|
||||
return this.validForCreate(requestModel)
|
||||
.flatMap(this.entityDAO::createNew)
|
||||
.flatMap(this::validForSave)
|
||||
.flatMap(this.userActivityLogDAO::logCreate)
|
||||
.flatMap(this::notifyCreated)
|
||||
.getOrThrow();
|
||||
|
@ -341,6 +340,15 @@ public abstract class EntityController<T extends GrantEntity, M extends GrantEnt
|
|||
return Result.of(entity);
|
||||
}
|
||||
|
||||
protected Result<M> validForCreate(final M entity) {
|
||||
if (entity.getModelId() == null) {
|
||||
return this.beanValidationService.validateBean(entity);
|
||||
} else {
|
||||
return Result.ofError(
|
||||
new IllegalAPIArgumentException("Model identifier already defined: " + entity.getModelId()));
|
||||
}
|
||||
}
|
||||
|
||||
protected Result<T> validForSave(final T entity) {
|
||||
if (entity.getModelId() != null) {
|
||||
return Result.of(entity);
|
||||
|
|
|
@ -11,11 +11,15 @@ package ch.ethz.seb.sebserver.webservice.weblayer.api;
|
|||
import java.io.InputStream;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.tomcat.util.http.fileupload.IOUtils;
|
||||
import org.mybatis.dynamic.sql.SqlTable;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
@ -28,6 +32,7 @@ import ch.ethz.seb.sebserver.gbl.authorization.PrivilegeType;
|
|||
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
|
||||
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetupTestResult;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.LmsSetupRecordDynamicSqlSupport;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationService;
|
||||
|
@ -35,6 +40,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionServic
|
|||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.LmsSetupDAO;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.LmsAPIService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationException;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationService;
|
||||
|
||||
@WebServiceProfile
|
||||
|
@ -74,33 +80,28 @@ public class LmsSetupController extends ActivatableEntityController<LmsSetup, Lm
|
|||
}
|
||||
|
||||
@RequestMapping(
|
||||
path = "/SEB_Configuration" + API.MODEL_ID_VAR_PATH_SEGMENT,
|
||||
path = API.SEB_CONFIG_EXPORT_PATH_SEGMENT + API.MODEL_ID_VAR_PATH_SEGMENT,
|
||||
method = RequestMethod.GET,
|
||||
produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) // TODO check if this is the right format
|
||||
public void downloadSEBConfig(
|
||||
@PathVariable final Long modelId,
|
||||
final HttpServletResponse response) {
|
||||
final HttpServletResponse response) throws Exception {
|
||||
|
||||
this.authorization.check(PrivilegeType.WRITE, EntityType.LMS_SETUP);
|
||||
|
||||
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
|
||||
response.setStatus(HttpStatus.OK.value());
|
||||
|
||||
try {
|
||||
final InputStream sebConfigFileIn = this.lmsAPIService
|
||||
.createSEBStartConfiguration(modelId)
|
||||
.getOrThrow();
|
||||
final InputStream sebConfigFileIn = this.lmsAPIService
|
||||
.createSEBStartConfiguration(modelId)
|
||||
.getOrThrow();
|
||||
|
||||
IOUtils.copyLarge(sebConfigFileIn, response.getOutputStream());
|
||||
response.flushBuffer();
|
||||
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException("Unexpected error while trying to creae SEB start config: ", e);
|
||||
}
|
||||
IOUtils.copyLarge(sebConfigFileIn, response.getOutputStream());
|
||||
response.flushBuffer();
|
||||
}
|
||||
|
||||
@RequestMapping(
|
||||
path = "/connection_report" + API.MODEL_ID_VAR_PATH_SEGMENT,
|
||||
path = API.LMS_SETUP_TEST_PATH_SEGMENT + API.MODEL_ID_VAR_PATH_SEGMENT,
|
||||
method = RequestMethod.GET,
|
||||
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public LmsSetupTestResult connectionReport(@PathVariable final Long modelId) {
|
||||
|
@ -117,4 +118,65 @@ public class LmsSetupController extends ActivatableEntityController<LmsSetup, Lm
|
|||
return new LmsSetup(null, postParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<LmsSetup> validForCreate(final LmsSetup entity) {
|
||||
|
||||
final SEBClientAuth clientAuth = new SEBClientAuth(entity.sebAuthName, entity.sebAuthSecret);
|
||||
|
||||
final Result<LmsSetup> result = super.validForCreate(entity);
|
||||
if (result.hasError()) {
|
||||
final Throwable error = result.getError();
|
||||
if (error instanceof BeanValidationException) {
|
||||
final BeanValidationException beanValidationException = (BeanValidationException) error;
|
||||
final Result<SEBClientAuth> validateSebAuth = this.beanValidationService.validateBean(clientAuth);
|
||||
if (validateSebAuth.hasError()) {
|
||||
final Throwable sebAuthError = validateSebAuth.getError();
|
||||
if (sebAuthError instanceof BeanValidationException) {
|
||||
final BindingResult bindingResult = beanValidationException.getBindingResult();
|
||||
bindingResult.addAllErrors(((BeanValidationException) sebAuthError).getBindingResult());
|
||||
return Result.ofError(new BeanValidationException(bindingResult));
|
||||
} else {
|
||||
return validateSebAuth
|
||||
.map(ce -> entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
return this.beanValidationService.validateBean(clientAuth)
|
||||
.map(ca -> entity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<LmsSetup> validForSave(final LmsSetup entity) {
|
||||
return super.validForSave(entity)
|
||||
.map(setup -> {
|
||||
|
||||
if (StringUtils.isNoneBlank(entity.sebAuthName)
|
||||
|| StringUtils.isNoneBlank(entity.sebAuthSecret)) {
|
||||
|
||||
throw new IllegalAPIArgumentException(
|
||||
"SEB Client Authentication cannot be changed after creation");
|
||||
}
|
||||
return setup;
|
||||
});
|
||||
}
|
||||
|
||||
public static final class SEBClientAuth {
|
||||
|
||||
@NotNull(message = "lmsSetup:sebClientname:notNull")
|
||||
@Size(min = 3, max = 255, message = "lmsSetup:sebClientname:size:{min}:{max}:${validatedValue}")
|
||||
public final String sebAuthName;
|
||||
|
||||
@NotNull(message = "lmsSetup:sebClientsecret:notNull")
|
||||
@Size(min = 8, max = 255, message = "lmsSetup:sebClientsecret:size:{min}:{max}:${validatedValue}")
|
||||
public final String sebAuthSecret;
|
||||
|
||||
protected SEBClientAuth(final String authName, final String authSecret) {
|
||||
this.sebAuthName = authName;
|
||||
this.sebAuthSecret = authSecret;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
|||
import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.PasswordChange;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserAccount;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserMod;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||
|
@ -113,15 +114,53 @@ public class UserAccountController extends ActivatableEntityController<UserInfo,
|
|||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
private UserInfo checkPasswordChange(final UserInfo info, final PasswordChange passwordChange) {
|
||||
final SEBServerUser authUser = this.userDAO.sebServerUserByUsername(info.username)
|
||||
.getOrThrow();
|
||||
|
||||
if (!this.userPasswordEncoder.matches(passwordChange.getOldPassword(), authUser.getPassword())) {
|
||||
throw new APIMessageException(APIMessage.fieldValidationError(
|
||||
new FieldError(
|
||||
"passwordChange",
|
||||
PasswordChange.ATTR_NAME_OLD_PASSWORD,
|
||||
"user:oldPassword:password.wrong")));
|
||||
}
|
||||
|
||||
if (!passwordChange.newPasswordMatch()) {
|
||||
|
||||
throw new APIMessageException(APIMessage.fieldValidationError(
|
||||
new FieldError(
|
||||
"passwordChange",
|
||||
PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD,
|
||||
"user:retypedNewPassword:password.mismatch")));
|
||||
}
|
||||
|
||||
return info;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<UserMod> validForCreate(final UserMod userInfo) {
|
||||
return super.validForCreate(userInfo)
|
||||
.flatMap(this::additionalConsistencyChecks);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<UserInfo> validForSave(final UserInfo userInfo) {
|
||||
return super.validForSave(userInfo)
|
||||
.flatMap(this::additionalConsistencyChecks);
|
||||
}
|
||||
|
||||
/** Additional consistency checks that has to be checked before create and save actions */
|
||||
private <T extends UserAccount> Result<T> additionalConsistencyChecks(final T userInfo) {
|
||||
return Result.tryCatch(() -> {
|
||||
final SEBServerUser currentUser = this.authorization.getUserService().getCurrentUser();
|
||||
final EnumSet<UserRole> rolesOfCurrentUser = currentUser.getUserRoles();
|
||||
final EnumSet<UserRole> userRolesOfAccount = userInfo.getUserRoles();
|
||||
|
||||
// check of institution of UserInfo is active. Otherwise save is not valid
|
||||
if (!this.beanValidationService.isActive(new EntityKey(userInfo.institutionId, EntityType.INSTITUTION))) {
|
||||
if (!this.beanValidationService
|
||||
.isActive(new EntityKey(userInfo.getInstitutionId(), EntityType.INSTITUTION))) {
|
||||
throw new IllegalAPIArgumentException(
|
||||
"User within an inactive institution cannot be created nor modified");
|
||||
}
|
||||
|
@ -174,31 +213,6 @@ public class UserAccountController extends ActivatableEntityController<UserInfo,
|
|||
.getOrThrow();
|
||||
}
|
||||
|
||||
private UserInfo checkPasswordChange(final UserInfo info, final PasswordChange passwordChange) {
|
||||
final SEBServerUser authUser = this.userDAO.sebServerUserByUsername(info.username)
|
||||
.getOrThrow();
|
||||
|
||||
if (!this.userPasswordEncoder.matches(passwordChange.getOldPassword(), authUser.getPassword())) {
|
||||
throw new APIMessageException(APIMessage.fieldValidationError(
|
||||
new FieldError(
|
||||
"passwordChange",
|
||||
PasswordChange.ATTR_NAME_OLD_PASSWORD,
|
||||
"user:oldPassword:password.wrong")));
|
||||
}
|
||||
|
||||
if (!passwordChange.newPasswordMatch()) {
|
||||
|
||||
throw new APIMessageException(APIMessage.fieldValidationError(
|
||||
new FieldError(
|
||||
"passwordChange",
|
||||
PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD,
|
||||
"user:retypedNewPassword:password.mismatch")));
|
||||
}
|
||||
|
||||
return info;
|
||||
|
||||
}
|
||||
|
||||
private Result<UserInfo> revokeAccessToken(final UserInfo userInfo) {
|
||||
return Result.tryCatch(() -> {
|
||||
this.applicationEventPublisher.publishEvent(
|
||||
|
|
|
@ -33,7 +33,7 @@ public final class AdminAPIClientDetails extends BaseClientDetails {
|
|||
|
||||
super(
|
||||
clientId,
|
||||
WebResourceServerConfiguration.ADMIN_API_RESOURCE_ID,
|
||||
WebserviceResourceConfiguration.ADMIN_API_RESOURCE_ID,
|
||||
"read,write",
|
||||
"password,refresh_token",
|
||||
null);
|
||||
|
|
|
@ -25,7 +25,7 @@ import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenCo
|
|||
|
||||
import ch.ethz.seb.sebserver.WebSecurityConfig;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.webservice.weblayer.ClientSessionWebSecurityConfig;
|
||||
import ch.ethz.seb.sebserver.webservice.weblayer.WebServiceSecurityConfig;
|
||||
import ch.ethz.seb.sebserver.webservice.weblayer.WebServiceUserDetails;
|
||||
|
||||
/** This is the main Spring configuration of OAuth2 Authorization Server.
|
||||
|
@ -52,7 +52,7 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap
|
|||
@Qualifier(WebSecurityConfig.CLIENT_PASSWORD_ENCODER_BEAN_NAME)
|
||||
private PasswordEncoder clientPasswordEncoder;
|
||||
@Autowired
|
||||
@Qualifier(ClientSessionWebSecurityConfig.AUTHENTICATION_MANAGER)
|
||||
@Qualifier(WebServiceSecurityConfig.AUTHENTICATION_MANAGER)
|
||||
private AuthenticationManager authenticationManager;
|
||||
|
||||
@Override
|
||||
|
|
|
@ -75,7 +75,7 @@ public class WebClientDetailsService implements ClientDetailsService {
|
|||
if ("test".equals(clientId)) {
|
||||
final BaseClientDetails baseClientDetails = new BaseClientDetails(
|
||||
clientId,
|
||||
WebResourceServerConfiguration.EXAM_API_RESOURCE_ID,
|
||||
WebserviceResourceConfiguration.EXAM_API_RESOURCE_ID,
|
||||
null,
|
||||
"client_credentials,refresh_token",
|
||||
"");
|
||||
|
|
|
@ -24,14 +24,14 @@ import org.springframework.security.web.AuthenticationEntryPoint;
|
|||
|
||||
/** Abstract Spring ResourceServerConfiguration to configure different resource services
|
||||
* for different API's. */
|
||||
public abstract class WebResourceServerConfiguration extends ResourceServerConfiguration {
|
||||
public abstract class WebserviceResourceConfiguration extends ResourceServerConfiguration {
|
||||
|
||||
/** The resource identifier of Administration API resources */
|
||||
public static final String ADMIN_API_RESOURCE_ID = "seb-server-administration-api";
|
||||
/** The resource identifier of the Exam API resources */
|
||||
public static final String EXAM_API_RESOURCE_ID = "seb-server-exam-api";
|
||||
|
||||
public WebResourceServerConfiguration(
|
||||
public WebserviceResourceConfiguration(
|
||||
final TokenStore tokenStore,
|
||||
final WebClientDetailsService webServiceClientDetails,
|
||||
final AuthenticationManager authenticationManager,
|
|
@ -15,4 +15,6 @@ sebserver.gui.webservice.apipath=/admin-api/v1
|
|||
sebserver.gui.theme=css/sebserver.css
|
||||
sebserver.gui.list.page.size=20
|
||||
sebserver.gui.date.displayformat=EEEE, dd MMMM yyyy - HH:mm
|
||||
sebserver.gui.multilingual=true
|
||||
sebserver.gui.languages=en,de
|
||||
|
||||
|
|
|
@ -147,14 +147,36 @@ sebserver.lmssetup.type.MOODLE=Moodle
|
|||
sebserver.lmssetup.type.OPEN_EDX=Open edX
|
||||
|
||||
sebserver.lmssetup.list.empty=No LMS Setup has been found. Please adapt the filter or create a new LMS Setup
|
||||
sebserver.lmssetup.list.title=LMS Setup
|
||||
sebserver.lmssetup.list.title=Learning Management System Setups
|
||||
sebserver.lmssetup.list.column.institution=Institution
|
||||
sebserver.lmssetup.list.column.name=Name
|
||||
sebserver.lmssetup.list.column.type=LMS Type
|
||||
sebserver.lmssetup.list.column.active=Active
|
||||
|
||||
sebserver.lmssetup.action.list=LMS Setups
|
||||
sebserver.lmssetup.action.list=LMS Setup
|
||||
sebserver.lmssetup.action.form=LMS Setup
|
||||
sebserver.lmssetup.action.new=New LMS Setup
|
||||
sebserver.lmssetup.action.list.view=View Selected
|
||||
sebserver.lmssetup.action.list.modify=Edit Selected
|
||||
sebserver.lmssetup.action.modify=Edit
|
||||
sebserver.lmssetup.action.save=Save LMS Setup
|
||||
sebserver.lmssetup.action.activate=Active
|
||||
sebserver.lmssetup.action.deactivate=Active
|
||||
sebserver.lmssetup.action.delete=Delete LMS Setup
|
||||
sebserver.lmssetup.action.export.sebconfig=Export SEB-Client Config
|
||||
|
||||
sebserver.lmssetup.info.pleaseSelect=Please Select a LMS Setup first
|
||||
|
||||
sebserver.lmssetup.form.title=Learning Management System Setup
|
||||
sebserver.lmssetup.form.title.new=New Learning Management System Setup
|
||||
sebserver.lmssetup.form.institution=Institution
|
||||
sebserver.lmssetup.form.name=Name
|
||||
sebserver.lmssetup.form.type=Type
|
||||
sebserver.lmssetup.form.clientname.seb=SEB Auth. Name
|
||||
sebserver.lmssetup.form.secret.seb=SEB Auth. Password
|
||||
sebserver.lmssetup.form.url=LMS Server Address
|
||||
sebserver.lmssetup.form.clientname.lms=LMS Server Username
|
||||
sebserver.lmssetup.form.secret.lms=LMS Server Password
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
SWT_Yes=Ja
|
||||
SWT_No=Nein
|
||||
SWT_OK=OK
|
||||
SWT_Cancel=Abbrechen
|
||||
SWT_Abort=Abbrechen
|
||||
SWT_Retry=New Versuchen
|
||||
SWT_Ignore=Ignorieren
|
|
@ -0,0 +1,7 @@
|
|||
SWT_Yes=Yes
|
||||
SWT_No=No
|
||||
SWT_OK=OK
|
||||
SWT_Cancel=Cancel
|
||||
SWT_Abort=Abort
|
||||
SWT_Retry=Retry
|
||||
SWT_Ignore=Ignore
|
|
@ -30,8 +30,8 @@ CREATE TABLE IF NOT EXISTS `lms_setup` (
|
|||
`name` VARCHAR(255) NOT NULL,
|
||||
`lms_type` VARCHAR(45) NOT NULL,
|
||||
`lms_url` VARCHAR(255) NULL,
|
||||
`lms_clientname` VARCHAR(255) NOT NULL,
|
||||
`lms_clientsecret` VARCHAR(255) NOT NULL,
|
||||
`lms_clientname` VARCHAR(255) NULL,
|
||||
`lms_clientsecret` VARCHAR(255) NULL,
|
||||
`lms_rest_api_token` VARCHAR(4000) NULL,
|
||||
`seb_clientname` VARCHAR(255) NOT NULL,
|
||||
`seb_clientsecret` VARCHAR(255) NOT NULL,
|
||||
|
|
|
@ -34,8 +34,8 @@ CREATE TABLE IF NOT EXISTS `lms_setup` (
|
|||
`name` VARCHAR(255) NOT NULL,
|
||||
`lms_type` VARCHAR(45) NOT NULL,
|
||||
`lms_url` VARCHAR(255) NULL,
|
||||
`lms_clientname` VARCHAR(255) NOT NULL,
|
||||
`lms_clientsecret` VARCHAR(255) NOT NULL,
|
||||
`lms_clientname` VARCHAR(255) NULL,
|
||||
`lms_clientsecret` VARCHAR(255) NULL,
|
||||
`lms_rest_api_token` VARCHAR(4000) NULL,
|
||||
`seb_clientname` VARCHAR(255) NOT NULL,
|
||||
`seb_clientsecret` VARCHAR(255) NOT NULL,
|
||||
|
|
|
@ -76,7 +76,7 @@ Label.selection {
|
|||
}
|
||||
|
||||
Label.selectionReadonly {
|
||||
padding: 4px 6px 3px 6px;
|
||||
padding: 4px 6px 3px 0px;
|
||||
}
|
||||
|
||||
Label:hover.selection {
|
||||
|
@ -186,18 +186,10 @@ Text {
|
|||
}
|
||||
|
||||
Text.error {
|
||||
font: 12px Verdana, "Lucida Sans", Arial, Helvetica, sans-serif;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
padding: 3px 10px 3px 10px;
|
||||
color: #4a4a4a;
|
||||
background-repeat: repeat;
|
||||
background-position: left top;
|
||||
background-color: #82BE1E;
|
||||
background-image: none;
|
||||
text-shadow: none;
|
||||
box-shadow: none;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
Text[MULTI] {
|
||||
|
@ -254,6 +246,13 @@ Combo-Field {
|
|||
padding: 3px 10px 3px 10px;
|
||||
}
|
||||
|
||||
Combo.error {
|
||||
background-repeat: repeat;
|
||||
background-position: left top;
|
||||
background-color: #82BE1E;
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
|
||||
/* Message titlebar */
|
||||
Shell.message {
|
||||
|
|
|
@ -20,7 +20,6 @@ import org.junit.Test;
|
|||
|
||||
import com.fasterxml.jackson.core.JsonParseException;
|
||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
import com.fasterxml.jackson.databind.ObjectWriter;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityName;
|
||||
|
@ -47,52 +46,20 @@ public class InstitutionTest {
|
|||
new Institution(3L, "InstThree", "three", "", true)));
|
||||
|
||||
final JSONMapper jsonMapper = new JSONMapper();
|
||||
final ObjectWriter writerWithDefaultPrettyPrinter = jsonMapper.writerWithDefaultPrettyPrinter();
|
||||
String json = writerWithDefaultPrettyPrinter.writeValueAsString(page);
|
||||
assertEquals("{\r\n" +
|
||||
" \"number_of_pages\" : 2,\r\n" +
|
||||
" \"page_number\" : 1,\r\n" +
|
||||
" \"sort\" : \"name\",\r\n" +
|
||||
" \"content\" : [ {\r\n" +
|
||||
" \"id\" : 1,\r\n" +
|
||||
" \"name\" : \"InstOne\",\r\n" +
|
||||
" \"urlSuffix\" : \"one\",\r\n" +
|
||||
" \"logoImage\" : \"\",\r\n" +
|
||||
" \"active\" : true\r\n" +
|
||||
" }, {\r\n" +
|
||||
" \"id\" : 2,\r\n" +
|
||||
" \"name\" : \"InstTwo\",\r\n" +
|
||||
" \"urlSuffix\" : \"two\",\r\n" +
|
||||
" \"logoImage\" : \"\",\r\n" +
|
||||
" \"active\" : true\r\n" +
|
||||
" }, {\r\n" +
|
||||
" \"id\" : 3,\r\n" +
|
||||
" \"name\" : \"InstThree\",\r\n" +
|
||||
" \"urlSuffix\" : \"three\",\r\n" +
|
||||
" \"logoImage\" : \"\",\r\n" +
|
||||
" \"active\" : true\r\n" +
|
||||
" } ],\r\n" +
|
||||
" \"page_size\" : 3\r\n" +
|
||||
"}", json);
|
||||
//final ObjectWriter writerWithDefaultPrettyPrinter = jsonMapper.writerWithDefaultPrettyPrinter();
|
||||
String json = jsonMapper.writeValueAsString(page);
|
||||
assertEquals(
|
||||
"{\"number_of_pages\":2,\"page_number\":1,\"sort\":\"name\",\"content\":[{\"id\":1,\"name\":\"InstOne\",\"urlSuffix\":\"one\",\"logoImage\":\"\",\"active\":true},{\"id\":2,\"name\":\"InstTwo\",\"urlSuffix\":\"two\",\"logoImage\":\"\",\"active\":true},{\"id\":3,\"name\":\"InstThree\",\"urlSuffix\":\"three\",\"logoImage\":\"\",\"active\":true}],\"page_size\":3}",
|
||||
json);
|
||||
|
||||
final List<EntityName> namesList = page.content.stream()
|
||||
.map(inst -> new EntityName(inst.getEntityKey(), inst.name))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
json = writerWithDefaultPrettyPrinter.writeValueAsString(namesList);
|
||||
assertEquals("[ {\r\n" +
|
||||
" \"entityType\" : \"INSTITUTION\",\r\n" +
|
||||
" \"modelId\" : \"1\",\r\n" +
|
||||
" \"name\" : \"InstOne\"\r\n" +
|
||||
"}, {\r\n" +
|
||||
" \"entityType\" : \"INSTITUTION\",\r\n" +
|
||||
" \"modelId\" : \"2\",\r\n" +
|
||||
" \"name\" : \"InstTwo\"\r\n" +
|
||||
"}, {\r\n" +
|
||||
" \"entityType\" : \"INSTITUTION\",\r\n" +
|
||||
" \"modelId\" : \"3\",\r\n" +
|
||||
" \"name\" : \"InstThree\"\r\n" +
|
||||
"} ]", json);
|
||||
json = jsonMapper.writeValueAsString(namesList);
|
||||
assertEquals(
|
||||
"[{\"entityType\":\"INSTITUTION\",\"modelId\":\"1\",\"name\":\"InstOne\"},{\"entityType\":\"INSTITUTION\",\"modelId\":\"2\",\"name\":\"InstTwo\"},{\"entityType\":\"INSTITUTION\",\"modelId\":\"3\",\"name\":\"InstThree\"}]",
|
||||
json);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,8 +17,6 @@ import java.util.Locale;
|
|||
import org.joda.time.DateTimeZone;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectWriter;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Page;
|
||||
|
||||
|
@ -35,45 +33,11 @@ public class UserInfoTest {
|
|||
new HashSet<>(Arrays.asList(UserRole.EXAM_ADMIN.name())))));
|
||||
|
||||
final JSONMapper jsonMapper = new JSONMapper();
|
||||
final ObjectWriter writerWithDefaultPrettyPrinter = jsonMapper.writerWithDefaultPrettyPrinter();
|
||||
final String json = writerWithDefaultPrettyPrinter.writeValueAsString(page);
|
||||
assertEquals("{\r\n" +
|
||||
" \"number_of_pages\" : 2,\r\n" +
|
||||
" \"page_number\" : 1,\r\n" +
|
||||
" \"sort\" : \"name\",\r\n" +
|
||||
" \"content\" : [ {\r\n" +
|
||||
" \"uuid\" : \"id1\",\r\n" +
|
||||
" \"institutionId\" : 1,\r\n" +
|
||||
" \"name\" : \"user1\",\r\n" +
|
||||
" \"username\" : \"user1\",\r\n" +
|
||||
" \"email\" : \"user1@inst2.none\",\r\n" +
|
||||
" \"active\" : true,\r\n" +
|
||||
" \"language\" : \"en\",\r\n" +
|
||||
" \"timezone\" : \"UTC\",\r\n" +
|
||||
" \"userRoles\" : [ \"EXAM_ADMIN\" ]\r\n" +
|
||||
" }, {\r\n" +
|
||||
" \"uuid\" : \"id2\",\r\n" +
|
||||
" \"institutionId\" : 3,\r\n" +
|
||||
" \"name\" : \"user2\",\r\n" +
|
||||
" \"username\" : \"user2\",\r\n" +
|
||||
" \"email\" : \"user2@inst2.none\",\r\n" +
|
||||
" \"active\" : true,\r\n" +
|
||||
" \"language\" : \"en\",\r\n" +
|
||||
" \"timezone\" : \"UTC\",\r\n" +
|
||||
" \"userRoles\" : [ \"EXAM_ADMIN\" ]\r\n" +
|
||||
" }, {\r\n" +
|
||||
" \"uuid\" : \"id3\",\r\n" +
|
||||
" \"institutionId\" : 4,\r\n" +
|
||||
" \"name\" : \"user3\",\r\n" +
|
||||
" \"username\" : \"user3\",\r\n" +
|
||||
" \"email\" : \"user3@inst2.none\",\r\n" +
|
||||
" \"active\" : false,\r\n" +
|
||||
" \"language\" : \"de\",\r\n" +
|
||||
" \"timezone\" : \"UTC\",\r\n" +
|
||||
" \"userRoles\" : [ \"EXAM_ADMIN\" ]\r\n" +
|
||||
" } ],\r\n" +
|
||||
" \"page_size\" : 3\r\n" +
|
||||
"}", json);
|
||||
//final ObjectWriter writerWithDefaultPrettyPrinter = jsonMapper.writerWithDefaultPrettyPrinter();
|
||||
final String json = jsonMapper.writeValueAsString(page);
|
||||
assertEquals(
|
||||
"{\"number_of_pages\":2,\"page_number\":1,\"sort\":\"name\",\"content\":[{\"uuid\":\"id1\",\"institutionId\":1,\"name\":\"user1\",\"username\":\"user1\",\"email\":\"user1@inst2.none\",\"active\":true,\"language\":\"en\",\"timezone\":\"UTC\",\"userRoles\":[\"EXAM_ADMIN\"]},{\"uuid\":\"id2\",\"institutionId\":3,\"name\":\"user2\",\"username\":\"user2\",\"email\":\"user2@inst2.none\",\"active\":true,\"language\":\"en\",\"timezone\":\"UTC\",\"userRoles\":[\"EXAM_ADMIN\"]},{\"uuid\":\"id3\",\"institutionId\":4,\"name\":\"user3\",\"username\":\"user3\",\"email\":\"user3@inst2.none\",\"active\":false,\"language\":\"de\",\"timezone\":\"UTC\",\"userRoles\":[\"EXAM_ADMIN\"]}],\"page_size\":3}",
|
||||
json);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -38,9 +38,11 @@ public class LmsSetupAPITest extends AdministrationAPIIntegrationTester {
|
|||
.withAccessToken(getAdminInstitution1Access())
|
||||
.withPath(API.LMS_SETUP_ENDPOINT)
|
||||
.withMethod(HttpMethod.POST)
|
||||
.withAttribute("name", "new LmsSetup 1")
|
||||
.withAttribute(Domain.LMS_SETUP.ATTR_INSTITUTION_ID, "1")
|
||||
.withAttribute(Domain.LMS_SETUP.ATTR_NAME, "new LmsSetup 1")
|
||||
.withAttribute(Domain.LMS_SETUP.ATTR_LMS_TYPE, LmsType.MOCKUP.name())
|
||||
.withAttribute("active", "false")
|
||||
.withAttribute(Domain.LMS_SETUP.ATTR_SEB_CLIENTNAME, "seb1Name")
|
||||
.withAttribute(Domain.LMS_SETUP.ATTR_SEB_CLIENTSECRET, "12345678")
|
||||
.withExpectedStatus(HttpStatus.OK)
|
||||
.getAsObject(new TypeReference<LmsSetup>() {
|
||||
});
|
||||
|
@ -53,7 +55,7 @@ public class LmsSetupAPITest extends AdministrationAPIIntegrationTester {
|
|||
assertFalse(lmsSetup.active);
|
||||
|
||||
// set lms server and credentials
|
||||
final LmsSetup modified = new LmsSetup(
|
||||
LmsSetup modified = new LmsSetup(
|
||||
lmsSetup.id,
|
||||
lmsSetup.institutionId,
|
||||
lmsSetup.name,
|
||||
|
@ -62,8 +64,8 @@ public class LmsSetupAPITest extends AdministrationAPIIntegrationTester {
|
|||
"lms1Secret",
|
||||
"https://www.lms1.com",
|
||||
null,
|
||||
"seb1Name",
|
||||
"seb1Secret",
|
||||
null,
|
||||
null,
|
||||
null);
|
||||
|
||||
lmsSetup = new RestAPITestHelper()
|
||||
|
@ -87,6 +89,34 @@ public class LmsSetupAPITest extends AdministrationAPIIntegrationTester {
|
|||
assertEquals(null, lmsSetup.sebAuthSecret);
|
||||
assertFalse(lmsSetup.active);
|
||||
|
||||
// trying to rest seb-client credentials should not be possible
|
||||
modified = new LmsSetup(
|
||||
lmsSetup.id,
|
||||
lmsSetup.institutionId,
|
||||
lmsSetup.name,
|
||||
lmsSetup.lmsType,
|
||||
"lms1Name",
|
||||
"lms1Secret",
|
||||
"https://www.lms1.com",
|
||||
null,
|
||||
"seb2Name",
|
||||
"shouldNotBePossible",
|
||||
null);
|
||||
|
||||
final List<APIMessage> errors = new RestAPITestHelper()
|
||||
.withAccessToken(getAdminInstitution1Access())
|
||||
.withPath(API.LMS_SETUP_ENDPOINT)
|
||||
.withMethod(HttpMethod.PUT)
|
||||
.withBodyJson(modified)
|
||||
.withExpectedStatus(HttpStatus.BAD_REQUEST)
|
||||
.getAsObject(new TypeReference<List<APIMessage>>() {
|
||||
});
|
||||
|
||||
assertNotNull(errors);
|
||||
assertTrue(errors.size() == 1);
|
||||
assertEquals("SEB Client Authentication cannot be changed after creation",
|
||||
errors.get(0).details);
|
||||
|
||||
// activate
|
||||
EntityProcessingReport report = new RestAPITestHelper()
|
||||
.withAccessToken(getAdminInstitution1Access())
|
||||
|
@ -180,20 +210,20 @@ public class LmsSetupAPITest extends AdministrationAPIIntegrationTester {
|
|||
|
||||
@Test
|
||||
public void testValidationOnCreate() throws Exception {
|
||||
// create new institution with seb-admin
|
||||
// create new LmsSetup with seb-admin
|
||||
final List<APIMessage> errors = new RestAPITestHelper()
|
||||
.withAccessToken(getAdminInstitution1Access())
|
||||
.withPath(API.LMS_SETUP_ENDPOINT)
|
||||
.withMethod(HttpMethod.POST)
|
||||
.withAttribute("name", "new LmsSetup 1")
|
||||
.withAttribute("active", "false")
|
||||
.withAttribute(Domain.LMS_SETUP.ATTR_INSTITUTION_ID, "1")
|
||||
.withAttribute(Domain.LMS_SETUP.ATTR_NAME, "new LmsSetup 1")
|
||||
.withAttribute(Domain.LMS_SETUP.ATTR_LMS_TYPE, LmsType.MOCKUP.name())
|
||||
.getAsObject(new TypeReference<List<APIMessage>>() {
|
||||
});
|
||||
|
||||
assertNotNull(errors);
|
||||
assertTrue(errors.size() == 1);
|
||||
assertTrue(errors.size() == 2);
|
||||
assertEquals("Field validation error", errors.get(0).systemMessage);
|
||||
assertEquals("[lmsSetup, lmsType, notNull]", String.valueOf(errors.get(0).attributes));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -205,7 +235,8 @@ public class LmsSetupAPITest extends AdministrationAPIIntegrationTester {
|
|||
.withMethod(HttpMethod.POST)
|
||||
.withAttribute("name", "new LmsSetup 1")
|
||||
.withAttribute(Domain.LMS_SETUP.ATTR_LMS_TYPE, LmsType.MOCKUP.name())
|
||||
.withAttribute("active", "false")
|
||||
.withAttribute(Domain.LMS_SETUP.ATTR_SEB_CLIENTNAME, "seb1Name")
|
||||
.withAttribute(Domain.LMS_SETUP.ATTR_SEB_CLIENTSECRET, "12345678")
|
||||
.withExpectedStatus(HttpStatus.OK)
|
||||
.getAsObject(new TypeReference<LmsSetup>() {
|
||||
});
|
||||
|
@ -215,7 +246,8 @@ public class LmsSetupAPITest extends AdministrationAPIIntegrationTester {
|
|||
.withMethod(HttpMethod.POST)
|
||||
.withAttribute("name", "new LmsSetup 2")
|
||||
.withAttribute(Domain.LMS_SETUP.ATTR_LMS_TYPE, LmsType.MOCKUP.name())
|
||||
.withAttribute("active", "false")
|
||||
.withAttribute(Domain.LMS_SETUP.ATTR_SEB_CLIENTNAME, "seb2Name")
|
||||
.withAttribute(Domain.LMS_SETUP.ATTR_SEB_CLIENTSECRET, "12345678")
|
||||
.withExpectedStatus(HttpStatus.OK)
|
||||
.getAsObject(new TypeReference<LmsSetup>() {
|
||||
});
|
||||
|
@ -242,7 +274,8 @@ public class LmsSetupAPITest extends AdministrationAPIIntegrationTester {
|
|||
.withMethod(HttpMethod.POST)
|
||||
.withAttribute("name", "new LmsSetup 1")
|
||||
.withAttribute(Domain.LMS_SETUP.ATTR_LMS_TYPE, LmsType.MOCKUP.name())
|
||||
.withAttribute("active", "false")
|
||||
.withAttribute(Domain.LMS_SETUP.ATTR_SEB_CLIENTNAME, "seb2Name")
|
||||
.withAttribute(Domain.LMS_SETUP.ATTR_SEB_CLIENTSECRET, "12345678")
|
||||
.withExpectedStatus(HttpStatus.OK)
|
||||
.getAsObject(new TypeReference<LmsSetup>() {
|
||||
});
|
||||
|
@ -252,7 +285,8 @@ public class LmsSetupAPITest extends AdministrationAPIIntegrationTester {
|
|||
.withMethod(HttpMethod.POST)
|
||||
.withAttribute("name", "new LmsSetup 2")
|
||||
.withAttribute(Domain.LMS_SETUP.ATTR_LMS_TYPE, LmsType.MOCKUP.name())
|
||||
.withAttribute("active", "false")
|
||||
.withAttribute(Domain.LMS_SETUP.ATTR_SEB_CLIENTNAME, "seb2Name")
|
||||
.withAttribute(Domain.LMS_SETUP.ATTR_SEB_CLIENTSECRET, "12345678")
|
||||
.withExpectedStatus(HttpStatus.OK)
|
||||
.getAsObject(new TypeReference<LmsSetup>() {
|
||||
});
|
||||
|
@ -275,9 +309,11 @@ public class LmsSetupAPITest extends AdministrationAPIIntegrationTester {
|
|||
.withAccessToken(getSebAdminAccess())
|
||||
.withPath(API.LMS_SETUP_ENDPOINT)
|
||||
.withMethod(HttpMethod.POST)
|
||||
.withAttribute(Domain.LMS_SETUP.ATTR_INSTITUTION_ID, "1")
|
||||
.withAttribute("name", "new LmsSetup 1")
|
||||
.withAttribute(Domain.LMS_SETUP.ATTR_LMS_TYPE, LmsType.MOCKUP.name())
|
||||
.withAttribute("active", "false")
|
||||
.withAttribute(Domain.LMS_SETUP.ATTR_SEB_CLIENTNAME, "seb2Name")
|
||||
.withAttribute(Domain.LMS_SETUP.ATTR_SEB_CLIENTSECRET, "12345678")
|
||||
.withExpectedStatus(HttpStatus.OK)
|
||||
.getAsObject(new TypeReference<LmsSetup>() {
|
||||
}).id;
|
||||
|
@ -286,10 +322,11 @@ public class LmsSetupAPITest extends AdministrationAPIIntegrationTester {
|
|||
.withAccessToken(getSebAdminAccess())
|
||||
.withPath(API.LMS_SETUP_ENDPOINT)
|
||||
.withMethod(HttpMethod.POST)
|
||||
.withAttribute("name", "new LmsSetup 2")
|
||||
.withAttribute(Domain.LMS_SETUP.ATTR_INSTITUTION_ID, "2")
|
||||
.withAttribute("name", "new LmsSetup 2")
|
||||
.withAttribute(Domain.LMS_SETUP.ATTR_LMS_TYPE, LmsType.MOCKUP.name())
|
||||
.withAttribute("active", "false")
|
||||
.withAttribute(Domain.LMS_SETUP.ATTR_SEB_CLIENTNAME, "seb2Name")
|
||||
.withAttribute(Domain.LMS_SETUP.ATTR_SEB_CLIENTSECRET, "12345678")
|
||||
.withExpectedStatus(HttpStatus.OK)
|
||||
.getAsObject(new TypeReference<LmsSetup>() {
|
||||
}).id;
|
||||
|
@ -305,7 +342,7 @@ public class LmsSetupAPITest extends AdministrationAPIIntegrationTester {
|
|||
assertNotNull(lmsSetup);
|
||||
assertTrue(lmsSetup.id.longValue() == id1.longValue());
|
||||
|
||||
// a seb-admin is also able to get an institution that is not the one he self belongs to
|
||||
// a seb-admin is also able to get lms setup that is not the own institution
|
||||
lmsSetup = new RestAPITestHelper()
|
||||
.withAccessToken(getSebAdminAccess())
|
||||
.withPath(API.LMS_SETUP_ENDPOINT)
|
||||
|
@ -317,7 +354,7 @@ public class LmsSetupAPITest extends AdministrationAPIIntegrationTester {
|
|||
assertNotNull(lmsSetup);
|
||||
assertTrue(lmsSetup.id.longValue() == id2.longValue());
|
||||
|
||||
// but a institutional-admin is not able to get an institution that is not the one he self belongs to
|
||||
// but a institutional-admin is not able to get lms setup that is on another institution
|
||||
new RestAPITestHelper()
|
||||
.withAccessToken(getAdminInstitution1Access())
|
||||
.withPath(API.LMS_SETUP_ENDPOINT)
|
||||
|
|
|
@ -30,8 +30,8 @@ CREATE TABLE IF NOT EXISTS `lms_setup` (
|
|||
`name` VARCHAR(255) NOT NULL,
|
||||
`lms_type` VARCHAR(45) NOT NULL,
|
||||
`lms_url` VARCHAR(255) NULL,
|
||||
`lms_clientname` VARCHAR(255) NOT NULL,
|
||||
`lms_clientsecret` VARCHAR(255) NOT NULL,
|
||||
`lms_clientname` VARCHAR(255) NULL,
|
||||
`lms_clientsecret` VARCHAR(255) NULL,
|
||||
`lms_rest_api_token` VARCHAR(4000) NULL,
|
||||
`seb_clientname` VARCHAR(255) NOT NULL,
|
||||
`seb_clientsecret` VARCHAR(255) NOT NULL,
|
||||
|
|
Loading…
Reference in a new issue