SEBSERV-27 & SEBSERV-21 password change and refactoring
This commit is contained in:
parent
f760eba750
commit
97bf08e602
56 changed files with 1135 additions and 836 deletions
|
@ -14,13 +14,26 @@ import javax.validation.constraints.Size;
|
|||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class PasswordChange {
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain.USER;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||
|
||||
public class PasswordChange implements Entity {
|
||||
|
||||
public static final String ATTR_NAME_OLD_PASSWORD = "oldPassword";
|
||||
public static final String ATTR_NAME_NEW_PASSWORD = "newPassword";
|
||||
public static final String ATTR_NAME_RETYPED_NEW_PASSWORD = "retypedNewPassword";
|
||||
|
||||
@NotNull
|
||||
@JsonProperty(USER.ATTR_UUID)
|
||||
public final String userId;
|
||||
|
||||
@NotNull(message = "user:password:notNull")
|
||||
@Size(min = 8, max = 255, message = "user:password:size:{min}:{max}:${validatedValue}")
|
||||
@JsonProperty(ATTR_NAME_OLD_PASSWORD)
|
||||
private final String oldPassword;
|
||||
|
||||
@NotNull(message = "user:password:notNull")
|
||||
@Size(min = 8, max = 255, message = "user:newPassword:size:{min}:{max}:${validatedValue}")
|
||||
@JsonProperty(ATTR_NAME_NEW_PASSWORD)
|
||||
private final String newPassword;
|
||||
|
||||
|
@ -29,13 +42,21 @@ public class PasswordChange {
|
|||
|
||||
@JsonCreator
|
||||
public PasswordChange(
|
||||
@JsonProperty(USER.ATTR_UUID) final String userId,
|
||||
@JsonProperty(ATTR_NAME_OLD_PASSWORD) final String oldPassword,
|
||||
@JsonProperty(ATTR_NAME_NEW_PASSWORD) final String newPassword,
|
||||
@JsonProperty(ATTR_NAME_RETYPED_NEW_PASSWORD) final String retypedNewPassword) {
|
||||
|
||||
this.userId = userId;
|
||||
this.oldPassword = oldPassword;
|
||||
this.newPassword = newPassword;
|
||||
this.retypedNewPassword = retypedNewPassword;
|
||||
}
|
||||
|
||||
public String getOldPassword() {
|
||||
return this.oldPassword;
|
||||
}
|
||||
|
||||
public String getNewPassword() {
|
||||
return this.newPassword;
|
||||
}
|
||||
|
@ -48,4 +69,19 @@ public class PasswordChange {
|
|||
return this.newPassword.equals(this.retypedNewPassword);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModelId() {
|
||||
return this.userId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityType entityType() {
|
||||
return EntityType.USER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "PasswordChange";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -32,9 +32,6 @@ import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
|||
|
||||
public final class UserMod implements UserAccount {
|
||||
|
||||
public static final String ATTR_NAME_NEW_PASSWORD = "newPassword";
|
||||
public static final String ATTR_NAME_RETYPED_NEW_PASSWORD = "retypedNewPassword";
|
||||
|
||||
public final String uuid;
|
||||
|
||||
/** The foreign key identifier to the institution where the User belongs to */
|
||||
|
@ -75,11 +72,11 @@ public final class UserMod implements UserAccount {
|
|||
|
||||
@NotNull(message = "user:newPassword:notNull")
|
||||
@Size(min = 8, max = 255, message = "user:password:size:{min}:{max}:${validatedValue}")
|
||||
@JsonProperty(ATTR_NAME_NEW_PASSWORD)
|
||||
@JsonProperty(PasswordChange.ATTR_NAME_NEW_PASSWORD)
|
||||
private final String newPassword;
|
||||
|
||||
@NotNull(message = "user:retypedNewPassword:notNull")
|
||||
@JsonProperty(ATTR_NAME_RETYPED_NEW_PASSWORD)
|
||||
@JsonProperty(PasswordChange.ATTR_NAME_RETYPED_NEW_PASSWORD)
|
||||
private final String retypedNewPassword;
|
||||
|
||||
@JsonCreator
|
||||
|
@ -89,8 +86,8 @@ public final class UserMod implements UserAccount {
|
|||
@JsonProperty(USER.ATTR_INSTITUTION_ID) final Long institutionId,
|
||||
@JsonProperty(USER.ATTR_NAME) final String name,
|
||||
@JsonProperty(USER.ATTR_USERNAME) final String username,
|
||||
@JsonProperty(ATTR_NAME_NEW_PASSWORD) final String newPassword,
|
||||
@JsonProperty(ATTR_NAME_RETYPED_NEW_PASSWORD) final String retypedNewPassword,
|
||||
@JsonProperty(PasswordChange.ATTR_NAME_NEW_PASSWORD) final String newPassword,
|
||||
@JsonProperty(PasswordChange.ATTR_NAME_RETYPED_NEW_PASSWORD) final String retypedNewPassword,
|
||||
@JsonProperty(USER.ATTR_EMAIL) final String email,
|
||||
@JsonProperty(USER.ATTR_LOCALE) final Locale locale,
|
||||
@JsonProperty(USER.ATTR_TIMEZONE) final DateTimeZone timeZone,
|
||||
|
@ -126,8 +123,8 @@ public final class UserMod implements UserAccount {
|
|||
public UserMod(final String modelId, final POSTMapper postAttrMapper) {
|
||||
this.uuid = modelId;
|
||||
this.institutionId = postAttrMapper.getLong(USER.ATTR_INSTITUTION_ID);
|
||||
this.newPassword = postAttrMapper.getString(ATTR_NAME_NEW_PASSWORD);
|
||||
this.retypedNewPassword = postAttrMapper.getString(ATTR_NAME_RETYPED_NEW_PASSWORD);
|
||||
this.newPassword = postAttrMapper.getString(PasswordChange.ATTR_NAME_NEW_PASSWORD);
|
||||
this.retypedNewPassword = postAttrMapper.getString(PasswordChange.ATTR_NAME_RETYPED_NEW_PASSWORD);
|
||||
this.name = postAttrMapper.getString(USER.ATTR_NAME);
|
||||
this.username = postAttrMapper.getString(USER.ATTR_USERNAME);
|
||||
this.email = postAttrMapper.getString(USER.ATTR_EMAIL);
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.springframework.context.annotation.Lazy;
|
|||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.authorization.PrivilegeType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
|
@ -22,11 +23,13 @@ import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
|
|||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.InstitutionActions;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.UserAccountActions;
|
||||
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.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageUtils;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||
|
@ -60,10 +63,6 @@ public class InstitutionForm implements TemplateComposer {
|
|||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Compose Institutoion Form within PageContext: {}", pageContext);
|
||||
}
|
||||
|
||||
final WidgetFactory widgetFactory = this.pageFormService.getWidgetFactory();
|
||||
final EntityKey entityKey = pageContext.getEntityKey();
|
||||
|
||||
|
@ -123,15 +122,14 @@ public class InstitutionForm implements TemplateComposer {
|
|||
.withCondition(() -> entityKey != null))
|
||||
.buildFor((entityKey == null)
|
||||
? this.restService.getRestCall(NewInstitution.class)
|
||||
: this.restService.getRestCall(SaveInstitution.class),
|
||||
InstitutionActions.postSaveAdapter(pageContext));
|
||||
: this.restService.getRestCall(SaveInstitution.class));
|
||||
|
||||
// propagate content actions to action-pane
|
||||
final boolean writeGrant = this.currentUser.hasPrivilege(PrivilegeType.WRITE, institution);
|
||||
final boolean modifyGrant = this.currentUser.hasPrivilege(PrivilegeType.MODIFY, institution);
|
||||
if (pageContext.isReadonly()) {
|
||||
formContext.createAction(ActionDefinition.INSTITUTION_NEW)
|
||||
.withExec(InstitutionActions::newInstitution)
|
||||
.withAttribute(AttributeKeys.READ_ONLY, "false")
|
||||
.publishIf(() -> writeGrant);
|
||||
formContext.createAction(ActionDefinition.INSTITUTION_MODIFY)
|
||||
.withExec(InstitutionActions::editInstitution)
|
||||
|
@ -145,7 +143,12 @@ public class InstitutionForm implements TemplateComposer {
|
|||
formContext.createAction(ActionDefinition.INSTITUTION_DEACTIVATE)
|
||||
.withExec(InstitutionActions::deactivateInstitution)
|
||||
.withConfirm(PageUtils.confirmDeactivation(institution, this.restService))
|
||||
.publishIf(() -> modifyGrant);
|
||||
.publishIf(() -> modifyGrant)
|
||||
.withParentEntityKey(entityKey)
|
||||
.createAction(ActionDefinition.USER_ACCOUNT_NEW)
|
||||
.withExec(UserAccountActions::newUserAccount)
|
||||
.withParentEntity(institution.getEntityKey())
|
||||
.publishIf(() -> this.currentUser.hasPrivilege(PrivilegeType.WRITE, EntityType.USER));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
|
|
@ -9,8 +9,6 @@
|
|||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
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;
|
||||
|
||||
|
@ -21,6 +19,7 @@ import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
|
|||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.InstitutionActions;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.UserAccountActions;
|
||||
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;
|
||||
|
@ -36,8 +35,6 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
|||
@GuiProfile
|
||||
public class InstitutionList implements TemplateComposer {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(InstitutionList.class);
|
||||
|
||||
private final WidgetFactory widgetFactory;
|
||||
private final RestService restService;
|
||||
private final CurrentUser currentUser;
|
||||
|
@ -54,11 +51,6 @@ public class InstitutionList implements TemplateComposer {
|
|||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Compose Institutoion list within PageContext: {}", pageContext);
|
||||
}
|
||||
|
||||
final Composite content = this.widgetFactory.defaultPageLayout(
|
||||
pageContext.getParent(),
|
||||
new LocTextKey("sebserver.institution.list.title"));
|
||||
|
@ -86,16 +78,21 @@ public class InstitutionList implements TemplateComposer {
|
|||
|
||||
// propagate content actions to action-pane
|
||||
pageContext.createAction(ActionDefinition.INSTITUTION_NEW)
|
||||
.withExec(InstitutionActions::newInstitution)
|
||||
.readonly(false)
|
||||
.publishIf(() -> this.currentUser.hasPrivilege(PrivilegeType.WRITE, EntityType.INSTITUTION))
|
||||
.createAction(ActionDefinition.INSTITUTION_VIEW_FROM_LIST)
|
||||
.withSelectionSupplier(table::getSelection)
|
||||
.withExec(InstitutionActions::viewInstitution)
|
||||
.withExec(InstitutionActions::viewInstitutionFromList)
|
||||
.publish()
|
||||
.createAction(ActionDefinition.INSTITUTION_MODIFY_FROM__LIST)
|
||||
.createAction(ActionDefinition.INSTITUTION_MODIFY_FROM_LIST)
|
||||
.withSelectionSupplier(table::getSelection)
|
||||
.withExec(InstitutionActions::editInstitutionFromList)
|
||||
.publishIf(() -> this.currentUser.hasPrivilege(PrivilegeType.MODIFY, EntityType.INSTITUTION));
|
||||
.readonly(false)
|
||||
.publishIf(() -> this.currentUser.hasPrivilege(PrivilegeType.MODIFY, EntityType.INSTITUTION))
|
||||
.createAction(ActionDefinition.USER_ACCOUNT_NEW)
|
||||
.withExec(UserAccountActions::newUserAccount)
|
||||
.publishIf(() -> this.currentUser.hasPrivilege(PrivilegeType.WRITE, EntityType.USER));
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -25,8 +25,8 @@ import ch.ethz.seb.sebserver.gui.content.activity.ActivitiesPane;
|
|||
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.event.ActivitySelectionEvent;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActivitySelectionListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEventListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.PageEventListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.impl.MainPageState;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
@ -119,19 +119,17 @@ public class MainPage implements TemplateComposer {
|
|||
contentObjectslayout.marginWidth = 0;
|
||||
contentObjects.setLayout(contentObjectslayout);
|
||||
contentObjects.setData(PageEventListener.LISTENER_ATTRIBUTE_KEY,
|
||||
new ActivitySelectionListener() {
|
||||
new ActionEventListener() {
|
||||
@Override
|
||||
public int priority() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notify(final ActivitySelectionEvent event) {
|
||||
public void notify(final ActionEvent event) {
|
||||
pageContext.composerService().compose(
|
||||
event.selection.activity.contentPaneComposer,
|
||||
pageContext
|
||||
.copyOf(contentObjects)
|
||||
.withSelection(event.selection));
|
||||
event.action.definition.contentPaneComposer,
|
||||
event.action.pageContext().copyOf(contentObjects));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -141,19 +139,17 @@ public class MainPage implements TemplateComposer {
|
|||
actionPane.setLayout(actionPaneGrid);
|
||||
actionPane.setData(RWT.CUSTOM_VARIANT, "actionPane");
|
||||
actionPane.setData(PageEventListener.LISTENER_ATTRIBUTE_KEY,
|
||||
new ActivitySelectionListener() {
|
||||
new ActionEventListener() {
|
||||
@Override
|
||||
public int priority() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notify(final ActivitySelectionEvent event) {
|
||||
public void notify(final ActionEvent event) {
|
||||
pageContext.composerService().compose(
|
||||
event.selection.activity.actionPaneComposer,
|
||||
pageContext
|
||||
.copyOf(actionPane)
|
||||
.withSelection(event.selection));
|
||||
event.action.definition.actionPaneComposer,
|
||||
event.action.pageContext().copyOf(actionPane));
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.PasswordChange;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.UserAccountActions;
|
||||
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.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.remote.webservice.api.RestService;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.ChangePassword;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccount;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class UserAccountChangePasswordForm implements TemplateComposer {
|
||||
|
||||
private final PageFormService pageFormService;
|
||||
private final RestService restService;
|
||||
|
||||
protected UserAccountChangePasswordForm(
|
||||
final PageFormService pageFormService,
|
||||
final RestService restService) {
|
||||
|
||||
this.pageFormService = pageFormService;
|
||||
this.restService = restService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
|
||||
final WidgetFactory widgetFactory = this.pageFormService.getWidgetFactory();
|
||||
final EntityKey entityKey = pageContext.getEntityKey();
|
||||
|
||||
final UserInfo userInfo = this.restService
|
||||
.getBuilder(GetUserAccount.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
||||
.call()
|
||||
.get(pageContext::notifyError);
|
||||
|
||||
final Composite content = widgetFactory.defaultPageLayout(
|
||||
pageContext.getParent(),
|
||||
new LocTextKey("sebserver.useraccount.form.pwchange.title", userInfo.username));
|
||||
|
||||
// The Password Change form
|
||||
final FormHandle<UserInfo> formHandle = this.pageFormService.getBuilder(
|
||||
pageContext.copyOf(content), 4)
|
||||
.readonly(pageContext.isReadonly())
|
||||
.putStaticValueIf(() -> entityKey != null,
|
||||
Domain.USER.ATTR_ID,
|
||||
entityKey.getModelId())
|
||||
.addField(FormBuilder.text(
|
||||
PasswordChange.ATTR_NAME_OLD_PASSWORD,
|
||||
"sebserver.useraccount.form.institution.password.old")
|
||||
.asPasswordField())
|
||||
.addField(FormBuilder.text(
|
||||
PasswordChange.ATTR_NAME_NEW_PASSWORD,
|
||||
"sebserver.useraccount.form.institution.password.new")
|
||||
.asPasswordField())
|
||||
.addField(FormBuilder.text(
|
||||
PasswordChange.ATTR_NAME_RETYPED_NEW_PASSWORD,
|
||||
"sebserver.useraccount.form.institution.password.retyped")
|
||||
.asPasswordField()
|
||||
.withCondition(() -> entityKey != null))
|
||||
.buildFor(this.restService.getRestCall(ChangePassword.class));
|
||||
|
||||
pageContext.createAction(ActionDefinition.USER_ACCOUNT_CHANGE_PASSOWRD_SAVE)
|
||||
.withExec(formHandle::postChanges)
|
||||
.publish()
|
||||
.createAction(ActionDefinition.USER_ACCOUNT_CANCEL_MODIFY)
|
||||
.withExec(UserAccountActions::cancelEditUserAccount)
|
||||
.withConfirm("sebserver.overall.action.modify.cancel.confirm")
|
||||
.publish();
|
||||
}
|
||||
|
||||
}
|
|
@ -20,10 +20,13 @@ import org.springframework.stereotype.Component;
|
|||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.authorization.PrivilegeType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain.USER_ROLE;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
|
||||
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;
|
||||
|
@ -39,6 +42,7 @@ 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.remote.webservice.api.RestService;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitution;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccount;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.NewUserAccount;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.SaveUserAccount;
|
||||
|
@ -69,12 +73,9 @@ public class UserAccountForm implements TemplateComposer {
|
|||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Compose User Account Form within PageContext: {}", pageContext);
|
||||
}
|
||||
|
||||
final WidgetFactory widgetFactory = this.pageFormService.getWidgetFactory();
|
||||
final EntityKey entityKey = pageContext.getEntityKey();
|
||||
final EntityKey parentEntityKey = pageContext.getParentEntityKey();
|
||||
final BooleanSupplier isNew = () -> entityKey == null;
|
||||
final BooleanSupplier isNotNew = () -> !isNew.getAsBoolean();
|
||||
final BooleanSupplier isSEBAdmin = () -> this.currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN);
|
||||
|
@ -126,9 +127,12 @@ public class UserAccountForm implements TemplateComposer {
|
|||
.addField(FormBuilder.singleSelection(
|
||||
Domain.USER.ATTR_INSTITUTION_ID,
|
||||
"sebserver.useraccount.form.institution",
|
||||
String.valueOf(userAccount.getInstitutionId()),
|
||||
(parentEntityKey != null && parentEntityKey.entityType == EntityType.INSTITUTION)
|
||||
? parentEntityKey.modelId
|
||||
: String.valueOf(userAccount.getInstitutionId()),
|
||||
() -> PageUtils.getInstitutionSelectionResource(this.restService))
|
||||
.withCondition(isSEBAdmin))
|
||||
.withCondition(isSEBAdmin)
|
||||
.readonlyIf(isNotNew))
|
||||
.addField(FormBuilder.text(
|
||||
Domain.USER.ATTR_NAME,
|
||||
"sebserver.useraccount.form.name",
|
||||
|
@ -157,44 +161,53 @@ public class UserAccountForm implements TemplateComposer {
|
|||
StringUtils.join(userAccount.getRoles(), Constants.LIST_SEPARATOR_CHAR),
|
||||
widgetFactory.getI18nSupport().localizedUserRoleResources()))
|
||||
.addField(FormBuilder.text(
|
||||
UserMod.ATTR_NAME_NEW_PASSWORD,
|
||||
"sebserver.useraccount.form.password",
|
||||
null)
|
||||
PasswordChange.ATTR_NAME_NEW_PASSWORD,
|
||||
"sebserver.useraccount.form.password")
|
||||
.asPasswordField()
|
||||
.withCondition(isNew))
|
||||
.addField(FormBuilder.text(
|
||||
UserMod.ATTR_NAME_RETYPED_NEW_PASSWORD,
|
||||
"sebserver.useraccount.form.password.retyped",
|
||||
null)
|
||||
PasswordChange.ATTR_NAME_RETYPED_NEW_PASSWORD,
|
||||
"sebserver.useraccount.form.password.retyped")
|
||||
.asPasswordField()
|
||||
.withCondition(isNew))
|
||||
.buildFor((entityKey == null)
|
||||
? this.restService.getRestCall(NewUserAccount.class)
|
||||
: this.restService.getRestCall(SaveUserAccount.class),
|
||||
UserAccountActions.postSaveAdapter(pageContext));
|
||||
: this.restService.getRestCall(SaveUserAccount.class));
|
||||
|
||||
// propagate content actions to action-pane
|
||||
final boolean writeGrant = this.currentUser.hasPrivilege(PrivilegeType.WRITE, userAccount);
|
||||
final boolean modifyGrant = this.currentUser.hasPrivilege(PrivilegeType.MODIFY, userAccount);
|
||||
if (pageContext.isReadonly()) {
|
||||
formContext.createAction(ActionDefinition.USER_ACCOUNT_NEW)
|
||||
.withExec(UserAccountActions::newUserAccount)
|
||||
|
||||
formContext.createAction(ActionDefinition.USER_ACCOUNT_CHANGE_PASSOWRD)
|
||||
.withEntity(userAccount.getEntityKey())
|
||||
.publishIf(() -> writeGrant);
|
||||
formContext.createAction(ActionDefinition.USER_ACCOUNT_MODIFY)
|
||||
.withExec(UserAccountActions::editUserAccount)
|
||||
.publishIf(() -> modifyGrant);
|
||||
|
||||
if (!userAccount.isActive()) {
|
||||
formContext.createAction(ActionDefinition.USER_ACCOUNT_ACTIVATE)
|
||||
.withExec(UserAccountActions::activateUserAccount)
|
||||
.publishIf(() -> modifyGrant);
|
||||
} else {
|
||||
formContext.createAction(ActionDefinition.USER_ACCOUNT_DEACTIVATE)
|
||||
.withExec(UserAccountActions::deactivateUserAccount)
|
||||
.withConfirm(PageUtils.confirmDeactivation(userAccount, this.restService))
|
||||
// modifying an UserAccount is not possible if the root institution is inactive
|
||||
final Institution inst = this.restService.getBuilder(GetInstitution.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, String.valueOf(userAccount.getInstitutionId()))
|
||||
.call()
|
||||
.getOrThrow();
|
||||
|
||||
if (inst.isActive()) {
|
||||
formContext.createAction(ActionDefinition.USER_ACCOUNT_NEW)
|
||||
.withExec(UserAccountActions::newUserAccount)
|
||||
.publishIf(() -> writeGrant);
|
||||
formContext.createAction(ActionDefinition.USER_ACCOUNT_MODIFY)
|
||||
.withExec(UserAccountActions::editUserAccount)
|
||||
.publishIf(() -> modifyGrant);
|
||||
|
||||
if (!userAccount.isActive()) {
|
||||
formContext.createAction(ActionDefinition.USER_ACCOUNT_ACTIVATE)
|
||||
.withExec(UserAccountActions::activateUserAccount)
|
||||
.publishIf(() -> modifyGrant);
|
||||
} else {
|
||||
formContext.createAction(ActionDefinition.USER_ACCOUNT_DEACTIVATE)
|
||||
.withExec(UserAccountActions::deactivateUserAccount)
|
||||
.withConfirm(PageUtils.confirmDeactivation(userAccount, this.restService))
|
||||
.publishIf(() -> modifyGrant);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
formContext.createAction(ActionDefinition.USER_ACCOUNT_SAVE)
|
||||
.withExec(formHandle::postChanges)
|
||||
|
|
|
@ -9,8 +9,6 @@
|
|||
package ch.ethz.seb.sebserver.gui.content;
|
||||
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
@ -29,8 +27,8 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
|||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccounts;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.table.EntityTable;
|
||||
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute;
|
||||
import ch.ethz.seb.sebserver.gui.table.EntityTable;
|
||||
import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
|
@ -39,8 +37,6 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
|||
@GuiProfile
|
||||
public class UserAccountList implements TemplateComposer {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(UserAccountList.class);
|
||||
|
||||
private final WidgetFactory widgetFactory;
|
||||
private final RestService restService;
|
||||
private final CurrentUser currentUser;
|
||||
|
@ -60,11 +56,6 @@ public class UserAccountList implements TemplateComposer {
|
|||
|
||||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Compose User Account list within PageContext: {}", pageContext);
|
||||
}
|
||||
|
||||
// content page layout with title
|
||||
final Composite content = this.widgetFactory.defaultPageLayout(
|
||||
pageContext.getParent(),
|
||||
|
@ -113,7 +104,7 @@ public class UserAccountList implements TemplateComposer {
|
|||
.withSelectionSupplier(table::getSelection)
|
||||
.withExec(UserAccountActions::viewUserAccountFromList)
|
||||
.publish()
|
||||
.createAction(ActionDefinition.USER_ACCOUNT_MODIFY)
|
||||
.createAction(ActionDefinition.USER_ACCOUNT_MODIFY_FROM__LIST)
|
||||
.withSelectionSupplier(table::getSelection)
|
||||
.withExec(UserAccountActions::editUserAccountFromList)
|
||||
.publishIf(() -> this.currentUser.hasPrivilege(PrivilegeType.MODIFY, EntityType.USER));
|
||||
|
|
|
@ -8,85 +8,205 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.gui.content.action;
|
||||
|
||||
import ch.ethz.seb.sebserver.gui.content.InstitutionForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.InstitutionList;
|
||||
import ch.ethz.seb.sebserver.gui.content.UserAccountChangePasswordForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.UserAccountForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.UserAccountList;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon;
|
||||
|
||||
public enum ActionDefinition {
|
||||
|
||||
INSTITUTION_VIEW_LIST(
|
||||
new LocTextKey("sebserver.institution.action.list"),
|
||||
InstitutionList.class),
|
||||
INSTITUTION_VIEW_FORM(
|
||||
new LocTextKey("sebserver.institution.action.form"),
|
||||
InstitutionForm.class,
|
||||
INSTITUTION_VIEW_LIST),
|
||||
INSTITUTION_NEW(
|
||||
"sebserver.institution.action.new",
|
||||
ImageIcon.NEW),
|
||||
|
||||
new LocTextKey("sebserver.institution.action.new"),
|
||||
ImageIcon.NEW,
|
||||
InstitutionForm.class,
|
||||
INSTITUTION_VIEW_LIST),
|
||||
INSTITUTION_VIEW_FROM_LIST(
|
||||
"sebserver.institution.action.list.view",
|
||||
ImageIcon.SHOW),
|
||||
new LocTextKey("sebserver.institution.action.list.view"),
|
||||
ImageIcon.SHOW,
|
||||
InstitutionForm.class,
|
||||
INSTITUTION_VIEW_LIST),
|
||||
|
||||
INSTITUTION_MODIFY_FROM__LIST(
|
||||
"sebserver.institution.action.list.modify",
|
||||
ImageIcon.EDIT),
|
||||
INSTITUTION_MODIFY_FROM_LIST(
|
||||
new LocTextKey("sebserver.institution.action.list.modify"),
|
||||
ImageIcon.EDIT,
|
||||
InstitutionForm.class,
|
||||
INSTITUTION_VIEW_LIST),
|
||||
|
||||
INSTITUTION_MODIFY(
|
||||
"sebserver.institution.action.modify",
|
||||
ImageIcon.EDIT),
|
||||
new LocTextKey("sebserver.institution.action.modify"),
|
||||
ImageIcon.EDIT,
|
||||
InstitutionForm.class,
|
||||
INSTITUTION_VIEW_LIST),
|
||||
|
||||
INSTITUTION_CANCEL_MODIFY(
|
||||
"sebserver.overall.action.modify.cancel",
|
||||
ImageIcon.CANCEL),
|
||||
new LocTextKey("sebserver.overall.action.modify.cancel"),
|
||||
ImageIcon.CANCEL,
|
||||
InstitutionForm.class,
|
||||
INSTITUTION_VIEW_LIST),
|
||||
|
||||
INSTITUTION_SAVE(
|
||||
"sebserver.institution.action.save",
|
||||
ImageIcon.SAVE),
|
||||
new LocTextKey("sebserver.institution.action.save"),
|
||||
ImageIcon.SAVE,
|
||||
InstitutionForm.class,
|
||||
INSTITUTION_VIEW_LIST),
|
||||
|
||||
INSTITUTION_ACTIVATE(
|
||||
"sebserver.institution.action.activate",
|
||||
ImageIcon.INACTIVE),
|
||||
new LocTextKey("sebserver.institution.action.activate"),
|
||||
ImageIcon.INACTIVE,
|
||||
InstitutionForm.class,
|
||||
INSTITUTION_VIEW_LIST),
|
||||
|
||||
INSTITUTION_DEACTIVATE(
|
||||
"sebserver.institution.action.deactivate",
|
||||
ImageIcon.ACTIVE),
|
||||
new LocTextKey("sebserver.institution.action.deactivate"),
|
||||
ImageIcon.ACTIVE,
|
||||
InstitutionForm.class,
|
||||
INSTITUTION_VIEW_LIST),
|
||||
|
||||
INSTITUTION_DELETE(
|
||||
"sebserver.institution.action.modify",
|
||||
ImageIcon.DELETE),
|
||||
new LocTextKey("sebserver.institution.action.modify"),
|
||||
ImageIcon.DELETE,
|
||||
InstitutionList.class,
|
||||
INSTITUTION_VIEW_LIST),
|
||||
|
||||
USER_ACCOUNT_VIEW_LIST(
|
||||
new LocTextKey("sebserver.useraccount.action.list"),
|
||||
UserAccountList.class),
|
||||
USER_ACCOUNT_VIEW_FORM(
|
||||
new LocTextKey("sebserver.useraccount.action.form"),
|
||||
InstitutionForm.class,
|
||||
USER_ACCOUNT_VIEW_LIST),
|
||||
USER_ACCOUNT_NEW(
|
||||
"sebserver.useraccount.action.new",
|
||||
ImageIcon.NEW),
|
||||
new LocTextKey("sebserver.useraccount.action.new"),
|
||||
ImageIcon.NEW,
|
||||
UserAccountForm.class,
|
||||
USER_ACCOUNT_VIEW_LIST),
|
||||
|
||||
USER_ACCOUNT_VIEW(
|
||||
"sebserver.useraccount.action.view",
|
||||
ImageIcon.SHOW),
|
||||
new LocTextKey("sebserver.useraccount.action.view"),
|
||||
ImageIcon.SHOW,
|
||||
UserAccountForm.class,
|
||||
USER_ACCOUNT_VIEW_LIST),
|
||||
|
||||
USER_ACCOUNT_MODIFY_FROM__LIST(
|
||||
new LocTextKey("sebserver.useraccount.action.list.modify"),
|
||||
ImageIcon.EDIT,
|
||||
UserAccountForm.class,
|
||||
USER_ACCOUNT_VIEW_LIST),
|
||||
|
||||
USER_ACCOUNT_MODIFY(
|
||||
"sebserver.useraccount.action.modify",
|
||||
ImageIcon.EDIT),
|
||||
new LocTextKey("sebserver.useraccount.action.modify"),
|
||||
ImageIcon.EDIT,
|
||||
UserAccountForm.class,
|
||||
USER_ACCOUNT_VIEW_LIST),
|
||||
|
||||
USER_ACCOUNT_CANCEL_MODIFY(
|
||||
"sebserver.overall.action.modify.cancel",
|
||||
ImageIcon.CANCEL),
|
||||
new LocTextKey("sebserver.overall.action.modify.cancel"),
|
||||
ImageIcon.CANCEL,
|
||||
UserAccountForm.class,
|
||||
USER_ACCOUNT_VIEW_LIST),
|
||||
|
||||
USER_ACCOUNT_SAVE(
|
||||
"sebserver.useraccount.action.save",
|
||||
ImageIcon.SAVE),
|
||||
new LocTextKey("sebserver.useraccount.action.save"),
|
||||
ImageIcon.SAVE,
|
||||
UserAccountForm.class,
|
||||
USER_ACCOUNT_VIEW_LIST),
|
||||
|
||||
USER_ACCOUNT_ACTIVATE(
|
||||
"sebserver.useraccount.action.activate",
|
||||
ImageIcon.INACTIVE),
|
||||
new LocTextKey("sebserver.useraccount.action.activate"),
|
||||
ImageIcon.INACTIVE,
|
||||
UserAccountForm.class,
|
||||
USER_ACCOUNT_VIEW_LIST),
|
||||
|
||||
USER_ACCOUNT_DEACTIVATE(
|
||||
"sebserver.useraccount.action.deactivate",
|
||||
ImageIcon.ACTIVE),
|
||||
new LocTextKey("sebserver.useraccount.action.deactivate"),
|
||||
ImageIcon.ACTIVE,
|
||||
UserAccountForm.class,
|
||||
USER_ACCOUNT_VIEW_LIST),
|
||||
|
||||
USER_ACCOUNT_DELETE(
|
||||
"sebserver.useraccount.action.modify",
|
||||
ImageIcon.DELETE),
|
||||
;
|
||||
new LocTextKey("sebserver.useraccount.action.modify"),
|
||||
ImageIcon.DELETE,
|
||||
UserAccountList.class,
|
||||
USER_ACCOUNT_VIEW_LIST),
|
||||
|
||||
public final String name;
|
||||
USER_ACCOUNT_CHANGE_PASSOWRD(
|
||||
new LocTextKey("sebserver.useraccount.action.change.password"),
|
||||
ImageIcon.EDIT,
|
||||
UserAccountChangePasswordForm.class,
|
||||
USER_ACCOUNT_VIEW_LIST),
|
||||
USER_ACCOUNT_CHANGE_PASSOWRD_SAVE(
|
||||
new LocTextKey("sebserver.useraccount.action.change.password.save"),
|
||||
ImageIcon.SAVE,
|
||||
UserAccountForm.class,
|
||||
USER_ACCOUNT_VIEW_LIST),
|
||||
|
||||
;
|
||||
|
||||
public final LocTextKey title;
|
||||
public final ImageIcon icon;
|
||||
public final Class<? extends TemplateComposer> contentPaneComposer;
|
||||
public final Class<? extends TemplateComposer> actionPaneComposer;
|
||||
public final ActionDefinition activityAlias;
|
||||
|
||||
private ActionDefinition(final String name, final ImageIcon icon) {
|
||||
this.name = name;
|
||||
private 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;
|
||||
}
|
||||
|
||||
private ActionDefinition(
|
||||
final LocTextKey title,
|
||||
final Class<? extends TemplateComposer> contentPaneComposer,
|
||||
final ActionDefinition activityAlias) {
|
||||
|
||||
this.title = title;
|
||||
this.icon = null;
|
||||
this.contentPaneComposer = contentPaneComposer;
|
||||
this.actionPaneComposer = ActionPane.class;
|
||||
this.activityAlias = activityAlias;
|
||||
}
|
||||
|
||||
private ActionDefinition(
|
||||
final LocTextKey title,
|
||||
final ImageIcon icon,
|
||||
final Class<? extends TemplateComposer> contentPaneComposer,
|
||||
final ActionDefinition activityAlias) {
|
||||
|
||||
this.title = title;
|
||||
this.icon = icon;
|
||||
this.contentPaneComposer = contentPaneComposer;
|
||||
this.actionPaneComposer = ActionPane.class;
|
||||
this.activityAlias = activityAlias;
|
||||
}
|
||||
|
||||
private ActionDefinition(
|
||||
final LocTextKey title,
|
||||
final ImageIcon icon,
|
||||
final Class<? extends TemplateComposer> contentPaneComposer,
|
||||
final Class<? extends TemplateComposer> actionPaneComposer,
|
||||
final ActionDefinition activityAlias) {
|
||||
|
||||
this.title = title;
|
||||
this.icon = icon;
|
||||
this.contentPaneComposer = contentPaneComposer;
|
||||
this.actionPaneComposer = actionPaneComposer;
|
||||
this.activityAlias = activityAlias;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -90,7 +90,7 @@ public class ActionPane implements TemplateComposer {
|
|||
|
||||
final TreeItem actionItem = ActionPane.this.widgetFactory.treeItemLocalized(
|
||||
actions,
|
||||
event.action.definition.name);
|
||||
event.action.definition.title);
|
||||
|
||||
actionItem.setImage(event.action.definition.icon.getImage(
|
||||
pageContext.getParent().getDisplay()));
|
||||
|
|
|
@ -9,111 +9,86 @@
|
|||
package ch.ethz.seb.sebserver.gui.content.action;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.function.Function;
|
||||
|
||||
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.gbl.model.institution.Institution;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.gui.content.activity.Activity;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageMessageException;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.action.Action;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.activity.ActivitySelection;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActivitySelectionEvent;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.ActivateInstitution;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.DeactivateInstitution;
|
||||
|
||||
/** Defines the action execution functions for all Institution action. */
|
||||
public final class InstitutionActions {
|
||||
|
||||
public static Function<Institution, Institution> postSaveAdapter(final PageContext pageContext) {
|
||||
return inst -> {
|
||||
goToInstitution(pageContext, inst.getModelId(), false);
|
||||
return inst;
|
||||
};
|
||||
}
|
||||
|
||||
public static Result<?> newInstitution(final Action action) {
|
||||
return Result.of(goToInstitution(action.pageContext, null, true));
|
||||
}
|
||||
|
||||
public static Result<?> viewInstitution(final Action action) {
|
||||
public static Action viewInstitutionFromList(final Action action) {
|
||||
return fromSelection(action, false);
|
||||
}
|
||||
|
||||
public static Result<?> editInstitutionFromList(final Action action) {
|
||||
public static Action editInstitutionFromList(final Action action) {
|
||||
return fromSelection(action, true);
|
||||
}
|
||||
|
||||
public static Result<?> editInstitution(final Action action) {
|
||||
return Result.of(goToInstitution(
|
||||
action.pageContext,
|
||||
action.pageContext.getAttribute(AttributeKeys.ENTITY_ID),
|
||||
true));
|
||||
public static Action editInstitution(final Action action) {
|
||||
return goToInstitution(action, null, true);
|
||||
}
|
||||
|
||||
public static Result<?> cancelEditInstitution(final Action action) {
|
||||
if (action.pageContext.getEntityKey() == null) {
|
||||
final ActivitySelection toList = Activity.INSTITUTION_LIST.createSelection();
|
||||
action.pageContext.publishPageEvent(new ActivitySelectionEvent(toList));
|
||||
return Result.of(toList);
|
||||
public static Action cancelEditInstitution(final Action action) {
|
||||
if (action.getEntityKey() == null) {
|
||||
final PageContext pageContext = action.pageContext();
|
||||
final Action toList = pageContext.createAction(ActionDefinition.INSTITUTION_VIEW_LIST);
|
||||
pageContext.publishPageEvent(new ActionEvent(toList, false));
|
||||
return toList;
|
||||
} else {
|
||||
return Result.of(goToInstitution(
|
||||
action.pageContext,
|
||||
action.pageContext.getAttribute(AttributeKeys.ENTITY_ID),
|
||||
false));
|
||||
return goToInstitution(action, null, false);
|
||||
}
|
||||
}
|
||||
|
||||
public static Result<?> activateInstitution(final Action action) {
|
||||
public static Action activateInstitution(final Action action) {
|
||||
return action.restService
|
||||
.getBuilder(ActivateInstitution.class)
|
||||
.withURIVariable(
|
||||
API.PARAM_MODEL_ID,
|
||||
action.pageContext.getAttribute(AttributeKeys.ENTITY_ID))
|
||||
action.pageContext().getAttribute(AttributeKeys.ENTITY_ID))
|
||||
.call()
|
||||
.map(report -> goToInstitution(action.pageContext, report.getSingleSource().modelId, false));
|
||||
.map(report -> goToInstitution(action, report.getSingleSource().modelId, false))
|
||||
.getOrThrow();
|
||||
}
|
||||
|
||||
public static Result<?> deactivateInstitution(final Action action) {
|
||||
public static Action deactivateInstitution(final Action action) {
|
||||
return action.restService
|
||||
.getBuilder(DeactivateInstitution.class)
|
||||
.withURIVariable(
|
||||
API.PARAM_MODEL_ID,
|
||||
action.pageContext.getAttribute(AttributeKeys.ENTITY_ID))
|
||||
action.pageContext().getAttribute(AttributeKeys.ENTITY_ID))
|
||||
.call()
|
||||
.map(report -> goToInstitution(action.pageContext, report.getSingleSource().modelId, false));
|
||||
.map(report -> goToInstitution(action, report.getSingleSource().modelId, false))
|
||||
.getOrThrow();
|
||||
}
|
||||
|
||||
private static Result<?> fromSelection(final Action action, final boolean edit) {
|
||||
return Result.tryCatch(() -> {
|
||||
final Collection<String> selection = action.getSelectionSupplier().get();
|
||||
if (selection.isEmpty()) {
|
||||
throw new PageMessageException("sebserver.institution.info.pleaseSelect");
|
||||
}
|
||||
private static Action fromSelection(final Action action, final boolean edit) {
|
||||
final Collection<String> selection = action.getSelectionSupplier().get();
|
||||
if (selection.isEmpty()) {
|
||||
throw new PageMessageException("sebserver.institution.info.pleaseSelect");
|
||||
}
|
||||
|
||||
return goToInstitution(action.pageContext, selection.iterator().next(), edit);
|
||||
});
|
||||
return goToInstitution(action, selection.iterator().next(), edit);
|
||||
}
|
||||
|
||||
private static ActivitySelection goToInstitution(
|
||||
final PageContext pageContext,
|
||||
private static Action goToInstitution(
|
||||
final Action action,
|
||||
final String modelId,
|
||||
final boolean edit) {
|
||||
|
||||
final ActivitySelection activitySelection = Activity.INSTITUTION_FORM
|
||||
.createSelection()
|
||||
.withAttribute(AttributeKeys.READ_ONLY, String.valueOf(!edit));
|
||||
|
||||
action.withAttribute(AttributeKeys.READ_ONLY, String.valueOf(!edit));
|
||||
if (modelId != null) {
|
||||
activitySelection.withEntity(new EntityKey(modelId, EntityType.INSTITUTION));
|
||||
action.withEntity(new EntityKey(modelId, EntityType.INSTITUTION));
|
||||
}
|
||||
|
||||
pageContext.publishPageEvent(new ActivitySelectionEvent(activitySelection));
|
||||
return activitySelection;
|
||||
return action;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,110 +9,87 @@
|
|||
package ch.ethz.seb.sebserver.gui.content.action;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.function.Function;
|
||||
|
||||
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.gbl.model.user.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.gui.content.activity.Activity;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageMessageException;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.action.Action;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.activity.ActivitySelection;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActivitySelectionEvent;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.ActivateUserAccount;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.DeactivateUserAccount;
|
||||
|
||||
public final class UserAccountActions {
|
||||
|
||||
public static Function<UserInfo, UserInfo> postSaveAdapter(final PageContext pageContext) {
|
||||
return userAccount -> {
|
||||
goToUserAccount(pageContext, userAccount.getModelId(), false);
|
||||
return userAccount;
|
||||
};
|
||||
public static Action newUserAccount(final Action action) {
|
||||
return goToUserAccount(action, null, true);
|
||||
}
|
||||
|
||||
public static Result<?> newUserAccount(final Action action) {
|
||||
return Result.of(goToUserAccount(action.pageContext, null, true));
|
||||
}
|
||||
|
||||
public static Result<?> viewUserAccountFromList(final Action action) {
|
||||
public static Action viewUserAccountFromList(final Action action) {
|
||||
return fromSelection(action, false);
|
||||
}
|
||||
|
||||
public static Result<?> editUserAccountFromList(final Action action) {
|
||||
public static Action editUserAccountFromList(final Action action) {
|
||||
return fromSelection(action, true);
|
||||
}
|
||||
|
||||
public static Result<?> editUserAccount(final Action action) {
|
||||
return Result.of(goToUserAccount(
|
||||
action.pageContext,
|
||||
action.pageContext.getAttribute(AttributeKeys.ENTITY_ID),
|
||||
true));
|
||||
public static Action editUserAccount(final Action action) {
|
||||
return goToUserAccount(action, null, true);
|
||||
}
|
||||
|
||||
public static Result<?> cancelEditUserAccount(final Action action) {
|
||||
if (action.pageContext.getEntityKey() == null) {
|
||||
final ActivitySelection toList = Activity.USER_ACCOUNT_LIST.createSelection();
|
||||
action.pageContext.publishPageEvent(new ActivitySelectionEvent(toList));
|
||||
return Result.of(toList);
|
||||
public static Action cancelEditUserAccount(final Action action) {
|
||||
if (action.pageContext().getEntityKey() == null) {
|
||||
final Action toList = action.pageContext().createAction(ActionDefinition.USER_ACCOUNT_VIEW_LIST);
|
||||
action.pageContext().publishPageEvent(new ActionEvent(toList, false));
|
||||
return toList;
|
||||
} else {
|
||||
return Result.of(goToUserAccount(
|
||||
action.pageContext,
|
||||
action.pageContext.getAttribute(AttributeKeys.ENTITY_ID),
|
||||
false));
|
||||
return goToUserAccount(action, null, false);
|
||||
}
|
||||
}
|
||||
|
||||
public static Result<?> activateUserAccount(final Action action) {
|
||||
public static Action activateUserAccount(final Action action) {
|
||||
return action.restService
|
||||
.getBuilder(ActivateUserAccount.class)
|
||||
.withURIVariable(
|
||||
API.PARAM_MODEL_ID,
|
||||
action.pageContext.getAttribute(AttributeKeys.ENTITY_ID))
|
||||
action.pageContext().getAttribute(AttributeKeys.ENTITY_ID))
|
||||
.call()
|
||||
.map(report -> goToUserAccount(action.pageContext, report.getSingleSource().modelId, false));
|
||||
.map(report -> goToUserAccount(action, report.getSingleSource().modelId, false))
|
||||
.getOrThrow();
|
||||
}
|
||||
|
||||
public static Result<?> deactivateUserAccount(final Action action) {
|
||||
public static Action deactivateUserAccount(final Action action) {
|
||||
return action.restService
|
||||
.getBuilder(DeactivateUserAccount.class)
|
||||
.withURIVariable(
|
||||
API.PARAM_MODEL_ID,
|
||||
action.pageContext.getAttribute(AttributeKeys.ENTITY_ID))
|
||||
action.pageContext().getAttribute(AttributeKeys.ENTITY_ID))
|
||||
.call()
|
||||
.map(report -> goToUserAccount(action.pageContext, report.getSingleSource().modelId, false));
|
||||
.map(report -> goToUserAccount(action, report.getSingleSource().modelId, false))
|
||||
.getOrThrow();
|
||||
}
|
||||
|
||||
private static Result<?> fromSelection(final Action action, final boolean edit) {
|
||||
return Result.tryCatch(() -> {
|
||||
final Collection<String> selection = action.getSelectionSupplier().get();
|
||||
if (selection.isEmpty()) {
|
||||
throw new PageMessageException("sebserver.useraccount.info.pleaseSelect");
|
||||
}
|
||||
private static Action fromSelection(final Action action, final boolean edit) {
|
||||
final Collection<String> selection = action.getSelectionSupplier().get();
|
||||
if (selection.isEmpty()) {
|
||||
throw new PageMessageException("sebserver.useraccount.info.pleaseSelect");
|
||||
}
|
||||
|
||||
return goToUserAccount(action.pageContext, selection.iterator().next(), edit);
|
||||
});
|
||||
return goToUserAccount(action, selection.iterator().next(), edit);
|
||||
}
|
||||
|
||||
private static ActivitySelection goToUserAccount(
|
||||
final PageContext pageContext,
|
||||
private static Action goToUserAccount(
|
||||
final Action action,
|
||||
final String modelId,
|
||||
final boolean edit) {
|
||||
|
||||
final ActivitySelection activitySelection = Activity.USER_ACCOUNT_FORM
|
||||
.createSelection()
|
||||
.withAttribute(AttributeKeys.READ_ONLY, String.valueOf(!edit));
|
||||
|
||||
action.withAttribute(AttributeKeys.READ_ONLY, String.valueOf(!edit));
|
||||
if (modelId != null) {
|
||||
activitySelection.withEntity(new EntityKey(modelId, EntityType.USER));
|
||||
action.withEntity(new EntityKey(modelId, EntityType.USER));
|
||||
}
|
||||
|
||||
pageContext.publishPageEvent(new ActivitySelectionEvent(activitySelection));
|
||||
return activitySelection;
|
||||
return action;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,10 +8,6 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.gui.content.activity;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.widgets.Event;
|
||||
|
@ -30,15 +26,12 @@ import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
|||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.activity.ActivityActionHandler;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.activity.ActivitySelection;
|
||||
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.page.event.ActionEvent;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEventListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActivitySelectionEvent;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.PageEventListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.impl.MainPageState;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
|
||||
|
@ -50,26 +43,14 @@ public class ActivitiesPane implements TemplateComposer {
|
|||
private static final String ATTR_ACTIVITY_SELECTION = "ACTIVITY_SELECTION";
|
||||
|
||||
private final WidgetFactory widgetFactory;
|
||||
private final RestService restService;
|
||||
private final CurrentUser currentUser;
|
||||
|
||||
// TODO are those really needed?
|
||||
private final Map<ActionDefinition, ActivityActionHandler> activityActionHandler =
|
||||
new EnumMap<>(ActionDefinition.class);
|
||||
|
||||
public ActivitiesPane(
|
||||
final WidgetFactory widgetFactory,
|
||||
final RestService restService,
|
||||
final CurrentUser currentUser,
|
||||
final Collection<ActivityActionHandler> activityActionHandler) {
|
||||
final CurrentUser currentUser) {
|
||||
|
||||
this.widgetFactory = widgetFactory;
|
||||
this.restService = restService;
|
||||
this.currentUser = currentUser;
|
||||
|
||||
for (final ActivityActionHandler aah : activityActionHandler) {
|
||||
this.activityActionHandler.put(aah.handlesAction(), aah);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -89,7 +70,7 @@ public class ActivitiesPane implements TemplateComposer {
|
|||
pageContext.getParent(),
|
||||
SWT.SINGLE | SWT.FULL_SELECTION);
|
||||
final GridData navigationGridData = new GridData(SWT.FILL, SWT.FILL, true, true);
|
||||
navigationGridData.horizontalIndent = 10;
|
||||
//navigationGridData.horizontalIndent = 10;
|
||||
navigation.setLayoutData(navigationGridData);
|
||||
|
||||
// Institution
|
||||
|
@ -98,18 +79,20 @@ public class ActivitiesPane implements TemplateComposer {
|
|||
// institutions (list) as root
|
||||
final TreeItem institutions = this.widgetFactory.treeItemLocalized(
|
||||
navigation,
|
||||
Activity.INSTITUTION_LIST.title);
|
||||
injectActivitySelection(institutions, Activity.INSTITUTION_LIST.createSelection());
|
||||
ActionDefinition.INSTITUTION_VIEW_LIST.title);
|
||||
injectActivitySelection(
|
||||
institutions,
|
||||
pageContext.createAction(ActionDefinition.INSTITUTION_VIEW_LIST));
|
||||
|
||||
} else {
|
||||
// otherwise show the form of the institution for current user
|
||||
final TreeItem institutions = this.widgetFactory.treeItemLocalized(
|
||||
navigation,
|
||||
Activity.INSTITUTION_FORM.title);
|
||||
ActionDefinition.INSTITUTION_VIEW_FORM.title);
|
||||
injectActivitySelection(
|
||||
institutions,
|
||||
Activity.INSTITUTION_FORM.createSelection()
|
||||
.withEntity(new EntityKey(userInfo.institutionId, EntityType.INSTITUTION))
|
||||
pageContext.createAction(ActionDefinition.INSTITUTION_VIEW_FORM)
|
||||
.withEntity(userInfo.institutionId, EntityType.INSTITUTION)
|
||||
.withAttribute(AttributeKeys.READ_ONLY, "true"));
|
||||
}
|
||||
|
||||
|
@ -118,73 +101,40 @@ public class ActivitiesPane implements TemplateComposer {
|
|||
if (this.currentUser.hasPrivilege(PrivilegeType.READ_ONLY, EntityType.USER)) {
|
||||
final TreeItem userAccounts = this.widgetFactory.treeItemLocalized(
|
||||
navigation,
|
||||
Activity.USER_ACCOUNT_LIST.title);
|
||||
injectActivitySelection(userAccounts, Activity.USER_ACCOUNT_LIST.createSelection());
|
||||
ActionDefinition.USER_ACCOUNT_VIEW_LIST.title);
|
||||
injectActivitySelection(
|
||||
userAccounts,
|
||||
pageContext.createAction(ActionDefinition.USER_ACCOUNT_VIEW_LIST));
|
||||
} else {
|
||||
// otherwise show the user account form for current user
|
||||
final TreeItem userAccounts = this.widgetFactory.treeItemLocalized(
|
||||
navigation,
|
||||
Activity.USER_ACCOUNT_FORM.title);
|
||||
ActionDefinition.USER_ACCOUNT_VIEW_FORM.title);
|
||||
injectActivitySelection(
|
||||
userAccounts,
|
||||
Activity.USER_ACCOUNT_FORM.createSelection()
|
||||
pageContext.createAction(ActionDefinition.USER_ACCOUNT_VIEW_FORM)
|
||||
.withEntity(this.currentUser.get().getEntityKey())
|
||||
.withAttribute(AttributeKeys.READ_ONLY, "true"));
|
||||
}
|
||||
//
|
||||
// final TreeItem configs = this.widgetFactory.treeItemLocalized(
|
||||
// navigation,
|
||||
// "org.sebserver.activities.sebconfigs");
|
||||
// ActivitySelection.set(configs, Activity.SEB_CONFIGS.createSelection());
|
||||
//
|
||||
// final TreeItem config = this.widgetFactory.treeItemLocalized(
|
||||
// configs,
|
||||
// "org.sebserver.activities.sebconfig");
|
||||
// ActivitySelection.set(config, Activity.SEB_CONFIG.createSelection());
|
||||
//
|
||||
// final TreeItem configTemplates = this.widgetFactory.treeItemLocalized(
|
||||
// configs,
|
||||
// "org.sebserver.activities.sebconfig.templates");
|
||||
// ActivitySelection.set(configTemplates, Activity.SEB_CONFIG_TEMPLATES.createSelection());
|
||||
//
|
||||
// final TreeItem exams = this.widgetFactory.treeItemLocalized(
|
||||
// navigation,
|
||||
// "org.sebserver.activities.exam");
|
||||
// ActivitySelection.set(exams, Activity.EXAMS.createSelection());
|
||||
//
|
||||
// final TreeItem monitoring = this.widgetFactory.treeItemLocalized(
|
||||
// navigation,
|
||||
// "org.sebserver.activities.monitoring");
|
||||
// ActivitySelection.set(monitoring, Activity.MONITORING.createSelection());
|
||||
//
|
||||
// final TreeItem runningExams = this.widgetFactory.treeItemLocalized(
|
||||
// monitoring,
|
||||
// "org.sebserver.activities.runningExams");
|
||||
// ActivitySelection.set(runningExams, Activity.RUNNING_EXAMS.createSelection()
|
||||
// .withExpandFunction(this::runningExamExpand));
|
||||
// runningExams.setItemCount(1);
|
||||
//
|
||||
// final TreeItem logs = this.widgetFactory.treeItemLocalized(
|
||||
// monitoring,
|
||||
// "org.sebserver.activities.logs");
|
||||
// ActivitySelection.set(logs, Activity.LOGS.createSelection());
|
||||
|
||||
navigation.addListener(SWT.Expand, this::handleExpand);
|
||||
navigation.addListener(SWT.Selection, event -> handleSelection(pageContext, event));
|
||||
navigation.setData(
|
||||
PageEventListener.LISTENER_ATTRIBUTE_KEY,
|
||||
new ActionEventListener() {
|
||||
@Override
|
||||
public void notify(final ActionEvent event) {
|
||||
// final ActivityActionHandler aah =
|
||||
// ActivitiesPane.this.activityActionHandler.get(event.actionDefinition);
|
||||
// if (aah != null) {
|
||||
// aah.notifyAction(event, navigation, pageContext);
|
||||
// }
|
||||
// on case of an Action with ActivitySelection, reset the MainPageState
|
||||
if (event.source instanceof ActivitySelection) {
|
||||
final MainPageState mainPageState = MainPageState.get();
|
||||
mainPageState.activitySelection = (ActivitySelection) event.source;
|
||||
final MainPageState mainPageState = MainPageState.get();
|
||||
mainPageState.action = event.action;
|
||||
if (!event.activity) {
|
||||
final EntityKey entityKey = event.action.getEntityKey();
|
||||
final String modelId = (entityKey != null) ? entityKey.modelId : null;
|
||||
final TreeItem item = findItemByActionDefinition(
|
||||
navigation.getItems(),
|
||||
event.action.definition,
|
||||
modelId);
|
||||
if (item != null) {
|
||||
navigation.select(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -192,79 +142,47 @@ public class ActivitiesPane implements TemplateComposer {
|
|||
// page-selection on (re)load
|
||||
final MainPageState mainPageState = MainPageState.get();
|
||||
|
||||
if (mainPageState.activitySelection == null ||
|
||||
mainPageState.activitySelection.activity == Activity.NONE) {
|
||||
mainPageState.activitySelection = getActivitySelection(navigation.getItem(0));
|
||||
if (mainPageState.action == null) {
|
||||
mainPageState.action = getActivitySelection(navigation.getItem(0));
|
||||
}
|
||||
pageContext.publishPageEvent(
|
||||
new ActivitySelectionEvent(mainPageState.activitySelection));
|
||||
new ActionEvent(mainPageState.action, false));
|
||||
navigation.select(navigation.getItem(0));
|
||||
}
|
||||
|
||||
// private void runningExamExpand(final TreeItem item) {
|
||||
// item.removeAll();
|
||||
// final List<EntityName> runningExamNames = this.restService
|
||||
// .sebServerCall(GetRunningExamNames.class)
|
||||
// .onError(t -> {
|
||||
// throw new RuntimeException(t);
|
||||
// });
|
||||
//
|
||||
// if (runningExamNames != null) {
|
||||
// for (final EntityName runningExamName : runningExamNames) {
|
||||
// final TreeItem runningExams = this.widgetFactory.treeItemLocalized(
|
||||
// item,
|
||||
// runningExamName.name);
|
||||
// ActivitySelection.set(runningExams, Activity.RUNNING_EXAM.createSelection(runningExamName));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
private void handleExpand(final Event event) {
|
||||
final TreeItem treeItem = (TreeItem) event.item;
|
||||
|
||||
System.out.println("opened: " + treeItem);
|
||||
|
||||
final ActivitySelection activity = getActivitySelection(treeItem);
|
||||
if (activity != null) {
|
||||
activity.processExpand(treeItem);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSelection(final PageContext composerCtx, final Event event) {
|
||||
final TreeItem treeItem = (TreeItem) event.item;
|
||||
|
||||
System.out.println("selected: " + treeItem);
|
||||
|
||||
final MainPageState mainPageState = MainPageState.get();
|
||||
final ActivitySelection activitySelection = getActivitySelection(treeItem);
|
||||
if (mainPageState.activitySelection == null) {
|
||||
mainPageState.activitySelection = Activity.NONE.createSelection();
|
||||
}
|
||||
if (!mainPageState.activitySelection.equals(activitySelection)) {
|
||||
mainPageState.activitySelection = activitySelection;
|
||||
final Action action = getActivitySelection(treeItem);
|
||||
if (mainPageState.action.definition != action.definition) {
|
||||
mainPageState.action = action;
|
||||
composerCtx.publishPageEvent(
|
||||
new ActivitySelectionEvent(mainPageState.activitySelection));
|
||||
new ActionEvent(action, true));
|
||||
}
|
||||
}
|
||||
|
||||
static final TreeItem findItemByActivity(
|
||||
static final TreeItem findItemByActionDefinition(
|
||||
final TreeItem[] items,
|
||||
final Activity activity,
|
||||
final String objectId) {
|
||||
final ActionDefinition actionDefinition,
|
||||
final String modelId) {
|
||||
|
||||
if (items == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (final TreeItem item : items) {
|
||||
final ActivitySelection activitySelection = getActivitySelection(item);
|
||||
final String id = activitySelection.getEntityId();
|
||||
if (activitySelection != null && activitySelection.activity == activity &&
|
||||
(id == null || (objectId != null && objectId.equals(id)))) {
|
||||
final Action action = getActivitySelection(item);
|
||||
final EntityKey entityKey = action.getEntityKey();
|
||||
if (action != null
|
||||
&& (action.definition == actionDefinition || action.definition == actionDefinition.activityAlias) &&
|
||||
(entityKey == null || (modelId != null && modelId.equals(entityKey.modelId)))) {
|
||||
return item;
|
||||
}
|
||||
|
||||
final TreeItem _item = findItemByActivity(item.getItems(), activity, objectId);
|
||||
final TreeItem _item = findItemByActionDefinition(item.getItems(), actionDefinition, modelId);
|
||||
if (_item != null) {
|
||||
return _item;
|
||||
}
|
||||
|
@ -273,8 +191,8 @@ public class ActivitiesPane implements TemplateComposer {
|
|||
return null;
|
||||
}
|
||||
|
||||
static final TreeItem findItemByActivity(final TreeItem[] items, final Activity activity) {
|
||||
return findItemByActivity(items, activity, null);
|
||||
static final TreeItem findItemByActionDefinition(final TreeItem[] items, final ActionDefinition actionDefinition) {
|
||||
return findItemByActionDefinition(items, actionDefinition, null);
|
||||
}
|
||||
|
||||
static final void expand(final TreeItem item) {
|
||||
|
@ -286,12 +204,12 @@ public class ActivitiesPane implements TemplateComposer {
|
|||
expand(item.getParentItem());
|
||||
}
|
||||
|
||||
public static ActivitySelection getActivitySelection(final TreeItem item) {
|
||||
return (ActivitySelection) item.getData(ATTR_ACTIVITY_SELECTION);
|
||||
public static Action getActivitySelection(final TreeItem item) {
|
||||
return (Action) item.getData(ATTR_ACTIVITY_SELECTION);
|
||||
}
|
||||
|
||||
public static void injectActivitySelection(final TreeItem item, final ActivitySelection selection) {
|
||||
item.setData(ATTR_ACTIVITY_SELECTION, selection);
|
||||
public static void injectActivitySelection(final TreeItem item, final Action action) {
|
||||
item.setData(ATTR_ACTIVITY_SELECTION, action);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,81 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.content.activity;
|
||||
|
||||
import ch.ethz.seb.sebserver.gui.content.InstitutionForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.InstitutionList;
|
||||
import ch.ethz.seb.sebserver.gui.content.UserAccountForm;
|
||||
import ch.ethz.seb.sebserver.gui.content.UserAccountList;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionPane;
|
||||
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.page.activity.ActivitySelection;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.impl.TODOTemplate;
|
||||
|
||||
public enum Activity {
|
||||
NONE(TODOTemplate.class, TODOTemplate.class),
|
||||
INSTITUTION_LIST(
|
||||
InstitutionList.class,
|
||||
ActionPane.class,
|
||||
new LocTextKey("sebserver.activities.institution")),
|
||||
INSTITUTION_FORM(
|
||||
InstitutionForm.class,
|
||||
ActionPane.class,
|
||||
new LocTextKey("sebserver.activities.institution")),
|
||||
|
||||
USER_ACCOUNT_LIST(
|
||||
UserAccountList.class,
|
||||
ActionPane.class,
|
||||
new LocTextKey("sebserver.activities.useraccount")),
|
||||
|
||||
USER_ACCOUNT_FORM(
|
||||
UserAccountForm.class,
|
||||
ActionPane.class,
|
||||
new LocTextKey("sebserver.activities.useraccount")),
|
||||
|
||||
// USERS(UserAccountsForm.class, ActionPane.class),
|
||||
//
|
||||
// EXAMS(ExamsListPage.class, ActionPane.class),
|
||||
// SEB_CONFIGS(SEBConfigurationForm.class, ActionPane.class),
|
||||
// SEB_CONFIG(SEBConfigurationPage.class, ActionPane.class),
|
||||
// SEB_CONFIG_TEMPLATES(TODOTemplate.class, ActionPane.class),
|
||||
// MONITORING(MonitoringForm.class, ActionPane.class),
|
||||
// RUNNING_EXAMS(RunningExamForm.class, ActionPane.class),
|
||||
// RUNNING_EXAM(RunningExamPage.class, ActionPane.class, AttributeKeys.EXAM_ID),
|
||||
// LOGS(TODOTemplate.class, ActionPane.class),
|
||||
;
|
||||
|
||||
public final LocTextKey title;
|
||||
public final Class<? extends TemplateComposer> contentPaneComposer;
|
||||
public final Class<? extends TemplateComposer> actionPaneComposer;
|
||||
//public final String modelIdAttribute;
|
||||
|
||||
private Activity(
|
||||
final Class<? extends TemplateComposer> objectPaneComposer,
|
||||
final Class<? extends TemplateComposer> selectionPaneComposer,
|
||||
final LocTextKey title) {
|
||||
|
||||
this.title = title;
|
||||
this.contentPaneComposer = objectPaneComposer;
|
||||
this.actionPaneComposer = selectionPaneComposer;
|
||||
}
|
||||
|
||||
private Activity(
|
||||
final Class<? extends TemplateComposer> objectPaneComposer,
|
||||
final Class<? extends TemplateComposer> selectionPaneComposer) {
|
||||
|
||||
this.title = null;
|
||||
this.contentPaneComposer = objectPaneComposer;
|
||||
this.actionPaneComposer = selectionPaneComposer;
|
||||
}
|
||||
|
||||
public final ActivitySelection createSelection() {
|
||||
return new ActivitySelection(this);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* 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/.
|
||||
|
@ -10,13 +10,14 @@ package ch.ethz.seb.sebserver.gui.form;
|
|||
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
abstract class FieldBuilder {
|
||||
public abstract class FieldBuilder {
|
||||
int spanLabel = -1;
|
||||
int spanInput = -1;
|
||||
int spanEmptyCell = -1;
|
||||
boolean autoEmptyCellSeparation = false;
|
||||
String group = null;
|
||||
BooleanSupplier condition = null;
|
||||
boolean readonly = false;
|
||||
|
||||
final String name;
|
||||
final String label;
|
||||
|
@ -58,6 +59,16 @@ abstract class FieldBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public FieldBuilder readonly(final boolean readonly) {
|
||||
this.readonly = readonly;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FieldBuilder readonlyIf(final BooleanSupplier readonly) {
|
||||
this.readonly = readonly != null && readonly.getAsBoolean();
|
||||
return this;
|
||||
}
|
||||
|
||||
abstract void build(FormBuilder builder);
|
||||
|
||||
}
|
|
@ -44,7 +44,6 @@ public final class Form implements FormBinding {
|
|||
|
||||
private final Map<String, String> staticValues = new LinkedHashMap<>();
|
||||
private final MultiValueMap<String, FormFieldAccessor> formFields = new LinkedMultiValueMap<>();
|
||||
//private final Map<String, List<FormFieldAccessor>> formFields = new LinkedHashMap<>();
|
||||
private final Map<String, Form> subForms = new LinkedHashMap<>();
|
||||
private final Map<String, List<Form>> subLists = new LinkedHashMap<>();
|
||||
private final Map<String, Set<String>> groups = new LinkedHashMap<>();
|
||||
|
|
|
@ -10,10 +10,10 @@ package ch.ethz.seb.sebserver.gui.form;
|
|||
|
||||
import java.util.List;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.rap.rwt.RWT;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
|
@ -25,6 +25,7 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
|
||||
|
@ -159,15 +160,13 @@ public class FormBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public <T> FormHandle<T> buildFor(
|
||||
final RestCall<T> post,
|
||||
final Function<T, T> postPostHandle) {
|
||||
public <T extends Entity> FormHandle<T> buildFor(
|
||||
final RestCall<T> post) {
|
||||
|
||||
return new FormHandle<>(
|
||||
this.pageContext,
|
||||
this.form,
|
||||
post,
|
||||
(postPostHandle == null) ? Function.identity() : postPostHandle,
|
||||
this.polyglotPageService.getI18nSupport());
|
||||
}
|
||||
|
||||
|
@ -177,6 +176,10 @@ public class FormBuilder {
|
|||
empty.setText("");
|
||||
}
|
||||
|
||||
public static TextFieldBuilder text(final String name, final String label) {
|
||||
return new TextFieldBuilder(name, label, null);
|
||||
}
|
||||
|
||||
public static TextFieldBuilder text(final String name, final String label, final String value) {
|
||||
return new TextFieldBuilder(name, label, value);
|
||||
}
|
||||
|
@ -207,8 +210,9 @@ 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);
|
||||
gridData.verticalIndent = 5;
|
||||
gridData.verticalIndent = 4;
|
||||
label.setLayoutData(gridData);
|
||||
label.setData(RWT.CUSTOM_VARIANT, "head");
|
||||
return label;
|
||||
}
|
||||
|
||||
|
@ -216,6 +220,7 @@ public class FormBuilder {
|
|||
final Label label = new Label(parent, SWT.NONE);
|
||||
label.setText((StringUtils.isNoneBlank(value)) ? value : Constants.EMPTY_NOTE);
|
||||
final GridData gridData = new GridData(SWT.LEFT, SWT.CENTER, true, false, hspan, 1);
|
||||
gridData.verticalIndent = 4;
|
||||
label.setLayoutData(gridData);
|
||||
return label;
|
||||
}
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
package ch.ethz.seb.sebserver.gui.form;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.form.Form.FormFieldAccessor;
|
||||
|
@ -21,12 +21,13 @@ 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.FieldValidationError;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.action.Action;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCallError;
|
||||
|
||||
public class FormHandle<T> {
|
||||
public class FormHandle<T extends Entity> {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(FormHandle.class);
|
||||
|
||||
|
@ -35,28 +36,26 @@ public class FormHandle<T> {
|
|||
private final PageContext pageContext;
|
||||
private final Form form;
|
||||
private final RestCall<T> post;
|
||||
private final Function<T, T> postPostHandle;
|
||||
private final I18nSupport i18nSupport;
|
||||
|
||||
FormHandle(
|
||||
final PageContext pageContext,
|
||||
final Form form,
|
||||
final RestCall<T> post,
|
||||
final Function<T, T> postPostHandle,
|
||||
final I18nSupport i18nSupport) {
|
||||
|
||||
this.pageContext = pageContext;
|
||||
this.form = form;
|
||||
this.post = post;
|
||||
this.postPostHandle = postPostHandle;
|
||||
this.i18nSupport = i18nSupport;
|
||||
}
|
||||
|
||||
public final Result<T> postChanges(final Action action) {
|
||||
return doAPIPost(action.definition);
|
||||
public final Action postChanges(final Action action) {
|
||||
return doAPIPost(action.definition)
|
||||
.getOrThrow();
|
||||
}
|
||||
|
||||
public Result<T> doAPIPost(final ActionDefinition action) {
|
||||
public Result<Action> doAPIPost(final ActionDefinition actionDefinition) {
|
||||
this.form.process(
|
||||
name -> true,
|
||||
fieldAccessor -> fieldAccessor.resetError());
|
||||
|
@ -66,11 +65,15 @@ public class FormHandle<T> {
|
|||
.withFormBinding(this.form)
|
||||
.call()
|
||||
.map(result -> {
|
||||
this.pageContext.publishPageEvent(new ActionEvent(action, result));
|
||||
return result;
|
||||
final Action action = this.pageContext.createAction(actionDefinition)
|
||||
.withAttribute(AttributeKeys.READ_ONLY, "true")
|
||||
.withEntity(result.getEntityKey());
|
||||
this.pageContext.publishPageEvent(new ActionEvent(action, false));
|
||||
return action;
|
||||
})
|
||||
.onErrorDo(this::handleError)
|
||||
.map(this.postPostHandle);
|
||||
//.map(this.postPostHandle)
|
||||
;
|
||||
}
|
||||
|
||||
private void handleError(final Throwable error) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* 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/.
|
||||
|
@ -27,7 +27,7 @@ public final class ImageUploadFieldBuilder extends FieldBuilder {
|
|||
final ImageUpload imageUpload = builder.widgetFactory.imageUploadLocalized(
|
||||
builder.formParent,
|
||||
new LocTextKey("sebserver.overall.upload"),
|
||||
builder.readonly);
|
||||
builder.readonly || this.readonly);
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false, this.spanInput, 1);
|
||||
imageUpload.setLayoutData(gridData);
|
||||
imageUpload.setImageBase64(this.value);
|
||||
|
|
|
@ -13,11 +13,13 @@ import java.util.Collection;
|
|||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.rap.rwt.RWT;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Control;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
|
||||
|
@ -26,6 +28,7 @@ import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
|||
import ch.ethz.seb.sebserver.gui.widget.MultiSelection;
|
||||
import ch.ethz.seb.sebserver.gui.widget.Selection;
|
||||
import ch.ethz.seb.sebserver.gui.widget.SingleSelection;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
|
||||
|
||||
public final class SelectionFieldBuilder extends FieldBuilder {
|
||||
|
||||
|
@ -56,7 +59,7 @@ public final class SelectionFieldBuilder extends FieldBuilder {
|
|||
@Override
|
||||
void build(final FormBuilder builder) {
|
||||
final Label lab = builder.labelLocalized(builder.formParent, this.label, this.spanLabel);
|
||||
if (builder.readonly) {
|
||||
if (builder.readonly || this.readonly) {
|
||||
buildReadOnly(builder, lab);
|
||||
} else {
|
||||
buildInput(builder, lab);
|
||||
|
@ -85,38 +88,45 @@ public final class SelectionFieldBuilder extends FieldBuilder {
|
|||
|
||||
/* Build the read-only representation of the selection field */
|
||||
private void buildReadOnly(final FormBuilder builder, final Label lab) {
|
||||
builder.form.putField(
|
||||
this.name, lab,
|
||||
builder.valueLabel(
|
||||
builder.formParent,
|
||||
getSelectionValue(this.value, this.multi),
|
||||
this.spanInput));
|
||||
}
|
||||
if (this.multi) {
|
||||
final Composite composite = new Composite(builder.formParent, SWT.NONE);
|
||||
final GridLayout gridLayout = new GridLayout(1, true);
|
||||
gridLayout.verticalSpacing = 1;
|
||||
gridLayout.marginLeft = 0;
|
||||
gridLayout.marginHeight = 0;
|
||||
gridLayout.marginWidth = 0;
|
||||
composite.setLayout(gridLayout);
|
||||
if (StringUtils.isBlank(this.value)) {
|
||||
createMuliSelectionReadonlyLabel(composite, Constants.EMPTY_NOTE);
|
||||
} else {
|
||||
final Collection<String> keys = Arrays.asList(StringUtils.split(this.value, Constants.LIST_SEPARATOR));
|
||||
this.itemsSupplier.get()
|
||||
.stream()
|
||||
.filter(tuple -> keys.contains(tuple._1))
|
||||
.map(tuple -> tuple._2)
|
||||
.forEach(v -> createMuliSelectionReadonlyLabel(composite, v));
|
||||
}
|
||||
|
||||
/*
|
||||
* For Single selection just the selected value, for multi selection a comma
|
||||
* separated list of values within a String value.
|
||||
*
|
||||
* @param key the key or keys, in case of multi selection a comma separated String of keys
|
||||
*
|
||||
* @param multi indicates multi seleciton
|
||||
*
|
||||
* @return selected value or comma separated String list of selected values
|
||||
*/
|
||||
private String getSelectionValue(final String key, final boolean multi) {
|
||||
if (multi) {
|
||||
final Collection<String> keys = Arrays.asList(StringUtils.split(key, Constants.LIST_SEPARATOR));
|
||||
return StringUtils.join(this.itemsSupplier.get().stream()
|
||||
.filter(tuple -> keys.contains(tuple._1))
|
||||
.map(tuple -> tuple._2)
|
||||
.collect(Collectors.toList()),
|
||||
Constants.LIST_SEPARATOR);
|
||||
} else {
|
||||
return this.itemsSupplier.get().stream()
|
||||
.filter(tuple -> key.equals(tuple._1))
|
||||
.findFirst()
|
||||
.map(tuple -> tuple._2)
|
||||
.orElse(null);
|
||||
builder.form.putField(
|
||||
this.name, lab,
|
||||
builder.valueLabel(
|
||||
builder.formParent,
|
||||
this.itemsSupplier.get().stream()
|
||||
.filter(tuple -> this.value.equals(tuple._1))
|
||||
.findFirst()
|
||||
.map(tuple -> tuple._2)
|
||||
.orElse(null),
|
||||
this.spanInput));
|
||||
}
|
||||
}
|
||||
|
||||
private void createMuliSelectionReadonlyLabel(final Composite composite, final String value) {
|
||||
final Label label = new Label(composite, SWT.NONE);
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.CENTER, true, true);
|
||||
label.setLayoutData(gridData);
|
||||
label.setData(RWT.CUSTOM_VARIANT, CustomVariant.SELECTION_READONLY.key);
|
||||
label.setText(value);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* 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/.
|
||||
|
@ -33,7 +33,7 @@ public final class TextFieldBuilder extends FieldBuilder {
|
|||
}
|
||||
|
||||
final Label lab = builder.labelLocalized(builder.formParent, this.label, this.spanLabel);
|
||||
if (builder.readonly) {
|
||||
if (builder.readonly || this.readonly) {
|
||||
builder.form.putField(this.name, lab,
|
||||
builder.valueLabel(builder.formParent, this.value, this.spanInput));
|
||||
} else {
|
||||
|
|
|
@ -15,7 +15,6 @@ import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
|||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.action.Action;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.activity.ActivitySelection;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.PageEvent;
|
||||
|
||||
public interface PageContext {
|
||||
|
@ -75,6 +74,8 @@ public interface PageContext {
|
|||
* @return the parent Component */
|
||||
Composite getParent();
|
||||
|
||||
PageContext copy();
|
||||
|
||||
/** Create a copy of this PageContext with a new parent Composite.
|
||||
*
|
||||
* @param parent the new parent Composite
|
||||
|
@ -95,11 +96,11 @@ public interface PageContext {
|
|||
* @return this PageContext instance (builder pattern) */
|
||||
PageContext withAttribute(String key, String value);
|
||||
|
||||
default PageContext withSelection(final ActivitySelection selection) {
|
||||
return withSelection(selection, true);
|
||||
}
|
||||
|
||||
PageContext withSelection(ActivitySelection selection, boolean clearAttributes);
|
||||
// default PageContext withSelection(final ActivitySelection selection) {
|
||||
// return withSelection(selection, true);
|
||||
// }
|
||||
//
|
||||
// PageContext withSelection(ActivitySelection selection, boolean clearAttributes);
|
||||
|
||||
String getAttribute(String name);
|
||||
|
||||
|
@ -157,5 +158,4 @@ public interface PageContext {
|
|||
void publishPageMessage(LocTextKey title, LocTextKey message);
|
||||
|
||||
void publishPageMessage(PageMessageException pme);
|
||||
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
||||
|
@ -57,6 +58,7 @@ public final class PageUtils {
|
|||
|
||||
public static List<Tuple<String>> getInstitutionSelectionResource(final RestService restService) {
|
||||
return restService.getBuilder(GetInstitutionNames.class)
|
||||
.withQueryParam(Domain.INSTITUTION.ATTR_ACTIVE, "true")
|
||||
.call()
|
||||
.getOr(Collections.emptyList())
|
||||
.stream()
|
||||
|
|
|
@ -16,10 +16,12 @@ import java.util.function.Supplier;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
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;
|
||||
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.PageContext.AttributeKeys;
|
||||
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;
|
||||
|
@ -31,7 +33,6 @@ public final class Action implements Runnable {
|
|||
private static final Logger log = LoggerFactory.getLogger(Action.class);
|
||||
|
||||
public final RestService restService;
|
||||
public final PageContext pageContext;
|
||||
public final ActionDefinition definition;
|
||||
Supplier<LocTextKey> confirm;
|
||||
LocTextKey successMessage;
|
||||
|
@ -39,7 +40,8 @@ public final class Action implements Runnable {
|
|||
|
||||
Supplier<Set<String>> selectionSupplier;
|
||||
|
||||
private Function<Action, Result<?>> exec;
|
||||
private PageContext pageContext;
|
||||
private Function<Action, Action> exec = Function.identity();
|
||||
|
||||
public Action(
|
||||
final ActionDefinition definition,
|
||||
|
@ -66,13 +68,15 @@ public final class Action implements Runnable {
|
|||
private void exec() {
|
||||
try {
|
||||
|
||||
this.exec.apply(this)
|
||||
.map(value -> {
|
||||
this.pageContext.publishPageEvent(
|
||||
new ActionEvent(this.definition, value));
|
||||
return value;
|
||||
})
|
||||
.getOrThrow();
|
||||
this.pageContext.publishPageEvent(new ActionEvent(this.exec.apply(this), false));
|
||||
|
||||
// this.exec.apply(this)
|
||||
// .map(action -> {
|
||||
// this.pageContext.publishPageEvent(
|
||||
// new ActionEvent(action, false));
|
||||
// return action;
|
||||
// })
|
||||
// .getOrThrow();
|
||||
|
||||
} catch (final PageMessageException pme) {
|
||||
Action.this.pageContext.publishPageMessage(pme);
|
||||
|
@ -96,7 +100,7 @@ public final class Action implements Runnable {
|
|||
return this.selectionSupplier;
|
||||
}
|
||||
|
||||
public Action withExec(final Function<Action, Result<?>> exec) {
|
||||
public Action withExec(final Function<Action, Action> exec) {
|
||||
this.exec = exec;
|
||||
return this;
|
||||
}
|
||||
|
@ -126,6 +130,38 @@ public final class Action implements Runnable {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Action withEntity(final EntityKey entityKey) {
|
||||
this.pageContext = this.pageContext.withEntityKey(entityKey);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Action withEntity(final Long modelId, final EntityType entityType) {
|
||||
if (modelId != null) {
|
||||
return withEntity(String.valueOf(modelId), entityType);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Action withEntity(final String modelId, final EntityType entityType) {
|
||||
if (modelId == null || entityType == null) {
|
||||
return this;
|
||||
}
|
||||
|
||||
this.pageContext = this.pageContext.withEntityKey(new EntityKey(modelId, entityType));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Action withParentEntity(final EntityKey entityKey) {
|
||||
this.pageContext = this.pageContext.withParentEntityKey(entityKey);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Action withAttribute(final String name, final String value) {
|
||||
this.pageContext = this.pageContext.withAttribute(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PageContext publish() {
|
||||
this.pageContext.publishPageEvent(new ActionPublishEvent(this));
|
||||
return this.pageContext;
|
||||
|
@ -139,4 +175,16 @@ public final class Action implements Runnable {
|
|||
return this.pageContext;
|
||||
}
|
||||
|
||||
public EntityKey getEntityKey() {
|
||||
return this.pageContext.getEntityKey();
|
||||
}
|
||||
|
||||
public PageContext pageContext() {
|
||||
return this.pageContext;
|
||||
}
|
||||
|
||||
public Action readonly(final boolean b) {
|
||||
return this.withAttribute(AttributeKeys.READ_ONLY, "false");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.page.activity;
|
||||
|
||||
import org.eclipse.swt.widgets.Tree;
|
||||
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
|
||||
|
||||
public interface ActivityActionHandler {
|
||||
|
||||
public ActionDefinition handlesAction();
|
||||
|
||||
void notifyAction(
|
||||
final ActionEvent event,
|
||||
final Tree navigation,
|
||||
final PageContext composerCtx);
|
||||
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.page.activity;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.eclipse.swt.widgets.TreeItem;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gui.content.activity.Activity;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
|
||||
|
||||
public class ActivitySelection {
|
||||
|
||||
public static final Consumer<TreeItem> EMPTY_FUNCTION = ti -> {
|
||||
};
|
||||
public static final Consumer<TreeItem> COLLAPSE_NONE_EMPTY = ti -> {
|
||||
ti.removeAll();
|
||||
ti.setItemCount(1);
|
||||
};
|
||||
|
||||
public final Activity activity;
|
||||
final Map<String, String> attributes;
|
||||
Consumer<TreeItem> expandFunction = EMPTY_FUNCTION;
|
||||
|
||||
public ActivitySelection(final Activity activity) {
|
||||
this.activity = activity;
|
||||
this.attributes = new HashMap<>();
|
||||
}
|
||||
|
||||
public ActivitySelection withEntity(final EntityKey entityKey) {
|
||||
if (entityKey != null) {
|
||||
this.attributes.put(AttributeKeys.ENTITY_ID, entityKey.modelId);
|
||||
this.attributes.put(AttributeKeys.ENTITY_TYPE, entityKey.entityType.name());
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ActivitySelection withParentEntity(final EntityKey parentEntityKey) {
|
||||
if (parentEntityKey != null) {
|
||||
this.attributes.put(AttributeKeys.PARENT_ENTITY_ID, parentEntityKey.modelId);
|
||||
this.attributes.put(AttributeKeys.PARENT_ENTITY_TYPE, parentEntityKey.entityType.name());
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ActivitySelection withAttribute(final String name, final String value) {
|
||||
this.attributes.put(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Map<String, String> getAttributes() {
|
||||
return Collections.unmodifiableMap(this.attributes);
|
||||
}
|
||||
|
||||
public ActivitySelection withExpandFunction(final Consumer<TreeItem> expandFunction) {
|
||||
if (expandFunction == null) {
|
||||
this.expandFunction = EMPTY_FUNCTION;
|
||||
}
|
||||
this.expandFunction = expandFunction;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void processExpand(final TreeItem item) {
|
||||
this.expandFunction.accept(item);
|
||||
}
|
||||
|
||||
public String getEntityId() {
|
||||
return this.attributes.get(AttributeKeys.ENTITY_ID);
|
||||
}
|
||||
|
||||
}
|
|
@ -8,21 +8,19 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.gui.service.page.event;
|
||||
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.action.Action;
|
||||
|
||||
/** This Event is used to propagate a user-action to the GUI system.
|
||||
* Potentially every component can listen to an Event and react on the user-action */
|
||||
public final class ActionEvent implements PageEvent {
|
||||
|
||||
public final ActionDefinition actionDefinition;
|
||||
public final Object source;
|
||||
public final Action action;
|
||||
public final boolean activity;
|
||||
|
||||
public ActionEvent(
|
||||
final ActionDefinition actionDefinition,
|
||||
final Object source) {
|
||||
|
||||
this.actionDefinition = actionDefinition;
|
||||
this.source = source;
|
||||
public ActionEvent(final Action action, final boolean activity) {
|
||||
super();
|
||||
this.action = action;
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,13 +8,6 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.gui.service.page.event;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.eclipse.swt.widgets.Widget;
|
||||
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
|
||||
public interface ActionEventListener extends PageEventListener<ActionEvent> {
|
||||
|
||||
@Override
|
||||
|
@ -32,42 +25,42 @@ public interface ActionEventListener extends PageEventListener<ActionEvent> {
|
|||
// }
|
||||
//
|
||||
|
||||
static ActionEventListener of(
|
||||
final Predicate<ActionEvent> predicate,
|
||||
final Consumer<ActionEvent> eventConsumer) {
|
||||
// static ActionEventListener of(
|
||||
// final Predicate<ActionEvent> predicate,
|
||||
// final Consumer<ActionEvent> eventConsumer) {
|
||||
//
|
||||
// return new ActionEventListener() {
|
||||
// @Override
|
||||
// public void notify(final ActionEvent event) {
|
||||
// if (predicate.test(event)) {
|
||||
// eventConsumer.accept(event);
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
|
||||
return new ActionEventListener() {
|
||||
@Override
|
||||
public void notify(final ActionEvent event) {
|
||||
if (predicate.test(event)) {
|
||||
eventConsumer.accept(event);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static ActionEventListener of(
|
||||
final ActionDefinition actionDefinition,
|
||||
final Consumer<ActionEvent> eventConsumer) {
|
||||
|
||||
return new ActionEventListener() {
|
||||
@Override
|
||||
public void notify(final ActionEvent event) {
|
||||
if (event.actionDefinition == actionDefinition) {
|
||||
eventConsumer.accept(event);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static void injectListener(
|
||||
final Widget widget,
|
||||
final ActionDefinition actionDefinition,
|
||||
final Consumer<ActionEvent> eventConsumer) {
|
||||
|
||||
widget.setData(
|
||||
PageEventListener.LISTENER_ATTRIBUTE_KEY,
|
||||
of(actionDefinition, eventConsumer));
|
||||
}
|
||||
// static ActionEventListener of(
|
||||
// final ActionDefinition actionDefinition,
|
||||
// final Consumer<ActionEvent> eventConsumer) {
|
||||
//
|
||||
// return new ActionEventListener() {
|
||||
// @Override
|
||||
// public void notify(final ActionEvent event) {
|
||||
// if (event.actionDefinition == actionDefinition) {
|
||||
// eventConsumer.accept(event);
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
//
|
||||
// static void injectListener(
|
||||
// final Widget widget,
|
||||
// final ActionDefinition actionDefinition,
|
||||
// final Consumer<ActionEvent> eventConsumer) {
|
||||
//
|
||||
// widget.setData(
|
||||
// PageEventListener.LISTENER_ATTRIBUTE_KEY,
|
||||
// of(actionDefinition, eventConsumer));
|
||||
// }
|
||||
|
||||
}
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.page.event;
|
||||
|
||||
import ch.ethz.seb.sebserver.gui.service.page.activity.ActivitySelection;
|
||||
|
||||
public class ActivitySelectionEvent implements PageEvent {
|
||||
|
||||
public final ActivitySelection selection;
|
||||
|
||||
public ActivitySelectionEvent(final ActivitySelection selection) {
|
||||
this.selection = selection;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.page.event;
|
||||
|
||||
public interface ActivitySelectionListener extends PageEventListener<ActivitySelectionEvent> {
|
||||
|
||||
@Override
|
||||
default boolean match(final Class<? extends PageEvent> eventType) {
|
||||
return eventType == ActivitySelectionEvent.class;
|
||||
}
|
||||
|
||||
}
|
|
@ -15,14 +15,13 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ch.ethz.seb.sebserver.gui.content.MainPage;
|
||||
import ch.ethz.seb.sebserver.gui.content.activity.Activity;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.activity.ActivitySelection;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.action.Action;
|
||||
|
||||
public final class MainPageState {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(MainPageState.class);
|
||||
|
||||
public ActivitySelection activitySelection = Activity.NONE.createSelection();
|
||||
public Action action = null;
|
||||
|
||||
private MainPageState() {
|
||||
}
|
||||
|
@ -49,6 +48,6 @@ public final class MainPageState {
|
|||
|
||||
public static void clear() {
|
||||
final MainPageState mainPageState = get();
|
||||
mainPageState.activitySelection = Activity.NONE.createSelection();
|
||||
mainPageState.action = null;
|
||||
}
|
||||
}
|
|
@ -36,7 +36,6 @@ import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
|||
import ch.ethz.seb.sebserver.gui.service.page.PageDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageMessageException;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.action.Action;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.activity.ActivitySelection;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.PageEvent;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.PageEventListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||
|
@ -95,6 +94,11 @@ public class PageContextImpl implements PageContext {
|
|||
return this.parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageContext copy() {
|
||||
return copyOf(this.parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageContext copyOf(final Composite parent) {
|
||||
return new PageContextImpl(
|
||||
|
@ -134,26 +138,26 @@ public class PageContextImpl implements PageContext {
|
|||
attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageContext withSelection(final ActivitySelection selection, final boolean clearAttributes) {
|
||||
if (selection == null) {
|
||||
return this;
|
||||
}
|
||||
|
||||
final Map<String, String> attrs = new HashMap<>();
|
||||
if (!clearAttributes) {
|
||||
attrs.putAll(this.attributes);
|
||||
}
|
||||
attrs.putAll(selection.getAttributes());
|
||||
|
||||
return new PageContextImpl(
|
||||
this.restService,
|
||||
this.i18nSupport,
|
||||
this.composerService,
|
||||
this.root,
|
||||
this.parent,
|
||||
attrs);
|
||||
}
|
||||
// @Override
|
||||
// public PageContext withSelection(final ActivitySelection selection, final boolean clearAttributes) {
|
||||
// if (selection == null) {
|
||||
// return this;
|
||||
// }
|
||||
//
|
||||
// final Map<String, String> attrs = new HashMap<>();
|
||||
// if (!clearAttributes) {
|
||||
// attrs.putAll(this.attributes);
|
||||
// }
|
||||
// attrs.putAll(selection.getAttributes());
|
||||
//
|
||||
// return new PageContextImpl(
|
||||
// this.restService,
|
||||
// this.i18nSupport,
|
||||
// this.composerService,
|
||||
// this.root,
|
||||
// this.parent,
|
||||
// attrs);
|
||||
// }
|
||||
|
||||
@Override
|
||||
public String getAttribute(final String name) {
|
||||
|
|
|
@ -206,7 +206,6 @@ public abstract class RestCall<T> {
|
|||
} else {
|
||||
this.body = formBinding.getFormUrlEncoded();
|
||||
return this;
|
||||
//return withHeaders(formBinding.getFormAsQueryAttributes());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.useraccount;
|
||||
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class ChangePassword extends RestCall<UserInfo> {
|
||||
|
||||
protected ChangePassword() {
|
||||
super(
|
||||
new TypeReference<UserInfo>() {
|
||||
},
|
||||
HttpMethod.PUT,
|
||||
MediaType.APPLICATION_JSON_UTF8,
|
||||
API.USER_ACCOUNT_ENDPOINT + API.PASSWORD_PATH_SEGMENT);
|
||||
}
|
||||
|
||||
}
|
|
@ -14,20 +14,51 @@ import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
|||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
|
||||
/** Defines functionality for the SEB Server webservice authorization context used to
|
||||
* manage a user session on GUI service. */
|
||||
public interface SEBServerAuthorizationContext {
|
||||
|
||||
/** Indicates if this authorization context is still valid
|
||||
*
|
||||
* @return true if the SEBServerAuthorizationContext is valid. False of not. */
|
||||
boolean isValid();
|
||||
|
||||
/** Indicated whether a user is logged in within this authorization context or not.
|
||||
*
|
||||
* @return whether a user is logged in within this authorization context or not */
|
||||
boolean isLoggedIn();
|
||||
|
||||
/** Requests a login with username and password on SEB Server webservice.
|
||||
* This uses OAuth 2 and Springs OAuth2RestTemplate to exchange user/client credentials
|
||||
* with an access and refresh token.
|
||||
*
|
||||
* @param username the username for login
|
||||
* @param password the password for login
|
||||
* @return */
|
||||
boolean login(String username, String password);
|
||||
|
||||
/** Requests a logout on SEB Server webservice if a user is currently logged in
|
||||
* This uses OAuth 2 and Springs OAuth2RestTemplate to make a revoke token request for the
|
||||
* currently logged in user and also invalidates this SEBServerAuthorizationContext
|
||||
*
|
||||
* @return true if logout was successful */
|
||||
boolean logout();
|
||||
|
||||
/** Gets a Result of the UserInfo data of currently logged in user or of an error if no user is logged in
|
||||
* or there was an unexpected error while trying to get the user information.
|
||||
*
|
||||
* @return Result of logged in user data or of an error on fail */
|
||||
Result<UserInfo> getLoggedInUser();
|
||||
|
||||
/** Returns true if a current logged in user has the specified role.
|
||||
*
|
||||
* @param role the UserRole to check
|
||||
* @return true if a current logged in user has the specified role */
|
||||
public boolean hasRole(UserRole role);
|
||||
|
||||
/** Get the underling RestTemplate to connect and communicate with the SEB Server webservice.
|
||||
*
|
||||
* @return the underling RestTemplate to connect and communicate with the SEB Server webservice */
|
||||
RestTemplate getRestTemplate();
|
||||
|
||||
}
|
||||
|
|
|
@ -176,6 +176,15 @@ public class EntityTable<ROW extends Entity> extends Composite {
|
|||
this.sortOrder);
|
||||
}
|
||||
|
||||
public String getSingleSelection() {
|
||||
final TableItem[] selection = this.table.getSelection();
|
||||
if (selection == null || selection.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return getRowDataId(selection[0]);
|
||||
}
|
||||
|
||||
public Set<String> getSelection() {
|
||||
final TableItem[] selection = this.table.getSelection();
|
||||
if (selection == null) {
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.eclipse.swt.widgets.Label;
|
|||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.CustomVariant;
|
||||
|
||||
public class MultiSelection extends Composite implements Selection {
|
||||
|
||||
|
@ -37,6 +38,8 @@ public class MultiSelection extends Composite implements Selection {
|
|||
final GridLayout gridLayout = new GridLayout(1, true);
|
||||
gridLayout.verticalSpacing = 1;
|
||||
gridLayout.marginLeft = 0;
|
||||
gridLayout.marginHeight = 0;
|
||||
gridLayout.marginWidth = 0;
|
||||
setLayout(gridLayout);
|
||||
}
|
||||
|
||||
|
@ -44,25 +47,29 @@ public class MultiSelection extends Composite implements Selection {
|
|||
public void applyNewMapping(final List<Tuple<String>> mapping) {
|
||||
final String selectionValue = getSelectionValue();
|
||||
this.selected.clear();
|
||||
this.labels.clear();
|
||||
for (final Tuple<String> tuple : mapping) {
|
||||
final Label label = new Label(this, SWT.NONE);
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.CENTER, true, true);
|
||||
label.setLayoutData(gridData);
|
||||
label.setData(OPTION_VALUE, tuple._1);
|
||||
label.setData(RWT.CUSTOM_VARIANT, "selection");
|
||||
label.setText(" " + tuple._2);
|
||||
label.setData(RWT.CUSTOM_VARIANT, CustomVariant.SELECTION.key);
|
||||
label.setText(tuple._2);
|
||||
label.addListener(SWT.MouseDown, event -> {
|
||||
final Label l = (Label) event.widget;
|
||||
if (this.selected.contains(l)) {
|
||||
l.setData(RWT.CUSTOM_VARIANT, "selection");
|
||||
l.setData(RWT.CUSTOM_VARIANT, CustomVariant.SELECTION.key);
|
||||
this.selected.remove(l);
|
||||
} else {
|
||||
l.setData(RWT.CUSTOM_VARIANT, "selected");
|
||||
l.setData(RWT.CUSTOM_VARIANT, CustomVariant.SELECTED.key);
|
||||
this.selected.add(l);
|
||||
}
|
||||
});
|
||||
this.labels.add(label);
|
||||
}
|
||||
if (StringUtils.isNoneBlank(selectionValue)) {
|
||||
select(selectionValue);
|
||||
}
|
||||
select(selectionValue);
|
||||
}
|
||||
|
||||
public void selectOne(final String key) {
|
||||
|
@ -70,7 +77,7 @@ public class MultiSelection extends Composite implements Selection {
|
|||
.filter(label -> key.equals(label.getData(OPTION_VALUE)))
|
||||
.findFirst()
|
||||
.ifPresent(label -> {
|
||||
label.setData(RWT.CUSTOM_VARIANT, "selected");
|
||||
label.setData(RWT.CUSTOM_VARIANT, CustomVariant.SELECTED.key);
|
||||
this.selected.add(label);
|
||||
});
|
||||
}
|
||||
|
@ -80,14 +87,14 @@ public class MultiSelection extends Composite implements Selection {
|
|||
.filter(label -> key.equals(label.getData(OPTION_VALUE)))
|
||||
.findFirst()
|
||||
.ifPresent(label -> {
|
||||
label.setData(RWT.CUSTOM_VARIANT, "selection");
|
||||
label.setData(RWT.CUSTOM_VARIANT, CustomVariant.SELECTION.key);
|
||||
this.selected.remove(label);
|
||||
});
|
||||
}
|
||||
|
||||
public void deselectAll() {
|
||||
for (final Label label : this.selected) {
|
||||
label.setData(RWT.CUSTOM_VARIANT, "selection");
|
||||
label.setData(RWT.CUSTOM_VARIANT, CustomVariant.SELECTION.key);
|
||||
}
|
||||
this.selected.clear();
|
||||
}
|
||||
|
@ -96,10 +103,10 @@ public class MultiSelection extends Composite implements Selection {
|
|||
public void select(final String keys) {
|
||||
this.selected.clear();
|
||||
if (StringUtils.isNotBlank(keys)) {
|
||||
final List<String> split = Arrays.asList(keys.split(keys, Constants.LIST_SEPARATOR_CHAR));
|
||||
final List<String> split = Arrays.asList(StringUtils.split(keys, Constants.LIST_SEPARATOR));
|
||||
for (final Label label : this.labels) {
|
||||
if (split.contains(label.getData(OPTION_VALUE))) {
|
||||
label.setData(RWT.CUSTOM_VARIANT, "selected");
|
||||
label.setData(RWT.CUSTOM_VARIANT, CustomVariant.SELECTED.key);
|
||||
this.selected.add(label);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,7 +49,6 @@ import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
|||
import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEventListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.push.ServerPushService;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
||||
import ch.ethz.seb.sebserver.gui.table.TableBuilder;
|
||||
|
@ -105,6 +104,10 @@ public class WidgetFactory {
|
|||
IMAGE_BUTTON("imageButton"),
|
||||
TEXT_ACTION("action"),
|
||||
|
||||
SELECTION("selection"),
|
||||
SELECTED("selected"),
|
||||
SELECTION_READONLY("selectionReadonly"),
|
||||
|
||||
FOOTER("footer"),
|
||||
|
||||
;
|
||||
|
@ -158,10 +161,10 @@ public class WidgetFactory {
|
|||
final Composite defaultPageLayout = defaultPageLayout(parent);
|
||||
final Label labelLocalizedTitle = labelLocalizedTitle(defaultPageLayout, title);
|
||||
labelLocalizedTitle.setLayoutData(new GridData(SWT.TOP, SWT.LEFT, true, false));
|
||||
ActionEventListener.injectListener(
|
||||
labelLocalizedTitle,
|
||||
actionDefinition,
|
||||
eventFunction.apply(labelLocalizedTitle));
|
||||
// ActionEventListener.injectListener(
|
||||
// labelLocalizedTitle,
|
||||
// actionDefinition,
|
||||
// eventFunction.apply(labelLocalizedTitle));
|
||||
return defaultPageLayout;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ import java.util.Collections;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
|
@ -135,7 +136,10 @@ public class BulkActionService {
|
|||
final List<BulkActionSupportDAO<?>> dependantSupporterInHierarchicalOrder =
|
||||
getDependantSupporterInHierarchicalOrder(action);
|
||||
Collections.reverse(dependantSupporterInHierarchicalOrder);
|
||||
return dependantSupporterInHierarchicalOrder;
|
||||
return dependantSupporterInHierarchicalOrder
|
||||
.stream()
|
||||
.filter(v -> v != null)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
default:
|
||||
return getDependantSupporterInHierarchicalOrder(action);
|
||||
|
|
|
@ -39,4 +39,10 @@ public interface ActivatableEntityDAO<T extends Entity, M extends ModelIdAware>
|
|||
* @return The Collection of Results refer to the EntityKey instance or refer to an error if happened */
|
||||
Result<Collection<EntityKey>> setActive(Set<EntityKey> all, boolean active);
|
||||
|
||||
/** Indicates if the activatable entity with specified model identifier is currently active
|
||||
*
|
||||
* @param modelId the model identifier of the entity
|
||||
* @return true if the entity is active, false otherwise */
|
||||
boolean isActive(String modelId);
|
||||
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ public interface UserActivityLogDAO extends
|
|||
CREATE,
|
||||
IMPORT,
|
||||
MODIFY,
|
||||
PASSWORD_CHANGE,
|
||||
DEACTIVATE,
|
||||
ACTIVATE,
|
||||
DELETE
|
||||
|
|
|
@ -43,6 +43,7 @@ public interface UserDAO extends ActivatableEntityDAO<UserInfo, UserMod>, BulkAc
|
|||
Result<UserInfo> changePassword(String modelId, String newPassword);
|
||||
|
||||
/** Use this to get the SEBServerUser principal for a given username.
|
||||
* This should be used for internal authorization and consider only active user accounts
|
||||
*
|
||||
* @param username The username of the user to get SEBServerUser from
|
||||
* @return a Result of SEBServerUser for specified username. Or an exception result on error case */
|
||||
|
|
|
@ -235,6 +235,21 @@ public class ExamDAOImpl implements ExamDAO {
|
|||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public boolean isActive(final String modelId) {
|
||||
if (StringUtils.isBlank(modelId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.examRecordMapper.countByExample()
|
||||
.where(ExamRecordDynamicSqlSupport.id, isEqualTo(Long.valueOf(modelId)))
|
||||
.and(ExamRecordDynamicSqlSupport.active, isEqualTo(BooleanUtils.toInteger(true)))
|
||||
.build()
|
||||
.execute()
|
||||
.longValue() > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Result<Collection<EntityKey>> delete(final Set<EntityKey> all) {
|
||||
|
|
|
@ -204,6 +204,21 @@ public class InstitutionDAOImpl implements InstitutionDAO {
|
|||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public boolean isActive(final String modelId) {
|
||||
if (StringUtils.isBlank(modelId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.institutionRecordMapper.countByExample()
|
||||
.where(InstitutionRecordDynamicSqlSupport.id, isEqualTo(Long.valueOf(modelId)))
|
||||
.and(InstitutionRecordDynamicSqlSupport.active, isEqualTo(BooleanUtils.toInteger(true)))
|
||||
.build()
|
||||
.execute()
|
||||
.longValue() > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Result<Collection<EntityKey>> delete(final Set<EntityKey> all) {
|
||||
|
@ -266,5 +281,4 @@ public class InstitutionDAOImpl implements InstitutionDAO {
|
|||
record.getLogoImage(),
|
||||
BooleanUtils.toBooleanObject(record.getActive())));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -207,6 +207,21 @@ public class LmsSetupDAOImpl implements LmsSetupDAO {
|
|||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public boolean isActive(final String modelId) {
|
||||
if (StringUtils.isBlank(modelId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.lmsSetupRecordMapper.countByExample()
|
||||
.where(LmsSetupRecordDynamicSqlSupport.id, isEqualTo(Long.valueOf(modelId)))
|
||||
.and(LmsSetupRecordDynamicSqlSupport.active, isEqualTo(BooleanUtils.toInteger(true)))
|
||||
.build()
|
||||
.execute()
|
||||
.longValue() > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Result<Collection<EntityKey>> delete(final Set<EntityKey> all) {
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.util.stream.Collectors;
|
|||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -32,6 +33,7 @@ import org.springframework.stereotype.Component;
|
|||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import ch.ethz.seb.sebserver.WebSecurityConfig;
|
||||
import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage.APIMessageException;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage.ErrorMessage;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
|
@ -276,6 +278,21 @@ public class UserDaoImpl implements UserDAO {
|
|||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public boolean isActive(final String modelId) {
|
||||
if (StringUtils.isBlank(modelId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.userRecordMapper.countByExample()
|
||||
.where(UserRecordDynamicSqlSupport.id, isEqualTo(Long.valueOf(modelId)))
|
||||
.and(UserRecordDynamicSqlSupport.active, isEqualTo(BooleanUtils.toInteger(true)))
|
||||
.build()
|
||||
.execute()
|
||||
.longValue() > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Result<Collection<EntityKey>> delete(final Set<EntityKey> all) {
|
||||
|
@ -307,7 +324,9 @@ public class UserDaoImpl implements UserDAO {
|
|||
@Transactional(readOnly = true)
|
||||
public Set<EntityKey> getDependencies(final BulkAction bulkAction) {
|
||||
// all of institution
|
||||
if (bulkAction.sourceType == EntityType.INSTITUTION) {
|
||||
if (bulkAction.sourceType == EntityType.INSTITUTION &&
|
||||
(bulkAction.type == BulkActionType.DEACTIVATE || bulkAction.type == BulkActionType.HARD_DELETE)) {
|
||||
|
||||
return getDependencies(bulkAction, this::allIdsOfInstitution);
|
||||
}
|
||||
|
||||
|
@ -356,13 +375,13 @@ public class UserDaoImpl implements UserDAO {
|
|||
|
||||
private Result<Collection<EntityKey>> allIdsOfInstitution(final EntityKey institutionKey) {
|
||||
return Result.tryCatch(() -> {
|
||||
return this.userRecordMapper.selectIdsByExample()
|
||||
return this.userRecordMapper.selectByExample()
|
||||
.where(UserRecordDynamicSqlSupport.institutionId,
|
||||
isEqualTo(Long.valueOf(institutionKey.modelId)))
|
||||
.build()
|
||||
.execute()
|
||||
.stream()
|
||||
.map(id -> new EntityKey(id, EntityType.USER))
|
||||
.map(rec -> new EntityKey(rec.getUuid(), EntityType.USER))
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
@ -390,7 +409,7 @@ public class UserDaoImpl implements UserDAO {
|
|||
.selectByExample()
|
||||
.where(UserRecordDynamicSqlSupport.username, isEqualTo(username))
|
||||
.and(UserRecordDynamicSqlSupport.active,
|
||||
isEqualToWhenPresent(BooleanUtils.toInteger(true)))
|
||||
isEqualTo(BooleanUtils.toInteger(true)))
|
||||
.build()
|
||||
.execute());
|
||||
}
|
||||
|
|
|
@ -8,21 +8,37 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.webservice.servicelayer.validation;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.DirectFieldBindingResult;
|
||||
import org.springframework.validation.Validator;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ActivatableEntityDAO;
|
||||
|
||||
@Service
|
||||
@WebServiceProfile
|
||||
public class BeanValidationService {
|
||||
|
||||
private final Validator validator;
|
||||
private final Map<EntityType, ActivatableEntityDAO<?, ?>> activatableDAOs;
|
||||
|
||||
public BeanValidationService(
|
||||
final Validator validator,
|
||||
final Collection<ActivatableEntityDAO<?, ?>> activatableDAOs) {
|
||||
|
||||
public BeanValidationService(final Validator validator) {
|
||||
this.validator = validator;
|
||||
this.activatableDAOs = activatableDAOs
|
||||
.stream()
|
||||
.collect(Collectors.toUnmodifiableMap(
|
||||
dao -> dao.entityType(),
|
||||
dao -> dao));
|
||||
}
|
||||
|
||||
public <T> Result<T> validateBean(final T bean) {
|
||||
|
@ -35,4 +51,13 @@ public class BeanValidationService {
|
|||
return Result.of(bean);
|
||||
}
|
||||
|
||||
public boolean isActive(final EntityKey entityKey) {
|
||||
final ActivatableEntityDAO<?, ?> activatableEntityDAO = this.activatableDAOs.get(entityKey.entityType);
|
||||
if (activatableEntityDAO == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return activatableEntityDAO.isActive(entityKey.modelId);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ public class WebServiceUserDetails implements UserDetailsService {
|
|||
this.userDAO = userDAO;
|
||||
}
|
||||
|
||||
// TODO do we need an institution id here? otherwise username must be unique thought all institutions!
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {
|
||||
return this.userDAO.sebServerUserByUsername(username)
|
||||
|
|
|
@ -15,8 +15,8 @@ import org.springframework.web.bind.annotation.RequestMethod;
|
|||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
|
||||
|
@ -121,15 +121,16 @@ public abstract class ActivatableEntityController<T extends GrantEntity, M exten
|
|||
.getOrThrow();
|
||||
}
|
||||
|
||||
private Result<EntityProcessingReport> setActive(final String id, final boolean active) {
|
||||
private Result<EntityProcessingReport> setActive(final String modelId, final boolean active) {
|
||||
final EntityType entityType = this.entityDAO.entityType();
|
||||
final BulkAction bulkAction = new BulkAction(
|
||||
(active) ? BulkActionType.ACTIVATE : BulkActionType.DEACTIVATE,
|
||||
entityType,
|
||||
new EntityKey(id, entityType));
|
||||
new EntityKey(modelId, entityType));
|
||||
|
||||
return this.entityDAO.byModelId(id)
|
||||
return this.entityDAO.byModelId(modelId)
|
||||
.flatMap(this.authorization::checkWrite)
|
||||
.flatMap(this::validForSave)
|
||||
.flatMap(entity -> this.bulkActionService.createReport(bulkAction));
|
||||
}
|
||||
|
||||
|
|
|
@ -249,6 +249,7 @@ public abstract class EntityController<T extends GrantEntity, M extends GrantEnt
|
|||
|
||||
return this.beanValidationService.validateBean(requestModel)
|
||||
.flatMap(this.entityDAO::createNew)
|
||||
.flatMap(this::validForSave)
|
||||
.flatMap(this.userActivityLogDAO::logCreate)
|
||||
.flatMap(this::notifyCreated)
|
||||
.getOrThrow();
|
||||
|
|
|
@ -11,18 +11,23 @@ package ch.ethz.seb.sebserver.webservice.weblayer.api;
|
|||
import javax.validation.Valid;
|
||||
|
||||
import org.mybatis.dynamic.sql.SqlTable;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.validation.FieldError;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import ch.ethz.seb.sebserver.WebSecurityConfig;
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage.APIMessageException;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage.ErrorMessage;
|
||||
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.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserMod;
|
||||
|
@ -31,6 +36,7 @@ import ch.ethz.seb.sebserver.gbl.util.Result;
|
|||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.UserRecordDynamicSqlSupport;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.SEBServerUser;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO.ActivityType;
|
||||
|
@ -45,6 +51,7 @@ public class UserAccountController extends ActivatableEntityController<UserInfo,
|
|||
|
||||
private final ApplicationEventPublisher applicationEventPublisher;
|
||||
private final UserDAO userDAO;
|
||||
private final PasswordEncoder userPasswordEncoder;
|
||||
|
||||
public UserAccountController(
|
||||
final UserDAO userDAO,
|
||||
|
@ -53,7 +60,8 @@ public class UserAccountController extends ActivatableEntityController<UserInfo,
|
|||
final PaginationService paginationService,
|
||||
final BulkActionService bulkActionService,
|
||||
final ApplicationEventPublisher applicationEventPublisher,
|
||||
final BeanValidationService beanValidationService) {
|
||||
final BeanValidationService beanValidationService,
|
||||
@Qualifier(WebSecurityConfig.USER_PASSWORD_ENCODER_BEAN_NAME) final PasswordEncoder userPasswordEncoder) {
|
||||
|
||||
super(authorization,
|
||||
bulkActionService,
|
||||
|
@ -63,6 +71,7 @@ public class UserAccountController extends ActivatableEntityController<UserInfo,
|
|||
beanValidationService);
|
||||
this.applicationEventPublisher = applicationEventPublisher;
|
||||
this.userDAO = userDAO;
|
||||
this.userPasswordEncoder = userPasswordEncoder;
|
||||
}
|
||||
|
||||
@RequestMapping(path = "/me", method = RequestMethod.GET)
|
||||
|
@ -88,28 +97,60 @@ public class UserAccountController extends ActivatableEntityController<UserInfo,
|
|||
return new UserMod(null, postParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<UserInfo> validForSave(final UserInfo userInfo) {
|
||||
return Result.tryCatch(() -> {
|
||||
// check of institution of UserInfo is active. Otherwise save is not valid
|
||||
if (!this.beanValidationService.isActive(new EntityKey(userInfo.institutionId, EntityType.INSTITUTION))) {
|
||||
throw new IllegalAPIArgumentException(
|
||||
"User within an inactive institution cannot be created nor modified");
|
||||
}
|
||||
return userInfo;
|
||||
});
|
||||
}
|
||||
|
||||
@RequestMapping(
|
||||
path = API.MODEL_ID_VAR_PATH_SEGMENT + API.PASSWORD_PATH_SEGMENT,
|
||||
path = API.PASSWORD_PATH_SEGMENT,
|
||||
method = RequestMethod.PUT,
|
||||
consumes = MediaType.APPLICATION_JSON_VALUE,
|
||||
produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public UserInfo changePassword(
|
||||
@PathVariable final String modelId,
|
||||
@Valid @RequestBody final PasswordChange passwordChange) {
|
||||
|
||||
if (!passwordChange.newPasswordMatch()) {
|
||||
throw new APIMessageException(ErrorMessage.PASSWORD_MISMATCH);
|
||||
}
|
||||
public UserInfo changePassword(@Valid @RequestBody final PasswordChange passwordChange) {
|
||||
|
||||
final String modelId = passwordChange.getModelId();
|
||||
return this.userDAO.byModelId(modelId)
|
||||
.flatMap(this.authorization::checkWrite)
|
||||
.map(ui -> checkPasswordChange(ui, passwordChange))
|
||||
.flatMap(e -> this.userDAO.changePassword(modelId, passwordChange.getNewPassword()))
|
||||
.flatMap(this::revokeAccessToken)
|
||||
.flatMap(e -> this.userActivityLogDAO.log(ActivityType.MODIFY, e))
|
||||
|
||||
.flatMap(e -> this.userActivityLogDAO.log(ActivityType.PASSWORD_CHANGE, e))
|
||||
.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,
|
||||
"old password is wrong")));
|
||||
}
|
||||
|
||||
if (!passwordChange.newPasswordMatch()) {
|
||||
|
||||
throw new APIMessageException(APIMessage.fieldValidationError(
|
||||
new FieldError(
|
||||
"passwordChange",
|
||||
PasswordChange.ATTR_NAME_RETYPED_NEW_PASSWORD,
|
||||
"old password is wrong")));
|
||||
}
|
||||
|
||||
return info;
|
||||
|
||||
}
|
||||
|
||||
private Result<UserInfo> revokeAccessToken(final UserInfo userInfo) {
|
||||
return Result.tryCatch(() -> {
|
||||
this.applicationEventPublisher.publishEvent(
|
||||
|
|
|
@ -1,13 +1,31 @@
|
|||
INSERT INTO institution VALUES
|
||||
(1, 'ETH Zürich', 'ethz', null, 1)
|
||||
(1, 'ETH Zürich', 'ethz', null, 1),
|
||||
(2, 'Institution 2', 'inst2', null, 1),
|
||||
(3, 'Institution 3', 'inst3', null, 0),
|
||||
(4, 'Institution 4', 'inst4', null, 0),
|
||||
(5, 'Institution 5', 'inst5', null, 0),
|
||||
(6, 'Institution 6', 'inst6', null, 0),
|
||||
(7, 'Institution 7', 'inst7', null, 0),
|
||||
(8, 'Institution 8', 'inst8', null, 0)
|
||||
;
|
||||
|
||||
INSERT INTO user VALUES
|
||||
(1, 1, 'internalDemoAdmin', 'Admin1', 'admin', '$2a$08$c2GKYEYoUVXH1Yb8GXVXVu66ltPvbZgLMcVSXRH.LgZNF/YeaYB8m', 'admin@nomail.nomail', 'en', 'UTC', 1)
|
||||
(1, 1, 'super-admin', 'super-admin', 'super-admin', '$2a$08$c2GKYEYoUVXH1Yb8GXVXVu66ltPvbZgLMcVSXRH.LgZNF/YeaYB8m', 'super-admin@nomail.nomail', 'en', 'UTC', 1),
|
||||
(2, 1, 'internalDemoAdmin', 'Admin1', 'admin', '$2a$08$c2GKYEYoUVXH1Yb8GXVXVu66ltPvbZgLMcVSXRH.LgZNF/YeaYB8m', 'admin@nomail.nomail', 'en', 'UTC', 1),
|
||||
(3, 1, 'inst1Admin', 'Institutional1 Admin', 'inst1Admin', '$2a$08$c2GKYEYoUVXH1Yb8GXVXVu66ltPvbZgLMcVSXRH.LgZNF/YeaYB8m', 'admin@nomail.nomail', 'de', 'UTC', 1),
|
||||
(4, 2, 'inst2Admin', 'Institutional2 Admin', 'inst2Admin', '$2a$08$c2GKYEYoUVXH1Yb8GXVXVu66ltPvbZgLMcVSXRH.LgZNF/YeaYB8m', 'admin@nomail.nomail', 'en', 'UTC', 1),
|
||||
(5, 2, 'examAdminInst2', 'Exam Admin 2', 'examAdmin2', '$2a$08$c2GKYEYoUVXH1Yb8GXVXVu66ltPvbZgLMcVSXRH.LgZNF/YeaYB8m', 'admin@nomail.nomail', 'de', 'UTC', 1)
|
||||
;
|
||||
|
||||
INSERT INTO user_role VALUES
|
||||
(1, 1, 'SEB_SERVER_ADMIN')
|
||||
(1, 1, 'SEB_SERVER_ADMIN'),
|
||||
(2, 1, 'INSTITUTIONAL_ADMIN'),
|
||||
(3, 1, 'EXAM_ADMIN'),
|
||||
(4, 1, 'EXAM_SUPPORTER'),
|
||||
(5, 2, 'SEB_SERVER_ADMIN'),
|
||||
(6, 3, 'INSTITUTIONAL_ADMIN'),
|
||||
(7, 4, 'INSTITUTIONAL_ADMIN'),
|
||||
(8, 5, 'EXAM_ADMIN')
|
||||
;
|
||||
|
||||
|
||||
|
|
|
@ -52,12 +52,6 @@ sebserver.mainpage.minimize.tooltip=Minimize
|
|||
sebserver.activitiespane.title=Activities
|
||||
sebserver.actionpane.title=Actions
|
||||
|
||||
# Activities
|
||||
sebserver.activities.institution=Institution
|
||||
sebserver.activities.useraccount=User Account
|
||||
|
||||
|
||||
|
||||
################################
|
||||
# Institution
|
||||
################################
|
||||
|
@ -67,6 +61,7 @@ sebserver.institution.list.column.name=Name
|
|||
sebserver.institution.list.column.urlSuffix=URL Suffix
|
||||
sebserver.institution.list.column.active=Active
|
||||
|
||||
sebserver.institution.action.list=Institution
|
||||
sebserver.institution.action.new=New Institution
|
||||
sebserver.institution.action.list.view=View Selected
|
||||
sebserver.institution.action.modify=Edit Institution
|
||||
|
@ -101,13 +96,16 @@ sebserver.useraccount.list.column.email=Mail
|
|||
sebserver.useraccount.list.column.language=Language
|
||||
sebserver.useraccount.list.column.active=Active
|
||||
|
||||
sebserver.useraccount.action.list=User Account
|
||||
sebserver.useraccount.action.new=New User Account
|
||||
sebserver.useraccount.action.view=View Selected
|
||||
sebserver.useraccount.action.modify=Edit Selected
|
||||
sebserver.useraccount.action.list.modify=Edit Selected
|
||||
sebserver.useraccount.action.modify=Edit
|
||||
sebserver.useraccount.action.save=Save User Account
|
||||
sebserver.useraccount.action.activate=Active
|
||||
sebserver.useraccount.action.deactivate=Active
|
||||
sebserver.useraccount.action.delete=Delete User Account
|
||||
sebserver.useraccount.action.change.password=Change Password
|
||||
|
||||
sebserver.useraccount.info.pleaseSelect=Please Select an User Account first.
|
||||
|
||||
|
@ -123,5 +121,10 @@ sebserver.useraccount.form.roles=User Roles
|
|||
sebserver.useraccount.form.password=Password
|
||||
sebserver.useraccount.form.password.retyped=Retyped Password
|
||||
|
||||
sebserver.useraccount.form.pwchange.title=Change Password : {0}
|
||||
sebserver.useraccount.form.institution.password.old=Old Password
|
||||
sebserver.useraccount.form.institution.password.new=New Password
|
||||
sebserver.useraccount.form.institution.password.retyped=Retyped New Password
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -26,6 +26,10 @@ Label {
|
|||
text-shadow: none;
|
||||
}
|
||||
|
||||
Label.head {
|
||||
font: bold 12px Verdana, "Lucida Sans", Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
Label.action {
|
||||
font: 12px Verdana, "Lucida Sans", Arial, Helvetica, sans-serif;
|
||||
color: #82BE1E;
|
||||
|
@ -71,6 +75,10 @@ Label.selection {
|
|||
padding: 4px 6px 3px 6px;
|
||||
}
|
||||
|
||||
Label.selectionReadonly {
|
||||
padding: 4px 6px 3px 6px;
|
||||
}
|
||||
|
||||
Label:hover.selection {
|
||||
color: #4a4a4a;
|
||||
background-color: #b5b5b5;
|
||||
|
@ -80,8 +88,8 @@ Label:hover.selection {
|
|||
|
||||
Label.selected {
|
||||
color: #4a4a4a;
|
||||
background-color: #b5b5b5;
|
||||
background-image: gradient(linear, left top, left bottom, from(#b5b5b5),to(#b5b5b5));
|
||||
background-color: #c5c5c5;
|
||||
background-image: gradient(linear, left top, left bottom, from(#c5c5c5),to(#c5c5c5));
|
||||
padding: 4px 6px 3px 6px;
|
||||
}
|
||||
|
||||
|
@ -368,7 +376,7 @@ Tree {
|
|||
border: none;
|
||||
color: #1f407a;
|
||||
margin: 0px 0px 0px 0px;
|
||||
padding: 0px 0px 0px 0px;
|
||||
padding: 0px 0px 0px 40px;
|
||||
}
|
||||
|
||||
Tree[BORDER] {
|
||||
|
@ -383,13 +391,14 @@ TreeItem {
|
|||
text-shadow: none;
|
||||
background-image: none;
|
||||
margin: 20px 20px 20px 20px;
|
||||
padding: 20px 20px 20px 20px;
|
||||
padding: 20px 20px 20px 40px;
|
||||
}
|
||||
|
||||
TreeItem:linesvisible:even {
|
||||
background-color: #f3f3f4;
|
||||
}
|
||||
|
||||
|
||||
Tree-RowOverlay {
|
||||
background-color: transparent;
|
||||
color: inherit;
|
||||
|
@ -402,12 +411,12 @@ Tree-RowOverlay:hover {
|
|||
}
|
||||
|
||||
Tree-RowOverlay:selected {
|
||||
background-color: #b5b5b5;
|
||||
background-color: #82be1e;
|
||||
color: #1F407A;
|
||||
}
|
||||
|
||||
Tree-RowOverlay:selected:unfocused {
|
||||
background-color: #b5b5b5;
|
||||
background-color: #82be1e;
|
||||
color: #1f407a;
|
||||
}
|
||||
|
||||
|
@ -438,6 +447,7 @@ TreeItem.actions {
|
|||
margin: 0 0 0 0;
|
||||
}
|
||||
|
||||
|
||||
Tree-RowOverlay:hover.actions {
|
||||
background-color: #82be1e;
|
||||
color: #4a4a4a;
|
||||
|
@ -448,6 +458,31 @@ Tree-RowOverlay:selected.actions {
|
|||
color: #4a4a4a;
|
||||
}
|
||||
|
||||
Tree-Indent {
|
||||
width: 16px;
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
Tree-Indent:collapsed {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
Tree-Indent:collapsed:hover {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
Tree-Indent:expanded {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
Tree-Indent:expanded:hover {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
Tree-Indent:line {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
/* TabFolder default theme */
|
||||
|
||||
TabFolder {
|
||||
|
@ -665,14 +700,14 @@ Table-RowOverlay:hover {
|
|||
|
||||
Table-RowOverlay:selected {
|
||||
color: #4a4a4a;
|
||||
background-color: #b5b5b5;
|
||||
background-image: gradient(linear, left top, left bottom, from(#b5b5b5),to(#b5b5b5));
|
||||
background-color: #c5c5c5;
|
||||
background-image: gradient(linear, left top, left bottom, from(#c5c5c5),to(#c5c5c5));
|
||||
}
|
||||
|
||||
Table-RowOverlay:selected:unfocused {
|
||||
color: #4a4a4a;
|
||||
background-color: #b5b5b5;
|
||||
background-image: gradient(linear, left top, left bottom, from(#b5b5b5),to(#b5b5b5));
|
||||
background-color: #c5c5c5;
|
||||
background-image: gradient(linear, left top, left bottom, from(#c5c5c5),to(#c5c5c5));
|
||||
}
|
||||
|
||||
Table-RowOverlay:linesvisible:even:hover {
|
||||
|
@ -683,13 +718,13 @@ Table-RowOverlay:linesvisible:even:hover {
|
|||
|
||||
Table-RowOverlay:linesvisible:even:selected {
|
||||
color: #4a4a4a;
|
||||
background-color: #b5b5b5;
|
||||
background-image: gradient(linear, left top, left bottom, from(#b5b5b5),to(#b5b5b5));
|
||||
background-color: #c5c5c5;
|
||||
background-image: gradient(linear, left top, left bottom, from(#c5c5c5),to(#c5c5c5));
|
||||
}
|
||||
|
||||
Table-RowOverlay:linesvisible:even:selected:unfocused {
|
||||
background-color: #b5b5b5;
|
||||
background-image: gradient(linear, left top, left bottom, from(#b5b5b5),to(#b5b5b5));
|
||||
background-color: #c5c5c5;
|
||||
background-image: gradient(linear, left top, left bottom, from(#c5c5c5),to(#c5c5c5));
|
||||
color: #4a4a4a;
|
||||
}
|
||||
|
||||
|
|
|
@ -417,9 +417,9 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester {
|
|||
|
||||
assertNotNull(dependencies);
|
||||
assertTrue(dependencies.size() == 3);
|
||||
assertTrue(dependencies.contains(new EntityKey("1", EntityType.USER)));
|
||||
assertTrue(dependencies.contains(new EntityKey("2", EntityType.USER)));
|
||||
assertTrue(dependencies.contains(new EntityKey("5", EntityType.USER)));
|
||||
assertTrue(dependencies.contains(new EntityKey("user1", EntityType.USER)));
|
||||
assertTrue(dependencies.contains(new EntityKey("user2", EntityType.USER)));
|
||||
assertTrue(dependencies.contains(new EntityKey("user5", EntityType.USER)));
|
||||
}
|
||||
|
||||
static void assertContainsInstitution(final String name, final Collection<Institution> institutions) {
|
||||
|
|
|
@ -24,6 +24,7 @@ import java.util.stream.Stream;
|
|||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.junit.Test;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.jdbc.Sql;
|
||||
|
@ -39,10 +40,10 @@ import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
|||
import ch.ethz.seb.sebserver.gbl.model.EntityName;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Page;
|
||||
import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.PasswordChange;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserActivityLog;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserMod;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO.ActivityType;
|
||||
|
||||
|
@ -449,8 +450,8 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
.param(Domain.USER.ATTR_USERNAME, "NewTestUser")
|
||||
.param(Domain.USER.ATTR_LOCALE, Locale.ENGLISH.toLanguageTag())
|
||||
.param(Domain.USER.ATTR_TIMEZONE, DateTimeZone.UTC.getID())
|
||||
.param(UserMod.ATTR_NAME_NEW_PASSWORD, "12345678")
|
||||
.param(UserMod.ATTR_NAME_RETYPED_NEW_PASSWORD, "12345678"))
|
||||
.param(PasswordChange.ATTR_NAME_NEW_PASSWORD, "12345678")
|
||||
.param(PasswordChange.ATTR_NAME_RETYPED_NEW_PASSWORD, "12345678"))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn().getResponse().getContentAsString(),
|
||||
new TypeReference<UserInfo>() {
|
||||
|
@ -621,6 +622,51 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
assertEquals("[EXAM_ADMIN, EXAM_SUPPORTER]", String.valueOf(modifiedUserResult.roles));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testModifyUserOnInactiveInstitutionNotAllowed() throws Exception {
|
||||
// create new institution with seb-admin that is not active
|
||||
final Institution institution = new RestAPITestHelper()
|
||||
.withAccessToken(getSebAdminAccess())
|
||||
.withPath(API.INSTITUTION_ENDPOINT)
|
||||
.withMethod(HttpMethod.POST)
|
||||
.withAttribute("name", "new institution")
|
||||
.withAttribute("urlSuffix", "new_inst")
|
||||
.withAttribute("active", "false")
|
||||
.withExpectedStatus(HttpStatus.OK)
|
||||
.getAsObject(new TypeReference<Institution>() {
|
||||
});
|
||||
|
||||
assertNotNull(institution);
|
||||
assertNotNull(institution.id);
|
||||
assertEquals("new institution", institution.name);
|
||||
|
||||
// try to create a user for this institution should not be possible
|
||||
final Collection<APIMessage> errors = this.jsonMapper.readValue(
|
||||
this.mockMvc.perform(post(this.endpoint + API.USER_ACCOUNT_ENDPOINT)
|
||||
.header("Authorization", "Bearer " + getSebAdminAccess())
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
.param(Domain.USER.ATTR_INSTITUTION_ID, String.valueOf(institution.id))
|
||||
.param(Domain.USER.ATTR_NAME, "NewTestUser")
|
||||
.param(Domain.USER.ATTR_USERNAME, "NewTestUser")
|
||||
.param(Domain.USER.ATTR_LOCALE, Locale.ENGLISH.toLanguageTag())
|
||||
.param(Domain.USER.ATTR_TIMEZONE, DateTimeZone.UTC.getID())
|
||||
.param(PasswordChange.ATTR_NAME_NEW_PASSWORD, "12345678")
|
||||
.param(PasswordChange.ATTR_NAME_RETYPED_NEW_PASSWORD, "12345678"))
|
||||
.andExpect(status().isBadRequest())
|
||||
.andReturn().getResponse().getContentAsString(),
|
||||
new TypeReference<Collection<APIMessage>>() {
|
||||
});
|
||||
|
||||
assertNotNull(errors);
|
||||
assertTrue(errors.size() == 1);
|
||||
assertEquals(
|
||||
"Illegal API request argument",
|
||||
errors.iterator().next().systemMessage);
|
||||
assertEquals(
|
||||
"User within an inactive institution cannot be created nor modified",
|
||||
errors.iterator().next().details);
|
||||
}
|
||||
|
||||
// @Test
|
||||
// public void modifyUserWithPOSTMethod() throws Exception {
|
||||
// final String token = getSebAdminAccess();
|
||||
|
@ -685,8 +731,8 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
.param(Domain.USER.ATTR_INSTITUTION_ID, "2")
|
||||
.param(Domain.USER.ATTR_NAME, "NewTestUser")
|
||||
.param(UserMod.ATTR_NAME_NEW_PASSWORD, "12345678")
|
||||
.param(UserMod.ATTR_NAME_RETYPED_NEW_PASSWORD, "12345678"))
|
||||
.param(PasswordChange.ATTR_NAME_NEW_PASSWORD, "12345678")
|
||||
.param(PasswordChange.ATTR_NAME_RETYPED_NEW_PASSWORD, "12345678"))
|
||||
.andExpect(status().isForbidden())
|
||||
.andReturn().getResponse().getContentAsString();
|
||||
|
||||
|
@ -712,8 +758,8 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
.param(Domain.USER.ATTR_INSTITUTION_ID, "2")
|
||||
.param(Domain.USER.ATTR_NAME, "NewTestUser")
|
||||
.param(UserMod.ATTR_NAME_NEW_PASSWORD, "12345678")
|
||||
.param(UserMod.ATTR_NAME_RETYPED_NEW_PASSWORD, "12345678"))
|
||||
.param(PasswordChange.ATTR_NAME_NEW_PASSWORD, "12345678")
|
||||
.param(PasswordChange.ATTR_NAME_RETYPED_NEW_PASSWORD, "12345678"))
|
||||
.andExpect(status().isForbidden())
|
||||
.andReturn().getResponse().getContentAsString();
|
||||
|
||||
|
@ -748,12 +794,14 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
});
|
||||
|
||||
final PasswordChange passwordChange = new PasswordChange(
|
||||
examAdmin1.uuid,
|
||||
"admin",
|
||||
"newPassword",
|
||||
"newPassword");
|
||||
final String modifiedUserJson = this.jsonMapper.writeValueAsString(passwordChange);
|
||||
|
||||
this.mockMvc.perform(
|
||||
put(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/" + examAdmin1.uuid + API.PASSWORD_PATH_SEGMENT)
|
||||
put(this.endpoint + API.USER_ACCOUNT_ENDPOINT + API.PASSWORD_PATH_SEGMENT)
|
||||
.header("Authorization", "Bearer " + sebAdminToken)
|
||||
.contentType(MediaType.APPLICATION_JSON_UTF8)
|
||||
.content(modifiedUserJson))
|
||||
|
@ -796,17 +844,18 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
|
||||
// must be longer then 8 chars
|
||||
PasswordChange passwordChange = new PasswordChange(
|
||||
examAdmin1.uuid,
|
||||
"admin",
|
||||
"new",
|
||||
"new");
|
||||
String modifiedUserJson = this.jsonMapper.writeValueAsString(passwordChange);
|
||||
|
||||
List<APIMessage> messages = this.jsonMapper.readValue(
|
||||
this.mockMvc.perform(
|
||||
put(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/" + examAdmin1.uuid
|
||||
+ API.PASSWORD_PATH_SEGMENT)
|
||||
.header("Authorization", "Bearer " + sebAdminToken)
|
||||
.contentType(MediaType.APPLICATION_JSON_UTF8)
|
||||
.content(modifiedUserJson))
|
||||
put(this.endpoint + API.USER_ACCOUNT_ENDPOINT + API.PASSWORD_PATH_SEGMENT)
|
||||
.header("Authorization", "Bearer " + sebAdminToken)
|
||||
.contentType(MediaType.APPLICATION_JSON_UTF8)
|
||||
.content(modifiedUserJson))
|
||||
.andExpect(status().isBadRequest())
|
||||
.andReturn().getResponse().getContentAsString(),
|
||||
new TypeReference<List<APIMessage>>() {
|
||||
|
@ -815,21 +864,22 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
assertNotNull(messages);
|
||||
assertTrue(1 == messages.size());
|
||||
assertEquals("1200", messages.get(0).messageCode);
|
||||
assertEquals("[user, password, size, 8, 255, new]", String.valueOf(messages.get(0).getAttributes()));
|
||||
assertEquals("[user, newPassword, size, 8, 255, new]", String.valueOf(messages.get(0).getAttributes()));
|
||||
|
||||
// wrong password retype
|
||||
passwordChange = new PasswordChange(
|
||||
examAdmin1.uuid,
|
||||
"admin",
|
||||
"12345678",
|
||||
"87654321");
|
||||
modifiedUserJson = this.jsonMapper.writeValueAsString(passwordChange);
|
||||
|
||||
messages = this.jsonMapper.readValue(
|
||||
this.mockMvc.perform(
|
||||
put(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/" + examAdmin1.uuid
|
||||
+ API.PASSWORD_PATH_SEGMENT)
|
||||
.header("Authorization", "Bearer " + sebAdminToken)
|
||||
.contentType(MediaType.APPLICATION_JSON_UTF8)
|
||||
.content(modifiedUserJson))
|
||||
put(this.endpoint + API.USER_ACCOUNT_ENDPOINT + API.PASSWORD_PATH_SEGMENT)
|
||||
.header("Authorization", "Bearer " + sebAdminToken)
|
||||
.contentType(MediaType.APPLICATION_JSON_UTF8)
|
||||
.content(modifiedUserJson))
|
||||
.andExpect(status().isBadRequest())
|
||||
.andReturn().getResponse().getContentAsString(),
|
||||
new TypeReference<List<APIMessage>>() {
|
||||
|
@ -837,7 +887,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
|
||||
assertNotNull(messages);
|
||||
assertTrue(1 == messages.size());
|
||||
assertEquals("1300", messages.get(0).messageCode);
|
||||
assertEquals("1200", messages.get(0).messageCode);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in a new issue