Skip to content

Commit

Permalink
Remove ChannelPermissionUpdater, favour immutable permission collections
Browse files Browse the repository at this point in the history
  • Loading branch information
ScoreUnder committed Jan 24, 2021
1 parent 7a43754 commit 2f44296
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 72 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package score.discord.generalbot.discord.permissions

import net.dv8tion.jda.api.Permission
import net.dv8tion.jda.api.entities.PermissionOverride
import scala.jdk.CollectionConverters._

case class PermissionAttachment(allows: Set[Permission] = Set.empty, denies: Set[Permission] = Set.empty) {
def allow(perms: Permission*): PermissionAttachment =
Expand All @@ -14,4 +16,13 @@ case class PermissionAttachment(allows: Set[Permission] = Set.empty, denies: Set

def merge(other: PermissionAttachment): PermissionAttachment =
copy(allows = allows &~ other.denies | other.allows, denies = denies &~ other.allows | other.denies)

def isEmpty: Boolean = allows.isEmpty && denies.isEmpty
}

object PermissionAttachment {
def apply(ov: PermissionOverride): PermissionAttachment =
PermissionAttachment(allows = ov.getAllowed.asScala.toSet, denies = ov.getDenied.asScala.toSet)

def empty: PermissionAttachment = PermissionAttachment(Set.empty, Set.empty)
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ import score.discord.generalbot.wrappers.FutureEither._
import score.discord.generalbot.wrappers.Scheduler
import score.discord.generalbot.wrappers.collections.AsyncMapConversions._
import score.discord.generalbot.wrappers.jda.Conversions._
import score.discord.generalbot.wrappers.jda.ID
import score.discord.generalbot.wrappers.jda.IdConversions._
import score.discord.generalbot.wrappers.jda.matching.Events.GuildVoiceUpdate
import score.discord.generalbot.wrappers.jda.{ChannelPermissionUpdater, ID}

import java.util.concurrent.ConcurrentHashMap
import scala.async.Async._
Expand Down Expand Up @@ -165,18 +165,17 @@ class PrivateVoiceChats(

private def addVoicePerms(users: Seq[User], channel: VoiceChannel, guild: Guild): Future[(Seq[User], Seq[User])] = {
try {
val permUpdater = ChannelPermissionUpdater(channel)
val addedMembers = users.map(guild.findMember).map {
case Some(targetMember) =>
permUpdater.grant(targetMember, Permission.VOICE_CONNECT)
Right(())
case None =>
Left("Member missing from guild")
}

val (granted, notFound) = (addedMembers zip users).partition(_._1.isRight)
permUpdater.queue().transform {
case Success(_) => Success((granted.map(_._2), notFound.map(_._2)))
val (members, notFound) = users
.map(user => user -> guild.findMember(user))
.partition(_._2.isDefined)
val grants = PermissionCollection(members
.flatMap(_._2)
.foldLeft(Vector.empty[(Member, PermissionAttachment)]) { (acc, member) =>
acc :+ member -> channel.getPermissionAttachment(member).allow(Permission.VOICE_CONNECT)
})

channel.applyPerms(grants).queueFuture().transform {
case Success(_) => Success((members.map(_._1), notFound.map(_._1)))
case Failure(_) => Success((Nil, users))
}
} catch {
Expand Down Expand Up @@ -318,7 +317,7 @@ class PrivateVoiceChats(
channelReq <- createChannel(name, guild, category)
} yield {
async {
val categoryPerms = category.fold(PermissionCollection.empty[IPermissionHolder])(_.permissionOverrides)
val categoryPerms = category.fold(PermissionCollection.empty[IPermissionHolder])(_.permissionAttachments)
val channelPerms = getChannelPermissions(member, limit, public)
val newPerms = categoryPerms.merge(channelPerms).mapValues(_.clear(Permission.MANAGE_ROLES, Permission.MANAGE_PERMISSIONS))
channelReq.applyPerms(newPerms)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import net.dv8tion.jda.api.requests.ErrorResponse._
import net.dv8tion.jda.api.{JDA, Permission}
import score.discord.generalbot.collections.{AsyncMap, ReplyCache}
import score.discord.generalbot.command.Command
import score.discord.generalbot.discord.permissions.{PermissionAttachment, PermissionCollection}
import score.discord.generalbot.functionality.Commands
import score.discord.generalbot.functionality.ownership.MessageOwnership
import score.discord.generalbot.util.APIHelper.Error
Expand Down Expand Up @@ -227,14 +228,11 @@ class VoiceKick(ownerByChannel: AsyncMap[(ID[Guild], ID[VoiceChannel]), ID[User]

def removeTemporaryVoiceBan(voiceChannel: VoiceChannel, member: Member, logChannel: Option[MessageChannel], explicitGrant: Boolean): Unit = {
Option(voiceChannel.getPermissionOverride(member)).foreach { permissionOverride =>
val originalPerms = (permissionOverride.getAllowedRaw, permissionOverride.getDeniedRaw)
val permsWithoutVoiceBan =
(originalPerms._1, originalPerms._2 & ~Permission.VOICE_CONNECT.getRawValue)
val originalPerms = PermissionAttachment(permissionOverride)
val permsWithoutVoiceBan = originalPerms.clear(Permission.VOICE_CONNECT)

APIHelper.tryRequest({
if ((permsWithoutVoiceBan._1 | permsWithoutVoiceBan._2) == 0) {
// if all permissions are inherited after removing voice ban,
// then remove the override
if (permsWithoutVoiceBan.isEmpty) {
permissionOverride.delete()
} else if (explicitGrant) {
permissionOverride.getManager.grant(Permission.VOICE_CONNECT)
Expand All @@ -258,24 +256,22 @@ class VoiceKick(ownerByChannel: AsyncMap[(ID[Guild], ID[VoiceChannel]), ID[User]
def addTemporaryVoiceBan(voiceChannel: VoiceChannel, member: Member, logChannel: MessageChannel): Unit = {
val originalPerms =
Option(voiceChannel.getPermissionOverride(member))
.map(p => (p.getAllowedRaw, p.getDeniedRaw))
.getOrElse((0L, 0L))
.fold(PermissionAttachment.empty)(PermissionAttachment.apply)

if ((originalPerms._2 & Permission.VOICE_CONNECT.getRawValue) == 0) {
if (!originalPerms.denies.contains(Permission.VOICE_CONNECT)) {
val permsWithVoiceBan = originalPerms.deny(Permission.VOICE_CONNECT)
val futureReq = APIHelper.tryRequest({
// XXX Oh my god static mutable globals in a multithreaded environment
// XXX Hack: JDA seems to consistently get the wrong idea about permissions here for some reason.
Manager.setPermissionChecksEnabled(false)
try
voiceChannel.getManager.putPermissionOverride(member,
originalPerms._1 & ~Permission.VOICE_CONNECT.getRawValue,
originalPerms._2 | Permission.VOICE_CONNECT.getRawValue)
finally
try {
voiceChannel.applyPerms(PermissionCollection(Seq(member -> permsWithVoiceBan)))
} finally
Manager.setPermissionChecksEnabled(true)
}, onFail = APIHelper.loudFailure(s"adding voice tempban permissions to ${voiceChannel.mention} for ${member.getUser.mention}", logChannel))

// Whether we need to explicitly grant the permission back
val explicitGrant = (originalPerms._1 & Permission.VOICE_CONNECT.getRawValue) != 0
val explicitGrant = originalPerms.allows.contains(Permission.VOICE_CONNECT)

futureReq.foreach { _ =>
// Take note (in DB) of when the voice ban should expire
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
package score.discord.generalbot.wrappers.jda

import net.dv8tion.jda.api.entities.{GuildChannel, IPermissionHolder}
import net.dv8tion.jda.api.managers.ChannelManager
import score.discord.generalbot.discord.permissions.{PermissionAttachment, PermissionCollection}

import scala.jdk.CollectionConverters._

class RichGuildChannel(val _me: GuildChannel) extends AnyVal {
def permissionOverrides: PermissionCollection[IPermissionHolder] =
def permissionAttachments: PermissionCollection[IPermissionHolder] =
PermissionCollection(_me.getPermissionOverrides.asScala.map { ov =>
ov.getPermissionHolder -> PermissionAttachment(ov.getAllowed.asScala.toSet, ov.getDenied.asScala.toSet)
ov.getPermissionHolder -> PermissionAttachment(ov)
}.toSeq)

def getPermissionAttachment(what: IPermissionHolder): PermissionAttachment =
Option(_me.getPermissionOverride(what)).fold(PermissionAttachment.empty)(PermissionAttachment.apply)

def applyPerms(perms: PermissionCollection[IPermissionHolder]): ChannelManager = {
val manager = _me.getManager
perms.values.foreach { case (k, v) => manager.putPermissionOverride(k, v.allows.asJava, v.denies.asJava) }
manager
}
}

0 comments on commit 2f44296

Please sign in to comment.