88 lines
2.6 KiB
Go
88 lines
2.6 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"time"
|
|
|
|
libmongo "gateway/internal/library/mongo"
|
|
authdomain "gateway/internal/model/auth/domain"
|
|
"gateway/internal/model/auth/domain/entity"
|
|
domrepo "gateway/internal/model/auth/domain/repository"
|
|
|
|
"go.mongodb.org/mongo-driver/v2/bson"
|
|
mongodriver "go.mongodb.org/mongo-driver/v2/mongo"
|
|
"go.mongodb.org/mongo-driver/v2/mongo/options"
|
|
)
|
|
|
|
// InviteRepositoryParam configures the Mongo invite repository.
|
|
type InviteRepositoryParam struct {
|
|
Conf *libmongo.Conf
|
|
}
|
|
|
|
type inviteRepository struct {
|
|
db libmongo.DocumentDBUseCase
|
|
}
|
|
|
|
// NewInviteRepository creates a Mongo-backed InviteRepository.
|
|
func NewInviteRepository(param InviteRepositoryParam) domrepo.InviteRepository {
|
|
documentDB, err := libmongo.NewDocumentDB(param.Conf, entity.InviteCode{}.CollectionName())
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return &inviteRepository{db: documentDB}
|
|
}
|
|
|
|
func (r *inviteRepository) GetByTenantAndCodeHash(ctx context.Context, tenantID, codeHash string) (*entity.InviteCode, error) {
|
|
var doc entity.InviteCode
|
|
filter := bson.M{
|
|
authdomain.BSONFieldTenantID: tenantID,
|
|
authdomain.BSONFieldCodeHash: codeHash,
|
|
}
|
|
if err := r.db.GetClient().FindOne(ctx, &doc, filter); err != nil {
|
|
if errors.Is(err, mongodriver.ErrNoDocuments) {
|
|
return nil, authdomain.ErrInviteNotFound
|
|
}
|
|
return nil, err
|
|
}
|
|
return &doc, nil
|
|
}
|
|
|
|
func (r *inviteRepository) ConsumeOne(ctx context.Context, id bson.ObjectID) (*entity.InviteCode, error) {
|
|
now := time.Now().UTC().UnixMilli()
|
|
filter := bson.M{
|
|
authdomain.BSONFieldID: id,
|
|
"$expr": bson.M{
|
|
"$lt": bson.A{"$" + authdomain.BSONFieldUsedCount, "$" + authdomain.BSONFieldMaxUses},
|
|
},
|
|
"$or": bson.A{
|
|
bson.M{authdomain.BSONFieldExpiresAt: bson.M{"$lte": 0}},
|
|
bson.M{authdomain.BSONFieldExpiresAt: bson.M{"$gt": now}},
|
|
},
|
|
}
|
|
update := bson.M{
|
|
"$inc": bson.M{authdomain.BSONFieldUsedCount: 1},
|
|
"$set": bson.M{authdomain.BSONFieldUpdateAt: now},
|
|
}
|
|
opts := options.FindOneAndUpdate().SetReturnDocument(options.After)
|
|
var doc entity.InviteCode
|
|
if err := r.db.GetClient().FindOneAndUpdate(ctx, &doc, filter, update, opts); err != nil {
|
|
if errors.Is(err, mongodriver.ErrNoDocuments) {
|
|
return nil, authdomain.ErrInviteExhausted
|
|
}
|
|
return nil, err
|
|
}
|
|
return &doc, nil
|
|
}
|
|
|
|
// Index20260521001UP ensures invite_codes collection indexes exist.
|
|
func (r *inviteRepository) Index20260521001UP(ctx context.Context) error {
|
|
return r.db.PopulateMultiIndex(ctx,
|
|
[]string{authdomain.BSONFieldTenantID, authdomain.BSONFieldCodeHash},
|
|
[]int32{1, 1},
|
|
true,
|
|
)
|
|
}
|
|
|
|
var _ domrepo.InviteRepository = (*inviteRepository)(nil)
|