2026-07-13 01:15:30 +00:00
|
|
|
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) {
|
2026-07-20 06:33:14 +00:00
|
|
|
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}},
|
|
|
|
|
},
|
2026-07-13 01:15:30 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 {
|
2026-07-20 06:33:14 +00:00
|
|
|
res, err := s.n.UpdateOne(ctx, bson.M{"_id": id, "owner_uid": ownerUID}, bson.M{
|
|
|
|
|
"$set": bson.M{"read_at": domain.NowNano()},
|
|
|
|
|
})
|
2026-07-13 01:15:30 +00:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2026-07-20 06:33:14 +00:00
|
|
|
if res.MatchedCount > 0 {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
n, findErr := s.FindByID(ctx, id)
|
|
|
|
|
if findErr != nil {
|
|
|
|
|
return findErr
|
|
|
|
|
}
|
2026-07-13 01:15:30 +00:00
|
|
|
if n.OwnerUID != ownerUID {
|
|
|
|
|
return domain.ErrForbidden
|
|
|
|
|
}
|
2026-07-20 06:33:14 +00:00
|
|
|
return domain.ErrNotFound
|
2026-07-13 01:15:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *MonStore) MarkAllRead(ctx context.Context, ownerUID int64) error {
|
2026-07-20 06:33:14 +00:00
|
|
|
_, err := s.n.UpdateMany(
|
|
|
|
|
ctx,
|
|
|
|
|
unreadFilter(ownerUID),
|
|
|
|
|
bson.M{"$set": bson.M{"read_at": domain.NowNano()}},
|
|
|
|
|
)
|
|
|
|
|
return err
|
2026-07-13 01:15:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-20 06:33:14 +00:00
|
|
|
func (s *MonStore) UpdateJobNotification(ctx context.Context, n *domain.Notification, markUnread bool) error {
|
2026-07-13 01:15:30 +00:00
|
|
|
if n == nil || n.ID == "" {
|
|
|
|
|
return domain.ErrNotFound
|
|
|
|
|
}
|
2026-07-20 06:33:14 +00:00
|
|
|
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})
|
2026-07-13 01:15:30 +00:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if res.MatchedCount == 0 {
|
|
|
|
|
return domain.ErrNotFound
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var _ domain.Repository = (*MonStore)(nil)
|