forked from carrydela/mygoTgChanBot
修复转发跳收藏;修复若干小bug
This commit is contained in:
@@ -72,6 +72,7 @@ toc:
|
||||
|------|------|
|
||||
| `/cat_add <名称> [排序]` | 创建分类 |
|
||||
| `/cat_del <名称>` | 删除分类 |
|
||||
| `/cat_rename <旧名称> <新名称>` | 重命名分类(自动更新所有条目) |
|
||||
| `/cat_list` | 列出所有分类 |
|
||||
|
||||
### 管理员管理 (仅超级管理员)
|
||||
|
||||
@@ -105,6 +105,62 @@ func (s *Storage) UpdateCategoryOrder(name string, order int) error {
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Storage) RenameCategory(oldName, newName string) error {
|
||||
return s.db.Update(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket(bucketCategories)
|
||||
|
||||
// 检查旧分类是否存在
|
||||
data := b.Get([]byte(oldName))
|
||||
if data == nil {
|
||||
return fmt.Errorf("category %q not found", oldName)
|
||||
}
|
||||
|
||||
// 检查新名称是否已存在
|
||||
if b.Get([]byte(newName)) != nil {
|
||||
return fmt.Errorf("category %q already exists", newName)
|
||||
}
|
||||
|
||||
// 解码旧分类
|
||||
var cat Category
|
||||
if err := decodeJSON(data, &cat); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 更新名称
|
||||
cat.Name = newName
|
||||
newData, err := encodeJSON(cat)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 删除旧键,写入新键
|
||||
if err := b.Delete([]byte(oldName)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := b.Put([]byte(newName), newData); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 同步更新所有条目的分类名
|
||||
entries := tx.Bucket(bucketEntries)
|
||||
return entries.ForEach(func(k, v []byte) error {
|
||||
var entry Entry
|
||||
if err := decodeJSON(v, &entry); err != nil {
|
||||
return err
|
||||
}
|
||||
if entry.Category == oldName {
|
||||
entry.Category = newName
|
||||
newEntryData, err := encodeJSON(entry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return entries.Put(k, newEntryData)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Storage) CategoryExists(name string) bool {
|
||||
exists := false
|
||||
s.db.View(func(tx *bolt.Tx) error {
|
||||
|
||||
@@ -51,6 +51,7 @@ func (b *Bot) setupRoutes() {
|
||||
// Category management
|
||||
adminOnly.Handle("/cat_add", b.handleCatAdd)
|
||||
adminOnly.Handle("/cat_del", b.handleCatDel)
|
||||
adminOnly.Handle("/cat_rename", b.handleCatRename)
|
||||
adminOnly.Handle("/cat_list", b.handleCatList)
|
||||
|
||||
// Post flow
|
||||
@@ -97,6 +98,7 @@ func (b *Bot) setCommands() {
|
||||
{Text: "cat_list", Description: "分类列表"},
|
||||
{Text: "cat_add", Description: "添加分类 <名称> [排序]"},
|
||||
{Text: "cat_del", Description: "删除分类 <名称>"},
|
||||
{Text: "cat_rename", Description: "重命名分类 <旧名称> <新名称>"},
|
||||
{Text: "del", Description: "删除条目 <ID>"},
|
||||
{Text: "edit", Description: "编辑标题 <ID> <新标题>"},
|
||||
{Text: "move", Description: "移动条目 <ID> <新分类>"},
|
||||
|
||||
@@ -42,6 +42,24 @@ func (b *Bot) handleCatDel(c tele.Context) error {
|
||||
return c.Reply(fmt.Sprintf("✅ 分类 [%s] 已删除", name))
|
||||
}
|
||||
|
||||
func (b *Bot) handleCatRename(c tele.Context) error {
|
||||
args := strings.Fields(c.Message().Payload)
|
||||
if len(args) < 2 {
|
||||
return c.Reply("用法: /cat_rename <旧名称> <新名称>\n例如: /cat_rename iOS Apple")
|
||||
}
|
||||
|
||||
oldName := args[0]
|
||||
newName := args[1]
|
||||
|
||||
if err := b.storage.RenameCategory(oldName, newName); err != nil {
|
||||
return c.Reply(fmt.Sprintf("❌ 重命名失败: %v", err))
|
||||
}
|
||||
|
||||
b.toc.TriggerUpdate()
|
||||
|
||||
return c.Reply(fmt.Sprintf("✅ 分类 [%s] 已重命名为 [%s]", oldName, newName))
|
||||
}
|
||||
|
||||
func (b *Bot) handleCatList(c tele.Context) error {
|
||||
categories, err := b.storage.ListCategories()
|
||||
if err != nil {
|
||||
|
||||
@@ -2,6 +2,7 @@ package telegram
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"html"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -94,7 +95,7 @@ func (b *Bot) handleEntryList(c tele.Context) error {
|
||||
|
||||
var sb strings.Builder
|
||||
if category != "" {
|
||||
sb.WriteString(fmt.Sprintf("📋 分类 [%s] 的条目:\n\n", category))
|
||||
sb.WriteString(fmt.Sprintf("📋 分类 [%s] 的条目:\n\n", html.EscapeString(category)))
|
||||
} else {
|
||||
sb.WriteString("📋 所有条目:\n\n")
|
||||
}
|
||||
@@ -103,12 +104,12 @@ func (b *Bot) handleEntryList(c tele.Context) error {
|
||||
for _, e := range entries {
|
||||
if category == "" && e.Category != currentCat {
|
||||
currentCat = e.Category
|
||||
sb.WriteString(fmt.Sprintf("\n【%s】\n", currentCat))
|
||||
sb.WriteString(fmt.Sprintf("\n【%s】\n", html.EscapeString(currentCat)))
|
||||
}
|
||||
sb.WriteString(fmt.Sprintf("• [%s] %s\n", e.ID, e.Title))
|
||||
sb.WriteString(fmt.Sprintf("• <code>%s</code> %s\n", e.ID, html.EscapeString(e.Title)))
|
||||
}
|
||||
|
||||
return c.Reply(sb.String())
|
||||
return c.Reply(sb.String(), tele.ModeHTML)
|
||||
}
|
||||
|
||||
func (b *Bot) handleRefresh(c tele.Context) error {
|
||||
|
||||
@@ -110,8 +110,8 @@ func (b *Bot) handleTextInput(c tele.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 检查是否为转发消息
|
||||
isForwarded := msg.OriginalChat != nil || msg.OriginalSender != nil
|
||||
// 检查是否为转发消息(OriginalUnixtime 在隐私设置隐藏来源时仍存在)
|
||||
isForwarded := msg.OriginalChat != nil || msg.OriginalSender != nil || msg.OriginalUnixtime > 0
|
||||
|
||||
state := b.states.Get(c.Sender().ID)
|
||||
|
||||
@@ -148,8 +148,8 @@ func (b *Bot) handleForwarded(c tele.Context) error {
|
||||
}
|
||||
|
||||
msg := c.Message()
|
||||
// 检查是否为转发消息(来自频道/群组或个人用户)
|
||||
if msg.OriginalChat == nil && msg.OriginalSender == nil {
|
||||
// 检查是否为转发消息(OriginalUnixtime 在隐私设置隐藏来源时仍存在)
|
||||
if msg.OriginalChat == nil && msg.OriginalSender == nil && msg.OriginalUnixtime == 0 {
|
||||
return c.Reply("❌ 这不是一条转发消息,请转发一条消息给我")
|
||||
}
|
||||
|
||||
@@ -438,7 +438,7 @@ func (b *Bot) handleConfirmCallback(c tele.Context, userID int64, action string)
|
||||
}
|
||||
|
||||
// 使用频道消息的链接
|
||||
link := buildChannelLink(b.cfg.Channel.ID, channelMsg.ID)
|
||||
link := b.buildChannelLink(channelMsg.ID)
|
||||
|
||||
entry, err := b.storage.CreateEntry(state.SelectedCat, title, link)
|
||||
if err != nil {
|
||||
@@ -484,8 +484,15 @@ func (b *Bot) sendAlbumCopy(to *tele.Chat, msgs []*tele.Message) (*tele.Message,
|
||||
return &sentMsgs[0], nil
|
||||
}
|
||||
|
||||
func buildChannelLink(channelID int64, msgID int) string {
|
||||
chatID := channelID
|
||||
func (b *Bot) buildChannelLink(msgID int) string {
|
||||
// 尝试获取频道信息,检查是否为公开频道
|
||||
chat, err := b.bot.ChatByID(b.cfg.Channel.ID)
|
||||
if err == nil && chat.Username != "" {
|
||||
return fmt.Sprintf("https://t.me/%s/%d", chat.Username, msgID)
|
||||
}
|
||||
|
||||
// 私有频道 fallback
|
||||
chatID := b.cfg.Channel.ID
|
||||
if chatID < 0 {
|
||||
chatID = -chatID - 1000000000000
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user