rename User to Profile and Role to Permission. refs #15

This commit is contained in:
Thomas Peetz
2025-04-30 17:22:40 +02:00
parent 8833d2ca6a
commit 5850b1cfb0
29 changed files with 567 additions and 579 deletions
+14 -14
View File
@@ -7,15 +7,15 @@ from sqlalchemy.orm import relationship, mapped_column, Mapped
from src.db.models.base import Base, BaseMixin
class User(Base, BaseMixin):
__tablename__ = 'user'
class Profile(Base, BaseMixin):
__tablename__ = 'profile'
first_name = Column(String(255))
last_name = Column(String(255))
user_name = Column(String(255), nullable=False)
email = Column(String(255))
password = Column(String(255))
enabled = Column(BIT(1))
matrix = relationship("AuthorizationMatrix")
assignments = relationship("Assignment")
tokens = relationship("Token")
def get_full_name(self) -> str:
@@ -35,22 +35,22 @@ class Token(Base, BaseMixin):
name = Column(String(255))
last_used_date: Mapped[datetime] = mapped_column()
enabled = Column(BIT(1))
user_id = Column(String(255), ForeignKey("user.id"), nullable=False)
user = relationship("User", back_populates="tokens")
profile_id = Column(String(255), ForeignKey("profile.id"), nullable=False)
profile = relationship("Profile", back_populates="tokens")
class Role(Base, BaseMixin):
__tablename__ = "role"
class Permission(Base, BaseMixin):
__tablename__ = "permission"
name = Column(String(255), nullable=False)
matrix = relationship("AuthorizationMatrix")
assignments = relationship("Assignment")
class AuthorizationMatrix(Base, BaseMixin):
__tablename__ = "authorization_matrix"
user_id = Column(String, ForeignKey("user.id"), nullable=False)
user = relationship("User", back_populates="matrix")
role_id = Column(String, ForeignKey("role.id"), nullable=False)
role = relationship("Role", back_populates="matrix")
class Assignment(Base, BaseMixin):
__tablename__ = "assignment"
profile_id = Column(String, ForeignKey("profile.id"), nullable=False)
profile = relationship("Profile", back_populates="assignments")
permission_id = Column(String, ForeignKey("permission.id"), nullable=False)
permission = relationship("Permission", back_populates="assignments")
class ModuleData(Base, BaseMixin):
+1 -1
View File
@@ -1,5 +1,5 @@
"""
copy data from SQLite to MariaDB
copy data from JSON to MariaDB
"""
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
from pathlib import Path
+14 -14
View File
@@ -7,15 +7,15 @@ from sqlalchemy.orm import relationship, mapped_column, Mapped
from .base import Base, BaseMixin
class User(Base, BaseMixin):
__tablename__ = 'user'
class Profile(Base, BaseMixin):
__tablename__ = 'profile'
first_name = Column(String(255))
last_name = Column(String(255))
user_name = Column(String(255), nullable=False)
email = Column(String(255))
password = Column(String(255))
enabled = Column(BIT(1))
matrix = relationship("AuthorizationMatrix")
assignments = relationship("Assignment")
tokens = relationship("Token")
def get_full_name(self) -> str:
@@ -35,22 +35,22 @@ class Token(Base, BaseMixin):
name = Column(String(255))
last_used_date: Mapped[datetime] = mapped_column()
enabled = Column(BIT(1))
user_id = Column(String(255), ForeignKey("user.id"), nullable=False)
user = relationship("User", back_populates="tokens")
profile_id = Column(String(255), ForeignKey("profile.id"), nullable=False)
profile = relationship("Profile", back_populates="tokens")
class Role(Base, BaseMixin):
__tablename__ = "role"
class Permission(Base, BaseMixin):
__tablename__ = "permission"
name = Column(String(255), nullable=False)
matrix = relationship("AuthorizationMatrix")
assignments = relationship("Assignment")
class AuthorizationMatrix(Base, BaseMixin):
__tablename__ = "authorization_matrix"
user_id = Column(String, ForeignKey("user.id"), nullable=False)
user = relationship("User", back_populates="matrix")
role_id = Column(String, ForeignKey("role.id"), nullable=False)
role = relationship("Role", back_populates="matrix")
class Assignment(Base, BaseMixin):
__tablename__ = "assignment"
profile_id = Column(String, ForeignKey("profile.id"), nullable=False)
profile = relationship("Profile", back_populates="assignments")
permission_id = Column(String, ForeignKey("permission.id"), nullable=False)
permission = relationship("Permission", back_populates="assignments")
class ModuleData(Base, BaseMixin):
+4 -4
View File
@@ -13,7 +13,7 @@ from sqlalchemy.orm import sessionmaker
from .tysc import Card, CardSet, Rooster, Team, FieldPosition, Player, Vendor, Sport
from .comic import Issue, TradePaperback, StoryArc, Volume, ComicWork, Artist, Comic, Publisher, WorkType
from .bookshelf import ArticleAuthor, BookAuthor, BookshelfPublisher, Article, Book, Author
from .admin import Mail, MailAccount, ModuleData, Role, User, Token, AuthorizationMatrix
from .admin import Mail, MailAccount, ModuleData, Permission, Profile, Token, Assignment
from .metadata import MetaDataTable, MetaDataColumn
from .media import MediaVideo, MediaArticle, MediaFile, MediaActor, MediaActorFile
@@ -81,10 +81,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
@@ -18,36 +18,36 @@ public class AdminConstants {
public static final String ADMIN_TITLE = "Verwaltung";
public static final String AUTHORIZATION = "Berechtigungen";
public static final String AUTHORIZATION_ROUTE = "/admin/authorization";
public static final String ASSIGNMENT_ROUTE = "/admin/assignment";
public static final String DATA = "Daten";
public static final String METADATA_ROUTE = "admin/metadata";
public static final String ROLE = "Rollen";
public static final String ROLE_ROUTE = "/admin/role";
public static final String USER = "Benutzer";
public static final String USER_ROUTE = "/admin/user";
public static final String PERMISSION = "Berechtigungen";
public static final String PERMISSION_ROUTE = "/admin/permission";
public static final String PROFILE = "Benutzer";
public static final String PROFILE_ROUTE = "/admin/profile";
public static final String ADMIN = "admin";
public static final String ADMIN_ROUTE = "/admin";
public static RouterLink getUserNavigation() {
return new RouterLink(USER, UserView.class);
public static RouterLink getProfileNavigation() {
return new RouterLink(PROFILE, ProfileView.class);
}
public static RouterLink getRoleNavigation() {
return new RouterLink(ROLE, RoleView.class);
public static RouterLink getPermissionNavigation() {
return new RouterLink(PERMISSION, PermissionView.class);
}
public static RouterLink getAuthorizationNavigation() {
return new RouterLink(AUTHORIZATION, AuthorizationView.class);
return new RouterLink(AUTHORIZATION, AssignmentView.class);
}
public static SideNavItem getAdminNavigation() {
SideNavItem administration = new SideNavItem(ADMIN_TITLE, USER_ROUTE, VaadinIcon.GROUP.create());
administration.addItem(new SideNavItem(USER, USER_ROUTE, VaadinIcon.USERS.create()));
administration.addItem(new SideNavItem(ROLE, RoleView.class));
SideNavItem data = new SideNavItem(DATA, AUTHORIZATION_ROUTE, VaadinIcon.DATABASE.create());
SideNavItem administration = new SideNavItem(ADMIN_TITLE, PROFILE_ROUTE, VaadinIcon.GROUP.create());
administration.addItem(new SideNavItem(PROFILE, PROFILE_ROUTE, VaadinIcon.USERS.create()));
administration.addItem(new SideNavItem(PERMISSION, PermissionView.class));
SideNavItem data = new SideNavItem(DATA, ASSIGNMENT_ROUTE, VaadinIcon.DATABASE.create());
data.addItem(new SideNavItem(ComicConstants.COMICWORK, ComicWorkView.class));
data.addItem(new SideNavItem(MediaConstants.MEDIAACTORFILE, MediaActorFileView.class));
data.addItem(new SideNavItem(AUTHORIZATION, AuthorizationView.class));
data.addItem(new SideNavItem(AUTHORIZATION, AssignmentView.class));
data.addItem(new SideNavItem("Data Import", ModuleDataView.class));
data.addItem(new SideNavItem("Meta Data", MetaDataView.class));
administration.addItem(data);
@@ -1,9 +1,7 @@
package de.thpeetz.kontor.admin;
import de.thpeetz.kontor.admin.data.*;
import de.thpeetz.kontor.admin.repository.AuthorizationMatrixRepository;
import de.thpeetz.kontor.admin.repository.MailAccountRepository;
import de.thpeetz.kontor.admin.repository.UserRepository;
import de.thpeetz.kontor.admin.repository.*;
import de.thpeetz.kontor.admin.services.AdminService;
import de.thpeetz.kontor.admin.services.MetaDataService;
import de.thpeetz.kontor.mailclient.data.MailAccount;
@@ -23,10 +21,10 @@ public class SetupModuleAdmin implements ApplicationListener<ContextRefreshedEve
boolean alreadySetup = false;
@Autowired
private UserRepository userRepository;
private ProfileRepository profileRepository;
@Autowired
private AuthorizationMatrixRepository authorizationMatrixRepository;
private AssignmentRepository assignmentRepository;
@Autowired
private PasswordEncoder passwordEncoder;
@@ -50,13 +48,13 @@ public class SetupModuleAdmin implements ApplicationListener<ContextRefreshedEve
}
// Create initial roles and users
Role adminRole = adminService.addRole("ROLE_ADMIN");
Role userRole = adminService.addRole("ROLE_USER");
List<User> users = userRepository.findAll();
if (users.isEmpty()) {
User adminUser = initAdminUser();
initMatrix(adminRole, adminUser);
initMatrix(userRole, adminUser);
Permission adminPermission = adminService.addPermission("ROLE_ADMIN");
Permission userPermission = adminService.addPermission("ROLE_USER");
List<Profile> profiles = profileRepository.findAll();
if (profiles.isEmpty()) {
Profile adminProfile = initAdminUser();
initAssignments(adminPermission, adminProfile);
initAssignments(userPermission, adminProfile);
}
log.info("MailProperties: {}", mailProperties);
initMail(mailProperties);
@@ -98,32 +96,32 @@ public class SetupModuleAdmin implements ApplicationListener<ContextRefreshedEve
}
}
private void initMatrix(Role role, User user) {
log.info("initMatrix: Role {} for User {}", role.getName(), user.getUserName());
Collection<AuthorizationMatrix> configuredRoles = authorizationMatrixRepository.findByUser(user);
if (configuredRoles.stream().anyMatch(matrix -> matrix.getRole().getId().equals(role.getId()))) {
log.info("Role {} already defined", role.getName());
private void initAssignments(Permission permission, Profile profile) {
log.info("initAssignments: Permission {} for Profile {}", permission.getName(), profile.getUserName());
Collection<Assignment> configuredRoles = assignmentRepository.findByProfile(profile);
if (configuredRoles.stream().anyMatch(assignment -> assignment.getPermission().getId().equals(permission.getId()))) {
log.info("Permission {} already defined", permission.getName());
} else {
log.info("add Role {} to User {}", role.getName(), user.getUserName());
final AuthorizationMatrix adminMatrix = new AuthorizationMatrix();
adminMatrix.setUser(user);
adminMatrix.setRole(role);
authorizationMatrixRepository.save(adminMatrix);
log.info("add Permission {} to Profile {}", permission.getName(), profile.getUserName());
final Assignment assignment = new Assignment();
assignment.setProfile(profile);
assignment.setPermission(permission);
assignmentRepository.save(assignment);
}
}
private User initAdminUser() {
private Profile initAdminUser() {
log.info("initAdminUser");
User admin = userRepository.findByUserName("admin");
Profile admin = profileRepository.findByUserName("admin");
if (admin == null) {
log.info("User admin not found, will be created.");
admin = new User();
log.info("Profile admin not found, will be created.");
admin = new Profile();
admin.setFirstName("Admin");
admin.setLastName("Administrator");
admin.setUserName("admin");
admin.setEmail("admin@example.org");
admin.setPassword(passwordEncoder.encode("admin"));
userRepository.save(admin);
profileRepository.save(admin);
}
return admin;
}
@@ -348,17 +346,17 @@ public class SetupModuleAdmin implements ApplicationListener<ContextRefreshedEve
metaDataService.getColumn(cardTable, "card_set_id", "card_set_id", "TEXT", null, 7, Boolean.FALSE, "", Boolean.FALSE, null);
metaDataService.getColumn(cardTable, "rooster_id", "rooster_id", "TEXT", null, 8, Boolean.FALSE, "", Boolean.FALSE, null);
metaDataService.getColumn(cardTable, "vendor_id", "vendor_id", "TEXT", null, 9, Boolean.FALSE, "", Boolean.FALSE, null);
MetaDataTable userTable = metaDataService.getTable("user");
metaDataService.getColumn(userTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.TRUE, "", Boolean.FALSE, null);
metaDataService.getColumn(userTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
metaDataService.getColumn(userTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
metaDataService.getColumn(userTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
metaDataService.getColumn(userTable, "first_name", "first_name", "TEXT", null, 5, Boolean.TRUE, "", Boolean.FALSE, null);
metaDataService.getColumn(userTable, "last_name", "last_name", "TEXT", null, 6, Boolean.TRUE, "", Boolean.FALSE, null);
metaDataService.getColumn(userTable, "user_name", "user_name", "TEXT", "UNIQUE", 7, Boolean.TRUE, "", Boolean.FALSE, null);
metaDataService.getColumn(userTable, "email", "email", "TEXT", null, 8, Boolean.TRUE, "", Boolean.FALSE, null);
metaDataService.getColumn(userTable, "password", "password", "TEXT", null, 9, Boolean.FALSE, "Password", Boolean.FALSE, null);
metaDataService.getColumn(userTable, "enabled", "enabled", "BOOLEAN", null, 10, Boolean.TRUE, "", Boolean.TRUE, null);
MetaDataTable profileTable = metaDataService.getTable("profile");
metaDataService.getColumn(profileTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.TRUE, "", Boolean.FALSE, null);
metaDataService.getColumn(profileTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
metaDataService.getColumn(profileTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
metaDataService.getColumn(profileTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
metaDataService.getColumn(profileTable, "first_name", "first_name", "TEXT", null, 5, Boolean.TRUE, "", Boolean.FALSE, null);
metaDataService.getColumn(profileTable, "last_name", "last_name", "TEXT", null, 6, Boolean.TRUE, "", Boolean.FALSE, null);
metaDataService.getColumn(profileTable, "user_name", "user_name", "TEXT", "UNIQUE", 7, Boolean.TRUE, "", Boolean.FALSE, null);
metaDataService.getColumn(profileTable, "email", "email", "TEXT", null, 8, Boolean.TRUE, "", Boolean.FALSE, null);
metaDataService.getColumn(profileTable, "password", "password", "TEXT", null, 9, Boolean.FALSE, "Password", Boolean.FALSE, null);
metaDataService.getColumn(profileTable, "enabled", "enabled", "BOOLEAN", null, 10, Boolean.TRUE, "", Boolean.TRUE, null);
MetaDataTable tokenTable = metaDataService.getTable("token");
metaDataService.getColumn(tokenTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.TRUE, "", Boolean.FALSE, null);
metaDataService.getColumn(tokenTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
@@ -368,20 +366,20 @@ public class SetupModuleAdmin implements ApplicationListener<ContextRefreshedEve
metaDataService.getColumn(tokenTable, "name", "name", "TEXT", null, 6, Boolean.TRUE, "Name", Boolean.FALSE, null);
metaDataService.getColumn(tokenTable, "last_used_date", "used", "TIMESTAMP", null, 7, Boolean.FALSE, "", Boolean.FALSE, null);
metaDataService.getColumn(tokenTable, "enabled", "enabled", "BOOLEAN", null, 8, Boolean.TRUE, "", Boolean.TRUE, "Enabled");
metaDataService.getColumn(tokenTable, "user_id", "user_id", "TEXT", null, 9, Boolean.TRUE, "User", Boolean.FALSE, null, "user_name");
MetaDataTable roleTable = metaDataService.getTable("role");
metaDataService.getColumn(roleTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.TRUE, "", Boolean.FALSE, null);
metaDataService.getColumn(roleTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
metaDataService.getColumn(roleTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
metaDataService.getColumn(roleTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
metaDataService.getColumn(roleTable, "name", "name", "TEXT", null, 5, Boolean.TRUE, "", Boolean.FALSE, null);
MetaDataTable authorizationMatrix = metaDataService.getTable("authorization_matrix");
metaDataService.getColumn(authorizationMatrix, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.TRUE, "", Boolean.FALSE, null);
metaDataService.getColumn(authorizationMatrix, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
metaDataService.getColumn(authorizationMatrix, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
metaDataService.getColumn(authorizationMatrix, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
metaDataService.getColumn(authorizationMatrix, "user_id", "user_id", "TEXT", null, 5, Boolean.TRUE, "User", Boolean.FALSE, null, "user_name");
metaDataService.getColumn(authorizationMatrix, "role_id", "role_id", "TEXT", null, 6, Boolean.TRUE, "Role", Boolean.FALSE, null, "name");
metaDataService.getColumn(tokenTable, "profile_id", "profile_id", "TEXT", null, 9, Boolean.TRUE, "Profile", Boolean.FALSE, null, "user_name");
MetaDataTable permissionTable = metaDataService.getTable("permission");
metaDataService.getColumn(permissionTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.TRUE, "", Boolean.FALSE, null);
metaDataService.getColumn(permissionTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
metaDataService.getColumn(permissionTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
metaDataService.getColumn(permissionTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
metaDataService.getColumn(permissionTable, "name", "name", "TEXT", null, 5, Boolean.TRUE, "", Boolean.FALSE, null);
MetaDataTable AssignmentTable = metaDataService.getTable("assignment");
metaDataService.getColumn(AssignmentTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.TRUE, "", Boolean.FALSE, null);
metaDataService.getColumn(AssignmentTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
metaDataService.getColumn(AssignmentTable, "last_modified_date", "modified", "TIMESTAMP", null, 3, Boolean.FALSE, "", Boolean.FALSE, null);
metaDataService.getColumn(AssignmentTable, "version", "version", "LONG", null, 4, Boolean.FALSE, "", Boolean.FALSE, null);
metaDataService.getColumn(AssignmentTable, "profile_id", "profile_id", "TEXT", null, 5, Boolean.TRUE, "Profile", Boolean.FALSE, null, "user_name");
metaDataService.getColumn(AssignmentTable, "permission_id", "permission_id", "TEXT", null, 6, Boolean.TRUE, "Permission", Boolean.FALSE, null, "name");
MetaDataTable moduleDataTable = metaDataService.getTable("module_data");
metaDataService.getColumn(moduleDataTable, "id", "identifier", "TEXT", "PRIMARY KEY", 1, Boolean.TRUE, "", Boolean.FALSE, null);
metaDataService.getColumn(moduleDataTable, "created_date", "created", "TIMESTAMP", null, 2, Boolean.FALSE, "", Boolean.FALSE, null);
@@ -7,28 +7,27 @@ 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 {
public class Assignment extends AbstractEntity {
@ManyToOne
@JoinColumn(name = "user_id")
@JoinColumn(name = "profile_id")
@NotNull
private User user;
private Profile profile;
@ManyToOne
@JoinColumn(name = "role_id")
@JoinColumn(name = "permission_id")
@NotNull
private Role role;
private Permission permission;
@Override
public String toString() {
final StringBuffer sb = new StringBuffer("AuthorizationMatrix{");
sb.append("user=").append(user.getUserName());
sb.append(", role=").append(role.getName());
final StringBuffer sb = new StringBuffer("Assignment{");
sb.append("profile=").append(profile.getUserName());
sb.append(", permission=").append(permission.getName());
sb.append('}');
return sb.toString();
}
@@ -1,7 +1,5 @@
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;
@@ -13,18 +11,19 @@ import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import javax.annotation.Nullable;
import java.util.List;
@Slf4j
@Getter
@Setter
@ToString
@Entity
public class Role extends AbstractEntity {
public class Permission extends AbstractEntity {
@NotEmpty
private String name;
@OneToMany(fetch = FetchType.EAGER, mappedBy = "role")
@OneToMany(fetch = FetchType.EAGER, mappedBy = "permission")
@Nullable
private List<AuthorizationMatrix> matrix;
private List<Assignment> assignments;
}
@@ -1,12 +1,7 @@
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.persistence.*;
import jakarta.validation.constraints.NotEmpty;
import lombok.Getter;
import lombok.Setter;
@@ -23,7 +18,7 @@ import java.util.List;
@ToString
@Entity
@Table(indexes = @Index(columnList = "userName"), uniqueConstraints = @UniqueConstraint(columnNames = {"userName"}))
public class User extends AbstractEntity {
public class Profile extends AbstractEntity {
private String firstName;
@@ -38,25 +33,25 @@ public class User extends AbstractEntity {
private boolean enabled;
@OneToMany(fetch = FetchType.EAGER, mappedBy = "user")
@OneToMany(fetch = FetchType.EAGER, mappedBy = "profile")
@Nullable
private List<AuthorizationMatrix> matrix = new LinkedList<>();
private List<Assignment> assignments = new LinkedList<>();
@OneToMany(fetch = FetchType.EAGER, mappedBy = "user")
@OneToMany(fetch = FetchType.EAGER, mappedBy = "profile")
@Nullable
private List<Token> tokens = new LinkedList<>();
public String getFullName() {
StringBuilder fullNamBuilder = new StringBuilder();
StringBuilder fullNameBuilder = new StringBuilder();
if (firstName != null) {
fullNamBuilder.append(firstName);
fullNameBuilder.append(firstName);
}
if (lastName != null) {
if (fullNamBuilder.length() > 0) {
fullNamBuilder.append(" ");
if (!fullNameBuilder.isEmpty()) {
fullNameBuilder.append(" ");
}
fullNamBuilder.append(lastName);
fullNameBuilder.append(lastName);
}
return fullNamBuilder.toString();
return fullNameBuilder.toString();
}
}
@@ -31,7 +31,7 @@ public class Token extends AbstractEntity {
private boolean enabled;
@ManyToOne
@JoinColumn(name="user_id")
@JoinColumn(name="profile_id")
@NotNull
private User user;
private Profile profile;
}
@@ -0,0 +1,13 @@
package de.thpeetz.kontor.admin.repository;
import de.thpeetz.kontor.admin.data.*;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface AssignmentRepository extends JpaRepository<Assignment, String> {
List<Assignment> findByProfile(Profile profile);
List<Assignment> findByPermission(Permission permission);
}
@@ -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);
}
@@ -0,0 +1,19 @@
package de.thpeetz.kontor.admin.repository;
import de.thpeetz.kontor.admin.data.Permission;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
public interface PermissionRepository extends JpaRepository<Permission, String> {
@Query("select p from Permission p " +
"where lower(p.name) like lower(concat('%', :searchTerm, '%')) ")
List<Permission> search(@Param("searchTerm") String searchTerm);
@Query("select p from Permission p " +
"where lower(p.name) like lower(:name) ")
Permission findByName(@Param("name") String name);
}
@@ -0,0 +1,18 @@
package de.thpeetz.kontor.admin.repository;
import de.thpeetz.kontor.admin.data.Profile;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
import java.util.UUID;
public interface ProfileRepository extends JpaRepository<Profile, String> {
@Query("select p from Profile p " +
"where lower(p.lastName) like lower(concat('%', :searchTerm, '%')) ")
List<Profile> search(@Param("searchTerm") String searchTerm);
Profile findByUserName(String userName);
}
@@ -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);
}
@@ -3,108 +3,105 @@ package de.thpeetz.kontor.admin.services;
import java.util.Collection;
import java.util.List;
import de.thpeetz.kontor.admin.data.*;
import de.thpeetz.kontor.admin.repository.*;
import org.springframework.stereotype.Service;
import de.thpeetz.kontor.admin.data.AuthorizationMatrix;
import de.thpeetz.kontor.admin.repository.AuthorizationMatrixRepository;
import de.thpeetz.kontor.admin.data.Role;
import de.thpeetz.kontor.admin.repository.RoleRepository;
import de.thpeetz.kontor.admin.data.User;
import de.thpeetz.kontor.admin.repository.UserRepository;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class AdminService {
private final UserRepository userRepository;
private final RoleRepository roleRepository;
private final AuthorizationMatrixRepository authorizationMatrixRepository;
public AdminService(UserRepository userRepository, RoleRepository roleRepository,
AuthorizationMatrixRepository authorizationMatrixRepository) {
this.userRepository = userRepository;
this.roleRepository = roleRepository;
this.authorizationMatrixRepository = authorizationMatrixRepository;
private final ProfileRepository profileRepository;
private final PermissionRepository permissionRepository;
private final AssignmentRepository assignmentRepository;
public AdminService(ProfileRepository profileRepository,
PermissionRepository permissionRepository,
AssignmentRepository assignmentRepository) {
this.profileRepository = profileRepository;
this.permissionRepository = permissionRepository;
this.assignmentRepository = assignmentRepository;
}
public List<User> findAllUsers() {
return userRepository.findAll();
public List<Profile> findAllProfiles() { return profileRepository.findAll(); }
public Profile getProfile(String userName) {
log.debug("get Profile {}", userName);
return profileRepository.findByUserName(userName);
}
public List<Role> findAllRoles() {
return roleRepository.findAll();
}
public List<Permission> findAllPermissions() { return permissionRepository.findAll(); }
public Collection<Role> findAllRoles(String stringFilter) {
public Collection<Permission> findAllPermissions(String stringFilter) {
if (stringFilter == null || stringFilter.isEmpty()) {
return roleRepository.findAll();
return permissionRepository.findAll();
} else {
return roleRepository.search(stringFilter);
return permissionRepository.search(stringFilter);
}
}
public Role addRole(String roleName) {
Role role = roleRepository.findByName(roleName);
if (role == null) {
log.info("Role {} was not found, will create it.", roleName);
role = new Role();
role.setName(roleName);
roleRepository.save(role);
public Permission addPermission(String permissionName) {
Permission permission = permissionRepository.findByName(permissionName);
if (permission == null) {
log.info("Permission {} was not found, will create it.", permissionName);
permission = new Permission();
permission.setName(permissionName);
permissionRepository.save(permission);
}
return role;
return permission;
}
public void saveRole(Role role) {
if (role == null) {
log.warn("Role is null. Can't save it.");
public void savePermission(Permission permission) {
if (permission == null) {
log.warn("Permission is null. Can't save it.");
}
log.info("saveRole: role={}", role);
roleRepository.save(role);
log.info("savePermission: permission={}", permission);
permissionRepository.save(permission);
}
public void deleteRole(Role role) {
if (role == null) {
log.warn("Role is null. Can't delete it.");
public void deletePermission(Permission permission) {
if (permission == null) {
log.warn("Permission is null. Can't delete it.");
return;
}
log.info("deleteRole: role={}", role);
roleRepository.delete(role);
log.info("deletePermission: permission={}", permission);
permissionRepository.delete(permission);
}
public List<AuthorizationMatrix> findAllAuthorizationMatrices() {
return authorizationMatrixRepository.findAll();
public List<Assignment> findAllAssignments() {
return assignmentRepository.findAll();
}
public void saveAuthorizationMatrix(AuthorizationMatrix authorizationMatrix) {
if (authorizationMatrix == null) {
log.warn("AuthorizationMatrix is null. Can't save it.");
public void saveAssignment(Assignment assignment) {
if (assignment == null) {
log.warn("Assignment is null. Can't save it.");
return;
}
log.info("saveAuthorizationMatrix: authorizationMatrix={}", authorizationMatrix);
authorizationMatrixRepository.save(authorizationMatrix);
log.info("saveAssignment: assignment={}", assignment);
assignmentRepository.save(assignment);
}
public void deleteAuthorizationMatrix(AuthorizationMatrix authorizationMatrix) {
if (authorizationMatrix == null) {
log.warn("AuthorizationMatrix is null. Can't delete it.");
public void deleteAssignment(Assignment assignment) {
if (assignment == null) {
log.warn("Assignment is null. Can't delete it.");
return;
}
log.info("deleteAuthorizationMatrix: authorizationMatrix={}", authorizationMatrix);
authorizationMatrixRepository.delete(authorizationMatrix);
log.info("deleteAssignment: assignment={}", assignment);
assignmentRepository.delete(assignment);
}
public String getUserFullName(String userName) {
log.debug("get Fullname für user {}", userName);
User user = userRepository.findByUserName(userName);
if (user == null) {
public String getProfileFullName(String userName) {
log.debug("get Fullname für Profile {}", userName);
Profile profile = profileRepository.findByUserName(userName);
if (profile == null) {
log.info("keinen Eintrag für {} gefunden", userName);
return userName;
} else {
log.info("Voller Name des User {}: {}", userName, user.getFullName());
return user.getFullName();
log.info("Voller Name des Profile {}: {}", userName, profile.getFullName());
return profile.getFullName();
}
}
public User getUser(String userName) {
log.debug("get User {}", userName);
return userRepository.findByUserName(userName);
}
}
@@ -1,9 +1,7 @@
package de.thpeetz.kontor.admin.services;
import de.thpeetz.kontor.admin.data.*;
import de.thpeetz.kontor.admin.repository.AuthorizationMatrixRepository;
import de.thpeetz.kontor.admin.repository.RoleRepository;
import de.thpeetz.kontor.admin.repository.UserRepository;
import de.thpeetz.kontor.admin.repository.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
@@ -26,83 +24,86 @@ public class KontorUserDetailsService implements UserDetailsService {
private static SecureRandom random = new SecureRandom();
@Autowired
private UserRepository userRepository;
private ProfileRepository profileRepository;
@Autowired
private RoleRepository roleRepository;
private PermissionRepository permissionRepository;
@Autowired
private AuthorizationMatrixRepository authorizationMatrixRepository;
private AssignmentRepository assignmentRepository;
public Collection<User> findAllUsers(String stringFilter) {
public Collection<Profile> findAllProfiles(String stringFilter) {
if (stringFilter == null || stringFilter.isEmpty()) {
return userRepository.findAll();
return profileRepository.findAll();
} else {
return userRepository.search(stringFilter);
return profileRepository.search(stringFilter);
}
}
public void saveUser(User user) {
if (user == null) {
log.warn("User is null. Can't save it.");
public void saveProfile(Profile profile) {
if (profile == null) {
log.warn("Profile is null. Can't save it.");
return;
}
log.info("saveUser: user={}", user);
userRepository.save(user);
log.info("saveProfile: profile={}", profile);
profileRepository.save(profile);
}
public void saveUser(User user, List<Role> roles) {
if (user == null) {
log.warn("User is null. Can't save it.");
public void saveProfile(Profile profile, List<Permission> permissions) {
if (profile == null) {
log.warn("Profile is null. Can't save it.");
return;
}
log.info("First save user: {}", user);
user = userRepository.save(user);
List<Role> copy = roles.stream().collect(Collectors.toList());
List<AuthorizationMatrix> permissions = user.getMatrix();
permissions.forEach(matrix -> {
if (roles.contains(matrix.getRole())) {
log.info("Role {} already assigned", matrix.getRole());
copy.remove(matrix.getRole());
log.info("First save Profile: {}", profile);
profile = profileRepository.save(profile);
List<Permission> copy = permissions.stream().collect(Collectors.toList());
List<Assignment> assignments = profile.getAssignments();
assignments.forEach(assignment -> {
if (permissions.contains(assignment.getPermission())) {
log.info("Permission {} already assigned", assignment.getPermission());
copy.remove(assignment.getPermission());
} else {
log.info("Role {} has to be removed", matrix.getRole());
authorizationMatrixRepository.delete(matrix);
log.info("Permission {} has to be removed", assignment.getPermission());
assignmentRepository.delete(assignment);
}
});
log.info("remaining roles: {}", copy);
for (Role role : copy) {
AuthorizationMatrix matrix = new AuthorizationMatrix();
matrix.setUser(user);
matrix.setRole(role);
authorizationMatrixRepository.save(matrix);
for (Permission permission : copy) {
Assignment assignment = new Assignment();
assignment.setProfile(profile);
assignment.setPermission(permission);
assignmentRepository.save(assignment);
}
}
public void deleteUser(User user) {
if (user == null) {
log.warn("User is null. Can't delete it.");
public void deleteProfile(Profile profile) {
if (profile == null) {
log.warn("Profile is null. Can't delete it.");
return;
}
log.info("deleteUser: user={}", user);
userRepository.delete(user);
log.info("deleteProfile: profile={}", profile);
profileRepository.delete(profile);
}
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
log.info("loadUserByUsername: userName={}", userName);
User user = userRepository.findByUserName(userName);
if (user == null) {
Profile profile = profileRepository.findByUserName(userName);
if (profile == null) {
log.info("User not found");
return null;
}
Collection<? extends GrantedAuthority> authorities = getAuthorities(user);
log.info("User {} hat Rolen: {}", userName, authorities);
return new org.springframework.security.core.userdetails.User(user.getUserName(), user.getPassword(),
Collection<? extends GrantedAuthority> authorities = getAuthorities(profile);
log.info("Profile {} hat Permissions: {}", userName, authorities);
return new org.springframework.security.core.userdetails.User(profile.getUserName(), profile.getPassword(),
authorities);
}
private Collection<? extends GrantedAuthority> getAuthorities(User user) {
return authorizationMatrixRepository.findByUser(user).stream()
.map(matrix -> matrix.getRole().getName())
private Collection<? extends GrantedAuthority> getAuthorities(Profile profile) {
return assignmentRepository.findByProfile(profile).stream()
.map(assignment -> assignment.getPermission().getName())
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
}
@@ -122,7 +123,7 @@ public class KontorUserDetailsService implements UserDetailsService {
log.info("removeRememberedUser: id={}", id);
}
public List<Role> findAllRoles() {
return roleRepository.findAll();
public List<Permission> findAllPermissions() {
return permissionRepository.findAll();
}
}
@@ -29,7 +29,7 @@ public class AdminLayout extends AppLayout {
private HorizontalLayout getSecondaryNavigation() {
HorizontalLayout navigation = new HorizontalLayout();
navigation.addClassNames(LumoUtility.JustifyContent.CENTER, LumoUtility.Gap.SMALL, LumoUtility.Height.MEDIUM);
navigation.add(AdminConstants.getUserNavigation(), AdminConstants.getRoleNavigation(),
navigation.add(AdminConstants.getProfileNavigation(), AdminConstants.getPermissionNavigation(),
AdminConstants.getAuthorizationNavigation());
return navigation;
}
@@ -13,32 +13,32 @@ 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 de.thpeetz.kontor.admin.data.Assignment;
import de.thpeetz.kontor.admin.data.Permission;
import de.thpeetz.kontor.admin.data.Profile;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class AuthorizationForm extends FormLayout {
public class AssignmentForm extends FormLayout {
ComboBox<User> user = new ComboBox<>("User");
ComboBox<Role> role = new ComboBox<>("Role");
ComboBox<Profile> profile = new ComboBox<>("Proile");
ComboBox<Permission> permission = new ComboBox<>("Permission");
Button save = new Button("Save");
Button delete = new Button("Delete");
Button close = new Button("Cancel");
Binder<AuthorizationMatrix> binder = new BeanValidationBinder<>(AuthorizationMatrix.class);
Binder<Assignment> binder = new BeanValidationBinder<>(Assignment.class);
public AuthorizationForm(List<User> users, List<Role> roles) {
addClassName("authorizationmatrix-form");
public AssignmentForm(List<Profile> profiles, List<Permission> permissions) {
addClassName("assignment-form");
binder.bindInstanceFields(this);
user.setItems(users);
user.setItemLabelGenerator(User::getUserName);
role.setItems(roles);
role.setItemLabelGenerator(Role::getName);
add(user, role, createButtonsLayout());
profile.setItems(profiles);
profile.setItemLabelGenerator(Profile::getUserName);
permission.setItems(permissions);
permission.setItemLabelGenerator(Permission::getName);
add(profile, permission, createButtonsLayout());
}
private HorizontalLayout createButtonsLayout() {
@@ -63,37 +63,37 @@ public class AuthorizationForm extends FormLayout {
}
}
public void setAuthorizationMatrix(AuthorizationMatrix authorizationMatrix) {
binder.setBean(authorizationMatrix);
public void setAssignment(Assignment assignment) {
binder.setBean(assignment);
}
public abstract static class AuthorizationFormEvent extends ComponentEvent<AuthorizationForm> {
private AuthorizationMatrix authorizationMatrix;
public abstract static class AssignmentFormEvent extends ComponentEvent<AssignmentForm> {
private Assignment assignment;
protected AuthorizationFormEvent(AuthorizationForm source, AuthorizationMatrix authorizationMatrix) {
protected AssignmentFormEvent(AssignmentForm source, Assignment assignment) {
super(source, false);
this.authorizationMatrix = authorizationMatrix;
this.assignment = assignment;
}
public AuthorizationMatrix getAuthorizationMatrix() {
return authorizationMatrix;
public Assignment getAssignment() {
return assignment;
}
}
public static class SaveEvent extends AuthorizationFormEvent {
SaveEvent(AuthorizationForm source, AuthorizationMatrix authorizationMatrix) {
super(source, authorizationMatrix);
public static class SaveEvent extends AssignmentFormEvent {
SaveEvent(AssignmentForm source, Assignment assignment) {
super(source, assignment);
}
}
public static class DeleteEvent extends AuthorizationFormEvent {
DeleteEvent(AuthorizationForm source, AuthorizationMatrix authorizationMatrix) {
super(source, authorizationMatrix);
public static class DeleteEvent extends AssignmentFormEvent {
DeleteEvent(AssignmentForm source, Assignment assignment) {
super(source, assignment);
}
}
public static class CloseEvent extends AuthorizationFormEvent {
CloseEvent(AuthorizationForm source) {
public static class CloseEvent extends AssignmentFormEvent {
CloseEvent(AssignmentForm source) {
super(source, null);
}
}
@@ -1,5 +1,6 @@
package de.thpeetz.kontor.admin.views;
import de.thpeetz.kontor.admin.data.Assignment;
import org.springframework.context.annotation.Scope;
import com.vaadin.flow.component.Component;
@@ -13,7 +14,6 @@ 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;
@@ -23,17 +23,17 @@ import lombok.extern.slf4j.Slf4j;
@SpringComponent
@Scope("prototype")
@RolesAllowed("ROLE_ADMIN")
@Route(value = AdminConstants.AUTHORIZATION_ROUTE, layout = MainLayout.class)
@Route(value = AdminConstants.ASSIGNMENT_ROUTE, layout = MainLayout.class)
@PageTitle("Authorization | Admin | Kontor")
public class AuthorizationView extends VerticalLayout {
public class AssignmentView extends VerticalLayout {
Grid<AuthorizationMatrix> grid = new Grid<>(AuthorizationMatrix.class);
AuthorizationForm form;
Grid<Assignment> grid = new Grid<>(Assignment.class);
AssignmentForm form;
AdminService service;
public AuthorizationView(AdminService service) {
public AssignmentView(AdminService service) {
this.service = service;
addClassName("authoriaztionmatrix-view");
addClassName("assignment-view");
setSizeFull();
configureGrid();
configureForm();
@@ -43,30 +43,30 @@ public class AuthorizationView extends VerticalLayout {
}
private void configureGrid() {
grid.addClassName("authorizationmatrix-grid");
grid.addClassName("assignment-grid");
grid.setSizeFull();
grid.setColumns("user.userName", "role.name");
grid.setColumns("profile.userName", "permission.name");
grid.getColumns().forEach(col -> col.setAutoWidth(true));
grid.asSingleSelect().addValueChangeListener(event -> editAuthorizationMatrix(event.getValue()));
grid.asSingleSelect().addValueChangeListener(event -> editAssignment(event.getValue()));
}
private void configureForm() {
form = new AuthorizationForm(service.findAllUsers(), service.findAllRoles());
form = new AssignmentForm(service.findAllProfiles(), service.findAllPermissions());
form.setWidth("25em");
form.addSaveListener(this::saveAuthorizationMatrix);
form.addDeleteListener(this::deleteAuthorizationMatrix);
form.addSaveListener(this::saveAssignment);
form.addDeleteListener(this::deleteAssignment);
form.addCloseListener(e -> closeEditor());
}
private void saveAuthorizationMatrix(AuthorizationForm.SaveEvent event) {
AuthorizationMatrix authorizationMatrix = event.getAuthorizationMatrix();
service.saveAuthorizationMatrix(authorizationMatrix);
private void saveAssignment(AssignmentForm.SaveEvent event) {
Assignment assignment = event.getAssignment();
service.saveAssignment(assignment);
updateList();
closeEditor();
}
private void deleteAuthorizationMatrix(AuthorizationForm.DeleteEvent event) {
service.deleteAuthorizationMatrix(event.getAuthorizationMatrix());
private void deleteAssignment(AssignmentForm.DeleteEvent event) {
service.deleteAssignment(event.getAssignment());
updateList();
closeEditor();
}
@@ -81,34 +81,34 @@ public class AuthorizationView extends VerticalLayout {
}
private HorizontalLayout getToolbar() {
Button addAuthorizationMaxtrixButton = new Button("Add permssion", click -> addAuthorizationMatrix());
Button addAuthorizationMaxtrixButton = new Button("Add permission", click -> addAssignment());
HorizontalLayout toolbar = new HorizontalLayout(addAuthorizationMaxtrixButton);
toolbar.addClassName("toolbar");
return toolbar;
}
public void editAuthorizationMatrix(AuthorizationMatrix authorizationMatrix) {
if (authorizationMatrix == null) {
public void editAssignment(Assignment assignment) {
if (assignment == null) {
closeEditor();
} else {
form.setAuthorizationMatrix(authorizationMatrix);
form.setAssignment(assignment);
form.setVisible(true);
addClassName("editing");
}
}
public void closeEditor() {
form.setAuthorizationMatrix(null);
form.setAssignment(null);
form.setVisible(false);
removeClassName("editing");
}
private void addAuthorizationMatrix() {
private void addAssignment() {
grid.asSingleSelect().clear();
editAuthorizationMatrix(new AuthorizationMatrix());
editAssignment(new Assignment());
}
private void updateList() {
grid.setItems(service.findAllAuthorizationMatrices());
grid.setItems(service.findAllAssignments());
}
}
@@ -10,12 +10,11 @@ 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 de.thpeetz.kontor.admin.data.Permission;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class RoleForm extends FormLayout {
public class PermissionForm extends FormLayout {
TextField name = new TextField("Role name");
@@ -23,10 +22,10 @@ public class RoleForm extends FormLayout {
Button delete = new Button("Delete");
Button close = new Button("Cancel");
Binder<Role> binder = new BeanValidationBinder<>(Role.class);
Binder<Permission> binder = new BeanValidationBinder<>(Permission.class);
public RoleForm() {
addClassName("role-form");
public PermissionForm() {
addClassName("permission-form");
binder.bindInstanceFields(this);
add(name, createButtonsLayout());
}
@@ -53,37 +52,37 @@ public class RoleForm extends FormLayout {
}
}
public void setRole(Role role) {
binder.setBean(role);
public void setPermission(Permission permission) {
binder.setBean(permission);
}
public abstract static class RoleFormEvent extends ComponentEvent<RoleForm> {
private Role role;
public abstract static class PermissionFormEvent extends ComponentEvent<PermissionForm> {
private Permission permission;
protected RoleFormEvent(RoleForm source, Role role) {
protected PermissionFormEvent(PermissionForm source, Permission permission) {
super(source, false);
this.role = role;
this.permission = permission;
}
public Role getRole() {
return role;
public Permission getPermission() {
return permission;
}
}
public static class SaveEvent extends RoleFormEvent {
SaveEvent(RoleForm source, Role role) {
super(source, role);
public static class SaveEvent extends PermissionFormEvent {
SaveEvent(PermissionForm source, Permission permission) {
super(source, permission);
}
}
public static class DeleteEvent extends RoleFormEvent {
DeleteEvent(RoleForm source, Role role) {
super(source, role);
public static class DeleteEvent extends PermissionFormEvent {
DeleteEvent(PermissionForm source, Permission permission) {
super(source, permission);
}
}
public static class CloseEvent extends RoleFormEvent {
CloseEvent(RoleForm source) {
public static class CloseEvent extends PermissionFormEvent {
CloseEvent(PermissionForm source) {
super(source, null);
}
}
@@ -1,5 +1,6 @@
package de.thpeetz.kontor.admin.views;
import de.thpeetz.kontor.admin.data.Permission;
import org.springframework.context.annotation.Scope;
import com.vaadin.flow.component.Component;
@@ -14,7 +15,6 @@ 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;
@@ -24,17 +24,18 @@ import lombok.extern.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);
@Route(value = AdminConstants.PERMISSION_ROUTE, layout = MainLayout.class)
@PageTitle("Permissions | Admin | Kontor")
public class PermissionView extends VerticalLayout {
Grid<Permission> grid = new Grid<>(Permission.class);
TextField filterText = new TextField();
RoleForm form;
PermissionForm form;
AdminService service;
public RoleView(AdminService service) {
public PermissionView(AdminService service) {
this.service = service;
addClassName("user-view");
addClassName("permission-view");
setSizeFull();
configureGrid();
configureForm();
@@ -44,29 +45,29 @@ public class RoleView extends VerticalLayout {
}
private void configureGrid() {
grid.addClassName("user-grid");
grid.addClassName("permission-grid");
grid.setSizeFull();
grid.setColumns("name");
grid.getColumns().forEach(col -> col.setAutoWidth(true));
grid.asSingleSelect().addValueChangeListener(event -> editRole(event.getValue()));
grid.asSingleSelect().addValueChangeListener(event -> editPermission(event.getValue()));
}
private void configureForm() {
form = new RoleForm();
form = new PermissionForm();
form.setWidth("25em");
form.addSaveListener(this::saveRole);
form.addDeleteListener(this::deleteRole);
form.addSaveListener(this::savePermission);
form.addDeleteListener(this::deletePermission);
form.addCloseListener(e -> closeEditor());
}
private void saveRole(RoleForm.SaveEvent event) {
service.saveRole(event.getRole());
private void savePermission(PermissionForm.SaveEvent event) {
service.savePermission(event.getPermission());
updateList();
closeEditor();
}
private void deleteRole(RoleForm.DeleteEvent event) {
service.deleteRole(event.getRole());
private void deletePermission(PermissionForm.DeleteEvent event) {
service.deletePermission(event.getPermission());
updateList();
closeEditor();
}
@@ -85,34 +86,34 @@ public class RoleView extends VerticalLayout {
filterText.setClearButtonVisible(true);
filterText.setValueChangeMode(ValueChangeMode.LAZY);
filterText.addValueChangeListener(e -> updateList());
Button addUserButton = new Button("Add user", click -> addUser());
Button addUserButton = new Button("Add user", click -> addPermission());
HorizontalLayout toolbar = new HorizontalLayout(filterText, addUserButton);
toolbar.addClassName("toolbar");
return toolbar;
}
public void editRole(Role role) {
if (role == null) {
public void editPermission(Permission permission) {
if (permission == null) {
closeEditor();
} else {
form.setRole(role);
form.setPermission(permission);
form.setVisible(true);
addClassName("editing");
}
}
public void closeEditor() {
form.setRole(null);
form.setPermission(null);
form.setVisible(false);
removeClassName("editing");
}
private void addUser() {
private void addPermission() {
grid.asSingleSelect().clear();
editRole(new Role());
editPermission(new Permission());
}
private void updateList() {
grid.setItems(service.findAllRoles(filterText.getValue()));
grid.setItems(service.findAllPermissions(filterText.getValue()));
}
}
@@ -0,0 +1,143 @@
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.Permission;
import de.thpeetz.kontor.admin.data.Profile;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
@Slf4j
public class ProfileForm 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<Permission> permissionList = new CheckboxGroup<>("Permissions");
Button save = new Button("Save");
Button delete = new Button("Delete");
Button close = new Button("Cancel");
Binder<Profile> binder = new BeanValidationBinder<>(Profile.class);
public ProfileForm() {
addClassName("profile-form");
binder.bindInstanceFields(this);
add(userName, password, email, firstName, lastName, enabled, configurePermissionsGroup(), createButtonsLayout());
}
private CheckboxGroup<Permission> configurePermissionsGroup() {
permissionList.addThemeVariants(CheckboxGroupVariant.LUMO_VERTICAL);
permissionList.setItemLabelGenerator(Permission::getName);
permissionList.addValueChangeListener(event -> {
log.debug("permissions changed: {}", event);
});
return permissionList;
}
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 ProfileForm.DeleteEvent(this, binder.getBean())));
close.addClickListener(event -> fireEvent(new ProfileForm.CloseEvent(this)));
binder.addStatusChangeListener(e -> save.setEnabled(binder.isValid()));
return new HorizontalLayout(save, delete, close);
}
private void validateAndSave() {
if (binder.isValid()) {
fireEvent(new ProfileForm.SaveEvent(this, binder.getBean()));
}
}
public void setProfile(Profile profile) {
binder.setBean(profile);
//log.debug("UserForm.setUser: {}", user);
if (profile != null) {
this.originalPassword = profile.getPassword();
} else {
this.originalPassword = null;
}
}
public void setPermissions(List<Permission> permissions, Profile profile) {
permissionList.setItems(permissions);
profile.getAssignments().stream().forEach(assignment -> {
permissionList.select(assignment.getPermission());
});
}
public boolean hasPasswordChanged(Profile profile) {
return !originalPassword.equals(profile.getPassword());
}
public abstract static class ProfileFormEvent extends ComponentEvent<ProfileForm> {
private Profile profile;
protected ProfileFormEvent(ProfileForm source, Profile profile) {
super(source, false);
this.profile = profile;
}
public Profile getProfile() {
return profile;
}
}
public static class SaveEvent extends ProfileForm.ProfileFormEvent {
SaveEvent(ProfileForm source, Profile profile) {
super(source, profile);
}
}
public static class DeleteEvent extends ProfileForm.ProfileFormEvent {
DeleteEvent(ProfileForm source, Profile profile) {
super(source, profile);
}
}
public static class CloseEvent extends ProfileForm.ProfileFormEvent {
CloseEvent(ProfileForm source) {
super(source, null);
}
}
public void addDeleteListener(ComponentEventListener<ProfileForm.DeleteEvent> listener) {
addListener(ProfileForm.DeleteEvent.class, listener);
}
public void addSaveListener(ComponentEventListener<ProfileForm.SaveEvent> listener) {
addListener(ProfileForm.SaveEvent.class, listener);
}
public void addCloseListener(ComponentEventListener<ProfileForm.CloseEvent> listener) {
addListener(ProfileForm.CloseEvent.class, listener);
}
}
@@ -10,8 +10,8 @@ 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.data.Permission;
import de.thpeetz.kontor.admin.data.Profile;
import de.thpeetz.kontor.admin.services.KontorUserDetailsService;
import de.thpeetz.kontor.common.views.MainLayout;
import jakarta.annotation.security.RolesAllowed;
@@ -27,21 +27,21 @@ import java.util.stream.Collectors;
@SpringComponent
@Scope("prototype")
@RolesAllowed("ROLE_ADMIN")
@Route(value = "admin/user", layout = MainLayout.class)
@PageTitle("User | Admin | Kontor")
public class UserView extends VerticalLayout {
@Route(value = "admin/profile", layout = MainLayout.class)
@PageTitle("Profile | Admin | Kontor")
public class ProfileView extends VerticalLayout {
Grid<User> grid = new Grid<>(User.class);
Grid<Profile> grid = new Grid<>(Profile.class);
TextField filterText = new TextField();
UserForm form;
ProfileForm form;
KontorUserDetailsService service;
@Autowired
PasswordEncoder passwordEncoder;
public UserView(KontorUserDetailsService service) {
public ProfileView(KontorUserDetailsService service) {
this.service = service;
addClassName("user-view");
addClassName("profile-view");
setSizeFull();
configureGrid();
configureForm();
@@ -51,38 +51,38 @@ public class UserView extends VerticalLayout {
}
private void configureGrid() {
grid.addClassName("user-grid");
grid.addClassName("profile-grid");
grid.setSizeFull();
grid.setColumns("userName", "email", "firstName", "lastName", "enabled");
grid.getColumns().forEach(col -> col.setAutoWidth(true));
grid.asSingleSelect().addValueChangeListener(event -> editUser(event.getValue()));
grid.asSingleSelect().addValueChangeListener(event -> editProfile(event.getValue()));
}
private void configureForm() {
form = new UserForm();
form = new ProfileForm();
form.setWidth("25em");
form.setVisible(false);
form.addSaveListener(this::saveUser);
form.addDeleteListener(this::deleteUser);
form.addSaveListener(this::saveProfile);
form.addDeleteListener(this::deleteProfile);
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());
private void saveProfile(ProfileForm.SaveEvent event) {
Profile profile = event.getProfile();
log.debug("ProfileView.saveProfile: {}", profile);
List<Permission> permissions = form.permissionList.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);
if (form.hasPasswordChanged(profile)) {
profile.setPassword(passwordEncoder.encode(profile.getPassword()));
log.debug("password changed for profile {}", profile);
}
service.saveUser(user, permissions);
service.saveProfile(profile, permissions);
updateList();
closeEditor();
}
private void deleteUser(UserForm.DeleteEvent event) {
service.deleteUser(event.getUser());
private void deleteProfile(ProfileForm.DeleteEvent event) {
service.deleteProfile(event.getProfile());
updateList();
closeEditor();
}
@@ -101,35 +101,35 @@ public class UserView extends VerticalLayout {
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);
Button addProfileButton = new Button("Add profile", click -> addProfile());
HorizontalLayout toolbar = new HorizontalLayout(filterText, addProfileButton);
toolbar.addClassName("toolbar");
return toolbar;
}
public void editUser(User user) {
if (user == null) {
public void editProfile(Profile profile) {
if (profile == null) {
closeEditor();
} else {
form.setUser(user);
form.setRoles(service.findAllRoles(), user);
form.setProfile(profile);
form.setPermissions(service.findAllPermissions(), profile);
form.setVisible(true);
addClassName("editing");
}
}
public void closeEditor() {
form.setUser(null);
form.setProfile(null);
form.setVisible(false);
removeClassName("editing");
}
private void addUser() {
private void addProfile() {
grid.asSingleSelect().clear();
editUser(new User());
editProfile(new Profile());
}
private void updateList() {
grid.setItems(service.findAllUsers(filterText.getValue()));
grid.setItems(service.findAllProfiles(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);
}
}
@@ -10,7 +10,7 @@ import com.vaadin.flow.data.binder.BeanValidationBinder;
import com.vaadin.flow.data.binder.Binder;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import de.thpeetz.kontor.admin.data.User;
import de.thpeetz.kontor.admin.data.Profile;
import de.thpeetz.kontor.admin.services.AdminService;
import de.thpeetz.kontor.common.views.MainLayout;
import de.thpeetz.kontor.security.SecurityService;
@@ -32,7 +32,7 @@ public class UserProfileView extends VerticalLayout {
Button save = new Button("Save");
Button close = new Button("Cancel");
Binder<User> binder = new BeanValidationBinder<>(User.class);
Binder<Profile> binder = new BeanValidationBinder<>(Profile.class);
public UserProfileView(AdminService adminService, SecurityService securityService) {
this.adminService = adminService;
@@ -42,7 +42,7 @@ public class UserProfileView extends VerticalLayout {
add(firstName, lastName, createButtonsLayout());
securityService.getAuthenticatedUser().ifPresent(user -> {
log.info("UserProfileView: {}", user.getUsername());
binder.setBean(adminService.getUser(user.getUsername()));
binder.setBean(adminService.getProfile(user.getUsername()));
});
}
@@ -32,7 +32,7 @@ public class AvatarMenuBar extends Div {
log.info("AdminService: {}", adminService);
if (user != null) {
String userName = user.getUsername();
String fullName = adminService.getUserFullName(userName);
String fullName = adminService.getProfileFullName(userName);
avatar.setName(fullName);
}
});
@@ -23,7 +23,7 @@ public class SetupModuleMedia implements ApplicationListener<ContextRefreshedEve
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
adminService.addRole(MediaConstants.MEDIA_ROLE);
adminService.addPermission(MediaConstants.MEDIA_ROLE);
if (alreadySetup) {
log.info("SetupModuleMedia already executed, skipping");
return;