mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-11-01 11:22:28 +00:00
mcp: promote only the first joiner to owner
This commit is contained in:
1 parent
65d206c992
commit
efa31b460e
3 files changed
+28
-5
No files matched your search
@@ -66,6 +66,7 @@ export class Control implements Pick<ActionHooks, "refusal" | "saveCounter" | "p
|
||||
private members: T.GroupMember[] = []
|
||||
private writes: Promise<unknown> = Promise.resolve()
|
||||
private ownerCommands: Promise<unknown> = Promise.resolve()
|
||||
private events: Promise<unknown> = Promise.resolve()
|
||||
private linkText?: string
|
||||
|
||||
constructor(
|
||||
@@ -146,12 +147,18 @@ export class Control implements Pick<ActionHooks, "refusal" | "saveCounter" | "p
|
||||
.catch(error => logError("Main group command", error))
|
||||
}
|
||||
|
||||
async onEvent(event: ChatEvent): Promise<void> {
|
||||
onEvent(event: ChatEvent): Promise<void> {
|
||||
const handled = this.events.then(() => this.handleEvent(event))
|
||||
this.events = handled.catch(() => undefined)
|
||||
return handled
|
||||
}
|
||||
|
||||
private async handleEvent(event: ChatEvent): Promise<void> {
|
||||
if (this.actions.lost) return
|
||||
if (losesControl(event)) return this.lose()
|
||||
const before = this.approvers()
|
||||
await this.refreshMembers()
|
||||
if (event.type === "joinedGroupMember" && this.isHuman(event.member)) return this.ownerJoined(event.member)
|
||||
if (event.type === "joinedGroupMember" && this.isHuman(event.member) && this.approvers().length === 0) return this.ownerJoined(event.member)
|
||||
if (before.length > 0 && this.approvers().length === 0) {
|
||||
log(noOwners)
|
||||
await this.openLink()
|
||||
@@ -230,8 +237,9 @@ export class Control implements Pick<ActionHooks, "refusal" | "saveCounter" | "p
|
||||
|
||||
private async revoke(target: ChatTarget): Promise<string> {
|
||||
const view = this.sessions.get(target.session)
|
||||
const chatInfo = view === undefined ? undefined : await agentChat(view, target.chat)
|
||||
if (view === undefined || chatInfo === undefined || approvalOf(customDataOf(chatInfo)) === undefined) return `Messages to ${targetText(target)} have no standing approval.`
|
||||
if (view === undefined) return noSession(target.session)
|
||||
const chatInfo = await agentChat(view, target.chat)
|
||||
if (chatInfo === undefined || approvalOf(customDataOf(chatInfo)) === undefined) return `Messages to ${targetText(target)} have no standing approval.`
|
||||
const {simplexMcp, ...customData} = customDataOf(chatInfo) as {simplexMcp: unknown}
|
||||
await setCustomData(view.chat, target.chat, customData)
|
||||
return `Messages to ${chatName(chatSubject(chatInfo))} (${targetText(target)}) need approval again.`
|
||||
|
||||
@@ -237,7 +237,7 @@ describe("approval of all messages to a chat", () => {
|
||||
const {contact: directory} = chatInfoOf(chat, "@4") as T.ChatInfo.Direct
|
||||
directory.customData = {other: 1}
|
||||
await control.ownerCommand(alice, {keyword: "approve", params: "1:@4 all"})
|
||||
expect(await control.ownerCommand(alice, {keyword: "revoke", params: "2:@4"})).toBe("Messages to 2:@4 have no standing approval.")
|
||||
expect(await control.ownerCommand(alice, {keyword: "revoke", params: "2:@4"})).toBe("No open session 2. /list shows the open sessions.")
|
||||
expect(await control.ownerCommand(alice, {keyword: "revoke", params: "1:@4"})).toBe("Messages to bot SimpleX Directory (1:@4) need approval again.")
|
||||
expect(customDataOf(chat, "@4")).toEqual({other: 1})
|
||||
expect(control.standingApprover(chatInfoOf(chat, "@4"))).toBeUndefined()
|
||||
@@ -622,6 +622,20 @@ describe("sessions in the Main group", () => {
|
||||
expect(control.link).toBeUndefined()
|
||||
})
|
||||
|
||||
it("makes only the first of two people who join in a row the owner", async () => {
|
||||
const chat = agentChats()
|
||||
chat.members.set(10, [self])
|
||||
const {control} = await controlWith(chat, actionsWith("requests", fakeHooks()))
|
||||
await control.start()
|
||||
const carol = member(9, "Carol", T.GroupMemberRole.Member)
|
||||
const dave = member(11, "Dave", T.GroupMemberRole.Member)
|
||||
chat.members.set(10, [self, carol, dave])
|
||||
const joined = (joiner: T.GroupMember) => control.onEvent({type: "joinedGroupMember", user, groupInfo: group(10, "SimpleX MCP"), member: joiner} as unknown as ChatEvent)
|
||||
await Promise.all([joined(carol), joined(dave)])
|
||||
expect(chat.roles).toEqual([{groupId: 10, members: [9], role: T.GroupMemberRole.Owner}])
|
||||
expect(control.owners()).toEqual(["Carol"])
|
||||
})
|
||||
|
||||
it("opens a new link when the last owner leaves", async () => {
|
||||
const {control, chat} = await setup()
|
||||
chat.members.set(10, [self, bob])
|
||||
|
||||
@@ -202,6 +202,7 @@ export class FakeChat {
|
||||
|
||||
async apiSetMembersRole(groupId: number, members: number[], role: T.GroupMemberRole): Promise<void> {
|
||||
this.roles.push({groupId, members, role})
|
||||
this.members.set(groupId, (this.members.get(groupId) ?? []).map(m => (members.includes(m.groupMemberId) ? {...m, memberRole: role} : m)))
|
||||
}
|
||||
|
||||
async apiNewGroup(userId: number, groupProfile: T.GroupProfile): Promise<T.GroupInfo> {
|
||||
|
||||
Reference in new issue
Block a user