mirror of
https://github.com/whekin/household-bot.git
synced 2026-03-31 17:44:03 +00:00
feat(bot): add safe group unsetup flow
This commit is contained in:
@@ -60,6 +60,7 @@ function createRepositoryStub() {
|
||||
getHouseholdTopicBinding: async () => null,
|
||||
findHouseholdTopicByTelegramContext: async () => null,
|
||||
listHouseholdTopicBindings: async () => [],
|
||||
clearHouseholdTopicBindings: async () => {},
|
||||
listReminderTargets: async () => [],
|
||||
upsertHouseholdJoinToken: async (input) =>
|
||||
({
|
||||
|
||||
@@ -55,6 +55,7 @@ function createRepositoryStub() {
|
||||
async listHouseholdTopicBindings() {
|
||||
return []
|
||||
},
|
||||
async clearHouseholdTopicBindings() {},
|
||||
async listReminderTargets() {
|
||||
return []
|
||||
},
|
||||
|
||||
@@ -93,6 +93,9 @@ function createRepositoryStub() {
|
||||
async listHouseholdTopicBindings(householdId) {
|
||||
return bindings.get(householdId) ?? []
|
||||
},
|
||||
async clearHouseholdTopicBindings(householdId) {
|
||||
bindings.set(householdId, [])
|
||||
},
|
||||
async listReminderTargets() {
|
||||
return []
|
||||
},
|
||||
@@ -514,4 +517,56 @@ describe('createHouseholdSetupService', () => {
|
||||
reason: 'not_topic_message'
|
||||
})
|
||||
})
|
||||
|
||||
test('clears topic bindings when unsetup is run by a group admin', async () => {
|
||||
const { repository } = createRepositoryStub()
|
||||
const service = createHouseholdSetupService(repository)
|
||||
const setup = await service.setupGroupChat({
|
||||
actorIsAdmin: true,
|
||||
telegramChatId: '-100123',
|
||||
telegramChatType: 'supergroup',
|
||||
title: 'Kojori House'
|
||||
})
|
||||
|
||||
expect(setup.status).toBe('created')
|
||||
if (setup.status === 'rejected') {
|
||||
return
|
||||
}
|
||||
|
||||
await service.bindTopic({
|
||||
actorIsAdmin: true,
|
||||
telegramChatId: '-100123',
|
||||
role: 'purchase',
|
||||
telegramThreadId: '777',
|
||||
topicName: 'Shared purchases'
|
||||
})
|
||||
|
||||
const result = await service.unsetupGroupChat({
|
||||
actorIsAdmin: true,
|
||||
telegramChatId: '-100123',
|
||||
telegramChatType: 'supergroup'
|
||||
})
|
||||
|
||||
expect(result).toEqual({
|
||||
status: 'reset',
|
||||
household: setup.household
|
||||
})
|
||||
expect(await repository.listHouseholdTopicBindings(setup.household.householdId)).toEqual([])
|
||||
expect(await repository.getTelegramHouseholdChat('-100123')).toEqual(setup.household)
|
||||
})
|
||||
|
||||
test('treats repeated unsetup as a no-op', async () => {
|
||||
const { repository } = createRepositoryStub()
|
||||
const service = createHouseholdSetupService(repository)
|
||||
|
||||
const result = await service.unsetupGroupChat({
|
||||
actorIsAdmin: true,
|
||||
telegramChatId: '-100123',
|
||||
telegramChatType: 'supergroup'
|
||||
})
|
||||
|
||||
expect(result).toEqual({
|
||||
status: 'noop'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -41,6 +41,23 @@ export interface HouseholdSetupService {
|
||||
reason: 'not_admin' | 'household_not_found' | 'not_topic_message'
|
||||
}
|
||||
>
|
||||
unsetupGroupChat(input: {
|
||||
actorIsAdmin: boolean
|
||||
telegramChatId: string
|
||||
telegramChatType: string
|
||||
}): Promise<
|
||||
| {
|
||||
status: 'reset'
|
||||
household: HouseholdTelegramChatRecord
|
||||
}
|
||||
| {
|
||||
status: 'noop'
|
||||
}
|
||||
| {
|
||||
status: 'rejected'
|
||||
reason: 'not_admin' | 'invalid_chat_type'
|
||||
}
|
||||
>
|
||||
}
|
||||
|
||||
function isSupportedGroupChat(chatType: string): boolean {
|
||||
@@ -146,6 +163,36 @@ export function createHouseholdSetupService(
|
||||
household,
|
||||
binding
|
||||
}
|
||||
},
|
||||
|
||||
async unsetupGroupChat(input) {
|
||||
if (!input.actorIsAdmin) {
|
||||
return {
|
||||
status: 'rejected',
|
||||
reason: 'not_admin'
|
||||
}
|
||||
}
|
||||
|
||||
if (!isSupportedGroupChat(input.telegramChatType)) {
|
||||
return {
|
||||
status: 'rejected',
|
||||
reason: 'invalid_chat_type'
|
||||
}
|
||||
}
|
||||
|
||||
const household = await repository.getTelegramHouseholdChat(input.telegramChatId)
|
||||
if (!household) {
|
||||
return {
|
||||
status: 'noop'
|
||||
}
|
||||
}
|
||||
|
||||
await repository.clearHouseholdTopicBindings(household.householdId)
|
||||
|
||||
return {
|
||||
status: 'reset',
|
||||
household
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ function createRepository(): HouseholdConfigurationRepository {
|
||||
getHouseholdTopicBinding: async () => null,
|
||||
findHouseholdTopicByTelegramContext: async () => null,
|
||||
listHouseholdTopicBindings: async () => [],
|
||||
clearHouseholdTopicBindings: async () => {},
|
||||
listReminderTargets: async () => [],
|
||||
upsertHouseholdJoinToken: async () => ({
|
||||
householdId: household.householdId,
|
||||
|
||||
@@ -35,6 +35,7 @@ function repository(): HouseholdConfigurationRepository {
|
||||
topicName: 'Общие покупки'
|
||||
}
|
||||
],
|
||||
clearHouseholdTopicBindings: async () => {},
|
||||
listReminderTargets: async () => [],
|
||||
upsertHouseholdJoinToken: async () => ({
|
||||
householdId: 'household-1',
|
||||
|
||||
Reference in New Issue
Block a user