Files
store-scraper-bot/internal/bot/command/list_app.go
T
tiennm99 e695d9b223 feat: port logic from Java original to align with current Java behavior
- Switch Telegram parse mode to HTML to match Java client.
- Rename command identifiers to Java's: delgroup/delapple/delgoogle/
  checkappscore/rawappleapp/rawgoogleapp.
- Move admin singleton to "common" collection at _id="admin".
- Store group _id as string-of-int64 to match Java AbstractModel schema.
- Add `class` discriminator field on persisted models.
- Expand AppleAppResponse (42 fields) and GoogleAppResponse (63 fields,
  with nested Category/Feature) to match Java records.
- Add AppleAppRequest (track id or bundle id) / GoogleAppRequest types.
- Implement Raw* commands as Telegram document attachments instead of
  truncated text.
- Group-authorization gate (admin.HasGroup(chatId)) on non-admin commands.
- Cache TTL via millis timestamp; round score to 1 decimal; weekend silent
  send in scheduler.
- Match Java table renderer: " │ " separators, "─┼─" rows every 5 lines.
- Prefer MONGODB_CONNECTION_STRING env (Java parity); auto-extract DB
  name from URI with fallback to "store-scraper-bot".

Note: This is an AI-assisted port (not human-verified). Behavior parity
with the Java implementation has not been tested end-to-end; treat as a
starting point.
2026-04-25 20:26:25 +07:00

62 lines
1.9 KiB
Go

package command
import (
"context"
"fmt"
"strconv"
"strings"
"time"
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
"github.com/miti99/store-scraper-bot-go/internal/config"
"github.com/miti99/store-scraper-bot-go/internal/model"
"github.com/miti99/store-scraper-bot-go/internal/repository"
"github.com/miti99/store-scraper-bot-go/internal/util"
)
// /listapp — Java ListAppCommand. Two tables (Apple / Google) of tracked apps.
type ListAppCommand struct {
cfg *config.Config
adminRepo *repository.AdminRepository
groupRepo *repository.GroupRepository
}
func NewListAppCommand(cfg *config.Config, adminRepo *repository.AdminRepository, groupRepo *repository.GroupRepository) *ListAppCommand {
return &ListAppCommand{cfg: cfg, adminRepo: adminRepo, groupRepo: groupRepo}
}
func (c *ListAppCommand) Execute(msg *tgbotapi.Message, sender Sender) {
if !authorizeGroup(msg.Chat.ID, c.adminRepo, sender) {
return
}
if len(splitArgs(msg.CommandArguments())) != 0 {
_ = sender.SendMessage(msg.Chat.ID, "Invalid arguments")
return
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
group, err := c.groupRepo.Get(ctx, msg.Chat.ID)
if err != nil {
_ = sender.SendMessage(msg.Chat.ID, "Internal server error")
return
}
var sb strings.Builder
sb.WriteString("<b>Apple Apps</b>\n")
sb.WriteString(formatAppTable(group.AppleApps))
sb.WriteString("\n<b>Google Apps</b>\n")
sb.WriteString(formatAppTable(group.GoogleApps))
_ = sender.SendMessage(msg.Chat.ID, sb.String())
}
func formatAppTable(apps []model.AppInfo) string {
if len(apps) == 0 {
return "<i>(none)</i>\n"
}
rows := make([][]string, 0, len(apps))
for i, a := range apps {
rows = append(rows, []string{strconv.Itoa(i + 1), a.AppID, a.Country})
}
return fmt.Sprintf("<pre>%s</pre>\n", util.BuildTable([]string{"#", "AppId", "Country"}, rows))
}