// Sync doorbot users with a foreign data source using a bridge. func Sync(render render.Render, r doorbot.Repositories, b bridges.Bridges, a *doorbot.Account, session *auth.Authorization) { var bUsers []*doorbot.BridgeUser var registered []*doorbot.BridgeUser var err error personRepo := r.PersonRepository() bUserRepo := r.BridgeUserRepository() var bridgesToSync = []uint{bridges.BridgeHub, bridges.BridgeHipChat} for _, bridgeId := range bridgesToSync { f := func() bool { users, err := b.GetUsers(bridgeId) for _, u := range users { log.WithFields(log.Fields{"user": *u}).Info("User") } if err != nil { log.WithFields(log.Fields{ "error": err, "account_id": a.ID, "bridge_id": bridgeId, }).Error("Api::People->Sync bridge error") return false } existing, err := bUserRepo.FindByBridgeID(r.DB(), bridgeId) if err != nil { log.WithFields(log.Fields{ "error": err, "account_id": r.AccountScope(), "step": "bridge-user-find-by-bridge-id", "bridge_id": bridgeId, }).Error("Api::People->Sync database error") return false } registered = append(registered, existing...) bUsers = append(bUsers, users...) return true } f() } tx, err := r.Transaction() if err != nil { log.WithFields(log.Fields{ "error": err, "account_id": r.AccountScope(), "step": "transaction-create", }).Error("Api::People->Sync database error") render.JSON(http.StatusInternalServerError, doorbot.NewInternalServerErrorResponse([]string{})) return } var buser *doorbot.BridgeUser for _, u := range bUsers { log.WithFields(log.Fields{ "account_id": r.AccountScope(), "bridge_user_id": u.UserID, "bridge_user_email": u.Email, "bridge_user_name": u.Name, }).Debug("Api::People->Sync bridge user") buser = findRegistered(registered, u.UserID) if buser != nil { log.WithFields(log.Fields{ "account_id": r.AccountScope(), "bridge_user_id": buser.UserID, "person_id": buser.PersonID, }).Debug("Api::People->Sync registered user found") person, err := personRepo.Find(tx, buser.PersonID) if err != nil { log.WithFields(log.Fields{ "error": err, "account_id": r.AccountScope(), "bridge_user_id": buser.UserID, "person_id": buser.PersonID, "step": "person-find-from-bridge-id", }).Error("Api::People->Sync database error") break } person.Name = u.Name person.Email = u.Email person.PhoneNumber = u.PhoneNumber _, err = personRepo.Update(tx, person) if err != nil { log.WithFields(log.Fields{ "error": err, "account_id": r.AccountScope(), "bridge_user_id": buser.UserID, "person_id": buser.PersonID, "step": "person-update-from-bridge-data", }).Error("Api::People->Sync database error") break } log.WithFields(log.Fields{ "account_id": r.AccountScope(), "bridge_user_id": buser.UserID, "person_id": buser.PersonID, }).Info("Api::People->Sync person updated from bridge data") continue } log.WithFields(log.Fields{ "account_id": r.AccountScope(), "bridge_user_id": u.UserID, "bridge_user_email": u.Email, "bridge_user_name": u.Name, }).Info("Api::People->Sync new bridge user") // User does not exists. Create them args := doorbot.PersonArguments{ Name: u.Name, Email: u.Email, } person := doorbot.NewPerson(args) err = personRepo.Create(tx, person) if err != nil { log.WithFields(log.Fields{ "error": err, "account_id": r.AccountScope(), "bridge_user_id": buser.UserID, "step": "person-create-from-bridge-data", }).Error("Api::People->Sync database error") break } u.PersonID = person.ID err = bUserRepo.Create(tx, u) if err != nil { log.WithFields(log.Fields{ "error": err, "account_id": r.AccountScope(), "bridge_user_id": buser.UserID, "step": "bridge-user-create", }).Error("Api::People->Sync database error") break } continue } if err != nil { log.WithFields(log.Fields{ "error": err, "account_id": r.AccountScope(), }).Error("Api::People->Sync error") tx.Rollback() render.JSON(http.StatusInternalServerError, doorbot.NewInternalServerErrorResponse([]string{})) return } err = tx.Commit() if err != nil { log.WithFields(log.Fields{ "error": err, "account_id": r.AccountScope(), "step": "transaction-commit", }).Error("Api::People->Sync database error") render.JSON(http.StatusInternalServerError, doorbot.NewInternalServerErrorResponse([]string{})) return } log.WithFields(log.Fields{ "account_id": r.AccountScope(), }).Info("Api::People->Sync bridge sync completed.") render.Status(http.StatusNoContent) }
// Register a new account ( used by the dashboard ) func Register(render render.Render, config *doorbot.DoorbotConfig, r doorbot.Repositories, n notifications.Notificator, data RegisterViewModel) { repo := r.AccountRepository() tx, err := r.Transaction() if err != nil { log.WithFields(log.Fields{ "error": err, "step": "transaction-create", }).Error("Api::Accounts->Register database error.") render.Status(http.StatusInternalServerError) return } var host string if len(data.Account.Host) == 0 { host, err = generateHost(r, config) } else { var account *doorbot.Account account, err = repo.FindByHost(r.DB(), data.Account.Host) if account != nil { tx.Rollback() render.Status(http.StatusConflict) return } host = data.Account.Host } if err != nil { tx.Rollback() render.Status(http.StatusInternalServerError) return } if len(host) == 0 { log.WithFields(log.Fields{ "host": host, "step": "host-generation", }).Error("Api::Accounts->Register Unable to set a hostname.") tx.Rollback() render.Status(http.StatusServiceUnavailable) return } // Create the account instance account := &doorbot.Account{ Name: data.Account.Name, ContactName: data.Account.ContactName, ContactEmail: data.Account.ContactEmail, //TODO append the doorbot production domain Host: host, IsEnabled: true, } err = repo.Create(tx, account) if err != nil { tx.Rollback() log.WithFields(log.Fields{ "error": err, "host": host, "step": "account-create", }).Error("Api::Accounts->Register database error.") render.JSON(http.StatusInternalServerError, doorbot.NewInternalServerErrorResponse([]string{})) return } // Update the repositories account scopes to the one we just created. r.SetAccountScope(account.ID) // We need to create a person with a password to let them log in on the dashboard. person := &doorbot.Person{ Name: data.Account.ContactName, Email: data.Account.ContactEmail, AccountType: doorbot.AccountOwner, } ar := r.PersonRepository() err = ar.Create(tx, person) if err != nil { log.WithFields(log.Fields{ "error": err, "host": host, "email": person.Email, "step": "person-create", }).Error("Api::Accounts->Register database error.") tx.Rollback() render.Status(http.StatusInternalServerError) return } // Generate a random password password := security.RandomPassword(8) hash, err := security.PasswordCrypt([]byte(password)) if err != nil { log.WithFields(log.Fields{ "error": err, "host": host, "email": person.Email, "step": "person-password", }).Error("Api::Accounts->Register password generation error.") tx.Rollback() render.Status(http.StatusInternalServerError) return } // Create a new authentication record for the user authr := r.AuthenticationRepository() authentication := &doorbot.Authentication{ PersonID: person.ID, ProviderID: auth.ProviderPassword, Token: string(hash), } err = authr.Create(tx, authentication) if err != nil { log.WithFields(log.Fields{ "error": err, "host": host, "email": person.Email, "step": "person-authentication", }).Error("Api::Accounts->Register database error.") tx.Rollback() render.Status(http.StatusInternalServerError) return } err = tx.Commit() if err != nil { log.WithFields(log.Fields{ "error": err, "host": host, "email": person.Email, "step": "transaction-commit", }).Error("Api::Accounts->Register database error.") tx.Rollback() render.Status(http.StatusInternalServerError) return } //TODO Send an email to the user. log.WithFields(log.Fields{ "account_id": account.ID, "account_host": account.Host, "person_id": person.ID, }).Info("Account created") n.AccountCreated(account, person, password) render.JSON(http.StatusCreated, AccountViewModel{Account: account}) }