org_invite.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. package api
  2. import (
  3. "fmt"
  4. "github.com/grafana/grafana/pkg/api/dtos"
  5. "github.com/grafana/grafana/pkg/bus"
  6. "github.com/grafana/grafana/pkg/events"
  7. "github.com/grafana/grafana/pkg/metrics"
  8. "github.com/grafana/grafana/pkg/middleware"
  9. m "github.com/grafana/grafana/pkg/models"
  10. "github.com/grafana/grafana/pkg/setting"
  11. "github.com/grafana/grafana/pkg/util"
  12. )
  13. func GetPendingOrgInvites(c *middleware.Context) Response {
  14. query := m.GetTempUsersForOrgQuery{OrgId: c.OrgId, Status: m.TmpUserInvitePending}
  15. if err := bus.Dispatch(&query); err != nil {
  16. return ApiError(500, "Failed to get invites from db", err)
  17. }
  18. for _, invite := range query.Result {
  19. invite.Url = setting.ToAbsUrl("invite/" + invite.Code)
  20. }
  21. return Json(200, query.Result)
  22. }
  23. func AddOrgInvite(c *middleware.Context, inviteDto dtos.AddInviteForm) Response {
  24. if !inviteDto.Role.IsValid() {
  25. return ApiError(400, "Invalid role specified", nil)
  26. }
  27. // first try get existing user
  28. userQuery := m.GetUserByLoginQuery{LoginOrEmail: inviteDto.LoginOrEmail}
  29. if err := bus.Dispatch(&userQuery); err != nil {
  30. if err != m.ErrUserNotFound {
  31. return ApiError(500, "Failed to query db for existing user check", err)
  32. }
  33. } else {
  34. // user exists, add org role
  35. createOrgUserCmd := m.AddOrgUserCommand{OrgId: c.OrgId, UserId: userQuery.Result.Id, Role: inviteDto.Role}
  36. if err := bus.Dispatch(&createOrgUserCmd); err != nil {
  37. if err == m.ErrOrgUserAlreadyAdded {
  38. return ApiError(412, fmt.Sprintf("User %s is already added to organization", inviteDto.LoginOrEmail), err)
  39. }
  40. return ApiError(500, "Error while trying to create org user", err)
  41. } else {
  42. return ApiSuccess(fmt.Sprintf("Existing Grafana user %s added to org %s", userQuery.Result.NameOrFallback(), c.OrgName))
  43. }
  44. }
  45. cmd := m.CreateTempUserCommand{}
  46. cmd.OrgId = c.OrgId
  47. cmd.Email = inviteDto.LoginOrEmail
  48. cmd.Name = inviteDto.Name
  49. cmd.Status = m.TmpUserInvitePending
  50. cmd.InvitedByUserId = c.UserId
  51. cmd.Code = util.GetRandomString(30)
  52. cmd.Role = inviteDto.Role
  53. cmd.RemoteAddr = c.Req.RemoteAddr
  54. if err := bus.Dispatch(&cmd); err != nil {
  55. return ApiError(500, "Failed to save invite to database", err)
  56. }
  57. // send invite email
  58. if !inviteDto.SkipEmails && util.IsEmail(inviteDto.LoginOrEmail) {
  59. emailCmd := m.SendEmailCommand{
  60. To: []string{inviteDto.LoginOrEmail},
  61. Template: "new_user_invite.html",
  62. Data: map[string]interface{}{
  63. "NameOrEmail": util.StringsFallback2(cmd.Name, cmd.Email),
  64. "OrgName": c.OrgName,
  65. "Email": c.Email,
  66. "LinkUrl": setting.ToAbsUrl("invite/" + cmd.Code),
  67. "InvitedBy": util.StringsFallback3(c.Name, c.Email, c.Login),
  68. },
  69. }
  70. if err := bus.Dispatch(&emailCmd); err != nil {
  71. return ApiError(500, "Failed to send email invite", err)
  72. }
  73. return ApiSuccess(fmt.Sprintf("Sent invite to %s", inviteDto.LoginOrEmail))
  74. }
  75. return ApiSuccess(fmt.Sprintf("Created invite for %s", inviteDto.LoginOrEmail))
  76. }
  77. func RevokeInvite(c *middleware.Context) Response {
  78. cmd := m.UpdateTempUserStatusCommand{
  79. Code: c.Params(":code"),
  80. Status: m.TmpUserRevoked,
  81. }
  82. if err := bus.Dispatch(&cmd); err != nil {
  83. return ApiError(500, "Failed to update invite status", err)
  84. }
  85. return ApiSuccess("Invite revoked")
  86. }
  87. func GetInviteInfoByCode(c *middleware.Context) Response {
  88. query := m.GetTempUserByCodeQuery{Code: c.Params(":code")}
  89. if err := bus.Dispatch(&query); err != nil {
  90. if err == m.ErrTempUserNotFound {
  91. return ApiError(404, "Invite not found", nil)
  92. }
  93. return ApiError(500, "Failed to get invite", err)
  94. }
  95. invite := query.Result
  96. return Json(200, dtos.InviteInfo{
  97. Email: invite.Email,
  98. Name: invite.Name,
  99. Username: invite.Email,
  100. InvitedBy: util.StringsFallback3(invite.InvitedByName, invite.InvitedByLogin, invite.InvitedByEmail),
  101. })
  102. }
  103. func CompleteInvite(c *middleware.Context, completeInvite dtos.CompleteInviteForm) Response {
  104. query := m.GetTempUserByCodeQuery{Code: completeInvite.InviteCode}
  105. if err := bus.Dispatch(&query); err != nil {
  106. if err == m.ErrTempUserNotFound {
  107. return ApiError(404, "Invite not found", nil)
  108. }
  109. return ApiError(500, "Failed to get invite", err)
  110. }
  111. invite := query.Result
  112. if invite.Status != m.TmpUserInvitePending {
  113. return ApiError(412, fmt.Sprintf("Invite cannot be used in status %s", invite.Status), nil)
  114. }
  115. cmd := m.CreateUserCommand{
  116. Email: completeInvite.Email,
  117. Name: completeInvite.Name,
  118. Login: completeInvite.Username,
  119. Password: completeInvite.Password,
  120. }
  121. if err := bus.Dispatch(&cmd); err != nil {
  122. return ApiError(500, "failed to create user", err)
  123. }
  124. user := cmd.Result
  125. bus.Publish(&events.UserSignedUp{
  126. Id: user.Id,
  127. Name: user.Name,
  128. Email: user.Email,
  129. Login: user.Login,
  130. })
  131. // update temp user status
  132. updateTmpUserCmd := m.UpdateTempUserStatusCommand{Code: invite.Code, Status: m.TmpUserCompleted}
  133. if err := bus.Dispatch(&updateTmpUserCmd); err != nil {
  134. return ApiError(500, "Failed to update invite status", err)
  135. }
  136. loginUserWithUser(&user, c)
  137. metrics.M_Api_User_SignUp.Inc(1)
  138. metrics.M_Api_User_SignUpInvite.Inc(1)
  139. return ApiSuccess("User created and logged in")
  140. }