コード例 #1
0
ファイル: resources.go プロジェクト: app-kit/go-appkit
func (hooks UserResourceHooks) AllowUpdate(res kit.Resource, obj kit.Model, old kit.Model, user kit.User) bool {
	if user == nil {
		return false
	}
	if user.HasRole("admin") || user.HasPermission("users.update") {
		return true
	}
	return obj.GetId() == user.GetId()
}
コード例 #2
0
ファイル: resource.go プロジェクト: app-kit/go-appkit
func (UserResource) AllowDelete(res kit.Resource, obj kit.Model, user kit.User) bool {
	if user == nil {
		return false
	}
	if obj.(kit.UserModel).GetUserId() == user.GetId() {
		return true
	}
	return user.HasRole("admin") || user.HasPermission(res.Collection()+".delete")
}
コード例 #3
0
ファイル: models.go プロジェクト: app-kit/go-appkit
func (m *StrUserModel) SetUser(u kit.User) {
	if u == nil {
		m.User = nil
		m.UserId = ""
	} else {
		m.User = u.(*UserStrId)
		m.SetUserId(u.GetId())
	}
}
コード例 #4
0
ファイル: resource.go プロジェクト: app-kit/go-appkit
func (UserResource) AllowFind(res kit.Resource, model kit.Model, user kit.User) bool {
	if user == nil {
		return false
	}
	if model.(kit.UserModel).GetUserId() == user.GetId() {
		return true
	}
	return user.HasRole("admin")
}
コード例 #5
0
ファイル: models.go プロジェクト: app-kit/go-appkit
func (m *IntUserModel) SetUser(u kit.User) {
	if u == nil {
		m.User = nil
		m.UserId = 0
	} else {
		m.User = u.(*UserIntId)
		m.SetUserId(u.GetId())
	}
}
コード例 #6
0
ファイル: resources.go プロジェクト: app-kit/go-appkit
func (PageResource) AllowFind(res kit.Resource, obj kit.Model, user kit.User) bool {
	if p, ok := obj.(*PageIntId); ok && p.Published {
		return true
	} else if p, ok := obj.(*PageStrId); ok && p.Published {
		return true
	}

	u := obj.(kit.UserModel)

	return user != nil && (u.GetUserId() == user.GetId() || user.HasRole("admin"))
}
コード例 #7
0
ファイル: password.go プロジェクト: app-kit/go-appkit
func (a *AuthAdaptorPassword) RegisterUser(user kit.User, data map[string]interface{}) (kit.AuthItem, apperror.Error) {
	if data == nil {
		return nil, apperror.New("invalid_nil_data")
	}
	pw, _ := GetStringFromMap(data, "password")
	if pw == "" {
		return nil, apperror.New("invalid_data_no_password")
	}

	hash, err := bcrypt.GenerateFromPassword([]byte(pw), 10)
	if err != nil {
		return nil, apperror.Wrap(err, "hash_errr", "")
	}

	item := &AuthItemPassword{
		Hash: string(hash),
	}
	item.SetId(user.GetId())

	return item, nil
}
コード例 #8
0
ファイル: resource.go プロジェクト: app-kit/go-appkit
func (res *Resource) Create(obj kit.Model, user kit.User) apperror.Error {
	if hook, ok := res.hooks.(CreateHook); ok {
		return hook.Create(res, obj, user)
	}

	// This has to be done before tthe AllowCreate hook to allow the hook to
	// compare UserId value.
	if userModel, ok := obj.(kit.UserModel); ok && user != nil {
		if reflector.R(userModel.GetUserId()).IsZero() {
			userModel.SetUserId(user.GetId())
		}
	}

	if allowCreate, ok := res.hooks.(AllowCreateHook); ok {
		if !allowCreate.AllowCreate(res, obj, user) {
			return apperror.New("permission_denied")
		}
	}

	if beforeCreate, ok := res.hooks.(BeforeCreateHook); ok {
		if err := beforeCreate.BeforeCreate(res, obj, user); err != nil {
			return err
		}
	}

	if err := res.backend.Create(obj); err != nil {
		return err
	}

	if afterCreate, ok := res.hooks.(AfterCreateHook); ok {
		if err := afterCreate.AfterCreate(res, obj, user); err != nil {
			return err
		}
	}

	return nil
}
コード例 #9
0
ファイル: service.go プロジェクト: app-kit/go-appkit
func (s Service) StartSession(user kit.User, sessionType string) (kit.Session, apperror.Error) {
	token := randomToken()
	if token == "" {
		return nil, apperror.New("token_creation_failed")
	}

	session := s.Sessions.CreateModel().(kit.Session)

	session.SetType(sessionType)
	session.SetToken(token)
	session.SetStartedAt(time.Now())
	session.SetValidUntil(time.Now().Add(time.Hour * 12))

	if user != nil {
		session.SetUserId(user.GetId())
	}

	err := s.Sessions.Create(session, nil)
	if err != nil {
		return nil, err
	}

	return session, nil
}
コード例 #10
0
ファイル: password.go プロジェクト: app-kit/go-appkit
func (item *AuthItemPassword) SetUser(u kit.User) {
	item.SetUserId(u.GetId())
}
コード例 #11
0
ファイル: models.go プロジェクト: app-kit/go-appkit
func (p IntIdUserProfile) SetUser(user kit.User) {
	p.SetUserId(user.GetId())
}
コード例 #12
0
ファイル: app_test.go プロジェクト: app-kit/go-appkit
			})

			It("Should resend confirmation email", func() {
				if skipUser {
					Skip("Previous error")
				}

				js := `{"data": {}}`
				status, _, err := client.PostJson("/api/method/users.send-confirmation-email", js)
				Expect(err).ToNot(HaveOccurred())
				Expect(status).To(Equal(200))

				// Check that confirmation email was sent.
				logEntry := logMessages[len(logMessages)-2]
				Expect(logEntry.Data["action"]).To(Equal("users.email_confirmation_mail_sent"))
				Expect(logEntry.Data["user_id"]).To(Equal(currentUser.GetId()))
				Expect(logEntry.Data["email"]).To(Equal(currentUser.GetEmail()))

				currentToken = logEntry.Data["token"].(string)
			})

			It("Should confirm email", func() {
				if skipUser || currentToken == "" {
					Skip("Previous error")
				}

				js := fmt.Sprintf(`{"data": {"token": "%v"}}`, currentToken)
				status, _, err := client.PostJson("/api/method/users.confirm-email", js)
				Expect(err).ToNot(HaveOccurred())
				Expect(status).To(Equal(200))
コード例 #13
0
ファイル: service.go プロジェクト: app-kit/go-appkit
func (s *Service) SendPasswordResetEmail(user kit.User) apperror.Error {
	// Check that an email service is configured.

	mailService := s.registry.EmailService()
	if mailService == nil {
		return apperror.New("no_email_service")
	}

	hoursValid := 48

	// Generate a token.
	expiresAt := time.Now().Add(time.Hour * time.Duration(hoursValid))
	tokenItem, err := s.BuildToken("password_reset", user.GetStrId(), expiresAt)
	if err != nil {
		return err
	}
	token := tokenItem.GetToken()

	conf := s.registry.Config()

	// Build the confirmation url.

	url := conf.UString("url")
	if url == "" {
		return &apperror.Err{
			Code:    "no_url_set",
			Message: "Config must specify url",
		}
	}

	resetPath := conf.UString("users.passwordResetPath")
	if resetPath == "" {
		return &apperror.Err{
			Code:    "no_password_reset_path",
			Message: "Config must specify users.passwordResetPath",
		}
	}

	if !strings.Contains(resetPath, "{token}") {
		return &apperror.Err{
			Code:    "invalid_password_reset_path",
			Message: "users.passwordResetPath does not contain {token} placeholder",
		}
	}
	resetUrl := url + "/" + strings.Replace(resetPath, "{token}", token, -1)

	// Render email.

	subject := conf.UString("users.passwordResetSubject", "Password reset")

	var txtContent, htmlContent []byte

	txtTpl := conf.UString("users.passwordResetTextTpl")
	htmlTpl := conf.UString("users.passwordResetHtmlTpl")
	if txtTpl != "" && htmlTpl != "" {
		// Check that a template engine is configured.
		engine := s.registry.TemplateEngine()
		if engine == nil {
			return apperror.New("no_template_engine")
		}

		data := map[string]interface{}{
			"user":        user,
			"token":       token,
			"hours_valid": hoursValid,
		}
		var err apperror.Error

		txtContent, err = s.registry.TemplateEngine().BuildFileAndRender(txtTpl, data)
		if err != nil {
			return apperror.Wrap(err, "password_reset_tpl_error", "Could not render password reset tpl")
		}

		htmlContent, err = s.registry.TemplateEngine().BuildFileAndRender(htmlTpl, data)
		if err != nil {
			return apperror.Wrap(err, "password_reset_tpl_error", "Could not render password reset tpl")
		}
	} else {
		tpl := `Password reset

To reset your password, please visit %v.
The link will be valid for %v hours.
`

		htmlTpl := `Password Reset<br><br>

To reset your password, please visit <a href="%v">this link</a>.<br>
The link will be valid for %v hours.
`
		txtContent = []byte(fmt.Sprintf(tpl, resetUrl, hoursValid))
		htmlContent = []byte(fmt.Sprintf(htmlTpl, resetUrl, hoursValid))
	}

	// Now build the email and send it.
	email := email.NewMail()
	email.SetSubject(subject)
	email.AddBody("text/plain", txtContent)
	email.AddBody("text/html", htmlContent)
	email.AddTo(user.GetEmail(), "")

	if err := mailService.Send(email); err != nil {
		return err
	}

	s.registry.Logger().WithFields(logrus.Fields{
		"action":  "users.password_reset_requested",
		"email":   user.GetEmail(),
		"user_id": user.GetId(),
		"token":   token,
	}).Debugf("Password reset email sent to %v for user %v", user.GetEmail(), user.GetId())

	return nil
}
コード例 #14
0
ファイル: service.go プロジェクト: app-kit/go-appkit
func (s *Service) SendConfirmationEmail(user kit.User) apperror.Error {
	// Check that an email service is configured.

	mailService := s.registry.EmailService()
	if mailService == nil {
		return apperror.New("no_email_service")
	}

	conf := s.registry.Config()

	// Check that sending is enabled.
	if !conf.UBool("users.sendEmailConfirmationEmail", true) {
		return nil
	}

	// Generate a token.
	tokenItem, err := s.BuildToken("email_confirmation", user.GetStrId(), time.Time{})
	if err != nil {
		return err
	}
	token := tokenItem.GetToken()

	// Build the confirmation url.

	confirmationPath := conf.UString("users.emailConfirmationPath")
	if confirmationPath == "" {
		return &apperror.Err{
			Code:    "no_email_confirmation_path",
			Message: "Config must specify users.emailConfirmationPath",
		}
	}

	if !strings.Contains(confirmationPath, "{token}") {
		return &apperror.Err{
			Code:    "invalid_email_confirmation_path",
			Message: "users.emailConfirmationPath does not contain {token} placeholder",
		}
	}
	confirmationUrl := conf.UString("url") + "/" + strings.Replace(confirmationPath, "{token}", token, -1)

	// Render email.

	subject := conf.UString("users.emailConfirmationSubject", "Confirm your Email")

	var txtContent, htmlContent []byte

	txtTpl := conf.UString("users.emailConfirmationEmailTextTpl")
	htmlTpl := conf.UString("users.emailConfirmationEmailHtmlTpl")
	if txtTpl != "" && htmlTpl != "" {
		// Check that a template engine is configured.
		engine := s.registry.TemplateEngine()
		if engine == nil {
			return apperror.New("no_template_engine")
		}

		data := map[string]interface{}{
			"user":  user,
			"token": token,
		}
		var err apperror.Error

		txtContent, err = s.registry.TemplateEngine().BuildFileAndRender(txtTpl, data)
		if err != nil {
			return apperror.Wrap(err, "email_confirmation_tpl_error", "Could not render email confirmation tpl")
		}

		htmlContent, err = s.registry.TemplateEngine().BuildFileAndRender(htmlTpl, data)
		if err != nil {
			return apperror.Wrap(err, "email_confirmation_tpl_error", "Could not render email confirmation tpl")
		}
	} else {
		tpl := `Welcome to Appkit

To confirm your email address, please visit %v.
`

		htmlTpl := `Welcome to Appkit<br><br>

To confirm your email address, please visit <a href="%v">this link</a>.
`
		txtContent = []byte(fmt.Sprintf(tpl, confirmationUrl))
		htmlContent = []byte(fmt.Sprintf(htmlTpl, confirmationUrl))
	}

	// Now build the email and send it.
	email := email.NewMail()
	email.SetSubject(subject)
	email.AddBody("text/plain", txtContent)
	email.AddBody("text/html", htmlContent)
	email.AddTo(user.GetEmail(), "")

	if err := mailService.Send(email); err != nil {
		return err
	}

	s.registry.Logger().WithFields(logrus.Fields{
		"action":  "users.email_confirmation_mail_sent",
		"email":   user.GetEmail(),
		"user_id": user.GetId(),
		"token":   token,
	}).Debugf("Password reset email sent to %v for user %v", user.GetEmail(), user.GetId())

	return nil
}
コード例 #15
0
ファイル: service.go プロジェクト: app-kit/go-appkit
func (s *Service) CreateUser(user kit.User, adaptorName string, authData map[string]interface{}) apperror.Error {
	adaptor := s.AuthAdaptor(adaptorName)
	if adaptor == nil {
		return &apperror.Err{
			Code:    "unknown_auth_adaptor",
			Message: fmt.Sprintf("Auth adaptor %v was not registered with user service", adaptorName),
			Public:  true,
		}
	}

	authItem, err := adaptor.RegisterUser(user, authData)
	if err != nil {
		return apperror.Wrap(err, "adaptor_error", "")
	}

	if user.GetUsername() == "" {
		user.SetUsername(user.GetEmail())
	}

	// Check if user with same username or email exists.
	oldUser, err2 := s.Users.Q().
		Filter("email", user.GetEmail()).Or("username", user.GetUsername()).First()
	if err2 != nil {
		return err2
	} else if oldUser != nil {
		return &apperror.Err{
			Code:    "user_exists",
			Message: "A user with the username or email already exists",
			Public:  true,
		}
	}

	user.SetIsActive(true)

	profile := user.GetProfile()

	// If a profile is configured, and the user does not have a profile yet,
	// create a new one.
	if s.Profiles != nil && profile == nil {
		profile = s.Profiles.CreateModel().(kit.UserProfile)
		user.SetProfile(profile)
	}

	if err := s.Users.Create(user, nil); err != nil {
		return err
	}

	// Create profile if one exists.

	if profile != nil {
		profile.SetUser(user)
		if err := s.Profiles.Create(profile, user); err != nil {
			s.Users.Backend().Delete(user)
			return apperror.Wrap(err, "user_profile_create_error", "Could not create the user profile")
		}
	}

	// Persist auth item.
	if authItemUserId, ok := authItem.(kit.UserModel); ok {
		authItemUserId.SetUserId(user.GetId())
	}
	if err := s.Users.Backend().Create(authItem); err != nil {
		s.Users.Backend().Delete(user)
		if profile != nil {
			s.Profiles.Backend().Delete(profile)
		}
		return apperror.Wrap(err, "auth_item_create_error", "")
	}

	if err := s.SendConfirmationEmail(user); err != nil {
		s.registry.Logger().Errorf("Could not send confirmation email: %v", err)
	}

	return nil
}
コード例 #16
0
ファイル: oauth.go プロジェクト: app-kit/go-appkit
func (item *AuthItemOauth) SetUser(u kit.User) {
	item.SetUserId(u.GetId())
}