mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
feat(signup): progress on new sign up and email verification flow, #2353
This commit is contained in:
parent
d25624a8ad
commit
24dfa55465
@ -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))
|
||||
|
@ -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"`
|
||||
|
@ -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"})
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -7,6 +7,7 @@ define([
|
||||
'./jsonEditorCtrl',
|
||||
'./loginCtrl',
|
||||
'./invitedCtrl',
|
||||
'./signupCtrl',
|
||||
'./resetPasswordCtrl',
|
||||
'./sidemenuCtrl',
|
||||
'./errorCtrl',
|
||||
|
@ -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 + '/';
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
36
public/app/controllers/signupCtrl.js
Normal file
36
public/app/controllers/signupCtrl.js
Normal file
@ -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();
|
||||
|
||||
});
|
||||
});
|
113
public/app/partials/signup_step2.html
Normal file
113
public/app/partials/signup_step2.html
Normal file
@ -0,0 +1,113 @@
|
||||
<div class="container">
|
||||
|
||||
<div class="signup-page-background">
|
||||
</div>
|
||||
|
||||
<div class="login-box">
|
||||
|
||||
<div class="login-box-logo">
|
||||
<img src="img/logo_transparent_200x75.png">
|
||||
</div>
|
||||
|
||||
<div class="invite-box">
|
||||
<h3>
|
||||
You're almost there.
|
||||
</h3>
|
||||
|
||||
<div class="modal-tagline">
|
||||
We just need a couple of more bits of<br> information to finish creating your account.
|
||||
</div>
|
||||
|
||||
<div style="display: inline-block; margin-top: 25px; width: 300px">
|
||||
<div class="editor-option">
|
||||
<label class="small">Your email:</label>
|
||||
<span class="large">{{formModel.email}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<form name="signupForm" class="login-form">
|
||||
|
||||
<div style="display: inline-block; margin-bottom: 25px; width: 300px">
|
||||
<div class="editor-option">
|
||||
<label class="small">Email verification code: <em>Sent to your email just now</em></label>
|
||||
<input type="text" class="input input-xlarge" ng-model="formModel.code" required></input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tight-from-container">
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item" style="width: 128px">
|
||||
Organization
|
||||
</li>
|
||||
<li>
|
||||
<input type="text" name="orgName" class="tight-form-input last" ng-model='formModel.orgName' placeholder="Name your organization" style="width: 253px">
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item" style="width: 128px">
|
||||
Name
|
||||
</li>
|
||||
<li>
|
||||
<input type="text" name="name" class="tight-form-input last" ng-model='formModel.name' placeholder="Name (optional)" style="width: 253px">
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item" style="width: 128px">
|
||||
Username
|
||||
</li>
|
||||
<li>
|
||||
<input type="text" class="tight-form-input last" required ng-model='formModel.username' placeholder="Username" style="width: 253px" autocomplete="off">
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
<div class="tight-form">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item" style="width: 128px">
|
||||
Password
|
||||
</li>
|
||||
<li>
|
||||
<input type="password" class="tight-form-input last" required ng-model="formModel.password" id="inputPassword" style="width: 253px" placeholder="password" autocomplete="off">
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-left: 147px; width: 254px;">
|
||||
<password-strength password="formModel.password"></password-strength>
|
||||
</div>
|
||||
|
||||
<div class="login-submit-button-row">
|
||||
<button type="submit" class="btn" ng-click="submit();" ng-class="{'btn-inverse': !signUpForm.$valid, 'btn-primary': signUpForm.$valid}">
|
||||
Continue
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
<div class="row" style="margin-top: 50px">
|
||||
<div class="version-footer text-center small">
|
||||
Grafana version: {{buildInfo.version}}, commit: {{buildInfo.commit}},
|
||||
build date: {{buildInfo.buildstamp | date: 'yyyy-MM-dd HH:mm:ss' }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -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',
|
||||
|
@ -4,7 +4,7 @@
|
||||
float: left;
|
||||
margin-left: 25%;
|
||||
margin-right: 25%;
|
||||
padding-top: 50px;
|
||||
padding-top: 25px;
|
||||
}
|
||||
|
||||
.login-box {
|
||||
|
Loading…
Reference in New Issue
Block a user