Skip to content

Commit 3685c6f

Browse files
Added support for bulk updating permission overrides (discord-jda#646)
Added support for bulk updating permission overrides
1 parent 12e53c6 commit 3685c6f

File tree

2 files changed

+228
-11
lines changed

2 files changed

+228
-11
lines changed

src/main/java/net/dv8tion/jda/core/managers/ChannelManager.java

Lines changed: 205 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,22 @@
1616

1717
package net.dv8tion.jda.core.managers;
1818

19+
import gnu.trove.map.hash.TLongObjectHashMap;
20+
import gnu.trove.set.TLongSet;
21+
import gnu.trove.set.hash.TLongHashSet;
1922
import net.dv8tion.jda.core.Permission;
20-
import net.dv8tion.jda.core.entities.Category;
21-
import net.dv8tion.jda.core.entities.Channel;
22-
import net.dv8tion.jda.core.entities.ChannelType;
23-
import net.dv8tion.jda.core.entities.Guild;
23+
import net.dv8tion.jda.core.entities.*;
24+
import net.dv8tion.jda.core.entities.impl.AbstractChannelImpl;
2425
import net.dv8tion.jda.core.exceptions.InsufficientPermissionException;
2526
import net.dv8tion.jda.core.managers.impl.ManagerBase;
2627
import net.dv8tion.jda.core.requests.Route;
28+
import net.dv8tion.jda.core.requests.restaction.PermOverrideData;
2729
import net.dv8tion.jda.core.utils.Checks;
2830
import okhttp3.RequestBody;
2931
import org.json.JSONObject;
3032

3133
import javax.annotation.CheckReturnValue;
34+
import java.util.Collection;
3235

3336
/**
3437
* Manager providing functionality to update one or more fields for a {@link net.dv8tion.jda.core.entities.Channel Guild Channel}.
@@ -64,6 +67,8 @@ public class ChannelManager extends ManagerBase
6467
public static final long USERLIMIT = 0x20;
6568
/** Used to reset the bitrate field */
6669
public static final long BITRATE = 0x40;
70+
/** Used to reset the permission field */
71+
public static final long PERMISSION = 0x80;
6772

6873
protected final Channel channel;
6974

@@ -75,6 +80,10 @@ public class ChannelManager extends ManagerBase
7580
protected int userlimit;
7681
protected int bitrate;
7782

83+
protected final Object lock = new Object();
84+
protected final TLongObjectHashMap<PermOverrideData> overridesAdd;
85+
protected final TLongSet overridesRem;
86+
7887
/**
7988
* Creates a new ChannelManager instance
8089
*
@@ -89,8 +98,15 @@ public ChannelManager(Channel channel)
8998
this.channel = channel;
9099
if (isPermissionChecksEnabled())
91100
checkPermissions();
101+
this.overridesAdd = new TLongObjectHashMap<>();
102+
this.overridesRem = new TLongHashSet();
92103
}
93104

105+
/**
106+
* The {@link net.dv8tion.jda.core.entities.ChannelType ChannelType}
107+
*
108+
* @return The ChannelType
109+
*/
94110
public ChannelType getType()
95111
{
96112
return channel.getType();
@@ -133,6 +149,7 @@ public Guild getGuild()
133149
* <li>{@link #NSFW}</li>
134150
* <li>{@link #USERLIMIT}</li>
135151
* <li>{@link #BITRATE}</li>
152+
* <li>{@link #PERMISSION}</li>
136153
* </ul>
137154
*
138155
* @param fields
@@ -151,6 +168,14 @@ public ChannelManager reset(long fields)
151168
this.parent = null;
152169
if ((fields & TOPIC) == TOPIC)
153170
this.topic = null;
171+
if ((fields & PERMISSION) == PERMISSION)
172+
{
173+
withLock(lock, (lock) ->
174+
{
175+
this.overridesRem.clear();
176+
this.overridesAdd.clear();
177+
});
178+
}
154179
return this;
155180
}
156181

@@ -167,6 +192,7 @@ public ChannelManager reset(long fields)
167192
* <li>{@link #NSFW}</li>
168193
* <li>{@link #USERLIMIT}</li>
169194
* <li>{@link #BITRATE}</li>
195+
* <li>{@link #PERMISSION}</li>
170196
* </ul>
171197
*
172198
* @param fields
@@ -195,6 +221,149 @@ public ChannelManager reset()
195221
this.name = null;
196222
this.parent = null;
197223
this.topic = null;
224+
withLock(lock, (lock) ->
225+
{
226+
this.overridesRem.clear();
227+
this.overridesAdd.clear();
228+
});
229+
return this;
230+
}
231+
232+
/**
233+
* Clears the overrides added via {@link #putPermissionOverride(IPermissionHolder, Collection, Collection)}.
234+
*
235+
* @return ChannelManager for chaining convenience
236+
*/
237+
public ChannelManager clearOverridesAdded()
238+
{
239+
withLock(lock, (lock) ->
240+
{
241+
this.overridesAdd.clear();
242+
if (this.overridesRem.isEmpty())
243+
set &= ~PERMISSION;
244+
});
245+
return this;
246+
}
247+
248+
/**
249+
* Clears the overrides removed via {@link #removePermissionOverride(IPermissionHolder)}.
250+
*
251+
* @return ChannelManager for chaining convenience
252+
*/
253+
public ChannelManager clearOverridesRemoved()
254+
{
255+
withLock(lock, (lock) ->
256+
{
257+
this.overridesRem.clear();
258+
if (this.overridesAdd.isEmpty())
259+
set &= ~PERMISSION;
260+
});
261+
return this;
262+
}
263+
264+
/**
265+
* Adds an override for the specified {@link net.dv8tion.jda.core.entities.IPermissionHolder IPermissionHolder}
266+
* with the provided raw bitmasks as allowed and denied permissions. If the permission holder already
267+
* had an override on this channel it will be updated instead.
268+
*
269+
* @param permHolder
270+
* The permission holder
271+
* @param allow
272+
* The bitmask to grant
273+
* @param deny
274+
* The bitmask to deny
275+
*
276+
* @throws java.lang.IllegalArgumentException
277+
* If the provided permission holder is {@code null}
278+
* @throws net.dv8tion.jda.core.exceptions.InsufficientPermissionException
279+
* If the currently logged in account does not have {@link net.dv8tion.jda.core.Permission#MANAGE_PERMISSIONS Permission.MANAGE_PERMISSIONS}
280+
* in this channel
281+
*
282+
* @return ChannelManager for chaining convenience
283+
*
284+
* @see #putPermissionOverride(IPermissionHolder, Collection, Collection)
285+
* @see net.dv8tion.jda.core.Permission#getRaw(Permission...) Permission.getRaw(Permission...)
286+
*/
287+
@CheckReturnValue
288+
public ChannelManager putPermissionOverride(IPermissionHolder permHolder, long allow, long deny)
289+
{
290+
Checks.notNull(permHolder, "PermissionHolder");
291+
Checks.check(permHolder.getGuild().equals(getGuild()), "PermissionHolder is not from the same Guild!");
292+
if (isPermissionChecksEnabled() && !getGuild().getSelfMember().hasPermission(channel, Permission.MANAGE_PERMISSIONS))
293+
throw new InsufficientPermissionException(Permission.MANAGE_PERMISSIONS);
294+
final long id = getId(permHolder);
295+
final int type = permHolder instanceof Role ? PermOverrideData.ROLE_TYPE : PermOverrideData.MEMBER_TYPE;
296+
withLock(lock, (lock) ->
297+
{
298+
this.overridesRem.remove(id);
299+
this.overridesAdd.put(id, new PermOverrideData(type, id, allow, deny));
300+
set |= PERMISSION;
301+
});
302+
return this;
303+
}
304+
305+
/**
306+
* Adds an override for the specified {@link net.dv8tion.jda.core.entities.IPermissionHolder IPermissionHolder}
307+
* with the provided permission sets as allowed and denied permissions. If the permission holder already
308+
* had an override on this channel it will be updated instead.
309+
* <br>Example: {@code putPermissionOverride(guild.getSelfMember(), EnumSet.of(Permission.MESSAGE_WRITE, Permission.MESSAGE_READ), null)}
310+
*
311+
* @param permHolder
312+
* The permission holder
313+
* @param allow
314+
* The permissions to grant, or null
315+
* @param deny
316+
* The permissions to deny, or null
317+
*
318+
* @throws java.lang.IllegalArgumentException
319+
* If the provided permission holder is {@code null}
320+
* @throws net.dv8tion.jda.core.exceptions.InsufficientPermissionException
321+
* If the currently logged in account does not have {@link net.dv8tion.jda.core.Permission#MANAGE_PERMISSIONS Permission.MANAGE_PERMISSIONS}
322+
* in this channel
323+
*
324+
* @return ChannelManager for chaining convenience
325+
*
326+
* @see #putPermissionOverride(IPermissionHolder, long, long)
327+
* @see java.util.EnumSet EnumSet
328+
*/
329+
@CheckReturnValue
330+
public ChannelManager putPermissionOverride(IPermissionHolder permHolder, Collection<Permission> allow, Collection<Permission> deny)
331+
{
332+
long allowRaw = allow == null ? 0 : Permission.getRaw(allow);
333+
long denyRaw = deny == null ? 0 : Permission.getRaw(deny);
334+
return putPermissionOverride(permHolder, allowRaw, denyRaw);
335+
}
336+
337+
/**
338+
* Removes the {@link net.dv8tion.jda.core.entities.PermissionOverride PermissionOverride} for the specified
339+
* {@link net.dv8tion.jda.core.entities.IPermissionHolder IPermissionHolder}. If no override existed for this member
340+
* this does nothing.
341+
*
342+
* @param permHolder
343+
* The permission holder
344+
*
345+
* @throws java.lang.IllegalArgumentException
346+
* If the provided permission holder is {@code null}
347+
* @throws net.dv8tion.jda.core.exceptions.InsufficientPermissionException
348+
* If the currently logged in account does not have {@link net.dv8tion.jda.core.Permission#MANAGE_PERMISSIONS Permission.MANAGE_PERMISSIONS}
349+
* in this channel
350+
*
351+
* @return ChannelManager for chaining convenience
352+
*/
353+
@CheckReturnValue
354+
public ChannelManager removePermissionOverride(IPermissionHolder permHolder)
355+
{
356+
Checks.notNull(permHolder, "PermissionHolder");
357+
Checks.check(permHolder.getGuild().equals(getGuild()), "PermissionHolder is not from the same Guild!");
358+
if (isPermissionChecksEnabled() && !getGuild().getSelfMember().hasPermission(channel, Permission.MANAGE_PERMISSIONS))
359+
throw new InsufficientPermissionException(Permission.MANAGE_PERMISSIONS);
360+
final long id = getId(permHolder);
361+
withLock(lock, (lock) ->
362+
{
363+
this.overridesRem.add(id);
364+
this.overridesAdd.remove(id);
365+
set |= PERMISSION;
366+
});
198367
return this;
199368
}
200369

@@ -409,6 +578,11 @@ protected RequestBody finalizeData()
409578
frame.put("bitrate", bitrate);
410579
if (shouldUpdate(PARENT))
411580
frame.put("parent_id", opt(parent));
581+
withLock(lock, (lock) ->
582+
{
583+
if (shouldUpdate(PERMISSION))
584+
frame.put("permission_overwrites", getOverrides());
585+
});
412586

413587
reset();
414588
return getRequestBody(frame);
@@ -417,8 +591,34 @@ protected RequestBody finalizeData()
417591
@Override
418592
protected boolean checkPermissions()
419593
{
420-
if (!getGuild().getSelfMember().hasPermission(channel, Permission.MANAGE_CHANNEL))
594+
final Member selfMember = getGuild().getSelfMember();
595+
if (!selfMember.hasPermission(channel, Permission.MANAGE_CHANNEL))
421596
throw new InsufficientPermissionException(Permission.MANAGE_CHANNEL);
422597
return super.checkPermissions();
423598
}
599+
600+
protected Collection<PermOverrideData> getOverrides()
601+
{
602+
//note: overridesAdd and overridesRem are mutually disjoint
603+
TLongObjectHashMap<PermOverrideData> data = new TLongObjectHashMap<>(this.overridesAdd);
604+
605+
AbstractChannelImpl<?> impl = (AbstractChannelImpl<?>) channel;
606+
impl.getOverrideMap().forEachEntry((id, override) ->
607+
{
608+
//removed by not adding them here, this data set overrides the existing one
609+
//we can use remove because it will be reset afterwards either way
610+
if (!overridesRem.remove(id) && !data.containsKey(id))
611+
data.put(id, new PermOverrideData(override));
612+
return true;
613+
});
614+
return data.valueCollection();
615+
}
616+
617+
protected long getId(IPermissionHolder holder)
618+
{
619+
if (holder instanceof Role)
620+
return ((Role) holder).getIdLong();
621+
else
622+
return ((Member) holder).getUser().getIdLong();
623+
}
424624
}

src/main/java/net/dv8tion/jda/core/requests/restaction/PermOverrideData.java

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,26 +16,43 @@
1616

1717
package net.dv8tion.jda.core.requests.restaction;
1818

19+
import net.dv8tion.jda.core.entities.PermissionOverride;
1920
import org.json.JSONObject;
2021
import org.json.JSONString;
2122

22-
class PermOverrideData implements JSONString
23+
public class PermOverrideData implements JSONString
2324
{
2425
public static final int ROLE_TYPE = 0;
2526
public static final int MEMBER_TYPE = 1;
26-
protected final int type;
27-
protected final long id;
28-
protected final long allow;
29-
protected final long deny;
27+
public final int type;
28+
public final long id;
29+
public final long allow;
30+
public final long deny;
3031

31-
protected PermOverrideData(int type, long id, long allow, long deny)
32+
public PermOverrideData(int type, long id, long allow, long deny)
3233
{
3334
this.type = type;
3435
this.id = id;
3536
this.allow = allow;
3637
this.deny = deny;
3738
}
3839

40+
public PermOverrideData(PermissionOverride override)
41+
{
42+
if (override.isMemberOverride())
43+
{
44+
this.id = override.getMember().getUser().getIdLong();
45+
this.type = MEMBER_TYPE;
46+
}
47+
else
48+
{
49+
this.id = override.getRole().getIdLong();
50+
this.type = ROLE_TYPE;
51+
}
52+
this.allow = override.getAllowedRaw();
53+
this.deny = override.getDeniedRaw();
54+
}
55+
3956
@Override
4057
public String toJSONString()
4158
{

0 commit comments

Comments
 (0)