backup permission overwrites also
This commit is contained in:
parent
b2eccf90fd
commit
13296488f8
2 changed files with 114 additions and 5 deletions
|
|
@ -89,8 +89,82 @@ class BackupPermissions:
|
|||
|
||||
|
||||
class BackupPermissionOverwrite:
|
||||
"""Minimal stand-in for discord.PermissionOverwrite."""
|
||||
pass
|
||||
"""Minimal stand-in for discord.PermissionOverwrite.
|
||||
|
||||
Supports:
|
||||
- .pair() -> (BackupPermissions(allow), BackupPermissions(deny))
|
||||
- iteration: yields (perm_name, True|False|None) tuples
|
||||
- setattr(ow, perm_name, value) for merging
|
||||
"""
|
||||
|
||||
# Standard Discord permission flag names and their bit positions
|
||||
VALID_NAMES = {
|
||||
"create_instant_invite": 0, "kick_members": 1, "ban_members": 2,
|
||||
"administrator": 3, "manage_channels": 4, "manage_guild": 5,
|
||||
"add_reactions": 6, "view_audit_log": 7, "priority_speaker": 8,
|
||||
"stream": 9, "view_channel": 10, "send_messages": 11,
|
||||
"send_tts_messages": 12, "manage_messages": 13, "embed_links": 14,
|
||||
"attach_files": 15, "read_message_history": 16, "mention_everyone": 17,
|
||||
"use_external_emojis": 18, "view_guild_insights": 19, "connect": 20,
|
||||
"speak": 21, "mute_members": 22, "deafen_members": 23,
|
||||
"move_members": 24, "use_vad": 25, "change_nickname": 26,
|
||||
"manage_nicknames": 27, "manage_roles": 28, "manage_webhooks": 29,
|
||||
"manage_emojis_and_stickers": 30, "use_application_commands": 31,
|
||||
"request_to_speak": 32, "manage_events": 33, "manage_threads": 34,
|
||||
"create_public_threads": 35, "create_private_threads": 36,
|
||||
"use_external_stickers": 37, "send_messages_in_threads": 38,
|
||||
"use_embedded_activities": 39, "moderate_members": 40,
|
||||
}
|
||||
|
||||
def __init__(self, allow: int = 0, deny: int = 0):
|
||||
self._allow = allow
|
||||
self._deny = deny
|
||||
|
||||
def pair(self):
|
||||
"""Returns (Permissions(allow), Permissions(deny))."""
|
||||
return BackupPermissions(self._allow), BackupPermissions(self._deny)
|
||||
|
||||
def __iter__(self):
|
||||
"""Yields (perm_name, True|False|None) for each known permission."""
|
||||
for name, bit in self.VALID_NAMES.items():
|
||||
mask = 1 << bit
|
||||
if self._allow & mask:
|
||||
yield name, True
|
||||
elif self._deny & mask:
|
||||
yield name, False
|
||||
else:
|
||||
yield name, None
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
if name.startswith("_") or name not in self.VALID_NAMES:
|
||||
super().__setattr__(name, value)
|
||||
return
|
||||
bit = self.VALID_NAMES[name]
|
||||
mask = 1 << bit
|
||||
# Clear both first
|
||||
self._allow &= ~mask
|
||||
self._deny &= ~mask
|
||||
if value is True:
|
||||
self._allow |= mask
|
||||
elif value is False:
|
||||
self._deny |= mask
|
||||
# None = neutral, both cleared
|
||||
|
||||
|
||||
class BackupOverwriteTarget:
|
||||
"""Stand-in for the target (role) key in overwrites dict.
|
||||
|
||||
Satisfies: type(target).__name__ == 'Role' and target.id
|
||||
"""
|
||||
def __init__(self, role_id: int):
|
||||
self.id = role_id
|
||||
|
||||
def __repr__(self):
|
||||
return f"Role(id={self.id})"
|
||||
|
||||
# Allow `type(target).__name__` to return "Role"
|
||||
BackupOverwriteTarget.__name__ = "Role"
|
||||
BackupOverwriteTarget.__qualname__ = "Role"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
@ -150,6 +224,17 @@ class BackupRole:
|
|||
return f"BackupRole(id={self.id}, name='{self.name}')"
|
||||
|
||||
|
||||
def _parse_overwrites(raw_list: list) -> dict:
|
||||
"""Parse overwrites JSON list into {BackupOverwriteTarget: BackupPermissionOverwrite} dict."""
|
||||
result = {}
|
||||
for entry in raw_list:
|
||||
target = BackupOverwriteTarget(int(entry["id"]))
|
||||
ow = BackupPermissionOverwrite(allow=int(entry.get("allow", 0)),
|
||||
deny=int(entry.get("deny", 0)))
|
||||
result[target] = ow
|
||||
return result
|
||||
|
||||
|
||||
class BackupCategory:
|
||||
"""Minimal stand-in for discord.CategoryChannel."""
|
||||
|
||||
|
|
@ -163,7 +248,7 @@ class BackupCategory:
|
|||
self.name = data["name"]
|
||||
self.position = data.get("position", 0)
|
||||
self.type = ChannelType.category
|
||||
self.overwrites = {}
|
||||
self.overwrites = _parse_overwrites(data.get("overwrites", []))
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"BackupCategory(id={self.id}, name='{self.name}')"
|
||||
|
|
@ -194,7 +279,7 @@ class BackupChannel:
|
|||
self.parent_id = category_id
|
||||
self.available_tags = data.get("available_tags", [])
|
||||
self.guild = guild
|
||||
self.overwrites = {}
|
||||
self.overwrites = _parse_overwrites(data.get("overwrites", []))
|
||||
|
||||
@property
|
||||
def mention(self) -> str:
|
||||
|
|
|
|||
|
|
@ -228,11 +228,23 @@ class DiscordExporter:
|
|||
cat_channels = [c for c in channels if c.category_id == cat.id]
|
||||
formatted_channels = await asyncio.gather(*[self._format_channel(c) for c in cat_channels])
|
||||
chan_count += len(formatted_channels)
|
||||
# Serialize role-only permission overwrites
|
||||
cat_overwrites = []
|
||||
for target, ow in cat.overwrites.items():
|
||||
if isinstance(target, discord.Role):
|
||||
allow, deny = ow.pair()
|
||||
cat_overwrites.append({
|
||||
"id": str(target.id),
|
||||
"allow": allow.value,
|
||||
"deny": deny.value
|
||||
})
|
||||
|
||||
structure.append({
|
||||
"type": "category",
|
||||
"id": str(cat.id),
|
||||
"name": cat.name,
|
||||
"position": cat.position,
|
||||
"overwrites": cat_overwrites,
|
||||
"channels": list(formatted_channels)
|
||||
})
|
||||
|
||||
|
|
@ -255,13 +267,25 @@ class DiscordExporter:
|
|||
return structure, cat_count, chan_count
|
||||
|
||||
async def _format_channel(self, c):
|
||||
# Serialize role-only permission overwrites
|
||||
ch_overwrites = []
|
||||
for target, ow in c.overwrites.items():
|
||||
if isinstance(target, discord.Role):
|
||||
allow, deny = ow.pair()
|
||||
ch_overwrites.append({
|
||||
"id": str(target.id),
|
||||
"allow": allow.value,
|
||||
"deny": deny.value
|
||||
})
|
||||
|
||||
data = {
|
||||
"id": str(c.id),
|
||||
"name": c.name,
|
||||
"type": str(c.type),
|
||||
"position": c.position,
|
||||
"topic": getattr(c, "topic", None),
|
||||
"nsfw": getattr(c, "nsfw", False)
|
||||
"nsfw": getattr(c, "nsfw", False),
|
||||
"overwrites": ch_overwrites
|
||||
}
|
||||
|
||||
if isinstance(c, discord.ForumChannel):
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue