Пример #1
0
// 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)
}
Пример #2
0
// 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})
}