Browse Source

Add atomic keyword argument for member role editing operations.

This affects:

* Member.add_roles
* Member.remove_roles

This is the main attempt of fixing long standing bugs like #56. Since
cache consistency is too hard to ask for due to eventual consistency
and this generally being one of the only main roadblocks that the
cache ruins, it's best to just implement it in terms of the atomic
endpoint instead.

Fixes #56
pull/728/head
Rapptz 8 years ago
parent
commit
84f38b166e
  1. 44
      discord/member.py

44
discord/member.py

@ -484,7 +484,7 @@ class Member(discord.abc.Messageable, _BaseUser):
yield from self.edit(voice_channel=channel, reason=reason) yield from self.edit(voice_channel=channel, reason=reason)
@asyncio.coroutine @asyncio.coroutine
def add_roles(self, *roles, reason=None): def add_roles(self, *roles, reason=None, atomic=True):
"""|coro| """|coro|
Gives the member a number of :class:`Role`\s. Gives the member a number of :class:`Role`\s.
@ -499,6 +499,10 @@ class Member(discord.abc.Messageable, _BaseUser):
to give to the member. to give to the member.
reason: Optional[str] reason: Optional[str]
The reason for adding these roles. Shows up on the audit log. The reason for adding these roles. Shows up on the audit log.
atomic: bool
Whether to atomically add roles. This will ensure that multiple
operations will always be applied regardless of the current
state of the cache.
Raises Raises
------- -------
@ -508,11 +512,18 @@ class Member(discord.abc.Messageable, _BaseUser):
Adding roles failed. Adding roles failed.
""" """
new_roles = utils._unique(Object(id=r.id) for s in (self.roles[1:], roles) for r in s) if not atomic:
yield from self.edit(roles=new_roles, reason=reason) new_roles = utils._unique(Object(id=r.id) for s in (self.roles[1:], roles) for r in s)
yield from self.edit(roles=new_roles, reason=reason)
else:
req = self._state.http.add_role
guild_id = self.guild.id
user_id = self.id
for role in roles:
yield from req(guild_id, user_id, role.id, reason=reason)
@asyncio.coroutine @asyncio.coroutine
def remove_roles(self, *roles, reason=None): def remove_roles(self, *roles, reason=None, atomic=True):
"""|coro| """|coro|
Removes :class:`Role`\s from this member. Removes :class:`Role`\s from this member.
@ -527,6 +538,10 @@ class Member(discord.abc.Messageable, _BaseUser):
to remove from the member. to remove from the member.
reason: Optional[str] reason: Optional[str]
The reason for removing these roles. Shows up on the audit log. The reason for removing these roles. Shows up on the audit log.
atomic: bool
Whether to atomically add roles. This will ensure that multiple
operations will always be applied regardless of the current
state of the cache.
Raises Raises
------- -------
@ -536,11 +551,18 @@ class Member(discord.abc.Messageable, _BaseUser):
Removing the roles failed. Removing the roles failed.
""" """
new_roles = [Object(id=r.id) for r in self.roles[1:]] # remove @everyone if not atomic:
for role in roles: new_roles = [Object(id=r.id) for r in self.roles[1:]] # remove @everyone
try: for role in roles:
new_roles.remove(Object(id=role.id)) try:
except ValueError: new_roles.remove(Object(id=role.id))
pass except ValueError:
pass
yield from self.edit(roles=new_roles, reason=reason) yield from self.edit(roles=new_roles, reason=reason)
else:
req = self._state.http.remove_role
guild_id = self.guild.id
user_id = self.id
for role in roles:
yield from req(guild_id, user_id, role.id, reason=reason)

Loading…
Cancel
Save