package repository import ( "context" libmongo "apps/backend/internal/lib/mongo" "apps/backend/internal/module/appnotif/domain" "github.com/zeromicro/go-zero/core/stores/mon" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo/options" ) const col = "notifications" type MonStore struct { n *mon.Model } func NewMonStore(uri, database string) *MonStore { uri = libmongo.MustMongoURI(uri) return &MonStore{n: mon.MustNewModel(uri, database, col)} } func (s *MonStore) Insert(ctx context.Context, n *domain.Notification) error { _, err := s.n.InsertOne(ctx, n) return err } func (s *MonStore) ListByOwner(ctx context.Context, ownerUID int64) ([]*domain.Notification, error) { var list []*domain.Notification err := s.n.Find(ctx, &list, bson.M{"owner_uid": ownerUID}, options.Find().SetSort(bson.D{{Key: "created_at", Value: -1}})) return list, err } func (s *MonStore) UnreadCount(ctx context.Context, ownerUID int64) (int64, error) { return s.n.CountDocuments(ctx, unreadFilter(ownerUID)) } func unreadFilter(ownerUID int64) bson.M { return bson.M{ "owner_uid": ownerUID, "$or": []bson.M{ {"read_at": 0}, {"read_at": bson.M{"$exists": false}}, }, } } func (s *MonStore) FindByID(ctx context.Context, id string) (*domain.Notification, error) { var n domain.Notification err := s.n.FindOne(ctx, &n, bson.M{"_id": id}) if err != nil { if err == mon.ErrNotFound { return nil, domain.ErrNotFound } return nil, err } return &n, nil } func (s *MonStore) MarkRead(ctx context.Context, ownerUID int64, id string) error { res, err := s.n.UpdateOne(ctx, bson.M{"_id": id, "owner_uid": ownerUID}, bson.M{ "$set": bson.M{"read_at": domain.NowNano()}, }) if err != nil { return err } if res.MatchedCount > 0 { return nil } n, findErr := s.FindByID(ctx, id) if findErr != nil { return findErr } if n.OwnerUID != ownerUID { return domain.ErrForbidden } return domain.ErrNotFound } func (s *MonStore) MarkAllRead(ctx context.Context, ownerUID int64) error { _, err := s.n.UpdateMany( ctx, unreadFilter(ownerUID), bson.M{"$set": bson.M{"read_at": domain.NowNano()}}, ) return err } func (s *MonStore) FindLatestByJobRef(ctx context.Context, ownerUID int64, jobID string) (*domain.Notification, error) { if jobID == "" { return nil, domain.ErrNotFound } var list []*domain.Notification err := s.n.Find(ctx, &list, bson.M{ "owner_uid": ownerUID, "kind": domain.KindJob, "ref_type": domain.RefJob, "ref_id": jobID, }, options.Find().SetSort(bson.D{{Key: "created_at", Value: -1}}).SetLimit(1)) if err != nil { return nil, err } if len(list) == 0 { return nil, domain.ErrNotFound } return list[0], nil } func (s *MonStore) UpdateJobNotification(ctx context.Context, n *domain.Notification, markUnread bool) error { if n == nil || n.ID == "" { return domain.ErrNotFound } set := bson.M{ "title": n.Title, "body": n.Body, "kind": n.Kind, "ref_type": n.RefType, "ref_id": n.RefID, "created_at": n.CreatedAt, } if markUnread { set["read_at"] = 0 } res, err := s.n.UpdateOne(ctx, bson.M{"_id": n.ID, "owner_uid": n.OwnerUID}, bson.M{"$set": set}) if err != nil { return err } if res.MatchedCount == 0 { return domain.ErrNotFound } return nil } var _ domain.Repository = (*MonStore)(nil)