first commit
This commit is contained in:
@@ -0,0 +1,322 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
"go.mongodb.org/mongo-driver/v2/mongo"
|
||||
"go.mongodb.org/mongo-driver/v2/mongo/options"
|
||||
|
||||
"github.com/noteapp/backend/internal/domain/entities"
|
||||
)
|
||||
|
||||
// AccountRecoveryRepository implements account recovery operations
|
||||
type AccountRecoveryRepository struct {
|
||||
collection *mongo.Collection
|
||||
}
|
||||
|
||||
type featureFlagSettings struct {
|
||||
ID string `bson:"_id"`
|
||||
Flags entities.FeatureFlags `bson:"flags"`
|
||||
UpdatedAt time.Time `bson:"updated_at"`
|
||||
}
|
||||
|
||||
// FeatureFlagRepository implements app-wide feature flag operations.
|
||||
type FeatureFlagRepository struct {
|
||||
collection *mongo.Collection
|
||||
}
|
||||
|
||||
// NewFeatureFlagRepository creates a new feature flag repository.
|
||||
func NewFeatureFlagRepository(db *mongo.Database) *FeatureFlagRepository {
|
||||
return &FeatureFlagRepository{
|
||||
collection: db.Collection("app_settings"),
|
||||
}
|
||||
}
|
||||
|
||||
// GetFeatureFlags returns persisted feature flags or defaults when not set.
|
||||
func (r *FeatureFlagRepository) GetFeatureFlags(ctx context.Context) (*entities.FeatureFlags, error) {
|
||||
var settings featureFlagSettings
|
||||
err := r.collection.FindOne(ctx, bson.M{"_id": "feature_flags"}).Decode(&settings)
|
||||
if err != nil {
|
||||
if err == mongo.ErrNoDocuments {
|
||||
return entities.NewDefaultFeatureFlags(), nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
flags := settings.Flags
|
||||
return &flags, nil
|
||||
}
|
||||
|
||||
// UpdateFeatureFlags persists feature flags.
|
||||
func (r *FeatureFlagRepository) UpdateFeatureFlags(ctx context.Context, flags *entities.FeatureFlags) error {
|
||||
if flags == nil {
|
||||
flags = entities.NewDefaultFeatureFlags()
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
_, err := r.collection.UpdateOne(
|
||||
ctx,
|
||||
bson.M{"_id": "feature_flags"},
|
||||
bson.M{
|
||||
"$set": bson.M{
|
||||
"flags": flags,
|
||||
"updated_at": now,
|
||||
},
|
||||
},
|
||||
options.UpdateOne().SetUpsert(true),
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
// NewAccountRecoveryRepository creates a new recovery repository
|
||||
func NewAccountRecoveryRepository(db *mongo.Database) *AccountRecoveryRepository {
|
||||
return &AccountRecoveryRepository{
|
||||
collection: db.Collection("account_recovery"),
|
||||
}
|
||||
}
|
||||
|
||||
// CreateRecovery creates a new recovery token
|
||||
func (r *AccountRecoveryRepository) CreateRecovery(ctx context.Context, recovery *entities.AccountRecovery) error {
|
||||
recovery.ID = bson.NewObjectID()
|
||||
recovery.CreatedAt = time.Now()
|
||||
|
||||
_, err := r.collection.InsertOne(ctx, recovery)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetRecoveryByToken retrieves a recovery record by token
|
||||
func (r *AccountRecoveryRepository) GetRecoveryByToken(ctx context.Context, token string) (*entities.AccountRecovery, error) {
|
||||
var recovery entities.AccountRecovery
|
||||
err := r.collection.FindOne(ctx, bson.M{
|
||||
"token": token,
|
||||
"expires_at": bson.M{"$gt": time.Now()},
|
||||
"used_at": bson.M{"$exists": false},
|
||||
}).Decode(&recovery)
|
||||
|
||||
if err != nil {
|
||||
if err == mongo.ErrNoDocuments {
|
||||
return nil, errors.New("recovery token not found or expired")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &recovery, nil
|
||||
}
|
||||
|
||||
// MarkRecoveryUsed marks a recovery token as used
|
||||
func (r *AccountRecoveryRepository) MarkRecoveryUsed(ctx context.Context, id bson.ObjectID) error {
|
||||
now := time.Now()
|
||||
_, err := r.collection.UpdateOne(ctx, bson.M{"_id": id}, bson.M{
|
||||
"$set": bson.M{"used_at": now},
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// NoteRevisionRepository implements note revision operations
|
||||
type NoteRevisionRepository struct {
|
||||
collection *mongo.Collection
|
||||
}
|
||||
|
||||
// NewNoteRevisionRepository creates a new revision repository
|
||||
func NewNoteRevisionRepository(db *mongo.Database) *NoteRevisionRepository {
|
||||
return &NoteRevisionRepository{
|
||||
collection: db.Collection("note_revisions"),
|
||||
}
|
||||
}
|
||||
|
||||
// CreateRevision creates a new note revision
|
||||
func (r *NoteRevisionRepository) CreateRevision(ctx context.Context, revision *entities.NoteRevision) error {
|
||||
revision.ID = bson.NewObjectID()
|
||||
revision.CreatedAt = time.Now()
|
||||
|
||||
_, err := r.collection.InsertOne(ctx, revision)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetRevisionsByNoteID retrieves all revisions for a note
|
||||
func (r *NoteRevisionRepository) GetRevisionsByNoteID(ctx context.Context, noteID bson.ObjectID) ([]*entities.NoteRevision, error) {
|
||||
var revisions []*entities.NoteRevision
|
||||
|
||||
cursor, err := r.collection.Find(ctx, bson.M{"note_id": noteID})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cursor.Close(ctx)
|
||||
|
||||
if err = cursor.All(ctx, &revisions); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return revisions, nil
|
||||
}
|
||||
|
||||
// GetRevisionByID retrieves a specific revision
|
||||
func (r *NoteRevisionRepository) GetRevisionByID(ctx context.Context, id bson.ObjectID) (*entities.NoteRevision, error) {
|
||||
var revision entities.NoteRevision
|
||||
err := r.collection.FindOne(ctx, bson.M{"_id": id}).Decode(&revision)
|
||||
|
||||
if err != nil {
|
||||
if err == mongo.ErrNoDocuments {
|
||||
return nil, errors.New("revision not found")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &revision, nil
|
||||
}
|
||||
|
||||
// AuthProviderRepository implements auth provider operations
|
||||
type AuthProviderRepository struct {
|
||||
collection *mongo.Collection
|
||||
}
|
||||
|
||||
// NewAuthProviderRepository creates a new provider repository
|
||||
func NewAuthProviderRepository(db *mongo.Database) *AuthProviderRepository {
|
||||
return &AuthProviderRepository{
|
||||
collection: db.Collection("auth_providers"),
|
||||
}
|
||||
}
|
||||
|
||||
// CreateProvider creates a new provider
|
||||
func (r *AuthProviderRepository) CreateProvider(ctx context.Context, provider *entities.AuthProvider) error {
|
||||
provider.ID = bson.NewObjectID()
|
||||
provider.CreatedAt = time.Now()
|
||||
provider.UpdatedAt = time.Now()
|
||||
|
||||
_, err := r.collection.InsertOne(ctx, provider)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetProviderByID retrieves a provider by ID
|
||||
func (r *AuthProviderRepository) GetProviderByID(ctx context.Context, id bson.ObjectID) (*entities.AuthProvider, error) {
|
||||
var provider entities.AuthProvider
|
||||
err := r.collection.FindOne(ctx, bson.M{"_id": id}).Decode(&provider)
|
||||
|
||||
if err != nil {
|
||||
if err == mongo.ErrNoDocuments {
|
||||
return nil, errors.New("provider not found")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &provider, nil
|
||||
}
|
||||
|
||||
// GetAllProviders retrieves all active providers
|
||||
func (r *AuthProviderRepository) GetAllProviders(ctx context.Context) ([]*entities.AuthProvider, error) {
|
||||
var providers []*entities.AuthProvider
|
||||
|
||||
cursor, err := r.collection.Find(ctx, bson.M{"is_active": true})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cursor.Close(ctx)
|
||||
|
||||
if err = cursor.All(ctx, &providers); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return providers, nil
|
||||
}
|
||||
|
||||
// UpdateProvider updates a provider
|
||||
func (r *AuthProviderRepository) UpdateProvider(ctx context.Context, provider *entities.AuthProvider) error {
|
||||
provider.UpdatedAt = time.Now()
|
||||
_, err := r.collection.ReplaceOne(ctx, bson.M{"_id": provider.ID}, provider)
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteProvider deletes a provider
|
||||
func (r *AuthProviderRepository) DeleteProvider(ctx context.Context, id bson.ObjectID) error {
|
||||
_, err := r.collection.DeleteOne(ctx, bson.M{"_id": id})
|
||||
return err
|
||||
}
|
||||
|
||||
// UserProviderLinkRepository implements user provider link operations
|
||||
type UserProviderLinkRepository struct {
|
||||
collection *mongo.Collection
|
||||
}
|
||||
|
||||
// NewUserProviderLinkRepository creates a new link repository
|
||||
func NewUserProviderLinkRepository(db *mongo.Database) *UserProviderLinkRepository {
|
||||
return &UserProviderLinkRepository{
|
||||
collection: db.Collection("user_provider_links"),
|
||||
}
|
||||
}
|
||||
|
||||
// CreateLink creates a new user provider link
|
||||
func (r *UserProviderLinkRepository) CreateLink(ctx context.Context, link *entities.UserProviderLink) error {
|
||||
link.ID = bson.NewObjectID()
|
||||
link.LinkedAt = time.Now()
|
||||
|
||||
_, err := r.collection.InsertOne(ctx, link)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetLink retrieves a user provider link
|
||||
func (r *UserProviderLinkRepository) GetLink(ctx context.Context, userID, providerID bson.ObjectID) (*entities.UserProviderLink, error) {
|
||||
var link entities.UserProviderLink
|
||||
err := r.collection.FindOne(ctx, bson.M{
|
||||
"user_id": userID,
|
||||
"provider_id": providerID,
|
||||
}).Decode(&link)
|
||||
|
||||
if err != nil {
|
||||
if err == mongo.ErrNoDocuments {
|
||||
return nil, errors.New("link not found")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &link, nil
|
||||
}
|
||||
|
||||
// GetLinkByProviderUserID retrieves a link by provider user ID
|
||||
func (r *UserProviderLinkRepository) GetLinkByProviderUserID(ctx context.Context, providerID bson.ObjectID, providerUserID string) (*entities.UserProviderLink, error) {
|
||||
var link entities.UserProviderLink
|
||||
err := r.collection.FindOne(ctx, bson.M{
|
||||
"provider_id": providerID,
|
||||
"provider_user_id": providerUserID,
|
||||
}).Decode(&link)
|
||||
|
||||
if err != nil {
|
||||
if err == mongo.ErrNoDocuments {
|
||||
return nil, errors.New("link not found")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &link, nil
|
||||
}
|
||||
|
||||
// GetUserLinks retrieves all provider links for a user
|
||||
func (r *UserProviderLinkRepository) GetUserLinks(ctx context.Context, userID bson.ObjectID) ([]*entities.UserProviderLink, error) {
|
||||
var links []*entities.UserProviderLink
|
||||
|
||||
cursor, err := r.collection.Find(ctx, bson.M{"user_id": userID})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cursor.Close(ctx)
|
||||
|
||||
if err = cursor.All(ctx, &links); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return links, nil
|
||||
}
|
||||
|
||||
// UpdateLink updates a provider link
|
||||
func (r *UserProviderLinkRepository) UpdateLink(ctx context.Context, link *entities.UserProviderLink) error {
|
||||
_, err := r.collection.ReplaceOne(ctx, bson.M{"_id": link.ID}, link)
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteLink deletes a provider link
|
||||
func (r *UserProviderLinkRepository) DeleteLink(ctx context.Context, id bson.ObjectID) error {
|
||||
_, err := r.collection.DeleteOne(ctx, bson.M{"_id": id})
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user