repo_collaboration.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. // Copyright 2015 The Gogs Authors. All rights reserved.
  2. // Copyright 2018 Gitote. All rights reserved.
  3. //
  4. // This source code is licensed under the MIT license found in the
  5. // LICENSE file in the root directory of this source tree.
  6. package models
  7. import (
  8. "fmt"
  9. raven "github.com/getsentry/raven-go"
  10. api "gitlab.com/gitote/go-gitote-client"
  11. log "gopkg.in/clog.v1"
  12. )
  13. // Collaboration represent the relation between an individual and a repository.
  14. type Collaboration struct {
  15. ID int64
  16. RepoID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"`
  17. UserID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"`
  18. Mode AccessMode `xorm:"DEFAULT 2 NOT NULL"`
  19. }
  20. func (c *Collaboration) ModeI18nKey() string {
  21. switch c.Mode {
  22. case ACCESS_MODE_READ:
  23. return "repo.settings.collaboration.read"
  24. case ACCESS_MODE_WRITE:
  25. return "repo.settings.collaboration.write"
  26. case ACCESS_MODE_ADMIN:
  27. return "repo.settings.collaboration.admin"
  28. default:
  29. return "repo.settings.collaboration.undefined"
  30. }
  31. }
  32. // IsCollaborator returns true if the user is a collaborator of the repository.
  33. func IsCollaborator(repoID, userID int64) bool {
  34. collaboration := &Collaboration{
  35. RepoID: repoID,
  36. UserID: userID,
  37. }
  38. has, err := x.Get(collaboration)
  39. if err != nil {
  40. raven.CaptureErrorAndWait(err, nil)
  41. log.Error(2, "get collaboration [repo_id: %d, user_id: %d]: %v", repoID, userID, err)
  42. return false
  43. }
  44. return has
  45. }
  46. func (repo *Repository) IsCollaborator(userID int64) bool {
  47. return IsCollaborator(repo.ID, userID)
  48. }
  49. // AddCollaborator adds new collaboration to a repository with default access mode.
  50. func (repo *Repository) AddCollaborator(u *User) error {
  51. collaboration := &Collaboration{
  52. RepoID: repo.ID,
  53. UserID: u.ID,
  54. }
  55. has, err := x.Get(collaboration)
  56. if err != nil {
  57. return err
  58. } else if has {
  59. return nil
  60. }
  61. collaboration.Mode = ACCESS_MODE_WRITE
  62. sess := x.NewSession()
  63. defer sess.Close()
  64. if err = sess.Begin(); err != nil {
  65. return err
  66. }
  67. if _, err = sess.Insert(collaboration); err != nil {
  68. return err
  69. } else if err = repo.recalculateAccesses(sess); err != nil {
  70. return fmt.Errorf("recalculateAccesses [repo_id: %v]: %v", repo.ID, err)
  71. }
  72. return sess.Commit()
  73. }
  74. func (repo *Repository) getCollaborations(e Engine) ([]*Collaboration, error) {
  75. collaborations := make([]*Collaboration, 0)
  76. return collaborations, e.Find(&collaborations, &Collaboration{RepoID: repo.ID})
  77. }
  78. // Collaborator represents a user with collaboration details.
  79. type Collaborator struct {
  80. *User
  81. Collaboration *Collaboration
  82. }
  83. func (c *Collaborator) APIFormat() *api.Collaborator {
  84. return &api.Collaborator{
  85. User: c.User.APIFormat(),
  86. Permissions: api.Permission{
  87. Admin: c.Collaboration.Mode >= ACCESS_MODE_ADMIN,
  88. Push: c.Collaboration.Mode >= ACCESS_MODE_WRITE,
  89. Pull: c.Collaboration.Mode >= ACCESS_MODE_READ,
  90. },
  91. }
  92. }
  93. func (repo *Repository) getCollaborators(e Engine) ([]*Collaborator, error) {
  94. collaborations, err := repo.getCollaborations(e)
  95. if err != nil {
  96. return nil, fmt.Errorf("getCollaborations: %v", err)
  97. }
  98. collaborators := make([]*Collaborator, len(collaborations))
  99. for i, c := range collaborations {
  100. user, err := getUserByID(e, c.UserID)
  101. if err != nil {
  102. return nil, err
  103. }
  104. collaborators[i] = &Collaborator{
  105. User: user,
  106. Collaboration: c,
  107. }
  108. }
  109. return collaborators, nil
  110. }
  111. // GetCollaborators returns the collaborators for a repository
  112. func (repo *Repository) GetCollaborators() ([]*Collaborator, error) {
  113. return repo.getCollaborators(x)
  114. }
  115. // ChangeCollaborationAccessMode sets new access mode for the collaboration.
  116. func (repo *Repository) ChangeCollaborationAccessMode(userID int64, mode AccessMode) error {
  117. // Discard invalid input
  118. if mode <= ACCESS_MODE_NONE || mode > ACCESS_MODE_OWNER {
  119. return nil
  120. }
  121. collaboration := &Collaboration{
  122. RepoID: repo.ID,
  123. UserID: userID,
  124. }
  125. has, err := x.Get(collaboration)
  126. if err != nil {
  127. return fmt.Errorf("get collaboration: %v", err)
  128. } else if !has {
  129. return nil
  130. }
  131. if collaboration.Mode == mode {
  132. return nil
  133. }
  134. collaboration.Mode = mode
  135. // If it's an organizational repository, merge with team access level for highest permission
  136. if repo.Owner.IsOrganization() {
  137. teams, err := GetUserTeams(repo.OwnerID, userID)
  138. if err != nil {
  139. return fmt.Errorf("GetUserTeams: [org_id: %d, user_id: %d]: %v", repo.OwnerID, userID, err)
  140. }
  141. for i := range teams {
  142. if mode < teams[i].Authorize {
  143. mode = teams[i].Authorize
  144. }
  145. }
  146. }
  147. sess := x.NewSession()
  148. defer sess.Close()
  149. if err = sess.Begin(); err != nil {
  150. return err
  151. }
  152. if _, err = sess.ID(collaboration.ID).AllCols().Update(collaboration); err != nil {
  153. return fmt.Errorf("update collaboration: %v", err)
  154. }
  155. access := &Access{
  156. UserID: userID,
  157. RepoID: repo.ID,
  158. }
  159. has, err = sess.Get(access)
  160. if err != nil {
  161. return fmt.Errorf("get access record: %v", err)
  162. }
  163. if has {
  164. _, err = sess.Exec("UPDATE access SET mode = ? WHERE user_id = ? AND repo_id = ?", mode, userID, repo.ID)
  165. } else {
  166. access.Mode = mode
  167. _, err = sess.Insert(access)
  168. }
  169. if err != nil {
  170. return fmt.Errorf("update/insert access table: %v", err)
  171. }
  172. return sess.Commit()
  173. }
  174. // DeleteCollaboration removes collaboration relation between the user and repository.
  175. func DeleteCollaboration(repo *Repository, userID int64) (err error) {
  176. if !IsCollaborator(repo.ID, userID) {
  177. return nil
  178. }
  179. collaboration := &Collaboration{
  180. RepoID: repo.ID,
  181. UserID: userID,
  182. }
  183. sess := x.NewSession()
  184. defer sess.Close()
  185. if err = sess.Begin(); err != nil {
  186. return err
  187. }
  188. if has, err := sess.Delete(collaboration); err != nil || has == 0 {
  189. return err
  190. } else if err = repo.recalculateAccesses(sess); err != nil {
  191. return err
  192. }
  193. return sess.Commit()
  194. }
  195. func (repo *Repository) DeleteCollaboration(userID int64) error {
  196. return DeleteCollaboration(repo, userID)
  197. }