From 2cddbbc0621e8c6398a86eddfda5649ea4e6d05d Mon Sep 17 00:00:00 2001 From: _Bastler Date: Sun, 11 May 2025 13:25:46 +0200 Subject: [PATCH] updated dependencies, migrate RandomStringUtils, prepare notifications --- pom.xml | 2 +- .../businesslogic/NotificationsManager.java | 85 ++++++++++++ .../board/businesslogic/UserManager.java | 2 +- .../EmailNotificationProvider.java | 40 ++++++ .../notification/NotificationProvider.java | 14 ++ .../support/NotificationEntityListener.java | 26 ++++ .../board/controller/DebugController.java | 8 +- .../controller/NotificationController.java | 50 +++++++ .../de/bstly/board/model/Notification.java | 129 ++++++++++++++++++ .../board/model/support/Notificationable.java | 15 ++ .../repository/NotificationRepository.java | 18 +++ 11 files changed, 383 insertions(+), 6 deletions(-) create mode 100755 src/main/java/de/bstly/board/businesslogic/NotificationsManager.java create mode 100755 src/main/java/de/bstly/board/businesslogic/notification/EmailNotificationProvider.java create mode 100755 src/main/java/de/bstly/board/businesslogic/notification/NotificationProvider.java create mode 100755 src/main/java/de/bstly/board/businesslogic/support/NotificationEntityListener.java create mode 100755 src/main/java/de/bstly/board/controller/NotificationController.java create mode 100755 src/main/java/de/bstly/board/model/Notification.java create mode 100755 src/main/java/de/bstly/board/model/support/Notificationable.java create mode 100755 src/main/java/de/bstly/board/repository/NotificationRepository.java diff --git a/pom.xml b/pom.xml index 4718743..89a54e7 100644 --- a/pom.xml +++ b/pom.xml @@ -18,7 +18,7 @@ org.springframework.boot spring-boot-starter-parent - 3.2.4 + 3.4.5 diff --git a/src/main/java/de/bstly/board/businesslogic/NotificationsManager.java b/src/main/java/de/bstly/board/businesslogic/NotificationsManager.java new file mode 100755 index 0000000..2290955 --- /dev/null +++ b/src/main/java/de/bstly/board/businesslogic/NotificationsManager.java @@ -0,0 +1,85 @@ +package de.bstly.board.businesslogic; + +import java.util.List; +import java.util.stream.Collectors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.SmartInitializingSingleton; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +import com.google.common.collect.Lists; + +import de.bstly.board.businesslogic.notification.NotificationProvider; +import de.bstly.board.model.LocalUser; +import de.bstly.board.model.Notification; +import de.bstly.board.model.QNotification; +import de.bstly.board.model.support.Notificationable; +import de.bstly.board.repository.NotificationRepository; + +@Component +public class NotificationsManager implements SmartInitializingSingleton { + + private Logger logger = LoggerFactory.getLogger(NotificationsManager.class); + + @Autowired + private NotificationRepository notificationRepository; + @Autowired + private UserManager userManager; + @Autowired + private ApplicationContext applicationContext; + + private List providers; + + private QNotification qNotification; + + @Override + public void afterSingletonsInstantiated() { + providers = Lists.newArrayList(applicationContext.getBeansOfType(NotificationProvider.class).values()); + } + + public void processNotificationable(Notificationable notificationable) { + logger.info("Created new " + notificationable.getType() + " [" + notificationable.getId() + "] by " + + notificationable.getAuthor() + " at " + notificationable.getCreated()); + } + + public Notification geNotification(String username, Notificationable notificationable) { + return notificationRepository.findOne(qNotification.targetType.eq(notificationable.getType()) + .and(qNotification.owner.eq(username)) + .and(qNotification.target.eq(notificationable.getId()).or(qNotification.target.isNull()))).orElse(null); + } + + public Notification createNotification(Notification notification) { + return notificationRepository.save(notification); + } + + public Notification updateNotification(Notification notification) { + return notificationRepository.save(notification); + } + + public void deleteNotification(Long id) { + notificationRepository.deleteById(id); + } + + protected List getUsernames(Notificationable notificationable) { + List notifications = Lists + .newArrayList(notificationRepository.findAll(qNotification.targetType.eq(notificationable.getType()) + .and(qNotification.target.eq(notificationable.getId()).or(qNotification.target.isNull())).and(qNotification.disabled.isFalse()))); + + return notifications.stream().map(Notification::getOwner).collect(Collectors.toList()); + } + + @Async + protected void processNotificationable(String username, Notificationable notificationable) { + LocalUser user = userManager.getByUsername(username); + for (NotificationProvider provider : providers) { + if (user.getSettings() != null && user.getSettings().get(provider.getId()) == "true") { + provider.processNotificationable(user, notificationable); + } + } + } + +} diff --git a/src/main/java/de/bstly/board/businesslogic/UserManager.java b/src/main/java/de/bstly/board/businesslogic/UserManager.java index a492f0a..7f5229d 100644 --- a/src/main/java/de/bstly/board/businesslogic/UserManager.java +++ b/src/main/java/de/bstly/board/businesslogic/UserManager.java @@ -92,7 +92,7 @@ public class UserManager implements UserDetailsService, SmartInitializingSinglet public void afterSingletonsInstantiated() { if (!localUserRepository.exists(qLocalUser.roles.contains("ROLE_ADMIN"))) { if (!StringUtils.hasText(adminPassword)) { - adminPassword = RandomStringUtils.random(24, true, true); + adminPassword = RandomStringUtils.secure().next(24, true, true); logger.error("password for 'admin': " + adminPassword); } LocalUser admin = new LocalUser(); diff --git a/src/main/java/de/bstly/board/businesslogic/notification/EmailNotificationProvider.java b/src/main/java/de/bstly/board/businesslogic/notification/EmailNotificationProvider.java new file mode 100755 index 0000000..ebc1006 --- /dev/null +++ b/src/main/java/de/bstly/board/businesslogic/notification/EmailNotificationProvider.java @@ -0,0 +1,40 @@ +package de.bstly.board.businesslogic.notification; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.mail.SimpleMailMessage; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +import de.bstly.board.model.LocalUser; +import de.bstly.board.model.support.Notificationable; + +@Component +public class EmailNotificationProvider implements NotificationProvider{ + + + @Autowired + private JavaMailSender javaMailSender; + + @Value("bstly.board.email.from") + private String from; + + @Override + public String getId() { + return "notificationsEmail"; + } + + @Async + @Override + public void processNotificationable(LocalUser user, Notificationable notificationable) { + SimpleMailMessage message = new SimpleMailMessage(); + message.setFrom(from); + message.setTo(user.getEmail()); + message.setSubject("New " + notificationable.getType()); + message.setText("Created new " + notificationable.getType() +" by " + + notificationable.getAuthor() + " at " + notificationable.getCreated()); + javaMailSender.send(message); + } + +} diff --git a/src/main/java/de/bstly/board/businesslogic/notification/NotificationProvider.java b/src/main/java/de/bstly/board/businesslogic/notification/NotificationProvider.java new file mode 100755 index 0000000..fb6c609 --- /dev/null +++ b/src/main/java/de/bstly/board/businesslogic/notification/NotificationProvider.java @@ -0,0 +1,14 @@ +package de.bstly.board.businesslogic.notification; + +import org.springframework.scheduling.annotation.Async; + +import de.bstly.board.model.LocalUser; +import de.bstly.board.model.support.Notificationable; + +public interface NotificationProvider { + + String getId(); + + @Async + void processNotificationable(LocalUser user, Notificationable notificationable); +} diff --git a/src/main/java/de/bstly/board/businesslogic/support/NotificationEntityListener.java b/src/main/java/de/bstly/board/businesslogic/support/NotificationEntityListener.java new file mode 100755 index 0000000..3d0c7d1 --- /dev/null +++ b/src/main/java/de/bstly/board/businesslogic/support/NotificationEntityListener.java @@ -0,0 +1,26 @@ +package de.bstly.board.businesslogic.support; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import de.bstly.board.businesslogic.NotificationsManager; +import de.bstly.board.model.support.Notificationable; +import jakarta.persistence.PostPersist; + +@Component +public class NotificationEntityListener { + + private static NotificationsManager notificationsManager; + + @Autowired + public void setEntityProviderManager(NotificationsManager notificationsManager) { + NotificationEntityListener.notificationsManager = notificationsManager; + } + + @PostPersist + public void postPersist(Notificationable notificationable) { + if (notificationsManager != null) { + notificationsManager.processNotificationable(notificationable); + } + } +} diff --git a/src/main/java/de/bstly/board/controller/DebugController.java b/src/main/java/de/bstly/board/controller/DebugController.java index 77acddf..9df34c5 100644 --- a/src/main/java/de/bstly/board/controller/DebugController.java +++ b/src/main/java/de/bstly/board/controller/DebugController.java @@ -124,8 +124,8 @@ public class DebugController extends BaseController { entry.setEntryType(EntryType.INTERN); entry.setAuthor(username); entry.setCreated(Instant.now().minus(splittableRandom.nextLong(0, entryAge), ChronoUnit.SECONDS)); - entry.setTitle(RandomStringUtils.randomAscii(splittableRandom.nextInt(10, 250))); - entry.setText(RandomStringUtils.randomAscii(splittableRandom.nextInt(0, 2500))); + entry.setTitle(RandomStringUtils.secure().nextAscii(splittableRandom.nextInt(10, 250))); + entry.setText(RandomStringUtils.secure().nextAscii(splittableRandom.nextInt(0, 2500))); entry.setEntryStatus(EntryStatus.NORMAL); entry.setFlaggedStatus(FlaggedStatus.NORMAL); entry = entryManager.save(entry); @@ -150,7 +150,7 @@ public class DebugController extends BaseController { Comment comment = new Comment(); comment.setTarget(target); comment.setAuthor("user" + splittableRandom.nextLong(0, userCount)); - comment.setText(RandomStringUtils.randomAscii(splittableRandom.nextInt(0, 2500))); + comment.setText(RandomStringUtils.secure().nextAscii(splittableRandom.nextInt(0, 2500))); comment.setFlaggedStatus(FlaggedStatus.NORMAL); comment.setCreated(Instant.now().minus( splittableRandom.nextLong(0, (Instant.now().toEpochMilli() - date.toEpochMilli()) / 1000), @@ -183,7 +183,7 @@ public class DebugController extends BaseController { comment.setTarget(target); comment.setParent(parent); comment.setAuthor("user" + splittableRandom.nextLong(0, userCount)); - comment.setText(RandomStringUtils.randomAscii(splittableRandom.nextInt(0, 2500))); + comment.setText(RandomStringUtils.secure().nextAscii(splittableRandom.nextInt(0, 2500))); comment.setFlaggedStatus(FlaggedStatus.NORMAL); comment.setCreated(Instant.now().minus( splittableRandom.nextLong(0, (Instant.now().toEpochMilli() - date.toEpochMilli()) / 1000), diff --git a/src/main/java/de/bstly/board/controller/NotificationController.java b/src/main/java/de/bstly/board/controller/NotificationController.java new file mode 100755 index 0000000..9aecd3f --- /dev/null +++ b/src/main/java/de/bstly/board/controller/NotificationController.java @@ -0,0 +1,50 @@ +/** + * + */ +package de.bstly.board.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import de.bstly.board.businesslogic.NotificationsManager; +import de.bstly.board.model.Notification; + +/** + * The Class NotificationController. + */ +@RestController +@RequestMapping("/notifications") +public class NotificationController extends BaseController { + + @Autowired + private NotificationsManager notificationsManager; + + + @PreAuthorize("isAuthenticated()") + @PostMapping() + public Notification createNotification(@RequestBody Notification notification) { + notification.setOwner(getCurrentUsername()); + return notificationsManager.createNotification(notification); + } + + @PreAuthorize("isAuthenticated()") + @PatchMapping() + public Notification updateNotification(@RequestBody Notification notification) { + notification.setOwner(getCurrentUsername()); + return notificationsManager.updateNotification(notification); + } + + @PreAuthorize("isAuthenticated()") + @DeleteMapping("{id}") + public void deleteNotification(@PathVariable("id") Long id) { + notificationsManager.deleteNotification(id); + } + +} diff --git a/src/main/java/de/bstly/board/model/Notification.java b/src/main/java/de/bstly/board/model/Notification.java new file mode 100755 index 0000000..fe29150 --- /dev/null +++ b/src/main/java/de/bstly/board/model/Notification.java @@ -0,0 +1,129 @@ +/** + * + */ +package de.bstly.board.model; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import de.bstly.board.model.support.Types; + +/** + * The Class Flag. + */ +@Entity +@Table(name = "notifications") +@EntityListeners({ AuditingEntityListener.class }) +public class Notification { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "id") + private Long id; + @Column(name = "target") + private Long target; + @Column(name = "parent") + private Long parent; + @Column(name = "target_type", nullable = false) + private Types targetType; + @Column(name = "owner", nullable = false) + private String owner; + @Column(name = "disabled", nullable = false) + private boolean disabled; + + /** + * Gets the id. + * + * @return the id + */ + public Long getId() { + return id; + } + + /** + * Sets the id. + * + * @param id the new id + */ + public void setId(Long id) { + this.id = id; + } + + /** + * Gets the target. + * + * @return the target + */ + public Long getTarget() { + return target; + } + + public Long getParent() { + return parent; + } + + public void setParent(Long parent) { + this.parent = parent; + } + + /** + * Sets the target. + * + * @param target the new target + */ + public void setTarget(Long target) { + this.target = target; + } + + /** + * Gets the target type. + * + * @return the target type + */ + public Types getTargetType() { + return targetType; + } + + /** + * Sets the target type. + * + * @param targetType the new target type + */ + public void setTargetType(Types targetType) { + this.targetType = targetType; + } + + /** + * Gets the owner. + * + * @return the owner + */ + public String getOwner() { + return owner; + } + + /** + * Sets the owner. + * + * @param owner the new owner + */ + public void setOwner(String owner) { + this.owner = owner; + } + + public boolean isDisabled() { + return disabled; + } + + public void setDisabled(boolean disabled) { + this.disabled = disabled; + } + +} diff --git a/src/main/java/de/bstly/board/model/support/Notificationable.java b/src/main/java/de/bstly/board/model/support/Notificationable.java new file mode 100755 index 0000000..c765b33 --- /dev/null +++ b/src/main/java/de/bstly/board/model/support/Notificationable.java @@ -0,0 +1,15 @@ +package de.bstly.board.model.support; + +import java.time.Instant; + +public interface Notificationable { + + Long getId(); + + String getAuthor(); + + Instant getCreated(); + + Types getType(); + +} diff --git a/src/main/java/de/bstly/board/repository/NotificationRepository.java b/src/main/java/de/bstly/board/repository/NotificationRepository.java new file mode 100755 index 0000000..0ae691d --- /dev/null +++ b/src/main/java/de/bstly/board/repository/NotificationRepository.java @@ -0,0 +1,18 @@ +/** + * + */ +package de.bstly.board.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.querydsl.QuerydslPredicateExecutor; +import org.springframework.stereotype.Repository; + +import de.bstly.board.model.Notification; + +/** + * The Interface NotifcationRepository. + */ +@Repository +public interface NotificationRepository extends JpaRepository, QuerydslPredicateExecutor { + +}