Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions digletbot.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ ROLE_ALBION_US_REGISTERED=12345
ROLE_ALBION_EU_REGISTERED=12345
ROLE_ALBION_US_ANNOUNCEMENTS=12345
ROLE_ALBION_EU_ANNOUNCEMENTS=12345
# Comma separated IDs of the pings embeds in CHANNEL_ALBION_EU_ROLES (content pings and guild
# pings). Their ALB/ role names drive the sweep; leave unset to disable the sweep entirely.
MESSAGE_ALBION_PINGS=12345,67890
# Comma separated role IDs that keep ping roles without an Albion registration (alliance).
ALBION_PING_ROLE_EXEMPT_ROLES=12345,67890

# PS2 Channels & Roles
CHANNEL_PS2_VERIFY=1234567
Expand Down
2 changes: 2 additions & 0 deletions src/albion/albion.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { AlbionRegistrationService } from './services/albion.registration.servic
import { DiscordModule } from '../discord/discord.module';
import { AlbionScanningService } from './services/albion.scanning.service';
import { AlbionScanCommand } from './commands/scan.command';
import { AlbionPingRoleService } from './services/albion.ping.role.service';
import { AlbionCronService } from './services/albion.cron.service';
import { AlbionUtilities } from './utilities/albion.utilities';
import { AlbionLogCommand } from './commands/log.command';
Expand All @@ -29,6 +30,7 @@ import { GeneralModule } from '../general/general.module';
imports: [ConfigModule, DatabaseModule, DiscordModule, GeneralModule],
providers: [
AlbionApiService,
AlbionPingRoleService,
AlbionCronService,
AlbionDeregisterCommand,
AlbionDeregistrationService,
Expand Down
43 changes: 43 additions & 0 deletions src/albion/services/albion.deregistration.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { EntityRepository } from '@mikro-orm/core';
import { AlbionDeregistrationService } from './albion.deregistration.service';
import { DiscordService } from '../../discord/discord.service';
import { AlbionDeregisterDto } from '../dto/albion.deregister.dto';
import { AlbionPingRoleService } from './albion.ping.role.service';
import { Role } from 'discord.js';

let mockAlbionRegistrationsRepository: jest.Mocked<EntityRepository<AlbionRegistrationsEntity>>;
Expand All @@ -22,6 +23,7 @@ describe('AlbionDeregistrationService', () => {
let service: AlbionDeregistrationService;
let discordService: jest.Mocked<DiscordService>;
let configService: jest.Mocked<ConfigService>;
let albionPingRoleService: jest.Mocked<AlbionPingRoleService>;

beforeEach(async () => {
mockCharacter = TestBootstrapper.getMockAlbionCharacter();
Expand Down Expand Up @@ -59,6 +61,12 @@ describe('AlbionDeregistrationService', () => {
getRoleViaMember: jest.fn(),
},
},
{
provide: AlbionPingRoleService,
useValue: {
stripForDeregistration: jest.fn(),
},
},
{
provide: getRepositoryToken(AlbionRegistrationsEntity),
useValue: mockAlbionRegistrationsRepository,
Expand All @@ -71,6 +79,7 @@ describe('AlbionDeregistrationService', () => {
service = moduleRef.get<AlbionDeregistrationService>(AlbionDeregistrationService);
discordService = moduleRef.get(DiscordService) as any;
configService = moduleRef.get(ConfigService) as any;
albionPingRoleService = moduleRef.get(AlbionPingRoleService) as any;

// Ensure albion.roleMap + devUserId available for role stripping tests
(configService.get as jest.Mock).mockImplementation((key: string) => {
Expand Down Expand Up @@ -174,6 +183,40 @@ describe('AlbionDeregistrationService', () => {
expect(stripRolesSpy).not.toHaveBeenCalled();
});

it('should strip ping roles and reactions for the member', async () => {
const dto: AlbionDeregisterDto = { discordMember: mockDiscordMember.user };

await service.deregister(mockChannel, dto);

expect(albionPingRoleService.stripForDeregistration).toHaveBeenCalledWith(
mockRegistration.discordId,
mockDiscordMember,
mockChannel,
);
});

it('should still clear ping reactions when the member has left the server', async () => {
const dto: AlbionDeregisterDto = { discordMember: mockDiscordMember.user };
discordService.getGuildMember.mockRejectedValueOnce(new Error('Gone'));

await service.deregister(mockChannel, dto);

expect(albionPingRoleService.stripForDeregistration).toHaveBeenCalledWith(
mockRegistration.discordId,
null,
mockChannel,
);
});

it('should not strip ping roles when there was no registration to remove', async () => {
const dto: AlbionDeregisterDto = { discordMember: mockDiscordMember.user };
mockAlbionRegistrationsRepository.findOne.mockResolvedValueOnce(null);

await service.deregister(mockChannel, dto);

expect(albionPingRoleService.stripForDeregistration).not.toHaveBeenCalled();
});

it('should skip role stripping if member fetch fails (character path)', async () => {
const dto: AlbionDeregisterDto = { character: mockRegistration.characterName };
mockAlbionRegistrationsRepository.findOne.mockResolvedValueOnce(mockRegistration);
Expand Down
10 changes: 10 additions & 0 deletions src/albion/services/albion.deregistration.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { GuildMember, GuildTextBasedChannel } from 'discord.js';
import { AlbionRoleMapInterface } from '../../config/albion.app.config';
import { DiscordService } from '../../discord/discord.service';
import { AlbionDeregisterDto } from '../dto/albion.deregister.dto';
import { AlbionPingRoleService } from './albion.ping.role.service';

@Injectable()
export class AlbionDeregistrationService {
Expand All @@ -15,6 +16,7 @@ export class AlbionDeregistrationService {
constructor(
private readonly config: ConfigService,
private readonly discordService: DiscordService,
private readonly albionPingRoleService: AlbionPingRoleService,
@InjectRepository(AlbionRegistrationsEntity) private readonly albionRegistrationsRepository: EntityRepository<AlbionRegistrationsEntity>,
) {
}
Expand Down Expand Up @@ -67,6 +69,14 @@ export class AlbionDeregistrationService {

await this.stripRegistration(registration, responseChannel);

// Runs whether or not they're still on the server: their reactions on the content pings
// message outlive them, and Discord never prunes reactions of people who have left.
await this.albionPingRoleService.stripForDeregistration(
registration.discordId,
discordMember,
responseChannel,
);

if (!discordMember) {
const error = `Discord Member with ID "${registration.discordId}" not found in Discord! They have likely left the server, so no roles can be stripped.`;
this.logger.warn(error);
Expand Down
Loading