updated dependencies, migrate RandomStringUtils, prepare notifications

This commit is contained in:
2025-05-11 13:25:46 +02:00
parent a105ea7e93
commit 2cddbbc062
11 changed files with 383 additions and 6 deletions
@@ -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<NotificationProvider> 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<String> getUsernames(Notificationable notificationable) {
List<Notification> 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);
}
}
}
}
@@ -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();
@@ -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);
}
}
@@ -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);
}
@@ -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);
}
}
}
@@ -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),
@@ -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);
}
}
+129
View File
@@ -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;
}
}
@@ -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();
}
@@ -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<Notification, Long>, QuerydslPredicateExecutor<Notification> {
}