diff options
Diffstat (limited to 'platform-paper/src')
2 files changed, 208 insertions, 7 deletions
diff --git a/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/chat/channel/ChannelManager.kt b/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/chat/channel/ChannelManager.kt index 679d300..f5e1bf2 100644 --- a/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/chat/channel/ChannelManager.kt +++ b/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/chat/channel/ChannelManager.kt @@ -9,6 +9,8 @@ import dev.m1sk9.lunaticChat.engine.exception.ChannelLimitExceededException import dev.m1sk9.lunaticChat.engine.exception.ChannelMemberLimitExceededException import dev.m1sk9.lunaticChat.engine.exception.ChannelNoOwnerPermissionException import dev.m1sk9.lunaticChat.engine.exception.ChannelNotFoundException +import dev.m1sk9.lunaticChat.engine.exception.ChannelPlayerAlreadyBannedException +import dev.m1sk9.lunaticChat.engine.exception.ChannelPlayerNotBannedException import dev.m1sk9.lunaticChat.paper.config.key.ChannelChatFeatureConfig import java.util.UUID import java.util.concurrent.ConcurrentHashMap @@ -86,18 +88,20 @@ class ChannelManager( * * @param channelId The ID of the channel to delete. * @param requesterId The ID of the player requesting the deletion. + * @param hasBypassPermission Whether the requester has bypass permission. * @return Result indicating success or failure of the deletion. * @throws ChannelNotFoundException if the channel does not exist. */ fun deleteChannel( channelId: String, requesterId: UUID, + hasBypassPermission: Boolean = false, ): Result<Unit> { val channel = channelsCache[channelId] ?: return Result.failure(ChannelNotFoundException(channelId)) - if (channel.ownerId != requesterId) { + if (channel.ownerId != requesterId && !hasBypassPermission) { return Result.failure(ChannelNoOwnerPermissionException(requesterId)) } @@ -231,6 +235,162 @@ class ChannelManager( } /** + * Checks if a player is banned from a channel. + * + * @param channelId The ID of the channel. + * @param playerId The UUID of the player to check. + * @return Result containing true if banned, false otherwise. + * @throws ChannelNotFoundException if the channel does not exist. + */ + fun isPlayerBanned( + channelId: String, + playerId: UUID, + ): Result<Boolean> { + val channel = + channelsCache[channelId] + ?: return Result.failure(ChannelNotFoundException(channelId)) + + return Result.success(channel.bannedPlayers.contains(playerId)) + } + + /** + * Bans a player from a channel. + * + * @param channelId The ID of the channel. + * @param playerId The UUID of the player to ban. + * @return Result containing the updated channel or an error. + * @throws ChannelNotFoundException if the channel does not exist. + */ + fun banPlayer( + channelId: String, + playerId: UUID, + ): Result<Channel> { + val channel = + channelsCache[channelId] + ?: return Result.failure(ChannelNotFoundException(channelId)) + + // Check if player is already banned + if (channel.bannedPlayers.contains(playerId)) { + return Result.failure(ChannelPlayerAlreadyBannedException(playerId, channelId)) + } + + // Add player to banned list + val updatedChannel = channel.copy(bannedPlayers = channel.bannedPlayers + playerId) + channelsCache[channelId] = updatedChannel + + // Remove from members if currently a member + membersCache[channelId]?.removeIf { it.playerId == playerId } + + // Clear active channel if this was the player's active channel + if (activeChannels[playerId] == channelId) { + activeChannels.remove(playerId) + } + + saveToStorage() + logger.info("Player $playerId banned from channel $channelId.") + return Result.success(updatedChannel) + } + + /** + * Unbans a player from a channel. + * + * @param channelId The ID of the channel. + * @param playerId The UUID of the player to unban. + * @return Result containing the updated channel or an error. + * @throws ChannelNotFoundException if the channel does not exist. + * @throws ChannelPlayerNotBannedException if the player is not banned. + */ + fun unbanPlayer( + channelId: String, + playerId: UUID, + ): Result<Channel> { + val channel = + channelsCache[channelId] + ?: return Result.failure(ChannelNotFoundException(channelId)) + + // Check if player is actually banned + if (!channel.bannedPlayers.contains(playerId)) { + return Result.failure(ChannelPlayerNotBannedException(playerId, channelId)) + } + + // Remove player from banned list + val updatedChannel = channel.copy(bannedPlayers = channel.bannedPlayers - playerId) + channelsCache[channelId] = updatedChannel + + saveToStorage() + logger.info("Player $playerId unbanned from channel $channelId.") + return Result.success(updatedChannel) + } + + /** + * Updates a member's role in a channel. + * + * @param channelId The ID of the channel. + * @param playerId The UUID of the player whose role to update. + * @param newRole The new role for the member. + * @return Result indicating success or failure of the operation. + * @throws ChannelNotFoundException if the channel does not exist. + */ + fun updateMemberRole( + channelId: String, + playerId: UUID, + newRole: ChannelRole, + ): Result<Unit> { + channelsCache[channelId] + ?: return Result.failure(ChannelNotFoundException(channelId)) + + val members = + membersCache[channelId] + ?: return Result.failure(ChannelNotFoundException(channelId)) + + val member = members.find { it.playerId == playerId } ?: return Result.failure(ChannelNotFoundException(channelId)) + + // Update member role + members.remove(member) + members.add(member.copy(role = newRole)) + + saveToStorage() + return Result.success(Unit) + } + + /** + * Updates the channel owner. + * + * @param channelId The ID of the channel. + * @param newOwnerId The UUID of the new owner. + * @return Result containing the updated channel or an error. + * @throws ChannelNotFoundException if the channel does not exist. + */ + fun updateChannelOwner( + channelId: String, + newOwnerId: UUID, + ): Result<Channel> { + val channel = + channelsCache[channelId] + ?: return Result.failure(ChannelNotFoundException(channelId)) + + // Update channel owner + val updatedChannel = channel.copy(ownerId = newOwnerId) + channelsCache[channelId] = updatedChannel + + // Update member roles - new owner becomes OWNER, old owner becomes MODERATOR + val members = membersCache[channelId] + if (members != null) { + members.replaceAll { member -> + when (member.playerId) { + newOwnerId -> member.copy(role = ChannelRole.OWNER) + channel.ownerId -> member.copy(role = ChannelRole.MODERATOR) + else -> member + } + } + } + + saveToStorage() + logger.info("Channel $channelId owner changed from ${channel.ownerId} to $newOwnerId.") + return Result.success(updatedChannel) + } + + /** * Saves the current state of channels and members to storage asynchronously. */ private fun saveToStorage() { diff --git a/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/chat/channel/ChannelMembershipManager.kt b/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/chat/channel/ChannelMembershipManager.kt index 3c45eb4..07ce839 100644 --- a/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/chat/channel/ChannelMembershipManager.kt +++ b/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/chat/channel/ChannelMembershipManager.kt @@ -5,8 +5,10 @@ import dev.m1sk9.lunaticChat.engine.exception.ChannelAlreadyActiveException import dev.m1sk9.lunaticChat.engine.exception.ChannelMemberAlreadyException import dev.m1sk9.lunaticChat.engine.exception.ChannelNotFoundException import dev.m1sk9.lunaticChat.engine.exception.ChannelNotMemberException +import dev.m1sk9.lunaticChat.engine.exception.ChannelPlayerBannedException +import dev.m1sk9.lunaticChat.engine.exception.ChannelPlayerMembershipLimitExceededException +import dev.m1sk9.lunaticChat.engine.exception.ChannelPrivateRequiresInvitationException import dev.m1sk9.lunaticChat.engine.exception.ChannelRuntimeException -import dev.m1sk9.lunaticChat.engine.exception.PlayerChannelLimitExceededException import dev.m1sk9.lunaticChat.paper.config.key.ChannelChatFeatureConfig import java.util.UUID import java.util.logging.Logger @@ -51,6 +53,23 @@ class ChannelMembershipManager( } /** + * Gets the role of a member in a channel without throwing exceptions. + * + * @param playerId The UUID of the player. + * @param channelId The ID of the channel. + * @return The ChannelRole if the player is a member, null otherwise. + */ + fun getMemberRoleOrNull( + playerId: UUID, + channelId: String, + ): ChannelRole? = + channelManager + .getChannelMembers(channelId) + .getOrNull() + ?.find { it.playerId == playerId } + ?.role + + /** * Checks if a player has a specific role or higher in a channel. * * @param playerId The UUID of the player. @@ -83,15 +102,17 @@ class ChannelMembershipManager( * * @param playerId The UUID of the player. * @param channelId The ID of the channel. + * @param bypassPrivateCheck If true, allows joining private channels without invitation (used for invites). * @return Result indicating success or failure. * @throws ChannelNotFoundException if the channel does not exist. * @throws ChannelMemberAlreadyException if the player is already a member of this channel. - * @throws PlayerChannelLimitExceededException if the player has reached the maximum channel membership limit. + * @throws ChannelPlayerMembershipLimitExceededException if the player has reached the maximum channel membership limit. * @throws ChannelRuntimeException for other runtime errors. */ fun joinChannel( playerId: UUID, channelId: String, + bypassPrivateCheck: Boolean = false, ): Result<Unit> { // Check if channel exists val channel = @@ -109,6 +130,21 @@ class ChannelMembershipManager( ) } + // Check if player is banned + val isBanned = channelManager.isPlayerBanned(channelId, playerId).getOrElse { false } + if (isBanned) { + return Result.failure( + ChannelPlayerBannedException(playerId, channelId), + ) + } + + // Check if this is a private channel (only invited members can join) + if (channel.isPrivate && !bypassPrivateCheck) { + return Result.failure( + ChannelPrivateRequiresInvitationException(playerId, channelId), + ) + } + // Check if player is already a member val isAlreadyMember = isMember(playerId, channelId).getOrElse { @@ -136,7 +172,7 @@ class ChannelMembershipManager( if (playerChannelCount >= config.maxMembershipPerPlayer) { return Result.failure( - PlayerChannelLimitExceededException(playerId, config.maxMembershipPerPlayer), + ChannelPlayerMembershipLimitExceededException(playerId, config.maxMembershipPerPlayer), ) } } @@ -153,8 +189,8 @@ class ChannelMembershipManager( } /** - * Clears the player's active channel without removing them from channel membership. - * The player remains a member of the channel and can rejoin by using the join command. + * Removes the player from the active channel completely. + * The player will be removed from the channel membership and the active channel will be cleared. * * @param playerId The UUID of the player. * @return Result indicating success or failure. @@ -167,9 +203,14 @@ class ChannelMembershipManager( ChannelNotMemberException(playerId, "no active channel"), ) + // Remove from channel members + channelManager.removeMember(currentChannel, playerId).getOrElse { + return Result.failure(it) + } + // Clear active channel channelManager.setPlayerChannel(playerId, null) - logger.info("Player $playerId left active channel $currentChannel (still a member)") + logger.info("Player $playerId left channel $currentChannel (removed from members)") return Result.success(Unit) } |
