use PostgreSQL for kontor-spring and kontor-api
This commit is contained in:
@@ -13,7 +13,7 @@ from sqlalchemy.orm import sessionmaker
|
||||
from src.db.models.tysc import Card, CardSet, Rooster, Team, FieldPosition, Player, Vendor, Sport
|
||||
from src.db.models.comic import Issue, TradePaperback, StoryArc, Volume, ComicWork, Artist, Comic, Publisher, WorkType
|
||||
from src.db.models.bookshelf import ArticleAuthor, BookAuthor, BookshelfPublisher, Article, Book, Author
|
||||
from src.db.models.admin import Mail, MailAccount, ModuleData, Role, User, Token, AuthorizationMatrix
|
||||
from src.db.models.admin import Mail, MailAccount, ModuleData, Token, Assignment, Permission, Profile
|
||||
from src.db.models.metadata import MetaDataTable, MetaDataColumn
|
||||
from src.db.models.media import MediaVideo, MediaArticle, MediaFile, MediaActor, MediaActorFile
|
||||
|
||||
@@ -79,10 +79,10 @@ class KontorDB:
|
||||
self.registry[MediaVideo.__tablename__] = MediaVideo
|
||||
self.registry[MetaDataColumn.__tablename__] = MetaDataColumn
|
||||
self.registry[MetaDataTable.__tablename__] = MetaDataTable
|
||||
self.registry[AuthorizationMatrix.__tablename__] = AuthorizationMatrix
|
||||
self.registry[Assignment.__tablename__] = Assignment
|
||||
self.registry[Token.__tablename__] = Token
|
||||
self.registry[User.__tablename__] = User
|
||||
self.registry[Role.__tablename__] = Role
|
||||
self.registry[Profile.__tablename__] = Profile
|
||||
self.registry[Permission.__tablename__] = Permission
|
||||
self.registry[ModuleData.__tablename__] = ModuleData
|
||||
self.registry[MailAccount.__tablename__] = MailAccount
|
||||
self.registry[Mail.__tablename__] = Mail
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from sqlalchemy import Column, String, ForeignKey, Integer
|
||||
from sqlalchemy.dialects.mysql import BIT
|
||||
from sqlalchemy import Column, String, ForeignKey, Integer, Boolean
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
from src.db.models.base import Base, BaseMixin
|
||||
@@ -28,8 +27,8 @@ class MetaDataColumn(Base, BaseMixin):
|
||||
table = relationship("MetaDataTable", back_populates="table_columns")
|
||||
column_label = Column(String(255))
|
||||
filter_label = Column(String(255))
|
||||
is_shown = Column(BIT(1))
|
||||
show_filter = Column(BIT(1))
|
||||
is_shown = Column(Boolean)
|
||||
show_filter = Column(Boolean)
|
||||
ref_column = Column(String, nullable=True)
|
||||
|
||||
def __repr__(self):
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
"""
|
||||
copy data from JSON to Postgres
|
||||
"""
|
||||
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
|
||||
from pathlib import Path
|
||||
from config import get_logger, get_database_cursors
|
||||
import json
|
||||
import psycopg2
|
||||
from psycopg2.sql import SQL
|
||||
|
||||
parser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter)
|
||||
parser.add_argument('--verbose', '-v', action='count', default=0)
|
||||
parser.add_argument('--config', '-c', default='kontor-docker')
|
||||
parser.add_argument('--file', '-f', default='~/.sync/media/data.json')
|
||||
args = parser.parse_args()
|
||||
|
||||
def copy_data(postgres_conn, data_file: Path, log):
|
||||
postgres_cursor = postgres_conn.cursor()
|
||||
import_file = Path(data_file)
|
||||
if not import_file.exists():
|
||||
log.info(f"File {data_file} does not exist. Do nothing.")
|
||||
return
|
||||
log.info("read json file")
|
||||
with open(data_file, 'r') as json_file:
|
||||
json_load = json.load(json_file)
|
||||
for table in json_load:
|
||||
log.info(f"{table}: {len(json_load[table])}")
|
||||
# result[table] = import_table(table, json_load[table])
|
||||
truncate_statement = 'TRUNCATE {}'.format(table)
|
||||
#log.info(f"truncate: {truncate_statement}")
|
||||
postgres_cursor.execute("SET FOREIGN_KEY_CHECKS = 0")
|
||||
postgres_cursor.execute(truncate_statement)
|
||||
items = json_load[table]
|
||||
for item in items:
|
||||
#log.info(f"item: {item}")
|
||||
values = []
|
||||
columns = []
|
||||
for (key, value) in item.items():
|
||||
columns.append(key)
|
||||
values.append(value)
|
||||
row = tuple(values)
|
||||
log.info(f"values: {row}")
|
||||
insert_statement = 'INSERT INTO {}({}) VALUES({})'.format(table, ', '.join(columns), ', '.join(['%s']*len(columns)))
|
||||
#log.info(f"statement: {insert_statement}")
|
||||
postgres_cursor.execute(SQL(insert_statement), row)
|
||||
try:
|
||||
postgres_conn.commit()
|
||||
except psycopg2.Error as error:
|
||||
log.info('insert failed with %s', error)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
logger = get_logger(args.verbose, args.config)
|
||||
logger.info('kontor.json_to_postgres started')
|
||||
_, _, p_conn = get_database_cursors(logger, args.config)
|
||||
copy_data(p_conn, args.file, logger)
|
||||
p_conn.close()
|
||||
logger.info('kontor.json_to_postgres finished')
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
FROM alpine/java:21-jdk
|
||||
WORKDIR /
|
||||
ADD build/libs/kontor-spring-0.1.0-SNAPSHOT.jar app.jar
|
||||
ADD build/libs/kontor-spring-0.2.0-SNAPSHOT.jar app.jar
|
||||
EXPOSE 8000
|
||||
CMD ["java", "-jar", "-Dspring.profiles.active=prod", "-Dvaadin.productionMode=true", "app.jar"]
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
package de.thpeetz.kontor.admin.data;
|
||||
|
||||
import de.thpeetz.kontor.common.data.AbstractEntity;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Entity
|
||||
public class AuthorizationMatrix extends AbstractEntity {
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "user_id")
|
||||
@NotNull
|
||||
private User user;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "role_id")
|
||||
@NotNull
|
||||
private Role role;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuffer sb = new StringBuffer("AuthorizationMatrix{");
|
||||
sb.append("user=").append(user.getUserName());
|
||||
sb.append(", role=").append(role.getName());
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package de.thpeetz.kontor.admin.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import de.thpeetz.kontor.common.data.AbstractEntity;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@Slf4j
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@Entity
|
||||
public class Role extends AbstractEntity {
|
||||
|
||||
@NotEmpty
|
||||
private String name;
|
||||
|
||||
@OneToMany(fetch = FetchType.EAGER, mappedBy = "role")
|
||||
@Nullable
|
||||
private List<AuthorizationMatrix> matrix;
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package de.thpeetz.kontor.admin.data;
|
||||
|
||||
import de.thpeetz.kontor.common.data.AbstractEntity;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.Index;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.UniqueConstraint;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@Entity
|
||||
@Table(indexes = @Index(columnList = "userName"), uniqueConstraints = @UniqueConstraint(columnNames = {"userName"}))
|
||||
public class User extends AbstractEntity {
|
||||
|
||||
private String firstName;
|
||||
|
||||
private String lastName;
|
||||
|
||||
@NotEmpty
|
||||
private String userName;
|
||||
|
||||
private String email;
|
||||
|
||||
private String password;
|
||||
|
||||
private boolean enabled;
|
||||
|
||||
@OneToMany(fetch = FetchType.EAGER, mappedBy = "user")
|
||||
@Nullable
|
||||
private List<AuthorizationMatrix> matrix = new LinkedList<>();
|
||||
|
||||
@OneToMany(fetch = FetchType.EAGER, mappedBy = "user")
|
||||
@Nullable
|
||||
private List<Token> tokens = new LinkedList<>();
|
||||
|
||||
public String getFullName() {
|
||||
StringBuilder fullNamBuilder = new StringBuilder();
|
||||
if (firstName != null) {
|
||||
fullNamBuilder.append(firstName);
|
||||
}
|
||||
if (lastName != null) {
|
||||
if (fullNamBuilder.length() > 0) {
|
||||
fullNamBuilder.append(" ");
|
||||
}
|
||||
fullNamBuilder.append(lastName);
|
||||
}
|
||||
return fullNamBuilder.toString();
|
||||
}
|
||||
}
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
package de.thpeetz.kontor.admin.repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import de.thpeetz.kontor.admin.data.AuthorizationMatrix;
|
||||
import de.thpeetz.kontor.admin.data.Role;
|
||||
import de.thpeetz.kontor.admin.data.User;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface AuthorizationMatrixRepository extends JpaRepository<AuthorizationMatrix, String> {
|
||||
|
||||
List<AuthorizationMatrix> findByUser(User user);
|
||||
|
||||
List<AuthorizationMatrix> findByRole(Role role);
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package de.thpeetz.kontor.admin.repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import de.thpeetz.kontor.admin.data.Role;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
public interface RoleRepository extends JpaRepository<Role, String> {
|
||||
|
||||
@Query("select r from Role r " +
|
||||
"where lower(r.name) like lower(concat('%', :searchTerm, '%')) ")
|
||||
List<Role> search(@Param("searchTerm") String searchTerm);
|
||||
|
||||
@Query("select r from Role r " +
|
||||
"where lower(r.name) like lower(:name) ")
|
||||
Role findByName(@Param("name") String name);
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package de.thpeetz.kontor.admin.repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import de.thpeetz.kontor.admin.data.User;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
public interface UserRepository extends JpaRepository<User, String> {
|
||||
|
||||
@Query("select u from User u " +
|
||||
"where lower(u.lastName) like lower(concat('%', :searchTerm, '%')) ")
|
||||
List<User> search(@Param("searchTerm") String searchTerm);
|
||||
|
||||
User findByUserName(String userName);
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
package de.thpeetz.kontor.admin.views;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.vaadin.flow.component.ComponentEvent;
|
||||
import com.vaadin.flow.component.ComponentEventListener;
|
||||
import com.vaadin.flow.component.Key;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
import com.vaadin.flow.component.button.ButtonVariant;
|
||||
import com.vaadin.flow.component.combobox.ComboBox;
|
||||
import com.vaadin.flow.component.formlayout.FormLayout;
|
||||
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||
import com.vaadin.flow.data.binder.BeanValidationBinder;
|
||||
import com.vaadin.flow.data.binder.Binder;
|
||||
|
||||
import de.thpeetz.kontor.admin.data.AuthorizationMatrix;
|
||||
import de.thpeetz.kontor.admin.data.Role;
|
||||
import de.thpeetz.kontor.admin.data.User;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class AuthorizationForm extends FormLayout {
|
||||
|
||||
ComboBox<User> user = new ComboBox<>("User");
|
||||
ComboBox<Role> role = new ComboBox<>("Role");
|
||||
|
||||
Button save = new Button("Save");
|
||||
Button delete = new Button("Delete");
|
||||
Button close = new Button("Cancel");
|
||||
|
||||
Binder<AuthorizationMatrix> binder = new BeanValidationBinder<>(AuthorizationMatrix.class);
|
||||
|
||||
public AuthorizationForm(List<User> users, List<Role> roles) {
|
||||
addClassName("authorizationmatrix-form");
|
||||
binder.bindInstanceFields(this);
|
||||
|
||||
user.setItems(users);
|
||||
user.setItemLabelGenerator(User::getUserName);
|
||||
role.setItems(roles);
|
||||
role.setItemLabelGenerator(Role::getName);
|
||||
add(user, role, createButtonsLayout());
|
||||
}
|
||||
|
||||
private HorizontalLayout createButtonsLayout() {
|
||||
save.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
|
||||
delete.addThemeVariants(ButtonVariant.LUMO_ERROR);
|
||||
close.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
|
||||
|
||||
save.addClickShortcut(Key.ENTER);
|
||||
close.addClickShortcut(Key.ESCAPE);
|
||||
|
||||
save.addClickListener(event -> validateAndSave());
|
||||
delete.addClickListener(event -> fireEvent(new DeleteEvent(this, binder.getBean())));
|
||||
close.addClickListener(event -> fireEvent(new CloseEvent(this)));
|
||||
|
||||
binder.addStatusChangeListener(e -> save.setEnabled(binder.isValid()));
|
||||
return new HorizontalLayout(save, delete, close);
|
||||
}
|
||||
|
||||
private void validateAndSave() {
|
||||
if (binder.isValid()) {
|
||||
fireEvent(new SaveEvent(this, binder.getBean()));
|
||||
}
|
||||
}
|
||||
|
||||
public void setAuthorizationMatrix(AuthorizationMatrix authorizationMatrix) {
|
||||
binder.setBean(authorizationMatrix);
|
||||
}
|
||||
|
||||
public abstract static class AuthorizationFormEvent extends ComponentEvent<AuthorizationForm> {
|
||||
private AuthorizationMatrix authorizationMatrix;
|
||||
|
||||
protected AuthorizationFormEvent(AuthorizationForm source, AuthorizationMatrix authorizationMatrix) {
|
||||
super(source, false);
|
||||
this.authorizationMatrix = authorizationMatrix;
|
||||
}
|
||||
|
||||
public AuthorizationMatrix getAuthorizationMatrix() {
|
||||
return authorizationMatrix;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SaveEvent extends AuthorizationFormEvent {
|
||||
SaveEvent(AuthorizationForm source, AuthorizationMatrix authorizationMatrix) {
|
||||
super(source, authorizationMatrix);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DeleteEvent extends AuthorizationFormEvent {
|
||||
DeleteEvent(AuthorizationForm source, AuthorizationMatrix authorizationMatrix) {
|
||||
super(source, authorizationMatrix);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CloseEvent extends AuthorizationFormEvent {
|
||||
CloseEvent(AuthorizationForm source) {
|
||||
super(source, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void addDeleteListener(ComponentEventListener<DeleteEvent> listener) {
|
||||
addListener(DeleteEvent.class, listener);
|
||||
}
|
||||
|
||||
public void addSaveListener(ComponentEventListener<SaveEvent> listener) {
|
||||
addListener(SaveEvent.class, listener);
|
||||
}
|
||||
|
||||
public void addCloseListener(ComponentEventListener<CloseEvent> listener) {
|
||||
addListener(CloseEvent.class, listener);
|
||||
}
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
package de.thpeetz.kontor.admin.views;
|
||||
|
||||
import org.springframework.context.annotation.Scope;
|
||||
|
||||
import com.vaadin.flow.component.Component;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
import com.vaadin.flow.component.grid.Grid;
|
||||
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.spring.annotation.SpringComponent;
|
||||
|
||||
import de.thpeetz.kontor.admin.AdminConstants;
|
||||
import de.thpeetz.kontor.admin.data.AuthorizationMatrix;
|
||||
import de.thpeetz.kontor.admin.services.AdminService;
|
||||
import de.thpeetz.kontor.common.views.MainLayout;
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@SpringComponent
|
||||
@Scope("prototype")
|
||||
@RolesAllowed("ROLE_ADMIN")
|
||||
@Route(value = AdminConstants.AUTHORIZATION_ROUTE, layout = MainLayout.class)
|
||||
@PageTitle("Authorization | Admin | Kontor")
|
||||
public class AuthorizationView extends VerticalLayout {
|
||||
|
||||
Grid<AuthorizationMatrix> grid = new Grid<>(AuthorizationMatrix.class);
|
||||
AuthorizationForm form;
|
||||
AdminService service;
|
||||
|
||||
public AuthorizationView(AdminService service) {
|
||||
this.service = service;
|
||||
addClassName("authoriaztionmatrix-view");
|
||||
setSizeFull();
|
||||
configureGrid();
|
||||
configureForm();
|
||||
|
||||
add(getToolbar(), getContent());
|
||||
updateList();
|
||||
}
|
||||
|
||||
private void configureGrid() {
|
||||
grid.addClassName("authorizationmatrix-grid");
|
||||
grid.setSizeFull();
|
||||
grid.setColumns("user.userName", "role.name");
|
||||
grid.getColumns().forEach(col -> col.setAutoWidth(true));
|
||||
grid.asSingleSelect().addValueChangeListener(event -> editAuthorizationMatrix(event.getValue()));
|
||||
}
|
||||
|
||||
private void configureForm() {
|
||||
form = new AuthorizationForm(service.findAllUsers(), service.findAllRoles());
|
||||
form.setWidth("25em");
|
||||
form.addSaveListener(this::saveAuthorizationMatrix);
|
||||
form.addDeleteListener(this::deleteAuthorizationMatrix);
|
||||
form.addCloseListener(e -> closeEditor());
|
||||
}
|
||||
|
||||
private void saveAuthorizationMatrix(AuthorizationForm.SaveEvent event) {
|
||||
AuthorizationMatrix authorizationMatrix = event.getAuthorizationMatrix();
|
||||
service.saveAuthorizationMatrix(authorizationMatrix);
|
||||
updateList();
|
||||
closeEditor();
|
||||
}
|
||||
|
||||
private void deleteAuthorizationMatrix(AuthorizationForm.DeleteEvent event) {
|
||||
service.deleteAuthorizationMatrix(event.getAuthorizationMatrix());
|
||||
updateList();
|
||||
closeEditor();
|
||||
}
|
||||
|
||||
private Component getContent() {
|
||||
HorizontalLayout content = new HorizontalLayout(grid, form);
|
||||
content.setFlexGrow(2, grid);
|
||||
content.setFlexGrow(1, form);
|
||||
content.addClassName("content");
|
||||
content.setSizeFull();
|
||||
return content;
|
||||
}
|
||||
|
||||
private HorizontalLayout getToolbar() {
|
||||
Button addAuthorizationMaxtrixButton = new Button("Add permssion", click -> addAuthorizationMatrix());
|
||||
HorizontalLayout toolbar = new HorizontalLayout(addAuthorizationMaxtrixButton);
|
||||
toolbar.addClassName("toolbar");
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
public void editAuthorizationMatrix(AuthorizationMatrix authorizationMatrix) {
|
||||
if (authorizationMatrix == null) {
|
||||
closeEditor();
|
||||
} else {
|
||||
form.setAuthorizationMatrix(authorizationMatrix);
|
||||
form.setVisible(true);
|
||||
addClassName("editing");
|
||||
}
|
||||
}
|
||||
|
||||
public void closeEditor() {
|
||||
form.setAuthorizationMatrix(null);
|
||||
form.setVisible(false);
|
||||
removeClassName("editing");
|
||||
}
|
||||
|
||||
private void addAuthorizationMatrix() {
|
||||
grid.asSingleSelect().clear();
|
||||
editAuthorizationMatrix(new AuthorizationMatrix());
|
||||
}
|
||||
|
||||
private void updateList() {
|
||||
grid.setItems(service.findAllAuthorizationMatrices());
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
package de.thpeetz.kontor.admin.views;
|
||||
|
||||
import com.vaadin.flow.component.ComponentEvent;
|
||||
import com.vaadin.flow.component.ComponentEventListener;
|
||||
import com.vaadin.flow.component.Key;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
import com.vaadin.flow.component.button.ButtonVariant;
|
||||
import com.vaadin.flow.component.formlayout.FormLayout;
|
||||
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||
import com.vaadin.flow.component.textfield.TextField;
|
||||
import com.vaadin.flow.data.binder.BeanValidationBinder;
|
||||
import com.vaadin.flow.data.binder.Binder;
|
||||
|
||||
import de.thpeetz.kontor.admin.data.Role;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class RoleForm extends FormLayout {
|
||||
|
||||
TextField name = new TextField("Role name");
|
||||
|
||||
Button save = new Button("Save");
|
||||
Button delete = new Button("Delete");
|
||||
Button close = new Button("Cancel");
|
||||
|
||||
Binder<Role> binder = new BeanValidationBinder<>(Role.class);
|
||||
|
||||
public RoleForm() {
|
||||
addClassName("role-form");
|
||||
binder.bindInstanceFields(this);
|
||||
add(name, createButtonsLayout());
|
||||
}
|
||||
|
||||
private HorizontalLayout createButtonsLayout() {
|
||||
save.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
|
||||
delete.addThemeVariants(ButtonVariant.LUMO_ERROR);
|
||||
close.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
|
||||
|
||||
save.addClickShortcut(Key.ENTER);
|
||||
close.addClickShortcut(Key.ESCAPE);
|
||||
|
||||
save.addClickListener(event -> validateAndSave());
|
||||
delete.addClickListener(event -> fireEvent(new DeleteEvent(this, binder.getBean())));
|
||||
close.addClickListener(event -> fireEvent(new CloseEvent(this)));
|
||||
|
||||
binder.addStatusChangeListener(e -> save.setEnabled(binder.isValid()));
|
||||
return new HorizontalLayout(save, delete, close);
|
||||
}
|
||||
|
||||
private void validateAndSave() {
|
||||
if (binder.isValid()) {
|
||||
fireEvent(new SaveEvent(this, binder.getBean()));
|
||||
}
|
||||
}
|
||||
|
||||
public void setRole(Role role) {
|
||||
binder.setBean(role);
|
||||
}
|
||||
|
||||
public abstract static class RoleFormEvent extends ComponentEvent<RoleForm> {
|
||||
private Role role;
|
||||
|
||||
protected RoleFormEvent(RoleForm source, Role role) {
|
||||
super(source, false);
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
public Role getRole() {
|
||||
return role;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SaveEvent extends RoleFormEvent {
|
||||
SaveEvent(RoleForm source, Role role) {
|
||||
super(source, role);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DeleteEvent extends RoleFormEvent {
|
||||
DeleteEvent(RoleForm source, Role role) {
|
||||
super(source, role);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CloseEvent extends RoleFormEvent {
|
||||
CloseEvent(RoleForm source) {
|
||||
super(source, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void addDeleteListener(ComponentEventListener<DeleteEvent> listener) {
|
||||
addListener(DeleteEvent.class, listener);
|
||||
}
|
||||
|
||||
public void addSaveListener(ComponentEventListener<SaveEvent> listener) {
|
||||
addListener(SaveEvent.class, listener);
|
||||
}
|
||||
|
||||
public void addCloseListener(ComponentEventListener<CloseEvent> listener) {
|
||||
addListener(CloseEvent.class, listener);
|
||||
}
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
package de.thpeetz.kontor.admin.views;
|
||||
|
||||
import org.springframework.context.annotation.Scope;
|
||||
|
||||
import com.vaadin.flow.component.Component;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
import com.vaadin.flow.component.grid.Grid;
|
||||
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||
import com.vaadin.flow.component.textfield.TextField;
|
||||
import com.vaadin.flow.data.value.ValueChangeMode;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.spring.annotation.SpringComponent;
|
||||
|
||||
import de.thpeetz.kontor.admin.AdminConstants;
|
||||
import de.thpeetz.kontor.admin.data.Role;
|
||||
import de.thpeetz.kontor.admin.services.AdminService;
|
||||
import de.thpeetz.kontor.common.views.MainLayout;
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@SpringComponent
|
||||
@Scope("prototype")
|
||||
@RolesAllowed("ROLE_ADMIN")
|
||||
@Route(value = AdminConstants.ROLE_ROUTE, layout = MainLayout.class)
|
||||
@PageTitle("Rollen | Admin | Kontor")
|
||||
public class RoleView extends VerticalLayout {
|
||||
Grid<Role> grid = new Grid<>(Role.class);
|
||||
TextField filterText = new TextField();
|
||||
RoleForm form;
|
||||
AdminService service;
|
||||
|
||||
public RoleView(AdminService service) {
|
||||
this.service = service;
|
||||
addClassName("user-view");
|
||||
setSizeFull();
|
||||
configureGrid();
|
||||
configureForm();
|
||||
|
||||
add(getToolbar(), getContent());
|
||||
updateList();
|
||||
}
|
||||
|
||||
private void configureGrid() {
|
||||
grid.addClassName("user-grid");
|
||||
grid.setSizeFull();
|
||||
grid.setColumns("name");
|
||||
grid.getColumns().forEach(col -> col.setAutoWidth(true));
|
||||
grid.asSingleSelect().addValueChangeListener(event -> editRole(event.getValue()));
|
||||
}
|
||||
|
||||
private void configureForm() {
|
||||
form = new RoleForm();
|
||||
form.setWidth("25em");
|
||||
form.addSaveListener(this::saveRole);
|
||||
form.addDeleteListener(this::deleteRole);
|
||||
form.addCloseListener(e -> closeEditor());
|
||||
}
|
||||
|
||||
private void saveRole(RoleForm.SaveEvent event) {
|
||||
service.saveRole(event.getRole());
|
||||
updateList();
|
||||
closeEditor();
|
||||
}
|
||||
|
||||
private void deleteRole(RoleForm.DeleteEvent event) {
|
||||
service.deleteRole(event.getRole());
|
||||
updateList();
|
||||
closeEditor();
|
||||
}
|
||||
|
||||
private Component getContent() {
|
||||
HorizontalLayout content = new HorizontalLayout(grid, form);
|
||||
content.setFlexGrow(2, grid);
|
||||
content.setFlexGrow(1, form);
|
||||
content.addClassName("content");
|
||||
content.setSizeFull();
|
||||
return content;
|
||||
}
|
||||
|
||||
private HorizontalLayout getToolbar() {
|
||||
filterText.setPlaceholder("Filter by user name...");
|
||||
filterText.setClearButtonVisible(true);
|
||||
filterText.setValueChangeMode(ValueChangeMode.LAZY);
|
||||
filterText.addValueChangeListener(e -> updateList());
|
||||
Button addUserButton = new Button("Add user", click -> addUser());
|
||||
HorizontalLayout toolbar = new HorizontalLayout(filterText, addUserButton);
|
||||
toolbar.addClassName("toolbar");
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
public void editRole(Role role) {
|
||||
if (role == null) {
|
||||
closeEditor();
|
||||
} else {
|
||||
form.setRole(role);
|
||||
form.setVisible(true);
|
||||
addClassName("editing");
|
||||
}
|
||||
}
|
||||
|
||||
public void closeEditor() {
|
||||
form.setRole(null);
|
||||
form.setVisible(false);
|
||||
removeClassName("editing");
|
||||
}
|
||||
|
||||
private void addUser() {
|
||||
grid.asSingleSelect().clear();
|
||||
editRole(new Role());
|
||||
}
|
||||
|
||||
private void updateList() {
|
||||
grid.setItems(service.findAllRoles(filterText.getValue()));
|
||||
}
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
package de.thpeetz.kontor.admin.views;
|
||||
|
||||
import com.vaadin.flow.component.ComponentEvent;
|
||||
import com.vaadin.flow.component.ComponentEventListener;
|
||||
import com.vaadin.flow.component.Key;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
import com.vaadin.flow.component.button.ButtonVariant;
|
||||
import com.vaadin.flow.component.checkbox.Checkbox;
|
||||
import com.vaadin.flow.component.checkbox.CheckboxGroup;
|
||||
import com.vaadin.flow.component.checkbox.CheckboxGroupVariant;
|
||||
import com.vaadin.flow.component.formlayout.FormLayout;
|
||||
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||
import com.vaadin.flow.component.textfield.EmailField;
|
||||
import com.vaadin.flow.component.textfield.PasswordField;
|
||||
import com.vaadin.flow.component.textfield.TextField;
|
||||
import com.vaadin.flow.data.binder.BeanValidationBinder;
|
||||
import com.vaadin.flow.data.binder.Binder;
|
||||
import de.thpeetz.kontor.admin.data.Role;
|
||||
import de.thpeetz.kontor.admin.data.User;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
public class UserForm extends FormLayout {
|
||||
|
||||
TextField userName = new TextField("User name");
|
||||
PasswordField password = new PasswordField("Password");
|
||||
EmailField email = new EmailField("Email");
|
||||
TextField firstName = new TextField("First name");
|
||||
TextField lastName = new TextField("Last name");
|
||||
Checkbox enabled = new Checkbox("Enabled");
|
||||
String originalPassword;
|
||||
|
||||
CheckboxGroup<Role> permissions = new CheckboxGroup<>("Permissions");
|
||||
|
||||
Button save = new Button("Save");
|
||||
Button delete = new Button("Delete");
|
||||
Button close = new Button("Cancel");
|
||||
|
||||
Binder<User> binder = new BeanValidationBinder<>(User.class);
|
||||
|
||||
public UserForm() {
|
||||
addClassName("user-form");
|
||||
binder.bindInstanceFields(this);
|
||||
add(userName, password, email, firstName, lastName, enabled, configurePermissionsGroup(), createButtonsLayout());
|
||||
}
|
||||
|
||||
private CheckboxGroup<Role> configurePermissionsGroup() {
|
||||
permissions.addThemeVariants(CheckboxGroupVariant.LUMO_VERTICAL);
|
||||
permissions.setItemLabelGenerator(Role::getName);
|
||||
permissions.addValueChangeListener(event -> {
|
||||
log.debug("permissions changed: {}", event);
|
||||
});
|
||||
return permissions;
|
||||
}
|
||||
|
||||
private HorizontalLayout createButtonsLayout() {
|
||||
save.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
|
||||
delete.addThemeVariants(ButtonVariant.LUMO_ERROR);
|
||||
close.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
|
||||
|
||||
save.addClickShortcut(Key.ENTER);
|
||||
close.addClickShortcut(Key.ESCAPE);
|
||||
|
||||
save.addClickListener(event -> validateAndSave());
|
||||
delete.addClickListener(event -> fireEvent(new DeleteEvent(this, binder.getBean())));
|
||||
close.addClickListener(event -> fireEvent(new CloseEvent(this)));
|
||||
|
||||
binder.addStatusChangeListener(e -> save.setEnabled(binder.isValid()));
|
||||
return new HorizontalLayout(save, delete, close);
|
||||
}
|
||||
|
||||
private void validateAndSave() {
|
||||
if (binder.isValid()) {
|
||||
fireEvent(new SaveEvent(this, binder.getBean()));
|
||||
}
|
||||
}
|
||||
|
||||
public void setUser(User user) {
|
||||
binder.setBean(user);
|
||||
//log.debug("UserForm.setUser: {}", user);
|
||||
if (user != null) {
|
||||
this.originalPassword = user.getPassword();
|
||||
} else {
|
||||
this.originalPassword = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setRoles(List<Role> roles, User user) {
|
||||
permissions.setItems(roles);
|
||||
user.getMatrix().stream().forEach(authorizationMatrix -> {
|
||||
permissions.select(authorizationMatrix.getRole());
|
||||
});
|
||||
}
|
||||
|
||||
public boolean hasPasswordChanged(User user) {
|
||||
return !originalPassword.equals(user.getPassword());
|
||||
}
|
||||
|
||||
public abstract static class UserFormEvent extends ComponentEvent<UserForm> {
|
||||
private User user;
|
||||
|
||||
protected UserFormEvent(UserForm source, User user) {
|
||||
super(source, false);
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public User getUser() {
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SaveEvent extends UserFormEvent {
|
||||
SaveEvent(UserForm source, User user) {
|
||||
super(source, user);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DeleteEvent extends UserFormEvent {
|
||||
DeleteEvent(UserForm source, User user) {
|
||||
super(source, user);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CloseEvent extends UserFormEvent {
|
||||
CloseEvent(UserForm source) {
|
||||
super(source, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void addDeleteListener(ComponentEventListener<DeleteEvent> listener) {
|
||||
addListener(DeleteEvent.class, listener);
|
||||
}
|
||||
|
||||
public void addSaveListener(ComponentEventListener<SaveEvent> listener) {
|
||||
addListener(SaveEvent.class, listener);
|
||||
}
|
||||
|
||||
public void addCloseListener(ComponentEventListener<CloseEvent> listener) {
|
||||
addListener(CloseEvent.class, listener);
|
||||
}
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
package de.thpeetz.kontor.admin.views;
|
||||
|
||||
import com.vaadin.flow.component.Component;
|
||||
import com.vaadin.flow.component.button.Button;
|
||||
import com.vaadin.flow.component.grid.Grid;
|
||||
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
|
||||
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
|
||||
import com.vaadin.flow.component.textfield.TextField;
|
||||
import com.vaadin.flow.data.value.ValueChangeMode;
|
||||
import com.vaadin.flow.router.PageTitle;
|
||||
import com.vaadin.flow.router.Route;
|
||||
import com.vaadin.flow.spring.annotation.SpringComponent;
|
||||
import de.thpeetz.kontor.admin.data.Role;
|
||||
import de.thpeetz.kontor.admin.data.User;
|
||||
import de.thpeetz.kontor.admin.services.KontorUserDetailsService;
|
||||
import de.thpeetz.kontor.common.views.MainLayout;
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@SpringComponent
|
||||
@Scope("prototype")
|
||||
@RolesAllowed("ROLE_ADMIN")
|
||||
@Route(value = "admin/user", layout = MainLayout.class)
|
||||
@PageTitle("User | Admin | Kontor")
|
||||
public class UserView extends VerticalLayout {
|
||||
|
||||
Grid<User> grid = new Grid<>(User.class);
|
||||
TextField filterText = new TextField();
|
||||
UserForm form;
|
||||
KontorUserDetailsService service;
|
||||
|
||||
@Autowired
|
||||
PasswordEncoder passwordEncoder;
|
||||
|
||||
public UserView(KontorUserDetailsService service) {
|
||||
this.service = service;
|
||||
addClassName("user-view");
|
||||
setSizeFull();
|
||||
configureGrid();
|
||||
configureForm();
|
||||
|
||||
add(getToolbar(), getContent());
|
||||
updateList();
|
||||
}
|
||||
|
||||
private void configureGrid() {
|
||||
grid.addClassName("user-grid");
|
||||
grid.setSizeFull();
|
||||
grid.setColumns("userName", "email", "firstName", "lastName", "enabled");
|
||||
grid.getColumns().forEach(col -> col.setAutoWidth(true));
|
||||
grid.asSingleSelect().addValueChangeListener(event -> editUser(event.getValue()));
|
||||
}
|
||||
|
||||
private void configureForm() {
|
||||
form = new UserForm();
|
||||
form.setWidth("25em");
|
||||
form.setVisible(false);
|
||||
form.addSaveListener(this::saveUser);
|
||||
form.addDeleteListener(this::deleteUser);
|
||||
form.addCloseListener(e -> closeEditor());
|
||||
}
|
||||
|
||||
private void saveUser(UserForm.SaveEvent event) {
|
||||
User user = event.getUser();
|
||||
log.debug("UserView.saveUser: {}", user);
|
||||
List<Role> permissions = form.permissions.getSelectedItems().stream().collect(Collectors.toList());
|
||||
log.info("selected permissions: {}", permissions);
|
||||
if (form.hasPasswordChanged(user)) {
|
||||
user.setPassword(passwordEncoder.encode(user.getPassword()));
|
||||
log.debug("password changed for user {}", user);
|
||||
}
|
||||
service.saveUser(user, permissions);
|
||||
updateList();
|
||||
closeEditor();
|
||||
}
|
||||
|
||||
private void deleteUser(UserForm.DeleteEvent event) {
|
||||
service.deleteUser(event.getUser());
|
||||
updateList();
|
||||
closeEditor();
|
||||
}
|
||||
|
||||
private Component getContent() {
|
||||
HorizontalLayout content = new HorizontalLayout(grid, form);
|
||||
content.setFlexGrow(2, grid);
|
||||
content.setFlexGrow(1, form);
|
||||
content.addClassName("content");
|
||||
content.setSizeFull();
|
||||
return content;
|
||||
}
|
||||
|
||||
private HorizontalLayout getToolbar() {
|
||||
filterText.setPlaceholder("Filter by user name...");
|
||||
filterText.setClearButtonVisible(true);
|
||||
filterText.setValueChangeMode(ValueChangeMode.LAZY);
|
||||
filterText.addValueChangeListener(e -> updateList());
|
||||
Button addUserButton = new Button("Add user", click -> addUser());
|
||||
HorizontalLayout toolbar = new HorizontalLayout(filterText, addUserButton);
|
||||
toolbar.addClassName("toolbar");
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
public void editUser(User user) {
|
||||
if (user == null) {
|
||||
closeEditor();
|
||||
} else {
|
||||
form.setUser(user);
|
||||
form.setRoles(service.findAllRoles(), user);
|
||||
form.setVisible(true);
|
||||
addClassName("editing");
|
||||
}
|
||||
}
|
||||
|
||||
public void closeEditor() {
|
||||
form.setUser(null);
|
||||
form.setVisible(false);
|
||||
removeClassName("editing");
|
||||
}
|
||||
|
||||
private void addUser() {
|
||||
grid.asSingleSelect().clear();
|
||||
editUser(new User());
|
||||
}
|
||||
|
||||
private void updateList() {
|
||||
grid.setItems(service.findAllUsers(filterText.getValue()));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user