preserve server strucutre order in fluxer

This commit is contained in:
rambros 2026-03-06 18:11:23 +05:30
parent 19750d2862
commit 92b73178ec
3 changed files with 29 additions and 16 deletions

View file

@ -59,8 +59,9 @@ async def migrate_channels(context: MigrationContext, progress_callback: Callabl
progress_callback: Optional callback receiving (item_name, status, current, total)
force: If True, re-create channels even if they exist in state.
"""
categories = await context.discord_reader.get_categories()
channels = await context.discord_reader.get_channels()
# Sort by position to respect Discord arrangement
categories = sorted(await context.discord_reader.get_categories(), key=lambda c: getattr(c, 'position', 0))
channels = sorted(await context.discord_reader.get_channels(), key=lambda c: getattr(c, 'position', 0))
cloned_info = {
"categories_created": [],
@ -105,7 +106,8 @@ async def migrate_channels(context: MigrationContext, progress_callback: Callabl
if not context.is_running: break
state_key = str(cat.id)
fluxer_id = await context.fluxer_writer.create_channel(cat.name, type=4)
pos = getattr(cat, 'position', None)
fluxer_id = await context.fluxer_writer.create_channel(cat.name, type=4, position=pos)
context.state.set_category_mapping(state_key, fluxer_id)
cloned_info["categories_created"].append(cat.name)
if cat.name not in cloned_info["structure"]:
@ -127,6 +129,7 @@ async def migrate_channels(context: MigrationContext, progress_callback: Callabl
logger.debug(f"Creating channel {channel.name}: topic={topic}, nsfw={nsfw}, slowmode={slowmode}")
parent_id = context.state.get_fluxer_category_id(str(channel.category_id)) if channel.category_id else None
pos = getattr(channel, 'position', None)
fluxer_id = await context.fluxer_writer.create_channel(
name=channel.name,
@ -134,7 +137,8 @@ async def migrate_channels(context: MigrationContext, progress_callback: Callabl
type=0,
parent_id=parent_id,
nsfw=nsfw,
slowmode_delay=slowmode
slowmode_delay=slowmode,
position=pos
)
context.state.set_channel_mapping(state_key, fluxer_id)
cloned_info["channels_created"].append(channel.name)
@ -151,7 +155,8 @@ async def migrate_channels(context: MigrationContext, progress_callback: Callabl
name=channel.name,
topic=topic,
nsfw=nsfw,
slowmode_delay=slowmode
slowmode_delay=slowmode,
position=pos
)
current_idx += 1
@ -169,13 +174,16 @@ async def migrate_channels(context: MigrationContext, progress_callback: Callabl
logger.debug(f"Syncing existing channel {channel.name} ({fluxer_id}): topic={topic}, nsfw={nsfw}, slowmode={slowmode}")
pos = getattr(channel, 'position', None)
await context.fluxer_writer.modify_channel(
channel_id=fluxer_id,
parent_id=parent_id,
name=channel.name,
topic=topic,
nsfw=nsfw,
slowmode_delay=slowmode
slowmode_delay=slowmode,
position=pos
)
cloned_info["channels_synced"].append(channel.name)

View file

@ -131,7 +131,8 @@ async def sync_permissions(context: MigrationContext, progress_callback: Callabl
async def migrate_roles(context: MigrationContext, progress_callback: Callable[[str, int, int], Awaitable[None]] | None = None, force: bool = False) -> list[str]:
"""Copies roles and their baseline permissions. Returns a list of cloned role names."""
roles = await context.discord_reader.get_roles()
# Sort roles by position to respect Discord hierarchy
roles = sorted(await context.discord_reader.get_roles(), key=lambda r: r.position)
if not force:
roles = [r for r in roles if not context.state.get_fluxer_role_id(str(r.id))]
@ -151,7 +152,8 @@ async def migrate_roles(context: MigrationContext, progress_callback: Callable[[
name=role.name,
color=role.color.value,
hoist=role.hoist,
mentionable=role.mentionable
mentionable=role.mentionable,
position=role.position
)
if fluxer_id:
context.state.set_role_mapping(str(role.id), fluxer_id)

View file

@ -167,14 +167,14 @@ class FluxerWriter:
"permissions": permissions
}
async def create_channel(self, name: str, topic: str = "", type: int = 0, parent_id: Optional[str] = None, nsfw: bool = False, slowmode_delay: int = 0) -> str:
async def create_channel(self, name: str, topic: str = "", type: int = 0, parent_id: Optional[str] = None, nsfw: bool = False, slowmode_delay: int = 0, position: Optional[int] = None) -> str:
"""
Creates a new channel in the target Fluxer community.
Returns the new Fluxer channel ID.
"""
assert self.client is not None
logger.debug(f"Fluxer: Creating channel {name} (type {type}) with topic='{topic}', nsfw={nsfw}, slowmode={slowmode_delay}")
logger.debug(f"Fluxer: Creating channel {name} (type {type}) with topic='{topic}', nsfw={nsfw}, slowmode={slowmode_delay}, position={position}")
guild_channel = await self.client.create_guild_channel(
guild_id=self.community_id,
@ -183,17 +183,18 @@ class FluxerWriter:
topic=topic or None,
parent_id=parent_id,
nsfw=nsfw,
rate_limit_per_user=slowmode_delay
rate_limit_per_user=slowmode_delay,
position=position
)
return str(guild_channel["id"])
async def modify_channel(self, channel_id: str, parent_id: Optional[str] = None, name: Optional[str] = None, topic: Optional[str] = None, nsfw: Optional[bool] = None, slowmode_delay: Optional[int] = None) -> bool:
async def modify_channel(self, channel_id: str, parent_id: Optional[str] = None, name: Optional[str] = None, topic: Optional[str] = None, nsfw: Optional[bool] = None, slowmode_delay: Optional[int] = None, position: Optional[int] = None) -> bool:
"""
Updates channel properties.
"""
assert self.client is not None
logger.debug(f"Fluxer: Modifying channel {channel_id}: name={name}, topic='{topic}', parent_id={parent_id}, nsfw={nsfw}, slowmode={slowmode_delay}")
logger.debug(f"Fluxer: Modifying channel {channel_id}: name={name}, topic='{topic}', parent_id={parent_id}, nsfw={nsfw}, slowmode={slowmode_delay}, position={position}")
try:
await self.client.modify_channel(
@ -202,7 +203,8 @@ class FluxerWriter:
topic=topic,
parent_id=parent_id,
nsfw=nsfw,
rate_limit_per_user=slowmode_delay
rate_limit_per_user=slowmode_delay,
position=position
)
except Forbidden as e:
if getattr(e, 'code', None) == "NSFW_CONTENT_AGE_RESTRICTED":
@ -318,7 +320,7 @@ class FluxerWriter:
print(f"Failed to send marker: {e}")
return None
async def create_role(self, name: str, color: int, hoist: bool, mentionable: bool) -> str:
async def create_role(self, name: str, color: int, hoist: bool, mentionable: bool, position: Optional[int] = None) -> str:
"""
Creates a new role in the Fluxer community.
Returns the new Fluxer role ID.
@ -331,7 +333,8 @@ class FluxerWriter:
name=name,
color=color,
hoist=hoist,
mentionable=mentionable
mentionable=mentionable,
position=position
)
return str(role["id"])
except Exception as e: