func getAccountByNick(nick string) bool { if _, err := existingAccountByNick.Get(nick); err == nil { return true } if _, err := deletedAccountByNick.Get(nick); err == nil { return false } acc, err := helper.GetAccount(nick) if err == mgo.ErrNotFound { deletedAccountByNick.Set(nick, struct{}{}) return false } // treat them as existing on random errors if err != nil { fmt.Printf("err while getting acc by nick %q, %s\n", nick, err.Error()) return true } id := acc.Id.Hex() if acc.Type == "deleted" { deletedAccountByID.Set(id, struct{}{}) deletedAccountByNick.Set(acc.Profile.Nickname, struct{}{}) return false } existingAccountByID.Set(id, struct{}{}) existingAccountByNick.Set(acc.Profile.Nickname, id) return true }
func (cmd *GroupStack) details(username string) (*modelhelper.StackDetails, error) { user, err := modelhelper.GetUser(username) if err != nil { return nil, fmt.Errorf("unable to find a user %q: %s", username, err) } group, err := modelhelper.GetGroup(cmd.groupSlug) if err != nil { return nil, fmt.Errorf("unable to find a group %q: %s", cmd.groupSlug, err) } machine, err := modelhelper.GetMachineBySlug(user.ObjectId, cmd.machineSlug) if err != nil { return nil, fmt.Errorf("unable to find a machine slug=%q, userID=%q: %s", cmd.machineSlug, user.ObjectId.Hex(), err) } account, err := modelhelper.GetAccount(username) if err != nil { return nil, fmt.Errorf("unable to find an account for %q: %s", username, err) } sd := &modelhelper.StackDetails{ UserID: user.ObjectId, AccountID: account.Id, GroupID: group.Id, UserName: user.Name, GroupSlug: group.Slug, MachineID: machine.ObjectId, BaseID: bson.ObjectIdHex(cmd.baseID), } return sd, nil }
// Migrate implements the Database interface. func (db *mongoDatabase) Migrate(opts *MigrateOptions) error { stack := models.NewStackTemplate(opts.Provider, opts.Identifier) stack.Machines = make([]bson.M, len(opts.Machines)) for i := range stack.Machines { stack.Machines[i] = bson.M(machineBuilder.Build(opts.Machines[i])) } account, err := modelhelper.GetAccount(opts.Username) if err != nil { return fmt.Errorf("account lookup failed for %q: %s", opts.Username, err) } sum := sha1.Sum([]byte(opts.Template)) stack.Title = opts.StackName stack.OriginID = account.Id stack.Template.Details = bson.M{ "lastUpdaterId": account.Id, } stack.Group = opts.GroupName stack.Template.Content = opts.Template stack.Template.Sum = hex.EncodeToString(sum[:]) if s, err := yamlReencode(opts.Template); err == nil { stack.Template.RawContent = s } if err := modelhelper.CreateStackTemplate(stack); err != nil { return fmt.Errorf("failed to create stack template: %s", err) } change := bson.M{ "$set": bson.M{ "meta.migration.modifiedAt": time.Now(), "meta.migration.status": MigrationMigrated, "meta.migration.stackTemplateId": stack.Id, }, } for _, id := range opts.MachineIDs { if e := modelhelper.UpdateMachine(id, change); e != nil { err = multierror.Append(err, fmt.Errorf("failed to update migration details for %q: %s", id.Hex(), err)) } } // Failure updating jMachine migration metadata is not critical, // just log the error and continue. if err != nil { opts.Log.Error("%s", err) } return nil }
// GetAccount gets the account which sent the message by email of user func GetAccount(mailAddress string) (*mongomodels.Account, error) { user, err := modelhelper.FetchUserByEmail(mailAddress) if err != nil { return nil, ErrEmailIsNotFetched } // This GetAccount account, err := modelhelper.GetAccount(user.Name) if err != nil { return nil, ErrAccountIsNotFound } return account, nil }
// makeSureAccount checks if incoming account is in postgres, if not creates it // lazily and sets socialapi id of it in mongo func makeSureAccount(groupName string, username string) (*models.Account, error) { // try to fetch account from postgres acc := models.NewAccount() err := acc.ByNick(username) if err == nil { return acc, nil } if err != bongo.RecordNotFound { return acc, err } // if account is not in postgres, try to create it // we need account first macc, err := modelhelper.GetAccount(username) if err != nil { return nil, err } acc = models.NewAccount() // account is nil, set it acc.OldId = macc.Id.Hex() acc.Nick = username if err := acc.Create(); err != nil { return nil, err } // set it to cache, in case we may need it if err := models.Cache.Account.SetToCache(acc); err != nil { return nil, err } // we just created the account in postgres, so update mongo with // socialApiId s := modelhelper.Selector{ "profile.nickname": username, } o := modelhelper.Selector{"$set": modelhelper.Selector{ "socialApiId": strconv.FormatInt(acc.Id, 10), }} if err := modelhelper.UpdateAccount(s, o); err != nil { return nil, err } return acc, nil }
func (f *Controller) handleAccount(data *models.Account, cleanupGuest bool, tagMap map[string]interface{}) error { // do not send guests to algolia if strings.HasPrefix(data.Nick, "guest-") { if cleanupGuest { return f.delete(IndexAccounts, data.OldId) } return nil } user, err := modelhelper.GetUser(data.Nick) if err != nil && err != mgo.ErrNotFound { return err } if err == mgo.ErrNotFound { f.log.Error("user %+v is not found in mongodb", data) return nil } mongoaccount, err := modelhelper.GetAccount(data.Nick) if err != nil && err != mgo.ErrNotFound { return err } if err == mgo.ErrNotFound { f.log.Error("account %+v is not found in mongodb", data) return nil } return f.partialUpdate(IndexAccounts, map[string]interface{}{ "objectID": data.OldId, "nick": data.Nick, "email": user.Email, "firstName": mongoaccount.Profile.FirstName, "lastName": mongoaccount.Profile.LastName, "_tags": tagMap, }) }
// TODO refactor this function to use postgres func (p *ChannelRequest) obtainParticipantIds() ([]int64, error) { participantIds := make([]int64, len(p.Recipients)) for i, participantName := range p.Recipients { // get account from mongo account, err := modelhelper.GetAccount(participantName) if err != nil { return nil, err } a := NewAccount() socialApiId, _ := account.GetSocialApiId() a.Id = socialApiId a.OldId = account.Id.Hex() a.Nick = account.Profile.Nickname // fetch or create social api id if a.Id == 0 { if err := a.FetchOrCreate(); err != nil { return nil, err } } participantIds[i] = a.Id } // append creator to the recipients participantIds = prependCreatorId(participantIds, p.AccountId) // author and atleast one recipient should be in the // recipient list if len(participantIds) < 1 { // user can send private message to themself return nil, ErrRecipientsNotDefined } return participantIds, nil }
func CreateAccountInBothDbsWithNick(nick string) (*Account, error) { accId := bson.NewObjectId() accHex := nick oldAcc, err := modelhelper.GetAccount(nick) if err == mgo.ErrNotFound { oldAcc = &kodingmodels.Account{ Id: accId, Profile: struct { Nickname string `bson:"nickname" json:"nickname"` FirstName string `bson:"firstName" json:"firstName"` LastName string `bson:"lastName" json:"lastName"` Hash string `bson:"hash" json:"hash"` }{ Nickname: nick, }, } err := modelhelper.CreateAccount(oldAcc) if err != nil { return nil, err } } oldUser, err := modelhelper.GetUser(nick) if err == mgo.ErrNotFound { oldUser = &kodingmodels.User{ ObjectId: bson.NewObjectId(), Password: accHex, Salt: accHex, Name: nick, Email: accHex + "@koding.com", Status: "confirmed", EmailFrequency: &kodingmodels.EmailFrequency{}, } err = modelhelper.CreateUser(oldUser) if err != nil { return nil, err } } a := NewAccount() a.Nick = nick a.OldId = accId.Hex() if err := a.ByNick(nick); err == bongo.RecordNotFound { if err := a.Create(); err != nil { return nil, err } } if oldAcc.SocialApiId != strconv.FormatInt(a.Id, 10) { s := modelhelper.Selector{"_id": oldAcc.Id} o := modelhelper.Selector{"$set": modelhelper.Selector{ "socialApiId": strconv.FormatInt(a.Id, 10), }} if err := modelhelper.UpdateAccount(s, o); err != nil { return nil, err } } return a, nil }
func (m *Migrate) Action(args []string) error { if err := m.Valid(); err != nil { return err } c, err := kloudClient() if err != nil { return err } defer c.Close() modelhelper.Initialize(*m.MongoURL) defer modelhelper.Close() account, err := modelhelper.GetAccount(*m.User) if err != nil { return err } if *m.Credential == "" { *m.Credential = bson.NewObjectId().Hex() cred := &models.Credential{ Id: bson.NewObjectId(), Provider: "aws", Identifier: *m.Credential, OriginId: account.Id, } credData := &models.CredentialData{ Id: bson.NewObjectId(), Identifier: *m.Credential, OriginId: account.Id, Meta: bson.M{ "access_key": *m.Key, "secret_key": *m.Secret, "region": *m.Region, }, } if err := modelhelper.InsertCredential(cred, credData); err != nil { return err } credRelationship := &models.Relationship{ Id: bson.NewObjectId(), TargetId: cred.Id, TargetName: "JCredential", SourceId: account.Id, SourceName: "JAccount", As: "owner", } if err := modelhelper.AddRelationship(credRelationship); err != nil { return err } } req := &MigrateRequest{ Provider: "aws", Machines: m.Machines, Identifier: *m.Credential, GroupName: *m.Team, StackName: "Migrated Stack", Impersonate: *m.User, } _, err = c.Tell("migrate", req) return err }
// BuildCredentials fetches credential details for current b.Stack from MongoDB. // // When nil error is returned, the b.Koding and b.Credentials fields are non-nil. // // TODO(rjeczalik): Replace with *credential.Client func (b *Builder) BuildCredentials(method, username, groupname string, identifiers []string) error { // fetch jaccount from username account, err := modelhelper.GetAccount(username) if err != nil { return models.ResError(err, "jAccount") } // fetch jUser from username user, err := modelhelper.GetUser(username) if err != nil { return models.ResError(err, "jUser") } kodingMeta := &KodingMeta{ Email: user.Email, Username: user.Name, Nickname: account.Profile.Nickname, Firstname: account.Profile.FirstName, Lastname: account.Profile.LastName, Hash: account.Profile.Hash, } if b.StackTemplate != nil { kodingMeta.TemplateID = b.StackTemplate.Id.Hex() } if b.Stack != nil { kodingMeta.StackID = b.Stack.Stack.Id.Hex() kodingMeta.TemplateID = b.Stack.Stack.BaseStackId.Hex() } groupIDs := []bson.ObjectId{account.Id} if groupname != "" { // fetch jGroup from group slug name group, err := modelhelper.GetGroup(groupname) if err != nil { return models.ResError(err, "jGroup") } // validate if username belongs to groupnam selector := modelhelper.Selector{ "targetId": account.Id, "sourceId": group.Id, "as": bson.M{ "$in": []string{"member"}, }, } count, err := modelhelper.RelationshipCount(selector) if err != nil || count == 0 { return fmt.Errorf("username '%s' does not belong to group '%s'", username, groupname) } kodingMeta.Title = group.Title kodingMeta.Slug = group.Slug groupIDs = append(groupIDs, group.Id) } // 2- fetch credential from identifiers via args credentials, err := modelhelper.GetCredentialsFromIdentifiers(identifiers...) if err != nil { return models.ResError(err, "jCredential") } credentialTitles := make(map[string]string, len(credentials)) for _, cred := range credentials { credentialTitles[cred.Identifier] = cred.Title } // 3- count relationship with credential id and jaccount id as user or // owner. Any non valid credentials will be discarded validKeys := make(map[string]string, len(credentials)) permittedTargets, ok := credPermissions[method] if !ok { return fmt.Errorf("no permission data available for method '%s'", method) } for _, cred := range credentials { selector := modelhelper.Selector{ "targetId": cred.Id, "sourceId": bson.M{ "$in": groupIDs, }, "as": bson.M{"$in": permittedTargets}, } count, err := modelhelper.RelationshipCount(selector) if err != nil { return models.ResError(err, "jRelationship") } if count == 0 { return fmt.Errorf("credential with identifier '%s' is not validated: %v", cred.Identifier, err) } validKeys[cred.Identifier] = cred.Provider } // 5- return list of keys. b.Koding = &stack.Credential{ Provider: "koding", Credential: kodingMeta, } creds := make([]*stack.Credential, 0, len(validKeys)) for ident, provider := range validKeys { creds = append(creds, &stack.Credential{ Title: credentialTitles[ident], Provider: provider, Identifier: ident, }) } if err := b.FetchCredentials(username, creds...); err != nil { // TODO(rjeczalik): add *NotFoundError support to CredStore return models.ResError(err, "jCredentialData") } b.Credentials = append(b.Credentials, creds...) for i, cred := range b.Credentials { b.Log.Debug("Built credential #%d: %# v (%+v, %+v)", i, cred, cred.Credential, cred.Bootstrap) } return nil }
func (db *mongoDatabase) fetchModels(f *Filter, perm *MongoPerm) (err error) { log := db.Log.New("fetchModels") if perm.AccModel == nil { log.Debug("fetching %q account", f.Username) perm.AccModel, err = modelhelper.GetAccount(f.Username) if err != nil { return models.ResError(err, "jAccount") } perm.CredGroups = append(perm.CredGroups, perm.AccModel.Id) } if perm.UserModel == nil { log.Debug("fetching %q user", f.Username) perm.UserModel, err = modelhelper.GetUser(f.Username) if err != nil { return models.ResError(err, "jUser") } } if f.Teamname != "" { if perm.TeamModel == nil { log.Debug("fetching %q team", f.Teamname) perm.TeamModel, err = modelhelper.GetGroup(f.Teamname) if err != nil { return models.ResError(err, "jGroup") } perm.CredGroups = append(perm.CredGroups, perm.TeamModel.Id) } if !perm.Member { belongs := modelhelper.Selector{ "targetId": perm.AccModel.Id, "sourceId": perm.TeamModel.Id, "as": "member", } log.Debug("testing relationship for %+v", belongs) if count, err := modelhelper.RelationshipCount(belongs); err != nil || count == 0 { if err == nil { err = fmt.Errorf("user %q does not belong to %q group", f.Username, f.Teamname) } return models.ResError(err, "jRelationship") } perm.Member = true } } if perm.CredModel == nil && f.Ident != "" { log.Debug("fetching %q credential", f.Ident) perm.CredModel, err = modelhelper.GetCredential(f.Ident) if err != nil { return models.ResError(err, "jCredential") } } return nil }
func CreateUser(opts *UserOptions) (*User, error) { username := opts.Username groupname := opts.Groupname provider := opts.Provider template := opts.Template privateKey, publicKey, err := sshutil.TemporaryKey() if err != nil { return nil, err } labels, err := machineLabels([]byte(template)) if err != nil { return nil, err } relationExists := true // jAccounts account, err := modelhelper.GetAccount(username) if err == mgo.ErrNotFound { relationExists = false account = &models.Account{ Id: bson.NewObjectId(), Profile: models.AccountProfile{ Nickname: username, }, } err = modelhelper.CreateAccount(account) } if err != nil { return nil, errors.New("failure looking up jAccounts: " + err.Error()) } // jGroups group, err := modelhelper.GetGroup(groupname) if err == mgo.ErrNotFound { relationExists = false group = &models.Group{ Id: bson.NewObjectId(), Title: groupname, Slug: groupname, } err = modelhelper.CreateGroup(group) } if err != nil { return nil, errors.New("failure looking up jGroups: " + err.Error()) } if !relationExists { // add relation between use and group relationship := &models.Relationship{ Id: bson.NewObjectId(), TargetId: account.Id, TargetName: "JAccount", SourceId: group.Id, SourceName: "JGroup", As: "member", } err := modelhelper.AddRelationship(relationship) if err != nil { return nil, errors.New("failure insering relationship: " + err.Error()) } } // jUsers user, err := modelhelper.GetUser(username) if err == nil && len(user.SshKeys) != 0 { publicKey = user.SshKeys[0].Key } if err == mgo.ErrNotFound { user = &models.User{ ObjectId: bson.NewObjectId(), Email: username + "@" + username + ".com", LastLoginDate: time.Now().UTC(), RegisteredAt: time.Now().UTC(), Name: username, // bson equivelant is username Password: "******", Status: "confirmed", SshKeys: []struct { Title string `bson:"title"` Key string `bson:"key"` }{ {Key: publicKey}, }, } err = modelhelper.CreateUser(user) } if err != nil { return nil, errors.New("failure looking up jUsers: " + err.Error()) } queryString := protocol.Kite{ID: opts.KlientID}.String() cred := &models.Credential{ Id: bson.NewObjectId(), Provider: opts.Provider, Identifier: bson.NewObjectId().Hex(), OriginId: account.Id, } credData := &models.CredentialData{ Id: bson.NewObjectId(), Identifier: cred.Identifier, OriginId: account.Id, Meta: bson.M{ "queryString": queryString, "memory": 0, "cpu": 0, "box": "", }, } if err := modelhelper.InsertCredential(cred, credData); err != nil { return nil, err } relationship := &models.Relationship{ Id: bson.NewObjectId(), TargetId: cred.Id, TargetName: "JCredential", SourceId: account.Id, SourceName: "JAccount", As: "owner", } if err := modelhelper.AddRelationship(relationship); err != nil { return nil, err } // jComputeStack and jStackTemplates stackTemplateId := bson.NewObjectId() stackTemplate := &models.StackTemplate{ Id: stackTemplateId, Credentials: map[string][]string{ "vagrant": {cred.Identifier}, }, } stackTemplate.Template.Content = template if err := modelhelper.CreateStackTemplate(stackTemplate); err != nil { return nil, err } // later we can add more users with "Owner:false" to test sharing capabilities users := []models.MachineUser{ {Id: user.ObjectId, Sudo: true, Owner: true}, } machineIds := make([]bson.ObjectId, len(labels)) for i, label := range labels { machineId := bson.NewObjectId() machine := &models.Machine{ ObjectId: machineId, Label: label, Domain: username + ".dev.koding.io", Provider: provider, CreatedAt: time.Now().UTC(), Users: users, Meta: make(bson.M, 0), Groups: make([]models.MachineGroup, 0), Credential: username, } machine.Assignee.InProgress = false machine.Assignee.AssignedAt = time.Now().UTC() machine.Status.State = machinestate.NotInitialized.String() machine.Status.ModifiedAt = time.Now().UTC() machineIds[i] = machine.ObjectId if err := modelhelper.CreateMachine(machine); err != nil { return nil, err } } computeStackID := bson.NewObjectId() computeStack := &models.ComputeStack{ Id: computeStackID, BaseStackId: stackTemplateId, Machines: machineIds, } if err := modelhelper.CreateComputeStack(computeStack); err != nil { return nil, err } return &User{ MachineIDs: machineIds, MachineLabels: labels, StackID: computeStackID.Hex(), StackTemplateID: stackTemplate.Id.Hex(), AccountID: account.Id, CredID: cred.Id.Hex(), CredDataID: credData.Id.Hex(), PrivateKey: privateKey, PublicKey: publicKey, Identifiers: []string{cred.Identifier}, }, nil }
func TestChannelUpdatedCalculateUnreadItemCount(t *testing.T) { r := runner.New("test") if err := r.Init(); err != nil { t.Fatalf("couldnt start bongo %s", err.Error()) } defer r.Close() appConfig := config.MustRead(r.Conf.Path) modelhelper.Initialize(appConfig.Mongo) defer modelhelper.Close() groupName := models.RandomGroupName() Convey("while testing get account", t, func() { Convey("if cookie is not set, should return nil", func() { a := getAccount(&http.Request{}, models.Channel_KODING_NAME) So(a, ShouldNotBeNil) So(a.Id, ShouldBeZeroValue) }) Convey("if cookie value is not set, should return nil", func() { req, _ := http.NewRequest("GET", "/", nil) expire := time.Now().AddDate(0, 0, 1) cookie := http.Cookie{ Name: "clientId", Value: "", Path: "/", Domain: "localhost", Expires: expire, } req.AddCookie(&cookie) a := getAccount(req, models.Channel_KODING_NAME) So(a, ShouldNotBeNil) So(a.Id, ShouldBeZeroValue) }) Convey("if session doesnt have username, should return nil", func() { ses, err := modelhelper.CreateSessionForAccount("", groupName) So(err, ShouldBeNil) So(ses, ShouldNotBeNil) req, _ := http.NewRequest("GET", "/", nil) expire := time.Now().AddDate(0, 0, 1) cookie := http.Cookie{ Name: "clientId", Value: ses.ClientId, Path: "/", Domain: "localhost", Expires: expire, } req.AddCookie(&cookie) a := getAccount(req, models.Channel_KODING_NAME) So(a, ShouldNotBeNil) So(a.Id, ShouldBeZeroValue) }) Convey("if session is valid, should return account", func() { acc, err := models.CreateAccountInBothDbs() So(err, ShouldBeNil) So(acc, ShouldNotBeNil) ses, err := modelhelper.CreateSessionForAccount(acc.Nick, groupName) So(err, ShouldBeNil) So(ses, ShouldNotBeNil) req, _ := http.NewRequest("GET", "/", nil) expire := time.Now().AddDate(0, 0, 1) cookie := http.Cookie{ Name: "clientId", Value: ses.ClientId, Path: "/", Domain: "localhost", Expires: expire, } req.AddCookie(&cookie) res := getAccount(req, models.Channel_KODING_NAME) So(res, ShouldNotBeNil) So(acc.Id, ShouldEqual, res.Id) }) }) Convey("while making sure account", t, func() { Convey("if account is not in postgres", func() { nick := models.RandomName() oldAcc := &kodingmodels.Account{ Id: bson.NewObjectId(), Profile: kodingmodels.AccountProfile{ Nickname: nick, }, } err := modelhelper.CreateAccount(oldAcc) So(err, ShouldBeNil) oldUser := &kodingmodels.User{ ObjectId: bson.NewObjectId(), Password: nick, Salt: nick, Name: nick, Email: nick + "@koding.com", EmailFrequency: &kodingmodels.EmailFrequency{}, } err = modelhelper.CreateUser(oldUser) So(err, ShouldBeNil) groupName := models.RandomGroupName() _, err = makeSureAccount(groupName, nick) So(err, ShouldBeNil) Convey("should create it in postgres", func() { a := models.NewAccount() err = a.ByNick(nick) So(err, ShouldBeNil) So(a.OldId, ShouldEqual, oldAcc.Id.Hex()) Convey("should set socialAPI id in mongo", func() { oldAccFromDB, err := modelhelper.GetAccount(nick) So(err, ShouldBeNil) So(oldAccFromDB.SocialApiId, ShouldEqual, strconv.FormatInt(a.Id, 10)) }) }) }) Convey("if account is in postgres", func() { acc, err := models.CreateAccountInBothDbs() So(err, ShouldBeNil) So(acc, ShouldNotBeNil) groupName := models.RandomGroupName() _, err = makeSureAccount(groupName, acc.Nick) So(err, ShouldBeNil) Convey("should be in postgres", func() { a := models.NewAccount() err = a.ByNick(acc.Nick) So(err, ShouldBeNil) So(a.OldId, ShouldEqual, acc.OldId) Convey("should have socialAPI set", func() { oldAccFromDB, err := modelhelper.GetAccount(acc.Nick) So(err, ShouldBeNil) So(oldAccFromDB.SocialApiId, ShouldEqual, strconv.FormatInt(a.Id, 10)) }) }) }) }) Convey("while making sure group membership", t, func() { Convey("if account is not not a member", func() { account := models.CreateAccountWithTest() requester := models.CreateAccountWithTest() groupChannel := models.CreateTypedPublicChannelWithTest(account.Id, models.Channel_TYPE_GROUP) err := makeSureMembership(groupChannel, requester.Id) So(err, ShouldBeNil) Convey("should add as participant", func() { status, err := groupChannel.IsParticipant(requester.Id) So(err, ShouldBeNil) So(status, ShouldBeTrue) Convey("if account is a member", func() { err := makeSureMembership(groupChannel, requester.Id) So(err, ShouldBeNil) Convey("should be a participant", func() { status, err := groupChannel.IsParticipant(requester.Id) So(err, ShouldBeNil) So(status, ShouldBeTrue) }) }) }) }) }) }