usermanager
This commit is contained in:
parent
4f050f6034
commit
04a118528a
7 changed files with 120 additions and 27 deletions
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue