diff --git a/.gitignore b/.gitignore index 6b1d5594..180a0dc5 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ logs test/run-management-api.sh test/run-smtp-bridge.sh test/run-participant-api.sh +test/run-all.sh test/participant-api.yaml test/smtp-bridge.yaml *-api-routes.txt diff --git a/go.mod b/go.mod index 1fd747ee..1653cc82 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/gin-contrib/cors v1.7.6 github.com/gin-gonic/gin v1.10.1 github.com/golang-jwt/jwt/v5 v5.3.0 - go.mongodb.org/mongo-driver v1.17.4 + go.mongodb.org/mongo-driver/v2 v2.5.0 ) require ( @@ -24,7 +24,6 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.27.0 // indirect github.com/goccy/go-json v0.10.5 // indirect - github.com/golang/snappy v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect @@ -34,12 +33,11 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/montanaflynn/stats v0.7.1 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.3.0 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect - github.com/xdg-go/scram v1.1.2 // indirect + github.com/xdg-go/scram v1.2.0 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect golang.org/x/arch v0.20.0 // indirect diff --git a/go.sum b/go.sum index 9ea268ed..9bf02032 100644 --- a/go.sum +++ b/go.sum @@ -28,8 +28,6 @@ github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= -github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= -github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -54,8 +52,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= -github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -77,15 +73,15 @@ github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= -github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= -github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= +github.com/xdg-go/scram v1.2.0 h1:bYKF2AEwG5rqd1BumT4gAnvwU/M9nBp2pTSxeZw7Wvs= +github.com/xdg-go/scram v1.2.0/go.mod h1:3dlrS0iBaWKYVt2ZfA4cj48umJZ+cAEbR6/SjLA88I8= github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM= github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.mongodb.org/mongo-driver v1.17.4 h1:jUorfmVzljjr0FLzYQsGP8cgN/qzzxlY9Vh0C9KFXVw= -go.mongodb.org/mongo-driver v1.17.4/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= +go.mongodb.org/mongo-driver/v2 v2.5.0 h1:yXUhImUjjAInNcpTcAlPHiT7bIXhshCTL3jVBkF3xaE= +go.mongodb.org/mongo-driver/v2 v2.5.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0= golang.org/x/arch v0.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c= golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= diff --git a/jobs/db-migration/main.go b/jobs/db-migration/main.go index 36ad56be..09d9f59a 100644 --- a/jobs/db-migration/main.go +++ b/jobs/db-migration/main.go @@ -8,7 +8,7 @@ import ( "path/filepath" "time" - "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/v2/bson" ) func main() { diff --git a/jobs/messaging/participant-messages.go b/jobs/messaging/participant-messages.go index 3cd75468..525e6bf3 100644 --- a/jobs/messaging/participant-messages.go +++ b/jobs/messaging/participant-messages.go @@ -11,8 +11,7 @@ import ( messagingTypes "github.com/case-framework/case-backend/pkg/messaging/types" studyservice "github.com/case-framework/case-backend/pkg/study" studyTypes "github.com/case-framework/case-backend/pkg/study/types" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/v2/bson" ) func handleParticipantMessages(wg *sync.WaitGroup) { @@ -174,7 +173,7 @@ func getRelevantMessages(p studyTypes.Participant) []studyTypes.StudyMessage { if message.ScheduledFor > time.Now().Unix() { continue } - _id, err := primitive.ObjectIDFromHex(message.ID) + _id, err := bson.ObjectIDFromHex(message.ID) if err != nil { slog.Error("Error parsing message id", slog.String("messageID", message.ID), slog.String("error", err.Error())) continue diff --git a/jobs/messaging/scheduled-messages.go b/jobs/messaging/scheduled-messages.go index 082ab534..53073f0a 100644 --- a/jobs/messaging/scheduled-messages.go +++ b/jobs/messaging/scheduled-messages.go @@ -13,7 +13,7 @@ import ( studyTypes "github.com/case-framework/case-backend/pkg/study/types" umTypes "github.com/case-framework/case-backend/pkg/user-management/types" umUtils "github.com/case-framework/case-backend/pkg/user-management/utils" - "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/v2/bson" ) func handleScheduledMessages(wg *sync.WaitGroup) { diff --git a/jobs/study-daily-data-export/response-exporter.go b/jobs/study-daily-data-export/response-exporter.go index 3d48eb04..048d1a0b 100644 --- a/jobs/study-daily-data-export/response-exporter.go +++ b/jobs/study-daily-data-export/response-exporter.go @@ -13,7 +13,7 @@ import ( surveydefinition "github.com/case-framework/case-backend/pkg/study/exporter/survey-definition" surveyresponses "github.com/case-framework/case-backend/pkg/study/exporter/survey-responses" studyTypes "github.com/case-framework/case-backend/pkg/study/types" - "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/v2/bson" ) func runResponseExportsForTask(rExpTask ResponseExportTask) { diff --git a/jobs/study-timer/main.go b/jobs/study-timer/main.go index 283c4802..9e6b0e99 100644 --- a/jobs/study-timer/main.go +++ b/jobs/study-timer/main.go @@ -7,7 +7,7 @@ import ( studyservice "github.com/case-framework/case-backend/pkg/study" studyTypes "github.com/case-framework/case-backend/pkg/study/types" studyUtils "github.com/case-framework/case-backend/pkg/study/utils" - "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/v2/bson" ) func main() { diff --git a/jobs/user-management/generate-id-lookup.go b/jobs/user-management/generate-id-lookup.go index 1cda1ae5..f38e5cf3 100644 --- a/jobs/user-management/generate-id-lookup.go +++ b/jobs/user-management/generate-id-lookup.go @@ -7,7 +7,7 @@ import ( studyService "github.com/case-framework/case-backend/pkg/study" studyTypes "github.com/case-framework/case-backend/pkg/study/types" umTypes "github.com/case-framework/case-backend/pkg/user-management/types" - "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/v2/bson" ) func generateProfileIDLookup() { diff --git a/jobs/user-management/main.go b/jobs/user-management/main.go index 4d996d5f..189e233d 100644 --- a/jobs/user-management/main.go +++ b/jobs/user-management/main.go @@ -5,7 +5,7 @@ import ( "log/slog" "time" - "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/v2/bson" emailsending "github.com/case-framework/case-backend/pkg/messaging/email-sending" emailTypes "github.com/case-framework/case-backend/pkg/messaging/types" diff --git a/jobs/user-management/migrate-account-info.go b/jobs/user-management/migrate-account-info.go index eac09846..40278f4b 100644 --- a/jobs/user-management/migrate-account-info.go +++ b/jobs/user-management/migrate-account-info.go @@ -9,7 +9,7 @@ import ( studyUtils "github.com/case-framework/case-backend/pkg/study/utils" umTypes "github.com/case-framework/case-backend/pkg/user-management/types" umUtils "github.com/case-framework/case-backend/pkg/user-management/utils" - "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/v2/bson" ) func migrateAccountInfo() { diff --git a/pkg/apihelpers/parsePaginatedQuery.go b/pkg/apihelpers/parse-paginated-query.go similarity index 98% rename from pkg/apihelpers/parsePaginatedQuery.go rename to pkg/apihelpers/parse-paginated-query.go index e9ecc1f6..4946d943 100644 --- a/pkg/apihelpers/parsePaginatedQuery.go +++ b/pkg/apihelpers/parse-paginated-query.go @@ -8,7 +8,7 @@ import ( surveyresponses "github.com/case-framework/case-backend/pkg/study/exporter/survey-responses" "github.com/gin-gonic/gin" - "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/v2/bson" ) type PagenatedQuery struct { diff --git a/pkg/db/global-infos/blocked-jwts.go b/pkg/db/global-infos/blocked-jwts.go index 3226c126..d1435f06 100644 --- a/pkg/db/global-infos/blocked-jwts.go +++ b/pkg/db/global-infos/blocked-jwts.go @@ -1,15 +1,24 @@ package globalinfos import ( - "fmt" "log/slog" "time" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" ) +const ( + idxBlockedJwtsToken = "token_1" + idxBlockedJwtsExpiresAt = "expiresAt_1" +) + +var defaultBlockedJwtIndexNames = []string{ + idxBlockedJwtsToken, + idxBlockedJwtsExpiresAt, +} + type BlockedJwt struct { Token string `bson:"token"` ExpiresAt time.Time `bson:"expiresAt"` @@ -20,13 +29,13 @@ var indexesForBlockedJwtsCollection = []mongo.IndexModel{ Keys: bson.D{ {Key: "token", Value: 1}, }, - Options: options.Index().SetName("token_1"), + Options: options.Index().SetName(idxBlockedJwtsToken), }, { Keys: bson.D{ {Key: "expiresAt", Value: 1}, }, - Options: options.Index().SetExpireAfterSeconds(0).SetName("expiresAt_1"), + Options: options.Index().SetExpireAfterSeconds(0).SetName(idxBlockedJwtsExpiresAt), }, } @@ -35,18 +44,17 @@ func (dbService *GlobalInfosDBService) DropIndexForBlockedJwtsCollection(dropAll defer cancel() if dropAll { - _, err := dbService.collectionBlockedJwts().Indexes().DropAll(ctx) + err := dbService.collectionBlockedJwts().Indexes().DropAll(ctx) if err != nil { slog.Error("Error dropping all indexes for blocked jwts", slog.String("error", err.Error())) } } else { - for _, index := range indexesForBlockedJwtsCollection { - if index.Options == nil || index.Options.Name == nil { - slog.Error("Index name is nil for blocked jwts collection", slog.String("index", fmt.Sprintf("%+v", index))) + for _, indexName := range defaultBlockedJwtIndexNames { + if indexName == "" { + slog.Error("Index name is empty for blocked jwts collection") continue } - indexName := *index.Options.Name - _, err := dbService.collectionBlockedJwts().Indexes().DropOne(ctx, indexName) + err := dbService.collectionBlockedJwts().Indexes().DropOne(ctx, indexName) if err != nil { slog.Error("Error dropping index for blocked jwts", slog.String("error", err.Error()), slog.String("indexName", indexName)) } diff --git a/pkg/db/global-infos/db.go b/pkg/db/global-infos/db.go index 74de685a..30d6fd22 100644 --- a/pkg/db/global-infos/db.go +++ b/pkg/db/global-infos/db.go @@ -6,9 +6,9 @@ import ( "time" "github.com/case-framework/case-backend/pkg/db" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" ) // collection names @@ -26,10 +26,7 @@ type GlobalInfosDBService struct { } func NewGlobalInfosDBService(configs db.DBConfig) (*GlobalInfosDBService, error) { - ctx, cancel := context.WithTimeout(context.Background(), time.Duration(configs.Timeout)*time.Second) - defer cancel() - - dbClient, err := mongo.Connect(ctx, + dbClient, err := mongo.Connect( options.Client().ApplyURI(configs.URI), options.Client().SetMaxConnIdleTime(time.Duration(configs.IdleConnTimeout)*time.Second), options.Client().SetMaxPoolSize(configs.MaxPoolSize), diff --git a/pkg/db/global-infos/temptoken.go b/pkg/db/global-infos/temptoken.go index 458f0bc5..64265123 100644 --- a/pkg/db/global-infos/temptoken.go +++ b/pkg/db/global-infos/temptoken.go @@ -2,18 +2,29 @@ package globalinfos import ( "errors" - "fmt" "log/slog" "time" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" userTypes "github.com/case-framework/case-backend/pkg/user-management/types" umUtils "github.com/case-framework/case-backend/pkg/user-management/utils" ) +const ( + idxTemptokensUserIDInstanceIDPurpose = "userID_1_instanceID_1_purpose_1" + idxTemptokensExpiration = "expiration_1" + idxTemptokensToken = "token_1" +) + +var defaultTemptokenIndexNames = []string{ + idxTemptokensUserIDInstanceIDPurpose, + idxTemptokensExpiration, + idxTemptokensToken, +} + var indexesForTemptokensCollection = []mongo.IndexModel{ { Keys: bson.D{ @@ -21,19 +32,19 @@ var indexesForTemptokensCollection = []mongo.IndexModel{ {Key: "instanceID", Value: 1}, {Key: "purpose", Value: 1}, }, - Options: options.Index().SetName("userID_1_instanceID_1_purpose_1"), + Options: options.Index().SetName(idxTemptokensUserIDInstanceIDPurpose), }, { Keys: bson.D{ {Key: "expiration", Value: 1}, }, - Options: options.Index().SetExpireAfterSeconds(0).SetName("expiration_1"), + Options: options.Index().SetExpireAfterSeconds(0).SetName(idxTemptokensExpiration), }, { Keys: bson.D{ {Key: "token", Value: 1}, }, - Options: options.Index().SetUnique(true).SetName("token_1"), + Options: options.Index().SetUnique(true).SetName(idxTemptokensToken), }, } @@ -42,17 +53,16 @@ func (dbService *GlobalInfosDBService) DropIndexForTemptokensCollection(dropAll defer cancel() if dropAll { - if _, err := dbService.collectionTemptokens().Indexes().DropAll(ctx); err != nil { + if err := dbService.collectionTemptokens().Indexes().DropAll(ctx); err != nil { slog.Error("Error dropping indexes for temptokens", slog.String("error", err.Error())) } } else { - for _, index := range indexesForTemptokensCollection { - if index.Options == nil || index.Options.Name == nil { - slog.Error("Index name is nil for temptokens collection", slog.String("index", fmt.Sprintf("%+v", index))) + for _, indexName := range defaultTemptokenIndexNames { + if indexName == "" { + slog.Error("Index name is empty for temptokens collection") continue } - indexName := *index.Options.Name - _, err := dbService.collectionTemptokens().Indexes().DropOne(ctx, indexName) + err := dbService.collectionTemptokens().Indexes().DropOne(ctx, indexName) if err != nil { slog.Error("Error dropping index for temptokens", slog.String("error", err.Error()), slog.String("indexName", indexName)) } diff --git a/pkg/db/management-user/app-roles.go b/pkg/db/management-user/app-roles.go index 0be2c26a..72624570 100644 --- a/pkg/db/management-user/app-roles.go +++ b/pkg/db/management-user/app-roles.go @@ -2,14 +2,12 @@ package managementuser import ( "errors" - "fmt" "log/slog" "time" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" ) // store which users have which roles @@ -22,14 +20,28 @@ func (dbService *ManagementUserDBService) collectionAppRoleTemplates(instanceID return dbService.DBClient.Database(dbService.getDBName(instanceID)).Collection(COLLECTION_NAME_APP_ROLE_TEMPLATES) } +const ( + idxAppRolesSubjectID = "subjectId_1" + idxAppRolesAppName = "appName_1" + idxAppRolesUniqueSubjectTypeRoleKey = "uniq_subjectType_1_subjectId_1_appName_1_role_1" + idxAppRoleTemplatesUniqueAppRole = "uniq_appName_1_role_1" + idxAppRoleTemplatesAppName = "appName_1" +) + +var defaultAppRoleIndexNames = []string{ + idxAppRolesSubjectID, + idxAppRolesAppName, + idxAppRolesUniqueSubjectTypeRoleKey, +} + var indexesForAppRolesCollection = []mongo.IndexModel{ { Keys: bson.D{{Key: "subjectId", Value: 1}}, - Options: options.Index().SetName("subjectId_1"), + Options: options.Index().SetName(idxAppRolesSubjectID), }, { Keys: bson.D{{Key: "appName", Value: 1}}, - Options: options.Index().SetName("appName_1"), + Options: options.Index().SetName(idxAppRolesAppName), }, { Keys: bson.D{ @@ -38,7 +50,7 @@ var indexesForAppRolesCollection = []mongo.IndexModel{ {Key: "appName", Value: 1}, {Key: "role", Value: 1}, }, - Options: options.Index().SetName("uniq_subjectType_1_subjectId_1_appName_1_role_1").SetUnique(true), + Options: options.Index().SetName(idxAppRolesUniqueSubjectTypeRoleKey).SetUnique(true), }, } @@ -46,18 +58,17 @@ func (dbService *ManagementUserDBService) DropIndexForAppRolesCollection(instanc ctx, cancel := dbService.getContext() defer cancel() if dropAll { - _, err := dbService.collectionAppRoles(instanceID).Indexes().DropAll(ctx) + err := dbService.collectionAppRoles(instanceID).Indexes().DropAll(ctx) if err != nil { slog.Error("Error dropping all indexes for app roles", slog.String("error", err.Error())) } } else { - for _, index := range indexesForAppRolesCollection { - if index.Options == nil || index.Options.Name == nil { - slog.Error("Index name is nil for app roles collection", slog.String("index", fmt.Sprintf("%+v", index))) + for _, indexName := range defaultAppRoleIndexNames { + if indexName == "" { + slog.Error("Index name is empty for app roles collection") continue } - indexName := *index.Options.Name - _, err := dbService.collectionAppRoles(instanceID).Indexes().DropOne(ctx, indexName) + err := dbService.collectionAppRoles(instanceID).Indexes().DropOne(ctx, indexName) if err != nil { slog.Error("Error dropping index for app roles", slog.String("error", err.Error()), slog.String("indexName", indexName)) } @@ -75,14 +86,19 @@ func (dbService *ManagementUserDBService) CreateDefaultIndexesForAppRolesCollect } } +var defaultAppRoleTemplateIndexNames = []string{ + idxAppRoleTemplatesUniqueAppRole, + idxAppRoleTemplatesAppName, +} + var indexesForAppRoleTemplatesCollection = []mongo.IndexModel{ { Keys: bson.D{{Key: "appName", Value: 1}, {Key: "role", Value: 1}}, - Options: options.Index().SetName("uniq_appName_1_role_1").SetUnique(true), + Options: options.Index().SetName(idxAppRoleTemplatesUniqueAppRole).SetUnique(true), }, { Keys: bson.D{{Key: "appName", Value: 1}}, - Options: options.Index().SetName("appName_1"), + Options: options.Index().SetName(idxAppRoleTemplatesAppName), }, } @@ -90,18 +106,17 @@ func (dbService *ManagementUserDBService) DropIndexForAppRoleTemplatesCollection ctx, cancel := dbService.getContext() defer cancel() if dropAll { - _, err := dbService.collectionAppRoleTemplates(instanceID).Indexes().DropAll(ctx) + err := dbService.collectionAppRoleTemplates(instanceID).Indexes().DropAll(ctx) if err != nil { slog.Error("Error dropping all indexes for app role templates", slog.String("error", err.Error())) } } else { - for _, index := range indexesForAppRoleTemplatesCollection { - if index.Options == nil || index.Options.Name == nil { - slog.Error("Index name is nil for app role templates collection: ", slog.String("index", fmt.Sprintf("%+v", index))) + for _, indexName := range defaultAppRoleTemplateIndexNames { + if indexName == "" { + slog.Error("Index name is empty for app role templates collection") continue } - indexName := *index.Options.Name - _, err := dbService.collectionAppRoleTemplates(instanceID).Indexes().DropOne(ctx, indexName) + err := dbService.collectionAppRoleTemplates(instanceID).Indexes().DropOne(ctx, indexName) if err != nil { slog.Error("Error dropping index for app role templates", slog.String("error", err.Error()), slog.String("indexName", indexName)) } @@ -141,7 +156,7 @@ func (dbService *ManagementUserDBService) AddAppRoleTemplate( if err != nil { return err } - appRoleTemplate.ID = res.InsertedID.(primitive.ObjectID) + appRoleTemplate.ID = res.InsertedID.(bson.ObjectID) return nil } @@ -174,7 +189,7 @@ func (dbService *ManagementUserDBService) GetAppRoleTemplateByID( ctx, cancel := dbService.getContext() defer cancel() - objID, err := primitive.ObjectIDFromHex(appRoleTemplateID) + objID, err := bson.ObjectIDFromHex(appRoleTemplateID) if err != nil { return AppRoleTemplate{}, err } @@ -198,7 +213,7 @@ func (dbService *ManagementUserDBService) UpdateAppRoleTemplate( ctx, cancel := dbService.getContext() defer cancel() - objID, err := primitive.ObjectIDFromHex(appRoleTemplateID) + objID, err := bson.ObjectIDFromHex(appRoleTemplateID) if err != nil { return err } @@ -228,7 +243,7 @@ func (dbService *ManagementUserDBService) DeleteAppRoleTemplate( ctx, cancel := dbService.getContext() defer cancel() - objID, err := primitive.ObjectIDFromHex(appRoleTemplateID) + objID, err := bson.ObjectIDFromHex(appRoleTemplateID) if err != nil { return err } @@ -272,7 +287,7 @@ func (dbService *ManagementUserDBService) AddAppRoleForSubject( if err != nil { return err } - appRole.ID = res.InsertedID.(primitive.ObjectID) + appRole.ID = res.InsertedID.(bson.ObjectID) return nil } @@ -327,7 +342,7 @@ func (dbService *ManagementUserDBService) DeleteAppRole( ctx, cancel := dbService.getContext() defer cancel() - objID, err := primitive.ObjectIDFromHex(appRoleID) + objID, err := bson.ObjectIDFromHex(appRoleID) if err != nil { return err } diff --git a/pkg/db/management-user/db.go b/pkg/db/management-user/db.go index a70e90c1..e73b3c69 100644 --- a/pkg/db/management-user/db.go +++ b/pkg/db/management-user/db.go @@ -6,9 +6,9 @@ import ( "time" "github.com/case-framework/case-backend/pkg/db" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" ) // collection names @@ -35,10 +35,7 @@ type ManagementUserDBService struct { } func NewManagementUserDBService(configs db.DBConfig) (*ManagementUserDBService, error) { - ctx, cancel := context.WithTimeout(context.Background(), time.Duration(configs.Timeout)*time.Second) - defer cancel() - - dbClient, err := mongo.Connect(ctx, + dbClient, err := mongo.Connect( options.Client().ApplyURI(configs.URI), options.Client().SetMaxConnIdleTime(time.Duration(configs.IdleConnTimeout)*time.Second), options.Client().SetMaxPoolSize(configs.MaxPoolSize), diff --git a/pkg/db/management-user/management-users.go b/pkg/db/management-user/management-users.go index fb6c1b6b..e701efa8 100644 --- a/pkg/db/management-user/management-users.go +++ b/pkg/db/management-user/management-users.go @@ -1,20 +1,22 @@ package managementuser import ( - "fmt" "log/slog" "time" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" ) +const idxManagementUsersSub = "uniq_sub_1" + +var defaultManagementUserIndexNames = []string{idxManagementUsersSub} + var indexesForManagementUsersCollection = []mongo.IndexModel{ { Keys: bson.D{{Key: "sub", Value: 1}}, - Options: options.Index().SetUnique(true).SetName("uniq_sub_1"), + Options: options.Index().SetUnique(true).SetName(idxManagementUsersSub), }, } @@ -23,18 +25,17 @@ func (dbService *ManagementUserDBService) DropIndexForManagementUsersCollection( defer cancel() if dropAll { - _, err := dbService.collectionManagementUsers(instanceID).Indexes().DropAll(ctx) + err := dbService.collectionManagementUsers(instanceID).Indexes().DropAll(ctx) if err != nil { slog.Error("Error dropping all indexes for management users", slog.String("error", err.Error())) } } else { - for _, index := range indexesForManagementUsersCollection { - if index.Options == nil || index.Options.Name == nil { - slog.Error("Index name is nil for management users collection", slog.String("index", fmt.Sprintf("%+v", index)), slog.String("instanceID", instanceID)) + for _, indexName := range defaultManagementUserIndexNames { + if indexName == "" { + slog.Error("Index name is empty for management users collection", slog.String("instanceID", instanceID)) continue } - indexName := *index.Options.Name - _, err := dbService.collectionManagementUsers(instanceID).Indexes().DropOne(ctx, indexName) + err := dbService.collectionManagementUsers(instanceID).Indexes().DropOne(ctx, indexName) if err != nil { slog.Error("Error dropping index for management users", slog.String("error", err.Error()), slog.String("indexName", indexName), slog.String("instanceID", instanceID)) } @@ -62,7 +63,7 @@ func (dbService *ManagementUserDBService) CreateUser( if err != nil { return nil, err } - newUser.ID = res.InsertedID.(primitive.ObjectID) + newUser.ID = res.InsertedID.(bson.ObjectID) return newUser, nil } @@ -89,7 +90,7 @@ func (dbService *ManagementUserDBService) GetUserByID( ctx, cancel := dbService.getContext() defer cancel() var user ManagementUser - objID, err := primitive.ObjectIDFromHex(id) + objID, err := bson.ObjectIDFromHex(id) if err != nil { return nil, err } @@ -113,7 +114,7 @@ func (dbService *ManagementUserDBService) UpdateUser( ) error { ctx, cancel := dbService.getContext() defer cancel() - objID, err := primitive.ObjectIDFromHex(id) + objID, err := bson.ObjectIDFromHex(id) if err != nil { return err } @@ -149,7 +150,7 @@ func (dbService *ManagementUserDBService) DeleteUser( } // delete the user - objID, err := primitive.ObjectIDFromHex(id) + objID, err := bson.ObjectIDFromHex(id) if err != nil { return err } @@ -204,9 +205,9 @@ func (dbService *ManagementUserDBService) GetUsersByIDs( ctx, cancel := dbService.getContext() defer cancel() - var objIDs []primitive.ObjectID + var objIDs []bson.ObjectID for _, id := range ids { - objID, err := primitive.ObjectIDFromHex(id) + objID, err := bson.ObjectIDFromHex(id) if err != nil { return nil, err } diff --git a/pkg/db/management-user/permissions.go b/pkg/db/management-user/permissions.go index 290b1d8d..a80f0de3 100644 --- a/pkg/db/management-user/permissions.go +++ b/pkg/db/management-user/permissions.go @@ -1,15 +1,17 @@ package managementuser import ( - "fmt" "log/slog" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" ) +const idxPermissionsSubjectResourceAction = "subjectId_1_subjectType_1_resourceType_1_resourceKey_1_action_1" + +var defaultPermissionIndexNames = []string{idxPermissionsSubjectResourceAction} + var indexesForPermissionsCollection = []mongo.IndexModel{ { Keys: bson.D{ @@ -19,7 +21,7 @@ var indexesForPermissionsCollection = []mongo.IndexModel{ {Key: "resourceKey", Value: 1}, {Key: "action", Value: 1}, }, - Options: options.Index().SetName("subjectId_1_subjectType_1_resourceType_1_resourceKey_1_action_1"), + Options: options.Index().SetName(idxPermissionsSubjectResourceAction), }, } @@ -28,18 +30,17 @@ func (dbService *ManagementUserDBService) DropIndexForPermissionsCollection(inst defer cancel() if dropAll { - _, err := dbService.collectionPermissions(instanceID).Indexes().DropAll(ctx) + err := dbService.collectionPermissions(instanceID).Indexes().DropAll(ctx) if err != nil { slog.Error("Error dropping all indexes for permissions: ", slog.String("error", err.Error())) } } else { - for _, index := range indexesForPermissionsCollection { - if index.Options == nil || index.Options.Name == nil { - slog.Error("Index name is nil for permissions collection: ", slog.String("index", fmt.Sprintf("%+v", index))) + for _, indexName := range defaultPermissionIndexNames { + if indexName == "" { + slog.Error("Index name is empty for permissions collection") continue } - indexName := *index.Options.Name - _, err := dbService.collectionPermissions(instanceID).Indexes().DropOne(ctx, indexName) + err := dbService.collectionPermissions(instanceID).Indexes().DropOne(ctx, indexName) if err != nil { slog.Error("Error dropping index for permissions: ", slog.String("error", err.Error()), slog.String("indexName", indexName)) } @@ -82,7 +83,7 @@ func (dbService *ManagementUserDBService) CreatePermission( if err != nil { return nil, err } - permission.ID = res.InsertedID.(primitive.ObjectID) + permission.ID = res.InsertedID.(bson.ObjectID) return permission, nil } @@ -94,7 +95,7 @@ func (dbService *ManagementUserDBService) GetPermissionByID( ctx, cancel := dbService.getContext() defer cancel() - objID, err := primitive.ObjectIDFromHex(permissionID) + objID, err := bson.ObjectIDFromHex(permissionID) if err != nil { return nil, err } @@ -195,7 +196,7 @@ func (dbService *ManagementUserDBService) UpdatePermissionLimiter( ctx, cancel := dbService.getContext() defer cancel() - objID, err := primitive.ObjectIDFromHex(permissionID) + objID, err := bson.ObjectIDFromHex(permissionID) if err != nil { return err } @@ -217,7 +218,7 @@ func (dbService *ManagementUserDBService) DeletePermission( ctx, cancel := dbService.getContext() defer cancel() - objID, err := primitive.ObjectIDFromHex(permissionID) + objID, err := bson.ObjectIDFromHex(permissionID) if err != nil { return err } diff --git a/pkg/db/management-user/service-users.go b/pkg/db/management-user/service-users.go index 9c32d97a..2e6d3216 100644 --- a/pkg/db/management-user/service-users.go +++ b/pkg/db/management-user/service-users.go @@ -2,16 +2,24 @@ package managementuser import ( "errors" - "fmt" "log/slog" "time" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" ) +const ( + idxServiceUserAPIKeysKey = "key_1" + idxServiceUserAPIKeysExpiresAt = "expiresAt_1" +) + +var defaultServiceUserAPIKeyIndexNames = []string{ + idxServiceUserAPIKeysKey, + idxServiceUserAPIKeysExpiresAt, +} + func (dbService *ManagementUserDBService) collectionServiceUsers(instanceID string) *mongo.Collection { return dbService.DBClient.Database(dbService.getDBName(instanceID)).Collection(COLLECTION_NAME_SERVICE_USERS) } @@ -25,13 +33,13 @@ var indexesForServiceUserAPIKeysCollection = []mongo.IndexModel{ Keys: bson.D{ {Key: "key", Value: 1}, }, - Options: options.Index().SetUnique(true).SetName("key_1"), + Options: options.Index().SetUnique(true).SetName(idxServiceUserAPIKeysKey), }, { Keys: bson.D{ {Key: "expiresAt", Value: 1}, }, - Options: options.Index().SetExpireAfterSeconds(0).SetName("expiresAt_1"), + Options: options.Index().SetExpireAfterSeconds(0).SetName(idxServiceUserAPIKeysExpiresAt), }, } @@ -40,18 +48,17 @@ func (dbService *ManagementUserDBService) DropIndexForServiceUserAPIKeysCollecti defer cancel() if dropAll { - _, err := dbService.collectionServiceUserAPIKeys(instanceID).Indexes().DropAll(ctx) + err := dbService.collectionServiceUserAPIKeys(instanceID).Indexes().DropAll(ctx) if err != nil { slog.Error("Error dropping all indexes for service user API keys: ", slog.String("error", err.Error())) } } else { - for _, index := range indexesForServiceUserAPIKeysCollection { - if index.Options == nil || index.Options.Name == nil { - slog.Error("Index name is nil for service user API keys collection: ", slog.String("index", fmt.Sprintf("%+v", index))) + for _, indexName := range defaultServiceUserAPIKeyIndexNames { + if indexName == "" { + slog.Error("Index name is empty for service user API keys collection") continue } - indexName := *index.Options.Name - _, err := dbService.collectionServiceUserAPIKeys(instanceID).Indexes().DropOne(ctx, indexName) + err := dbService.collectionServiceUserAPIKeys(instanceID).Indexes().DropOne(ctx, indexName) if err != nil { slog.Error("Error dropping index for service user API keys: ", slog.String("error", err.Error()), slog.String("indexName", indexName)) } @@ -92,7 +99,7 @@ func (dbService *ManagementUserDBService) CreateServiceUser(instanceID string, l return nil, err } - serviceUser.ID = result.InsertedID.(primitive.ObjectID) + serviceUser.ID = result.InsertedID.(bson.ObjectID) return serviceUser, nil } @@ -102,7 +109,7 @@ func (dbService *ManagementUserDBService) GetServiceUserByID(instanceID string, ctx, cancel := dbService.getContext() defer cancel() - _id, err := primitive.ObjectIDFromHex(id) + _id, err := bson.ObjectIDFromHex(id) if err != nil { return nil, err } @@ -148,7 +155,7 @@ func (dbService *ManagementUserDBService) DeleteServiceUser(instanceID string, i ctx, cancel := dbService.getContext() defer cancel() - _id, err := primitive.ObjectIDFromHex(id) + _id, err := bson.ObjectIDFromHex(id) if err != nil { slog.Error("Error converting ID to ObjectID", slog.String("error", err.Error())) return err @@ -180,7 +187,7 @@ func (dbService *ManagementUserDBService) UpdateServiceUser(instanceID string, i ctx, cancel := dbService.getContext() defer cancel() - _id, err := primitive.ObjectIDFromHex(id) + _id, err := bson.ObjectIDFromHex(id) if err != nil { slog.Error("Error converting ID to ObjectID", slog.String("error", err.Error())) return err @@ -258,7 +265,7 @@ func (dbService *ManagementUserDBService) DeleteServiceUserAPIKey(instanceID str ctx, cancel := dbService.getContext() defer cancel() - _id, err := primitive.ObjectIDFromHex(id) + _id, err := bson.ObjectIDFromHex(id) if err != nil { return err } diff --git a/pkg/db/management-user/sessions.go b/pkg/db/management-user/sessions.go index 94214d07..d14e34e1 100644 --- a/pkg/db/management-user/sessions.go +++ b/pkg/db/management-user/sessions.go @@ -1,16 +1,18 @@ package managementuser import ( - "fmt" "log/slog" "time" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" ) +const idxSessionsCreatedAt = "createdAt_1" + +var defaultSessionIndexNames = []string{idxSessionsCreatedAt} + func (dbService *ManagementUserDBService) collectionSessions(instanceID string) *mongo.Collection { return dbService.DBClient.Database(dbService.getDBName(instanceID)).Collection(COLLECTION_NAME_SESSIONS) } @@ -18,7 +20,7 @@ func (dbService *ManagementUserDBService) collectionSessions(instanceID string) var indexesForSessionsCollection = []mongo.IndexModel{ { Keys: bson.D{{Key: "createdAt", Value: 1}}, - Options: options.Index().SetExpireAfterSeconds(REMOVE_SESSIONS_AFTER).SetName("createdAt_1"), + Options: options.Index().SetExpireAfterSeconds(REMOVE_SESSIONS_AFTER).SetName(idxSessionsCreatedAt), }, } @@ -27,18 +29,17 @@ func (dbService *ManagementUserDBService) DropIndexForSessionsCollection(instanc defer cancel() if dropAll { - _, err := dbService.collectionSessions(instanceID).Indexes().DropAll(ctx) + err := dbService.collectionSessions(instanceID).Indexes().DropAll(ctx) if err != nil { slog.Error("Error dropping all indexes for sessions", slog.String("error", err.Error())) } } else { - for _, index := range indexesForSessionsCollection { - if index.Options == nil || index.Options.Name == nil { - slog.Error("Index name is nil for sessions collection: ", slog.String("index", fmt.Sprintf("%+v", index))) + for _, indexName := range defaultSessionIndexNames { + if indexName == "" { + slog.Error("Index name is empty for sessions collection") continue } - indexName := *index.Options.Name - _, err := dbService.collectionSessions(instanceID).Indexes().DropOne(ctx, indexName) + err := dbService.collectionSessions(instanceID).Indexes().DropOne(ctx, indexName) if err != nil { slog.Error("Error dropping index for sessions", slog.String("error", err.Error()), slog.String("indexName", indexName)) } @@ -74,7 +75,7 @@ func (dbService *ManagementUserDBService) CreateSession( if err != nil { return nil, err } - session.ID = res.InsertedID.(primitive.ObjectID) + session.ID = res.InsertedID.(bson.ObjectID) return session, nil } @@ -87,7 +88,7 @@ func (dbService *ManagementUserDBService) GetSession( defer cancel() var session Session - objID, err := primitive.ObjectIDFromHex(sessionID) + objID, err := bson.ObjectIDFromHex(sessionID) if err != nil { return nil, err } @@ -106,7 +107,7 @@ func (dbService *ManagementUserDBService) DeleteSession( ctx, cancel := dbService.getContext() defer cancel() - objID, err := primitive.ObjectIDFromHex(sessionID) + objID, err := bson.ObjectIDFromHex(sessionID) if err != nil { return err } diff --git a/pkg/db/management-user/types.go b/pkg/db/management-user/types.go index 58fa968b..ecd22168 100644 --- a/pkg/db/management-user/types.go +++ b/pkg/db/management-user/types.go @@ -3,13 +3,13 @@ package managementuser import ( "time" - "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/v2/bson" ) // enum for the subject type type Permission struct { - ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` + ID bson.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` SubjectID string `json:"subjectId,omitempty" bson:"subjectId,omitempty"` SubjectType string `json:"subjectType,omitempty" bson:"subjectType,omitempty"` ResourceType string `json:"resourceType,omitempty" bson:"resourceType,omitempty"` @@ -25,7 +25,7 @@ type Permission struct { // Action is the action that is allowed e.g., download_responses, upload_survey, etc. type ManagementUser struct { - ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` + ID bson.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` Sub string `json:"sub,omitempty" bson:"sub,omitempty"` Email string `json:"email,omitempty" bson:"email,omitempty"` Username string `json:"username,omitempty" bson:"username,omitempty"` @@ -37,42 +37,42 @@ type ManagementUser struct { } type Session struct { - ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` - UserID string `json:"userId,omitempty" bson:"userId,omitempty"` - RenewToken string `json:"renewToken,omitempty" bson:"renewToken,omitempty"` - CreatedAt time.Time `json:"createdAt,omitempty" bson:"createdAt,omitempty"` + ID bson.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` + UserID string `json:"userId,omitempty" bson:"userId,omitempty"` + RenewToken string `json:"renewToken,omitempty" bson:"renewToken,omitempty"` + CreatedAt time.Time `json:"createdAt,omitempty" bson:"createdAt,omitempty"` } type ServiceUser struct { - ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` - Label string `json:"label,omitempty" bson:"label,omitempty"` - Description string `json:"description,omitempty" bson:"description,omitempty"` - CreatedAt time.Time `json:"createdAt,omitempty" bson:"createdAt,omitempty"` + ID bson.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` + Label string `json:"label,omitempty" bson:"label,omitempty"` + Description string `json:"description,omitempty" bson:"description,omitempty"` + CreatedAt time.Time `json:"createdAt,omitempty" bson:"createdAt,omitempty"` } type ServiceUserAPIKey struct { - ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` - ServiceUserID string `json:"serviceUserId,omitempty" bson:"serviceUserId,omitempty"` - Key string `json:"key,omitempty" bson:"key,omitempty"` - ExpiresAt *time.Time `json:"expiresAt,omitempty" bson:"expiresAt,omitempty"` - CreatedAt time.Time `json:"createdAt,omitempty" bson:"createdAt,omitempty"` - LastUsedAt time.Time `json:"lastUsedAt,omitempty" bson:"lastUsedAt,omitempty"` + ID bson.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` + ServiceUserID string `json:"serviceUserId,omitempty" bson:"serviceUserId,omitempty"` + Key string `json:"key,omitempty" bson:"key,omitempty"` + ExpiresAt *time.Time `json:"expiresAt,omitempty" bson:"expiresAt,omitempty"` + CreatedAt time.Time `json:"createdAt,omitempty" bson:"createdAt,omitempty"` + LastUsedAt time.Time `json:"lastUsedAt,omitempty" bson:"lastUsedAt,omitempty"` } type AppRole struct { - ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` - SubjectID string `json:"subjectId,omitempty" bson:"subjectId,omitempty"` - SubjectType string `json:"subjectType,omitempty" bson:"subjectType,omitempty"` - AppName string `json:"appName,omitempty" bson:"appName,omitempty"` - Role string `json:"role,omitempty" bson:"role,omitempty"` - CreatedAt time.Time `json:"createdAt,omitempty" bson:"createdAt,omitempty"` + ID bson.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` + SubjectID string `json:"subjectId,omitempty" bson:"subjectId,omitempty"` + SubjectType string `json:"subjectType,omitempty" bson:"subjectType,omitempty"` + AppName string `json:"appName,omitempty" bson:"appName,omitempty"` + Role string `json:"role,omitempty" bson:"role,omitempty"` + CreatedAt time.Time `json:"createdAt,omitempty" bson:"createdAt,omitempty"` } type AppRoleTemplate struct { - ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` - AppName string `json:"appName,omitempty" bson:"appName,omitempty"` - Role string `json:"role,omitempty" bson:"role,omitempty"` - RequiredPermissions []Permission `json:"requiredPermissions,omitempty" bson:"requiredPermissions,omitempty"` - CreatedAt time.Time `json:"createdAt,omitempty" bson:"createdAt,omitempty"` - UpdatedAt time.Time `json:"updatedAt,omitempty" bson:"updatedAt,omitempty"` + ID bson.ObjectID `json:"id,omitempty" bson:"_id,omitempty"` + AppName string `json:"appName,omitempty" bson:"appName,omitempty"` + Role string `json:"role,omitempty" bson:"role,omitempty"` + RequiredPermissions []Permission `json:"requiredPermissions,omitempty" bson:"requiredPermissions,omitempty"` + CreatedAt time.Time `json:"createdAt,omitempty" bson:"createdAt,omitempty"` + UpdatedAt time.Time `json:"updatedAt,omitempty" bson:"updatedAt,omitempty"` } diff --git a/pkg/db/messaging/db.go b/pkg/db/messaging/db.go index 5cce09e4..c496597a 100644 --- a/pkg/db/messaging/db.go +++ b/pkg/db/messaging/db.go @@ -6,9 +6,9 @@ import ( "time" "github.com/case-framework/case-backend/pkg/db" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" ) // collection names @@ -30,10 +30,7 @@ type MessagingDBService struct { } func NewMessagingDBService(configs db.DBConfig) (*MessagingDBService, error) { - ctx, cancel := context.WithTimeout(context.Background(), time.Duration(configs.Timeout)*time.Second) - defer cancel() - - dbClient, err := mongo.Connect(ctx, + dbClient, err := mongo.Connect( options.Client().ApplyURI(configs.URI), options.Client().SetMaxConnIdleTime(time.Duration(configs.IdleConnTimeout)*time.Second), options.Client().SetMaxPoolSize(configs.MaxPoolSize), diff --git a/pkg/db/messaging/email-templates.go b/pkg/db/messaging/email-templates.go index 67733751..177925f0 100644 --- a/pkg/db/messaging/email-templates.go +++ b/pkg/db/messaging/email-templates.go @@ -1,24 +1,28 @@ package messaging import ( - "fmt" "log/slog" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" messagingTypes "github.com/case-framework/case-backend/pkg/messaging/types" ) +const idxEmailTemplatesMessageTypeStudyKey = "messageType_1_studyKey_1" + +var defaultEmailTemplateIndexNames = []string{ + idxEmailTemplatesMessageTypeStudyKey, +} + var indexesForEmailTemplatesCollection = []mongo.IndexModel{ { Keys: bson.D{ {Key: "messageType", Value: 1}, {Key: "studyKey", Value: 1}, }, - Options: options.Index().SetUnique(true).SetName("messageType_1_studyKey_1"), + Options: options.Index().SetUnique(true).SetName(idxEmailTemplatesMessageTypeStudyKey), }, } @@ -27,18 +31,17 @@ func (messagingDBService *MessagingDBService) DropIndexForEmailTemplatesCollecti defer cancel() if dropAll { - _, err := messagingDBService.collectionEmailTemplates(instanceID).Indexes().DropAll(ctx) + err := messagingDBService.collectionEmailTemplates(instanceID).Indexes().DropAll(ctx) if err != nil { slog.Error("Error dropping all indexes for email templates", slog.String("error", err.Error()), slog.String("instanceID", instanceID)) } } else { - for _, index := range indexesForEmailTemplatesCollection { - if index.Options == nil || index.Options.Name == nil { - slog.Error("Index name is nil for email templates collection", slog.String("index", fmt.Sprintf("%+v", index))) + for _, indexName := range defaultEmailTemplateIndexNames { + if indexName == "" { + slog.Error("Index name is empty for email templates collection") continue } - indexName := *index.Options.Name - _, err := messagingDBService.collectionEmailTemplates(instanceID).Indexes().DropOne(ctx, indexName) + err := messagingDBService.collectionEmailTemplates(instanceID).Indexes().DropOne(ctx, indexName) if err != nil { slog.Error("Error dropping index for email templates", slog.String("error", err.Error()), slog.String("instanceID", instanceID), slog.String("indexName", indexName)) } @@ -93,7 +96,7 @@ func (messagingDBService *MessagingDBService) GetEmailTemplateByID(instanceID st ctx, cancel := messagingDBService.getContext() defer cancel() - _id, err := primitive.ObjectIDFromHex(id) + _id, err := bson.ObjectIDFromHex(id) if err != nil { return nil, err } @@ -114,22 +117,21 @@ func (messagingDBService *MessagingDBService) SaveEmailTemplate(instanceID strin defer cancel() if emailTemplate.ID.IsZero() { - emailTemplate.ID = primitive.NewObjectID() + emailTemplate.ID = bson.NewObjectID() // new email template res, err := messagingDBService.collectionEmailTemplates(instanceID).InsertOne(ctx, emailTemplate) if err != nil { return messagingTypes.EmailTemplate{}, err } - emailTemplate.ID = res.InsertedID.(primitive.ObjectID) + emailTemplate.ID = res.InsertedID.(bson.ObjectID) return emailTemplate, nil } // update email template filter := bson.M{"_id": emailTemplate.ID} - upsert := false - after := options.After - opt := options.FindOneAndReplaceOptions{Upsert: &upsert, ReturnDocument: &after} - err := messagingDBService.collectionEmailTemplates(instanceID).FindOneAndReplace(ctx, filter, emailTemplate, &opt).Decode(&emailTemplate) + opt := options.FindOneAndReplace().SetUpsert(false).SetReturnDocument(options.After) + err := messagingDBService.collectionEmailTemplates(instanceID).FindOneAndReplace(ctx, filter, emailTemplate, opt).Decode(&emailTemplate) + if err != nil { return messagingTypes.EmailTemplate{}, err } diff --git a/pkg/db/messaging/outgoing-emails.go b/pkg/db/messaging/outgoing-emails.go index 7cfc82c3..1b4ac26b 100644 --- a/pkg/db/messaging/outgoing-emails.go +++ b/pkg/db/messaging/outgoing-emails.go @@ -6,8 +6,7 @@ import ( "time" messagingTypes "github.com/case-framework/case-backend/pkg/messaging/types" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/v2/bson" ) func (dbService *MessagingDBService) DropIndexForOutgoingEmailsCollection(instanceID string, dropAll bool) { @@ -15,7 +14,7 @@ func (dbService *MessagingDBService) DropIndexForOutgoingEmailsCollection(instan defer cancel() if dropAll { - _, err := dbService.collectionOutgoingEmails(instanceID).Indexes().DropAll(ctx) + err := dbService.collectionOutgoingEmails(instanceID).Indexes().DropAll(ctx) if err != nil { slog.Error("Error dropping all indexes for outgoing emails", slog.String("error", err.Error()), slog.String("instanceID", instanceID)) } @@ -36,7 +35,7 @@ func (dbService *MessagingDBService) AddToOutgoingEmails(instanceID string, emai if err != nil { return email, err } - email.ID = res.InsertedID.(primitive.ObjectID) + email.ID = res.InsertedID.(bson.ObjectID) return email, nil } @@ -92,7 +91,7 @@ func (dbService *MessagingDBService) ResetLastSendAttemptForOutgoing(instanceID ctx, cancel := dbService.getContext() defer cancel() - _id, _ := primitive.ObjectIDFromHex(emailID) + _id, _ := bson.ObjectIDFromHex(emailID) filter := bson.M{"_id": _id} update := bson.M{"$set": bson.M{"lastSendAttempt": 0}} res, err := dbService.collectionOutgoingEmails(instanceID).UpdateOne(ctx, filter, update) @@ -109,10 +108,10 @@ func (dbService *MessagingDBService) DeleteOutgoingEmail(instanceID string, id s ctx, cancel := dbService.getContext() defer cancel() - _id, _ := primitive.ObjectIDFromHex(id) + _id, _ := bson.ObjectIDFromHex(id) filter := bson.M{"_id": _id} - res, err := dbService.collectionOutgoingEmails(instanceID).DeleteOne(ctx, filter, nil) + res, err := dbService.collectionOutgoingEmails(instanceID).DeleteOne(ctx, filter) if err != nil { return err } diff --git a/pkg/db/messaging/scheduledEmail.go b/pkg/db/messaging/scheduled-email.go similarity index 82% rename from pkg/db/messaging/scheduledEmail.go rename to pkg/db/messaging/scheduled-email.go index 19b27904..36aa42ea 100644 --- a/pkg/db/messaging/scheduledEmail.go +++ b/pkg/db/messaging/scheduled-email.go @@ -6,9 +6,8 @@ import ( messagingTypes "github.com/case-framework/case-backend/pkg/messaging/types" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo/options" ) func (dbService *MessagingDBService) DropIndexForEmailSchedulesCollection(instanceID string, dropAll bool) { @@ -16,7 +15,7 @@ func (dbService *MessagingDBService) DropIndexForEmailSchedulesCollection(instan defer cancel() if dropAll { - _, err := dbService.collectionEmailSchedules(instanceID).Indexes().DropAll(ctx) + err := dbService.collectionEmailSchedules(instanceID).Indexes().DropAll(ctx) if err != nil { slog.Error("Error dropping all indexes for email schedules", slog.String("error", err.Error()), slog.String("instanceID", instanceID)) } @@ -85,7 +84,7 @@ func (dbService *MessagingDBService) GetScheduledEmailByID(instanceID string, id ctx, cancel := dbService.getContext() defer cancel() - _id, err := primitive.ObjectIDFromHex(id) + _id, err := bson.ObjectIDFromHex(id) if err != nil { return nil, err } @@ -106,24 +105,21 @@ func (dbService *MessagingDBService) SaveScheduledEmail(instanceID string, sched if !scheduledEmail.ID.IsZero() { filter := bson.M{"_id": scheduledEmail.ID} - upsert := false - rd := options.After - options := options.FindOneAndReplaceOptions{ - Upsert: &upsert, - ReturnDocument: &rd, - } + opts := options.FindOneAndReplace(). + SetUpsert(false). + SetReturnDocument(options.After) elem := messagingTypes.ScheduledEmail{} - err := dbService.collectionEmailSchedules(instanceID).FindOneAndReplace( - ctx, filter, scheduledEmail, &options, - ).Decode(&elem) + err := dbService.collectionEmailSchedules(instanceID). + FindOneAndReplace(ctx, filter, scheduledEmail, opts). + Decode(&elem) return elem, err } else { - scheduledEmail.ID = primitive.NewObjectID() + scheduledEmail.ID = bson.NewObjectID() res, err := dbService.collectionEmailSchedules(instanceID).InsertOne(ctx, scheduledEmail) if err != nil { return scheduledEmail, err } - scheduledEmail.ID = res.InsertedID.(primitive.ObjectID) + scheduledEmail.ID = res.InsertedID.(bson.ObjectID) return scheduledEmail, nil } } @@ -133,7 +129,7 @@ func (dbService *MessagingDBService) DeleteScheduledEmail(instanceID string, id ctx, cancel := dbService.getContext() defer cancel() - _id, err := primitive.ObjectIDFromHex(id) + _id, err := bson.ObjectIDFromHex(id) if err != nil { return err } diff --git a/pkg/db/messaging/sent-emails.go b/pkg/db/messaging/sent-emails.go index 696a3477..7550d90b 100644 --- a/pkg/db/messaging/sent-emails.go +++ b/pkg/db/messaging/sent-emails.go @@ -1,24 +1,28 @@ package messaging import ( - "fmt" "log/slog" "time" messagingTypes "github.com/case-framework/case-backend/pkg/messaging/types" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" ) +const idxSentEmailsUserIDSentAt = "userId_1_sentAt_1" + +var defaultSentEmailIndexNames = []string{ + idxSentEmailsUserIDSentAt, +} + var indexesForSentEmailsCollection = []mongo.IndexModel{ { Keys: bson.D{ {Key: "userId", Value: 1}, {Key: "sentAt", Value: 1}, }, - Options: options.Index().SetName("userId_1_sentAt_1"), + Options: options.Index().SetName(idxSentEmailsUserIDSentAt), }, } @@ -27,18 +31,17 @@ func (dbService *MessagingDBService) DropIndexForSentEmailsCollection(instanceID defer cancel() if dropAll { - _, err := dbService.collectionSentEmails(instanceID).Indexes().DropAll(ctx) + err := dbService.collectionSentEmails(instanceID).Indexes().DropAll(ctx) if err != nil { slog.Error("Error dropping all indexes for sent emails", slog.String("error", err.Error()), slog.String("instanceID", instanceID)) } } else { - for _, index := range indexesForSentEmailsCollection { - if index.Options == nil || index.Options.Name == nil { - slog.Error("Index name is nil for sent emails collection", slog.String("index", fmt.Sprintf("%+v", index))) + for _, indexName := range defaultSentEmailIndexNames { + if indexName == "" { + slog.Error("Index name is empty for sent emails collection") continue } - indexName := *index.Options.Name - _, err := dbService.collectionSentEmails(instanceID).Indexes().DropOne(ctx, indexName) + err := dbService.collectionSentEmails(instanceID).Indexes().DropOne(ctx, indexName) if err != nil { slog.Error("Error dropping index for sent emails", slog.String("error", err.Error()), slog.String("instanceID", instanceID), slog.String("indexName", indexName)) } @@ -63,11 +66,11 @@ func (dbService *MessagingDBService) AddToSentEmails(instanceID string, email me email.SentAt = time.Now().UTC() email.To = []string{} - email.ID = primitive.NilObjectID + email.ID = bson.NilObjectID res, err := dbService.collectionSentEmails(instanceID).InsertOne(ctx, email) if err != nil { return email, err } - email.ID = res.InsertedID.(primitive.ObjectID) + email.ID = res.InsertedID.(bson.ObjectID) return email, nil } diff --git a/pkg/db/messaging/sent-sms.go b/pkg/db/messaging/sent-sms.go index 9e752004..28dc9280 100644 --- a/pkg/db/messaging/sent-sms.go +++ b/pkg/db/messaging/sent-sms.go @@ -1,17 +1,21 @@ package messaging import ( - "fmt" "log/slog" "time" "github.com/case-framework/case-backend/pkg/messaging/types" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" ) +const idxSentSMSUserIDSentAtMessageType = "userID_1_sentAt_1_messageType_1" + +var defaultSentSMSIndexNames = []string{ + idxSentSMSUserIDSentAtMessageType, +} + var indexesForSentSMSCollection = []mongo.IndexModel{ { Keys: bson.D{ @@ -19,7 +23,7 @@ var indexesForSentSMSCollection = []mongo.IndexModel{ {Key: "sentAt", Value: 1}, {Key: "messageType", Value: 1}, }, - Options: options.Index().SetName("userID_1_sentAt_1_messageType_1"), + Options: options.Index().SetName(idxSentSMSUserIDSentAtMessageType), }, } @@ -28,18 +32,17 @@ func (dbService *MessagingDBService) DropIndexForSentSMSCollection(instanceID st defer cancel() if dropAll { - _, err := dbService.collectionSentSMS(instanceID).Indexes().DropAll(ctx) + err := dbService.collectionSentSMS(instanceID).Indexes().DropAll(ctx) if err != nil { slog.Error("Error dropping all indexes for sent SMS", slog.String("error", err.Error()), slog.String("instanceID", instanceID)) } } else { - for _, index := range indexesForSentSMSCollection { - if index.Options == nil || index.Options.Name == nil { - slog.Error("Index name is nil for sent SMS collection", slog.String("index", fmt.Sprintf("%+v", index))) + for _, indexName := range defaultSentSMSIndexNames { + if indexName == "" { + slog.Error("Index name is empty for sent SMS collection") continue } - indexName := *index.Options.Name - _, err := dbService.collectionSentSMS(instanceID).Indexes().DropOne(ctx, indexName) + err := dbService.collectionSentSMS(instanceID).Indexes().DropOne(ctx, indexName) if err != nil { slog.Error("Error dropping index for sent SMS", slog.String("error", err.Error()), slog.String("instanceID", instanceID), slog.String("indexName", indexName)) } @@ -65,7 +68,7 @@ func (dbService *MessagingDBService) AddToSentSMS(instanceID string, sms types.S if err != nil { return sms, err } - sms.ID = res.InsertedID.(primitive.ObjectID) + sms.ID = res.InsertedID.(bson.ObjectID) return sms, nil } diff --git a/pkg/db/messaging/sms-templates.go b/pkg/db/messaging/sms-templates.go index 841af01d..ab28c704 100644 --- a/pkg/db/messaging/sms-templates.go +++ b/pkg/db/messaging/sms-templates.go @@ -1,23 +1,27 @@ package messaging import ( - "fmt" "log/slog" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" messagingTypes "github.com/case-framework/case-backend/pkg/messaging/types" ) +const idxSMSTemplatesMessageType = "messageType_1" + +var defaultSMSTemplateIndexNames = []string{ + idxSMSTemplatesMessageType, +} + var indexesForSMSTemplatesCollection = []mongo.IndexModel{ { Keys: bson.D{ {Key: "messageType", Value: 1}, }, - Options: options.Index().SetUnique(true).SetName("messageType_1"), + Options: options.Index().SetUnique(true).SetName(idxSMSTemplatesMessageType), }, } @@ -25,18 +29,17 @@ func (messagingDBService *MessagingDBService) DropIndexForSMSTemplatesCollection ctx, cancel := messagingDBService.getContext() defer cancel() if dropAll { - _, err := messagingDBService.collectionSMSTemplates(instanceID).Indexes().DropAll(ctx) + err := messagingDBService.collectionSMSTemplates(instanceID).Indexes().DropAll(ctx) if err != nil { slog.Error("Error dropping all indexes for SMS templates", slog.String("error", err.Error()), slog.String("instanceID", instanceID)) } } else { - for _, index := range indexesForSMSTemplatesCollection { - if index.Options == nil || index.Options.Name == nil { - slog.Error("Index name is nil for SMS templates collection", slog.String("index", fmt.Sprintf("%+v", index))) + for _, indexName := range defaultSMSTemplateIndexNames { + if indexName == "" { + slog.Error("Index name is empty for SMS templates collection") continue } - indexName := *index.Options.Name - _, err := messagingDBService.collectionSMSTemplates(instanceID).Indexes().DropOne(ctx, indexName) + err := messagingDBService.collectionSMSTemplates(instanceID).Indexes().DropOne(ctx, indexName) if err != nil { slog.Error("Error dropping index for SMS templates", slog.String("error", err.Error()), slog.String("instanceID", instanceID), slog.String("indexName", indexName)) } @@ -60,22 +63,20 @@ func (messagingDBService *MessagingDBService) SaveSMSTemplate(instanceID string, defer cancel() if smsTemplate.ID.IsZero() { - smsTemplate.ID = primitive.NewObjectID() + smsTemplate.ID = bson.NewObjectID() // new template res, err := messagingDBService.collectionSMSTemplates(instanceID).InsertOne(ctx, smsTemplate) if err != nil { return messagingTypes.SMSTemplate{}, err } - smsTemplate.ID = res.InsertedID.(primitive.ObjectID) + smsTemplate.ID = res.InsertedID.(bson.ObjectID) return smsTemplate, nil } // update template filter := bson.M{"_id": smsTemplate.ID} - upsert := false - after := options.After - opt := options.FindOneAndReplaceOptions{Upsert: &upsert, ReturnDocument: &after} - err := messagingDBService.collectionSMSTemplates(instanceID).FindOneAndReplace(ctx, filter, smsTemplate, &opt).Decode(&smsTemplate) + opt := options.FindOneAndReplace().SetUpsert(false).SetReturnDocument(options.After) + err := messagingDBService.collectionSMSTemplates(instanceID).FindOneAndReplace(ctx, filter, smsTemplate, opt).Decode(&smsTemplate) if err != nil { return messagingTypes.SMSTemplate{}, err } diff --git a/pkg/db/participant-user/db.go b/pkg/db/participant-user/db.go index 832e995e..9d0f0c43 100644 --- a/pkg/db/participant-user/db.go +++ b/pkg/db/participant-user/db.go @@ -6,9 +6,9 @@ import ( "time" "github.com/case-framework/case-backend/pkg/db" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" ) // collection names @@ -29,10 +29,7 @@ type ParticipantUserDBService struct { } func NewParticipantUserDBService(configs db.DBConfig) (*ParticipantUserDBService, error) { - ctx, cancel := context.WithTimeout(context.Background(), time.Duration(configs.Timeout)*time.Second) - defer cancel() - - dbClient, err := mongo.Connect(ctx, + dbClient, err := mongo.Connect( options.Client().ApplyURI(configs.URI), options.Client().SetMaxConnIdleTime(time.Duration(configs.IdleConnTimeout)*time.Second), options.Client().SetMaxPoolSize(configs.MaxPoolSize), diff --git a/pkg/db/participant-user/failedOtpAttempts.go b/pkg/db/participant-user/failedOtpAttempts.go index e02b99b8..07c92d94 100644 --- a/pkg/db/participant-user/failedOtpAttempts.go +++ b/pkg/db/participant-user/failedOtpAttempts.go @@ -1,19 +1,25 @@ package participantuser import ( - "fmt" "log/slog" "time" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" ) const ( - FAILED_OTP_ATTEMP_WINDOW = 60 * 5 + FAILED_OTP_ATTEMP_WINDOW = 60 * 5 + idxFailedOtpAttemptsUserID = "userID_1" + idxFailedOtpAttemptsTimestamp = "timestamp_1" ) +var defaultFailedOtpAttemptIndexNames = []string{ + idxFailedOtpAttemptsUserID, + idxFailedOtpAttemptsTimestamp, +} + type FailedOtpAttempt struct { Timestamp time.Time `json:"timestamp" bson:"timestamp"` UserID string `json:"userId" bson:"userID"` @@ -24,13 +30,13 @@ var indexesForFailedOtpAttemptsCollection = []mongo.IndexModel{ Keys: bson.D{ {Key: "userID", Value: 1}, }, - Options: options.Index().SetName("userID_1"), + Options: options.Index().SetName(idxFailedOtpAttemptsUserID), }, { Keys: bson.D{ {Key: "timestamp", Value: 1}, }, - Options: options.Index().SetExpireAfterSeconds(FAILED_OTP_ATTEMP_WINDOW).SetName("timestamp_1"), + Options: options.Index().SetExpireAfterSeconds(FAILED_OTP_ATTEMP_WINDOW).SetName(idxFailedOtpAttemptsTimestamp), }, } @@ -39,18 +45,17 @@ func (dbService *ParticipantUserDBService) DropIndexForFailedOtpAttemptsCollecti defer cancel() if dropAll { - _, err := dbService.collectionFailedOtpAttempts(instanceID).Indexes().DropAll(ctx) + err := dbService.collectionFailedOtpAttempts(instanceID).Indexes().DropAll(ctx) if err != nil { slog.Error("Error dropping all indexes for FailedOtpAttempts", slog.String("error", err.Error())) } } else { - for _, index := range indexesForFailedOtpAttemptsCollection { - if index.Options == nil || index.Options.Name == nil { - slog.Error("Index name is nil for FailedOtpAttempts collection", slog.String("index", fmt.Sprintf("%+v", index))) + for _, indexName := range defaultFailedOtpAttemptIndexNames { + if indexName == "" { + slog.Error("Index name is empty for FailedOtpAttempts collection") continue } - indexName := *index.Options.Name - _, err := dbService.collectionFailedOtpAttempts(instanceID).Indexes().DropOne(ctx, indexName) + err := dbService.collectionFailedOtpAttempts(instanceID).Indexes().DropOne(ctx, indexName) if err != nil { slog.Error("Error dropping index for FailedOtpAttempts", slog.String("error", err.Error()), slog.String("indexName", indexName)) } diff --git a/pkg/db/participant-user/otps.go b/pkg/db/participant-user/otps.go index b2179cf8..2af41dfd 100644 --- a/pkg/db/participant-user/otps.go +++ b/pkg/db/participant-user/otps.go @@ -1,35 +1,42 @@ package participantuser import ( + "context" "errors" - "fmt" "log/slog" "time" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" userTypes "github.com/case-framework/case-backend/pkg/user-management/types" ) const ( - OTP_TTL = 60 * 15 + OTP_TTL = 60 * 15 + idxOTPsUserIDCode = "uniq_userID_1_code_1" + idxOTPsCreatedAt = "createdAt_1" ) +var defaultOTPIndexNames = []string{ + idxOTPsUserIDCode, + idxOTPsCreatedAt, +} + var indexesForOTPsCollection = []mongo.IndexModel{ { Keys: bson.D{ {Key: "userID", Value: 1}, {Key: "code", Value: 1}, }, - Options: options.Index().SetUnique(true).SetName("uniq_userID_1_code_1"), + Options: options.Index().SetUnique(true).SetName(idxOTPsUserIDCode), }, { Keys: bson.D{ {Key: "createdAt", Value: 1}, }, - Options: options.Index().SetExpireAfterSeconds(OTP_TTL).SetName("createdAt_1"), + Options: options.Index().SetExpireAfterSeconds(OTP_TTL).SetName(idxOTPsCreatedAt), }, } @@ -38,18 +45,17 @@ func (dbService *ParticipantUserDBService) DropIndexForOTPsCollection(instanceID defer cancel() if dropAll { - _, err := dbService.collectionOTPs(instanceID).Indexes().DropAll(ctx) + err := dbService.collectionOTPs(instanceID).Indexes().DropAll(ctx) if err != nil { slog.Error("Error dropping all indexes for OTPs", slog.String("error", err.Error())) } } else { - for _, index := range indexesForOTPsCollection { - if index.Options == nil || index.Options.Name == nil { - slog.Error("Index name is nil for OTPs collection", slog.String("index", fmt.Sprintf("%+v", index))) + for _, indexName := range defaultOTPIndexNames { + if indexName == "" { + slog.Error("Index name is empty for OTPs collection") continue } - indexName := *index.Options.Name - _, err := dbService.collectionOTPs(instanceID).Indexes().DropOne(ctx, indexName) + err := dbService.collectionOTPs(instanceID).Indexes().DropOne(ctx, indexName) if err != nil { slog.Error("Error dropping index for OTPs", slog.String("error", err.Error()), slog.String("indexName", indexName)) } @@ -77,7 +83,7 @@ func (dbService *ParticipantUserDBService) CreateOTP(instanceID string, userID s } defer session.EndSession(ctx) - createOTPIfLimitNotReached := func(sessCtx mongo.SessionContext) error { + createOTPIfLimitNotReached := func(sessCtx context.Context) error { filter := bson.M{"userID": userID} count, err := dbService.collectionOTPs(instanceID).CountDocuments(sessCtx, filter) @@ -98,7 +104,6 @@ func (dbService *ParticipantUserDBService) CreateOTP(instanceID string, userID s _, err = dbService.collectionOTPs(instanceID).InsertOne(sessCtx, otp) return err } - return mongo.WithSession(ctx, session, createOTPIfLimitNotReached) } diff --git a/pkg/db/participant-user/renew-tokens.go b/pkg/db/participant-user/renew-tokens.go index f95a303c..a1f77aff 100644 --- a/pkg/db/participant-user/renew-tokens.go +++ b/pkg/db/participant-user/renew-tokens.go @@ -2,22 +2,32 @@ package participantuser import ( "errors" - "fmt" "log/slog" "time" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" userTypes "github.com/case-framework/case-backend/pkg/user-management/types" ) const ( - RENEW_TOKEN_GRACE_PERIOD = 30 // seconds - RENEW_TOKEN_DEFAULT_LIFETIME = 60 * 60 * 24 * 90 + RENEW_TOKEN_GRACE_PERIOD = 30 // seconds + RENEW_TOKEN_DEFAULT_LIFETIME = 60 * 60 * 24 * 90 + idxRenewTokensUserIDRenewTokenExpiresAt = "userID_1_renewToken_1_expiresAt_1" + idxRenewTokensUserIDSessionID = "userID_1_sessionID_1" + idxRenewTokensExpiresAt = "expiresAt_1" + idxRenewTokensUniqueRenewToken = "uniq_renewToken_1" ) +var defaultRenewTokenIndexNames = []string{ + idxRenewTokensUserIDRenewTokenExpiresAt, + idxRenewTokensUserIDSessionID, + idxRenewTokensExpiresAt, + idxRenewTokensUniqueRenewToken, +} + var indexesForRenewTokensCollection = []mongo.IndexModel{ { Keys: bson.D{ @@ -25,26 +35,26 @@ var indexesForRenewTokensCollection = []mongo.IndexModel{ {Key: "renewToken", Value: 1}, {Key: "expiresAt", Value: 1}, }, - Options: options.Index().SetName("userID_1_renewToken_1_expiresAt_1"), + Options: options.Index().SetName(idxRenewTokensUserIDRenewTokenExpiresAt), }, { Keys: bson.D{ {Key: "userID", Value: 1}, {Key: "sessionID", Value: 1}, }, - Options: options.Index().SetName("userID_1_sessionID_1"), + Options: options.Index().SetName(idxRenewTokensUserIDSessionID), }, { Keys: bson.D{ {Key: "expiresAt", Value: 1}, }, - Options: options.Index().SetExpireAfterSeconds(RENEW_TOKEN_GRACE_PERIOD).SetName("expiresAt_1"), + Options: options.Index().SetExpireAfterSeconds(RENEW_TOKEN_GRACE_PERIOD).SetName(idxRenewTokensExpiresAt), }, { Keys: bson.D{ {Key: "renewToken", Value: 1}, }, - Options: options.Index().SetUnique(true).SetName("uniq_renewToken_1"), + Options: options.Index().SetUnique(true).SetName(idxRenewTokensUniqueRenewToken), }, } @@ -53,18 +63,17 @@ func (dbService *ParticipantUserDBService) DropIndexForRenewTokensCollection(ins defer cancel() if dropAll { - _, err := dbService.collectionRenewTokens(instanceID).Indexes().DropAll(ctx) + err := dbService.collectionRenewTokens(instanceID).Indexes().DropAll(ctx) if err != nil { slog.Error("Error dropping all indexes for renew tokens", slog.String("error", err.Error())) } } else { - for _, index := range indexesForRenewTokensCollection { - if index.Options == nil || index.Options.Name == nil { - slog.Error("Index name is nil for renew tokens collection", slog.String("index", fmt.Sprintf("%+v", index))) + for _, indexName := range defaultRenewTokenIndexNames { + if indexName == "" { + slog.Error("Index name is empty for renew tokens collection") continue } - indexName := *index.Options.Name - _, err := dbService.collectionRenewTokens(instanceID).Indexes().DropOne(ctx, indexName) + err := dbService.collectionRenewTokens(instanceID).Indexes().DropOne(ctx, indexName) if err != nil { slog.Error("Error dropping index for renew tokens", slog.String("error", err.Error()), slog.String("indexName", indexName)) } @@ -108,7 +117,7 @@ func (dbService *ParticipantUserDBService) DeleteRenewTokenByToken(instanceID st ctx, cancel := dbService.getContext() defer cancel() - res, err := dbService.collectionRenewTokens(instanceID).DeleteOne(ctx, filter, nil) + res, err := dbService.collectionRenewTokens(instanceID).DeleteOne(ctx, filter) if err != nil { return err } @@ -123,7 +132,7 @@ func (dbService *ParticipantUserDBService) DeleteRenewTokensForUser(instanceID s ctx, cancel := dbService.getContext() defer cancel() - res, err := dbService.collectionRenewTokens(instanceID).DeleteMany(ctx, filter, nil) + res, err := dbService.collectionRenewTokens(instanceID).DeleteMany(ctx, filter) if err != nil { return 0, err } @@ -135,7 +144,7 @@ func (dbService *ParticipantUserDBService) DeleteRenewTokensForSession(instanceI ctx, cancel := dbService.getContext() defer cancel() - res, err := dbService.collectionRenewTokens(instanceID).DeleteMany(ctx, filter, nil) + res, err := dbService.collectionRenewTokens(instanceID).DeleteMany(ctx, filter) if err != nil { return 0, err } diff --git a/pkg/db/participant-user/user-attributes.go b/pkg/db/participant-user/user-attributes.go index 9e77136e..cef31760 100644 --- a/pkg/db/participant-user/user-attributes.go +++ b/pkg/db/participant-user/user-attributes.go @@ -2,22 +2,26 @@ package participantuser import ( "context" - "fmt" "log/slog" "time" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" userTypes "github.com/case-framework/case-backend/pkg/user-management/types" ) +const idxParticipantUserAttributesUserIdType = "userId_1_type_1" + +var defaultParticipantUserAttributeIndexNames = []string{ + idxParticipantUserAttributesUserIdType, +} + var indexesForParticipantUserAttributesCollection = []mongo.IndexModel{ { Keys: bson.D{{Key: "userId", Value: 1}, {Key: "type", Value: 1}}, - Options: options.Index().SetName("userId_1_type_1").SetUnique(true), + Options: options.Index().SetName(idxParticipantUserAttributesUserIdType).SetUnique(true), }, } @@ -26,18 +30,17 @@ func (dbService *ParticipantUserDBService) DropIndexForParticipantUserAttributes defer cancel() if dropAll { - _, err := dbService.collectionParticipantUserAttributes(instanceID).Indexes().DropAll(ctx) + err := dbService.collectionParticipantUserAttributes(instanceID).Indexes().DropAll(ctx) if err != nil { slog.Error("Error dropping all indexes for participant user attributes", slog.String("error", err.Error()), slog.String("instanceID", instanceID)) } } else { - for _, index := range indexesForParticipantUserAttributesCollection { - if index.Options == nil || index.Options.Name == nil { - slog.Error("Index name is nil for participant user attributes collection", slog.String("index", fmt.Sprintf("%+v", index)), slog.String("instanceID", instanceID)) + for _, indexName := range defaultParticipantUserAttributeIndexNames { + if indexName == "" { + slog.Error("Index name is empty for participant user attributes collection", slog.String("instanceID", instanceID)) continue } - indexName := *index.Options.Name - _, err := dbService.collectionParticipantUserAttributes(instanceID).Indexes().DropOne(ctx, indexName) + err := dbService.collectionParticipantUserAttributes(instanceID).Indexes().DropOne(ctx, indexName) if err != nil { slog.Error("Error dropping index for participant user attributes", slog.String("error", err.Error()), slog.String("indexName", indexName), slog.String("instanceID", instanceID)) } @@ -65,7 +68,7 @@ func (dbService *ParticipantUserDBService) SetUserAttribute( ctx, cancel := dbService.getContext() defer cancel() - userIDObj, err := primitive.ObjectIDFromHex(userID) + userIDObj, err := bson.ObjectIDFromHex(userID) if err != nil { return err } @@ -74,7 +77,7 @@ func (dbService *ParticipantUserDBService) SetUserAttribute( ctx, bson.M{"userId": userIDObj, "type": attributeType}, bson.M{"$set": bson.M{"attributes": attributes, "createdAt": time.Now().UTC()}}, - options.Update().SetUpsert(true), + options.UpdateOne().SetUpsert(true), ) return err } @@ -85,7 +88,7 @@ func (dbService *ParticipantUserDBService) DeleteAllUserAttributes( instanceID string, userID string, ) error { - userIDObj, err := primitive.ObjectIDFromHex(userID) + userIDObj, err := bson.ObjectIDFromHex(userID) if err != nil { return err } @@ -99,12 +102,12 @@ func (dbService *ParticipantUserDBService) DeleteUserAttribute(instanceID string ctx, cancel := dbService.getContext() defer cancel() - userIDObj, err := primitive.ObjectIDFromHex(userID) + userIDObj, err := bson.ObjectIDFromHex(userID) if err != nil { return err } - attributeIDObj, err := primitive.ObjectIDFromHex(attributeID) + attributeIDObj, err := bson.ObjectIDFromHex(attributeID) if err != nil { return err } @@ -118,7 +121,7 @@ func (dbService *ParticipantUserDBService) GetAttributesForUser(instanceID strin ctx, cancel := dbService.getContext() defer cancel() - userIDObj, err := primitive.ObjectIDFromHex(userID) + userIDObj, err := bson.ObjectIDFromHex(userID) if err != nil { return nil, err } diff --git a/pkg/db/participant-user/users.go b/pkg/db/participant-user/users.go index eb3ade50..69e0f8ca 100644 --- a/pkg/db/participant-user/users.go +++ b/pkg/db/participant-user/users.go @@ -3,50 +3,64 @@ package participantuser import ( "context" "errors" - "fmt" "log/slog" "time" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" umTypes "github.com/case-framework/case-backend/pkg/user-management/types" ) +const ( + idxParticipantUsersMarkedForDeletion = "timestamps.markedForDeletion_1" + idxParticipantUsersUniqueAccountID = "uniq_account.accountID_1" + idxParticipantUsersCreatedAt = "timestamps.createdAt_1" + idxParticipantUsersAccountConfirmedCreate = "account.accountConfirmedAt_1_timestamps.createdAt_1" + idxParticipantUsersWeeklyMessageDay = "contactPreferences.receiveWeeklyMessageDayOfWeek_1" +) + +var defaultParticipantUserIndexNames = []string{ + idxParticipantUsersMarkedForDeletion, + idxParticipantUsersUniqueAccountID, + idxParticipantUsersCreatedAt, + idxParticipantUsersAccountConfirmedCreate, + idxParticipantUsersWeeklyMessageDay, +} + var indexesForParticipantUsersCollection = []mongo.IndexModel{ { Keys: bson.D{ {Key: "timestamps.markedForDeletion", Value: 1}, }, - Options: options.Index().SetName("timestamps.markedForDeletion_1"), + Options: options.Index().SetName(idxParticipantUsersMarkedForDeletion), }, { Keys: bson.D{ {Key: "account.accountID", Value: 1}, }, Options: options.Index().SetUnique(true). - SetName("uniq_account.accountID_1"), + SetName(idxParticipantUsersUniqueAccountID), }, { Keys: bson.D{ {Key: "timestamps.createdAt", Value: 1}, }, - Options: options.Index().SetName("timestamps.createdAt_1"), + Options: options.Index().SetName(idxParticipantUsersCreatedAt), }, { Keys: bson.D{ {Key: "account.accountConfirmedAt", Value: 1}, {Key: "timestamps.createdAt", Value: 1}, }, - Options: options.Index().SetName("account.accountConfirmedAt_1_timestamps.createdAt_1"), + Options: options.Index().SetName(idxParticipantUsersAccountConfirmedCreate), }, { Keys: bson.D{ {Key: "contactPreferences.receiveWeeklyMessageDayOfWeek", Value: 1}, }, - Options: options.Index().SetName("contactPreferences.receiveWeeklyMessageDayOfWeek_1"), + Options: options.Index().SetName(idxParticipantUsersWeeklyMessageDay), }, } @@ -55,18 +69,17 @@ func (dbService *ParticipantUserDBService) DropIndexForParticipantUsersCollectio defer cancel() if dropAll { - _, err := dbService.collectionParticipantUsers(instanceID).Indexes().DropAll(ctx) + err := dbService.collectionParticipantUsers(instanceID).Indexes().DropAll(ctx) if err != nil { slog.Error("Error dropping all indexes for participant users", slog.String("error", err.Error())) } } else { - for _, index := range indexesForParticipantUsersCollection { - if index.Options == nil || index.Options.Name == nil { - slog.Error("Index name is nil for participant users collection", slog.String("index", fmt.Sprintf("%+v", index))) + for _, indexName := range defaultParticipantUserIndexNames { + if indexName == "" { + slog.Error("Index name is empty for participant users collection") continue } - indexName := *index.Options.Name - _, err := dbService.collectionParticipantUsers(instanceID).Indexes().DropOne(ctx, indexName) + err := dbService.collectionParticipantUsers(instanceID).Indexes().DropOne(ctx, indexName) if err != nil { slog.Error("Error dropping index for participant users", slog.String("error", err.Error()), slog.String("indexName", indexName)) } @@ -106,13 +119,10 @@ func (dbService *ParticipantUserDBService) AddUser(instanceID string, user umTyp defer cancel() filter := bson.M{"account.accountID": user.Account.AccountID} - upsert := true - opts := options.UpdateOptions{ - Upsert: &upsert, - } + opts := options.UpdateOne().SetUpsert(true) res, err := dbService.collectionParticipantUsers(instanceID).UpdateOne(ctx, filter, bson.M{ "$setOnInsert": user, - }, &opts) + }, opts) if err != nil { return } @@ -122,7 +132,7 @@ func (dbService *ParticipantUserDBService) AddUser(instanceID string, user umTyp return } - id = res.UpsertedID.(primitive.ObjectID).Hex() + id = res.UpsertedID.(bson.ObjectID).Hex() return } @@ -130,7 +140,7 @@ func (dbService *ParticipantUserDBService) GetUser(instanceID, objectID string) ctx, cancel := dbService.getContext() defer cancel() - _id, err := primitive.ObjectIDFromHex(objectID) + _id, err := bson.ObjectIDFromHex(objectID) if err != nil { return umTypes.User{}, err } @@ -156,7 +166,7 @@ func (dbService *ParticipantUserDBService) GetUserByProfileID(instanceID, profil defer cancel() var user umTypes.User - _profileID, err := primitive.ObjectIDFromHex(profileID) + _profileID, err := bson.ObjectIDFromHex(profileID) if err != nil { return umTypes.User{}, err } @@ -169,7 +179,7 @@ func (dbService *ParticipantUserDBService) SaveFailedLoginAttempt(instanceID str ctx, cancel := dbService.getContext() defer cancel() - _id, err := primitive.ObjectIDFromHex(userID) + _id, err := bson.ObjectIDFromHex(userID) if err != nil { return err } @@ -188,7 +198,7 @@ func (dbService *ParticipantUserDBService) SavePasswordResetTrigger(instanceID s ctx, cancel := dbService.getContext() defer cancel() - _id, _ := primitive.ObjectIDFromHex(userID) + _id, _ := bson.ObjectIDFromHex(userID) filter := bson.M{"_id": _id} update := bson.M{"$push": bson.M{"account.passwordResetTriggers": time.Now().Unix()}} _, err := dbService.collectionParticipantUsers(instanceID).UpdateOne(ctx, filter, update) @@ -205,11 +215,9 @@ func (dbService *ParticipantUserDBService) _updateUserInDB(orgID string, user um elem := umTypes.User{} filter := bson.M{"_id": user.ID} - rd := options.After - fro := options.FindOneAndReplaceOptions{ - ReturnDocument: &rd, - } - err := dbService.collectionParticipantUsers(orgID).FindOneAndReplace(ctx, filter, user, &fro).Decode(&elem) + fro := options.FindOneAndReplace(). + SetReturnDocument(options.After) + err := dbService.collectionParticipantUsers(orgID).FindOneAndReplace(ctx, filter, user, fro).Decode(&elem) return elem, err } @@ -232,7 +240,7 @@ func (dbService *ParticipantUserDBService) DeleteUser(instanceID, userID string) ctx, cancel := dbService.getContext() defer cancel() - _id, err := primitive.ObjectIDFromHex(userID) + _id, err := bson.ObjectIDFromHex(userID) if err != nil { return err } @@ -256,7 +264,7 @@ func (dbService *ParticipantUserDBService) UpdateUser(instanceID string, userID ctx, cancel := dbService.getContext() defer cancel() - _id, err := primitive.ObjectIDFromHex(userID) + _id, err := bson.ObjectIDFromHex(userID) if err != nil { return err } diff --git a/pkg/db/study/confidential-id-map.go b/pkg/db/study/confidential-id-map.go index 36d1d0a3..217bb553 100644 --- a/pkg/db/study/confidential-id-map.go +++ b/pkg/db/study/confidential-id-map.go @@ -1,21 +1,26 @@ package study import ( - "fmt" "log/slog" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" ) +const idxConfidentialIDMapConfidentialIDStudyKey = "confidentialID_1_studyKey_1" + +var defaultConfidentialIDMapIndexNames = []string{ + idxConfidentialIDMapConfidentialIDStudyKey, +} + var indexesForConfidentialIDMapCollection = []mongo.IndexModel{ { Keys: bson.D{ {Key: "confidentialID", Value: 1}, {Key: "studyKey", Value: 1}, }, - Options: options.Index().SetUnique(true).SetName("confidentialID_1_studyKey_1"), + Options: options.Index().SetUnique(true).SetName(idxConfidentialIDMapConfidentialIDStudyKey), }, } @@ -25,18 +30,17 @@ func (dbService *StudyDBService) DropIndexForConfidentialIDMapCollection(instanc collection := dbService.collectionConfidentialIDMap(instanceID) if dropAll { - _, err := collection.Indexes().DropAll(ctx) + err := collection.Indexes().DropAll(ctx) if err != nil { slog.Error("Error dropping all indexes for confidentialIDMap", slog.String("error", err.Error()), slog.String("instanceID", instanceID)) } } else { - for _, index := range indexesForConfidentialIDMapCollection { - if index.Options == nil || index.Options.Name == nil { - slog.Error("Index name is nil for confidentialIDMap collection", slog.String("index", fmt.Sprintf("%+v", index))) + for _, indexName := range defaultConfidentialIDMapIndexNames { + if indexName == "" { + slog.Error("Index name is empty for confidentialIDMap collection") continue } - indexName := *index.Options.Name - _, err := collection.Indexes().DropOne(ctx, indexName) + err := collection.Indexes().DropOne(ctx, indexName) if err != nil { slog.Error("Error dropping index for confidentialIDMap", slog.String("error", err.Error()), slog.String("instanceID", instanceID), slog.String("indexName", indexName)) } diff --git a/pkg/db/study/confidentialResponses.go b/pkg/db/study/confidential-responses.go similarity index 86% rename from pkg/db/study/confidentialResponses.go rename to pkg/db/study/confidential-responses.go index f6000d64..7774ff8f 100644 --- a/pkg/db/study/confidentialResponses.go +++ b/pkg/db/study/confidential-responses.go @@ -3,23 +3,27 @@ package study import ( "context" "errors" - "fmt" "log/slog" studyTypes "github.com/case-framework/case-backend/pkg/study/types" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" ) +const idxConfidentialResponsesParticipantIDKey = "participantID_1_key_1" + +var defaultConfidentialResponseIndexNames = []string{ + idxConfidentialResponsesParticipantIDKey, +} + var indexesForConfidentialResponsesCollection = []mongo.IndexModel{ { Keys: bson.D{ {Key: "participantID", Value: 1}, {Key: "key", Value: 1}, }, - Options: options.Index().SetName("participantID_1_key_1"), + Options: options.Index().SetName(idxConfidentialResponsesParticipantIDKey), }, } @@ -30,18 +34,17 @@ func (dbService *StudyDBService) DropIndexForConfidentialResponsesCollection(ins collection := dbService.collectionConfidentialResponses(instanceID, studyKey) if dropAll { - _, err := collection.Indexes().DropAll(ctx) + err := collection.Indexes().DropAll(ctx) if err != nil { slog.Error("Error dropping all indexes for confidential responses", slog.String("error", err.Error()), slog.String("instanceID", instanceID), slog.String("studyKey", studyKey)) } } else { - for _, index := range indexesForConfidentialResponsesCollection { - if index.Options == nil || index.Options.Name == nil { - slog.Error("Index name is nil for confidential responses collection", slog.String("index", fmt.Sprintf("%+v", index))) + for _, indexName := range defaultConfidentialResponseIndexNames { + if indexName == "" { + slog.Error("Index name is empty for confidential responses collection") continue } - indexName := *index.Options.Name - _, err := collection.Indexes().DropOne(ctx, indexName) + err := collection.Indexes().DropOne(ctx, indexName) if err != nil { slog.Error("Error dropping index for confidential responses", slog.String("error", err.Error()), slog.String("instanceID", instanceID), slog.String("studyKey", studyKey), slog.String("indexName", indexName)) } @@ -67,8 +70,11 @@ func (dbService *StudyDBService) AddConfidentialResponse(instanceID string, stud return "", errors.New("participantID must be defined") } res, err := dbService.collectionConfidentialResponses(instanceID, studyKey).InsertOne(ctx, response) - id := res.InsertedID.(primitive.ObjectID) - return id.Hex(), err + if err != nil { + return "", err + } + id := res.InsertedID.(bson.ObjectID) + return id.Hex(), nil } func (dbService *StudyDBService) ReplaceConfidentialResponse(instanceID string, studyKey string, response studyTypes.SurveyResponse) error { @@ -80,11 +86,9 @@ func (dbService *StudyDBService) ReplaceConfidentialResponse(instanceID string, "key": response.Key, } - upsert := true - options := options.ReplaceOptions{ - Upsert: &upsert, - } - _, err := dbService.collectionConfidentialResponses(instanceID, studyKey).ReplaceOne(ctx, filter, response, &options) + opts := options.Replace().SetUpsert(true) + + _, err := dbService.collectionConfidentialResponses(instanceID, studyKey).ReplaceOne(ctx, filter, response, opts) return err } @@ -103,7 +107,6 @@ func (dbService *StudyDBService) FindConfidentialResponses(instanceID string, st cur, err := dbService.collectionConfidentialResponses(instanceID, studyKey).Find( ctx, filter, - nil, ) if err != nil { diff --git a/pkg/db/study/db.go b/pkg/db/study/db.go index aca7a433..ded6d99f 100644 --- a/pkg/db/study/db.go +++ b/pkg/db/study/db.go @@ -6,9 +6,9 @@ import ( "time" "github.com/case-framework/case-backend/pkg/db" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" ) // collection names @@ -38,10 +38,7 @@ type StudyDBService struct { } func NewStudyDBService(configs db.DBConfig) (*StudyDBService, error) { - ctx, cancel := context.WithTimeout(context.Background(), time.Duration(configs.Timeout)*time.Second) - defer cancel() - - dbClient, err := mongo.Connect(ctx, + dbClient, err := mongo.Connect( options.Client().ApplyURI(configs.URI), options.Client().SetMaxConnIdleTime(time.Duration(configs.IdleConnTimeout)*time.Second), options.Client().SetMaxPoolSize(configs.MaxPoolSize), diff --git a/pkg/db/study/participantFileInfos.go b/pkg/db/study/participant-file-infos.go similarity index 81% rename from pkg/db/study/participantFileInfos.go rename to pkg/db/study/participant-file-infos.go index 8d4e89df..cb357fa6 100644 --- a/pkg/db/study/participantFileInfos.go +++ b/pkg/db/study/participant-file-infos.go @@ -1,31 +1,39 @@ package study import ( - "fmt" "log/slog" "time" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" studytypes "github.com/case-framework/case-backend/pkg/study/types" ) +const ( + idxParticipantFilesParticipantIDCreatedAt = "participantID_1_createdAt_-1" + idxParticipantFilesCreatedAt = "createdAt_-1" +) + +var defaultParticipantFileIndexNames = []string{ + idxParticipantFilesParticipantIDCreatedAt, + idxParticipantFilesCreatedAt, +} + var indexesForParticipantFilesCollection = []mongo.IndexModel{ { Keys: bson.D{ {Key: "participantID", Value: 1}, {Key: "createdAt", Value: -1}, }, - Options: options.Index().SetName("participantID_1_createdAt_-1"), + Options: options.Index().SetName(idxParticipantFilesParticipantIDCreatedAt), }, { Keys: bson.D{ {Key: "createdAt", Value: -1}, }, - Options: options.Index().SetName("createdAt_-1"), + Options: options.Index().SetName(idxParticipantFilesCreatedAt), }, } @@ -36,18 +44,17 @@ func (dbService *StudyDBService) DropIndexForParticipantFilesCollection(instance collection := dbService.collectionFiles(instanceID, studyKey) if dropAll { - _, err := collection.Indexes().DropAll(ctx) + err := collection.Indexes().DropAll(ctx) if err != nil { slog.Error("Error dropping all indexes for participant files", slog.String("error", err.Error()), slog.String("instanceID", instanceID), slog.String("studyKey", studyKey)) } } else { - for _, index := range indexesForParticipantFilesCollection { - if index.Options == nil || index.Options.Name == nil { - slog.Error("Index name is nil for participant files collection", slog.String("index", fmt.Sprintf("%+v", index)), slog.String("instanceID", instanceID), slog.String("studyKey", studyKey)) + for _, indexName := range defaultParticipantFileIndexNames { + if indexName == "" { + slog.Error("Index name is empty for participant files collection", slog.String("instanceID", instanceID), slog.String("studyKey", studyKey)) continue } - indexName := *index.Options.Name - _, err := collection.Indexes().DropOne(ctx, indexName) + err := collection.Indexes().DropOne(ctx, indexName) if err != nil { slog.Error("Error dropping index for participant files", slog.String("error", err.Error()), slog.String("instanceID", instanceID), slog.String("studyKey", studyKey), slog.String("indexName", indexName)) } @@ -71,7 +78,7 @@ func (dbService *StudyDBService) GetParticipantFileInfoByID(instanceID string, s ctx, cancel := dbService.getContext() defer cancel() - _id, err := primitive.ObjectIDFromHex(fileInfoID) + _id, err := bson.ObjectIDFromHex(fileInfoID) if err != nil { return participantFileInfo, err } @@ -89,7 +96,7 @@ func (dbService *StudyDBService) DeleteParticipantFileInfoByID(instanceID string ctx, cancel := dbService.getContext() defer cancel() - _id, err := primitive.ObjectIDFromHex(fileInfoID) + _id, err := bson.ObjectIDFromHex(fileInfoID) if err != nil { return err } @@ -132,7 +139,7 @@ func (dbService *StudyDBService) GetParticipantFileInfos(instanceID string, stud ) sortByCreatedAt := bson.D{ - primitive.E{Key: "createdAt", Value: -1}, + {Key: "createdAt", Value: -1}, } opts := options.Find() @@ -161,7 +168,7 @@ func (dbService *StudyDBService) CreateParticipantFileInfo(instanceID string, st return fileInfo, err } - if oid, ok := result.InsertedID.(primitive.ObjectID); ok { + if oid, ok := result.InsertedID.(bson.ObjectID); ok { fileInfo.ID = oid } @@ -173,7 +180,7 @@ func (dbService *StudyDBService) UpdateParticipantFileInfoPathAndStatus(instance ctx, cancel := dbService.getContext() defer cancel() - _id, err := primitive.ObjectIDFromHex(fileInfoID) + _id, err := bson.ObjectIDFromHex(fileInfoID) if err != nil { return err } diff --git a/pkg/db/study/participants.go b/pkg/db/study/participants.go index b91f4f6a..62c73d58 100644 --- a/pkg/db/study/participants.go +++ b/pkg/db/study/participants.go @@ -3,49 +3,63 @@ package study import ( "context" "errors" - "fmt" "log/slog" "time" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" studyTypes "github.com/case-framework/case-backend/pkg/study/types" ) +const ( + idxParticipantsParticipantID = "participantID_1" + idxParticipantsStudyStatus = "studyStatus_1" + idxParticipantsEnteredAt = "enteredAt_1" + idxParticipantsMessagesScheduledForStatus = "messages.scheduledFor_1_studyStatus_1" + idxParticipantsMessagesScheduledFor = "messages.scheduledFor_1" +) + +var defaultParticipantIndexNames = []string{ + idxParticipantsParticipantID, + idxParticipantsStudyStatus, + idxParticipantsEnteredAt, + idxParticipantsMessagesScheduledForStatus, + idxParticipantsMessagesScheduledFor, +} + var indexesForParticipantsCollection = []mongo.IndexModel{ { Keys: bson.D{ {Key: "participantID", Value: 1}, }, - Options: options.Index().SetUnique(true).SetName("participantID_1"), + Options: options.Index().SetUnique(true).SetName(idxParticipantsParticipantID), }, { Keys: bson.D{ {Key: "studyStatus", Value: 1}, }, - Options: options.Index().SetName("studyStatus_1"), + Options: options.Index().SetName(idxParticipantsStudyStatus), }, { Keys: bson.D{ {Key: "enteredAt", Value: 1}, }, - Options: options.Index().SetName("enteredAt_1"), + Options: options.Index().SetName(idxParticipantsEnteredAt), }, { Keys: bson.D{ {Key: "messages.scheduledFor", Value: 1}, {Key: "studyStatus", Value: 1}, }, - Options: options.Index().SetName("messages.scheduledFor_1_studyStatus_1"), + Options: options.Index().SetName(idxParticipantsMessagesScheduledForStatus), }, { Keys: bson.D{ {Key: "messages.scheduledFor", Value: 1}, }, - Options: options.Index().SetName("messages.scheduledFor_1"), + Options: options.Index().SetName(idxParticipantsMessagesScheduledFor), }, } @@ -56,18 +70,17 @@ func (dbService *StudyDBService) DropIndexForParticipantsCollection(instanceID s collection := dbService.collectionParticipants(instanceID, studyKey) if dropAll { - _, err := collection.Indexes().DropAll(ctx) + err := collection.Indexes().DropAll(ctx) if err != nil { slog.Error("Error dropping all indexes for participants", slog.String("error", err.Error()), slog.String("instanceID", instanceID), slog.String("studyKey", studyKey)) } } else { - for _, index := range indexesForParticipantsCollection { - if index.Options == nil || index.Options.Name == nil { - slog.Error("Index name is nil for participants collection", slog.String("index", fmt.Sprintf("%+v", index))) + for _, indexName := range defaultParticipantIndexNames { + if indexName == "" { + slog.Error("Index name is empty for participants collection") continue } - indexName := *index.Options.Name - _, err := collection.Indexes().DropOne(ctx, indexName) + err := collection.Indexes().DropOne(ctx, indexName) if err != nil { slog.Error("Error dropping index for participants", slog.String("error", err.Error()), slog.String("instanceID", instanceID), slog.String("studyKey", studyKey), slog.String("indexName", indexName)) } @@ -95,13 +108,12 @@ func (dbService *StudyDBService) SaveParticipantState(instanceID string, studyKe upsert := true rd := options.After - qOpts := options.FindOneAndReplaceOptions{ - Upsert: &upsert, - ReturnDocument: &rd, - } + qOpts := options.FindOneAndReplace(). + SetUpsert(upsert). + SetReturnDocument(rd) elem := studyTypes.Participant{} err := dbService.collectionParticipants(instanceID, studyKey).FindOneAndReplace( - ctx, filter, pState, &qOpts, + ctx, filter, pState, qOpts, ).Decode(&elem) return elem, err } @@ -117,7 +129,7 @@ func (dbService *StudyDBService) UpdateParticipantIfNotModified(instanceID strin filter["modifiedAt"] = bson.M{"$lte": pState.ModifiedAt} } - pState.ID = primitive.NilObjectID + pState.ID = bson.NilObjectID pState.ModifiedAt = time.Now().Unix() update := bson.M{"$set": pState} diff --git a/pkg/db/study/reports.go b/pkg/db/study/reports.go index ca3f0f09..4313eb59 100644 --- a/pkg/db/study/reports.go +++ b/pkg/db/study/reports.go @@ -7,10 +7,9 @@ import ( "log/slog" "time" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" studyTypes "github.com/case-framework/case-backend/pkg/study/types" ) @@ -23,18 +22,30 @@ type ReportKeyFilters struct { ToTS int64 } +const ( + idxReportsParticipantID = "participantID_1" + idxReportsTimestamp = "timestamp_1" + idxReportsParticipantIDKeyTimestamp = "participantID_1_key_1_timestamp_1" +) + +var defaultReportIndexNames = []string{ + idxReportsParticipantID, + idxReportsTimestamp, + idxReportsParticipantIDKeyTimestamp, +} + var indexesForReportsCollection = []mongo.IndexModel{ { Keys: bson.D{ {Key: "participantID", Value: 1}, }, - Options: options.Index().SetName("participantID_1"), + Options: options.Index().SetName(idxReportsParticipantID), }, { Keys: bson.D{ {Key: "timestamp", Value: 1}, }, - Options: options.Index().SetName("timestamp_1"), + Options: options.Index().SetName(idxReportsTimestamp), }, { Keys: bson.D{ @@ -42,7 +53,7 @@ var indexesForReportsCollection = []mongo.IndexModel{ {Key: "key", Value: 1}, {Key: "timestamp", Value: 1}, }, - Options: options.Index().SetName("participantID_1_key_1_timestamp_1"), + Options: options.Index().SetName(idxReportsParticipantIDKeyTimestamp), }, } @@ -53,18 +64,17 @@ func (dbService *StudyDBService) DropIndexForReportsCollection(instanceID string collection := dbService.collectionReports(instanceID, studyKey) if dropAll { - _, err := collection.Indexes().DropAll(ctx) + err := collection.Indexes().DropAll(ctx) if err != nil { slog.Error("Error dropping all indexes for reports", slog.String("error", err.Error()), slog.String("instanceID", instanceID), slog.String("studyKey", studyKey)) } } else { - for _, index := range indexesForReportsCollection { - if index.Options == nil || index.Options.Name == nil { - slog.Error("Index name is nil for reports collection", slog.String("index", fmt.Sprintf("%+v", index))) + for _, indexName := range defaultReportIndexNames { + if indexName == "" { + slog.Error("Index name is empty for reports collection") continue } - indexName := *index.Options.Name - _, err := collection.Indexes().DropOne(ctx, indexName) + err := collection.Indexes().DropOne(ctx, indexName) if err != nil { slog.Error("Error dropping index for reports", slog.String("error", err.Error()), slog.String("instanceID", instanceID), slog.String("studyKey", studyKey), slog.String("indexName", indexName)) } @@ -95,7 +105,7 @@ func (dbService *StudyDBService) GetReportByID(instanceID string, studyKey strin ctx, cancel := dbService.getContext() defer cancel() - _id, err := primitive.ObjectIDFromHex(reportID) + _id, err := bson.ObjectIDFromHex(reportID) if err != nil { return report, err } @@ -127,7 +137,7 @@ func (dbService *StudyDBService) UpdateReportData( ctx, cancel := dbService.getContext() defer cancel() - _id, err := primitive.ObjectIDFromHex(reportID) + _id, err := bson.ObjectIDFromHex(reportID) if err != nil { return err } @@ -155,7 +165,7 @@ func (dbService *StudyDBService) UpdateReportData( } var reportSortOnTimestamp = bson.D{ - primitive.E{Key: "timestamp", Value: -1}, + {Key: "timestamp", Value: -1}, } // get report count for query @@ -280,16 +290,9 @@ func (dbService *StudyDBService) GetUniqueReportKeysForStudy( } } - res, err := dbService.collectionReports(instanceID, studyKey).Distinct(ctx, "key", filter) - if err != nil { + var keys []string + if err := dbService.collectionReports(instanceID, studyKey).Distinct(ctx, "key", filter).Decode(&keys); err != nil { return nil, err } - - keys := make([]string, 0, len(res)) - for _, r := range res { - if v, ok := r.(string); ok { - keys = append(keys, v) - } - } return keys, nil } diff --git a/pkg/db/study/researcher-messages.go b/pkg/db/study/researcher-messages.go index e1991586..71f7ed0e 100644 --- a/pkg/db/study/researcher-messages.go +++ b/pkg/db/study/researcher-messages.go @@ -3,8 +3,7 @@ package study import ( "log/slog" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/v2/bson" studyTypes "github.com/case-framework/case-backend/pkg/study/types" ) @@ -52,9 +51,9 @@ func (dbService *StudyDBService) DeleteResearcherMessages(instanceID string, stu ctx, cancel := dbService.getContext() defer cancel() - idsToDelete := []primitive.ObjectID{} + idsToDelete := []bson.ObjectID{} for _, id := range messageIDs { - _id, err := primitive.ObjectIDFromHex(id) + _id, err := bson.ObjectIDFromHex(id) if err != nil { slog.Debug("unexpected error while converting id to ObjectID: %v", slog.String("error", err.Error())) continue diff --git a/pkg/db/study/responses.go b/pkg/db/study/responses.go index 08e760f4..44ae7112 100644 --- a/pkg/db/study/responses.go +++ b/pkg/db/study/responses.go @@ -3,24 +3,38 @@ package study import ( "context" "errors" - "fmt" "log/slog" "time" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" studyTypes "github.com/case-framework/case-backend/pkg/study/types" ) +const ( + idxResponsesParticipantID = "participantID_1" + idxResponsesParticipantIDKeySubmittedAt = "participantID_1_key_1_submittedAt_1" + idxResponsesSubmittedAt = "submittedAt_1" + idxResponsesArrivedAt = "arrivedAt_1" + idxResponsesKey = "key_1" +) + +var defaultResponseIndexNames = []string{ + idxResponsesParticipantID, + idxResponsesParticipantIDKeySubmittedAt, + idxResponsesSubmittedAt, + idxResponsesArrivedAt, + idxResponsesKey, +} + var indexesForResponsesCollection = []mongo.IndexModel{ { Keys: bson.D{ {Key: "participantID", Value: 1}, }, - Options: options.Index().SetName("participantID_1"), + Options: options.Index().SetName(idxResponsesParticipantID), }, { Keys: bson.D{ @@ -28,25 +42,25 @@ var indexesForResponsesCollection = []mongo.IndexModel{ {Key: "key", Value: 1}, {Key: "submittedAt", Value: 1}, }, - Options: options.Index().SetName("participantID_1_key_1_submittedAt_1"), + Options: options.Index().SetName(idxResponsesParticipantIDKeySubmittedAt), }, { Keys: bson.D{ {Key: "submittedAt", Value: 1}, }, - Options: options.Index().SetName("submittedAt_1"), + Options: options.Index().SetName(idxResponsesSubmittedAt), }, { Keys: bson.D{ {Key: "arrivedAt", Value: 1}, }, - Options: options.Index().SetName("arrivedAt_1"), + Options: options.Index().SetName(idxResponsesArrivedAt), }, { Keys: bson.D{ {Key: "key", Value: 1}, }, - Options: options.Index().SetName("key_1"), + Options: options.Index().SetName(idxResponsesKey), }, } @@ -55,18 +69,17 @@ func (dbService *StudyDBService) DropIndexForResponsesCollection(instanceID stri defer cancel() if dropAll { - _, err := dbService.collectionResponses(instanceID, studyKey).Indexes().DropAll(ctx) + err := dbService.collectionResponses(instanceID, studyKey).Indexes().DropAll(ctx) if err != nil { slog.Error("Error dropping all indexes for responses", slog.String("error", err.Error()), slog.String("instanceID", instanceID), slog.String("studyKey", studyKey)) } } else { - for _, index := range indexesForResponsesCollection { - if index.Options == nil || index.Options.Name == nil { - slog.Error("Index name is nil for responses collection", slog.String("index", fmt.Sprintf("%+v", index))) + for _, indexName := range defaultResponseIndexNames { + if indexName == "" { + slog.Error("Index name is empty for responses collection") continue } - indexName := *index.Options.Name - _, err := dbService.collectionResponses(instanceID, studyKey).Indexes().DropOne(ctx, indexName) + err := dbService.collectionResponses(instanceID, studyKey).Indexes().DropOne(ctx, indexName) if err != nil { slog.Error("Error dropping index for responses", slog.String("error", err.Error()), slog.String("instanceID", instanceID), slog.String("studyKey", studyKey), slog.String("indexName", indexName)) } @@ -93,8 +106,11 @@ func (dbService *StudyDBService) AddSurveyResponse(instanceID string, studyKey s response.ArrivedAt = time.Now().Unix() } res, err := dbService.collectionResponses(instanceID, studyKey).InsertOne(ctx, response) - id := res.InsertedID.(primitive.ObjectID) - return id.Hex(), err + if err != nil { + return "", err + } + id := res.InsertedID.(bson.ObjectID) + return id.Hex(), nil } // get response by id @@ -102,7 +118,7 @@ func (dbService *StudyDBService) GetResponseByID(instanceID string, studyKey str ctx, cancel := dbService.getContext() defer cancel() - _id, err := primitive.ObjectIDFromHex(responseID) + _id, err := bson.ObjectIDFromHex(responseID) if err != nil { return response, err } @@ -158,11 +174,11 @@ func (dbService *StudyDBService) GetResponsesCount(instanceID string, studyKey s } type ResponseInfo struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` - Key string `bson:"key" json:"key"` - ParticipantID string `bson:"participantID" json:"participantId"` - VersionID string `bson:"versionID" json:"versionId"` - ArrivedAt int64 `bson:"arrivedAt" json:"arrivedAt"` + ID bson.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + Key string `bson:"key" json:"key"` + ParticipantID string `bson:"participantID" json:"participantId"` + VersionID string `bson:"versionID" json:"versionId"` + ArrivedAt int64 `bson:"arrivedAt" json:"arrivedAt"` } func (dbService *StudyDBService) GetResponseInfos(instanceID string, studyKey string, filter bson.M, page int64, limit int64) (responseInfos []ResponseInfo, paginationInfo *PaginationInfos, err error) { @@ -183,7 +199,7 @@ func (dbService *StudyDBService) GetResponseInfos(instanceID string, studyKey st skip := (paginationInfo.CurrentPage - 1) * paginationInfo.PageSize sortBySubmittedAt := bson.D{ - primitive.E{Key: "submittedAt", Value: -1}, + {Key: "submittedAt", Value: -1}, } opts := options.Find() @@ -192,11 +208,11 @@ func (dbService *StudyDBService) GetResponseInfos(instanceID string, studyKey st opts.SetLimit(paginationInfo.PageSize) projection := bson.D{ - primitive.E{Key: "_id", Value: 1}, - primitive.E{Key: "key", Value: 1}, - primitive.E{Key: "participantID", Value: 1}, - primitive.E{Key: "versionID", Value: 1}, - primitive.E{Key: "arrivedAt", Value: 1}, + {Key: "_id", Value: 1}, + {Key: "key", Value: 1}, + {Key: "participantID", Value: 1}, + {Key: "versionID", Value: 1}, + {Key: "arrivedAt", Value: 1}, } opts.SetProjection(projection) @@ -252,7 +268,7 @@ func (dbService *StudyDBService) DeleteResponseByID(instanceID string, studyKey ctx, cancel := dbService.getContext() defer cancel() - _id, err := primitive.ObjectIDFromHex(responseID) + _id, err := bson.ObjectIDFromHex(responseID) if err != nil { return err } diff --git a/pkg/db/study/study-code-lists.go b/pkg/db/study/study-code-lists.go index ab5fe0b9..69889581 100644 --- a/pkg/db/study/study-code-lists.go +++ b/pkg/db/study/study-code-lists.go @@ -1,17 +1,22 @@ package study import ( - "fmt" "log/slog" "time" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" studytypes "github.com/case-framework/case-backend/pkg/study/types" ) +const idxStudyCodeListsStudyKeyListKeyCode = "studyKey_1_listKey_1_code_1" + +var defaultStudyCodeListIndexNames = []string{ + idxStudyCodeListsStudyKeyListKeyCode, +} + var indexesForStudyCodeListsCollection = []mongo.IndexModel{ { Keys: bson.D{ @@ -19,7 +24,7 @@ var indexesForStudyCodeListsCollection = []mongo.IndexModel{ {Key: "listKey", Value: 1}, {Key: "code", Value: 1}, }, - Options: options.Index().SetUnique(true).SetName("studyKey_1_listKey_1_code_1"), + Options: options.Index().SetUnique(true).SetName(idxStudyCodeListsStudyKeyListKeyCode), }, } @@ -29,18 +34,17 @@ func (dbService *StudyDBService) DropIndexForStudyCodeListsCollection(instanceID collection := dbService.collectionStudyCodeLists(instanceID) if dropAll { - _, err := collection.Indexes().DropAll(ctx) + err := collection.Indexes().DropAll(ctx) if err != nil { slog.Error("Error dropping all indexes for studyCodeLists", slog.String("error", err.Error()), slog.String("instanceID", instanceID)) } } else { - for _, index := range indexesForStudyCodeListsCollection { - if index.Options == nil || index.Options.Name == nil { - slog.Error("Index name is nil for studyCodeLists collection", slog.String("index", fmt.Sprintf("%+v", index)), slog.String("instanceID", instanceID)) + for _, indexName := range defaultStudyCodeListIndexNames { + if indexName == "" { + slog.Error("Index name is empty for studyCodeLists collection", slog.String("instanceID", instanceID)) continue } - indexName := *index.Options.Name - _, err := collection.Indexes().DropOne(ctx, indexName) + err := collection.Indexes().DropOne(ctx, indexName) if err != nil { slog.Error("Error dropping index for studyCodeLists", slog.String("error", err.Error()), slog.String("instanceID", instanceID), slog.String("indexName", indexName)) } diff --git a/pkg/db/study/study-counters.go b/pkg/db/study/study-counters.go index 13285e41..2c349f03 100644 --- a/pkg/db/study/study-counters.go +++ b/pkg/db/study/study-counters.go @@ -1,14 +1,19 @@ package study import ( - "fmt" "log/slog" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" ) +const idxStudyCountersStudyKeyScope = "studyKey_1_scope_1" + +var defaultStudyCounterIndexNames = []string{ + idxStudyCountersStudyKeyScope, +} + type StudyCounter struct { StudyKey string `json:"studyKey" bson:"studyKey"` Scope string `json:"scope" bson:"scope"` @@ -21,7 +26,7 @@ var indexesForStudyCountersCollection = []mongo.IndexModel{ {Key: "studyKey", Value: 1}, {Key: "scope", Value: 1}, }, - Options: options.Index().SetUnique(true).SetName("studyKey_1_scope_1"), + Options: options.Index().SetUnique(true).SetName(idxStudyCountersStudyKeyScope), }, } @@ -31,18 +36,17 @@ func (dbService *StudyDBService) DropIndexForStudyCountersCollection(instanceID collection := dbService.collectionStudyCounters(instanceID) if dropAll { - _, err := collection.Indexes().DropAll(ctx) + err := collection.Indexes().DropAll(ctx) if err != nil { slog.Error("Error dropping all indexes for studyCounters", slog.String("error", err.Error()), slog.String("instanceID", instanceID)) } } else { - for _, index := range indexesForStudyCountersCollection { - if index.Options == nil || index.Options.Name == nil { - slog.Error("Index name is nil for studyCounters collection", slog.String("index", fmt.Sprintf("%+v", index)), slog.String("instanceID", instanceID)) + for _, indexName := range defaultStudyCounterIndexNames { + if indexName == "" { + slog.Error("Index name is empty for studyCounters collection", slog.String("instanceID", instanceID)) continue } - indexName := *index.Options.Name - _, err := collection.Indexes().DropOne(ctx, indexName) + err := collection.Indexes().DropOne(ctx, indexName) if err != nil { slog.Error("Error dropping index for studyCounters", slog.String("error", err.Error()), slog.String("instanceID", instanceID), slog.String("indexName", indexName)) } diff --git a/pkg/db/study/studyInfos.go b/pkg/db/study/study-infos.go similarity index 92% rename from pkg/db/study/studyInfos.go rename to pkg/db/study/study-infos.go index 3d36875a..d14cf1eb 100644 --- a/pkg/db/study/studyInfos.go +++ b/pkg/db/study/study-infos.go @@ -1,23 +1,27 @@ package study import ( - "fmt" "log/slog" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" studyTypes "github.com/case-framework/case-backend/pkg/study/types" ) +const idxStudyInfosKey = "key_1" + +var defaultStudyInfoIndexNames = []string{ + idxStudyInfosKey, +} + var indexesForStudyInfosCollection = []mongo.IndexModel{ { Keys: bson.D{ {Key: "key", Value: 1}, }, - Options: options.Index().SetUnique(true).SetName("key_1"), + Options: options.Index().SetUnique(true).SetName(idxStudyInfosKey), }, } @@ -26,18 +30,17 @@ func (dbService *StudyDBService) DropIndexForStudyInfosCollection(instanceID str defer cancel() if dropAll { - _, err := dbService.collectionStudyInfos(instanceID).Indexes().DropAll(ctx) + err := dbService.collectionStudyInfos(instanceID).Indexes().DropAll(ctx) if err != nil { slog.Error("Error dropping all indexes for studyInfos", slog.String("error", err.Error()), slog.String("instanceID", instanceID)) } } else { - for _, index := range indexesForStudyInfosCollection { - if index.Options == nil || index.Options.Name == nil { - slog.Error("Index name is nil for studyInfos collection", slog.String("index", fmt.Sprintf("%+v", index))) + for _, indexName := range defaultStudyInfoIndexNames { + if indexName == "" { + slog.Error("Index name is empty for studyInfos collection") continue } - indexName := *index.Options.Name - _, err := dbService.collectionStudyInfos(instanceID).Indexes().DropOne(ctx, indexName) + err := dbService.collectionStudyInfos(instanceID).Indexes().DropOne(ctx, indexName) if err != nil { slog.Error("Error dropping index for studyInfos", slog.String("error", err.Error()), slog.String("instanceID", instanceID), slog.String("indexName", indexName)) } @@ -68,9 +71,9 @@ func (dbService *StudyDBService) GetStudies(instanceID string, statusFilter stri opts := options.Find() if onlyKeys { projection := bson.D{ - primitive.E{Key: "key", Value: 1}, - primitive.E{Key: "secretKey", Value: 1}, - primitive.E{Key: "configs.idMappingMethod", Value: 1}, + {Key: "key", Value: 1}, + {Key: "secretKey", Value: 1}, + {Key: "configs.idMappingMethod", Value: 1}, } opts.SetProjection(projection) } diff --git a/pkg/db/study/studyRules.go b/pkg/db/study/study-rules.go similarity index 80% rename from pkg/db/study/studyRules.go rename to pkg/db/study/study-rules.go index 7bb2ae0f..767bc3c4 100644 --- a/pkg/db/study/studyRules.go +++ b/pkg/db/study/study-rules.go @@ -1,30 +1,38 @@ package study import ( - "fmt" "log/slog" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" studyTypes "github.com/case-framework/case-backend/pkg/study/types" ) +const ( + idxStudyRulesStudyKey = "studyKey_1" + idxStudyRulesUploadedAtStudyKey = "uploadedAt_1_studyKey_1" +) + +var defaultStudyRuleIndexNames = []string{ + idxStudyRulesStudyKey, + idxStudyRulesUploadedAtStudyKey, +} + var indexesForStudyRulesCollection = []mongo.IndexModel{ { Keys: bson.D{ {Key: "studyKey", Value: 1}, }, - Options: options.Index().SetName("studyKey_1"), + Options: options.Index().SetName(idxStudyRulesStudyKey), }, { Keys: bson.D{ {Key: "uploadedAt", Value: 1}, {Key: "studyKey", Value: 1}, }, - Options: options.Index().SetName("uploadedAt_1_studyKey_1"), + Options: options.Index().SetName(idxStudyRulesUploadedAtStudyKey), }, } @@ -35,18 +43,17 @@ func (dbService *StudyDBService) DropIndexForStudyRulesCollection(instanceID str collection := dbService.collectionStudyRules(instanceID) if dropAll { - _, err := collection.Indexes().DropAll(ctx) + err := collection.Indexes().DropAll(ctx) if err != nil { slog.Error("Error dropping all indexes for studyRules", slog.String("error", err.Error()), slog.String("instanceID", instanceID)) } } else { - for _, index := range indexesForStudyRulesCollection { - if index.Options == nil || index.Options.Name == nil { - slog.Error("Index name is nil for studyRules collection", slog.String("index", fmt.Sprintf("%+v", index))) + for _, indexName := range defaultStudyRuleIndexNames { + if indexName == "" { + slog.Error("Index name is empty for studyRules collection") continue } - indexName := *index.Options.Name - _, err := collection.Indexes().DropOne(ctx, indexName) + err := collection.Indexes().DropOne(ctx, indexName) if err != nil { slog.Error("Error dropping index for studyRules", slog.String("error", err.Error()), slog.String("instanceID", instanceID), slog.String("indexName", indexName)) } @@ -90,16 +97,14 @@ func (dbService *StudyDBService) GetCurrentStudyRules(instanceID string, studyKe collection := dbService.collectionStudyRules(instanceID) sortByPublished := bson.D{ - primitive.E{Key: "uploadedAt", Value: -1}, + {Key: "uploadedAt", Value: -1}, } filter := bson.M{ "studyKey": studyKey, } - opts := &options.FindOneOptions{ - Sort: sortByPublished, - } + opts := options.FindOne().SetSort(sortByPublished) err = collection.FindOne(ctx, filter, opts).Decode(&rules) if err != nil { @@ -115,7 +120,7 @@ func (dbService *StudyDBService) GetStudyRulesByID(instanceID string, studyKey s collection := dbService.collectionStudyRules(instanceID) - _id, err := primitive.ObjectIDFromHex(id) + _id, err := bson.ObjectIDFromHex(id) if err != nil { return rules, err } @@ -140,7 +145,7 @@ func (dbService *StudyDBService) DeleteStudyRulesByID(instanceID string, studyKe collection := dbService.collectionStudyRules(instanceID) - _id, err := primitive.ObjectIDFromHex(id) + _id, err := bson.ObjectIDFromHex(id) if err != nil { return err } @@ -169,8 +174,8 @@ func (dbService *StudyDBService) GetStudyRulesHistory(instanceID string, studyKe opts := options.Find().SetSort(bson.D{{Key: "uploadedAt", Value: -1}}) opts.SetProjection(bson.D{ - primitive.E{Key: "rules", Value: 0}, - primitive.E{Key: "serialisedRules", Value: 0}, + {Key: "rules", Value: 0}, + {Key: "serialisedRules", Value: 0}, }) cursor, err := collection.Find(ctx, filter, opts) if err != nil { diff --git a/pkg/db/study/study-variables.go b/pkg/db/study/study-variables.go index 4e5ca7a1..3acceb56 100644 --- a/pkg/db/study/study-variables.go +++ b/pkg/db/study/study-variables.go @@ -1,26 +1,30 @@ package study import ( - "fmt" "log/slog" "time" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" studytypes "github.com/case-framework/case-backend/pkg/study/types" ) +const idxStudyVariablesStudyKeyKey = "studyKey_1_key_1" + +var defaultStudyVariableIndexNames = []string{ + idxStudyVariablesStudyKeyKey, +} + var indexesForStudyVariablesCollection = []mongo.IndexModel{ { Keys: bson.D{ {Key: "studyKey", Value: 1}, {Key: "key", Value: 1}, }, - Options: options.Index().SetUnique(true).SetName("studyKey_1_key_1"), + Options: options.Index().SetUnique(true).SetName(idxStudyVariablesStudyKeyKey), }, } @@ -40,18 +44,17 @@ func (dbService *StudyDBService) DropIndexForStudyVariablesCollection(instanceID collection := dbService.collectionStudyVariables(instanceID) if dropAll { - _, err := collection.Indexes().DropAll(ctx) + err := collection.Indexes().DropAll(ctx) if err != nil { slog.Error("Error dropping all indexes for studyVariables", slog.String("error", err.Error()), slog.String("instanceID", instanceID)) } } else { - for _, index := range indexesForStudyVariablesCollection { - if index.Options == nil || index.Options.Name == nil { - slog.Error("Index name is nil for studyVariables collection", slog.String("index", fmt.Sprintf("%+v", index)), slog.String("instanceID", instanceID)) + for _, indexName := range defaultStudyVariableIndexNames { + if indexName == "" { + slog.Error("Index name is empty for studyVariables collection", slog.String("instanceID", instanceID)) continue } - indexName := *index.Options.Name - _, err := collection.Indexes().DropOne(ctx, indexName) + err := collection.Indexes().DropOne(ctx, indexName) if err != nil { slog.Error("Error dropping index for studyVariables", slog.String("error", err.Error()), slog.String("instanceID", instanceID), slog.String("indexName", indexName)) } @@ -90,7 +93,7 @@ func (dbService *StudyDBService) CreateStudyVariable(instanceID string, variable if err != nil { return "", err } - id := res.InsertedID.(primitive.ObjectID) + id := res.InsertedID.(bson.ObjectID) return id.Hex(), nil } @@ -183,7 +186,7 @@ func (dbService *StudyDBService) GetStudyVariableByID(instanceID string, id stri ctx, cancel := dbService.getContext() defer cancel() - _id, err := primitive.ObjectIDFromHex(id) + _id, err := bson.ObjectIDFromHex(id) if err != nil { return studytypes.StudyVariables{}, err } @@ -216,7 +219,7 @@ func (dbService *StudyDBService) DeleteStudyVariableByID(instanceID string, id s ctx, cancel := dbService.getContext() defer cancel() - _id, err := primitive.ObjectIDFromHex(id) + _id, err := bson.ObjectIDFromHex(id) if err != nil { return err } diff --git a/pkg/db/study/surveys.go b/pkg/db/study/surveys.go index 3f8c08af..79cf69d0 100644 --- a/pkg/db/study/surveys.go +++ b/pkg/db/study/surveys.go @@ -2,18 +2,30 @@ package study import ( "errors" - "fmt" "log/slog" "time" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" studyTypes "github.com/case-framework/case-backend/pkg/study/types" ) +const ( + idxSurveysSurveyDefinitionUnpublishedPublished = "surveyDefinition.key_1_unpublished_1_published_-1" + idxSurveysPublishedSurveyDefinition = "published_1_surveyDefinition.key_1" + idxSurveysUnpublished = "unpublished_1" + idxSurveysSurveyDefinitionVersionIDUnique = "surveyDefinition.key_1_versionID_1" +) + +var defaultSurveyIndexNames = []string{ + idxSurveysSurveyDefinitionUnpublishedPublished, + idxSurveysPublishedSurveyDefinition, + idxSurveysUnpublished, + idxSurveysSurveyDefinitionVersionIDUnique, +} + var indexesForSurveysCollection = []mongo.IndexModel{ { Keys: bson.D{ @@ -21,27 +33,27 @@ var indexesForSurveysCollection = []mongo.IndexModel{ {Key: "unpublished", Value: 1}, {Key: "published", Value: -1}, }, - Options: options.Index().SetName("surveyDefinition.key_1_unpublished_1_published_-1"), + Options: options.Index().SetName(idxSurveysSurveyDefinitionUnpublishedPublished), }, { Keys: bson.D{ {Key: "published", Value: 1}, {Key: "surveyDefinition.key", Value: 1}, }, - Options: options.Index().SetName("published_1_surveyDefinition.key_1"), + Options: options.Index().SetName(idxSurveysPublishedSurveyDefinition), }, { Keys: bson.D{ {Key: "unpublished", Value: 1}, }, - Options: options.Index().SetName("unpublished_1"), + Options: options.Index().SetName(idxSurveysUnpublished), }, { Keys: bson.D{ {Key: "surveyDefinition.key", Value: 1}, {Key: "versionID", Value: 1}, }, - Options: options.Index().SetName("surveyDefinition.key_1_versionID_1").SetUnique(true), + Options: options.Index().SetName(idxSurveysSurveyDefinitionVersionIDUnique).SetUnique(true), }, } @@ -50,18 +62,17 @@ func (dbService *StudyDBService) DropIndexForSurveysCollection(instanceID string defer cancel() if dropAll { - _, err := dbService.collectionSurveys(instanceID, studyKey).Indexes().DropAll(ctx) + err := dbService.collectionSurveys(instanceID, studyKey).Indexes().DropAll(ctx) if err != nil { slog.Error("Error dropping all indexes for surveys", slog.String("error", err.Error()), slog.String("instanceID", instanceID), slog.String("studyKey", studyKey)) } } else { - for _, index := range indexesForSurveysCollection { - if index.Options == nil || index.Options.Name == nil { - slog.Error("Index name is nil for surveys collection", slog.String("index", fmt.Sprintf("%+v", index))) + for _, indexName := range defaultSurveyIndexNames { + if indexName == "" { + slog.Error("Index name is empty for surveys collection") continue } - indexName := *index.Options.Name - _, err := dbService.collectionSurveys(instanceID, studyKey).Indexes().DropOne(ctx, indexName) + err := dbService.collectionSurveys(instanceID, studyKey).Indexes().DropOne(ctx, indexName) if err != nil { slog.Error("Error dropping index for surveys", slog.String("error", err.Error()), slog.String("instanceID", instanceID), slog.String("studyKey", studyKey), slog.String("indexName", indexName)) } @@ -88,7 +99,7 @@ func (dbService *StudyDBService) SaveSurveyVersion(instanceID string, studyKey s if err != nil { return err } - survey.ID = ret.InsertedID.(primitive.ObjectID) + survey.ID = ret.InsertedID.(bson.ObjectID) return nil } @@ -101,26 +112,21 @@ func (dbService *StudyDBService) GetSurveyKeysForStudy(instanceID string, studyK if !includeUnpublished { filter["unpublished"] = 0 } - res, err := dbService.collectionSurveys(instanceID, studyKey).Distinct(ctx, "surveyDefinition.key", filter) - if err != nil { - return surveyKeys, err - } - surveyKeys = make([]string, len(res)) - for i, r := range res { - surveyKeys[i] = r.(string) + if err = dbService.collectionSurveys(instanceID, studyKey).Distinct(ctx, "surveyDefinition.key", filter).Decode(&surveyKeys); err != nil { + return nil, err } - return surveyKeys, err + return surveyKeys, nil } var ( sortByPublishedDesc = bson.D{ - primitive.E{Key: "published", Value: -1}, + {Key: "published", Value: -1}, } projectionToRemoveSurveyContentAndRules = bson.D{ - primitive.E{Key: "surveyDefinition.items", Value: 0}, - primitive.E{Key: "prefillRules", Value: 0}, - primitive.E{Key: "contextRules", Value: 0}, + {Key: "surveyDefinition.items", Value: 0}, + {Key: "prefillRules", Value: 0}, + {Key: "contextRules", Value: 0}, } ) @@ -132,11 +138,9 @@ func (dbService *StudyDBService) GetSurveyVersions(instanceID string, studyKey s if len(surveyKey) > 0 { filter["surveyDefinition.key"] = surveyKey } - opts := &options.FindOptions{} - - opts.SetProjection(projectionToRemoveSurveyContentAndRules) - - opts.SetSort(sortByPublishedDesc) + opts := options.Find(). + SetProjection(projectionToRemoveSurveyContentAndRules). + SetSort(sortByPublishedDesc) cur, err := dbService.collectionSurveys(instanceID, studyKey).Find( ctx, @@ -181,8 +185,7 @@ func (dbService *StudyDBService) GetCurrentSurveyVersion(instanceID string, stud }, } - opts := &options.FindOneOptions{} - opts.SetSort(sortByPublishedDesc) + opts := options.FindOne().SetSort(sortByPublishedDesc) err = dbService.collectionSurveys(instanceID, studyKey).FindOne(ctx, filter, opts).Decode(&survey) if err != nil { diff --git a/pkg/db/study/taskQueue.go b/pkg/db/study/task-queue.go similarity index 83% rename from pkg/db/study/taskQueue.go rename to pkg/db/study/task-queue.go index 57817ff7..5fd67522 100644 --- a/pkg/db/study/taskQueue.go +++ b/pkg/db/study/task-queue.go @@ -1,26 +1,29 @@ package study import ( - "fmt" "log/slog" "time" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" studyTypes "github.com/case-framework/case-backend/pkg/study/types" ) const ( REMOVE_TASK_FROM_QUEUE_AFTER = 60 * 60 * 24 * 2 // 2 days + idxTaskQueueUpdatedAt = "updatedAt_1" ) +var defaultTaskQueueIndexNames = []string{ + idxTaskQueueUpdatedAt, +} + var indexesForTaskQueueCollection = []mongo.IndexModel{ { Keys: bson.D{{Key: "updatedAt", Value: 1}}, - Options: options.Index().SetExpireAfterSeconds(REMOVE_TASK_FROM_QUEUE_AFTER).SetName("updatedAt_1"), + Options: options.Index().SetExpireAfterSeconds(REMOVE_TASK_FROM_QUEUE_AFTER).SetName(idxTaskQueueUpdatedAt), }, } @@ -29,18 +32,17 @@ func (dbService *StudyDBService) DropIndexForTaskQueueCollection(instanceID stri defer cancel() if dropAll { - _, err := dbService.collectionTaskQueue(instanceID).Indexes().DropAll(ctx) + err := dbService.collectionTaskQueue(instanceID).Indexes().DropAll(ctx) if err != nil { slog.Error("Error dropping all indexes for task queue", slog.String("error", err.Error()), slog.String("instanceID", instanceID)) } } else { - for _, index := range indexesForTaskQueueCollection { - if index.Options == nil || index.Options.Name == nil { - slog.Error("Index name is nil for task queue collection", slog.String("index", fmt.Sprintf("%+v", index))) + for _, indexName := range defaultTaskQueueIndexNames { + if indexName == "" { + slog.Error("Index name is empty for task queue collection") continue } - indexName := *index.Options.Name - _, err := dbService.collectionTaskQueue(instanceID).Indexes().DropOne(ctx, indexName) + err := dbService.collectionTaskQueue(instanceID).Indexes().DropOne(ctx, indexName) if err != nil { slog.Error("Error dropping index for task queue", slog.String("error", err.Error()), slog.String("instanceID", instanceID), slog.String("indexName", indexName)) } @@ -82,7 +84,7 @@ func (dbService *StudyDBService) CreateTask( if err != nil { return task, err } - task.ID = ret.InsertedID.(primitive.ObjectID) + task.ID = ret.InsertedID.(bson.ObjectID) return task, nil } @@ -91,7 +93,7 @@ func (dbService *StudyDBService) GetTaskByID(instanceID string, taskID string) ( ctx, cancel := dbService.getContext() defer cancel() - _id, err := primitive.ObjectIDFromHex(taskID) + _id, err := bson.ObjectIDFromHex(taskID) if err != nil { return task, err } @@ -125,7 +127,7 @@ func (dbService *StudyDBService) UpdateTaskTotalCount(instanceID string, taskID ctx, cancel := dbService.getContext() defer cancel() - _id, err := primitive.ObjectIDFromHex(taskID) + _id, err := bson.ObjectIDFromHex(taskID) if err != nil { return err } @@ -148,7 +150,7 @@ func (dbService *StudyDBService) UpdateTaskProgress(instanceID string, taskID st ctx, cancel := dbService.getContext() defer cancel() - _id, err := primitive.ObjectIDFromHex(taskID) + _id, err := bson.ObjectIDFromHex(taskID) if err != nil { return err } @@ -177,7 +179,7 @@ func (dbService *StudyDBService) UpdateTaskCompleted( ctx, cancel := dbService.getContext() defer cancel() - _id, err := primitive.ObjectIDFromHex(taskID) + _id, err := bson.ObjectIDFromHex(taskID) if err != nil { return err } @@ -203,7 +205,7 @@ func (dbService *StudyDBService) DeleteTaskByID(instanceID string, taskID string ctx, cancel := dbService.getContext() defer cancel() - _id, err := primitive.ObjectIDFromHex(taskID) + _id, err := bson.ObjectIDFromHex(taskID) if err != nil { return err } diff --git a/pkg/db/utils.go b/pkg/db/utils.go index 238d1eda..6cd28fbf 100644 --- a/pkg/db/utils.go +++ b/pkg/db/utils.go @@ -7,8 +7,8 @@ import ( "log/slog" "time" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" ) const ( diff --git a/pkg/messaging/types/emailTemplate.go b/pkg/messaging/types/email-template.go similarity index 93% rename from pkg/messaging/types/emailTemplate.go rename to pkg/messaging/types/email-template.go index 29adfdff..82fd8bf4 100644 --- a/pkg/messaging/types/emailTemplate.go +++ b/pkg/messaging/types/email-template.go @@ -1,6 +1,6 @@ package types -import "go.mongodb.org/mongo-driver/bson/primitive" +import "go.mongodb.org/mongo-driver/v2/bson" const ( EMAIL_TYPE_REGISTRATION = "registration" @@ -21,7 +21,7 @@ const ( ) type EmailTemplate struct { - ID primitive.ObjectID `bson:"_id" json:"id,omitempty"` + ID bson.ObjectID `bson:"_id" json:"id,omitempty"` MessageType string `bson:"messageType" json:"messageType"` StudyKey string `bson:"studyKey,omitempty" json:"studyKey"` DefaultLanguage string `bson:"defaultLanguage" json:"defaultLanguage"` diff --git a/pkg/messaging/types/outgoing_email.go b/pkg/messaging/types/outgoing_email.go index 7d55f25b..3015512a 100644 --- a/pkg/messaging/types/outgoing_email.go +++ b/pkg/messaging/types/outgoing_email.go @@ -3,20 +3,20 @@ package types import ( "time" - "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/v2/bson" ) type OutgoingEmail struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id"` - MessageType string `bson:"messageType" json:"messageType"` - UserID string `bson:"userId" json:"userId"` - To []string `bson:"to" json:"to"` - Subject string `bson:"subject" json:"subject"` - HeaderOverrides *HeaderOverrides `bson:"headerOverrides" json:"headerOverrides"` - Content string `bson:"content" json:"content"` - AddedAt int64 `bson:"addedAt" json:"addedAt"` - SentAt time.Time `bson:"sentAt" json:"sentAt"` - ExpiresAt int64 `bson:"expiresAt" json:"expiresAt"` - HighPrio bool `bson:"highPrio" json:"highPrio"` - LastSendAttempt int64 `bson:"lastSendAttempt" json:"lastSendAttempt"` + ID bson.ObjectID `bson:"_id,omitempty" json:"id"` + MessageType string `bson:"messageType" json:"messageType"` + UserID string `bson:"userId" json:"userId"` + To []string `bson:"to" json:"to"` + Subject string `bson:"subject" json:"subject"` + HeaderOverrides *HeaderOverrides `bson:"headerOverrides" json:"headerOverrides"` + Content string `bson:"content" json:"content"` + AddedAt int64 `bson:"addedAt" json:"addedAt"` + SentAt time.Time `bson:"sentAt" json:"sentAt"` + ExpiresAt int64 `bson:"expiresAt" json:"expiresAt"` + HighPrio bool `bson:"highPrio" json:"highPrio"` + LastSendAttempt int64 `bson:"lastSendAttempt" json:"lastSendAttempt"` } diff --git a/pkg/messaging/types/scheduledEmails.go b/pkg/messaging/types/scheduledEmails.go index 6f0e8612..a5ae870c 100644 --- a/pkg/messaging/types/scheduledEmails.go +++ b/pkg/messaging/types/scheduledEmails.go @@ -2,11 +2,11 @@ package types import ( study "github.com/case-framework/case-backend/pkg/study/types" - "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/v2/bson" ) type ScheduledEmail struct { - ID primitive.ObjectID `bson:"_id" json:"id,omitempty"` + ID bson.ObjectID `bson:"_id" json:"id,omitempty"` Template EmailTemplate `bson:"template" json:"template"` Type string `bson:"type" json:"type"` StudyKey string `bson:"studyKey" json:"studyKey"` diff --git a/pkg/messaging/types/sms.go b/pkg/messaging/types/sms.go index 525a9708..ccbc6fae 100644 --- a/pkg/messaging/types/sms.go +++ b/pkg/messaging/types/sms.go @@ -3,19 +3,19 @@ package types import ( "time" - "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/v2/bson" ) type SentSMS struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id"` - UserID string `bson:"userID" json:"userID"` - MessageType string `bson:"messageType" json:"messageType"` - SentAt time.Time `bson:"sentAt" json:"sentAt"` - PhoneNumber string `bson:"phoneNumber" json:"phoneNumber"` + ID bson.ObjectID `bson:"_id,omitempty" json:"id"` + UserID string `bson:"userID" json:"userID"` + MessageType string `bson:"messageType" json:"messageType"` + SentAt time.Time `bson:"sentAt" json:"sentAt"` + PhoneNumber string `bson:"phoneNumber" json:"phoneNumber"` } type SMSTemplate struct { - ID primitive.ObjectID `bson:"_id" json:"id,omitempty"` + ID bson.ObjectID `bson:"_id" json:"id,omitempty"` MessageType string `bson:"messageType" json:"messageType"` DefaultLanguage string `bson:"defaultLanguage" json:"defaultLanguage"` From string `bson:"from" json:"from"` diff --git a/pkg/study/participant-data.go b/pkg/study/participant-data.go index 2411c6f2..b7eefb3b 100644 --- a/pkg/study/participant-data.go +++ b/pkg/study/participant-data.go @@ -9,7 +9,7 @@ import ( "github.com/case-framework/case-backend/pkg/study/studyengine" studyTypes "github.com/case-framework/case-backend/pkg/study/types" - "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/v2/bson" ) type AssignedSurveyWithContext struct { diff --git a/pkg/study/study-service.go b/pkg/study/study-service.go index 249eff7f..98868bff 100644 --- a/pkg/study/study-service.go +++ b/pkg/study/study-service.go @@ -12,8 +12,7 @@ import ( "github.com/case-framework/case-backend/pkg/study/types" studyTypes "github.com/case-framework/case-backend/pkg/study/types" studyUtils "github.com/case-framework/case-backend/pkg/study/utils" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/v2/bson" ) var ( @@ -137,7 +136,7 @@ func OnRegisterTempParticipant(instanceID string, studyKey string) (pState *stud return } - tempProfileID := primitive.NewObjectID().Hex() + tempProfileID := bson.NewObjectID().Hex() participantID, _, err := ComputeParticipantIDs(study, tempProfileID) if err != nil { slog.Error("Error computing participant IDs", slog.String("instanceID", instanceID), slog.String("studyKey", studyKey), slog.String("error", err.Error())) @@ -180,7 +179,7 @@ func OnRegisterVirtualParticipant(instanceID string, studyKey string) (pState *s return } - virtualProfileID := primitive.NewObjectID().Hex() + virtualProfileID := bson.NewObjectID().Hex() participantID, _, err := ComputeParticipantIDs(study, virtualProfileID) if err != nil { slog.Error("Error computing participant IDs", slog.String("instanceID", instanceID), slog.String("studyKey", studyKey), slog.String("error", err.Error())) diff --git a/pkg/study/studyengine/actions.go b/pkg/study/studyengine/actions.go index 96ea2247..8dadd3f5 100644 --- a/pkg/study/studyengine/actions.go +++ b/pkg/study/studyengine/actions.go @@ -15,7 +15,7 @@ import ( httpclient "github.com/case-framework/case-backend/pkg/http-client" studyTypes "github.com/case-framework/case-backend/pkg/study/types" - "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/v2/bson" ) func ActionEval(action studyTypes.Expression, oldState ActionData, event StudyEvent) (newState ActionData, err error) { @@ -553,7 +553,7 @@ func addMessage(action studyTypes.Expression, oldState ActionData, event StudyEv } newMessage := studyTypes.ParticipantMessage{ - ID: primitive.NewObjectID().Hex(), + ID: bson.NewObjectID().Hex(), Type: messageType, ScheduledFor: int64(timestamp), } diff --git a/pkg/study/studyengine/expressions.go b/pkg/study/studyengine/expressions.go index add6ecf5..1536415b 100644 --- a/pkg/study/studyengine/expressions.go +++ b/pkg/study/studyengine/expressions.go @@ -13,7 +13,7 @@ import ( "github.com/case-framework/case-backend/pkg/apihelpers" httpclient "github.com/case-framework/case-backend/pkg/http-client" studyTypes "github.com/case-framework/case-backend/pkg/study/types" - "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/v2/bson" ) func ExpressionEval(expression studyTypes.Expression, evalCtx EvalContext) (val interface{}, err error) { diff --git a/pkg/study/studyengine/expressions_test.go b/pkg/study/studyengine/expressions_test.go index 0d979552..505e2750 100644 --- a/pkg/study/studyengine/expressions_test.go +++ b/pkg/study/studyengine/expressions_test.go @@ -7,7 +7,7 @@ import ( studyDB "github.com/case-framework/case-backend/pkg/db/study" studyTypes "github.com/case-framework/case-backend/pkg/study/types" - "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/v2/bson" ) // Reference/Lookup methods diff --git a/pkg/study/studyengine/types.go b/pkg/study/studyengine/types.go index 69be806b..60a9957c 100644 --- a/pkg/study/studyengine/types.go +++ b/pkg/study/studyengine/types.go @@ -6,7 +6,7 @@ import ( studyDB "github.com/case-framework/case-backend/pkg/db/study" studyTypes "github.com/case-framework/case-backend/pkg/study/types" - "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/v2/bson" ) const ( diff --git a/pkg/study/types/assignedSurvey.go b/pkg/study/types/assigned-survey.go similarity index 100% rename from pkg/study/types/assignedSurvey.go rename to pkg/study/types/assigned-survey.go diff --git a/pkg/study/types/localisedObject.go b/pkg/study/types/localised-object.go similarity index 100% rename from pkg/study/types/localisedObject.go rename to pkg/study/types/localised-object.go diff --git a/pkg/study/types/participantFileinfo.go b/pkg/study/types/participant-file-info.go similarity index 52% rename from pkg/study/types/participantFileinfo.go rename to pkg/study/types/participant-file-info.go index 9479efdf..67dec0fb 100644 --- a/pkg/study/types/participantFileinfo.go +++ b/pkg/study/types/participant-file-info.go @@ -3,7 +3,7 @@ package types import ( "time" - "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/v2/bson" ) const ( @@ -12,12 +12,12 @@ const ( ) type FileInfo struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` - ParticipantID string `bson:"participantID,omitempty" json:"participantID,omitempty"` - Status string `bson:"status,omitempty" json:"status,omitempty"` - UploadedBy string `bson:"uploadedBy,omitempty" json:"uploadedBy,omitempty"` // if not uploaded by the participant - Path string `bson:"path,omitempty" json:"path,omitempty"` - PreviewPath string `bson:"previewPath,omitempty" json:"previewPath,omitempty"` + ID bson.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + ParticipantID string `bson:"participantID,omitempty" json:"participantID,omitempty"` + Status string `bson:"status,omitempty" json:"status,omitempty"` + UploadedBy string `bson:"uploadedBy,omitempty" json:"uploadedBy,omitempty"` // if not uploaded by the participant + Path string `bson:"path,omitempty" json:"path,omitempty"` + PreviewPath string `bson:"previewPath,omitempty" json:"previewPath,omitempty"` SubmittedAt int64 `bson:"submittedAt,omitempty" json:"submittedAt,omitempty"` // deprecated, use CreatedAt instead CreatedAt time.Time `bson:"createdAt,omitempty" json:"createdAt,omitempty"` diff --git a/pkg/study/types/participant.go b/pkg/study/types/participant.go index 72183288..b1127ea0 100644 --- a/pkg/study/types/participant.go +++ b/pkg/study/types/participant.go @@ -1,6 +1,6 @@ package types -import "go.mongodb.org/mongo-driver/bson/primitive" +import "go.mongodb.org/mongo-driver/v2/bson" const ( PARTICIPANT_STUDY_STATUS_ACTIVE = "active" @@ -12,7 +12,7 @@ const ( // Participant defines the datamodel for current state of the participant in a study as stored in the database type Participant struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + ID bson.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` ParticipantID string `bson:"participantID" json:"participantId"` // reference to the study specific participant ID CurrentStudySession string `bson:"currentStudySession" json:"currentStudySession"` ModifiedAt int64 `bson:"modifiedAt" json:"modifiedAt"` diff --git a/pkg/study/types/report.go b/pkg/study/types/report.go index 1803776e..28ae8c44 100644 --- a/pkg/study/types/report.go +++ b/pkg/study/types/report.go @@ -3,17 +3,17 @@ package types import ( "time" - "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/v2/bson" ) type Report struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` - Key string `bson:"key" json:"key"` - ParticipantID string `bson:"participantID" json:"participantID"` // reference to the study specific participant ID - ResponseID string `bson:"responseID" json:"responseID"` // reference to the report - Timestamp int64 `bson:"timestamp" json:"timestamp"` - ModifiedAt time.Time `bson:"modifiedAt,omitempty" json:"modifiedAt,omitempty"` // if report is updated later, this is the time of the update - Data []ReportData `bson:"data" json:"data,omitempty"` + ID bson.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + Key string `bson:"key" json:"key"` + ParticipantID string `bson:"participantID" json:"participantID"` // reference to the study specific participant ID + ResponseID string `bson:"responseID" json:"responseID"` // reference to the report + Timestamp int64 `bson:"timestamp" json:"timestamp"` + ModifiedAt time.Time `bson:"modifiedAt,omitempty" json:"modifiedAt,omitempty"` // if report is updated later, this is the time of the update + Data []ReportData `bson:"data" json:"data,omitempty"` } type ReportData struct { diff --git a/pkg/study/types/study-code-list.go b/pkg/study/types/study-code-list.go index 86bae580..7b1e5063 100644 --- a/pkg/study/types/study-code-list.go +++ b/pkg/study/types/study-code-list.go @@ -3,13 +3,13 @@ package types import ( "time" - "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/v2/bson" ) type StudyCodeListEntry struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` - StudyKey string `bson:"studyKey" json:"studyKey"` - ListKey string `bson:"listKey" json:"listKey"` - Code string `bson:"code" json:"code"` - AddedAt time.Time `bson:"addedAt" json:"addedAt"` + ID bson.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + StudyKey string `bson:"studyKey" json:"studyKey"` + ListKey string `bson:"listKey" json:"listKey"` + Code string `bson:"code" json:"code"` + AddedAt time.Time `bson:"addedAt" json:"addedAt"` } diff --git a/pkg/study/types/study-message.go b/pkg/study/types/study-message.go index 9af55e02..fea15ebc 100644 --- a/pkg/study/types/study-message.go +++ b/pkg/study/types/study-message.go @@ -1,10 +1,10 @@ package types -import "go.mongodb.org/mongo-driver/bson/primitive" +import "go.mongodb.org/mongo-driver/v2/bson" type StudyMessage struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` - Type string `bson:"type,omitempty" json:"type,omitempty"` - Payload map[string]string `bson:"payload,omitempty" json:"payload,omitempty"` - ParticipantID string `bson:"participantID,omitempty" json:"participantID,omitempty"` + ID bson.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + Type string `bson:"type,omitempty" json:"type,omitempty"` + Payload map[string]string `bson:"payload,omitempty" json:"payload,omitempty"` + ParticipantID string `bson:"participantID,omitempty" json:"participantID,omitempty"` } diff --git a/pkg/study/types/studyRules.go b/pkg/study/types/study-rules.go similarity index 57% rename from pkg/study/types/studyRules.go rename to pkg/study/types/study-rules.go index bc7a8d42..2fb5a6ee 100644 --- a/pkg/study/types/studyRules.go +++ b/pkg/study/types/study-rules.go @@ -3,16 +3,16 @@ package types import ( "encoding/json" - "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/v2/bson" ) type StudyRules struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` - StudyKey string `bson:"studyKey" json:"studyKey"` - UploadedAt int64 `bson:"uploadedAt" json:"uploadedAt"` - UploadedBy string `bson:"uploadedBy" json:"uploadedBy"` - Rules []Expression `bson:"rules,omitempty" json:"rules"` - SerialisedRules string `bson:"serialisedRules,omitempty" json:"serialisedRules,omitempty"` + ID bson.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + StudyKey string `bson:"studyKey" json:"studyKey"` + UploadedAt int64 `bson:"uploadedAt" json:"uploadedAt"` + UploadedBy string `bson:"uploadedBy" json:"uploadedBy"` + Rules []Expression `bson:"rules,omitempty" json:"rules"` + SerialisedRules string `bson:"serialisedRules,omitempty" json:"serialisedRules,omitempty"` } func (studyRules *StudyRules) MarshalRules() error { diff --git a/pkg/study/types/study-variables.go b/pkg/study/types/study-variables.go index e307266d..d997c99d 100644 --- a/pkg/study/types/study-variables.go +++ b/pkg/study/types/study-variables.go @@ -10,7 +10,7 @@ import ( "strings" "time" - "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/v2/bson" ) type StudyVariablesType string @@ -24,7 +24,7 @@ const ( ) type StudyVariables struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + ID bson.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` CreatedAt time.Time `bson:"createdAt" json:"createdAt"` ConfigUpdatedAt time.Time `bson:"configUpdatedAt" json:"configUpdatedAt"` ValueUpdatedAt time.Time `bson:"valueUpdatedAt" json:"valueUpdatedAt"` @@ -48,7 +48,7 @@ type StudyVariables struct { func (sv *StudyVariables) UnmarshalJSON(data []byte) error { // Define a wire struct that treats Value as raw JSON. type studyVariablesWire struct { - ID primitive.ObjectID `json:"id,omitempty"` + ID bson.ObjectID `json:"id,omitempty"` CreatedAt time.Time `json:"createdAt"` ConfigUpdatedAt time.Time `json:"configUpdatedAt"` ValueUpdatedAt time.Time `json:"valueUpdatedAt"` diff --git a/pkg/study/types/study.go b/pkg/study/types/study.go index 45540242..b652e84c 100644 --- a/pkg/study/types/study.go +++ b/pkg/study/types/study.go @@ -1,6 +1,6 @@ package types -import "go.mongodb.org/mongo-driver/bson/primitive" +import "go.mongodb.org/mongo-driver/v2/bson" const ( STUDY_STATUS_ACTIVE = "active" @@ -12,7 +12,7 @@ const ( ) type Study struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + ID bson.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` Key string `bson:"key" json:"key"` SecretKey string `bson:"secretKey" json:"secretKey"` Status string `bson:"status" json:"status"` diff --git a/pkg/study/types/survey-item.go b/pkg/study/types/survey-item.go index e9c82f18..7eea4dd0 100644 --- a/pkg/study/types/survey-item.go +++ b/pkg/study/types/survey-item.go @@ -1,6 +1,6 @@ package types -import "go.mongodb.org/mongo-driver/bson/primitive" +import "go.mongodb.org/mongo-driver/v2/bson" const ( SURVEY_ITEM_TYPE_PAGE_BREAK = "pageBreak" @@ -8,11 +8,11 @@ const ( ) type SurveyItem struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` - Key string `bson:"key" json:"key"` - Follows []string `bson:"follows,omitempty" json:"follows,omitempty"` - Condition *Expression `bson:"condition,omitempty" json:"condition,omitempty"` - Priority float32 `bson:"priority,omitempty" json:"priority,omitempty"` + ID bson.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + Key string `bson:"key" json:"key"` + Follows []string `bson:"follows,omitempty" json:"follows,omitempty"` + Condition *Expression `bson:"condition,omitempty" json:"condition,omitempty"` + Priority float32 `bson:"priority,omitempty" json:"priority,omitempty"` Metadata map[string]string `bson:"metadata,omitempty" json:"metadata,omitempty"` diff --git a/pkg/study/types/surveyResponse.go b/pkg/study/types/survey-response.go similarity index 93% rename from pkg/study/types/surveyResponse.go rename to pkg/study/types/survey-response.go index af8e26a1..f041f361 100644 --- a/pkg/study/types/surveyResponse.go +++ b/pkg/study/types/survey-response.go @@ -1,9 +1,9 @@ package types -import "go.mongodb.org/mongo-driver/bson/primitive" +import "go.mongodb.org/mongo-driver/v2/bson" type SurveyResponse struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + ID bson.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` Key string `bson:"key" json:"key"` ParticipantID string `bson:"participantID" json:"participantId"` VersionID string `bson:"versionID" json:"versionId"` diff --git a/pkg/study/types/survey.go b/pkg/study/types/survey.go index 53042e4d..11e5356c 100644 --- a/pkg/study/types/survey.go +++ b/pkg/study/types/survey.go @@ -1,6 +1,6 @@ package types -import "go.mongodb.org/mongo-driver/bson/primitive" +import "go.mongodb.org/mongo-driver/v2/bson" const ( SURVEY_AVAILABLE_FOR_PUBLIC = "public" @@ -10,14 +10,14 @@ const ( ) type Survey struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` - SurveyKey string `bson:"surveyKey,omitempty" json:"surveyKey,omitempty"` - Props SurveyProps `bson:"props,omitempty" json:"props,omitempty"` - PrefillRules []Expression `bson:"prefillRules,omitempty" json:"prefillRules,omitempty"` - ContextRules *SurveyContextDef `bson:"contextRules,omitempty" json:"contextRules,omitempty"` - MaxItemsPerPage *MaxItemsPerPage `bson:"maxItemsPerPage,omitempty" json:"maxItemsPerPage,omitempty"` - AvailableFor string `bson:"availableFor,omitempty" json:"availableFor,omitempty"` - RequireLoginBeforeSubmission bool `bson:"requireLoginBeforeSubmission,omitempty" json:"requireLoginBeforeSubmission,omitempty"` + ID bson.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + SurveyKey string `bson:"surveyKey,omitempty" json:"surveyKey,omitempty"` + Props SurveyProps `bson:"props,omitempty" json:"props,omitempty"` + PrefillRules []Expression `bson:"prefillRules,omitempty" json:"prefillRules,omitempty"` + ContextRules *SurveyContextDef `bson:"contextRules,omitempty" json:"contextRules,omitempty"` + MaxItemsPerPage *MaxItemsPerPage `bson:"maxItemsPerPage,omitempty" json:"maxItemsPerPage,omitempty"` + AvailableFor string `bson:"availableFor,omitempty" json:"availableFor,omitempty"` + RequireLoginBeforeSubmission bool `bson:"requireLoginBeforeSubmission,omitempty" json:"requireLoginBeforeSubmission,omitempty"` Published int64 `bson:"published,omitempty" json:"published,omitempty"` Unpublished int64 `bson:"unpublished,omitempty" json:"unpublished,omitempty"` diff --git a/pkg/study/types/task.go b/pkg/study/types/task.go index 66185972..4e9515e9 100644 --- a/pkg/study/types/task.go +++ b/pkg/study/types/task.go @@ -3,7 +3,7 @@ package types import ( "time" - "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/v2/bson" ) const ( @@ -15,12 +15,12 @@ const ( ) type Task struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` - CreatedAt time.Time `bson:"createdAt" json:"createdAt"` - CreatedBy string `bson:"createdBy" json:"createdBy"` - UpdatedAt time.Time `bson:"updatedAt" json:"updatedAt"` - Status string `bson:"status" json:"status"` - TargetCount int `bson:"targetCount" json:"targetCount"` + ID bson.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + CreatedAt time.Time `bson:"createdAt" json:"createdAt"` + CreatedBy string `bson:"createdBy" json:"createdBy"` + UpdatedAt time.Time `bson:"updatedAt" json:"updatedAt"` + Status string `bson:"status" json:"status"` + TargetCount int `bson:"targetCount" json:"targetCount"` ProcessedCount int `bson:"processedCount" json:"processedCount"` ResultFile string `bson:"resultFile" json:"resultFile"` FileType string `bson:"fileType" json:"fileType"` diff --git a/pkg/study/utils/participantID_test.go b/pkg/study/utils/participantID_test.go index 5a1d565d..a6006f12 100644 --- a/pkg/study/utils/participantID_test.go +++ b/pkg/study/utils/participantID_test.go @@ -5,7 +5,7 @@ import ( "encoding/hex" "testing" - "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/v2/bson" ) func createGlobalKey() string { @@ -21,8 +21,8 @@ func testProfileIDtoParticipantMethod(t *testing.T, method string, studySecret s globalKey := createGlobalKey() - testProfileID := primitive.NewObjectID().Hex() - testProfileID2 := primitive.NewObjectID().Hex() + testProfileID := bson.NewObjectID().Hex() + testProfileID2 := bson.NewObjectID().Hex() t.Run("same user same keys", func(t *testing.T) { pId, err := ProfileIDtoParticipantID(testProfileID, globalKey, studySecret, method) @@ -134,7 +134,7 @@ func benchmarkMappingParticipantID(b *testing.B, method string) { studySecret := "this!study.-a.sd" globalKey := createGlobalKey() for n := 0; n < b.N; n++ { - testProfileID := primitive.NewObjectID().Hex() + testProfileID := bson.NewObjectID().Hex() _, err := ProfileIDtoParticipantID(testProfileID, globalKey, studySecret, method) if err != nil { b.Errorf("unexpected error: %s", err.Error()) diff --git a/pkg/user-management/types/contact-info.go b/pkg/user-management/types/contact-info.go index 8efc7268..db1a8916 100644 --- a/pkg/user-management/types/contact-info.go +++ b/pkg/user-management/types/contact-info.go @@ -1,12 +1,12 @@ package types -import "go.mongodb.org/mongo-driver/bson/primitive" +import "go.mongodb.org/mongo-driver/v2/bson" type ContactInfo struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id"` - Type ContactInfoType `bson:"type" json:"type"` - ConfirmedAt int64 `bson:"confirmedAt" json:"confirmedAt"` - ConfirmationLinkSentAt int64 `bson:"confirmationLinkSentAt" json:"confirmationLinkSentAt"` - Email string `bson:"email,omitempty" json:"email,omitempty"` - Phone string `bson:"phone,omitempty" json:"phone,omitempty"` + ID bson.ObjectID `bson:"_id,omitempty" json:"id"` + Type ContactInfoType `bson:"type" json:"type"` + ConfirmedAt int64 `bson:"confirmedAt" json:"confirmedAt"` + ConfirmationLinkSentAt int64 `bson:"confirmationLinkSentAt" json:"confirmationLinkSentAt"` + Email string `bson:"email,omitempty" json:"email,omitempty"` + Phone string `bson:"phone,omitempty" json:"phone,omitempty"` } diff --git a/pkg/user-management/types/profile.go b/pkg/user-management/types/profile.go index 51fc8300..be3cd18b 100644 --- a/pkg/user-management/types/profile.go +++ b/pkg/user-management/types/profile.go @@ -1,12 +1,12 @@ package types -import "go.mongodb.org/mongo-driver/bson/primitive" +import "go.mongodb.org/mongo-driver/v2/bson" type Profile struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id"` - Alias string `bson:"alias" json:"alias"` - ConsentConfirmedAt int64 `bson:"consentConfirmedAt" json:"consentConfirmedAt"` - CreatedAt int64 `bson:"createdAt" json:"createdAt"` - AvatarID string `bson:"avatarID" json:"avatarID"` - MainProfile bool `bson:"mainProfile" json:"mainProfile"` + ID bson.ObjectID `bson:"_id,omitempty" json:"id"` + Alias string `bson:"alias" json:"alias"` + ConsentConfirmedAt int64 `bson:"consentConfirmedAt" json:"consentConfirmedAt"` + CreatedAt int64 `bson:"createdAt" json:"createdAt"` + AvatarID string `bson:"avatarID" json:"avatarID"` + MainProfile bool `bson:"mainProfile" json:"mainProfile"` } diff --git a/pkg/user-management/types/temptoken.go b/pkg/user-management/types/temptoken.go index 479acddd..4ca46b20 100644 --- a/pkg/user-management/types/temptoken.go +++ b/pkg/user-management/types/temptoken.go @@ -3,7 +3,7 @@ package types import ( "time" - "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/v2/bson" ) const ( @@ -17,11 +17,11 @@ const ( ) type TempToken struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"token_id,omitempty"` - Token string `bson:"token" json:"token"` - Expiration time.Time `bson:"expiration" json:"expiration"` - Purpose string `bson:"purpose" json:"purpose"` - UserID string `bson:"userID" json:"userID"` - Info map[string]string `bson:"info" json:"info"` - InstanceID string `bson:"instanceID" json:"instanceID"` + ID bson.ObjectID `bson:"_id,omitempty" json:"token_id,omitempty"` + Token string `bson:"token" json:"token"` + Expiration time.Time `bson:"expiration" json:"expiration"` + Purpose string `bson:"purpose" json:"purpose"` + UserID string `bson:"userID" json:"userID"` + Info map[string]string `bson:"info" json:"info"` + InstanceID string `bson:"instanceID" json:"instanceID"` } diff --git a/pkg/user-management/types/user-attributes.go b/pkg/user-management/types/user-attributes.go index d38c219e..3b45185d 100644 --- a/pkg/user-management/types/user-attributes.go +++ b/pkg/user-management/types/user-attributes.go @@ -3,13 +3,13 @@ package types import ( "time" - "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/v2/bson" ) type UserAttributes struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id"` - UserID primitive.ObjectID `bson:"userId" json:"userId"` - Type string `bson:"type" json:"type"` - Attributes map[string]any `bson:"attributes" json:"attributes"` - CreatedAt time.Time `bson:"createdAt" json:"createdAt"` + ID bson.ObjectID `bson:"_id,omitempty" json:"id"` + UserID bson.ObjectID `bson:"userId" json:"userId"` + Type string `bson:"type" json:"type"` + Attributes map[string]any `bson:"attributes" json:"attributes"` + CreatedAt time.Time `bson:"createdAt" json:"createdAt"` } diff --git a/pkg/user-management/types/user.go b/pkg/user-management/types/user.go index 925890f3..41e54ffb 100644 --- a/pkg/user-management/types/user.go +++ b/pkg/user-management/types/user.go @@ -4,7 +4,7 @@ import ( "errors" "time" - "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/v2/bson" ) const ACCOUNT_TYPE_EMAIL = "email" @@ -17,7 +17,7 @@ const ( ) type User struct { - ID primitive.ObjectID `bson:"_id,omitempty" json:"id"` + ID bson.ObjectID `bson:"_id,omitempty" json:"id"` Account Account `bson:"account" json:"account"` Timestamps Timestamps `bson:"timestamps" json:"timestamps"` @@ -29,7 +29,7 @@ type User struct { // Add a new email address func (u *User) AddNewEmail(addr string, confirmed bool) { contactInfo := ContactInfo{ - ID: primitive.NewObjectID(), + ID: bson.NewObjectID(), Type: CONTACT_INFO_TYPE_EMAIL, ConfirmedAt: 0, Email: addr, @@ -71,7 +71,7 @@ func (u *User) SetPhoneNumber(phone string) { newContactInfos = append(newContactInfos, ci) } contactInfo := ContactInfo{ - ID: primitive.NewObjectID(), + ID: bson.NewObjectID(), Type: CONTACT_INFO_TYPE_PHONE, ConfirmedAt: 0, Phone: phone, @@ -181,7 +181,7 @@ func (u *User) ReplaceContactInfoInContactPreferences(oldId string, newId string // AddProfile generates unique ID and adds profile to the user's array func (u *User) AddProfile(p *Profile) { - p.ID = primitive.NewObjectID() + p.ID = bson.NewObjectID() p.CreatedAt = time.Now().Unix() u.Profiles = append(u.Profiles, *p) } diff --git a/pkg/user-management/utils/new-user-init.go b/pkg/user-management/utils/new-user-init.go index 64a47aad..b10847db 100644 --- a/pkg/user-management/utils/new-user-init.go +++ b/pkg/user-management/utils/new-user-init.go @@ -4,7 +4,7 @@ import ( "time" userTypes "github.com/case-framework/case-backend/pkg/user-management/types" - "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/v2/bson" ) func InitNewEmailUser( @@ -22,7 +22,7 @@ func InitNewEmailUser( }, Profiles: []userTypes.Profile{ { - ID: primitive.NewObjectID(), + ID: bson.NewObjectID(), Alias: BlurEmailAddress(email), MainProfile: true, AvatarID: "default", diff --git a/pkg/user-management/utils/profiles_test.go b/pkg/user-management/utils/profiles_test.go index 08671f7f..0430f4c4 100644 --- a/pkg/user-management/utils/profiles_test.go +++ b/pkg/user-management/utils/profiles_test.go @@ -4,14 +4,14 @@ import ( "testing" userTypes "github.com/case-framework/case-backend/pkg/user-management/types" - "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/v2/bson" ) func TestGetMainAndOtherProfiles(t *testing.T) { t.Run("with a single profile with main flag", func(t *testing.T) { user := userTypes.User{ Profiles: []userTypes.Profile{ - {ID: primitive.NewObjectID(), MainProfile: true}, + {ID: bson.NewObjectID(), MainProfile: true}, }, } main, others := GetMainAndOtherProfiles(user) @@ -26,7 +26,7 @@ func TestGetMainAndOtherProfiles(t *testing.T) { t.Run("with a single profile without main flag", func(t *testing.T) { user := userTypes.User{ Profiles: []userTypes.Profile{ - {ID: primitive.NewObjectID()}, + {ID: bson.NewObjectID()}, }, } main, others := GetMainAndOtherProfiles(user) @@ -41,10 +41,10 @@ func TestGetMainAndOtherProfiles(t *testing.T) { t.Run("with mulitple profiles without main flag", func(t *testing.T) { user := userTypes.User{ Profiles: []userTypes.Profile{ - {ID: primitive.NewObjectID(), MainProfile: false}, - {ID: primitive.NewObjectID(), MainProfile: false}, - {ID: primitive.NewObjectID(), MainProfile: false}, - {ID: primitive.NewObjectID(), MainProfile: false}, + {ID: bson.NewObjectID(), MainProfile: false}, + {ID: bson.NewObjectID(), MainProfile: false}, + {ID: bson.NewObjectID(), MainProfile: false}, + {ID: bson.NewObjectID(), MainProfile: false}, }, } main, others := GetMainAndOtherProfiles(user) @@ -59,9 +59,9 @@ func TestGetMainAndOtherProfiles(t *testing.T) { t.Run("with mulitple profiles one main flag", func(t *testing.T) { user := userTypes.User{ Profiles: []userTypes.Profile{ - {ID: primitive.NewObjectID(), MainProfile: false}, - {ID: primitive.NewObjectID(), MainProfile: true}, - {ID: primitive.NewObjectID(), MainProfile: false}, + {ID: bson.NewObjectID(), MainProfile: false}, + {ID: bson.NewObjectID(), MainProfile: true}, + {ID: bson.NewObjectID(), MainProfile: false}, }, } main, others := GetMainAndOtherProfiles(user) @@ -76,9 +76,9 @@ func TestGetMainAndOtherProfiles(t *testing.T) { t.Run("with mulitple profiles multiply main flag", func(t *testing.T) { user := userTypes.User{ Profiles: []userTypes.Profile{ - {ID: primitive.NewObjectID(), MainProfile: false}, - {ID: primitive.NewObjectID(), MainProfile: true}, - {ID: primitive.NewObjectID(), MainProfile: true}, + {ID: bson.NewObjectID(), MainProfile: false}, + {ID: bson.NewObjectID(), MainProfile: true}, + {ID: bson.NewObjectID(), MainProfile: true}, }, } main, others := GetMainAndOtherProfiles(user) diff --git a/services/management-api/apihandlers/study-management.go b/services/management-api/apihandlers/study-management.go index cbf53749..02cb9b0d 100644 --- a/services/management-api/apihandlers/study-management.go +++ b/services/management-api/apihandlers/study-management.go @@ -25,8 +25,7 @@ import ( studyutils "github.com/case-framework/case-backend/pkg/study/utils" "github.com/case-framework/case-backend/pkg/utils" "github.com/gin-gonic/gin" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/v2/bson" studyDB "github.com/case-framework/case-backend/pkg/db/study" studyService "github.com/case-framework/case-backend/pkg/study" @@ -1238,7 +1237,7 @@ func (h *HttpEndpoints) exportStudyConfig(c *gin.Context) { configWriter.WriteKeyValue("exportedAt", time.Now()) if includeConfig { - study.ID = primitive.NilObjectID + study.ID = bson.NilObjectID study.NextTimerEvent = 0 study.Stats = studyTypes.StudyStats{} configWriter.WriteString(",") @@ -1249,7 +1248,7 @@ func (h *HttpEndpoints) exportStudyConfig(c *gin.Context) { rules, err := h.studyDBConn.GetCurrentStudyRules(token.InstanceID, studyKey) if err == nil { - rules.ID = primitive.NilObjectID + rules.ID = bson.NilObjectID rules.UploadedBy = "" configWriter.WriteString(",") configWriter.WriteKeyValue("rules", rules) @@ -1268,7 +1267,7 @@ func (h *HttpEndpoints) exportStudyConfig(c *gin.Context) { slog.Error("failed to get latest survey", slog.String("error", err.Error())) continue } - survey.ID = primitive.NilObjectID + survey.ID = bson.NilObjectID surveys = append(surveys, survey) } diff --git a/services/participant-api/apihandlers/authentication.go b/services/participant-api/apihandlers/authentication.go index 02d450b8..dff7ee83 100644 --- a/services/participant-api/apihandlers/authentication.go +++ b/services/participant-api/apihandlers/authentication.go @@ -17,8 +17,7 @@ import ( "github.com/case-framework/case-backend/pkg/user-management/pwhash" umUtils "github.com/case-framework/case-backend/pkg/user-management/utils" "github.com/gin-gonic/gin" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/v2/bson" userTypes "github.com/case-framework/case-backend/pkg/user-management/types" ) @@ -310,7 +309,7 @@ func (h *HttpEndpoints) signupWithEmail(c *gin.Context) { return } - newUser.ID, _ = primitive.ObjectIDFromHex(id) + newUser.ID, _ = bson.ObjectIDFromHex(id) // contact verification in go routine go h.prepAndSendEmailVerification( diff --git a/services/participant-api/apihandlers/password-reset.go b/services/participant-api/apihandlers/password-reset.go index 2fd9b383..ffbc147f 100644 --- a/services/participant-api/apihandlers/password-reset.go +++ b/services/participant-api/apihandlers/password-reset.go @@ -10,7 +10,7 @@ import ( userTypes "github.com/case-framework/case-backend/pkg/user-management/types" umUtils "github.com/case-framework/case-backend/pkg/user-management/utils" "github.com/gin-gonic/gin" - "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/v2/bson" emailTypes "github.com/case-framework/case-backend/pkg/messaging/types" ) diff --git a/services/participant-api/apihandlers/study-service.go b/services/participant-api/apihandlers/study-service.go index 8f35645e..3a308f0b 100644 --- a/services/participant-api/apihandlers/study-service.go +++ b/services/participant-api/apihandlers/study-service.go @@ -15,7 +15,7 @@ import ( jwthandling "github.com/case-framework/case-backend/pkg/jwt-handling" "github.com/case-framework/case-backend/pkg/utils" "github.com/gin-gonic/gin" - "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/v2/bson" studyService "github.com/case-framework/case-backend/pkg/study" surveydefinition "github.com/case-framework/case-backend/pkg/study/exporter/survey-definition" diff --git a/services/participant-api/apihandlers/user-management.go b/services/participant-api/apihandlers/user-management.go index 2b9122da..97d0e27f 100644 --- a/services/participant-api/apihandlers/user-management.go +++ b/services/participant-api/apihandlers/user-management.go @@ -13,7 +13,7 @@ import ( emailTypes "github.com/case-framework/case-backend/pkg/messaging/types" studyTypes "github.com/case-framework/case-backend/pkg/study/types" "github.com/gin-gonic/gin" - "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/v2/bson" studyService "github.com/case-framework/case-backend/pkg/study" "github.com/case-framework/case-backend/pkg/user-management/pwhash" diff --git a/test/mongodb-driver-update.md b/test/mongodb-driver-update.md new file mode 100644 index 00000000..4cda35e9 --- /dev/null +++ b/test/mongodb-driver-update.md @@ -0,0 +1,412 @@ +# Update mongodb driver: v1 → v2 + +## Overview of Changes + +The following lists all changes in the upgrade from MongoDB Go Driver v1 to v2. The `bson/primitive` types were replaced globally throughout the codebase. This is followed by changes that were applied uniformly across all DB packages, and finally by changes specific to individual DB collections. + +### All files + +- **primitive package**: The bson/primitive package has been merged into the bson package —> changed any instance of primitive.ObjectID to bson.ObjectID. + +### All DB packages + +- `mongo.Connect()`: context.Context parameter has been removed. (The deployment connector doesn’t accept a context, meaning that the context passed to mongo.Connect() in previous versions didn't serve a purpose.) +- `context.WithTimeout()`: removed unused `context.WithTimeout()` call (including `defer cancel()`) before `mongo.Connect()` — the context was discarded with `_` and never passed to `mongo.Connect()`, which in v2 no longer accepts a context parameter anyway. +- `DropOne` and `DropAll`: simplified methods by removing the unused server response +- **Index Model**: The old `IndexOptionsBuilder` type was removed and `IndexModel.Options.Name` is no longer accessible as a field. Required steps: + - define static default index name constants/lists per collection + - reuse those names for both index creation and `DropOne` in `drop defaults` + - tested, see [Index migration test protocol](#index-migration) + +### Messaging + +#### email-templates + +- `SaveEmailTemplate`: use the options builder, and pass a pointer returned by options.FindOneAndReplace() instead of constructing FindOneAndReplaceOptions as a struct literal (tested, see [SaveEmailTemplate test protocol](#saveemailtemplate)) + +#### scheduled-emails + +- `SaveScheduledEmail`: use the options builder, and pass a pointer returned by options.FindOneAndReplace() instead of constructing FindOneAndReplaceOptions as a struct literal (tested, see [SaveScheduledEmail test protocol](#savescheduledemail-and-savesmstemplate)) + +#### sms-templates + +- `SaveSMSTemplate`: use the options builder, and pass a pointer returned by options.FindOneAndReplace() instead of constructing FindOneAndReplaceOptions as a struct literal (tested, see [SaveSMSTemplate test protocol](#savescheduledemail-and-savesmstemplate)) + +### Participant User + +#### user-attributes + +- `SetUserAttribute`: `UpdateOptions` has been changed to `UpdateOneOptions` to configure UpdateOne operation. (tested, see [SetUserAttribute test protocol](#setuserattribute)) + +#### users + +- `AddUser`: MongoDB Go Driver v2 no longer allows constructing or modifying option structs directly, so update options must now be created through the new builder API (options.UpdateOne().SetUpsert(true)) instead of setting fields on UpdateOptions manually. (tested, see [AddUser test protocol](#adduser)) +- `_updateUserInDB`: `FindOneAndReplaceOptions` can no longer be created or populated as a struct, so the v2 driver requires using the builder pattern (options.FindOneAndReplace().SetReturnDocument(options.After)) instead of setting option fields directly. (tested, see [_updateUserInDB test protocol](#_updateuserindb)) + +#### otps + +- `CreateOTP`: update the callback for mongo.WithSession to use a context.Context implementation, rather than the custom mongo.SessionContext (tested, see [CreateOTP test protocol](#createotp)) + +### Study + +#### participants + +- `SaveParticipantState`: `FindOneAndReplaceOptions` can no longer be created or populated as a struct, so the v2 driver requires using the builder pattern (options.FindOneAndReplace().SetUpsert(true).SetReturnDocument(options.After)) instead of setting option fields directly. (tested, see [SaveParticipantState test protocol](#saveparticipantstate)) + +#### confidential-responses + +- `ReplaceConfidentialResponse`: `ReplaceOptions` can no longer be created or populated as a struct, so the v2 driver requires using the builder pattern (options.Replace().SetUpsert(true)) instead of setting option fields directly. (tested, see [ReplaceConfidentialResponse test protocol](#replaceconfidentialresponse)) + +#### study-rules + +- `GetCurrentStudyRules`: `FindOneOptions` can no longer be created or populated as a struct, so the v2 driver requires using the builder pattern (options.FindOne().SetSort(sortByPublished)) instead of setting option fields directly. (tested, see [GetCurrentStudyRules test protocol](#getcurrentstudyrules)) + +#### reports + +- `GetUniqueReportKeysForStudy`: `Distinct()` no longer returns `([]interface{}, error)`; it returns a single result type on which you call `.Decode(&target)` directly into a `[]string`, eliminating the manual type-assertion loop. (tested, see [GetUniqueReportKeysForStudy test protocol](#getuniquereportkeysforstudy)) + +#### surveys + +- `GetSurveyKeysForStudy`: `Distinct()` no longer returns `([]interface{}, error)`; it returns a single result type on which you call `.Decode(&target)` directly into a `[]string`, eliminating the manual type-assertion loop. (tested, see [GetSurveyKeysForStudy test protocol](#getsurveykeysforstudy)) +- `GetCurrentSurveyVersion`: create FindOneOptions using the options.FindOne() builder and setters (for example, options.FindOne().SetSort(sortByPublishedDesc)) instead of instantiating &options.FindOneOptions{} and mutating its fields. (tested, see [GetCurrentSurveyVersion test protocol](#getcurrentsurveyversion)) +- `GetSurveyVersions`: create FindOptions using the options.Find() builder and its setters (for example, options.Find().SetProjection(...).SetSort(...)) instead of instantiating &options.FindOptions{} and mutating its fields. (tested, see [GetSurveyVersions test protocol](#getsurveyversions)) + +## Manual Test Protocol + +### Index Migration + +Date: 24.03.2026 + +Goal: + +- Preserve MongoDB driver v1 behavior for default index drop/recreate flows after migration to driver v2. +- Verify that custom manually added indexes are not affected by default-index drop. + +Executed commands: + +```bash +CONFIG_FILE_PATH=test/jobs/dbm-01-before.yaml go run ./jobs/db-migration/*.go +CONFIG_FILE_PATH=test/jobs/dbm-02-drop-defaults.yaml go run ./jobs/db-migration/*.go +CONFIG_FILE_PATH=test/jobs/dbm-03-create-defaults.yaml go run ./jobs/db-migration/*.go +``` + +Test steps: + +- Phase 1 (`dbm-01-before.yaml`): baseline index snapshot exported. +- Manual step: added at least one custom index directly in MongoDB. +- Phase 2 (`dbm-02-drop-defaults.yaml`): dropped default indexes. +- Phase 3 (`dbm-03-create-defaults.yaml`): recreated default indexes. + +Result summary: + +- Default indexes were removed in phase 2 and recreated in phase 3 as expected. +- Manually added custom index remained untouched by `drop defaults`. +- Unique index behavior verified: inserting a document with the same index field value as an existing document is rejected by MongoDB. +- TTL index behavior verified: documents are automatically deleted by MongoDB once the `expireAfterSeconds` threshold has passed. + +Conclusion: + +- The previous v1 behavior is preserved under v2: + - `drop defaults` removes only default indexes. + - custom manually added indexes remain untouched. + - `create defaults` restores the default indexes again. + - unique and TTL index properties are correctly applied after recreation. + +### SaveEmailTemplate + +Date: 25.03.2026 + +Scope: + +- Verify unchanged behavior for `SaveEmailTemplate` after switching to `options.FindOneAndReplace().SetUpsert(false).SetReturnDocument(options.After)`. +- Covered cases: create, update existing, and study-template flow. +- Not covered in this run: update with valid but non-existing `id` (requires direct API request outside UI). + +Test execution: + +1. Created new global email templates in UI and saved them. +2. Edited existing global email templates in UI and saved again. +3. Repeated create and update flow for study-scoped email templates. + +Expected and observed results: + +1. Create path (`id` empty): new template is inserted and returned with generated `id`. +2. Update path (`id` exists): existing template is replaced/updated and returned with same `id`. +3. Study-template behavior: same create/update behavior as global templates. +4. Unique index behavior: no duplicate email templates with identical `messageType` are created (default unique index is enforced). + +Conclusion: + +- No behavioral change observed in the covered `SaveEmailTemplate` flows. +- Current implementation remains consistent with previous driver-v1 behavior for UI-accessible paths. + +### SaveScheduledEmail and SaveSMSTemplate + +Date: 07.04.2026 + +Scope: + +- Verify unchanged behavior for scheduled-email and sms-template save flows after switching to options-builder usage for FindOneAndReplace options. + +Test execution: + +1. Created new scheduled emails in UI and saved them. +2. Updated existing scheduled emails in UI and saved the changes. +3. Created new SMS templates in UI and saved them. +4. Updated existing SMS templates in UI and saved the changes. + +Expected and observed results: + +1. Create path: new schedules are created successfully. +2. Update path: existing schedules are updated successfully. +3. Create/update path for SMS templates: works successfully as before. + +Conclusion: + +- No behavioral change observed in the tested `SaveScheduledEmail` and `SaveSMSTemplate` create/update flows. + +### GetSurveyVersions + +Date: 09.04.2026 + +Scope: + +- Verify unchanged behavior for `GetSurveyVersions` after switching to `options.Find()` builder with setters. + +Test execution: + +1. Opened survey version list in UI for a study/survey. +2. Verified API request used endpoint `GET /v1/studies/:studyKey/surveys/:surveyKey/versions`. + +Expected and observed results: + +1. Survey versions are returned and displayed as expected. +2. No behavioral change observed compared to previous behavior. + +Conclusion: + +- `GetSurveyVersions` behavior is unchanged for the tested UI/API flow. + +### GetCurrentSurveyVersion + +Date: 10.04.2026 + +Scope: + +- Verify unchanged behavior for `GetCurrentSurveyVersion` after switching to `options.FindOne()` builder with setters. + +Test execution: + +1. Exported study configuration as JSON via the UI (study configuration export). +2. `GetCurrentSurveyVersion` is called internally during this export to retrieve the current version of all surveys belonging to the study. + +Expected and observed results: + +1. The exported JSON file is identical to the file exported with the previous MongoDB driver version. +2. No behavioral change observed. + +Conclusion: + +- `GetCurrentSurveyVersion` behavior is unchanged after the driver migration. + +### GetCurrentStudyRules + +Date: 10.04.2026 + +Scope: + +- Verify unchanged behavior for `GetCurrentStudyRules` after switching to `options.FindOne()` builder with setters. + +Test execution: + +1. Exported study configuration as JSON via the UI (study configuration export). +2. `GetCurrentStudyRules` is called internally during this export to retrieve the current study rules belonging to the study. + +Expected and observed results: + +1. The exported JSON file is identical to the file exported with the previous MongoDB driver version. +2. No behavioral change observed. + +Conclusion: + +- `GetCurrentStudyRules` behavior is unchanged after the driver migration. + +### ReplaceConfidentialResponse + +Date: 13.04.2026 + +Scope: + +- Verify unchanged behavior for `ReplaceConfidentialResponse` after switching to `options.Replace().SetUpsert(true)` builder usage. + +Test execution: + +1. Submitted a survey with confidential responses for a participant for the first time (insert path). +2. Submitted the same survey again for the same participant (replace path), so the existing confidential response was replaced by the new one. + +Expected and observed results: + +1. First submission: confidential response was inserted as a new document in the database. +2. Subsequent submission: existing confidential response was replaced by the new response, no duplicate was created. + +Conclusion: + +- No behavioral change observed for the insert and replace paths of `ReplaceConfidentialResponse`. + +### SaveParticipantState + +Date: 13.04.2026 + +Scope: + +- Verify unchanged behavior for `SaveParticipantState` after switching to `options.FindOneAndReplace().SetUpsert(true).SetReturnDocument(options.After)` builder usage. + +Test execution: + +1. Created a new participant by enrolling in a study (insert path). +2. Changed the state of an existing participant (replace path), e.g. by submitting a survey that modifies participant flags or survey assignments. + +Expected and observed results: + +1. Insert path: new participant document was created successfully in the database. +2. Replace path: existing participant state was updated correctly, no duplicate was created. + +Conclusion: + +- No behavioral change observed for the insert and replace paths of `SaveParticipantState`. + +### AddUser + +Date: 14.04.2026 + +Scope: + +- Verify unchanged behavior for `AddUser` after switching to `options.UpdateOne().SetUpsert(true)` builder usage. + +Test execution: + +1. Created a new user with a fresh email address (insert path). +2. Attempted to create another new user with the same email address as an already existing user (duplicate path). + +Expected and observed results: + +1. Insert path: new user was created successfully in the database. +2. Duplicate path: error `"user already exists"` was returned correctly, no duplicate user was created in the database. + +Conclusion: + +- No behavioral change observed for the insert and duplicate paths of `AddUser`. + +### _updateUserInDB + +Date: 14.04.2026 + +Scope: + +- Verify unchanged behavior for `_updateUserInDB` (called via `ReplaceUser`) after switching to `options.FindOneAndReplace().SetReturnDocument(options.After)` builder usage. + +Test execution: + +1. Logged in as a participant user (triggers `ReplaceUser` → `_updateUserInDB` to update login timestamps). +2. Created a new profile for the logged-in user (triggers another `ReplaceUser` → `_updateUserInDB` to persist the updated user document). + +Expected and observed results: + +1. Login: user document was updated correctly in the database (e.g. `lastLogin` timestamp). +2. New profile: profile was saved correctly and the updated user document was returned, no duplicate was created. + +Conclusion: + +- No behavioral change observed for the replace path of `_updateUserInDB`. + +### SetUserAttribute + +Date: 15.04.2026 + +Scope: + +- Verify unchanged behavior for `SetUserAttribute` after switching to `options.UpdateOne().SetUpsert(true)` builder usage. + +Test execution: + +1. Registered a new user at flusurvey (insert path: user attribute document created for the first time). + +Expected and observed results: + +1. Insert path: user attribute was created successfully as a new document in the database. + +Conclusion: + +- No behavioral change observed for the insert path of `SetUserAttribute`. + +### GetUniqueReportKeysForStudy + +Date: 15.04.2026 + +Scope: + +- Verify unchanged behavior for `GetUniqueReportKeysForStudy` after switching to the new `Distinct()` API that returns a result type decoded directly into `[]string`. + +Test execution: + +1. Opened the reports page in the CASE management UI for a study with existing reports. +2. Checked the dropdown that lists all available report keys. +3. Applied a `participantID` filter and verified the dropdown updated accordingly. +4. Applied `from` and `until` date filters and verified the dropdown updated accordingly. + +Expected and observed results: + +1. All available and filtered report keys were listed correctly in the dropdown. +2. No behavioral change observed compared to previous behavior. + +Conclusion: + +- No behavioral change observed for `GetUniqueReportKeysForStudy` after the driver migration. + +### GetSurveyKeysForStudy + +Date: 15.04.2026 + +Scope: + +- Verify unchanged behavior for `GetSurveyKeysForStudy` after switching to the new `Distinct()` API that returns a result type decoded directly into `[]string`. + +Test execution: + +1. Opened the CASE management UI and checked the survey dropdown used to manually assign a survey to a participant – verified that all available survey keys were listed correctly. +2. Exported study configuration as JSON via the UI and verified that the survey keys are correctly included in the export. + +Expected and observed results: + +1. All available survey keys were listed correctly in the dropdown. +2. The exported study configuration JSON contained the correct survey keys, identical to the export with the previous MongoDB driver version. + +Conclusion: + +- No behavioral change observed for `GetSurveyKeysForStudy` after the driver migration. + +### CreateOTP + +Date: 21.04.2026 + +Scope: + +- Verify unchanged behavior for `CreateOTP` after switching the `mongo.WithSession` callback from `mongo.SessionContext` to `context.Context`. + +Test execution: + +1. Triggered an OTP request via the login flow (normal case: OTP created and email received). +2. Verified the OTP by entering the received code successfully. +3. Triggered OTP requests repeatedly until the `maxOTPCount` limit was reached — subsequent requests correctly returned an error. +4. Waited for OTP expiry (TTL of 15 minutes) and verified the OTP document was automatically deleted from the database. + +Expected and observed results: + +1. Normal case: OTP was created and email was sent successfully. +2. Verification: OTP verification succeeded with the correct code. +3. Limit case: Error returned correctly after exceeding `maxOTPCount`, no additional OTP was created. +4. TTL: OTP document was deleted automatically after expiry. + +Conclusion: + +- No behavioral change observed for `CreateOTP` after the driver migration.