mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-06 03:38:23 +00:00
fix(concord): Make/Remove admin keep the member's other roles
A Grant replaces the member's whole role set, but Make admin granted only the Admin role and Remove admin granted none, so both silently stripped every other role the member held — a private channel's access role included — and neither rotated that channel's key afterwards, leaving the member able to read it. Make admin now adds Admin to the member's current roles and Remove admin drops only Admin; both reconcile private-channel access like the Roles dialog does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
1d0390b609
commit
1a821544f5
+17
-5
@@ -1618,7 +1618,11 @@ class AccountConcordActions(
|
||||
return Triple(communityId, author, isAdmin)
|
||||
}
|
||||
|
||||
/** Promote [member] to the community Admin role, defining that role first if it doesn't exist yet. */
|
||||
/**
|
||||
* Promote [member] to the community Admin role, defining that role first if it doesn't exist
|
||||
* yet. A Grant replaces the member's whole role set, so Admin is added to the roles they already
|
||||
* hold — granting it alone would silently strip, say, a private channel's access role.
|
||||
*/
|
||||
suspend fun makeConcordAdmin(
|
||||
communityId: String,
|
||||
member: HexKey,
|
||||
@@ -1626,6 +1630,7 @@ class AccountConcordActions(
|
||||
val session = account.concordSessions.sessionFor(communityId) ?: return false
|
||||
if (!account.isWriteable()) return false
|
||||
val cp = controlKeysForAction(session, ConcordPermissions.MANAGE_ROLES, member) ?: return false
|
||||
val before = session.state.value?.authority
|
||||
|
||||
val existing =
|
||||
session.state.value
|
||||
@@ -1656,7 +1661,7 @@ class AccountConcordActions(
|
||||
controlPlane = cp,
|
||||
communityId = communityId.hexToByteArray(),
|
||||
member = member,
|
||||
roleIds = listOf(roleIdHex),
|
||||
roleIds = (before?.rolesOf(member).orEmpty() + roleIdHex).toList(),
|
||||
current = session.controlEditions(),
|
||||
createdAt = TimeUtils.now(),
|
||||
owner = session.entry.owner,
|
||||
@@ -1664,10 +1669,11 @@ class AccountConcordActions(
|
||||
epoch = session.entry.rootEpoch,
|
||||
)
|
||||
publishConcordWrap(session.entry, grantWrap)
|
||||
reconcileConcordChannelAccess(communityId, before)
|
||||
return true
|
||||
}
|
||||
|
||||
/** Revoke all roles from [member] (demote an admin back to a plain member). */
|
||||
/** Take the Admin role away from [member], keeping every other role they hold (e.g. a channel's access role). */
|
||||
suspend fun removeConcordAdmin(
|
||||
communityId: String,
|
||||
member: HexKey,
|
||||
@@ -1675,8 +1681,14 @@ class AccountConcordActions(
|
||||
val session = account.concordSessions.sessionFor(communityId) ?: return false
|
||||
if (!account.isWriteable()) return false
|
||||
val cp = controlKeysForAction(session, ConcordPermissions.MANAGE_ROLES, member) ?: return false
|
||||
val before = session.state.value?.authority
|
||||
val grantWrap = ConcordModeration.grant(account.signer, cp, communityId.hexToByteArray(), member, emptyList(), session.controlEditions(), TimeUtils.now(), owner = session.entry.owner)
|
||||
val state = session.state.value ?: return false
|
||||
val before = state.authority
|
||||
val adminRoleIds =
|
||||
state.roles.entries
|
||||
.filter { it.value.name == CONCORD_ADMIN_ROLE && it.value.position == 1L }
|
||||
.mapTo(HashSet()) { it.key }
|
||||
val kept = before.rolesOf(member) - adminRoleIds
|
||||
val grantWrap = ConcordModeration.grant(account.signer, cp, communityId.hexToByteArray(), member, kept.toList(), session.controlEditions(), TimeUtils.now(), owner = session.entry.owner)
|
||||
publishConcordWrap(session.entry, grantWrap)
|
||||
reconcileConcordChannelAccess(communityId, before)
|
||||
return true
|
||||
|
||||
Reference in New Issue
Block a user