Commit 9524ea1e authored by nanahira's avatar nanahira

group allow

parent 0fbf86e0
Pipeline #3108 passed with stages
in 3 minutes and 49 seconds
......@@ -45,3 +45,15 @@ defaultTemplateMap.set('bad_params', BadParamsText);
export const AdminQuitGroup = `已退出群 {{groupId}}。`;
defaultTemplateMap.set('admin_quit_group', AdminQuitGroup);
export const WelcomeMessageDemo = `本群的欢迎信息是:\n{{&message}}\n\n示例:\n{{&demo}}`;
defaultTemplateMap.set('welcome_message_demo', WelcomeMessageDemo);
export const WelcomeMessageNotFound = `本群没有设置欢迎信息。\n使用 .group.welcome <信息> 来设置一个。`;
defaultTemplateMap.set('welcome_message_not_found', WelcomeMessageNotFound);
export const WelcomeMessageSet = `已经设置群欢迎信息为 {{&message}}`;
defaultTemplateMap.set('welcome_message_set', WelcomeMessageSet);
export const GroupAllowSet = `已经设置群 {{groupId}} 可加入状态为 {{value}}。`;
defaultTemplateMap.set('group_allow_set', GroupAllowSet);
......@@ -90,16 +90,26 @@ export class AppService {
return profile;
}
async checkJoinGroup(userId: string) {
const user = await this.botService.findOrCreateUser(userId);
this.log.log(`Bot being invited by ${user.name} ${userId}`);
async checkJoinGroup(userData: KoishiSessionLike) {
this.log.log(
`Bot being invited to ${userData.groupId} by ${userData.username} ${userData.userId}`,
);
const { user, group, profile, banReason } = await this.getDatabaseUserData(
userData,
);
if (banReason) {
this.log.log(`Bot rejected because of: ${banReason}.`);
return false;
}
if (group && group.allowedToJoin) {
this.log.log(`Bot accepted for being allowed.`);
return true;
}
if (user.checkPermissions(UserPermissions.inviteBot)) {
this.log.log(`Bot accepted.`);
this.log.log(`Bot accepted for admin.`);
return true;
} else if (user.banReason) {
this.log.log(`Bot rejected because of banned user: ${user.banReason}.`);
return false;
}
this.log.log(`Bot ignored.`);
return undefined;
}
......@@ -452,4 +462,63 @@ export class AppService {
)
).join('\n----------\n');
}
async getWelcomeMessage(userData: KoishiSessionLike) {
const { user, group, profile, banReason } = await this.getDatabaseUserData(
userData,
);
if (banReason) {
return await this.renderTemplate('bad_user', { reason: banReason });
}
if (group.welcomeMessage) {
return await this.renderTemplate(
'welcome_message_demo',
{ message: group.welcomeMessage, demo: group.welcomeUser(user) },
userData.groupId,
);
} else {
return await this.renderTemplate(
'welcome_message_not_found',
{},
userData.groupId,
);
}
}
async setWelcomeMessage(userData: KoishiSessionLike, message: string) {
const { user, group, profile, banReason } = await this.getDatabaseUserData(
userData,
);
if (banReason) {
return await this.renderTemplate('bad_user', { reason: banReason });
}
group.setWelcomeMessage(message);
await this.db.getRepository(Group).save(group);
return await this.renderTemplate(
'welcome_message_set',
{ message },
userData.groupId,
);
}
async handleWelcome(userData: KoishiSessionLike) {
const { user, group, profile, banReason } = await this.getDatabaseUserData(
userData,
);
if (banReason) {
return null;
}
return group.welcomeUser(user);
}
async setGroupAllow(
userData: KoishiSessionLike,
groupId: string,
value: number,
) {
const { user, banReason } = await this.getDatabaseUserData(userData);
if (banReason) {
return await this.renderTemplate('bad_user', { reason: banReason });
}
const group = await this.botService.findOrCreateGroup(groupId);
group.allowedToJoin = value;
await this.db.getRepository(Group).save(group);
return await this.renderTemplate('group_allow_set', { groupId, value });
}
}
......@@ -32,8 +32,7 @@ export class BotController {
this.bot.plugin(koishiCommonPlugin, {
onFriendRequest: true,
onGroupRequest: async (session) => {
const userId = session.userId;
return await this.appService.checkJoinGroup(userId);
return await this.appService.checkJoinGroup(session);
},
});
this.loadBotRouters();
......@@ -64,6 +63,17 @@ export class BotController {
}
return next();
});
groupCtx.on('group-member-added', async (session) => {
const messageToSend = await this.appService.handleWelcome(session);
if (messageToSend) {
this.botService.log.log(
`${session.userId} ${session.username} joined group ${session.groupId} => ${messageToSend}`,
);
await session.send(
`${segment('at', { id: session.userId })} ${messageToSend}`,
);
}
});
globalCtx
.command('rolldice', '投掷骰子')
.option('count', '-c <count:posint> 骰子数量', { fallback: 1 })
......@@ -84,28 +94,52 @@ export class BotController {
return await this.appService.rollDice(rollResult, session);
});
const groupCommand = groupCtx.command('group', '群内指令');
groupCtx
.command('dismiss', '退群,请使用这个命令,而不是踢我出去。')
.usage('只有管理员可以操作。群内数据会保留。')
.action(async (argv) => {
const session = argv.session;
return await this.processDismissCommand(session);
});
groupCommand
.subcommand('.dismiss', '退群')
.usage('群内数据会保留。')
.alias('dismiss')
.usage('只有管理员可以操作。群内数据会保留。')
.action(async (argv) => {
const session = argv.session;
return await this.processDismissCommand(session);
});
groupCommand
.subcommand('.welcome [message:text]', '设置群欢迎消息')
.usage(
'只有管理员可以操作。新人加入的时候会自动发送。允许使用模板。设置为 null 则清除。',
)
.alias('welcome')
.action(async (argv, message) => {
const session = argv.session;
if (!message || message === 'get') {
const ret = await this.appService.getWelcomeMessage(session);
return `${segment('at', {
id: session.userId,
})} ${ret}`;
}
if (
!(await this.checkGroupAdminOrPermission(
session,
UserPermissions.GroupDismiss,
UserPermissions.GroupTemplateRead,
))
) {
return `${segment('at', {
id: session.userId,
})} ${await this.appService.renderTemplate(
'permission_denied',
{ action: '退群' },
{ action: '设置群欢迎消息' },
session.groupId,
)}`;
}
await this.groupDismiss(session.groupId);
return undefined;
const ret = await this.appService.setWelcomeMessage(session, message);
return `${segment('at', {
id: session.userId,
})} ${ret}`;
});
const groupTemplateCommand = groupCommand
.subcommand('.template', '获取本群自定义模板')
......@@ -216,7 +250,7 @@ export class BotController {
return `${segment('at', { id: session.userId })} ${ret}`;
});
const groupUserCommand = groupCommand
.subcommand('.user [field:text]', '查看群内用户信息')
.subcommand('.user [field:string]', '查看群内用户信息')
.usage('带参数查看其他人的用户信息,但是只有管理员可以用。')
.example(
'.user 查看自己的用户信息。.user Nanahira 查看 Nanahira 的用户信息。',
......@@ -255,7 +289,7 @@ export class BotController {
return `${segment('at', { id: session.userId })} ${ret}`;
});
const userCommand = globalCtx
.command('account [field:text]', '查看用户信息')
.command('account [field:string]', '查看用户信息')
.usage('带参数查看其他人的用户信息,但是只有管理员可以用。')
.example(
'.account 查看自己的用户信息。.account Nanahira 查看 Nanahira 的用户信息。',
......@@ -325,6 +359,34 @@ export class BotController {
session.groupId,
);
});
adminCommand
.subcommand('.join <groupId:string>', '设置允许加入指定群')
.usage('并不会主动加群,但是允许被邀请的时候加群。')
.option('value', '-v <value:integer>', { fallback: 1 })
.option('value', '--disable', { value: 0 })
.action(async (argv, groupId) => {
const session = argv.session;
const value = argv.options.value;
if (
!(await this.checkUserPermission(session, UserPermissions.inviteBot))
) {
return `${segment('at', {
id: session.userId,
})} ${await this.appService.renderTemplate(
'permission_denied',
{ action: '设置允许加入指定群' },
session.groupId,
)}`;
}
if (!groupId) {
return await this.appService.renderTemplate(
'bad_params',
{},
session.groupId,
);
}
return await this.appService.setGroupAllow(session, groupId, value);
});
const adminTemplateCommand = adminCommand
.subcommand('.template', '获取默认模板')
.usage(
......@@ -491,6 +553,42 @@ export class BotController {
getBot() {
return (this.bot.bots[0] as unknown) as CQBot;
}
async processDismissCommand(
session: Session<
never,
never,
'onebot',
keyof Session.Events,
| keyof Session.MessageType
| 'role'
| 'ban'
| keyof Session.GroupMemberChangeType
| 'poke'
| 'lucky-king'
| 'honor'
>,
) {
if (
!(await this.checkUserPermission(session, UserPermissions.GroupDismiss))
) {
if (
!(await this.checkGroupAdminOrPermission(
session,
UserPermissions.GroupDismiss,
))
) {
return `${segment('at', {
id: session.userId,
})} ${await this.appService.renderTemplate(
'permission_denied',
{ action: '退群' },
session.groupId,
)}`;
}
await this.groupDismiss(session.groupId);
return undefined;
}
}
async groupDismiss(groupId: string) {
try {
await this.getBot().$setGroupLeave(groupId, false);
......
......@@ -9,6 +9,7 @@ export const UserPermissions = {
GroupUserWrite: 0x200,
TemplateWrite: 0x400,
GroupTemplateWrite: 0x800,
GroupWelcomeMessage: 0x1000,
// others
inviteBot: 0x10000,
GroupDismiss: 0x20000,
......
......@@ -2,6 +2,9 @@ import { QQIDBase } from './QQIDBase';
import { Column, Entity, OneToMany } from 'typeorm';
import { GroupTemplate } from './GroupTemplate';
import { GroupUserProfile } from './GroupUserProfile';
import he from 'he';
import { User } from './User';
import Mustache from 'mustache';
@Entity()
export class Group extends QQIDBase {
......@@ -11,6 +14,27 @@ export class Group extends QQIDBase {
@OneToMany((type) => GroupUserProfile, (profile) => profile.group)
userProfiles: GroupUserProfile[];
@Column('text', { nullable: true })
welcomeMessage: string;
@Column('tinyint', { default: 0 })
allowedToJoin: number;
setWelcomeMessage(message: string) {
if (!message || message === 'null') {
this.welcomeMessage = null;
} else {
this.welcomeMessage = he.decode(message);
}
}
welcomeUser(user: User) {
if (!this.welcomeMessage) {
return null;
}
return Mustache.render(this.welcomeMessage, user);
}
renderText(key: string, data: any) {
const template = this.templates.find((t) => key === t.key);
if (this.templates) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment