You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

access.go 4.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package models
  5. type AccessMode int
  6. const (
  7. ACCESS_MODE_NONE AccessMode = iota
  8. ACCESS_MODE_READ
  9. ACCESS_MODE_WRITE
  10. ACCESS_MODE_ADMIN
  11. ACCESS_MODE_OWNER
  12. )
  13. // Access represents the highest access level of a user to the repository. The only access type
  14. // that is not in this table is the real owner of a repository. In case of an organization
  15. // repository, the members of the owners team are in this table.
  16. type Access struct {
  17. ID int64 `xorm:"pk autoincr"`
  18. UserID int64 `xorm:"UNIQUE(s)"`
  19. RepoID int64 `xorm:"UNIQUE(s)"`
  20. Mode AccessMode
  21. }
  22. func accessLevel(e Engine, u *User, repo *Repository) (AccessMode, error) {
  23. mode := ACCESS_MODE_NONE
  24. if !repo.IsPrivate {
  25. mode = ACCESS_MODE_READ
  26. }
  27. if u != nil {
  28. if u.Id == repo.OwnerId {
  29. return ACCESS_MODE_OWNER, nil
  30. }
  31. a := &Access{UserID: u.Id, RepoID: repo.Id}
  32. if has, err := e.Get(a); !has || err != nil {
  33. return mode, err
  34. }
  35. return a.Mode, nil
  36. }
  37. return mode, nil
  38. }
  39. // AccessLevel returns the Access a user has to a repository. Will return NoneAccess if the
  40. // user does not have access. User can be nil!
  41. func AccessLevel(u *User, repo *Repository) (AccessMode, error) {
  42. return accessLevel(x, u, repo)
  43. }
  44. func hasAccess(e Engine, u *User, repo *Repository, testMode AccessMode) (bool, error) {
  45. mode, err := accessLevel(e, u, repo)
  46. return testMode <= mode, err
  47. }
  48. // HasAccess returns true if someone has the request access level. User can be nil!
  49. func HasAccess(u *User, repo *Repository, testMode AccessMode) (bool, error) {
  50. return hasAccess(x, u, repo, testMode)
  51. }
  52. // GetAccessibleRepositories finds all repositories where a user has access to,
  53. // besides his own.
  54. func (u *User) GetAccessibleRepositories() (map[*Repository]AccessMode, error) {
  55. accesses := make([]*Access, 0, 10)
  56. if err := x.Find(&accesses, &Access{UserID: u.Id}); err != nil {
  57. return nil, err
  58. }
  59. repos := make(map[*Repository]AccessMode, len(accesses))
  60. for _, access := range accesses {
  61. repo, err := GetRepositoryById(access.RepoID)
  62. if err != nil {
  63. return nil, err
  64. }
  65. if err = repo.GetOwner(); err != nil {
  66. return nil, err
  67. } else if repo.OwnerId == u.Id {
  68. continue
  69. }
  70. repos[repo] = access.Mode
  71. }
  72. return repos, nil
  73. }
  74. func maxAccessMode(modes ...AccessMode) AccessMode {
  75. max := ACCESS_MODE_NONE
  76. for _, mode := range modes {
  77. if mode > max {
  78. max = mode
  79. }
  80. }
  81. return max
  82. }
  83. func (repo *Repository) recalculateTeamAccesses(e Engine, mode AccessMode) error {
  84. return nil
  85. }
  86. func (repo *Repository) recalculateAccesses(e Engine) error {
  87. accessMap := make(map[int64]AccessMode, 20)
  88. // FIXME: should be able to have read-only access.
  89. // Give all collaborators write access.
  90. collaborators, err := repo.getCollaborators(e)
  91. if err != nil {
  92. return err
  93. }
  94. for _, c := range collaborators {
  95. accessMap[c.Id] = ACCESS_MODE_WRITE
  96. }
  97. if err := repo.getOwner(e); err != nil {
  98. return err
  99. }
  100. if repo.Owner.IsOrganization() {
  101. if err = repo.Owner.getTeams(e); err != nil {
  102. return err
  103. }
  104. for _, team := range repo.Owner.Teams {
  105. if team.IsOwnerTeam() {
  106. team.Authorize = ACCESS_MODE_OWNER
  107. }
  108. if err = team.getMembers(e); err != nil {
  109. return err
  110. }
  111. for _, u := range team.Members {
  112. accessMap[u.Id] = maxAccessMode(accessMap[u.Id], team.Authorize)
  113. }
  114. }
  115. }
  116. // FIXME: do corss-comparison so reduce deletions and additions to the minimum?
  117. minMode := ACCESS_MODE_READ
  118. if !repo.IsPrivate {
  119. minMode = ACCESS_MODE_WRITE
  120. }
  121. newAccesses := make([]Access, 0, len(accessMap))
  122. for userID, mode := range accessMap {
  123. if mode < minMode {
  124. continue
  125. }
  126. newAccesses = append(newAccesses, Access{
  127. UserID: userID,
  128. RepoID: repo.Id,
  129. Mode: mode,
  130. })
  131. }
  132. // Delete old accesses and insert new ones for repository.
  133. if _, err = e.Delete(&Access{RepoID: repo.Id}); err != nil {
  134. return err
  135. } else if _, err = e.Insert(newAccesses); err != nil {
  136. return err
  137. }
  138. return nil
  139. }
  140. // RecalculateAccesses recalculates all accesses for repository.
  141. func (r *Repository) RecalculateAccesses() error {
  142. return r.recalculateAccesses(x)
  143. }