Skip to content

Commit

Permalink
add plugin: admin
Browse files Browse the repository at this point in the history
  • Loading branch information
RicheyJang committed Feb 4, 2022
1 parent fbbdddf commit cfa3d0e
Show file tree
Hide file tree
Showing 4 changed files with 251 additions and 32 deletions.
1 change: 1 addition & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (

// 普通插件
_ "github.com/RicheyJang/PaimengBot/plugins/COVID"
_ "github.com/RicheyJang/PaimengBot/plugins/admin"
_ "github.com/RicheyJang/PaimengBot/plugins/chat"
_ "github.com/RicheyJang/PaimengBot/plugins/contact"
_ "github.com/RicheyJang/PaimengBot/plugins/echo"
Expand Down
187 changes: 187 additions & 0 deletions plugins/admin/init.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
package admin

import (
"fmt"
"regexp"
"strconv"
"strings"
"time"

"github.com/RicheyJang/PaimengBot/manager"
"github.com/RicheyJang/PaimengBot/utils"
"github.com/RicheyJang/PaimengBot/utils/rules"

log "github.com/sirupsen/logrus"
"github.com/spf13/cast"
zero "github.com/wdvxdr1123/ZeroBot"
)

var info = manager.PluginInfo{
Name: "群管理",
Classify: "群功能",
Usage: `用法:(需要设为管理员)
踢了 [QQ号或@]:并在后续询问中答复"是",则将指定QQ号或@的人踢出本群
禁言 [QQ号或@] [时长]:将指定QQ号或@的人指定时长(时长为0则解除禁言)
另外,回复某条消息"禁言 [时长]",则可以将原消息发送者禁言指定时长
示例:
禁言 123456 30m:将123456禁言30分钟
禁言 @XXX 1d12h:将XXX禁言1天12小时
禁言 123456 0:将123456解除禁言`,
AdminLevel: 5,
}
var proxy *manager.PluginProxy

func init() {
proxy = manager.RegisterPlugin(info)
if proxy == nil {
return
}
proxy.OnCommands([]string{"踢了"}, zero.OnlyGroup).SetBlock(true).ThirdPriority().Handle(kickSomeone)
proxy.OnCommands([]string{"禁言"}, zero.OnlyGroup).SetBlock(true).ThirdPriority().Handle(muteSomeone)
proxy.OnMessage(zero.OnlyGroup, rules.ReplyAndCommands("禁言")).SetBlock(true).ThirdPriority().Handle(muteReply)
}

func kickSomeone(ctx *zero.Ctx) {
id, _, err := analysisArgs(ctx, false)
if err != nil {
log.Errorf("解析参数错误:%v", err)
return
}
if id <= 0 {
ctx.Send("请指定踢出的QQ号或@")
return
}
// 获取确认
ctx.Send(fmt.Sprintf("确认踢出用户%v?", id))
event := utils.WaitNextMessage(ctx)
if event == nil { // 无回应
return
}
confirm := strings.TrimSpace(event.Message.ExtractPlainText())
if confirm == "是" || confirm == "确定" || confirm == "确认" {
// 确认踢出
ctx.SetGroupKick(ctx.Event.GroupID, id, false)
log.Infof("将用户%v踢出群%v", id, ctx.Event.GroupID)
} else {
ctx.Send("已取消")
}
}

func muteSomeone(ctx *zero.Ctx) {
id, duration, err := analysisArgs(ctx, true)
if err != nil {
log.Errorf("解析参数错误:%v", err)
return
}
if id < 0 {
ctx.Send("请指定禁言的QQ号或@")
return
}
if duration != 0 && duration <= time.Minute { // 至少禁言1分钟
duration = time.Minute
}
// 禁言
if id == 0 { // WARNING Go-Cqhttp的全员禁言目前无法使用,会在下一版本修复
ctx.SetGroupWholeBan(ctx.Event.GroupID, duration != 0)
} else {
ctx.SetGroupBan(ctx.Event.GroupID, id, int64(duration/time.Second))
}
// log
if duration == 0 {
log.Infof("将用户%v解除禁言", id)
} else {
log.Infof("将用户%v禁言%v", id, duration)
}
}

func muteReply(ctx *zero.Ctx) {
replyID := cast.ToInt64(ctx.State["reply_id"])
// 追溯消息
msg := ctx.GetMessage(replyID)
if msg.Sender == nil {
ctx.Send("消息失效了")
return
}
// 解析时长
args := strings.TrimSpace(utils.GetArgs(ctx))
var duration time.Duration
if args == "0" {
duration = 0
} else {
seconds, err := parseDurationWithDay(args)
if err != nil {
ctx.Send("时长格式错误")
return
}
duration = seconds
}
if duration != 0 && duration <= time.Minute { // 至少禁言1分钟
duration = time.Minute
}
// 禁言
// WARNING Go-Cqhttp并没有提供AnonymousFlag字段,因此无法支持禁言匿名用户
ctx.SetGroupBan(ctx.Event.GroupID, msg.Sender.ID, int64(duration/time.Second))
log.Infof("将用户%v禁言%s", msg.Sender.ID, duration)
}

func analysisArgs(ctx *zero.Ctx, parseTime bool) (ID int64, seconds time.Duration, err error) {
parseID := true
// @
for _, msg := range ctx.Event.Message {
if msg.Type == "at" {
parseID = false
ID, _ = strconv.ParseInt(msg.Data["qq"], 10, 64)
if !parseTime {
return
}
}
}
// 文字
args := strings.TrimSpace(utils.GetArgs(ctx))
subs := strings.Split(args, " ")
if len(subs) < 1 { // 要么要有QQ号,要么要有时长
ctx.Send("参数不足")
return 0, 0, fmt.Errorf("参数不足")
}
// 解析QQ号
if parseID {
ID, err = strconv.ParseInt(subs[0], 10, 64)
if err != nil {
ctx.Send("QQ号格式错误")
return
}
}
// 解析时长
if parseTime {
if subs[len(subs)-1] == "0" {
seconds = 0
return
}
seconds, err = parseDurationWithDay(subs[len(subs)-1])
if err != nil {
ctx.Send("时长格式错误")
return
}
}
return
}

func parseDurationWithDay(duration string) (res time.Duration, err error) {
if len(duration) == 0 {
return 0, fmt.Errorf("duration too short")
}
if match, _ := regexp.MatchString("^[1-9]+d.*", duration); match {
dIndex := strings.IndexRune(duration, 'd')
day, _ := strconv.Atoi(duration[:dIndex])
res = 24 * time.Hour * time.Duration(day)
duration = duration[dIndex+1:]
if len(duration) == 0 {
return
}
}
other, err := time.ParseDuration(duration)
if err != nil {
return 0, err
}
return other + res, err
}
34 changes: 2 additions & 32 deletions plugins/withdraw/withdraw.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package withdraw

import (
"strings"

"github.com/RicheyJang/PaimengBot/manager"
"github.com/RicheyJang/PaimengBot/utils"
"github.com/RicheyJang/PaimengBot/utils/rules"

log "github.com/sirupsen/logrus"
"github.com/spf13/cast"
Expand All @@ -25,36 +24,7 @@ func init() {
if proxy == nil {
return
}
proxy.OnMessage(zero.OnlyGroup, zero.OnlyToMe, checkNeedWithdraw).SetBlock(true).FirstPriority().Handle(withDrawMsg)
}

func checkNeedWithdraw(ctx *zero.Ctx) bool {
if len(ctx.Event.Message) < 2 || ctx.Event.Message[0].Type != "reply" { // 回复消息
return false
}
for _, msg := range ctx.Event.Message {
if msg.Type == "text" && checkTextMsgNeedWithdraw(msg.Data["text"]) {
ctx.State["reply_id"] = ctx.Event.Message[0].Data["id"]
return true
}
}
return false
}

// 检查消息中是否包含撤回字眼
func checkTextMsgNeedWithdraw(msg string) bool {
if len(msg) <= 1 {
return false
}
msg = strings.TrimSpace(msg)
for _, nick := range utils.GetBotConfig().NickName { // 去除昵称前缀
if strings.HasPrefix(msg, nick) {
msg = msg[len(nick):]
msg = strings.TrimSpace(msg)
break
}
}
return strings.HasPrefix(msg, "撤回") || strings.HasPrefix(msg, "快撤回")
proxy.OnMessage(zero.OnlyGroup, rules.ReplyAndCommands("撤回", "快撤回")).SetBlock(true).FirstPriority().Handle(withDrawMsg)
}

func withDrawMsg(ctx *zero.Ctx) {
Expand Down
61 changes: 61 additions & 0 deletions utils/rules/builder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package rules

import (
"strings"

"github.com/RicheyJang/PaimengBot/utils"
zero "github.com/wdvxdr1123/ZeroBot"
)

// ReplyAndCommands Rule生成器: 含回复且文本中包含指定命令
func ReplyAndCommands(commands ...string) func(ctx *zero.Ctx) bool {
return func(ctx *zero.Ctx) bool {
if len(ctx.Event.Message) < 2 || ctx.Event.Message[0].Type != "reply" { // 回复消息
return false
}
ctx.State["reply_id"] = ctx.Event.Message[0].Data["id"]
for i, msg := range ctx.Event.Message {
if msg.Type == "text" && checkTextMsgCommands(ctx, msg.Data["text"], i, commands...) {
return true
}
}
return false
}
}

// 检查文本消息中是否包含指定命令
func checkTextMsgCommands(ctx *zero.Ctx, msg string, textIndex int, commands ...string) bool {
if len(msg) == 0 {
return false
}
msg = strings.TrimSpace(msg)
// 去除昵称前缀
if !utils.IsMessagePrimary(ctx) {
for _, nick := range utils.GetBotConfig().NickName {
if strings.HasPrefix(msg, nick) {
msg = msg[len(nick):]
msg = strings.TrimSpace(msg)
ctx.Event.IsToMe = true
break
}
}
}
// 检查命令前缀
if !strings.HasPrefix(msg, utils.GetBotConfig().CommandPrefix) {
return false
}
cmdMessage := msg[len(utils.GetBotConfig().CommandPrefix):]
// 检查命令
for _, command := range commands {
if strings.HasPrefix(cmdMessage, command) {
ctx.State["command"] = command
arg := strings.TrimLeft(cmdMessage[len(command):], " ")
if len(ctx.Event.Message) > textIndex+1 {
arg += ctx.Event.Message[textIndex+1:].ExtractPlainText()
}
ctx.State["args"] = arg
return true
}
}
return false
}

0 comments on commit cfa3d0e

Please sign in to comment.