mirror of
https://github.com/grafana/grafana.git
synced 2025-09-28 05:44:12 +08:00
feat(invite): more progress on completing invite form and actually creating a real user, #2353
This commit is contained in:
@ -45,6 +45,7 @@ func Register(r *macaron.Macaron) {
|
|||||||
|
|
||||||
// invited
|
// invited
|
||||||
r.Get("/api/user/invite/:code", wrap(GetInviteInfoByCode))
|
r.Get("/api/user/invite/:code", wrap(GetInviteInfoByCode))
|
||||||
|
r.Post("/api/user/invite/complete", bind(dtos.CompleteInviteForm{}), wrap(CompleteInvite))
|
||||||
|
|
||||||
// reset password
|
// reset password
|
||||||
r.Get("/user/password/send-reset-email", Index)
|
r.Get("/user/password/send-reset-email", Index)
|
||||||
@ -97,7 +98,7 @@ func Register(r *macaron.Macaron) {
|
|||||||
// invites
|
// invites
|
||||||
r.Get("/invites", wrap(GetPendingOrgInvites))
|
r.Get("/invites", wrap(GetPendingOrgInvites))
|
||||||
r.Post("/invites", bind(dtos.AddInviteForm{}), wrap(AddOrgInvite))
|
r.Post("/invites", bind(dtos.AddInviteForm{}), wrap(AddOrgInvite))
|
||||||
r.Patch("/invites/:id/revoke", wrap(RevokeInvite))
|
r.Patch("/invites/:code/revoke", wrap(RevokeInvite))
|
||||||
}, regOrgAdmin)
|
}, regOrgAdmin)
|
||||||
|
|
||||||
// create new org
|
// create new org
|
||||||
|
@ -14,3 +14,12 @@ type InviteInfo struct {
|
|||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CompleteInviteForm struct {
|
||||||
|
InviteCode string `json:"inviteCode"`
|
||||||
|
Email string `json:"email" binding:"Required"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
ConfirmPassword string `json:"confirmPassword"`
|
||||||
|
}
|
||||||
|
@ -3,6 +3,8 @@ package api
|
|||||||
import (
|
import (
|
||||||
"github.com/grafana/grafana/pkg/api/dtos"
|
"github.com/grafana/grafana/pkg/api/dtos"
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
|
"github.com/grafana/grafana/pkg/events"
|
||||||
|
"github.com/grafana/grafana/pkg/metrics"
|
||||||
"github.com/grafana/grafana/pkg/middleware"
|
"github.com/grafana/grafana/pkg/middleware"
|
||||||
m "github.com/grafana/grafana/pkg/models"
|
m "github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
@ -85,8 +87,7 @@ func AddOrgInvite(c *middleware.Context, inviteDto dtos.AddInviteForm) Response
|
|||||||
|
|
||||||
func RevokeInvite(c *middleware.Context) Response {
|
func RevokeInvite(c *middleware.Context) Response {
|
||||||
cmd := m.UpdateTempUserStatusCommand{
|
cmd := m.UpdateTempUserStatusCommand{
|
||||||
Id: c.ParamsInt64(":id"),
|
Code: c.Params(":code"),
|
||||||
OrgId: c.OrgId,
|
|
||||||
Status: m.TmpUserRevoked,
|
Status: m.TmpUserRevoked,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +99,7 @@ func RevokeInvite(c *middleware.Context) Response {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetInviteInfoByCode(c *middleware.Context) Response {
|
func GetInviteInfoByCode(c *middleware.Context) Response {
|
||||||
query := m.GetTempUsersByCodeQuery{Code: c.Params(":code")}
|
query := m.GetTempUserByCodeQuery{Code: c.Params(":code")}
|
||||||
|
|
||||||
if err := bus.Dispatch(&query); err != nil {
|
if err := bus.Dispatch(&query); err != nil {
|
||||||
if err == m.ErrTempUserNotFound {
|
if err == m.ErrTempUserNotFound {
|
||||||
@ -115,3 +116,48 @@ func GetInviteInfoByCode(c *middleware.Context) Response {
|
|||||||
|
|
||||||
return Json(200, &info)
|
return Json(200, &info)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CompleteInvite(c *middleware.Context, completeInvite dtos.CompleteInviteForm) Response {
|
||||||
|
query := m.GetTempUserByCodeQuery{Code: completeInvite.InviteCode}
|
||||||
|
|
||||||
|
if err := bus.Dispatch(&query); err != nil {
|
||||||
|
if err == m.ErrTempUserNotFound {
|
||||||
|
return ApiError(404, "Invite not found", nil)
|
||||||
|
}
|
||||||
|
return ApiError(500, "Failed to get invite", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
invite := query.Result
|
||||||
|
|
||||||
|
cmd := m.CreateUserCommand{
|
||||||
|
Email: completeInvite.Email,
|
||||||
|
Name: completeInvite.Name,
|
||||||
|
Login: completeInvite.Username,
|
||||||
|
Password: completeInvite.Password,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := bus.Dispatch(&cmd); err != nil {
|
||||||
|
return ApiError(500, "failed to create user", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
user := cmd.Result
|
||||||
|
|
||||||
|
bus.Publish(&events.UserSignedUp{
|
||||||
|
Id: user.Id,
|
||||||
|
Name: user.Name,
|
||||||
|
Email: user.Email,
|
||||||
|
Login: user.Login,
|
||||||
|
})
|
||||||
|
|
||||||
|
// update temp user status
|
||||||
|
updateTmpUserCmd := m.UpdateTempUserStatusCommand{Code: invite.Code, Status: m.TmpUserCompleted}
|
||||||
|
if err := bus.Dispatch(&updateTmpUserCmd); err != nil {
|
||||||
|
return ApiError(500, "Failed to update invite status", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
loginUserWithUser(&user, c)
|
||||||
|
|
||||||
|
metrics.M_Api_User_SignUp.Inc(1)
|
||||||
|
|
||||||
|
return ApiSuccess("User created and logged in")
|
||||||
|
}
|
||||||
|
@ -56,8 +56,7 @@ type CreateTempUserCommand struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type UpdateTempUserStatusCommand struct {
|
type UpdateTempUserStatusCommand struct {
|
||||||
Id int64
|
Code string
|
||||||
OrgId int64
|
|
||||||
Status TempUserStatus
|
Status TempUserStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +67,7 @@ type GetTempUsersForOrgQuery struct {
|
|||||||
Result []*TempUserDTO
|
Result []*TempUserDTO
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetTempUsersByCodeQuery struct {
|
type GetTempUserByCodeQuery struct {
|
||||||
Code string
|
Code string
|
||||||
|
|
||||||
Result *TempUser
|
Result *TempUser
|
||||||
|
@ -12,13 +12,13 @@ func init() {
|
|||||||
bus.AddHandler("sql", CreateTempUser)
|
bus.AddHandler("sql", CreateTempUser)
|
||||||
bus.AddHandler("sql", GetTempUsersForOrg)
|
bus.AddHandler("sql", GetTempUsersForOrg)
|
||||||
bus.AddHandler("sql", UpdateTempUserStatus)
|
bus.AddHandler("sql", UpdateTempUserStatus)
|
||||||
bus.AddHandler("sql", GetTempUsersByCode)
|
bus.AddHandler("sql", GetTempUserByCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateTempUserStatus(cmd *m.UpdateTempUserStatusCommand) error {
|
func UpdateTempUserStatus(cmd *m.UpdateTempUserStatusCommand) error {
|
||||||
return inTransaction(func(sess *xorm.Session) error {
|
return inTransaction(func(sess *xorm.Session) error {
|
||||||
var rawSql = "UPDATE temp_user SET status=? WHERE id=? and org_id=?"
|
var rawSql = "UPDATE temp_user SET status=? WHERE code=?"
|
||||||
_, err := sess.Exec(rawSql, string(cmd.Status), cmd.Id, cmd.OrgId)
|
_, err := sess.Exec(rawSql, string(cmd.Status), cmd.Code)
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -70,7 +70,7 @@ func GetTempUsersForOrg(query *m.GetTempUsersForOrgQuery) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetTempUsersByCode(query *m.GetTempUsersByCodeQuery) error {
|
func GetTempUserByCode(query *m.GetTempUserByCodeQuery) error {
|
||||||
var user m.TempUser
|
var user m.TempUser
|
||||||
has, err := x.Table("temp_user").Where("code=?", query.Code).Get(&user)
|
has, err := x.Table("temp_user").Where("code=?", query.Code).Get(&user)
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ func TestTempUserCommandsAndQueries(t *testing.T) {
|
|||||||
cmd := m.CreateTempUserCommand{
|
cmd := m.CreateTempUserCommand{
|
||||||
OrgId: 2256,
|
OrgId: 2256,
|
||||||
Name: "hello",
|
Name: "hello",
|
||||||
|
Code: "asd",
|
||||||
Email: "e@as.co",
|
Email: "e@as.co",
|
||||||
Status: m.TmpUserInvitePending,
|
Status: m.TmpUserInvitePending,
|
||||||
}
|
}
|
||||||
@ -32,7 +33,7 @@ func TestTempUserCommandsAndQueries(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
Convey("Should be able update status", func() {
|
Convey("Should be able update status", func() {
|
||||||
cmd2 := m.UpdateTempUserStatusCommand{OrgId: 2256, Status: m.TmpUserRevoked, Id: cmd.Result.Id}
|
cmd2 := m.UpdateTempUserStatusCommand{Code: "asd", Status: m.TmpUserRevoked}
|
||||||
err := UpdateTempUserStatus(&cmd2)
|
err := UpdateTempUserStatus(&cmd2)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
})
|
})
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
define([
|
define([
|
||||||
'angular',
|
'angular',
|
||||||
|
'config',
|
||||||
],
|
],
|
||||||
function (angular) {
|
function (angular, config) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var module = angular.module('grafana.controllers');
|
var module = angular.module('grafana.controllers');
|
||||||
@ -10,20 +11,27 @@ function (angular) {
|
|||||||
|
|
||||||
contextSrv.sidemenu = false;
|
contextSrv.sidemenu = false;
|
||||||
|
|
||||||
$scope.user = {};
|
$scope.formModel = {};
|
||||||
|
|
||||||
$scope.init = function() {
|
$scope.init = function() {
|
||||||
backendSrv.get('/api/user/invite/' + $routeParams.code).then(function(invite) {
|
backendSrv.get('/api/user/invite/' + $routeParams.code).then(function(invite) {
|
||||||
$scope.user.name = invite.name;
|
$scope.formModel.name = invite.name;
|
||||||
$scope.user.email = invite.email;
|
$scope.formModel.email = invite.email;
|
||||||
$scope.user.username = invite.email;
|
$scope.formModel.username = invite.email;
|
||||||
$scope.user.inviteId = invite.id;
|
$scope.formModel.inviteCode = $routeParams.code;
|
||||||
|
|
||||||
$scope.greeting = invite.name || invite.email;
|
$scope.greeting = invite.name || invite.email;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.submit = function() {
|
$scope.submit = function() {
|
||||||
|
if (!$scope.inviteForm.$valid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
backendSrv.post('/api/user/invite/complete', $scope.formModel).then(function() {
|
||||||
|
window.location.href = config.appSubUrl + '/';
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.init();
|
$scope.init();
|
||||||
|
@ -40,7 +40,7 @@ function (angular) {
|
|||||||
|
|
||||||
$scope.revokeInvite = function(invite, evt) {
|
$scope.revokeInvite = function(invite, evt) {
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
backendSrv.patch('/api/org/invites/' + invite.id + '/revoke').then($scope.get);
|
backendSrv.patch('/api/org/invites/' + invite.code + '/revoke').then($scope.get);
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.copyInviteToClipboard = function(evt) {
|
$scope.copyInviteToClipboard = function(evt) {
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
Email
|
Email
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<input type="email" name="email" class="tight-form-input last" required ng-model='user.email' placeholder="Email" style="width: 253px">
|
<input type="email" name="email" class="tight-form-input last" required ng-model='formModel.email' placeholder="Email" style="width: 253px">
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
@ -38,7 +38,7 @@
|
|||||||
Name
|
Name
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<input type="text" name="name" class="tight-form-input last" ng-model='user.name' placeholder="Name (optional)" style="width: 253px">
|
<input type="text" name="name" class="tight-form-input last" ng-model='formModel.name' placeholder="Name (optional)" style="width: 253px">
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
@ -49,7 +49,7 @@
|
|||||||
Username
|
Username
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<input type="text" name="username" class="tight-form-input last" required ng-model='user.username' placeholder="Username" style="width: 253px">
|
<input type="text" name="username" class="tight-form-input last" required ng-model='formModel.username' placeholder="Username" style="width: 253px">
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
@ -61,7 +61,7 @@
|
|||||||
Password
|
Password
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<input type="password" name="password" class="tight-form-input last" required ng-model="user.password" id="inputPassword" style="width: 253px" placeholder="password">
|
<input type="password" name="password" class="tight-form-input last" required ng-model="formModel.password" id="inputPassword" style="width: 253px" placeholder="password">
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
@ -72,7 +72,7 @@
|
|||||||
Confirm Password
|
Confirm Password
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<input type="password" name="confirmPassword" class="tight-form-input last" required ng-model="user.confirmPassword" id="confirmPassword" style="width: 253px" placeholder="confirm password">
|
<input type="password" name="confirmPassword" class="tight-form-input last" required ng-model="formModel.confirmPassword" id="confirmPassword" style="width: 253px" placeholder="confirm password">
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
@ -80,7 +80,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="margin-left: 147px; width: 254px;">
|
<div style="margin-left: 147px; width: 254px;">
|
||||||
<password-strength password="user.password"></password-strength>
|
<password-strength password="formModel.password"></password-strength>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="login-submit-button-row">
|
<div class="login-submit-button-row">
|
||||||
|
Reference in New Issue
Block a user