From 0bd7271ef3763ae1e8de60ebad3f006fb672056b Mon Sep 17 00:00:00 2001 From: ScarletRedMan Date: Thu, 2 May 2024 17:16:14 +0700 Subject: [PATCH] implemented account details page --- .../picker/cp/component/AccountList.java | 8 +- .../picker/cp/page/AccountDetailsPage.java | 138 ++++++++++++++++++ .../picker/cp/util/RouteParamsExtractor.java | 6 + .../picker/controller/AccountsController.java | 6 +- 4 files changed, 153 insertions(+), 5 deletions(-) create mode 100644 control-panel/src/main/java/ru/dragonestia/picker/cp/page/AccountDetailsPage.java diff --git a/control-panel/src/main/java/ru/dragonestia/picker/cp/component/AccountList.java b/control-panel/src/main/java/ru/dragonestia/picker/cp/component/AccountList.java index c3a2533..8f1c0b1 100644 --- a/control-panel/src/main/java/ru/dragonestia/picker/cp/component/AccountList.java +++ b/control-panel/src/main/java/ru/dragonestia/picker/cp/component/AccountList.java @@ -73,7 +73,9 @@ public class AccountList extends VerticalLayout implements RefreshableTable { var button = new Button("Manage", VaadinIcon.COG_O.create()); button.addThemeVariants(ButtonVariant.LUMO_PRIMARY); button.addClickListener(event -> { - + getUI().ifPresent(ui -> { + ui.navigate("/admin/accounts/" + account.getUsername()); + }); }); layout.add(button); } @@ -171,7 +173,7 @@ public class AccountList extends VerticalLayout implements RefreshableTable { } if (password.length() < 5 || password.length() > 32) { - Notifications.error("Invalid username length. Valid is 5-32"); + Notifications.error("Invalid password length. Valid is 5-32"); return; } @@ -192,7 +194,7 @@ public class AccountList extends VerticalLayout implements RefreshableTable { refresh(); } - private static class PermissionCheckBox extends Checkbox { + public static class PermissionCheckBox extends Checkbox { private final Permission.Enum option; diff --git a/control-panel/src/main/java/ru/dragonestia/picker/cp/page/AccountDetailsPage.java b/control-panel/src/main/java/ru/dragonestia/picker/cp/page/AccountDetailsPage.java new file mode 100644 index 0000000..6da64c8 --- /dev/null +++ b/control-panel/src/main/java/ru/dragonestia/picker/cp/page/AccountDetailsPage.java @@ -0,0 +1,138 @@ +package ru.dragonestia.picker.cp.page; + +import com.vaadin.flow.component.AbstractField; +import com.vaadin.flow.component.Html; +import com.vaadin.flow.component.Unit; +import com.vaadin.flow.component.button.Button; +import com.vaadin.flow.component.button.ButtonVariant; +import com.vaadin.flow.component.html.H2; +import com.vaadin.flow.component.html.H3; +import com.vaadin.flow.component.html.Hr; +import com.vaadin.flow.component.orderedlayout.VerticalLayout; +import com.vaadin.flow.component.textfield.PasswordField; +import com.vaadin.flow.router.BeforeEnterEvent; +import com.vaadin.flow.router.BeforeEnterObserver; +import com.vaadin.flow.router.PageTitle; +import com.vaadin.flow.router.Route; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.security.RolesAllowed; +import lombok.RequiredArgsConstructor; +import ru.dragonestia.picker.api.impl.RoomPickerClient; +import ru.dragonestia.picker.api.model.account.IAccount; +import ru.dragonestia.picker.cp.component.AccountList; +import ru.dragonestia.picker.cp.component.Notifications; +import ru.dragonestia.picker.cp.model.Permission; +import ru.dragonestia.picker.cp.service.SecurityService; +import ru.dragonestia.picker.cp.util.RouteParamsExtractor; + +import java.util.ArrayList; + +@RequiredArgsConstructor +@RolesAllowed("ADMIN") +@PageTitle("Account details") +@Route(value = "/admin/accounts/:accountId", layout = MainLayout.class) +public class AccountDetailsPage extends VerticalLayout implements BeforeEnterObserver { + + private final SecurityService securityService; + private final RouteParamsExtractor paramsExtractor; + + private RoomPickerClient client; + private IAccount account; + + @PostConstruct + void postConstruct() { + client = securityService.getAuthenticatedAccount().getClient(); + } + + @Override + public void beforeEnter(BeforeEnterEvent event) { + account = paramsExtractor.extractAccount(event); + + init(); + } + + private void init() { + add(new H2("Account management")); + add(new Html("Username: %s".formatted(account.getUsername()))); + + add(new Hr()); + add(new H3("Change password")); + createChangePassword(); + + add(new Hr()); + add(new H3("Update permissions")); + createEditPermissions(); + + add(new Hr()); + add(new H3("Delete account")); + add(createDeleteAccountButton()); + } + + private void createChangePassword() { + var newPassword = new PasswordField("New password"); + newPassword.setMinWidth(25, Unit.PERCENTAGE); + add(newPassword); + + var confirmPassword = new PasswordField("Confirm new password"); + confirmPassword.setMinWidth(25, Unit.PERCENTAGE); + add(confirmPassword); + + var submit = new Button("Submit", event -> { + var pass = newPassword.getValue(); + var confirm = confirmPassword.getValue(); + + if (pass.length() < 5 || pass.length() > 32) { + Notifications.error("Invalid password length. Valid is 5-32"); + return; + } + + if (!pass.equals(confirm)) { + Notifications.error("Passwords are not equals"); + return; + } + + //TODO: change password + Notifications.success("Password successfully changed!"); + newPassword.setValue(""); + confirmPassword.setValue(""); + }); + submit.addThemeVariants(ButtonVariant.LUMO_PRIMARY); + add(submit); + } + + private void createEditPermissions() { + var permissionsList = new ArrayList(); + for (var permission: Permission.Enum.values()) { + var comp = new AccountList.PermissionCheckBox(permission); + comp.setValue(account.getPermissions().contains(permission.name())); + permissionsList.add(comp); + add(comp); + } + + var button = new Button("Update permissions", event -> { + var permissions = permissionsList.stream() + .filter(AbstractField::getValue) + .map(AccountList.PermissionCheckBox::getOption) + .map(Enum::name) + .toList(); + + client.getAccountRepository().setPermissions(account, permissions); + Notifications.success("Permissions successfully changed!"); + }); + button.addThemeVariants(ButtonVariant.LUMO_PRIMARY); + add(button); + } + + private Button createDeleteAccountButton() { + var button = new Button("Delete this account", event -> { + client.getAccountRepository().removeAccount(account); + Notifications.warn("Account '%s' was deleted.".formatted(account.getUsername())); + + getUI().ifPresent(ui -> { + ui.navigate("/admin/accounts"); + }); + }); + button.addThemeVariants(ButtonVariant.LUMO_PRIMARY, ButtonVariant.LUMO_ERROR); + return button; + } +} diff --git a/control-panel/src/main/java/ru/dragonestia/picker/cp/util/RouteParamsExtractor.java b/control-panel/src/main/java/ru/dragonestia/picker/cp/util/RouteParamsExtractor.java index e0205a8..ff9e758 100644 --- a/control-panel/src/main/java/ru/dragonestia/picker/cp/util/RouteParamsExtractor.java +++ b/control-panel/src/main/java/ru/dragonestia/picker/cp/util/RouteParamsExtractor.java @@ -6,6 +6,7 @@ import org.springframework.stereotype.Component; import ru.dragonestia.picker.api.exception.NodeNotFoundException; import ru.dragonestia.picker.api.exception.RoomNotFoundException; import ru.dragonestia.picker.api.impl.RoomPickerClient; +import ru.dragonestia.picker.api.model.account.IAccount; import ru.dragonestia.picker.api.model.node.INode; import ru.dragonestia.picker.api.model.room.IRoom; import ru.dragonestia.picker.api.model.user.IUser; @@ -37,4 +38,9 @@ public class RouteParamsExtractor { var userId = UserIdentifier.of(e.getRouteParameters().get("userId").orElseThrow(RuntimeException::new)); return client.getUserRepository().findUserById(FindUserById.withAllDetails(userId)); } + + public IAccount extractAccount(BeforeEnterEvent e) { + var accountId = e.getRouteParameters().get("accountId").orElseThrow(RuntimeException::new); + return client.getAccountRepository().findAccountByUsername(accountId).orElseThrow(RuntimeException::new); + } } diff --git a/server/src/main/java/ru/dragonestia/picker/controller/AccountsController.java b/server/src/main/java/ru/dragonestia/picker/controller/AccountsController.java index c4da1a9..62d0a39 100644 --- a/server/src/main/java/ru/dragonestia/picker/controller/AccountsController.java +++ b/server/src/main/java/ru/dragonestia/picker/controller/AccountsController.java @@ -49,11 +49,12 @@ public class AccountsController { } @PostMapping - ResponseAccount registerAccount(@RequestParam String username, @RequestParam String password, @RequestParam String permissions) { + ResponseAccount registerAccount(@RequestParam String username, @RequestParam String password, @RequestParam(defaultValue = "") String permissions) { var account = accountService.createNewAccount(username, password); var authorities = new HashSet(); for (var permStr : permissions.split(",")) { + if (permStr.isBlank()) continue; try { var perm = Permission.valueOf(permStr); authorities.add(perm); @@ -69,11 +70,12 @@ public class AccountsController { } @PutMapping("/{accountId}") - ResponseEntity updatePermissions(@PathVariable String accountId, @RequestParam String permissions) { + ResponseEntity updatePermissions(@PathVariable String accountId, @RequestParam(defaultValue = "") String permissions) { var account = accountService.findAccount(accountId).orElseThrow(() -> new AccountDoesNotExistsException(accountId)); var authorities = new HashSet(); for (var permStr : permissions.split(",")) { + if (permStr.isBlank()) continue; try { var perm = Permission.valueOf(permStr); authorities.add(perm);