diff --git a/pkg/api/api.go b/pkg/api/api.go index ef89311bdd6..fe165fe9307 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -43,7 +43,8 @@ func Register(r *macaron.Macaron) { // sign up r.Get("/signup", Index) - r.Post("/api/user/signup", bind(m.CreateUserCommand{}), wrap(SignUp)) + r.Post("/api/user/signup", bind(dtos.SignUpForm{}), wrap(SignUp)) + r.Post("/api/user/signup/step2", bind(dtos.SignUpStep2Form{}), wrap(SignUpStep2)) // invited r.Get("/api/user/invite/:code", wrap(GetInviteInfoByCode)) diff --git a/pkg/api/dtos/user.go b/pkg/api/dtos/user.go index 14aa1ded2a2..bf13d934085 100644 --- a/pkg/api/dtos/user.go +++ b/pkg/api/dtos/user.go @@ -4,6 +4,14 @@ type SignUpForm struct { Email string `json:"email" binding:"Required"` } +type SignUpStep2Form struct { + Email string `json:"email"` + Name string `json:"name"` + Username string `json:"username"` + Code string `json:"code"` + OrgName string `json:"orgName"` +} + type AdminCreateUserForm struct { Email string `json:"email"` Login string `json:"login"` diff --git a/pkg/api/signup.go b/pkg/api/signup.go index 78eac32d786..928403f219a 100644 --- a/pkg/api/signup.go +++ b/pkg/api/signup.go @@ -27,7 +27,7 @@ func SignUp(c *middleware.Context, form dtos.SignUpForm) Response { cmd.Email = form.Email cmd.Status = m.TmpUserSignUpStarted cmd.InvitedByUserId = c.UserId - cmd.Code = util.GetRandomString(10) + cmd.Code = util.GetRandomString(20) cmd.RemoteAddr = c.Req.RemoteAddr if err := bus.Dispatch(&cmd); err != nil { @@ -36,13 +36,41 @@ func SignUp(c *middleware.Context, form dtos.SignUpForm) Response { // user := cmd.Resu - bus.Publish(&events.UserSignedUp{Email: form.Email}) + bus.Publish(&events.SignUpStarted{ + Email: form.Email, + Code: cmd.Code, + }) - // // loginUserWithUser(&user, c) - // - // metrics.M_Api_User_SignUpStarted.Inc(1) - return ApiSuccess("User created and logged in") + + return Json(200, util.DynMap{"status": "SignUpCreated"}) +} + +func SignUpStep2(c *middleware.Context, form dtos.SignUpStep2Form) Response { + if !setting.AllowUserSignUp { + return ApiError(401, "User signup is disabled", nil) + } + + query := m.GetTempUserByCodeQuery{Code: form.Code} + + if err := bus.Dispatch(&query); err != nil { + if err == m.ErrTempUserNotFound { + return ApiError(404, "Invalid email verification code", nil) + } + return ApiError(500, "Failed to read temp user", err) + } + + tempUser := query.Result + if tempUser.Email != form.Email { + return ApiError(404, "Email verification code does not match email", nil) + } + + existing := m.GetUserByLoginQuery{LoginOrEmail: tempUser.Email} + if err := bus.Dispatch(&existing); err == nil { + return ApiError(401, "User with same email address already exists", nil) + } + + return Json(200, util.DynMap{"status": "SignUpCreated"}) } diff --git a/pkg/events/events.go b/pkg/events/events.go index 38a4c2e9848..8890f079716 100644 --- a/pkg/events/events.go +++ b/pkg/events/events.go @@ -70,12 +70,10 @@ type UserCreated struct { Email string `json:"email"` } -type UserSignedUp struct { +type SignUpStarted struct { Timestamp time.Time `json:"timestamp"` - Id int64 `json:"id"` - Name string `json:"name"` - Login string `json:"login"` Email string `json:"email"` + Code string `json:"code"` } type SignUpCompleted struct { diff --git a/pkg/services/notifications/notifications.go b/pkg/services/notifications/notifications.go index 6725616c2ed..ccfb41420ee 100644 --- a/pkg/services/notifications/notifications.go +++ b/pkg/services/notifications/notifications.go @@ -25,7 +25,7 @@ func Init() error { bus.AddHandler("email", validateResetPasswordCode) bus.AddHandler("email", sendEmailCommandHandler) - bus.AddEventListener(userSignedUpHandler) + bus.AddEventListener(signUpStartedHandler) mailTemplates = template.New("name") mailTemplates.Funcs(template.FuncMap{ @@ -120,7 +120,7 @@ func validateResetPasswordCode(query *m.ValidateResetPasswordCodeQuery) error { return nil } -func userSignedUpHandler(evt *events.UserSignedUp) error { +func signUpStartedHandler(evt *events.SignUpStarted) error { log.Info("User signed up: %s, send_option: %s", evt.Email, setting.Smtp.SendWelcomeEmailOnSignUp) if evt.Email == "" || !setting.Smtp.SendWelcomeEmailOnSignUp { diff --git a/public/app/controllers/all.js b/public/app/controllers/all.js index 500feea3516..3fdaf6ef3e9 100644 --- a/public/app/controllers/all.js +++ b/public/app/controllers/all.js @@ -7,6 +7,7 @@ define([ './jsonEditorCtrl', './loginCtrl', './invitedCtrl', + './signupCtrl', './resetPasswordCtrl', './sidemenuCtrl', './errorCtrl', diff --git a/public/app/controllers/loginCtrl.js b/public/app/controllers/loginCtrl.js index 40e8009b399..0ee370fb979 100644 --- a/public/app/controllers/loginCtrl.js +++ b/public/app/controllers/loginCtrl.js @@ -58,8 +58,12 @@ function (angular, config) { return; } - backendSrv.post('/api/user/signup', $scope.formModel).then(function() { - window.location.href = config.appSubUrl + '/'; + backendSrv.post('/api/user/signup', $scope.formModel).then(function(result) { + if (result.status === 'SignUpCreated') { + $location.path('/signup').search({email: $scope.formModel.email}); + } else { + window.location.href = config.appSubUrl + '/'; + } }); }; diff --git a/public/app/controllers/signupCtrl.js b/public/app/controllers/signupCtrl.js new file mode 100644 index 00000000000..366ec84df09 --- /dev/null +++ b/public/app/controllers/signupCtrl.js @@ -0,0 +1,36 @@ +define([ + 'angular', + 'config', +], +function (angular, config) { + 'use strict'; + + var module = angular.module('grafana.controllers'); + + module.controller('SignUpCtrl', function($scope, $location, contextSrv, backendSrv) { + + contextSrv.sidemenu = false; + + $scope.formModel = {}; + + $scope.init = function() { + var email = $location.search().email; + $scope.formModel.orgName = email; + $scope.formModel.email = email; + $scope.formModel.username = email; + }; + + $scope.submit = function() { + if (!$scope.signupForm.$valid) { + return; + } + + backendSrv.post('/api/user/signup/step2', $scope.formModel).then(function() { + window.location.href = config.appSubUrl + '/'; + }); + }; + + $scope.init(); + + }); +}); diff --git a/public/app/partials/signup_step2.html b/public/app/partials/signup_step2.html new file mode 100644 index 00000000000..0df3ea211de --- /dev/null +++ b/public/app/partials/signup_step2.html @@ -0,0 +1,113 @@ +
+ +
+
+ +
+ + + +
+

+ You're almost there. +

+ + + +
+
+ + {{formModel.email}} +
+
+ +
+ + + +
+
+ +
+ +
+ +
+ +
+ + diff --git a/public/app/routes/all.js b/public/app/routes/all.js index 28fa833439a..23ca3d19805 100644 --- a/public/app/routes/all.js +++ b/public/app/routes/all.js @@ -106,6 +106,10 @@ define([ templateUrl: 'app/partials/signup_invited.html', controller : 'InvitedCtrl', }) + .when('/signup', { + templateUrl: 'app/partials/signup_step2.html', + controller : 'SignUpCtrl', + }) .when('/user/password/send-reset-email', { templateUrl: 'app/partials/reset_password.html', controller : 'ResetPasswordCtrl', diff --git a/public/css/less/login.less b/public/css/less/login.less index 50369c06751..924659d9e16 100644 --- a/public/css/less/login.less +++ b/public/css/less/login.less @@ -4,7 +4,7 @@ float: left; margin-left: 25%; margin-right: 25%; - padding-top: 50px; + padding-top: 25px; } .login-box {