package invitationdb import ( "context" "fmt" "github.com/tech/sendico/pkg/db/repository" "github.com/tech/sendico/pkg/merrors" "github.com/tech/sendico/pkg/model" "github.com/tech/sendico/pkg/mservice" "github.com/tech/sendico/pkg/mutil/mzap" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.uber.org/zap" ) func (db *InvitationDB) GetPublic(ctx context.Context, invitationRef primitive.ObjectID) (*model.PublicInvitation, error) { roleField := repository.Field("role") orgField := repository.Field("organization") accField := repository.Field("account") empField := repository.Field("employee") regField := repository.Field("registrationAcc") descEmailField := repository.Field("description").Dot("email") pipeline := repository.Pipeline(). // 0) Filter to exactly the invitation(s) you want Match(repository.IDFilter(invitationRef).And(repository.Filter("status", model.InvitationCreated))). // 1) Lookup the role document Lookup( mservice.Roles, repository.Field("roleRef"), repository.IDField(), roleField, ). Unwind(repository.Ref(roleField)). // 2) Lookup the organization document Lookup( mservice.Organizations, repository.Field("organizationRef"), repository.IDField(), orgField, ). Unwind(repository.Ref(orgField)). // 3) Lookup the account document Lookup( mservice.Accounts, repository.Field("inviterRef"), repository.IDField(), accField, ). Unwind(repository.Ref(accField)). /* 4) do we already have an account whose login == invitation.description ? */ Lookup( mservice.Accounts, descEmailField, // local field (invitation.description.email) repository.Field("login"), // foreign field (account.login) regField, // array: 0-length or ≥1 ). // 5) Projection Project( repository.SimpleAlias( empField.Dot("description"), repository.Ref(accField), ), repository.SimpleAlias( empField.Dot("avatarUrl"), repository.Ref(accField.Dot("avatarUrl")), ), repository.SimpleAlias( orgField.Dot("description"), repository.Ref(orgField), ), repository.SimpleAlias( orgField.Dot("logoUrl"), repository.Ref(orgField.Dot("logoUrl")), ), repository.SimpleAlias( roleField, repository.Ref(roleField), ), repository.SimpleAlias( repository.Field("invitation"), // ← left-hand side repository.Ref(repository.Field("description")), // ← right-hand side (“$description”) ), repository.SimpleAlias( repository.Field("storable"), // ← left-hand side repository.RootRef(), // ← right-hand side (“$description”) ), repository.ProjectionExpr( repository.Field("registrationRequired"), repository.Eq( repository.Size(repository.Value(repository.Ref(regField).Build())), repository.Literal(0), ), ), ) var res model.PublicInvitation haveResult := false decoder := func(cur *mongo.Cursor) error { if haveResult { // should never get here db.DBImp.Logger.Warn("Unexpected extra invitation", mzap.ObjRef("invitation_ref", invitationRef)) return merrors.Internal("Unexpected extra invitation found by reference") } if e := cur.Decode(&res); e != nil { db.DBImp.Logger.Warn("Failed to decode entity", zap.Error(e), zap.Any("data", cur.Current.String())) return e } haveResult = true return nil } if err := db.DBImp.Repository.Aggregate(ctx, pipeline, decoder); err != nil { db.DBImp.Logger.Warn("Failed to execute aggregation pipeline", zap.Error(err), mzap.ObjRef("invitation_ref", invitationRef)) return nil, err } if !haveResult { db.DBImp.Logger.Warn("No results fetched", mzap.ObjRef("invitation_ref", invitationRef)) return nil, merrors.NoData(fmt.Sprintf("Invitation %s not found", invitationRef.Hex())) } return &res, nil }