accept.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. //go:build ee
  2. // +build ee
  3. package invite
  4. import (
  5. "errors"
  6. "fmt"
  7. "net/http"
  8. "net/url"
  9. "github.com/porter-dev/porter/api/server/handlers"
  10. "github.com/porter-dev/porter/api/server/shared/apierrors"
  11. "github.com/porter-dev/porter/api/server/shared/config"
  12. "github.com/porter-dev/porter/api/server/shared/requestutils"
  13. "github.com/porter-dev/porter/api/types"
  14. "github.com/porter-dev/porter/internal/models"
  15. "github.com/porter-dev/porter/internal/repository"
  16. "gorm.io/gorm"
  17. )
  18. type InviteAcceptHandler struct {
  19. handlers.PorterHandler
  20. }
  21. func NewInviteAcceptHandler(
  22. config *config.Config,
  23. ) http.Handler {
  24. return &InviteAcceptHandler{
  25. PorterHandler: handlers.NewDefaultPorterHandler(config, nil, nil),
  26. }
  27. }
  28. func (c *InviteAcceptHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  29. user, _ := r.Context().Value(types.UserScope).(*models.User)
  30. projectID, _ := requestutils.GetURLParamUint(r, types.URLParamProjectID)
  31. token, _ := requestutils.GetURLParamString(r, types.URLParamInviteToken)
  32. proj, err := c.Repo().Project().ReadProject(projectID)
  33. if err != nil {
  34. vals := url.Values{}
  35. if errors.Is(err, gorm.ErrRecordNotFound) {
  36. vals.Add("error", "Invalid invite token")
  37. } else {
  38. vals.Add("error", "Unknown error")
  39. }
  40. http.Redirect(w, r, fmt.Sprintf("/dashboard?%s", vals.Encode()), 302)
  41. return
  42. }
  43. invite, err := c.Repo().Invite().ReadInviteByToken(token)
  44. if err != nil || invite.ProjectID != proj.ID {
  45. vals := url.Values{}
  46. vals.Add("error", "Invalid invite token")
  47. http.Redirect(w, r, fmt.Sprintf("/dashboard?%s", vals.Encode()), 302)
  48. return
  49. }
  50. // check that the invite has not expired and has not been accepted
  51. if invite.IsExpired() || invite.IsAccepted() {
  52. vals := url.Values{}
  53. vals.Add("error", "Invite has expired")
  54. http.Redirect(w, r, fmt.Sprintf("/dashboard?%s", vals.Encode()), 302)
  55. return
  56. }
  57. // check that the invite email matches the user's email
  58. if user.Email != invite.Email {
  59. vals := url.Values{}
  60. vals.Add("error", "Wrong email for invite")
  61. http.Redirect(w, r, fmt.Sprintf("/dashboard?%s", vals.Encode()), 302)
  62. return
  63. }
  64. inviteType := invite.ToInviteType()
  65. if len(inviteType.Roles) > 0 {
  66. for _, roleUID := range inviteType.Roles {
  67. err := updateProjectRoleWithUser(c.Repo(), proj.ID, user.ID, roleUID)
  68. if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
  69. c.HandleAPIError(w, r, apierrors.NewErrNotFound(fmt.Errorf("no such role exists")))
  70. return
  71. } else if err != nil {
  72. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  73. return
  74. }
  75. }
  76. } else { // legacy operation
  77. kind := invite.Kind
  78. if kind == "" {
  79. kind = models.RoleDeveloper
  80. }
  81. err := updateProjectRoleWithUser(c.Repo(), proj.ID, user.ID, fmt.Sprintf("%d-%s", proj.ID, kind))
  82. if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
  83. c.HandleAPIError(w, r, apierrors.NewErrNotFound(fmt.Errorf("no such role exists")))
  84. return
  85. } else if err != nil {
  86. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  87. return
  88. }
  89. }
  90. // update the invite
  91. invite.UserID = user.ID
  92. if _, err = c.Repo().Invite().UpdateInvite(invite); err != nil {
  93. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  94. return
  95. }
  96. http.Redirect(w, r, "/dashboard", 302)
  97. }
  98. func updateProjectRoleWithUser(repo repository.Repository, projectID, userID uint, projectRoleUID string) error {
  99. role, err := repo.ProjectRole().ReadProjectRole(projectID, projectRoleUID)
  100. if err != nil {
  101. return err
  102. }
  103. userAlreadyInRole := false
  104. var userIDs []uint
  105. for _, u := range role.Users {
  106. if u.ID == userID {
  107. userAlreadyInRole = true
  108. break
  109. }
  110. userIDs = append(userIDs, u.ID)
  111. }
  112. if !userAlreadyInRole {
  113. userIDs = append(userIDs, userID)
  114. err := repo.ProjectRole().UpdateUsersInProjectRole(projectID, role.UniqueID, userIDs)
  115. if err != nil {
  116. return err
  117. }
  118. }
  119. return nil
  120. }