usermanager

This commit is contained in:
f43nd1r 2018-11-22 03:07:23 +01:00
parent 4f050f6034
commit 04a118528a
7 changed files with 120 additions and 27 deletions

View file

@ -1,6 +1,7 @@
package com.faendir.acra.ui.base; package com.faendir.acra.ui.base;
import com.faendir.acra.dataprovider.QueryDslDataProvider; import com.faendir.acra.dataprovider.QueryDslDataProvider;
import com.faendir.acra.ui.component.HasSize;
import com.querydsl.core.types.Expression; import com.querydsl.core.types.Expression;
import com.vaadin.flow.component.Component; import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.ComponentEventListener; import com.vaadin.flow.component.ComponentEventListener;
@ -26,7 +27,7 @@ import java.util.function.Function;
* @author lukas * @author lukas
* @since 13.07.18 * @since 13.07.18
*/ */
public class MyGrid<T> extends Composite<Grid<T>> implements LocaleChangeObserver { public class MyGrid<T> extends Composite<Grid<T>> implements LocaleChangeObserver, HasSize {
private final QueryDslDataProvider<T> dataProvider; private final QueryDslDataProvider<T> dataProvider;
private final Map<Grid.Column<T>, Pair<String, Object[]>> columnCaptions; private final Map<Grid.Column<T>, Pair<String, Object[]>> columnCaptions;

View file

@ -17,6 +17,7 @@
package com.faendir.acra.ui.base.popup; package com.faendir.acra.ui.base.popup;
import com.vaadin.flow.component.Component; import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.Composite;
import com.vaadin.flow.component.HasValidation; import com.vaadin.flow.component.HasValidation;
import com.vaadin.flow.component.HasValue; import com.vaadin.flow.component.HasValue;
import org.springframework.lang.NonNull; import org.springframework.lang.NonNull;
@ -33,16 +34,18 @@ import java.util.function.Supplier;
* @author Lukas * @author Lukas
* @since 22.06.2017 * @since 22.06.2017
*/ */
public class ValidatedField<V, T extends Component & HasValue<?,V> & HasValidation> { public class ValidatedField<V, T extends Component> {
private final T field; private final T field;
private final Supplier<V> valueSupplier; private final Supplier<V> valueSupplier;
private final Consumer<String> messageSetter;
private final Map<Function<V, Boolean>, String> validators; private final Map<Function<V, Boolean>, String> validators;
private final List<Listener> listeners; private final List<Listener> listeners;
private boolean valid; private boolean valid;
private ValidatedField(T field, Supplier<V> valueSupplier, Consumer<Consumer<V>> listenerRegistration) { private ValidatedField(T field, Supplier<V> valueSupplier, Consumer<Consumer<V>> listenerRegistration, Consumer<String> messageSetter) {
this.field = field; this.field = field;
this.valueSupplier = valueSupplier; this.valueSupplier = valueSupplier;
this.messageSetter = messageSetter;
this.validators = new HashMap<>(); this.validators = new HashMap<>();
this.listeners = new ArrayList<>(); this.listeners = new ArrayList<>();
this.valid = false; this.valid = false;
@ -50,11 +53,15 @@ public class ValidatedField<V, T extends Component & HasValue<?,V> & HasValidati
} }
public static <V, T extends Component & HasValue<?, V> & HasValidation> ValidatedField<V, T> of(T field) { public static <V, T extends Component & HasValue<?, V> & HasValidation> ValidatedField<V, T> of(T field) {
return new ValidatedField<>(field, field::getValue, vConsumer -> field.addValueChangeListener(event -> vConsumer.accept(event.getValue()))); return new ValidatedField<>(field, field::getValue, vConsumer -> field.addValueChangeListener(event -> vConsumer.accept(event.getValue())), field::setErrorMessage);
}
public static <V, C extends Composite<T>, T extends Component & HasValue<?, V> & HasValidation> ValidatedField<V, C> of(C field) {
return new ValidatedField<>(field, () -> field.getContent().getValue(), vConsumer -> field.getContent().addValueChangeListener(event -> vConsumer.accept(event.getValue())), m -> field.getContent().setErrorMessage(m));
} }
public static <V, T extends Component & HasValue<?, V> & HasValidation> ValidatedField<V, T> of(T field, Supplier<V> valueSupplier, Consumer<Consumer<V>> listenerRegistration) { public static <V, T extends Component & HasValue<?, V> & HasValidation> ValidatedField<V, T> of(T field, Supplier<V> valueSupplier, Consumer<Consumer<V>> listenerRegistration) {
return new ValidatedField<>(field, valueSupplier, listenerRegistration); return new ValidatedField<>(field, valueSupplier, listenerRegistration, field::setErrorMessage);
} }
public ValidatedField<V, T> addValidator(Function<V, Boolean> validator, String errorMessage) { public ValidatedField<V, T> addValidator(Function<V, Boolean> validator, String errorMessage) {
@ -73,10 +80,10 @@ public class ValidatedField<V, T extends Component & HasValue<?,V> & HasValidati
private boolean validate(V value) { private boolean validate(V value) {
boolean valid = validators.entrySet().stream().allMatch(entry -> { boolean valid = validators.entrySet().stream().allMatch(entry -> {
if (entry.getKey().apply(value)) { if (entry.getKey().apply(value)) {
field.setErrorMessage(null); messageSetter.accept(null);
return true; return true;
} else { } else {
field.setErrorMessage(entry.getValue()); messageSetter.accept(entry.getValue());
return false; return false;
} }
}); });

View file

@ -33,7 +33,8 @@ public class FlexLayout extends com.vaadin.flow.component.orderedlayout.FlexLayo
} }
public enum FlexDirection { public enum FlexDirection {
COLUMN("column"); COLUMN("column"),
ROW("row");
private final String value; private final String value;
FlexDirection(@NonNull String value) { FlexDirection(@NonNull String value) {

View file

@ -10,7 +10,6 @@ import com.faendir.acra.ui.component.FlexLayout;
import com.faendir.acra.ui.component.Translatable; import com.faendir.acra.ui.component.Translatable;
import com.faendir.acra.ui.view.MainView; import com.faendir.acra.ui.view.MainView;
import com.faendir.acra.ui.view.Overview; import com.faendir.acra.ui.view.Overview;
import com.vaadin.flow.component.AttachEvent;
import com.vaadin.flow.component.Composite; import com.vaadin.flow.component.Composite;
import com.vaadin.flow.component.UI; import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.notification.Notification; import com.vaadin.flow.component.notification.Notification;
@ -69,11 +68,6 @@ public class ChangePasswordView extends Composite<FlexLayout> implements HasRout
getContent().setAlignItems(FlexComponent.Alignment.CENTER); getContent().setAlignItems(FlexComponent.Alignment.CENTER);
} }
@Override
protected void onAttach(AttachEvent attachEvent) {
super.onAttach(attachEvent);
}
@NonNull @NonNull
@Override @Override
public Path.Element<?> getPathElement() { public Path.Element<?> getPathElement() {

View file

@ -1,14 +1,104 @@
package com.faendir.acra.ui.view.user; package com.faendir.acra.ui.view.user;
import com.faendir.acra.i18n.Messages;
import com.faendir.acra.model.App;
import com.faendir.acra.model.Permission;
import com.faendir.acra.model.QUser;
import com.faendir.acra.model.User;
import com.faendir.acra.security.SecurityUtils;
import com.faendir.acra.service.DataService;
import com.faendir.acra.service.UserService;
import com.faendir.acra.ui.base.MyGrid;
import com.faendir.acra.ui.base.popup.Popup;
import com.faendir.acra.ui.base.popup.ValidatedField;
import com.faendir.acra.ui.component.FlexLayout; import com.faendir.acra.ui.component.FlexLayout;
import com.faendir.acra.ui.component.Translatable;
import com.faendir.acra.ui.view.MainView; import com.faendir.acra.ui.view.MainView;
import com.vaadin.flow.component.AttachEvent;
import com.vaadin.flow.component.Composite; import com.vaadin.flow.component.Composite;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.checkbox.Checkbox;
import com.vaadin.flow.component.combobox.ComboBox;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.textfield.PasswordField;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.data.renderer.ComponentRenderer;
import com.vaadin.flow.router.Route; import com.vaadin.flow.router.Route;
import com.vaadin.flow.spring.annotation.SpringComponent;
import com.vaadin.flow.spring.annotation.UIScope;
import org.springframework.lang.NonNull;
import java.util.Arrays;
/** /**
* @author lukas * @author lukas
* @since 15.11.18 * @since 15.11.18
*/ */
@UIScope
@SpringComponent
@Route(value = "user-manager", layout = MainView.class) @Route(value = "user-manager", layout = MainView.class)
public class UserManager extends Composite<FlexLayout> { public class UserManager extends Composite<FlexLayout> {
private final UserService userService;
private final DataService dataService;
public UserManager(@NonNull UserService userService, @NonNull DataService dataService) {
this.userService = userService;
this.dataService = dataService;
getContent().setFlexDirection(FlexLayout.FlexDirection.COLUMN);
getContent().setWidthFull();
}
@Override
protected void onAttach(AttachEvent attachEvent) {
super.onAttach(attachEvent);
getContent().removeAll();
getContent().add(Translatable.createLabel(Messages.USERS));
MyGrid<User> userGrid = new MyGrid<>(userService.getUserProvider());
userGrid.setWidthFull();
userGrid.setSelectionMode(Grid.SelectionMode.NONE);
userGrid.addColumn(User::getUsername, QUser.user.username, Messages.USERNAME);
userGrid.addColumn(new ComponentRenderer<>(user -> {
Checkbox checkbox = new Checkbox(user.getRoles().contains(User.Role.ADMIN));
checkbox.addValueChangeListener(e -> {
userService.setAdmin(user, e.getValue());
userGrid.getDataProvider().refreshAll();
});
checkbox.setEnabled(!user.getUsername().equals(SecurityUtils.getUsername()));
return checkbox;
}), Messages.ADMIN);
userGrid.addColumn(new ComponentRenderer<>(user -> {
Checkbox checkbox = new Checkbox(user.getRoles().contains(User.Role.API));
checkbox.addValueChangeListener(e -> {
userService.setApiAccess(user, e.getValue());
userGrid.getDataProvider().refreshAll();
});
return checkbox;
}), Messages.API);
for (App app : dataService.findAllApps()) {
userGrid.addColumn(new ComponentRenderer<>(user -> {
Permission.Level permission = SecurityUtils.getPermission(app, user);
ComboBox<Permission.Level> levelComboBox = new ComboBox<>(null, Arrays.asList(Permission.Level.values()));
levelComboBox.setValue(permission);
levelComboBox.addValueChangeListener(e -> {
userService.setPermission(user, app, e.getValue());
userGrid.getDataProvider().refreshAll();
});
return levelComboBox;
}), Messages.ACCESS_PERMISSION, app.getName());
}
Translatable<Button> newUser = Translatable.createButton(e -> {
Translatable<TextField> name = Translatable.createTextField("", Messages.USERNAME);
Translatable<PasswordField> password = Translatable.createPasswordField(Messages.PASSWORD);
new Popup().setTitle(Messages.NEW_USER)
.addValidatedField(ValidatedField.of(name).addValidator(s -> !s.isEmpty(), Messages.USERNAME_EMPTY))
.addValidatedField(ValidatedField.of(password).addValidator(s -> !s.isEmpty(), Messages.PASSWORD_EMPTY))
.addValidatedField(ValidatedField.of(Translatable.createPasswordField(Messages.REPEAT_PASSWORD)).addValidator(s -> s.equals(password.getContent().getValue()), Messages.PASSWORDS_NOT_MATCHING))
.addCreateButton(popup -> {
userService.createUser(name.getContent().getValue().toLowerCase(), password.getContent().getValue());
userGrid.getDataProvider().refreshAll();
}, true)
.show();
}, Messages.NEW_USER);
getContent().add(userGrid, newUser);
}
} }

View file

@ -24,13 +24,13 @@ host=Host
port=Port port=Port
ssl=Nutze SSL ssl=Nutze SSL
databaseName=Datenbankname databaseName=Datenbankname
importSuccess=Import erfolgreich für {0} von {1} Berichten. importSuccess=Import erfolgreich für %s von %s Berichten.
acrarium=Acrarium acrarium=Acrarium
configurationLabel=Notiere die folgende ACRA Konfiguration. Sie kann später nicht mehr angezeigt werden:<br><code>\ configurationLabel=Notiere die folgende ACRA Konfiguration. Sie kann später nicht mehr angezeigt werden:<br><code>\
@AcraCore(reportFormat = StringFormat.JSON)<br>\ @AcraCore(reportFormat = StringFormat.JSON)<br>\
@AcraHttpSender(uri = "{0}{1}",<br>\ @AcraHttpSender(uri = "%s%s",<br>\
basicAuthLogin = "{2}",<br>\ basicAuthLogin = "%s",<br>\
basicAuthPassword = "{3}",<br>\ basicAuthPassword = "%s",<br>\
httpMethod = HttpSender.Method.POST)<br></code> httpMethod = HttpSender.Method.POST)<br></code>
create=Erzeugen create=Erzeugen
close=Schließen close=Schließen
@ -115,7 +115,7 @@ changePassword=Passwort ändern
success=Erfolgreich! success=Erfolgreich!
users=Nutzer users=Nutzer
username=Nutzername username=Nutzername
accessPermission=Zugriffsrechte für {0} accessPermission=Zugriffsrechte für %s
newUser=Neuer Benutzer newUser=Neuer Benutzer
password=Passwort password=Passwort
usernameEmpty=Nutzername darf nicht leer sein usernameEmpty=Nutzername darf nicht leer sein

View file

@ -24,13 +24,13 @@ host=Host
port=Port port=Port
ssl=Use SSL ssl=Use SSL
databaseName=Database Name databaseName=Database Name
importSuccess=Import successful for {0} of {1} reports. importSuccess=Import successful for %s of %s reports.
acrarium=Acrarium acrarium=Acrarium
configurationLabel=Take note of the following ACRA configuration. It cannot be viewed later:<br><code>\ configurationLabel=Take note of the following ACRA configuration. It cannot be viewed later:<br><code>\
@AcraCore(reportFormat = StringFormat.JSON)<br>\ @AcraCore(reportFormat = StringFormat.JSON)<br>\
@AcraHttpSender(uri = "{0}{1}",<br>\ @AcraHttpSender(uri = "%s%s",<br>\
basicAuthLogin = "{2}",<br>\ basicAuthLogin = "%s",<br>\
basicAuthPassword = "{3}",<br>\ basicAuthPassword = "%s",<br>\
httpMethod = HttpSender.Method.POST)<br></code> httpMethod = HttpSender.Method.POST)<br></code>
create=Create create=Create
close=Close close=Close
@ -67,7 +67,7 @@ download=Download
nothingSelected=Nothing selected nothingSelected=Nothing selected
export=Export export=Export
version=Version version=Version
deleteMappingConfirm=Are you sure you want to delete the mapping for version {0}? deleteMappingConfirm=Are you sure you want to delete the mapping for version %s?
newFile=Add File newFile=Add File
versionCode=Version code versionCode=Version code
mappingFile=Mapping file mappingFile=Mapping file
@ -115,7 +115,7 @@ changePassword=Change Password
success=Successful! success=Successful!
users=Users users=Users
username=Username username=Username
accessPermission=Access Permission for {0} accessPermission=Access Permission for %s
newUser=New User newUser=New User
password=Password password=Password
usernameEmpty=Username cannot be empty usernameEmpty=Username cannot be empty