From ab54971763ce5cb20408077a789dd52c1647c5e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 20 Jul 2015 17:46:48 +0200 Subject: [PATCH] feat(invite): more progress on completing invite form and actually creating a real user, #2353 --- pkg/api/api.go | 3 +- pkg/api/dtos/invite.go | 9 +++++ pkg/api/org_invite.go | 52 +++++++++++++++++++++++-- pkg/models/temp_user.go | 5 +-- pkg/services/sqlstore/temp_user.go | 8 ++-- pkg/services/sqlstore/temp_user_test.go | 3 +- public/app/controllers/invitedCtrl.js | 20 +++++++--- public/app/features/org/orgUsersCtrl.js | 2 +- public/app/partials/signup_invited.html | 12 +++--- 9 files changed, 89 insertions(+), 25 deletions(-) diff --git a/pkg/api/api.go b/pkg/api/api.go index a2957ce44ae..6e8fe57fddf 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -45,6 +45,7 @@ func Register(r *macaron.Macaron) { // invited r.Get("/api/user/invite/:code", wrap(GetInviteInfoByCode)) + r.Post("/api/user/invite/complete", bind(dtos.CompleteInviteForm{}), wrap(CompleteInvite)) // reset password r.Get("/user/password/send-reset-email", Index) @@ -97,7 +98,7 @@ func Register(r *macaron.Macaron) { // invites r.Get("/invites", wrap(GetPendingOrgInvites)) r.Post("/invites", bind(dtos.AddInviteForm{}), wrap(AddOrgInvite)) - r.Patch("/invites/:id/revoke", wrap(RevokeInvite)) + r.Patch("/invites/:code/revoke", wrap(RevokeInvite)) }, regOrgAdmin) // create new org diff --git a/pkg/api/dtos/invite.go b/pkg/api/dtos/invite.go index c9bc5b3bd6b..bc674aa2a75 100644 --- a/pkg/api/dtos/invite.go +++ b/pkg/api/dtos/invite.go @@ -14,3 +14,12 @@ type InviteInfo struct { Name string `json:"name"` 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"` +} diff --git a/pkg/api/org_invite.go b/pkg/api/org_invite.go index e1baa97d329..e3812e726e8 100644 --- a/pkg/api/org_invite.go +++ b/pkg/api/org_invite.go @@ -3,6 +3,8 @@ package api import ( "github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/events" + "github.com/grafana/grafana/pkg/metrics" "github.com/grafana/grafana/pkg/middleware" m "github.com/grafana/grafana/pkg/models" "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 { cmd := m.UpdateTempUserStatusCommand{ - Id: c.ParamsInt64(":id"), - OrgId: c.OrgId, + Code: c.Params(":code"), Status: m.TmpUserRevoked, } @@ -98,7 +99,7 @@ func RevokeInvite(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 == m.ErrTempUserNotFound { @@ -115,3 +116,48 @@ func GetInviteInfoByCode(c *middleware.Context) Response { 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") +} diff --git a/pkg/models/temp_user.go b/pkg/models/temp_user.go index 04db0053827..cf20517921c 100644 --- a/pkg/models/temp_user.go +++ b/pkg/models/temp_user.go @@ -56,8 +56,7 @@ type CreateTempUserCommand struct { } type UpdateTempUserStatusCommand struct { - Id int64 - OrgId int64 + Code string Status TempUserStatus } @@ -68,7 +67,7 @@ type GetTempUsersForOrgQuery struct { Result []*TempUserDTO } -type GetTempUsersByCodeQuery struct { +type GetTempUserByCodeQuery struct { Code string Result *TempUser diff --git a/pkg/services/sqlstore/temp_user.go b/pkg/services/sqlstore/temp_user.go index dde4bb286d4..0931cd2b1df 100644 --- a/pkg/services/sqlstore/temp_user.go +++ b/pkg/services/sqlstore/temp_user.go @@ -12,13 +12,13 @@ func init() { bus.AddHandler("sql", CreateTempUser) bus.AddHandler("sql", GetTempUsersForOrg) bus.AddHandler("sql", UpdateTempUserStatus) - bus.AddHandler("sql", GetTempUsersByCode) + bus.AddHandler("sql", GetTempUserByCode) } func UpdateTempUserStatus(cmd *m.UpdateTempUserStatusCommand) error { return inTransaction(func(sess *xorm.Session) error { - var rawSql = "UPDATE temp_user SET status=? WHERE id=? and org_id=?" - _, err := sess.Exec(rawSql, string(cmd.Status), cmd.Id, cmd.OrgId) + var rawSql = "UPDATE temp_user SET status=? WHERE code=?" + _, err := sess.Exec(rawSql, string(cmd.Status), cmd.Code) return err }) } @@ -70,7 +70,7 @@ func GetTempUsersForOrg(query *m.GetTempUsersForOrgQuery) error { return err } -func GetTempUsersByCode(query *m.GetTempUsersByCodeQuery) error { +func GetTempUserByCode(query *m.GetTempUserByCodeQuery) error { var user m.TempUser has, err := x.Table("temp_user").Where("code=?", query.Code).Get(&user) diff --git a/pkg/services/sqlstore/temp_user_test.go b/pkg/services/sqlstore/temp_user_test.go index c7c599b3db4..ad3681c2071 100644 --- a/pkg/services/sqlstore/temp_user_test.go +++ b/pkg/services/sqlstore/temp_user_test.go @@ -17,6 +17,7 @@ func TestTempUserCommandsAndQueries(t *testing.T) { cmd := m.CreateTempUserCommand{ OrgId: 2256, Name: "hello", + Code: "asd", Email: "e@as.co", Status: m.TmpUserInvitePending, } @@ -32,7 +33,7 @@ func TestTempUserCommandsAndQueries(t *testing.T) { }) 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) So(err, ShouldBeNil) }) diff --git a/public/app/controllers/invitedCtrl.js b/public/app/controllers/invitedCtrl.js index d5bfa22895a..e3e36d56463 100644 --- a/public/app/controllers/invitedCtrl.js +++ b/public/app/controllers/invitedCtrl.js @@ -1,7 +1,8 @@ define([ 'angular', + 'config', ], -function (angular) { +function (angular, config) { 'use strict'; var module = angular.module('grafana.controllers'); @@ -10,20 +11,27 @@ function (angular) { contextSrv.sidemenu = false; - $scope.user = {}; + $scope.formModel = {}; $scope.init = function() { backendSrv.get('/api/user/invite/' + $routeParams.code).then(function(invite) { - $scope.user.name = invite.name; - $scope.user.email = invite.email; - $scope.user.username = invite.email; - $scope.user.inviteId = invite.id; + $scope.formModel.name = invite.name; + $scope.formModel.email = invite.email; + $scope.formModel.username = invite.email; + $scope.formModel.inviteCode = $routeParams.code; $scope.greeting = invite.name || invite.email; }); }; $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(); diff --git a/public/app/features/org/orgUsersCtrl.js b/public/app/features/org/orgUsersCtrl.js index 9ea34127906..3d3e4d26ec3 100644 --- a/public/app/features/org/orgUsersCtrl.js +++ b/public/app/features/org/orgUsersCtrl.js @@ -40,7 +40,7 @@ function (angular) { $scope.revokeInvite = function(invite, evt) { 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) { diff --git a/public/app/partials/signup_invited.html b/public/app/partials/signup_invited.html index 6c896b3f249..d248df6527b 100644 --- a/public/app/partials/signup_invited.html +++ b/public/app/partials/signup_invited.html @@ -27,7 +27,7 @@ Email
  • - +
  • @@ -38,7 +38,7 @@ Name
  • - +
  • @@ -49,7 +49,7 @@ Username
  • - +
  • @@ -61,7 +61,7 @@ Password
  • - +
  • @@ -72,7 +72,7 @@ Confirm Password
  • - +
  • @@ -80,7 +80,7 @@
    - +