diff --git a/chatto/eclipse-formatter.xml b/chatto/eclipse-formatter.xml index 0f7be6f..d8ab3c9 100644 --- a/chatto/eclipse-formatter.xml +++ b/chatto/eclipse-formatter.xml @@ -308,7 +308,7 @@ - + diff --git a/chatto/src/main/java/org/ros/chatto/controller/RegistrationController.java b/chatto/src/main/java/org/ros/chatto/controller/RegistrationController.java index 3f67c07..a971337 100644 --- a/chatto/src/main/java/org/ros/chatto/controller/RegistrationController.java +++ b/chatto/src/main/java/org/ros/chatto/controller/RegistrationController.java @@ -66,7 +66,7 @@ public class RegistrationController { logger.debug("Captcha text from captcha map = {}", captchaMap.get(userRegistrationDTO.getCaptchaID())); if (userRegistrationDTO.getCaptchaInput().equals(captchaMap.get(userRegistrationDTO.getCaptchaID()))) { logger.info("Registration captcha equal success"); - userService.registerUser(userRegistrationDTO); + userService.createUser(userRegistrationDTO); return "redirect:registration?success"; } else { logger.warn("Registration captcha equal fail"); diff --git a/chatto/src/main/java/org/ros/chatto/model/ApplicationStatus.java b/chatto/src/main/java/org/ros/chatto/model/ApplicationStatus.java deleted file mode 100644 index 4b20eb2..0000000 --- a/chatto/src/main/java/org/ros/chatto/model/ApplicationStatus.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.ros.chatto.model; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Table; - -import lombok.Getter; -import lombok.Setter; - -@Entity -@Getter -@Setter -@Table(name="status") -public class ApplicationStatus { - @Id - private int id; - private String name; - @Column(name="value") - private boolean done; -} diff --git a/chatto/src/main/java/org/ros/chatto/model/ChatMessage.java b/chatto/src/main/java/org/ros/chatto/model/ChatMessage.java index 42b7741..d57ffc6 100644 --- a/chatto/src/main/java/org/ros/chatto/model/ChatMessage.java +++ b/chatto/src/main/java/org/ros/chatto/model/ChatMessage.java @@ -9,6 +9,7 @@ import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; import javax.persistence.OneToOne; import javax.persistence.Table; import javax.persistence.Temporal; @@ -24,15 +25,19 @@ public class ChatMessage { @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "m_id") private Long messageID; - @OneToOne(fetch = FetchType.LAZY) + + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "from_user") private ChatUser fromUser; - @OneToOne(fetch = FetchType.LAZY) + + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "to_user") private ChatUser toUser; + @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "message") private MessageCipher messageCipher; + @Temporal(TemporalType.TIMESTAMP) private Date messageTime; } diff --git a/chatto/src/main/java/org/ros/chatto/model/ChatUser.java b/chatto/src/main/java/org/ros/chatto/model/ChatUser.java index 2d9ee31..28ce85a 100644 --- a/chatto/src/main/java/org/ros/chatto/model/ChatUser.java +++ b/chatto/src/main/java/org/ros/chatto/model/ChatUser.java @@ -1,6 +1,7 @@ package org.ros.chatto.model; import java.util.Date; +import java.util.List; import java.util.Set; import javax.persistence.CascadeType; @@ -22,7 +23,9 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener; import lombok.AllArgsConstructor; import lombok.Data; +import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; +import lombok.ToString; @Entity @Table(name = "users") @@ -35,18 +38,26 @@ import lombok.NoArgsConstructor; public class ChatUser { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) -// @SequenceGenerator(name="user_generator", sequenceName = "user_seq", allocationSize=50) //mysql does not support sequence id generator @Column(name = "user_id") private int userID; + @Column(name = "name") private String userName; + String password; @Temporal(TemporalType.TIMESTAMP) private Date joinDate; -// @ManyToMany(cascade = CascadeType.ALL) -// @JoinTable(name = "users_roles", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id")) - @OneToMany(mappedBy = "user", cascade = CascadeType.ALL) + + @ToString.Exclude + @EqualsAndHashCode.Exclude + @OneToMany(mappedBy = "user", cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.DETACH, + CascadeType.REFRESH }) @JsonBackReference -// private Set userRoles = new HashSet(); private Set userRoles; + + // @ToString.Exclude + // @EqualsAndHashCode.Exclude + // @OneToMany(mappedBy = "fromUser", cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.DETACH, + // CascadeType.REFRESH }) + // private List chatMessages; } diff --git a/chatto/src/main/java/org/ros/chatto/model/Role.java b/chatto/src/main/java/org/ros/chatto/model/Role.java index d18e285..52ac2be 100644 --- a/chatto/src/main/java/org/ros/chatto/model/Role.java +++ b/chatto/src/main/java/org/ros/chatto/model/Role.java @@ -13,6 +13,8 @@ import javax.persistence.Table; import com.fasterxml.jackson.annotation.JsonBackReference; import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; @Entity @@ -22,10 +24,16 @@ public class Role { @Id @Column(name = "role_id") private int roleID; + @Column(name = "role_name") private String name; + private String description; - @OneToMany(mappedBy = "role", cascade = CascadeType.ALL) + + @OneToMany(mappedBy = "role", cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.DETACH, + CascadeType.REFRESH }) @JsonBackReference + @ToString.Exclude + @EqualsAndHashCode.Exclude private Set userRoles = new HashSet<>(); } diff --git a/chatto/src/main/java/org/ros/chatto/model/UserSession.java b/chatto/src/main/java/org/ros/chatto/model/UserSession.java index 7ee073b..ccb4a9a 100644 --- a/chatto/src/main/java/org/ros/chatto/model/UserSession.java +++ b/chatto/src/main/java/org/ros/chatto/model/UserSession.java @@ -2,7 +2,6 @@ package org.ros.chatto.model; import java.time.Instant; -import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; @@ -22,7 +21,7 @@ public class UserSession { @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; - @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) + @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "user_id") private ChatUser user; diff --git a/chatto/src/main/java/org/ros/chatto/model/UserToken.java b/chatto/src/main/java/org/ros/chatto/model/UserToken.java index d307cc1..072df85 100644 --- a/chatto/src/main/java/org/ros/chatto/model/UserToken.java +++ b/chatto/src/main/java/org/ros/chatto/model/UserToken.java @@ -23,7 +23,7 @@ public class UserToken implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "token_id") - private long tokenID; + private int tokenID; private String userName; private String tokenContent; private String role; diff --git a/chatto/src/main/java/org/ros/chatto/repository/UserRepository.java b/chatto/src/main/java/org/ros/chatto/repository/UserRepository.java index 9105ae2..742c635 100644 --- a/chatto/src/main/java/org/ros/chatto/repository/UserRepository.java +++ b/chatto/src/main/java/org/ros/chatto/repository/UserRepository.java @@ -11,6 +11,9 @@ import org.springframework.stereotype.Repository; public interface UserRepository extends JpaRepository{ @Query("select cu from ChatUser cu where cu.userName = ?1") public ChatUser findByUserName(String userName); + + @Query("select cu from ChatUser cu join fetch cu.userRoles where cu.userName = ?1") + public ChatUser findByUserNameWithRole(String userName); @Query("select cu.userName from ChatUser cu where cu.userName != ?1") public List findAllOtherUserNames(String userName); diff --git a/chatto/src/main/java/org/ros/chatto/security/MyUserDetailsService.java b/chatto/src/main/java/org/ros/chatto/security/MyUserDetailsService.java index 0310cea..5be621c 100644 --- a/chatto/src/main/java/org/ros/chatto/security/MyUserDetailsService.java +++ b/chatto/src/main/java/org/ros/chatto/security/MyUserDetailsService.java @@ -1,6 +1,6 @@ package org.ros.chatto.security; -import java.util.List; +import java.util.Set; import org.ros.chatto.model.ChatUser; import org.ros.chatto.model.UserRole; @@ -18,23 +18,26 @@ import lombok.extern.slf4j.Slf4j; @Slf4j public class MyUserDetailsService implements UserDetailsService { - @Autowired private UserService userService; @Override - public UserDetails loadUserByUsername(String username) { + public UserDetails loadUserByUsername(final String username) { log.trace("User Details - loading with username: {}", username); - List userRoles = userService.getUserWithRole(username); - if (userRoles.size() == 0) { + ChatUser user = userService.getUserWithRole(username); + + if (user == null) { log.warn("Request for unknown user {}", username); throw new UsernameNotFoundException(username); } - ChatUser user = userRoles.get(0).getUser(); - return User.withUsername(user.getUserName()).password(user.getPassword()) - .roles(userRoles.stream().map(userRole -> { - log.trace("role = " + userRole.getRole().getName()); - return userRole.getRole().getName(); - }).toArray(size -> new String[size])).build(); + + Set userRoles = user.getUserRoles(); + + return User.withUsername(user.getUserName()) + .password(user.getPassword()) + .roles(userRoles.stream() + .map(ur -> ur.getRole().getName()) + .toArray(size -> new String[size])) + .build(); } -} \ No newline at end of file +} diff --git a/chatto/src/main/java/org/ros/chatto/service/ChatServiceImpl.java b/chatto/src/main/java/org/ros/chatto/service/ChatServiceImpl.java index 78dfe29..f2a5b9c 100644 --- a/chatto/src/main/java/org/ros/chatto/service/ChatServiceImpl.java +++ b/chatto/src/main/java/org/ros/chatto/service/ChatServiceImpl.java @@ -29,10 +29,11 @@ public class ChatServiceImpl implements ChatService { private final ChatMessageRepository chatMessageRepository; private final MyConversionService myConversionService; - public ChatMessageDTO createMessage(final String fromUserName, final String toUserName, - final MessageCipherDTO messageCipherDTO) { + public ChatMessageDTO createMessage(final String fromUserName, + final String toUserName, final MessageCipherDTO messageCipherDTO) { - MessageCipher messageCipher = myConversionService.convertToMessageCipher(messageCipherDTO); + MessageCipher messageCipher = myConversionService + .convertToMessageCipher(messageCipherDTO); final ChatUser fromUser = userRepository.findByUserName(fromUserName); final ChatUser toUser = userRepository.findByUserName(toUserName); @@ -49,51 +50,53 @@ public class ChatServiceImpl implements ChatService { @Override @Transactional(readOnly = true) - public List getAllMessages(final String fromUser, final String toUser) { - final List chatMessages = chatMessageRepository.getAllMessages(fromUser, toUser); - final List chatMessageDTOs = myConversionService.convertToChatMessageDTOs(chatMessages); + public List getAllMessages(final String fromUser, + final String toUser) { + final List chatMessages = chatMessageRepository + .getAllMessages(fromUser, toUser); + final List chatMessageDTOs = myConversionService + .convertToChatMessageDTOs(chatMessages); return chatMessageDTOs; } @Override @Transactional(readOnly = true) - public List getAllMessagesForReencryption(final String fromUser, final String toUser) { - return myConversionService.convertToReencryptionDTOs(chatMessageRepository.getAllMessages(fromUser, toUser)); + public List getAllMessagesForReencryption( + final String fromUser, final String toUser) { + return myConversionService.convertToReencryptionDTOs( + chatMessageRepository.getAllMessages(fromUser, toUser)); } @Override @Transactional(readOnly = true) - public List getMessagePage(final String fromUser, final String toUser, final int page, - final int size) { - // Sort sort = Sort - // Page chatMessages = - // chatMessageRepository.getAllMessages(fromUser, toUser,PageRequest.of(page, - // size)); - // List chatMessageDTOs = - // myConversionService.convertToChatMessageDTOs(chatMessages); - // return chatMessageDTOs; + public List getMessagePage(final String fromUser, + final String toUser, final int page, final int size) { return myConversionService.convertToChatMessageDTOs( - chatMessageRepository.getAllMessages(fromUser, toUser, PageRequest.of(page, size))); + chatMessageRepository.getAllMessages(fromUser, toUser, + PageRequest.of(page, size))); } @Override @Transactional(readOnly = true) - public List getNewMessages(final String fromUser, final String toUser, final Date lastMessageTime) { - final List chatMessages = chatMessageRepository.getNewMessages(fromUser, toUser, lastMessageTime); - // List chatMessageDTOs + public List getNewMessages(final String fromUser, + final String toUser, final Date lastMessageTime) { + final List chatMessages = chatMessageRepository + .getNewMessages(fromUser, toUser, lastMessageTime); return myConversionService.convertToChatMessageDTOs(chatMessages); } @Override - public void reencryptMessages(final List reencryptionDTOs) { + public void reencryptMessages( + final List reencryptionDTOs) { final List messageCiphers = reencryptionDTOs.stream() - .map(reencryptionDTO -> reencryptionDTO.getMessageCipher()).collect(Collectors.toList()); + .map(reencryptionDTO -> reencryptionDTO.getMessageCipher()) + .collect(Collectors.toList()); messageCipherRepository.saveAll(messageCiphers); } @Override - public List getAllMessages(final String name, final String userName, - final PageRequest pageRequest) { + public List getAllMessages(final String name, + final String userName, final PageRequest pageRequest) { // TODO Auto-generated method stub return null; } diff --git a/chatto/src/main/java/org/ros/chatto/service/UserService.java b/chatto/src/main/java/org/ros/chatto/service/UserService.java index 03252fe..5d7941c 100644 --- a/chatto/src/main/java/org/ros/chatto/service/UserService.java +++ b/chatto/src/main/java/org/ros/chatto/service/UserService.java @@ -1,22 +1,32 @@ package org.ros.chatto.service; import java.util.List; +import java.util.Set; import org.ros.chatto.dto.ActiveUserDTO; import org.ros.chatto.dto.UserRegistrationDTO; import org.ros.chatto.model.ChatUser; -import org.ros.chatto.model.UserRole; +import org.ros.chatto.model.Role; import org.ros.chatto.model.UserSession; import org.springframework.stereotype.Service; @Service public interface UserService { public List findAllOtherUsers(String userName); - public UserRole registerUser(UserRegistrationDTO userRegistrationDTO); + + public ChatUser createUser(UserRegistrationDTO userRegistrationDTO); + public List getAllRegularUsers(); - public ChatUser findByUserName(String userName); + + public ChatUser getUser(String userName); + + public Set getRoles(ChatUser user); + public List getOtherActiveUsers(String userName); - public List getUserWithRole(String userName); + + public ChatUser getUserWithRole(String userName); + public UserSession incrementUserSession(String userName); + public UserSession decrementUserSession(String userName); } diff --git a/chatto/src/main/java/org/ros/chatto/service/UserServiceImpl.java b/chatto/src/main/java/org/ros/chatto/service/UserServiceImpl.java index cf50b94..bba4ffa 100644 --- a/chatto/src/main/java/org/ros/chatto/service/UserServiceImpl.java +++ b/chatto/src/main/java/org/ros/chatto/service/UserServiceImpl.java @@ -6,6 +6,8 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; import org.ros.chatto.dto.ActiveUserDTO; import org.ros.chatto.dto.UserRegistrationDTO; @@ -44,7 +46,7 @@ public class UserServiceImpl implements UserService { private final UserTokenService userTokenService; @Override - public UserRole registerUser(final UserRegistrationDTO userRegistrationDTO) { + public ChatUser createUser(final UserRegistrationDTO userRegistrationDTO) { final ChatUser user = new ChatUser(); user.setUserName(userRegistrationDTO.getUserName()); user.setPassword(passwordEncoder.encode(userRegistrationDTO.getPassword())); @@ -53,8 +55,7 @@ public class UserServiceImpl implements UserService { final Role role = roleRepository.findByName("USER"); userRole.setRole(role); userRole.setUser(changedUser); - userRoleRepository.save(userRole); - return userRole; + return userRoleRepository.save(userRole).getUser(); } @Override @@ -97,7 +98,7 @@ public class UserServiceImpl implements UserService { @Transactional(readOnly = true) @Override - public ChatUser findByUserName(final String userName) { + public ChatUser getUser(final String userName) { return userRepository.findByUserName(userName); } @@ -148,13 +149,14 @@ public class UserServiceImpl implements UserService { @Override @Transactional(readOnly = true) - public List getUserWithRole(final String userName) { - return userRoleRepository.findByUser(userName); + public ChatUser getUserWithRole(final String userName) { + return userRepository.findByUserNameWithRole(userName); } @Override public UserSession incrementUserSession(String userName) { - ChatUser chatUser = findByUserName(userName); + ChatUser chatUser = getUser(userName); + Instant instant = Instant.now(); UserSession userSession = userSessionRepository.findByUserName(userName); @@ -163,6 +165,7 @@ public class UserServiceImpl implements UserService { } userSession.setUser(chatUser); + userSession.setTimeStamp(instant); userSession.setOnline(true); userSession.setNumSessions(userSession.getNumSessions() + 1); return userSessionRepository.save(userSession); @@ -171,6 +174,7 @@ public class UserServiceImpl implements UserService { @Override public UserSession decrementUserSession(String userName) { UserSession userSession = userSessionRepository.findByUserName(userName); + Instant instant = Instant.now(); if (userSession == null) { log.error("User session is somehow null for user: " + userName); @@ -190,6 +194,12 @@ public class UserServiceImpl implements UserService { } userSession.setNumSessions(numSessions); + userSession.setTimeStamp(instant); return userSessionRepository.save(userSession); } + + @Override + public Set getRoles(ChatUser user) { + return user.getUserRoles().stream().map(ur -> ur.getRole()).collect(Collectors.toSet()); + } } diff --git a/chatto/src/main/resources/application.properties b/chatto/src/main/resources/application.properties index c7282ff..5ba5739 100644 --- a/chatto/src/main/resources/application.properties +++ b/chatto/src/main/resources/application.properties @@ -11,7 +11,7 @@ spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDial # Hibernate ddl auto (create, create-drop, validate, update) -spring.jpa.hibernate.ddl-auto = none +spring.jpa.hibernate.ddl-auto = validate spring.jpa.open-in-view=false logging.level.org.hibernate.stat=debug diff --git a/chatto/src/main/resources/db/migration/V1__ddl.sql b/chatto/src/main/resources/db/migration/V1__ddl.sql index cbc5ced..911de22 100644 --- a/chatto/src/main/resources/db/migration/V1__ddl.sql +++ b/chatto/src/main/resources/db/migration/V1__ddl.sql @@ -47,7 +47,7 @@ CREATE TABLE IF NOT EXISTS `users_roles` ( KEY `user` (`user_id`), KEY `role` (`role_id`), CONSTRAINT `FOREIGN KEY USER IN USERS-ROLES TABLE` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) ON DELETE CASCADE ON UPDATE CASCADE, - CONSTRAINT `fk_roles_roleAssignments` FOREIGN KEY (`role_id`) REFERENCES `roles` (`role_id`) ON DELETE CASCADE ON UPDATE CASCADE + CONSTRAINT `fk_roles_roleAssignments` FOREIGN KEY (`role_id`) REFERENCES `roles` (`role_id`) ON DELETE RESTRICT ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE IF NOT EXISTS `chat_messages` ( @@ -64,17 +64,10 @@ CREATE TABLE IF NOT EXISTS `chat_messages` ( KEY `FOREIGN KEY TO USER IN MESSAGES TABLE` (`to_user`), CONSTRAINT `FOREIGN KEY ENC MESSAGE TABLE` FOREIGN KEY (`message`) REFERENCES `message_ciphers` (`id`) ON UPDATE CASCADE, CONSTRAINT `FOREIGN KEY FROM USER IN MESSAGES TABLE` FOREIGN KEY (`from_user`) REFERENCES `users` (`user_id`) ON UPDATE CASCADE, - CONSTRAINT `FOREIGN KEY TO USER IN MESSAGES TABLE` FOREIGN KEY (`to_user`) REFERENCES `users` (`user_id`) ON UPDATE CASCADE + CONSTRAINT `FOREIGN KEY TO USER IN MESSAGES TABLE` FOREIGN KEY (`to_user`) REFERENCES `users` (`user_id`) ON UPDATE CASCADE, + UNIQUE KEY `UNIQUE MESSAGE CIPHER` (`message`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -CREATE TABLE IF NOT EXISTS `status` ( - `id` int(2) NOT NULL AUTO_INCREMENT, - `name` varchar(15) NOT NULL, - `value` tinyint(1) NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `name` (`name`) -) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4; - CREATE TABLE IF NOT EXISTS `user_sessions` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(15) NOT NULL, @@ -83,7 +76,8 @@ CREATE TABLE IF NOT EXISTS `user_sessions` ( `time_stamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `user_name` (`user_id`), - CONSTRAINT `FOREIGN KEY USER ID` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) ON DELETE CASCADE ON UPDATE CASCADE + CONSTRAINT `FOREIGN KEY USER ID` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) ON DELETE CASCADE ON UPDATE CASCADE, + UNIQUE KEY `UNIQUE USER CONSTRAINT` (`user_id`) ) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4; CREATE TABLE IF NOT EXISTS `tokens` (