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

org_team.go 20 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833
  1. // Copyright 2018 The Gitea Authors. All rights reserved.
  2. // Copyright 2016 The Gogs Authors. All rights reserved.
  3. // Use of this source code is governed by a MIT-style
  4. // license that can be found in the LICENSE file.
  5. package models
  6. import (
  7. "errors"
  8. "fmt"
  9. "strings"
  10. "code.gitea.io/gitea/modules/log"
  11. "code.gitea.io/gitea/modules/setting"
  12. "github.com/go-xorm/xorm"
  13. )
  14. const ownerTeamName = "Owners"
  15. // Team represents a organization team.
  16. type Team struct {
  17. ID int64 `xorm:"pk autoincr"`
  18. OrgID int64 `xorm:"INDEX"`
  19. LowerName string
  20. Name string
  21. Description string
  22. Authorize AccessMode
  23. Repos []*Repository `xorm:"-"`
  24. Members []*User `xorm:"-"`
  25. NumRepos int
  26. NumMembers int
  27. Units []*TeamUnit `xorm:"-"`
  28. }
  29. // GetUnits return a list of available units for a team
  30. func (t *Team) GetUnits() error {
  31. return t.getUnits(x)
  32. }
  33. func (t *Team) getUnits(e Engine) (err error) {
  34. if t.Units != nil {
  35. return nil
  36. }
  37. t.Units, err = getUnitsByTeamID(e, t.ID)
  38. return err
  39. }
  40. // GetUnitNames returns the team units names
  41. func (t *Team) GetUnitNames() (res []string) {
  42. for _, u := range t.Units {
  43. res = append(res, Units[u.Type].NameKey)
  44. }
  45. return
  46. }
  47. // HasWriteAccess returns true if team has at least write level access mode.
  48. func (t *Team) HasWriteAccess() bool {
  49. return t.Authorize >= AccessModeWrite
  50. }
  51. // IsOwnerTeam returns true if team is owner team.
  52. func (t *Team) IsOwnerTeam() bool {
  53. return t.Name == ownerTeamName
  54. }
  55. // IsMember returns true if given user is a member of team.
  56. func (t *Team) IsMember(userID int64) bool {
  57. isMember, err := IsTeamMember(t.OrgID, t.ID, userID)
  58. if err != nil {
  59. log.Error(4, "IsMember: %v", err)
  60. return false
  61. }
  62. return isMember
  63. }
  64. func (t *Team) getRepositories(e Engine) error {
  65. return e.Join("INNER", "team_repo", "repository.id = team_repo.repo_id").
  66. Where("team_repo.team_id=?", t.ID).Find(&t.Repos)
  67. }
  68. // GetRepositories returns all repositories in team of organization.
  69. func (t *Team) GetRepositories() error {
  70. return t.getRepositories(x)
  71. }
  72. func (t *Team) getMembers(e Engine) (err error) {
  73. t.Members, err = getTeamMembers(e, t.ID)
  74. return err
  75. }
  76. // GetMembers returns all members in team of organization.
  77. func (t *Team) GetMembers() (err error) {
  78. return t.getMembers(x)
  79. }
  80. // AddMember adds new membership of the team to the organization,
  81. // the user will have membership to the organization automatically when needed.
  82. func (t *Team) AddMember(userID int64) error {
  83. return AddTeamMember(t, userID)
  84. }
  85. // RemoveMember removes member from team of organization.
  86. func (t *Team) RemoveMember(userID int64) error {
  87. return RemoveTeamMember(t, userID)
  88. }
  89. func (t *Team) hasRepository(e Engine, repoID int64) bool {
  90. return hasTeamRepo(e, t.OrgID, t.ID, repoID)
  91. }
  92. // HasRepository returns true if given repository belong to team.
  93. func (t *Team) HasRepository(repoID int64) bool {
  94. return t.hasRepository(x, repoID)
  95. }
  96. func (t *Team) addRepository(e Engine, repo *Repository) (err error) {
  97. if err = addTeamRepo(e, t.OrgID, t.ID, repo.ID); err != nil {
  98. return err
  99. }
  100. if _, err = e.Incr("num_repos").ID(t.ID).Update(new(Team)); err != nil {
  101. return fmt.Errorf("update team: %v", err)
  102. }
  103. t.NumRepos++
  104. if err = repo.recalculateTeamAccesses(e, 0); err != nil {
  105. return fmt.Errorf("recalculateAccesses: %v", err)
  106. }
  107. // Make all team members watch this repo if enabled in global settings
  108. if setting.Service.AutoWatchNewRepos {
  109. if err = t.getMembers(e); err != nil {
  110. return fmt.Errorf("getMembers: %v", err)
  111. }
  112. for _, u := range t.Members {
  113. if err = watchRepo(e, u.ID, repo.ID, true); err != nil {
  114. return fmt.Errorf("watchRepo: %v", err)
  115. }
  116. }
  117. }
  118. return nil
  119. }
  120. // AddRepository adds new repository to team of organization.
  121. func (t *Team) AddRepository(repo *Repository) (err error) {
  122. if repo.OwnerID != t.OrgID {
  123. return errors.New("Repository does not belong to organization")
  124. } else if t.HasRepository(repo.ID) {
  125. return nil
  126. }
  127. sess := x.NewSession()
  128. defer sess.Close()
  129. if err = sess.Begin(); err != nil {
  130. return err
  131. }
  132. if err = t.addRepository(sess, repo); err != nil {
  133. return err
  134. }
  135. return sess.Commit()
  136. }
  137. func (t *Team) removeRepository(e Engine, repo *Repository, recalculate bool) (err error) {
  138. if err = removeTeamRepo(e, t.ID, repo.ID); err != nil {
  139. return err
  140. }
  141. t.NumRepos--
  142. if _, err = e.ID(t.ID).Cols("num_repos").Update(t); err != nil {
  143. return err
  144. }
  145. // Don't need to recalculate when delete a repository from organization.
  146. if recalculate {
  147. if err = repo.recalculateTeamAccesses(e, t.ID); err != nil {
  148. return err
  149. }
  150. }
  151. teamUsers, err := getTeamUsersByTeamID(e, t.ID)
  152. if err != nil {
  153. return fmt.Errorf("getTeamUsersByTeamID: %v", err)
  154. }
  155. for _, teamUser := range teamUsers {
  156. has, err := hasAccess(e, teamUser.UID, repo)
  157. if err != nil {
  158. return err
  159. } else if has {
  160. continue
  161. }
  162. if err = watchRepo(e, teamUser.UID, repo.ID, false); err != nil {
  163. return err
  164. }
  165. // Remove all IssueWatches a user has subscribed to in the repositories
  166. if err := removeIssueWatchersByRepoID(e, teamUser.UID, repo.ID); err != nil {
  167. return err
  168. }
  169. }
  170. return nil
  171. }
  172. // RemoveRepository removes repository from team of organization.
  173. func (t *Team) RemoveRepository(repoID int64) error {
  174. if !t.HasRepository(repoID) {
  175. return nil
  176. }
  177. repo, err := GetRepositoryByID(repoID)
  178. if err != nil {
  179. return err
  180. }
  181. sess := x.NewSession()
  182. defer sess.Close()
  183. if err = sess.Begin(); err != nil {
  184. return err
  185. }
  186. if err = t.removeRepository(sess, repo, true); err != nil {
  187. return err
  188. }
  189. return sess.Commit()
  190. }
  191. // UnitEnabled returns if the team has the given unit type enabled
  192. func (t *Team) UnitEnabled(tp UnitType) bool {
  193. return t.unitEnabled(x, tp)
  194. }
  195. func (t *Team) unitEnabled(e Engine, tp UnitType) bool {
  196. if err := t.getUnits(e); err != nil {
  197. log.Warn("Error loading repository (ID: %d) units: %s", t.ID, err.Error())
  198. }
  199. for _, unit := range t.Units {
  200. if unit.Type == tp {
  201. return true
  202. }
  203. }
  204. return false
  205. }
  206. // IsUsableTeamName tests if a name could be as team name
  207. func IsUsableTeamName(name string) error {
  208. switch name {
  209. case "new":
  210. return ErrNameReserved{name}
  211. default:
  212. return nil
  213. }
  214. }
  215. // NewTeam creates a record of new team.
  216. // It's caller's responsibility to assign organization ID.
  217. func NewTeam(t *Team) (err error) {
  218. if len(t.Name) == 0 {
  219. return errors.New("empty team name")
  220. }
  221. if err = IsUsableTeamName(t.Name); err != nil {
  222. return err
  223. }
  224. has, err := x.ID(t.OrgID).Get(new(User))
  225. if err != nil {
  226. return err
  227. } else if !has {
  228. return ErrOrgNotExist{t.OrgID, ""}
  229. }
  230. t.LowerName = strings.ToLower(t.Name)
  231. has, err = x.
  232. Where("org_id=?", t.OrgID).
  233. And("lower_name=?", t.LowerName).
  234. Get(new(Team))
  235. if err != nil {
  236. return err
  237. } else if has {
  238. return ErrTeamAlreadyExist{t.OrgID, t.LowerName}
  239. }
  240. sess := x.NewSession()
  241. defer sess.Close()
  242. if err = sess.Begin(); err != nil {
  243. return err
  244. }
  245. if _, err = sess.Insert(t); err != nil {
  246. sess.Rollback()
  247. return err
  248. }
  249. // insert units for team
  250. if len(t.Units) > 0 {
  251. for _, unit := range t.Units {
  252. unit.TeamID = t.ID
  253. }
  254. if _, err = sess.Insert(&t.Units); err != nil {
  255. sess.Rollback()
  256. return err
  257. }
  258. }
  259. // Update organization number of teams.
  260. if _, err = sess.Exec("UPDATE `user` SET num_teams=num_teams+1 WHERE id = ?", t.OrgID); err != nil {
  261. sess.Rollback()
  262. return err
  263. }
  264. return sess.Commit()
  265. }
  266. func getTeam(e Engine, orgID int64, name string) (*Team, error) {
  267. t := &Team{
  268. OrgID: orgID,
  269. LowerName: strings.ToLower(name),
  270. }
  271. has, err := e.Get(t)
  272. if err != nil {
  273. return nil, err
  274. } else if !has {
  275. return nil, ErrTeamNotExist
  276. }
  277. return t, nil
  278. }
  279. // GetTeam returns team by given team name and organization.
  280. func GetTeam(orgID int64, name string) (*Team, error) {
  281. return getTeam(x, orgID, name)
  282. }
  283. func getTeamByID(e Engine, teamID int64) (*Team, error) {
  284. t := new(Team)
  285. has, err := e.ID(teamID).Get(t)
  286. if err != nil {
  287. return nil, err
  288. } else if !has {
  289. return nil, ErrTeamNotExist
  290. }
  291. return t, nil
  292. }
  293. // GetTeamByID returns team by given ID.
  294. func GetTeamByID(teamID int64) (*Team, error) {
  295. return getTeamByID(x, teamID)
  296. }
  297. // UpdateTeam updates information of team.
  298. func UpdateTeam(t *Team, authChanged bool) (err error) {
  299. if len(t.Name) == 0 {
  300. return errors.New("empty team name")
  301. }
  302. if len(t.Description) > 255 {
  303. t.Description = t.Description[:255]
  304. }
  305. sess := x.NewSession()
  306. defer sess.Close()
  307. if err = sess.Begin(); err != nil {
  308. return err
  309. }
  310. t.LowerName = strings.ToLower(t.Name)
  311. has, err := sess.
  312. Where("org_id=?", t.OrgID).
  313. And("lower_name=?", t.LowerName).
  314. And("id!=?", t.ID).
  315. Get(new(Team))
  316. if err != nil {
  317. return err
  318. } else if has {
  319. return ErrTeamAlreadyExist{t.OrgID, t.LowerName}
  320. }
  321. if _, err = sess.ID(t.ID).AllCols().Update(t); err != nil {
  322. return fmt.Errorf("update: %v", err)
  323. }
  324. // update units for team
  325. if len(t.Units) > 0 {
  326. for _, unit := range t.Units {
  327. unit.TeamID = t.ID
  328. }
  329. // Delete team-unit.
  330. if _, err := sess.
  331. Where("team_id=?", t.ID).
  332. Delete(new(TeamUnit)); err != nil {
  333. return err
  334. }
  335. if _, err = sess.Insert(&t.Units); err != nil {
  336. sess.Rollback()
  337. return err
  338. }
  339. }
  340. // Update access for team members if needed.
  341. if authChanged {
  342. if err = t.getRepositories(sess); err != nil {
  343. return fmt.Errorf("getRepositories: %v", err)
  344. }
  345. for _, repo := range t.Repos {
  346. if err = repo.recalculateTeamAccesses(sess, 0); err != nil {
  347. return fmt.Errorf("recalculateTeamAccesses: %v", err)
  348. }
  349. }
  350. }
  351. return sess.Commit()
  352. }
  353. // DeleteTeam deletes given team.
  354. // It's caller's responsibility to assign organization ID.
  355. func DeleteTeam(t *Team) error {
  356. if err := t.GetRepositories(); err != nil {
  357. return err
  358. }
  359. sess := x.NewSession()
  360. defer sess.Close()
  361. if err := sess.Begin(); err != nil {
  362. return err
  363. }
  364. if err := t.getMembers(sess); err != nil {
  365. return err
  366. }
  367. // Delete all accesses.
  368. for _, repo := range t.Repos {
  369. if err := repo.recalculateTeamAccesses(sess, t.ID); err != nil {
  370. return err
  371. }
  372. // Remove watches from all users and now unaccessible repos
  373. for _, user := range t.Members {
  374. has, err := hasAccess(sess, user.ID, repo)
  375. if err != nil {
  376. return err
  377. } else if has {
  378. continue
  379. }
  380. if err = watchRepo(sess, user.ID, repo.ID, false); err != nil {
  381. return err
  382. }
  383. // Remove all IssueWatches a user has subscribed to in the repositories
  384. if err = removeIssueWatchersByRepoID(sess, user.ID, repo.ID); err != nil {
  385. return err
  386. }
  387. }
  388. }
  389. // Delete team-repo
  390. if _, err := sess.
  391. Where("team_id=?", t.ID).
  392. Delete(new(TeamRepo)); err != nil {
  393. return err
  394. }
  395. // Delete team-user.
  396. if _, err := sess.
  397. Where("org_id=?", t.OrgID).
  398. Where("team_id=?", t.ID).
  399. Delete(new(TeamUser)); err != nil {
  400. return err
  401. }
  402. // Delete team-unit.
  403. if _, err := sess.
  404. Where("team_id=?", t.ID).
  405. Delete(new(TeamUnit)); err != nil {
  406. return err
  407. }
  408. // Delete team.
  409. if _, err := sess.ID(t.ID).Delete(new(Team)); err != nil {
  410. return err
  411. }
  412. // Update organization number of teams.
  413. if _, err := sess.Exec("UPDATE `user` SET num_teams=num_teams-1 WHERE id=?", t.OrgID); err != nil {
  414. return err
  415. }
  416. return sess.Commit()
  417. }
  418. // ___________ ____ ___
  419. // \__ ___/___ _____ _____ | | \______ ___________
  420. // | |_/ __ \\__ \ / \| | / ___// __ \_ __ \
  421. // | |\ ___/ / __ \| Y Y \ | /\___ \\ ___/| | \/
  422. // |____| \___ >____ /__|_| /______//____ >\___ >__|
  423. // \/ \/ \/ \/ \/
  424. // TeamUser represents an team-user relation.
  425. type TeamUser struct {
  426. ID int64 `xorm:"pk autoincr"`
  427. OrgID int64 `xorm:"INDEX"`
  428. TeamID int64 `xorm:"UNIQUE(s)"`
  429. UID int64 `xorm:"UNIQUE(s)"`
  430. }
  431. func isTeamMember(e Engine, orgID, teamID, userID int64) (bool, error) {
  432. return e.
  433. Where("org_id=?", orgID).
  434. And("team_id=?", teamID).
  435. And("uid=?", userID).
  436. Table("team_user").
  437. Exist()
  438. }
  439. // IsTeamMember returns true if given user is a member of team.
  440. func IsTeamMember(orgID, teamID, userID int64) (bool, error) {
  441. return isTeamMember(x, orgID, teamID, userID)
  442. }
  443. func getTeamUsersByTeamID(e Engine, teamID int64) ([]*TeamUser, error) {
  444. teamUsers := make([]*TeamUser, 0, 10)
  445. return teamUsers, e.
  446. Where("team_id=?", teamID).
  447. Find(&teamUsers)
  448. }
  449. func getTeamMembers(e Engine, teamID int64) (_ []*User, err error) {
  450. teamUsers, err := getTeamUsersByTeamID(e, teamID)
  451. if err != nil {
  452. return nil, fmt.Errorf("get team-users: %v", err)
  453. }
  454. members := make([]*User, len(teamUsers))
  455. for i, teamUser := range teamUsers {
  456. member, err := getUserByID(e, teamUser.UID)
  457. if err != nil {
  458. return nil, fmt.Errorf("get user '%d': %v", teamUser.UID, err)
  459. }
  460. members[i] = member
  461. }
  462. return members, nil
  463. }
  464. // GetTeamMembers returns all members in given team of organization.
  465. func GetTeamMembers(teamID int64) ([]*User, error) {
  466. return getTeamMembers(x, teamID)
  467. }
  468. func getUserTeams(e Engine, userID int64) (teams []*Team, err error) {
  469. return teams, e.
  470. Join("INNER", "team_user", "team_user.team_id = team.id").
  471. Where("team_user.uid=?", userID).
  472. Find(&teams)
  473. }
  474. func getUserOrgTeams(e Engine, orgID, userID int64) (teams []*Team, err error) {
  475. return teams, e.
  476. Join("INNER", "team_user", "team_user.team_id = team.id").
  477. Where("team.org_id = ?", orgID).
  478. And("team_user.uid=?", userID).
  479. Find(&teams)
  480. }
  481. func getUserRepoTeams(e Engine, orgID, userID, repoID int64) (teams []*Team, err error) {
  482. return teams, e.
  483. Join("INNER", "team_user", "team_user.team_id = team.id").
  484. Join("INNER", "team_repo", "team_repo.team_id = team.id").
  485. Where("team.org_id = ?", orgID).
  486. And("team_user.uid=?", userID).
  487. And("team_repo.repo_id=?", repoID).
  488. Find(&teams)
  489. }
  490. // GetUserOrgTeams returns all teams that user belongs to in given organization.
  491. func GetUserOrgTeams(orgID, userID int64) ([]*Team, error) {
  492. return getUserOrgTeams(x, orgID, userID)
  493. }
  494. // GetUserTeams returns all teams that user belongs across all organizations.
  495. func GetUserTeams(userID int64) ([]*Team, error) {
  496. return getUserTeams(x, userID)
  497. }
  498. // AddTeamMember adds new membership of given team to given organization,
  499. // the user will have membership to given organization automatically when needed.
  500. func AddTeamMember(team *Team, userID int64) error {
  501. isAlreadyMember, err := IsTeamMember(team.OrgID, team.ID, userID)
  502. if err != nil || isAlreadyMember {
  503. return err
  504. }
  505. if err := AddOrgUser(team.OrgID, userID); err != nil {
  506. return err
  507. }
  508. // Get team and its repositories.
  509. if err := team.GetRepositories(); err != nil {
  510. return err
  511. }
  512. sess := x.NewSession()
  513. defer sess.Close()
  514. if err := sess.Begin(); err != nil {
  515. return err
  516. }
  517. if _, err := sess.Insert(&TeamUser{
  518. UID: userID,
  519. OrgID: team.OrgID,
  520. TeamID: team.ID,
  521. }); err != nil {
  522. return err
  523. } else if _, err := sess.Incr("num_members").ID(team.ID).Update(new(Team)); err != nil {
  524. return err
  525. }
  526. team.NumMembers++
  527. // Give access to team repositories.
  528. for _, repo := range team.Repos {
  529. if err := repo.recalculateTeamAccesses(sess, 0); err != nil {
  530. return err
  531. }
  532. if setting.Service.AutoWatchNewRepos {
  533. if err = watchRepo(sess, userID, repo.ID, true); err != nil {
  534. return err
  535. }
  536. }
  537. }
  538. return sess.Commit()
  539. }
  540. func removeTeamMember(e *xorm.Session, team *Team, userID int64) error {
  541. isMember, err := isTeamMember(e, team.OrgID, team.ID, userID)
  542. if err != nil || !isMember {
  543. return err
  544. }
  545. // Check if the user to delete is the last member in owner team.
  546. if team.IsOwnerTeam() && team.NumMembers == 1 {
  547. return ErrLastOrgOwner{UID: userID}
  548. }
  549. team.NumMembers--
  550. if err := team.getRepositories(e); err != nil {
  551. return err
  552. }
  553. if _, err := e.Delete(&TeamUser{
  554. UID: userID,
  555. OrgID: team.OrgID,
  556. TeamID: team.ID,
  557. }); err != nil {
  558. return err
  559. } else if _, err = e.
  560. ID(team.ID).
  561. Cols("num_members").
  562. Update(team); err != nil {
  563. return err
  564. }
  565. // Delete access to team repositories.
  566. for _, repo := range team.Repos {
  567. if err := repo.recalculateTeamAccesses(e, 0); err != nil {
  568. return err
  569. }
  570. // Remove watches from now unaccessible
  571. has, err := hasAccess(e, userID, repo)
  572. if err != nil {
  573. return err
  574. } else if has {
  575. continue
  576. }
  577. if err = watchRepo(e, userID, repo.ID, false); err != nil {
  578. return err
  579. }
  580. // Remove all IssueWatches a user has subscribed to in the repositories
  581. if err := removeIssueWatchersByRepoID(e, userID, repo.ID); err != nil {
  582. return err
  583. }
  584. }
  585. // Check if the user is a member of any team in the organization.
  586. if count, err := e.Count(&TeamUser{
  587. UID: userID,
  588. OrgID: team.OrgID,
  589. }); err != nil {
  590. return err
  591. } else if count == 0 {
  592. return removeOrgUser(e, team.OrgID, userID)
  593. }
  594. return nil
  595. }
  596. // RemoveTeamMember removes member from given team of given organization.
  597. func RemoveTeamMember(team *Team, userID int64) error {
  598. sess := x.NewSession()
  599. defer sess.Close()
  600. if err := sess.Begin(); err != nil {
  601. return err
  602. }
  603. if err := removeTeamMember(sess, team, userID); err != nil {
  604. return err
  605. }
  606. return sess.Commit()
  607. }
  608. // IsUserInTeams returns if a user in some teams
  609. func IsUserInTeams(userID int64, teamIDs []int64) (bool, error) {
  610. return x.Where("uid=?", userID).In("team_id", teamIDs).Exist(new(TeamUser))
  611. }
  612. // UsersInTeamsCount counts the number of users which are in userIDs and teamIDs
  613. func UsersInTeamsCount(userIDs []int64, teamIDs []int64) (count int64, err error) {
  614. if count, err = x.In("uid", userIDs).In("team_id", teamIDs).Count(new(TeamUser)); err != nil {
  615. return 0, err
  616. }
  617. return
  618. }
  619. // ___________ __________
  620. // \__ ___/___ _____ _____\______ \ ____ ______ ____
  621. // | |_/ __ \\__ \ / \| _// __ \\____ \ / _ \
  622. // | |\ ___/ / __ \| Y Y \ | \ ___/| |_> > <_> )
  623. // |____| \___ >____ /__|_| /____|_ /\___ > __/ \____/
  624. // \/ \/ \/ \/ \/|__|
  625. // TeamRepo represents an team-repository relation.
  626. type TeamRepo struct {
  627. ID int64 `xorm:"pk autoincr"`
  628. OrgID int64 `xorm:"INDEX"`
  629. TeamID int64 `xorm:"UNIQUE(s)"`
  630. RepoID int64 `xorm:"UNIQUE(s)"`
  631. }
  632. func hasTeamRepo(e Engine, orgID, teamID, repoID int64) bool {
  633. has, _ := e.
  634. Where("org_id=?", orgID).
  635. And("team_id=?", teamID).
  636. And("repo_id=?", repoID).
  637. Get(new(TeamRepo))
  638. return has
  639. }
  640. // HasTeamRepo returns true if given repository belongs to team.
  641. func HasTeamRepo(orgID, teamID, repoID int64) bool {
  642. return hasTeamRepo(x, orgID, teamID, repoID)
  643. }
  644. func addTeamRepo(e Engine, orgID, teamID, repoID int64) error {
  645. _, err := e.InsertOne(&TeamRepo{
  646. OrgID: orgID,
  647. TeamID: teamID,
  648. RepoID: repoID,
  649. })
  650. return err
  651. }
  652. func removeTeamRepo(e Engine, teamID, repoID int64) error {
  653. _, err := e.Delete(&TeamRepo{
  654. TeamID: teamID,
  655. RepoID: repoID,
  656. })
  657. return err
  658. }
  659. // GetTeamsWithAccessToRepo returns all teams in an organization that have given access level to the repository.
  660. func GetTeamsWithAccessToRepo(orgID, repoID int64, mode AccessMode) ([]*Team, error) {
  661. teams := make([]*Team, 0, 5)
  662. return teams, x.Where("team.authorize >= ?", mode).
  663. Join("INNER", "team_repo", "team_repo.team_id = team.id").
  664. And("team_repo.org_id = ?", orgID).
  665. And("team_repo.repo_id = ?", repoID).
  666. Find(&teams)
  667. }
  668. // ___________ ____ ___ .__ __
  669. // \__ ___/___ _____ _____ | | \____ |__|/ |_
  670. // | |_/ __ \\__ \ / \| | / \| \ __\
  671. // | |\ ___/ / __ \| Y Y \ | / | \ || |
  672. // |____| \___ >____ /__|_| /______/|___| /__||__|
  673. // \/ \/ \/ \/
  674. // TeamUnit describes all units of a repository
  675. type TeamUnit struct {
  676. ID int64 `xorm:"pk autoincr"`
  677. OrgID int64 `xorm:"INDEX"`
  678. TeamID int64 `xorm:"UNIQUE(s)"`
  679. Type UnitType `xorm:"UNIQUE(s)"`
  680. }
  681. // Unit returns Unit
  682. func (t *TeamUnit) Unit() Unit {
  683. return Units[t.Type]
  684. }
  685. func getUnitsByTeamID(e Engine, teamID int64) (units []*TeamUnit, err error) {
  686. return units, e.Where("team_id = ?", teamID).Find(&units)
  687. }
  688. // UpdateTeamUnits updates a teams's units
  689. func UpdateTeamUnits(team *Team, units []TeamUnit) (err error) {
  690. sess := x.NewSession()
  691. defer sess.Close()
  692. if err = sess.Begin(); err != nil {
  693. return err
  694. }
  695. if _, err = sess.Where("team_id = ?", team.ID).Delete(new(TeamUnit)); err != nil {
  696. return err
  697. }
  698. if _, err = sess.Insert(units); err != nil {
  699. sess.Rollback()
  700. return err
  701. }
  702. return sess.Commit()
  703. }