package repository import ( "context" "time" libmongo "apps/backend/internal/lib/mongo" "apps/backend/internal/module/threads/domain" "github.com/zeromicro/go-zero/core/stores/mon" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo/options" ) const ( colAccounts = "threads_accounts" colStates = "threads_oauth_states" ) // MonStore uses go-zero mon (no entity cache for tokens). type MonStore struct { accounts *mon.Model states *mon.Model } func NewMonStore(uri, database string) *MonStore { uri = libmongo.MustMongoURI(uri) return &MonStore{ accounts: mon.MustNewModel(uri, database, colAccounts), states: mon.MustNewModel(uri, database, colStates), } } func (s *MonStore) Insert(ctx context.Context, a *domain.Account) error { _, err := s.accounts.InsertOne(ctx, a) return err } func (s *MonStore) Update(ctx context.Context, a *domain.Account) error { a.UpdatedAt = domain.NowNano() res, err := s.accounts.ReplaceOne(ctx, bson.M{"_id": a.ID}, a) if err != nil { return err } if res.MatchedCount == 0 { return domain.ErrNotFound } return nil } func (s *MonStore) FindByID(ctx context.Context, id string) (*domain.Account, error) { var a domain.Account err := s.accounts.FindOne(ctx, &a, bson.M{"_id": id}) if err != nil { if err == mon.ErrNotFound { return nil, domain.ErrNotFound } return nil, err } return &a, nil } func (s *MonStore) FindByOwnerAndThreadsUser(ctx context.Context, ownerUID int64, threadsUserID string) (*domain.Account, error) { if threadsUserID == "" { return nil, domain.ErrNotFound } var a domain.Account err := s.accounts.FindOne(ctx, &a, bson.M{"owner_uid": ownerUID, "threads_user_id": threadsUserID}) if err != nil { if err == mon.ErrNotFound { return nil, domain.ErrNotFound } return nil, err } return &a, nil } func (s *MonStore) ListByOwner(ctx context.Context, ownerUID int64) ([]*domain.Account, error) { var list []*domain.Account err := s.accounts.Find(ctx, &list, bson.M{"owner_uid": ownerUID}, options.Find().SetSort(bson.D{{Key: "created_at", Value: -1}})) if err != nil { return nil, err } return list, nil } func (s *MonStore) Delete(ctx context.Context, id string) error { res, err := s.accounts.DeleteOne(ctx, bson.M{"_id": id}) if err != nil { return err } if res == 0 { return domain.ErrNotFound } return nil } func (s *MonStore) SaveState(ctx context.Context, st *domain.OAuthState) error { _, err := s.states.InsertOne(ctx, st) return err } func (s *MonStore) TakeState(ctx context.Context, state string) (*domain.OAuthState, error) { var st domain.OAuthState err := s.states.FindOneAndDelete(ctx, &st, bson.M{"_id": state}) if err != nil { if err == mon.ErrNotFound { return nil, domain.ErrInvalidState } return nil, err } if st.ExpiresAt > 0 && time.Now().UTC().UnixNano() > st.ExpiresAt { return nil, domain.ErrInvalidState } return &st, nil } var _ domain.Repository = (*MonStore)(nil)