gitea源码

org.go 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Copyright 2019 The Gitea Authors. All rights reserved.
  3. // SPDX-License-Identifier: MIT
  4. package organization
  5. import (
  6. "context"
  7. "fmt"
  8. "strings"
  9. "code.gitea.io/gitea/models/db"
  10. "code.gitea.io/gitea/models/perm"
  11. "code.gitea.io/gitea/models/unit"
  12. user_model "code.gitea.io/gitea/models/user"
  13. "code.gitea.io/gitea/modules/log"
  14. "code.gitea.io/gitea/modules/setting"
  15. "code.gitea.io/gitea/modules/structs"
  16. "code.gitea.io/gitea/modules/util"
  17. "xorm.io/builder"
  18. "xorm.io/xorm"
  19. )
  20. // ErrOrgNotExist represents a "OrgNotExist" kind of error.
  21. type ErrOrgNotExist struct {
  22. ID int64
  23. Name string
  24. }
  25. // IsErrOrgNotExist checks if an error is a ErrOrgNotExist.
  26. func IsErrOrgNotExist(err error) bool {
  27. _, ok := err.(ErrOrgNotExist)
  28. return ok
  29. }
  30. func (err ErrOrgNotExist) Error() string {
  31. return fmt.Sprintf("org does not exist [id: %d, name: %s]", err.ID, err.Name)
  32. }
  33. func (err ErrOrgNotExist) Unwrap() error {
  34. return util.ErrNotExist
  35. }
  36. // ErrLastOrgOwner represents a "LastOrgOwner" kind of error.
  37. type ErrLastOrgOwner struct {
  38. UID int64
  39. }
  40. // IsErrLastOrgOwner checks if an error is a ErrLastOrgOwner.
  41. func IsErrLastOrgOwner(err error) bool {
  42. _, ok := err.(ErrLastOrgOwner)
  43. return ok
  44. }
  45. func (err ErrLastOrgOwner) Error() string {
  46. return fmt.Sprintf("user is the last member of owner team [uid: %d]", err.UID)
  47. }
  48. // ErrUserNotAllowedCreateOrg represents a "UserNotAllowedCreateOrg" kind of error.
  49. type ErrUserNotAllowedCreateOrg struct{}
  50. // IsErrUserNotAllowedCreateOrg checks if an error is an ErrUserNotAllowedCreateOrg.
  51. func IsErrUserNotAllowedCreateOrg(err error) bool {
  52. _, ok := err.(ErrUserNotAllowedCreateOrg)
  53. return ok
  54. }
  55. func (err ErrUserNotAllowedCreateOrg) Error() string {
  56. return "user is not allowed to create organizations"
  57. }
  58. func (err ErrUserNotAllowedCreateOrg) Unwrap() error {
  59. return util.ErrPermissionDenied
  60. }
  61. // Organization represents an organization
  62. type Organization user_model.User
  63. // OrgFromUser converts user to organization
  64. func OrgFromUser(user *user_model.User) *Organization {
  65. return (*Organization)(user)
  66. }
  67. // TableName represents the real table name of Organization
  68. func (Organization) TableName() string {
  69. return "user"
  70. }
  71. // IsOwnedBy returns true if given user is in the owner team.
  72. func (org *Organization) IsOwnedBy(ctx context.Context, uid int64) (bool, error) {
  73. return IsOrganizationOwner(ctx, org.ID, uid)
  74. }
  75. // IsOrgAdmin returns true if given user is in the owner team or an admin team.
  76. func (org *Organization) IsOrgAdmin(ctx context.Context, uid int64) (bool, error) {
  77. return IsOrganizationAdmin(ctx, org.ID, uid)
  78. }
  79. // IsOrgMember returns true if given user is member of organization.
  80. func (org *Organization) IsOrgMember(ctx context.Context, uid int64) (bool, error) {
  81. return IsOrganizationMember(ctx, org.ID, uid)
  82. }
  83. // CanCreateOrgRepo returns true if given user can create repo in organization
  84. func (org *Organization) CanCreateOrgRepo(ctx context.Context, uid int64) (bool, error) {
  85. return CanCreateOrgRepo(ctx, org.ID, uid)
  86. }
  87. // GetTeam returns named team of organization.
  88. func (org *Organization) GetTeam(ctx context.Context, name string) (*Team, error) {
  89. return GetTeam(ctx, org.ID, name)
  90. }
  91. // GetOwnerTeam returns owner team of organization.
  92. func (org *Organization) GetOwnerTeam(ctx context.Context) (*Team, error) {
  93. return org.GetTeam(ctx, OwnerTeamName)
  94. }
  95. // FindOrgTeams returns all teams of a given organization
  96. func FindOrgTeams(ctx context.Context, orgID int64) ([]*Team, error) {
  97. var teams []*Team
  98. return teams, db.GetEngine(ctx).
  99. Where("org_id=?", orgID).
  100. OrderBy("CASE WHEN name LIKE '" + OwnerTeamName + "' THEN '' ELSE name END").
  101. Find(&teams)
  102. }
  103. // LoadTeams load teams if not loaded.
  104. func (org *Organization) LoadTeams(ctx context.Context) ([]*Team, error) {
  105. return FindOrgTeams(ctx, org.ID)
  106. }
  107. // GetMembers returns all members of organization.
  108. func (org *Organization) GetMembers(ctx context.Context, doer *user_model.User) (user_model.UserList, map[int64]bool, error) {
  109. return FindOrgMembers(ctx, &FindOrgMembersOpts{
  110. Doer: doer,
  111. OrgID: org.ID,
  112. })
  113. }
  114. // HasMemberWithUserID returns true if user with userID is part of the u organisation.
  115. func (org *Organization) HasMemberWithUserID(ctx context.Context, userID int64) bool {
  116. return org.hasMemberWithUserID(ctx, userID)
  117. }
  118. func (org *Organization) hasMemberWithUserID(ctx context.Context, userID int64) bool {
  119. isMember, err := IsOrganizationMember(ctx, org.ID, userID)
  120. if err != nil {
  121. log.Error("IsOrganizationMember: %v", err)
  122. return false
  123. }
  124. return isMember
  125. }
  126. // AvatarLink returns the full avatar link with http host
  127. func (org *Organization) AvatarLink(ctx context.Context) string {
  128. return org.AsUser().AvatarLink(ctx)
  129. }
  130. // HTMLURL returns the organization's full link.
  131. func (org *Organization) HTMLURL(ctx context.Context) string {
  132. return org.AsUser().HTMLURL(ctx)
  133. }
  134. // OrganisationLink returns the organization sub page link.
  135. func (org *Organization) OrganisationLink() string {
  136. return org.AsUser().OrganisationLink()
  137. }
  138. // ShortName ellipses username to length
  139. func (org *Organization) ShortName(length int) string {
  140. return org.AsUser().ShortName(length)
  141. }
  142. // HomeLink returns the user or organization home page link.
  143. func (org *Organization) HomeLink() string {
  144. return org.AsUser().HomeLink()
  145. }
  146. // FindOrgMembersOpts represensts find org members conditions
  147. type FindOrgMembersOpts struct {
  148. db.ListOptions
  149. Doer *user_model.User
  150. IsDoerMember bool
  151. OrgID int64
  152. }
  153. func (opts FindOrgMembersOpts) PublicOnly() bool {
  154. return opts.Doer == nil || !(opts.IsDoerMember || opts.Doer.IsAdmin)
  155. }
  156. // applyTeamMatesOnlyFilter make sure restricted users only see public team members and there own team mates
  157. func (opts FindOrgMembersOpts) applyTeamMatesOnlyFilter(sess *xorm.Session) {
  158. if opts.Doer != nil && opts.IsDoerMember && opts.Doer.IsRestricted {
  159. teamMates := builder.Select("DISTINCT team_user.uid").
  160. From("team_user").
  161. Where(builder.In("team_user.team_id", getUserTeamIDsQueryBuilder(opts.OrgID, opts.Doer.ID))).
  162. And(builder.Eq{"team_user.org_id": opts.OrgID})
  163. sess.And(
  164. builder.In("org_user.uid", teamMates).
  165. Or(builder.Eq{"org_user.is_public": true}),
  166. )
  167. }
  168. }
  169. // CountOrgMembers counts the organization's members
  170. func CountOrgMembers(ctx context.Context, opts *FindOrgMembersOpts) (int64, error) {
  171. sess := db.GetEngine(ctx).Where("org_id=?", opts.OrgID)
  172. if opts.PublicOnly() {
  173. sess = sess.And("is_public = ?", true)
  174. } else {
  175. opts.applyTeamMatesOnlyFilter(sess)
  176. }
  177. return sess.Count(new(OrgUser))
  178. }
  179. // FindOrgMembers loads organization members according conditions
  180. func FindOrgMembers(ctx context.Context, opts *FindOrgMembersOpts) (user_model.UserList, map[int64]bool, error) {
  181. ous, err := GetOrgUsersByOrgID(ctx, opts)
  182. if err != nil {
  183. return nil, nil, err
  184. }
  185. ids := make([]int64, len(ous))
  186. idsIsPublic := make(map[int64]bool, len(ous))
  187. for i, ou := range ous {
  188. ids[i] = ou.UID
  189. idsIsPublic[ou.UID] = ou.IsPublic
  190. }
  191. users, err := user_model.GetUsersByIDs(ctx, ids)
  192. if err != nil {
  193. return nil, nil, err
  194. }
  195. return users, idsIsPublic, nil
  196. }
  197. // AsUser returns the org as user object
  198. func (org *Organization) AsUser() *user_model.User {
  199. return (*user_model.User)(org)
  200. }
  201. // DisplayName returns full name if it's not empty,
  202. // returns username otherwise.
  203. func (org *Organization) DisplayName() string {
  204. return org.AsUser().DisplayName()
  205. }
  206. // CustomAvatarRelativePath returns user custom avatar relative path.
  207. func (org *Organization) CustomAvatarRelativePath() string {
  208. return org.Avatar
  209. }
  210. // UnitPermission returns unit permission
  211. func (org *Organization) UnitPermission(ctx context.Context, doer *user_model.User, unitType unit.Type) perm.AccessMode {
  212. if doer != nil {
  213. teams, err := GetUserOrgTeams(ctx, org.ID, doer.ID)
  214. if err != nil {
  215. log.Error("GetUserOrgTeams: %v", err)
  216. return perm.AccessModeNone
  217. }
  218. if err := teams.LoadUnits(ctx); err != nil {
  219. log.Error("LoadUnits: %v", err)
  220. return perm.AccessModeNone
  221. }
  222. if len(teams) > 0 {
  223. return teams.UnitMaxAccess(unitType)
  224. }
  225. }
  226. if org.Visibility.IsPublic() {
  227. return perm.AccessModeRead
  228. }
  229. return perm.AccessModeNone
  230. }
  231. // CreateOrganization creates record of a new organization.
  232. func CreateOrganization(ctx context.Context, org *Organization, owner *user_model.User) (err error) {
  233. if !owner.CanCreateOrganization() {
  234. return ErrUserNotAllowedCreateOrg{}
  235. }
  236. if err = user_model.IsUsableUsername(org.Name); err != nil {
  237. return err
  238. }
  239. isExist, err := user_model.IsUserExist(ctx, 0, org.Name)
  240. if err != nil {
  241. return err
  242. } else if isExist {
  243. return user_model.ErrUserAlreadyExist{Name: org.Name}
  244. }
  245. org.LowerName = strings.ToLower(org.Name)
  246. if org.Rands, err = user_model.GetUserSalt(); err != nil {
  247. return err
  248. }
  249. if org.Salt, err = user_model.GetUserSalt(); err != nil {
  250. return err
  251. }
  252. org.UseCustomAvatar = true
  253. org.MaxRepoCreation = -1
  254. org.NumTeams = 1
  255. org.NumMembers = 1
  256. org.Type = user_model.UserTypeOrganization
  257. return db.WithTx(ctx, func(ctx context.Context) error {
  258. if err = user_model.DeleteUserRedirect(ctx, org.Name); err != nil {
  259. return err
  260. }
  261. if err = db.Insert(ctx, org); err != nil {
  262. return fmt.Errorf("insert organization: %w", err)
  263. }
  264. if err = user_model.GenerateRandomAvatar(ctx, org.AsUser()); err != nil {
  265. return fmt.Errorf("generate random avatar: %w", err)
  266. }
  267. // Add initial creator to organization and owner team.
  268. if err = db.Insert(ctx, &OrgUser{
  269. UID: owner.ID,
  270. OrgID: org.ID,
  271. IsPublic: setting.Service.DefaultOrgMemberVisible,
  272. }); err != nil {
  273. return fmt.Errorf("insert org-user relation: %w", err)
  274. }
  275. // Create default owner team.
  276. t := &Team{
  277. OrgID: org.ID,
  278. LowerName: strings.ToLower(OwnerTeamName),
  279. Name: OwnerTeamName,
  280. AccessMode: perm.AccessModeOwner,
  281. NumMembers: 1,
  282. IncludesAllRepositories: true,
  283. CanCreateOrgRepo: true,
  284. }
  285. if err = db.Insert(ctx, t); err != nil {
  286. return fmt.Errorf("insert owner team: %w", err)
  287. }
  288. // insert units for team
  289. units := make([]TeamUnit, 0, len(unit.AllRepoUnitTypes))
  290. for _, tp := range unit.AllRepoUnitTypes {
  291. up := perm.AccessModeOwner
  292. if tp == unit.TypeExternalTracker || tp == unit.TypeExternalWiki {
  293. up = perm.AccessModeRead
  294. }
  295. units = append(units, TeamUnit{
  296. OrgID: org.ID,
  297. TeamID: t.ID,
  298. Type: tp,
  299. AccessMode: up,
  300. })
  301. }
  302. if err = db.Insert(ctx, &units); err != nil {
  303. return err
  304. }
  305. if err = db.Insert(ctx, &TeamUser{
  306. UID: owner.ID,
  307. OrgID: org.ID,
  308. TeamID: t.ID,
  309. }); err != nil {
  310. return fmt.Errorf("insert team-user relation: %w", err)
  311. }
  312. return nil
  313. })
  314. }
  315. // GetOrgByName returns organization by given name.
  316. func GetOrgByName(ctx context.Context, name string) (*Organization, error) {
  317. if len(name) == 0 {
  318. return nil, ErrOrgNotExist{0, name}
  319. }
  320. u := &Organization{
  321. LowerName: strings.ToLower(name),
  322. Type: user_model.UserTypeOrganization,
  323. }
  324. has, err := db.GetEngine(ctx).Get(u)
  325. if err != nil {
  326. return nil, err
  327. } else if !has {
  328. return nil, ErrOrgNotExist{0, name}
  329. }
  330. return u, nil
  331. }
  332. // GetOrgUserMaxAuthorizeLevel returns highest authorize level of user in an organization
  333. func (org *Organization) GetOrgUserMaxAuthorizeLevel(ctx context.Context, uid int64) (perm.AccessMode, error) {
  334. var authorize perm.AccessMode
  335. _, err := db.GetEngine(ctx).
  336. Select("max(team.authorize)").
  337. Table("team").
  338. Join("INNER", "team_user", "team_user.team_id = team.id").
  339. Where("team_user.uid = ?", uid).
  340. And("team_user.org_id = ?", org.ID).
  341. Get(&authorize)
  342. return authorize, err
  343. }
  344. // GetUsersWhoCanCreateOrgRepo returns users which are able to create repo in organization
  345. func GetUsersWhoCanCreateOrgRepo(ctx context.Context, orgID int64) (map[int64]*user_model.User, error) {
  346. // Use a map, in order to de-duplicate users.
  347. users := make(map[int64]*user_model.User)
  348. return users, db.GetEngine(ctx).
  349. Join("INNER", "`team_user`", "`team_user`.uid=`user`.id").
  350. Join("INNER", "`team`", "`team`.id=`team_user`.team_id").
  351. Where(builder.Eq{"team.can_create_org_repo": true}.Or(builder.Eq{"team.authorize": perm.AccessModeOwner})).
  352. And("team_user.org_id = ?", orgID).Find(&users)
  353. }
  354. // HasOrgOrUserVisible tells if the given user can see the given org or user
  355. func HasOrgOrUserVisible(ctx context.Context, orgOrUser, user *user_model.User) bool {
  356. // If user is nil, it's an anonymous user/request.
  357. // The Ghost user is handled like an anonymous user.
  358. if user == nil || user.IsGhost() {
  359. return orgOrUser.Visibility == structs.VisibleTypePublic
  360. }
  361. if user.IsAdmin || orgOrUser.ID == user.ID {
  362. return true
  363. }
  364. if (orgOrUser.Visibility == structs.VisibleTypePrivate || user.IsRestricted) && !OrgFromUser(orgOrUser).hasMemberWithUserID(ctx, user.ID) {
  365. return false
  366. }
  367. return true
  368. }
  369. // HasOrgsVisible tells if the given user can see at least one of the orgs provided
  370. func HasOrgsVisible(ctx context.Context, orgs []*Organization, user *user_model.User) bool {
  371. if len(orgs) == 0 {
  372. return false
  373. }
  374. for _, org := range orgs {
  375. if HasOrgOrUserVisible(ctx, org.AsUser(), user) {
  376. return true
  377. }
  378. }
  379. return false
  380. }
  381. // GetOrgUsersByOrgID returns all organization-user relations by organization ID.
  382. func GetOrgUsersByOrgID(ctx context.Context, opts *FindOrgMembersOpts) ([]*OrgUser, error) {
  383. sess := db.GetEngine(ctx).Where("org_id=?", opts.OrgID)
  384. if opts.PublicOnly() {
  385. sess = sess.And("is_public = ?", true)
  386. } else {
  387. opts.applyTeamMatesOnlyFilter(sess)
  388. }
  389. if opts.ListOptions.PageSize > 0 {
  390. sess = db.SetSessionPagination(sess, opts)
  391. ous := make([]*OrgUser, 0, opts.PageSize)
  392. return ous, sess.Find(&ous)
  393. }
  394. var ous []*OrgUser
  395. return ous, sess.Find(&ous)
  396. }
  397. // ChangeOrgUserStatus changes public or private membership status.
  398. func ChangeOrgUserStatus(ctx context.Context, orgID, uid int64, public bool) error {
  399. ou := new(OrgUser)
  400. has, err := db.GetEngine(ctx).
  401. Where("uid=?", uid).
  402. And("org_id=?", orgID).
  403. Get(ou)
  404. if err != nil {
  405. return err
  406. } else if !has {
  407. return nil
  408. }
  409. ou.IsPublic = public
  410. _, err = db.GetEngine(ctx).ID(ou.ID).Cols("is_public").Update(ou)
  411. return err
  412. }
  413. // AddOrgUser adds new user to given organization.
  414. func AddOrgUser(ctx context.Context, orgID, uid int64) error {
  415. isAlreadyMember, err := IsOrganizationMember(ctx, orgID, uid)
  416. if err != nil || isAlreadyMember {
  417. return err
  418. }
  419. return db.WithTx(ctx, func(ctx context.Context) error {
  420. // check in transaction
  421. isAlreadyMember, err = IsOrganizationMember(ctx, orgID, uid)
  422. if err != nil || isAlreadyMember {
  423. return err
  424. }
  425. ou := &OrgUser{
  426. UID: uid,
  427. OrgID: orgID,
  428. IsPublic: setting.Service.DefaultOrgMemberVisible,
  429. }
  430. if err := db.Insert(ctx, ou); err != nil {
  431. return err
  432. } else if _, err = db.Exec(ctx, "UPDATE `user` SET num_members = num_members + 1 WHERE id = ?", orgID); err != nil {
  433. return err
  434. }
  435. return nil
  436. })
  437. }
  438. // GetOrgByID returns the user object by given ID if exists.
  439. func GetOrgByID(ctx context.Context, id int64) (*Organization, error) {
  440. u := new(Organization)
  441. has, err := db.GetEngine(ctx).ID(id).Get(u)
  442. if err != nil {
  443. return nil, err
  444. } else if !has {
  445. return nil, user_model.ErrUserNotExist{
  446. UID: id,
  447. }
  448. }
  449. return u, nil
  450. }
  451. // RemoveOrgRepo removes all team-repository relations of organization.
  452. func RemoveOrgRepo(ctx context.Context, orgID, repoID int64) error {
  453. teamRepos := make([]*TeamRepo, 0, 10)
  454. e := db.GetEngine(ctx)
  455. if err := e.Find(&teamRepos, &TeamRepo{OrgID: orgID, RepoID: repoID}); err != nil {
  456. return err
  457. }
  458. if len(teamRepos) == 0 {
  459. return nil
  460. }
  461. if _, err := e.Delete(&TeamRepo{
  462. OrgID: orgID,
  463. RepoID: repoID,
  464. }); err != nil {
  465. return err
  466. }
  467. teamIDs := make([]int64, len(teamRepos))
  468. for i, teamRepo := range teamRepos {
  469. teamIDs[i] = teamRepo.TeamID
  470. }
  471. _, err := e.Decr("num_repos").In("id", teamIDs).Update(new(Team))
  472. return err
  473. }
  474. // GetUserTeams returns all teams that belong to user,
  475. // and that the user has joined.
  476. func (org *Organization) GetUserTeams(ctx context.Context, userID int64, cols ...string) ([]*Team, error) {
  477. teams := make([]*Team, 0, org.NumTeams)
  478. return teams, db.GetEngine(ctx).
  479. Where("`team_user`.org_id = ?", org.ID).
  480. Join("INNER", "team_user", "`team_user`.team_id = team.id").
  481. Join("INNER", "`user`", "`user`.id=team_user.uid").
  482. And("`team_user`.uid = ?", userID).
  483. Asc("`user`.name").
  484. Cols(cols...).
  485. Find(&teams)
  486. }
  487. // GetUserTeamIDs returns of all team IDs of the organization that user is member of.
  488. func (org *Organization) GetUserTeamIDs(ctx context.Context, userID int64) ([]int64, error) {
  489. teamIDs := make([]int64, 0, org.NumTeams)
  490. return teamIDs, db.GetEngine(ctx).
  491. Table("team").
  492. Cols("team.id").
  493. Where("`team_user`.org_id = ?", org.ID).
  494. Join("INNER", "team_user", "`team_user`.team_id = team.id").
  495. And("`team_user`.uid = ?", userID).
  496. Find(&teamIDs)
  497. }
  498. func getUserTeamIDsQueryBuilder(orgID, userID int64) *builder.Builder {
  499. return builder.Select("team.id").From("team").
  500. InnerJoin("team_user", "team_user.team_id = team.id").
  501. Where(builder.Eq{
  502. "team_user.org_id": orgID,
  503. "team_user.uid": userID,
  504. })
  505. }