diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/src/main/java/com/eternalcode/parcellockers/ParcelLockers.java b/src/main/java/com/eternalcode/parcellockers/ParcelLockers.java index cfb973a0..cf4c7a5c 100644 --- a/src/main/java/com/eternalcode/parcellockers/ParcelLockers.java +++ b/src/main/java/com/eternalcode/parcellockers/ParcelLockers.java @@ -126,15 +126,16 @@ public void onEnable() { parcelContentRepository, scheduler, config, - this.economy + this.economy, + server ); UserValidationService userValidationService = new UserValidator(); - UserManager userManager = new UserManagerImpl(userRepository, userValidationService); + UserManager userManager = new UserManagerImpl(userRepository, userValidationService, server); LockerValidationService lockerValidationService = new LockerValidator(); - LockerManager lockerManager = new LockerManager(config, lockerRepository, lockerValidationService, parcelRepository); + LockerManager lockerManager = new LockerManager(config, lockerRepository, lockerValidationService, parcelRepository, server); ParcelContentManager parcelContentManager = new ParcelContentManager(parcelContentRepository); - ItemStorageManager itemStorageManager = new ItemStorageManager(itemStorageRepository); + ItemStorageManager itemStorageManager = new ItemStorageManager(itemStorageRepository, server); DeliveryManager deliveryManager = new DeliveryManager(deliveryRepository); ParcelDispatchService parcelDispatchService = new ParcelDispatchService( diff --git a/src/main/java/com/eternalcode/parcellockers/delivery/DeliveryManager.java b/src/main/java/com/eternalcode/parcellockers/delivery/DeliveryManager.java index 2cacfa98..ceeb8edf 100644 --- a/src/main/java/com/eternalcode/parcellockers/delivery/DeliveryManager.java +++ b/src/main/java/com/eternalcode/parcellockers/delivery/DeliveryManager.java @@ -61,7 +61,7 @@ public CompletableFuture deleteAll(CommandSender sender, NoticeService not this.deliveryCache.invalidateAll(); noticeService.create() .viewer(sender) - .notice(messages -> messages.admin.deletedContents) + .notice(messages -> messages.admin.deletedDeliveries) .placeholder("{COUNT}", deleted.toString()) .send(); }); diff --git a/src/main/java/com/eternalcode/parcellockers/itemstorage/ItemStorageManager.java b/src/main/java/com/eternalcode/parcellockers/itemstorage/ItemStorageManager.java index 3ad125e1..9eb5860e 100644 --- a/src/main/java/com/eternalcode/parcellockers/itemstorage/ItemStorageManager.java +++ b/src/main/java/com/eternalcode/parcellockers/itemstorage/ItemStorageManager.java @@ -1,5 +1,6 @@ package com.eternalcode.parcellockers.itemstorage; +import com.eternalcode.parcellockers.itemstorage.event.ItemStorageUpdateEvent; import com.eternalcode.parcellockers.itemstorage.repository.ItemStorageRepository; import com.eternalcode.parcellockers.notification.NoticeService; import com.github.benmanes.caffeine.cache.Cache; @@ -9,6 +10,7 @@ import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; +import org.bukkit.Server; import org.bukkit.command.CommandSender; import org.bukkit.inventory.ItemStack; @@ -17,9 +19,11 @@ public class ItemStorageManager { private final Cache cache; private final ItemStorageRepository itemStorageRepository; + private final Server server; - public ItemStorageManager(ItemStorageRepository itemStorageRepository) { + public ItemStorageManager(ItemStorageRepository itemStorageRepository, Server server) { this.itemStorageRepository = itemStorageRepository; + this.server = server; this.cache = Caffeine.newBuilder() .expireAfterWrite(6, TimeUnit.HOURS) @@ -45,13 +49,20 @@ public ItemStorage getOrCreate(UUID owner, List items) { } public ItemStorage create(UUID owner, List items) { - ItemStorage itemStorage = new ItemStorage(owner, items); - if (this.cache.getIfPresent(owner) != null) { - throw new IllegalStateException("ItemStorage for owner " + owner + " already exists. Use ItemStorageManager#getOrCreate method instead."); + ItemStorage oldItemStorage = this.cache.getIfPresent(owner); + ItemStorage newItemStorage = new ItemStorage(owner, items); + + // This is an update operation - fire ItemStorageUpdateEvent + ItemStorageUpdateEvent event = new ItemStorageUpdateEvent(oldItemStorage, newItemStorage); + this.server.getPluginManager().callEvent(event); + + if (event.isCancelled()) { + throw new IllegalStateException("ItemStorage update was cancelled by event"); } - this.cache.put(owner, itemStorage); - this.itemStorageRepository.save(itemStorage); - return itemStorage; + + this.cache.put(owner, newItemStorage); + this.itemStorageRepository.save(newItemStorage); + return newItemStorage; } private void cacheAll() { diff --git a/src/main/java/com/eternalcode/parcellockers/itemstorage/event/ItemStorageUpdateEvent.java b/src/main/java/com/eternalcode/parcellockers/itemstorage/event/ItemStorageUpdateEvent.java new file mode 100644 index 00000000..bebb56fc --- /dev/null +++ b/src/main/java/com/eternalcode/parcellockers/itemstorage/event/ItemStorageUpdateEvent.java @@ -0,0 +1,50 @@ +package com.eternalcode.parcellockers.itemstorage.event; + +import com.eternalcode.parcellockers.itemstorage.ItemStorage; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +public class ItemStorageUpdateEvent extends Event implements Cancellable { + + private static final HandlerList HANDLER_LIST = new HandlerList(); + + private final ItemStorage oldItemStorage; + private final ItemStorage updatedItemStorage; + + private boolean cancelled; + + public ItemStorageUpdateEvent(ItemStorage oldItemStorage, ItemStorage updatedItemStorage) { + super(true); + this.oldItemStorage = oldItemStorage; + this.updatedItemStorage = updatedItemStorage; + } + + public static HandlerList getHandlerList() { + return HANDLER_LIST; + } + + public ItemStorage getOldItemStorage() { + return this.oldItemStorage; + } + + public ItemStorage getUpdatedItemStorage() { + return this.updatedItemStorage; + } + + @Override + public boolean isCancelled() { + return this.cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } + + @Override + public @NotNull HandlerList getHandlers() { + return HANDLER_LIST; + } +} diff --git a/src/main/java/com/eternalcode/parcellockers/locker/LockerManager.java b/src/main/java/com/eternalcode/parcellockers/locker/LockerManager.java index b55b1c6c..b3fe0803 100644 --- a/src/main/java/com/eternalcode/parcellockers/locker/LockerManager.java +++ b/src/main/java/com/eternalcode/parcellockers/locker/LockerManager.java @@ -1,6 +1,8 @@ package com.eternalcode.parcellockers.locker; import com.eternalcode.parcellockers.configuration.implementation.PluginConfig; +import com.eternalcode.parcellockers.locker.event.LockerCreateEvent; +import com.eternalcode.parcellockers.locker.event.LockerDeleteEvent; import com.eternalcode.parcellockers.locker.repository.LockerRepository; import com.eternalcode.parcellockers.locker.validation.LockerValidationService; import com.eternalcode.parcellockers.notification.NoticeService; @@ -18,6 +20,7 @@ import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.function.Function; +import org.bukkit.Server; import org.bukkit.command.CommandSender; public class LockerManager { @@ -26,6 +29,7 @@ public class LockerManager { private final LockerRepository lockerRepository; private final LockerValidationService validationService; private final ParcelRepository parcelRepository; + private final Server server; private final Cache lockersByUUID; private final Cache lockersByPosition; @@ -34,12 +38,14 @@ public LockerManager( PluginConfig config, LockerRepository lockerRepository, LockerValidationService validationService, - ParcelRepository parcelRepository + ParcelRepository parcelRepository, + Server server ) { this.config = config; this.lockerRepository = lockerRepository; this.validationService = validationService; this.parcelRepository = parcelRepository; + this.server = server; this.lockersByUUID = Caffeine.newBuilder() .expireAfterAccess(Duration.ofHours(2)) @@ -96,7 +102,7 @@ public CompletableFuture> get(Page page) { return this.lockerRepository.findPage(page); } - public CompletableFuture create(UUID uniqueId, String name, Position position) { + public CompletableFuture create(UUID uniqueId, String name, Position position, UUID playerUUID) { return CompletableFuture.supplyAsync(() -> { ValidationResult validation = this.validationService.validateCreateParameters(uniqueId, name, position); @@ -115,6 +121,15 @@ public CompletableFuture create(UUID uniqueId, String name, Position pos } Locker locker = new Locker(uniqueId, name, position); + + // Fire LockerCreateEvent + LockerCreateEvent event = new LockerCreateEvent(locker, playerUUID); + this.server.getPluginManager().callEvent(event); + + if (event.isCancelled()) { + throw new ValidationException("Locker creation cancelled by event"); + } + this.lockersByUUID.put(uniqueId, locker); this.lockersByPosition.put(position, locker); @@ -122,12 +137,26 @@ public CompletableFuture create(UUID uniqueId, String name, Position pos }).thenCompose(Function.identity()); } - public CompletableFuture delete(UUID uniqueId) { - return this.lockerRepository.delete(uniqueId).thenAccept(deleted -> { - if (deleted > 0) { - this.lockersByUUID.invalidate(uniqueId); - this.lockersByPosition.asMap().values().removeIf(locker -> locker.uuid().equals(uniqueId)); + public CompletableFuture delete(UUID uniqueId, UUID playerUUID) { + Locker cachedLocker = this.lockersByUUID.getIfPresent(uniqueId); + + CompletableFuture lockerFuture = cachedLocker != null + ? CompletableFuture.completedFuture(cachedLocker) + : this.lockerRepository.find(uniqueId).thenApply(opt -> opt.orElse(null)); + + return lockerFuture.thenCompose(locker -> { + if (locker == null) { + return CompletableFuture.completedFuture(null); + } + + LockerDeleteEvent event = new LockerDeleteEvent(locker, playerUUID); + this.server.getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return CompletableFuture.completedFuture(null); } + + return this.deleteLocker(uniqueId); }); } @@ -148,4 +177,13 @@ public CompletableFuture isLockerFull(UUID uniqueId) { return this.parcelRepository.countDeliveredParcelsByDestinationLocker(uniqueId) .thenApply(count -> count > 0 && count >= this.config.settings.maxParcelsPerLocker); } + + private CompletableFuture deleteLocker(UUID uniqueId) { + return this.lockerRepository.delete(uniqueId).thenAccept(deleted -> { + if (deleted > 0) { + this.lockersByUUID.invalidate(uniqueId); + this.lockersByPosition.asMap().values().removeIf(l -> l.uuid().equals(uniqueId)); + } + }); + } } diff --git a/src/main/java/com/eternalcode/parcellockers/locker/controller/LockerBreakController.java b/src/main/java/com/eternalcode/parcellockers/locker/controller/LockerBreakController.java index df1daf6a..03180901 100644 --- a/src/main/java/com/eternalcode/parcellockers/locker/controller/LockerBreakController.java +++ b/src/main/java/com/eternalcode/parcellockers/locker/controller/LockerBreakController.java @@ -57,7 +57,7 @@ public void onBlockBreak(BlockBreakEvent event) { return; } - this.lockerManager.delete(locker.get().uuid()); + this.lockerManager.delete(locker.get().uuid(), player.getUniqueId()); this.noticeService.player(player.getUniqueId(), messages -> messages.locker.deleted); diff --git a/src/main/java/com/eternalcode/parcellockers/locker/controller/LockerPlaceController.java b/src/main/java/com/eternalcode/parcellockers/locker/controller/LockerPlaceController.java index 499ba76e..21f1206b 100644 --- a/src/main/java/com/eternalcode/parcellockers/locker/controller/LockerPlaceController.java +++ b/src/main/java/com/eternalcode/parcellockers/locker/controller/LockerPlaceController.java @@ -128,7 +128,7 @@ public void onBlockPlace(BlockPlaceEvent event) { location.getWorld().getBlockAt(location).setBlockData(data); }); - this.lockerManager.create(UUID.randomUUID(), description, PositionAdapter.convert(location)) + this.lockerManager.create(UUID.randomUUID(), description, PositionAdapter.convert(location), player.getUniqueId()) .thenAccept(locker -> { this.noticeService.create() .player(player.getUniqueId()) diff --git a/src/main/java/com/eternalcode/parcellockers/locker/event/LockerCreateEvent.java b/src/main/java/com/eternalcode/parcellockers/locker/event/LockerCreateEvent.java new file mode 100644 index 00000000..cc5f5e82 --- /dev/null +++ b/src/main/java/com/eternalcode/parcellockers/locker/event/LockerCreateEvent.java @@ -0,0 +1,51 @@ +package com.eternalcode.parcellockers.locker.event; + +import com.eternalcode.parcellockers.locker.Locker; +import java.util.UUID; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +public class LockerCreateEvent extends Event implements Cancellable { + + private static final HandlerList HANDLER_LIST = new HandlerList(); + + private final Locker locker; + private final UUID player; + private boolean cancelled; + + public LockerCreateEvent(Locker locker, UUID player) { + super(true); + this.locker = locker; + this.player = player; + } + + public static HandlerList getHandlerList() { + return HANDLER_LIST; + } + + public Locker getLocker() { + return this.locker; + } + + public UUID getPlayer() { + return this.player; + } + + @Override + public boolean isCancelled() { + return this.cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } + + @Override + public @NotNull HandlerList getHandlers() { + return HANDLER_LIST; + } + +} diff --git a/src/main/java/com/eternalcode/parcellockers/locker/event/LockerDeleteEvent.java b/src/main/java/com/eternalcode/parcellockers/locker/event/LockerDeleteEvent.java new file mode 100644 index 00000000..9d48601a --- /dev/null +++ b/src/main/java/com/eternalcode/parcellockers/locker/event/LockerDeleteEvent.java @@ -0,0 +1,51 @@ +package com.eternalcode.parcellockers.locker.event; + +import com.eternalcode.parcellockers.locker.Locker; +import java.util.UUID; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +public class LockerDeleteEvent extends Event implements Cancellable { + + private static final HandlerList HANDLER_LIST = new HandlerList(); + + private final Locker locker; + private final UUID player; + private boolean cancelled; + + public LockerDeleteEvent(Locker locker, UUID player) { + super(true); + this.locker = locker; + this.player = player; + } + + public static HandlerList getHandlerList() { + return HANDLER_LIST; + } + + public Locker getLocker() { + return this.locker; + } + + public UUID getPlayer() { + return this.player; + } + + @Override + public boolean isCancelled() { + return this.cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } + + @Override + public @NotNull HandlerList getHandlers() { + return HANDLER_LIST; + } + +} diff --git a/src/main/java/com/eternalcode/parcellockers/parcel/event/ParcelCollectEvent.java b/src/main/java/com/eternalcode/parcellockers/parcel/event/ParcelCollectEvent.java new file mode 100644 index 00000000..b6aa8569 --- /dev/null +++ b/src/main/java/com/eternalcode/parcellockers/parcel/event/ParcelCollectEvent.java @@ -0,0 +1,43 @@ +package com.eternalcode.parcellockers.parcel.event; + +import com.eternalcode.parcellockers.parcel.Parcel; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +public class ParcelCollectEvent extends Event implements Cancellable { + + private static final HandlerList HANDLER_LIST = new HandlerList(); + + private final Parcel parcel; + private boolean cancelled; + + public ParcelCollectEvent(Parcel parcel) { + super(true); + this.parcel = parcel; + } + + public static HandlerList getHandlerList() { + return HANDLER_LIST; + } + + public Parcel getParcel() { + return this.parcel; + } + + @Override + public @NotNull HandlerList getHandlers() { + return HANDLER_LIST; + } + + @Override + public boolean isCancelled() { + return this.cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } +} diff --git a/src/main/java/com/eternalcode/parcellockers/parcel/event/ParcelDeliverEvent.java b/src/main/java/com/eternalcode/parcellockers/parcel/event/ParcelDeliverEvent.java new file mode 100644 index 00000000..47ac5347 --- /dev/null +++ b/src/main/java/com/eternalcode/parcellockers/parcel/event/ParcelDeliverEvent.java @@ -0,0 +1,43 @@ +package com.eternalcode.parcellockers.parcel.event; + +import com.eternalcode.parcellockers.parcel.Parcel; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +public class ParcelDeliverEvent extends Event implements Cancellable { + + private static final HandlerList HANDLER_LIST = new HandlerList(); + + private final Parcel parcel; + private boolean cancelled; + + public ParcelDeliverEvent(Parcel parcel) { + super(true); + this.parcel = parcel; + } + + public static HandlerList getHandlerList() { + return HANDLER_LIST; + } + + public Parcel getParcel() { + return this.parcel; + } + + @Override + public @NotNull HandlerList getHandlers() { + return HANDLER_LIST; + } + + @Override + public boolean isCancelled() { + return this.cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } +} diff --git a/src/main/java/com/eternalcode/parcellockers/parcel/event/ParcelSendEvent.java b/src/main/java/com/eternalcode/parcellockers/parcel/event/ParcelSendEvent.java new file mode 100644 index 00000000..c1c83d69 --- /dev/null +++ b/src/main/java/com/eternalcode/parcellockers/parcel/event/ParcelSendEvent.java @@ -0,0 +1,43 @@ +package com.eternalcode.parcellockers.parcel.event; + +import com.eternalcode.parcellockers.parcel.Parcel; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +public class ParcelSendEvent extends Event implements Cancellable { + + private static final HandlerList HANDLER_LIST = new HandlerList(); + + private final Parcel parcel; + private boolean cancelled; + + public ParcelSendEvent(Parcel parcel) { + super(true); + this.parcel = parcel; + } + + public static HandlerList getHandlerList() { + return HANDLER_LIST; + } + + public Parcel getParcel() { + return this.parcel; + } + + @Override + public @NotNull HandlerList getHandlers() { + return HANDLER_LIST; + } + + @Override + public boolean isCancelled() { + return this.cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } +} diff --git a/src/main/java/com/eternalcode/parcellockers/parcel/service/ParcelServiceImpl.java b/src/main/java/com/eternalcode/parcellockers/parcel/service/ParcelServiceImpl.java index bd977458..554acb1f 100644 --- a/src/main/java/com/eternalcode/parcellockers/parcel/service/ParcelServiceImpl.java +++ b/src/main/java/com/eternalcode/parcellockers/parcel/service/ParcelServiceImpl.java @@ -9,6 +9,8 @@ import com.eternalcode.parcellockers.content.repository.ParcelContentRepository; import com.eternalcode.parcellockers.notification.NoticeService; import com.eternalcode.parcellockers.parcel.Parcel; +import com.eternalcode.parcellockers.parcel.event.ParcelCollectEvent; +import com.eternalcode.parcellockers.parcel.event.ParcelSendEvent; import com.eternalcode.parcellockers.parcel.repository.ParcelRepository; import com.eternalcode.parcellockers.shared.Page; import com.eternalcode.parcellockers.shared.PageResult; @@ -23,6 +25,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import net.milkbowl.vault.economy.Economy; +import org.bukkit.Server; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; @@ -42,6 +45,7 @@ public class ParcelServiceImpl implements ParcelService { private final Scheduler scheduler; private final PluginConfig config; private final Economy economy; + private final Server server; private final Cache parcelsByUuid; @@ -51,7 +55,8 @@ public ParcelServiceImpl( ParcelContentRepository parcelContentRepository, Scheduler scheduler, PluginConfig config, - Economy economy + Economy economy, + Server server ) { this.noticeService = noticeService; this.parcelRepository = parcelRepository; @@ -59,6 +64,7 @@ public ParcelServiceImpl( this.scheduler = scheduler; this.config = config; this.economy = economy; + this.server = server; this.parcelsByUuid = Caffeine.newBuilder() .expireAfterAccess(CACHE_EXPIRE_HOURS, TimeUnit.HOURS) @@ -73,6 +79,15 @@ public CompletableFuture send(Player sender, Parcel parcel, List messages.parcel.cannotSend); + return CompletableFuture.completedFuture(false); + } + List itemsCopy = items.stream() .map(ItemStack::clone) .toList(); @@ -158,6 +173,15 @@ public CompletableFuture collect(Player player, Parcel parcel) { Objects.requireNonNull(player, "Player cannot be null"); Objects.requireNonNull(parcel, "Parcel cannot be null"); + // Fire ParcelCollectEvent + ParcelCollectEvent event = new ParcelCollectEvent(parcel); + this.server.getPluginManager().callEvent(event); + + if (event.isCancelled()) { + this.noticeService.player(player.getUniqueId(), messages -> messages.parcel.cannotCollect); + return CompletableFuture.completedFuture(null); + } + return this.parcelContentRepository.find(parcel.uuid()).thenCompose(optional -> { if (optional.isEmpty()) { this.noticeService.player(player.getUniqueId(), messages -> messages.parcel.cannotCollect); diff --git a/src/main/java/com/eternalcode/parcellockers/parcel/task/ParcelSendTask.java b/src/main/java/com/eternalcode/parcellockers/parcel/task/ParcelSendTask.java index 43bbc01a..98adac43 100644 --- a/src/main/java/com/eternalcode/parcellockers/parcel/task/ParcelSendTask.java +++ b/src/main/java/com/eternalcode/parcellockers/parcel/task/ParcelSendTask.java @@ -3,8 +3,10 @@ import com.eternalcode.parcellockers.delivery.DeliveryManager; import com.eternalcode.parcellockers.parcel.Parcel; import com.eternalcode.parcellockers.parcel.ParcelStatus; +import com.eternalcode.parcellockers.parcel.event.ParcelDeliverEvent; import com.eternalcode.parcellockers.parcel.service.ParcelService; import java.util.logging.Logger; +import org.bukkit.Bukkit; import org.bukkit.scheduler.BukkitRunnable; public class ParcelSendTask extends BukkitRunnable { @@ -40,6 +42,15 @@ public void run() { ParcelStatus.DELIVERED ); + // Fire ParcelDeliverEvent + ParcelDeliverEvent event = new ParcelDeliverEvent(updated); + Bukkit.getPluginManager().callEvent(event); + + if (event.isCancelled()) { + LOGGER.info("ParcelDeliverEvent was cancelled for parcel " + updated.uuid()); + return; + } + this.parcelService.update(updated) .exceptionally(throwable -> { LOGGER.severe("Failed to update parcel " + updated.uuid() + " to DELIVERED status: " + throwable.getMessage()); diff --git a/src/main/java/com/eternalcode/parcellockers/user/UserManager.java b/src/main/java/com/eternalcode/parcellockers/user/UserManager.java index e7daaaf2..fa386f12 100644 --- a/src/main/java/com/eternalcode/parcellockers/user/UserManager.java +++ b/src/main/java/com/eternalcode/parcellockers/user/UserManager.java @@ -17,4 +17,6 @@ public interface UserManager { CompletableFuture> get(UUID uniqueId); CompletableFuture> getPage(Page page); + + CompletableFuture changeName(UUID uuid, String newName); } diff --git a/src/main/java/com/eternalcode/parcellockers/user/UserManagerImpl.java b/src/main/java/com/eternalcode/parcellockers/user/UserManagerImpl.java index 8238c579..2c65ae91 100644 --- a/src/main/java/com/eternalcode/parcellockers/user/UserManagerImpl.java +++ b/src/main/java/com/eternalcode/parcellockers/user/UserManagerImpl.java @@ -3,6 +3,8 @@ import com.eternalcode.parcellockers.shared.Page; import com.eternalcode.parcellockers.shared.PageResult; import com.eternalcode.parcellockers.shared.validation.ValidationResult; +import com.eternalcode.parcellockers.user.event.UserChangeNameEvent; +import com.eternalcode.parcellockers.user.event.UserCreateEvent; import com.eternalcode.parcellockers.user.repository.UserRepository; import com.eternalcode.parcellockers.user.validation.UserValidationService; import com.github.benmanes.caffeine.cache.Cache; @@ -12,18 +14,21 @@ import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; +import org.bukkit.Server; public class UserManagerImpl implements UserManager { private final UserRepository userRepository; private final UserValidationService validationService; + private final Server server; private final Cache usersByUUID; private final Cache usersByName; - public UserManagerImpl(UserRepository userRepository, UserValidationService validationService) { + public UserManagerImpl(UserRepository userRepository, UserValidationService validationService, Server server) { this.userRepository = userRepository; this.validationService = validationService; + this.server = server; this.usersByUUID = Caffeine.newBuilder() .expireAfterAccess(2, TimeUnit.HOURS) .maximumSize(10_000) @@ -98,6 +103,11 @@ public CompletableFuture create(UUID uuid, String name) { } User user = new User(uuid, name); + + // Fire UserCreateEvent + UserCreateEvent event = new UserCreateEvent(user); + this.server.getPluginManager().callEvent(event); + this.usersByUUID.put(uuid, user); this.usersByName.put(name, user); this.userRepository.save(user); @@ -105,4 +115,30 @@ public CompletableFuture create(UUID uuid, String name) { return user; }); } + + @Override + public CompletableFuture changeName(UUID uuid, String newName) { + return CompletableFuture.supplyAsync(() -> { + User oldUser = this.usersByUUID.getIfPresent(uuid); + + if (oldUser == null) { + throw new ValidationException("User not found with UUID: " + uuid); + } + + String oldName = oldUser.name(); + + // Fire UserChangeNameEvent + UserChangeNameEvent event = new UserChangeNameEvent(oldUser, oldName); + this.server.getPluginManager().callEvent(event); + + // Update cache + User updatedUser = new User(uuid, newName); + this.usersByUUID.put(uuid, updatedUser); + this.usersByName.invalidate(oldName); + this.usersByName.put(newName, updatedUser); + + // Update in repository + return this.userRepository.changeName(uuid, newName); + }).thenCompose(future -> future); + } } diff --git a/src/main/java/com/eternalcode/parcellockers/user/event/UserChangeNameEvent.java b/src/main/java/com/eternalcode/parcellockers/user/event/UserChangeNameEvent.java new file mode 100644 index 00000000..972adcb9 --- /dev/null +++ b/src/main/java/com/eternalcode/parcellockers/user/event/UserChangeNameEvent.java @@ -0,0 +1,36 @@ +package com.eternalcode.parcellockers.user.event; + +import com.eternalcode.parcellockers.user.User; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +public class UserChangeNameEvent extends Event { + + private static final HandlerList HANDLER_LIST = new HandlerList(); + + private final User user; + private final String oldName; + + public UserChangeNameEvent(User user, String oldName) { + this.user = user; + this.oldName = oldName; + } + + public static HandlerList getHandlerList() { + return HANDLER_LIST; + } + + public User getUser() { + return this.user; + } + + public String getOldName() { + return this.oldName; + } + + @Override + public @NotNull HandlerList getHandlers() { + return HANDLER_LIST; + } +} diff --git a/src/main/java/com/eternalcode/parcellockers/user/event/UserCreateEvent.java b/src/main/java/com/eternalcode/parcellockers/user/event/UserCreateEvent.java new file mode 100644 index 00000000..a0439fe7 --- /dev/null +++ b/src/main/java/com/eternalcode/parcellockers/user/event/UserCreateEvent.java @@ -0,0 +1,30 @@ +package com.eternalcode.parcellockers.user.event; + +import com.eternalcode.parcellockers.user.User; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +public class UserCreateEvent extends Event { + + private static final HandlerList HANDLER_LIST = new HandlerList(); + + private final User user; + + public UserCreateEvent(User user) { + this.user = user; + } + + public static HandlerList getHandlerList() { + return HANDLER_LIST; + } + + public User getUser() { + return this.user; + } + + @Override + public @NotNull HandlerList getHandlers() { + return HANDLER_LIST; + } +}