mirror of
https://github.com/tiennm99/store-scraper-bot.git
synced 2026-09-01 00:30:41 +00:00
- 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.
132 lines
3.4 KiB
Go
132 lines
3.4 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/miti99/store-scraper-bot-go/internal/model"
|
|
"go.mongodb.org/mongo-driver/bson"
|
|
"go.mongodb.org/mongo-driver/mongo"
|
|
"go.mongodb.org/mongo-driver/mongo/options"
|
|
)
|
|
|
|
// GroupRepository persists Group documents in the "group" collection.
|
|
// Java schema stores _id as the string form of the Telegram chat ID.
|
|
type GroupRepository struct {
|
|
collection *mongo.Collection
|
|
}
|
|
|
|
func NewGroupRepository() *GroupRepository {
|
|
return &GroupRepository{collection: GetCollection("group")}
|
|
}
|
|
|
|
// Init creates an empty Group if not present.
|
|
func (r *GroupRepository) Init(ctx context.Context, groupID int64) error {
|
|
exists, err := r.Exists(ctx, groupID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if exists {
|
|
return nil
|
|
}
|
|
return r.Save(ctx, model.NewGroup(groupID))
|
|
}
|
|
|
|
func (r *GroupRepository) Exists(ctx context.Context, groupID int64) (bool, error) {
|
|
count, err := r.collection.CountDocuments(ctx, bson.M{"_id": model.GroupIDToKey(groupID)})
|
|
if err != nil {
|
|
return false, fmt.Errorf("failed to count group: %w", err)
|
|
}
|
|
return count > 0, nil
|
|
}
|
|
|
|
func (r *GroupRepository) Get(ctx context.Context, groupID int64) (*model.Group, error) {
|
|
group := &model.Group{}
|
|
err := r.collection.FindOne(ctx, bson.M{"_id": model.GroupIDToKey(groupID)}).Decode(group)
|
|
if err != nil {
|
|
if err == mongo.ErrNoDocuments {
|
|
return model.NewGroup(groupID), nil
|
|
}
|
|
return nil, fmt.Errorf("failed to get group: %w", err)
|
|
}
|
|
return group, nil
|
|
}
|
|
|
|
func (r *GroupRepository) Save(ctx context.Context, group *model.Group) error {
|
|
opts := options.Replace().SetUpsert(true)
|
|
_, err := r.collection.ReplaceOne(ctx, bson.M{"_id": group.ID}, group, opts)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to save group: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *GroupRepository) Delete(ctx context.Context, groupID int64) error {
|
|
_, err := r.collection.DeleteOne(ctx, bson.M{"_id": model.GroupIDToKey(groupID)})
|
|
if err != nil {
|
|
return fmt.Errorf("failed to delete group: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (r *GroupRepository) shortCtx() (context.Context, context.CancelFunc) {
|
|
return context.WithTimeout(context.Background(), 5*time.Second)
|
|
}
|
|
|
|
func (r *GroupRepository) AddAppleApp(groupID int64, appID, country string) (added bool, err error) {
|
|
ctx, cancel := r.shortCtx()
|
|
defer cancel()
|
|
|
|
group, err := r.Get(ctx, groupID)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if !group.AddAppleApp(appID, country) {
|
|
return false, nil
|
|
}
|
|
return true, r.Save(ctx, group)
|
|
}
|
|
|
|
func (r *GroupRepository) RemoveAppleApp(groupID int64, appID string) (removed bool, err error) {
|
|
ctx, cancel := r.shortCtx()
|
|
defer cancel()
|
|
|
|
group, err := r.Get(ctx, groupID)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if !group.RemoveAppleApp(appID) {
|
|
return false, nil
|
|
}
|
|
return true, r.Save(ctx, group)
|
|
}
|
|
|
|
func (r *GroupRepository) AddGoogleApp(groupID int64, appID, country string) (added bool, err error) {
|
|
ctx, cancel := r.shortCtx()
|
|
defer cancel()
|
|
|
|
group, err := r.Get(ctx, groupID)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if !group.AddGoogleApp(appID, country) {
|
|
return false, nil
|
|
}
|
|
return true, r.Save(ctx, group)
|
|
}
|
|
|
|
func (r *GroupRepository) RemoveGoogleApp(groupID int64, appID string) (removed bool, err error) {
|
|
ctx, cancel := r.shortCtx()
|
|
defer cancel()
|
|
|
|
group, err := r.Get(ctx, groupID)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if !group.RemoveGoogleApp(appID) {
|
|
return false, nil
|
|
}
|
|
return true, r.Save(ctx, group)
|
|
}
|