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.

1017 lines
24 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
9 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
  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. import (
  6. "errors"
  7. "fmt"
  8. "os"
  9. "strings"
  10. "github.com/go-xorm/xorm"
  11. )
  12. var (
  13. ErrOrgNotExist = errors.New("Organization does not exist")
  14. ErrTeamAlreadyExist = errors.New("Team already exist")
  15. ErrTeamNotExist = errors.New("Team does not exist")
  16. ErrTeamNameIllegal = errors.New("Team name contains illegal characters")
  17. )
  18. // IsOwnedBy returns true if given user is in the owner team.
  19. func (org *User) IsOwnedBy(uid int64) bool {
  20. return IsOrganizationOwner(org.Id, uid)
  21. }
  22. // IsOrgMember returns true if given user is member of organization.
  23. func (org *User) IsOrgMember(uid int64) bool {
  24. return org.IsOrganization() && IsOrganizationMember(org.Id, uid)
  25. }
  26. func (org *User) getTeam(e Engine, name string) (*Team, error) {
  27. return getTeam(e, org.Id, name)
  28. }
  29. // GetTeam returns named team of organization.
  30. func (org *User) GetTeam(name string) (*Team, error) {
  31. return org.getTeam(x, name)
  32. }
  33. func (org *User) getOwnerTeam(e Engine) (*Team, error) {
  34. return org.getTeam(e, OWNER_TEAM)
  35. }
  36. // GetOwnerTeam returns owner team of organization.
  37. func (org *User) GetOwnerTeam() (*Team, error) {
  38. return org.getOwnerTeam(x)
  39. }
  40. func (org *User) getTeams(e Engine) error {
  41. return e.Where("org_id=?", org.Id).Find(&org.Teams)
  42. }
  43. // GetTeams returns all teams that belong to organization.
  44. func (org *User) GetTeams() error {
  45. return org.getTeams(x)
  46. }
  47. // GetMembers returns all members of organization.
  48. func (org *User) GetMembers() error {
  49. ous, err := GetOrgUsersByOrgId(org.Id)
  50. if err != nil {
  51. return err
  52. }
  53. org.Members = make([]*User, len(ous))
  54. for i, ou := range ous {
  55. org.Members[i], err = GetUserByID(ou.Uid)
  56. if err != nil {
  57. return err
  58. }
  59. }
  60. return nil
  61. }
  62. // AddMember adds new member to organization.
  63. func (org *User) AddMember(uid int64) error {
  64. return AddOrgUser(org.Id, uid)
  65. }
  66. // RemoveMember removes member from organization.
  67. func (org *User) RemoveMember(uid int64) error {
  68. return RemoveOrgUser(org.Id, uid)
  69. }
  70. func (org *User) removeOrgRepo(e Engine, repoID int64) error {
  71. return removeOrgRepo(e, org.Id, repoID)
  72. }
  73. // RemoveOrgRepo removes all team-repository relations of organization.
  74. func (org *User) RemoveOrgRepo(repoID int64) error {
  75. return org.removeOrgRepo(x, repoID)
  76. }
  77. // CreateOrganization creates record of a new organization.
  78. func CreateOrganization(org, owner *User) (err error) {
  79. if err = IsUsableName(org.Name); err != nil {
  80. return err
  81. }
  82. isExist, err := IsUserExist(0, org.Name)
  83. if err != nil {
  84. return err
  85. } else if isExist {
  86. return ErrUserAlreadyExist{org.Name}
  87. }
  88. org.LowerName = strings.ToLower(org.Name)
  89. org.FullName = org.Name
  90. org.UseCustomAvatar = true
  91. org.NumTeams = 1
  92. org.NumMembers = 1
  93. sess := x.NewSession()
  94. defer sessionRelease(sess)
  95. if err = sess.Begin(); err != nil {
  96. return err
  97. }
  98. if _, err = sess.Insert(org); err != nil {
  99. return fmt.Errorf("insert organization: %v", err)
  100. }
  101. org.GenerateRandomAvatar()
  102. // Add initial creator to organization and owner team.
  103. if _, err = sess.Insert(&OrgUser{
  104. Uid: owner.Id,
  105. OrgID: org.Id,
  106. IsOwner: true,
  107. NumTeams: 1,
  108. }); err != nil {
  109. return fmt.Errorf("insert org-user relation: %v", err)
  110. }
  111. // Create default owner team.
  112. t := &Team{
  113. OrgID: org.Id,
  114. LowerName: strings.ToLower(OWNER_TEAM),
  115. Name: OWNER_TEAM,
  116. Authorize: ACCESS_MODE_OWNER,
  117. NumMembers: 1,
  118. }
  119. if _, err = sess.Insert(t); err != nil {
  120. return fmt.Errorf("insert owner team: %v", err)
  121. }
  122. if _, err = sess.Insert(&TeamUser{
  123. Uid: owner.Id,
  124. OrgID: org.Id,
  125. TeamID: t.ID,
  126. }); err != nil {
  127. return fmt.Errorf("insert team-user relation: %v", err)
  128. }
  129. if err = os.MkdirAll(UserPath(org.Name), os.ModePerm); err != nil {
  130. return fmt.Errorf("create directory: %v", err)
  131. }
  132. return sess.Commit()
  133. }
  134. // GetOrgByName returns organization by given name.
  135. func GetOrgByName(name string) (*User, error) {
  136. if len(name) == 0 {
  137. return nil, ErrOrgNotExist
  138. }
  139. u := &User{
  140. LowerName: strings.ToLower(name),
  141. Type: ORGANIZATION,
  142. }
  143. has, err := x.Get(u)
  144. if err != nil {
  145. return nil, err
  146. } else if !has {
  147. return nil, ErrOrgNotExist
  148. }
  149. return u, nil
  150. }
  151. // CountOrganizations returns number of organizations.
  152. func CountOrganizations() int64 {
  153. count, _ := x.Where("type=1").Count(new(User))
  154. return count
  155. }
  156. // Organizations returns number of organizations in given page.
  157. func Organizations(page, pageSize int) ([]*User, error) {
  158. orgs := make([]*User, 0, pageSize)
  159. return orgs, x.Limit(pageSize, (page-1)*pageSize).Where("type=1").Asc("id").Find(&orgs)
  160. }
  161. // DeleteOrganization completely and permanently deletes everything of organization.
  162. func DeleteOrganization(org *User) (err error) {
  163. if err := DeleteUser(org); err != nil {
  164. return err
  165. }
  166. sess := x.NewSession()
  167. defer sessionRelease(sess)
  168. if err = sess.Begin(); err != nil {
  169. return err
  170. }
  171. if err = deleteBeans(sess,
  172. &Team{OrgID: org.Id},
  173. &OrgUser{OrgID: org.Id},
  174. &TeamUser{OrgID: org.Id},
  175. ); err != nil {
  176. return fmt.Errorf("deleteBeans: %v", err)
  177. }
  178. if err = deleteUser(sess, org); err != nil {
  179. return fmt.Errorf("deleteUser: %v", err)
  180. }
  181. return sess.Commit()
  182. }
  183. // ________ ____ ___
  184. // \_____ \_______ ____ | | \______ ___________
  185. // / | \_ __ \/ ___\| | / ___// __ \_ __ \
  186. // / | \ | \/ /_/ > | /\___ \\ ___/| | \/
  187. // \_______ /__| \___ /|______//____ >\___ >__|
  188. // \/ /_____/ \/ \/
  189. // OrgUser represents an organization-user relation.
  190. type OrgUser struct {
  191. ID int64 `xorm:"pk autoincr"`
  192. Uid int64 `xorm:"INDEX UNIQUE(s)"`
  193. OrgID int64 `xorm:"INDEX UNIQUE(s)"`
  194. IsPublic bool
  195. IsOwner bool
  196. NumTeams int
  197. }
  198. // IsOrganizationOwner returns true if given user is in the owner team.
  199. func IsOrganizationOwner(orgId, uid int64) bool {
  200. has, _ := x.Where("is_owner=?", true).And("uid=?", uid).And("org_id=?", orgId).Get(new(OrgUser))
  201. return has
  202. }
  203. // IsOrganizationMember returns true if given user is member of organization.
  204. func IsOrganizationMember(orgId, uid int64) bool {
  205. has, _ := x.Where("uid=?", uid).And("org_id=?", orgId).Get(new(OrgUser))
  206. return has
  207. }
  208. // IsPublicMembership returns true if given user public his/her membership.
  209. func IsPublicMembership(orgId, uid int64) bool {
  210. has, _ := x.Where("uid=?", uid).And("org_id=?", orgId).And("is_public=?", true).Get(new(OrgUser))
  211. return has
  212. }
  213. func getOwnedOrgsByUserID(sess *xorm.Session, userID int64) ([]*User, error) {
  214. orgs := make([]*User, 0, 10)
  215. return orgs, sess.Where("`org_user`.uid=?", userID).And("`org_user`.is_owner=?", true).
  216. Join("INNER", "`org_user`", "`org_user`.org_id=`user`.id").Find(&orgs)
  217. }
  218. // GetOwnedOrgsByUserID returns a list of organizations are owned by given user ID.
  219. func GetOwnedOrgsByUserID(userID int64) ([]*User, error) {
  220. sess := x.NewSession()
  221. return getOwnedOrgsByUserID(sess, userID)
  222. }
  223. // GetOwnedOrganizationsByUserIDDesc returns a list of organizations are owned by
  224. // given user ID and descring order by given condition.
  225. func GetOwnedOrgsByUserIDDesc(userID int64, desc string) ([]*User, error) {
  226. sess := x.NewSession()
  227. return getOwnedOrgsByUserID(sess.Desc(desc), userID)
  228. }
  229. // GetOrgUsersByUserId returns all organization-user relations by user ID.
  230. func GetOrgUsersByUserId(uid int64) ([]*OrgUser, error) {
  231. ous := make([]*OrgUser, 0, 10)
  232. err := x.Where("uid=?", uid).Find(&ous)
  233. return ous, err
  234. }
  235. // GetOrgUsersByOrgId returns all organization-user relations by organization ID.
  236. func GetOrgUsersByOrgId(orgId int64) ([]*OrgUser, error) {
  237. ous := make([]*OrgUser, 0, 10)
  238. err := x.Where("org_id=?", orgId).Find(&ous)
  239. return ous, err
  240. }
  241. // ChangeOrgUserStatus changes public or private membership status.
  242. func ChangeOrgUserStatus(orgId, uid int64, public bool) error {
  243. ou := new(OrgUser)
  244. has, err := x.Where("uid=?", uid).And("org_id=?", orgId).Get(ou)
  245. if err != nil {
  246. return err
  247. } else if !has {
  248. return nil
  249. }
  250. ou.IsPublic = public
  251. _, err = x.Id(ou.ID).AllCols().Update(ou)
  252. return err
  253. }
  254. // AddOrgUser adds new user to given organization.
  255. func AddOrgUser(orgId, uid int64) error {
  256. if IsOrganizationMember(orgId, uid) {
  257. return nil
  258. }
  259. sess := x.NewSession()
  260. defer sess.Close()
  261. if err := sess.Begin(); err != nil {
  262. return err
  263. }
  264. ou := &OrgUser{
  265. Uid: uid,
  266. OrgID: orgId,
  267. }
  268. if _, err := sess.Insert(ou); err != nil {
  269. sess.Rollback()
  270. return err
  271. } else if _, err = sess.Exec("UPDATE `user` SET num_members = num_members + 1 WHERE id = ?", orgId); err != nil {
  272. sess.Rollback()
  273. return err
  274. }
  275. return sess.Commit()
  276. }
  277. // RemoveOrgUser removes user from given organization.
  278. func RemoveOrgUser(orgId, uid int64) error {
  279. ou := new(OrgUser)
  280. has, err := x.Where("uid=?", uid).And("org_id=?", orgId).Get(ou)
  281. if err != nil {
  282. return fmt.Errorf("get org-user: %v", err)
  283. } else if !has {
  284. return nil
  285. }
  286. u, err := GetUserByID(uid)
  287. if err != nil {
  288. return fmt.Errorf("GetUserById: %v", err)
  289. }
  290. org, err := GetUserByID(orgId)
  291. if err != nil {
  292. return fmt.Errorf("get organization: %v", err)
  293. } else if err = org.GetRepositories(); err != nil {
  294. return fmt.Errorf("GetRepositories: %v", err)
  295. }
  296. // Check if the user to delete is the last member in owner team.
  297. if IsOrganizationOwner(orgId, uid) {
  298. t, err := org.GetOwnerTeam()
  299. if err != nil {
  300. return err
  301. }
  302. if t.NumMembers == 1 {
  303. return ErrLastOrgOwner{UID: uid}
  304. }
  305. }
  306. sess := x.NewSession()
  307. defer sessionRelease(sess)
  308. if err := sess.Begin(); err != nil {
  309. return err
  310. }
  311. if _, err := sess.Id(ou.ID).Delete(ou); err != nil {
  312. return err
  313. } else if _, err = sess.Exec("UPDATE `user` SET num_members=num_members-1 WHERE id=?", orgId); err != nil {
  314. return err
  315. }
  316. // Delete all repository accesses.
  317. access := &Access{UserID: u.Id}
  318. for _, repo := range org.Repos {
  319. access.RepoID = repo.ID
  320. if _, err = sess.Delete(access); err != nil {
  321. return err
  322. } else if err = watchRepo(sess, u.Id, repo.ID, false); err != nil {
  323. return err
  324. }
  325. }
  326. // Delete member in his/her teams.
  327. teams, err := getUserTeams(sess, org.Id, u.Id)
  328. if err != nil {
  329. return err
  330. }
  331. for _, t := range teams {
  332. if err = removeTeamMember(sess, org.Id, t.ID, u.Id); err != nil {
  333. return err
  334. }
  335. }
  336. return sess.Commit()
  337. }
  338. // ___________
  339. // \__ ___/___ _____ _____
  340. // | |_/ __ \\__ \ / \
  341. // | |\ ___/ / __ \| Y Y \
  342. // |____| \___ >____ /__|_| /
  343. // \/ \/ \/
  344. const OWNER_TEAM = "Owners"
  345. // Team represents a organization team.
  346. type Team struct {
  347. ID int64 `xorm:"pk autoincr"`
  348. OrgID int64 `xorm:"INDEX"`
  349. LowerName string
  350. Name string
  351. Description string
  352. Authorize AccessMode
  353. Repos []*Repository `xorm:"-"`
  354. Members []*User `xorm:"-"`
  355. NumRepos int
  356. NumMembers int
  357. }
  358. // IsOwnerTeam returns true if team is owner team.
  359. func (t *Team) IsOwnerTeam() bool {
  360. return t.Name == OWNER_TEAM
  361. }
  362. // IsTeamMember returns true if given user is a member of team.
  363. func (t *Team) IsMember(uid int64) bool {
  364. return IsTeamMember(t.OrgID, t.ID, uid)
  365. }
  366. func (t *Team) getRepositories(e Engine) (err error) {
  367. teamRepos := make([]*TeamRepo, 0, t.NumRepos)
  368. if err = x.Where("team_id=?", t.ID).Find(&teamRepos); err != nil {
  369. return fmt.Errorf("get team-repos: %v", err)
  370. }
  371. t.Repos = make([]*Repository, 0, len(teamRepos))
  372. for i := range teamRepos {
  373. repo, err := getRepositoryByID(e, teamRepos[i].RepoID)
  374. if err != nil {
  375. return fmt.Errorf("getRepositoryById(%d): %v", teamRepos[i].RepoID, err)
  376. }
  377. t.Repos = append(t.Repos, repo)
  378. }
  379. return nil
  380. }
  381. // GetRepositories returns all repositories in team of organization.
  382. func (t *Team) GetRepositories() error {
  383. return t.getRepositories(x)
  384. }
  385. func (t *Team) getMembers(e Engine) (err error) {
  386. t.Members, err = getTeamMembers(e, t.ID)
  387. return err
  388. }
  389. // GetMembers returns all members in team of organization.
  390. func (t *Team) GetMembers() (err error) {
  391. return t.getMembers(x)
  392. }
  393. // AddMember adds new member to team of organization.
  394. func (t *Team) AddMember(uid int64) error {
  395. return AddTeamMember(t.OrgID, t.ID, uid)
  396. }
  397. // RemoveMember removes member from team of organization.
  398. func (t *Team) RemoveMember(uid int64) error {
  399. return RemoveTeamMember(t.OrgID, t.ID, uid)
  400. }
  401. func (t *Team) hasRepository(e Engine, repoID int64) bool {
  402. return hasTeamRepo(e, t.OrgID, t.ID, repoID)
  403. }
  404. // HasRepository returns true if given repository belong to team.
  405. func (t *Team) HasRepository(repoID int64) bool {
  406. return t.hasRepository(x, repoID)
  407. }
  408. func (t *Team) addRepository(e Engine, repo *Repository) (err error) {
  409. if err = addTeamRepo(e, t.OrgID, t.ID, repo.ID); err != nil {
  410. return err
  411. }
  412. t.NumRepos++
  413. if _, err = e.Id(t.ID).AllCols().Update(t); err != nil {
  414. return fmt.Errorf("update team: %v", err)
  415. }
  416. if err = repo.recalculateTeamAccesses(e, 0); err != nil {
  417. return fmt.Errorf("recalculateAccesses: %v", err)
  418. }
  419. if err = t.getMembers(e); err != nil {
  420. return fmt.Errorf("getMembers: %v", err)
  421. }
  422. for _, u := range t.Members {
  423. if err = watchRepo(e, u.Id, repo.ID, true); err != nil {
  424. return fmt.Errorf("watchRepo: %v", err)
  425. }
  426. }
  427. return nil
  428. }
  429. // AddRepository adds new repository to team of organization.
  430. func (t *Team) AddRepository(repo *Repository) (err error) {
  431. if repo.OwnerID != t.OrgID {
  432. return errors.New("Repository does not belong to organization")
  433. } else if t.HasRepository(repo.ID) {
  434. return nil
  435. }
  436. sess := x.NewSession()
  437. defer sessionRelease(sess)
  438. if err = sess.Begin(); err != nil {
  439. return err
  440. }
  441. if err = t.addRepository(sess, repo); err != nil {
  442. return err
  443. }
  444. return sess.Commit()
  445. }
  446. func (t *Team) removeRepository(e Engine, repo *Repository, recalculate bool) (err error) {
  447. if err = removeTeamRepo(e, t.ID, repo.ID); err != nil {
  448. return err
  449. }
  450. t.NumRepos--
  451. if _, err = e.Id(t.ID).AllCols().Update(t); err != nil {
  452. return err
  453. }
  454. // Don't need to recalculate when delete a repository from organization.
  455. if recalculate {
  456. if err = repo.recalculateTeamAccesses(e, t.ID); err != nil {
  457. return err
  458. }
  459. }
  460. if err = t.getMembers(e); err != nil {
  461. return fmt.Errorf("get team members: %v", err)
  462. }
  463. for _, u := range t.Members {
  464. has, err := hasAccess(e, u, repo, ACCESS_MODE_READ)
  465. if err != nil {
  466. return err
  467. } else if has {
  468. continue
  469. }
  470. if err = watchRepo(e, u.Id, repo.ID, false); err != nil {
  471. return err
  472. }
  473. }
  474. return nil
  475. }
  476. // RemoveRepository removes repository from team of organization.
  477. func (t *Team) RemoveRepository(repoID int64) error {
  478. if !t.HasRepository(repoID) {
  479. return nil
  480. }
  481. repo, err := GetRepositoryByID(repoID)
  482. if err != nil {
  483. return err
  484. }
  485. sess := x.NewSession()
  486. defer sessionRelease(sess)
  487. if err = sess.Begin(); err != nil {
  488. return err
  489. }
  490. if err = t.removeRepository(sess, repo, true); err != nil {
  491. return err
  492. }
  493. return sess.Commit()
  494. }
  495. // NewTeam creates a record of new team.
  496. // It's caller's responsibility to assign organization ID.
  497. func NewTeam(t *Team) (err error) {
  498. if err = IsUsableName(t.Name); err != nil {
  499. return err
  500. }
  501. has, err := x.Id(t.OrgID).Get(new(User))
  502. if err != nil {
  503. return err
  504. } else if !has {
  505. return ErrOrgNotExist
  506. }
  507. t.LowerName = strings.ToLower(t.Name)
  508. has, err = x.Where("org_id=?", t.OrgID).And("lower_name=?", t.LowerName).Get(new(Team))
  509. if err != nil {
  510. return err
  511. } else if has {
  512. return ErrTeamAlreadyExist
  513. }
  514. sess := x.NewSession()
  515. defer sess.Close()
  516. if err = sess.Begin(); err != nil {
  517. return err
  518. }
  519. if _, err = sess.Insert(t); err != nil {
  520. sess.Rollback()
  521. return err
  522. }
  523. // Update organization number of teams.
  524. if _, err = sess.Exec("UPDATE `user` SET num_teams=num_teams+1 WHERE id = ?", t.OrgID); err != nil {
  525. sess.Rollback()
  526. return err
  527. }
  528. return sess.Commit()
  529. }
  530. func getTeam(e Engine, orgId int64, name string) (*Team, error) {
  531. t := &Team{
  532. OrgID: orgId,
  533. LowerName: strings.ToLower(name),
  534. }
  535. has, err := e.Get(t)
  536. if err != nil {
  537. return nil, err
  538. } else if !has {
  539. return nil, ErrTeamNotExist
  540. }
  541. return t, nil
  542. }
  543. // GetTeam returns team by given team name and organization.
  544. func GetTeam(orgId int64, name string) (*Team, error) {
  545. return getTeam(x, orgId, name)
  546. }
  547. func getTeamById(e Engine, teamId int64) (*Team, error) {
  548. t := new(Team)
  549. has, err := e.Id(teamId).Get(t)
  550. if err != nil {
  551. return nil, err
  552. } else if !has {
  553. return nil, ErrTeamNotExist
  554. }
  555. return t, nil
  556. }
  557. // GetTeamById returns team by given ID.
  558. func GetTeamById(teamId int64) (*Team, error) {
  559. return getTeamById(x, teamId)
  560. }
  561. // UpdateTeam updates information of team.
  562. func UpdateTeam(t *Team, authChanged bool) (err error) {
  563. if err = IsUsableName(t.Name); err != nil {
  564. return err
  565. }
  566. if len(t.Description) > 255 {
  567. t.Description = t.Description[:255]
  568. }
  569. sess := x.NewSession()
  570. defer sessionRelease(sess)
  571. if err = sess.Begin(); err != nil {
  572. return err
  573. }
  574. t.LowerName = strings.ToLower(t.Name)
  575. if _, err = sess.Id(t.ID).AllCols().Update(t); err != nil {
  576. return fmt.Errorf("update: %v", err)
  577. }
  578. // Update access for team members if needed.
  579. if authChanged {
  580. if err = t.getRepositories(sess); err != nil {
  581. return fmt.Errorf("getRepositories:%v", err)
  582. }
  583. for _, repo := range t.Repos {
  584. if err = repo.recalculateTeamAccesses(sess, 0); err != nil {
  585. return fmt.Errorf("recalculateTeamAccesses: %v", err)
  586. }
  587. }
  588. }
  589. return sess.Commit()
  590. }
  591. // DeleteTeam deletes given team.
  592. // It's caller's responsibility to assign organization ID.
  593. func DeleteTeam(t *Team) error {
  594. if err := t.GetRepositories(); err != nil {
  595. return err
  596. }
  597. // Get organization.
  598. org, err := GetUserByID(t.OrgID)
  599. if err != nil {
  600. return err
  601. }
  602. sess := x.NewSession()
  603. defer sessionRelease(sess)
  604. if err = sess.Begin(); err != nil {
  605. return err
  606. }
  607. // Delete all accesses.
  608. for _, repo := range t.Repos {
  609. if err = repo.recalculateTeamAccesses(sess, t.ID); err != nil {
  610. return err
  611. }
  612. }
  613. // Delete team-user.
  614. if _, err = sess.Where("org_id=?", org.Id).Where("team_id=?", t.ID).Delete(new(TeamUser)); err != nil {
  615. return err
  616. }
  617. // Delete team.
  618. if _, err = sess.Id(t.ID).Delete(new(Team)); err != nil {
  619. return err
  620. }
  621. // Update organization number of teams.
  622. if _, err = sess.Exec("UPDATE `user` SET num_teams=num_teams-1 WHERE id=?", t.OrgID); err != nil {
  623. return err
  624. }
  625. return sess.Commit()
  626. }
  627. // ___________ ____ ___
  628. // \__ ___/___ _____ _____ | | \______ ___________
  629. // | |_/ __ \\__ \ / \| | / ___// __ \_ __ \
  630. // | |\ ___/ / __ \| Y Y \ | /\___ \\ ___/| | \/
  631. // |____| \___ >____ /__|_| /______//____ >\___ >__|
  632. // \/ \/ \/ \/ \/
  633. // TeamUser represents an team-user relation.
  634. type TeamUser struct {
  635. ID int64 `xorm:"pk autoincr"`
  636. OrgID int64 `xorm:"INDEX"`
  637. TeamID int64 `xorm:"UNIQUE(s)"`
  638. Uid int64 `xorm:"UNIQUE(s)"`
  639. }
  640. func isTeamMember(e Engine, orgID, teamID, uid int64) bool {
  641. has, _ := e.Where("org_id=?", orgID).And("team_id=?", teamID).And("uid=?", uid).Get(new(TeamUser))
  642. return has
  643. }
  644. // IsTeamMember returns true if given user is a member of team.
  645. func IsTeamMember(orgID, teamID, uid int64) bool {
  646. return isTeamMember(x, orgID, teamID, uid)
  647. }
  648. func getTeamMembers(e Engine, teamID int64) (_ []*User, err error) {
  649. teamUsers := make([]*TeamUser, 0, 10)
  650. if err = e.Where("team_id=?", teamID).Find(&teamUsers); err != nil {
  651. return nil, fmt.Errorf("get team-users: %v", err)
  652. }
  653. members := make([]*User, 0, len(teamUsers))
  654. for i := range teamUsers {
  655. member := new(User)
  656. if _, err = e.Id(teamUsers[i].Uid).Get(member); err != nil {
  657. return nil, fmt.Errorf("get user '%d': %v", teamUsers[i].Uid, err)
  658. }
  659. members = append(members, member)
  660. }
  661. return members, nil
  662. }
  663. // GetTeamMembers returns all members in given team of organization.
  664. func GetTeamMembers(teamID int64) ([]*User, error) {
  665. return getTeamMembers(x, teamID)
  666. }
  667. func getUserTeams(e Engine, orgId, uid int64) ([]*Team, error) {
  668. tus := make([]*TeamUser, 0, 5)
  669. if err := e.Where("uid=?", uid).And("org_id=?", orgId).Find(&tus); err != nil {
  670. return nil, err
  671. }
  672. ts := make([]*Team, len(tus))
  673. for i, tu := range tus {
  674. t := new(Team)
  675. has, err := e.Id(tu.TeamID).Get(t)
  676. if err != nil {
  677. return nil, err
  678. } else if !has {
  679. return nil, ErrTeamNotExist
  680. }
  681. ts[i] = t
  682. }
  683. return ts, nil
  684. }
  685. // GetUserTeams returns all teams that user belongs to in given organization.
  686. func GetUserTeams(orgId, uid int64) ([]*Team, error) {
  687. return getUserTeams(x, orgId, uid)
  688. }
  689. // AddTeamMember adds new member to given team of given organization.
  690. func AddTeamMember(orgId, teamId, uid int64) error {
  691. if IsTeamMember(orgId, teamId, uid) {
  692. return nil
  693. }
  694. if err := AddOrgUser(orgId, uid); err != nil {
  695. return err
  696. }
  697. // Get team and its repositories.
  698. t, err := GetTeamById(teamId)
  699. if err != nil {
  700. return err
  701. }
  702. t.NumMembers++
  703. if err = t.GetRepositories(); err != nil {
  704. return err
  705. }
  706. sess := x.NewSession()
  707. defer sessionRelease(sess)
  708. if err = sess.Begin(); err != nil {
  709. return err
  710. }
  711. tu := &TeamUser{
  712. Uid: uid,
  713. OrgID: orgId,
  714. TeamID: teamId,
  715. }
  716. if _, err = sess.Insert(tu); err != nil {
  717. return err
  718. } else if _, err = sess.Id(t.ID).Update(t); err != nil {
  719. return err
  720. }
  721. // Give access to team repositories.
  722. for _, repo := range t.Repos {
  723. if err = repo.recalculateTeamAccesses(sess, 0); err != nil {
  724. return err
  725. }
  726. }
  727. // We make sure it exists before.
  728. ou := new(OrgUser)
  729. if _, err = sess.Where("uid=?", uid).And("org_id=?", orgId).Get(ou); err != nil {
  730. return err
  731. }
  732. ou.NumTeams++
  733. if t.IsOwnerTeam() {
  734. ou.IsOwner = true
  735. }
  736. if _, err = sess.Id(ou.ID).AllCols().Update(ou); err != nil {
  737. return err
  738. }
  739. return sess.Commit()
  740. }
  741. func removeTeamMember(e Engine, orgId, teamId, uid int64) error {
  742. if !isTeamMember(e, orgId, teamId, uid) {
  743. return nil
  744. }
  745. // Get team and its repositories.
  746. t, err := getTeamById(e, teamId)
  747. if err != nil {
  748. return err
  749. }
  750. // Check if the user to delete is the last member in owner team.
  751. if t.IsOwnerTeam() && t.NumMembers == 1 {
  752. return ErrLastOrgOwner{UID: uid}
  753. }
  754. t.NumMembers--
  755. if err = t.getRepositories(e); err != nil {
  756. return err
  757. }
  758. // Get organization.
  759. org, err := getUserByID(e, orgId)
  760. if err != nil {
  761. return err
  762. }
  763. tu := &TeamUser{
  764. Uid: uid,
  765. OrgID: orgId,
  766. TeamID: teamId,
  767. }
  768. if _, err := e.Delete(tu); err != nil {
  769. return err
  770. } else if _, err = e.Id(t.ID).AllCols().Update(t); err != nil {
  771. return err
  772. }
  773. // Delete access to team repositories.
  774. for _, repo := range t.Repos {
  775. if err = repo.recalculateTeamAccesses(e, 0); err != nil {
  776. return err
  777. }
  778. }
  779. // This must exist.
  780. ou := new(OrgUser)
  781. _, err = e.Where("uid=?", uid).And("org_id=?", org.Id).Get(ou)
  782. if err != nil {
  783. return err
  784. }
  785. ou.NumTeams--
  786. if t.IsOwnerTeam() {
  787. ou.IsOwner = false
  788. }
  789. if _, err = e.Id(ou.ID).AllCols().Update(ou); err != nil {
  790. return err
  791. }
  792. return nil
  793. }
  794. // RemoveTeamMember removes member from given team of given organization.
  795. func RemoveTeamMember(orgId, teamId, uid int64) error {
  796. sess := x.NewSession()
  797. defer sessionRelease(sess)
  798. if err := sess.Begin(); err != nil {
  799. return err
  800. }
  801. if err := removeTeamMember(sess, orgId, teamId, uid); err != nil {
  802. return err
  803. }
  804. return sess.Commit()
  805. }
  806. // ___________ __________
  807. // \__ ___/___ _____ _____\______ \ ____ ______ ____
  808. // | |_/ __ \\__ \ / \| _// __ \\____ \ / _ \
  809. // | |\ ___/ / __ \| Y Y \ | \ ___/| |_> > <_> )
  810. // |____| \___ >____ /__|_| /____|_ /\___ > __/ \____/
  811. // \/ \/ \/ \/ \/|__|
  812. // TeamRepo represents an team-repository relation.
  813. type TeamRepo struct {
  814. ID int64 `xorm:"pk autoincr"`
  815. OrgID int64 `xorm:"INDEX"`
  816. TeamID int64 `xorm:"UNIQUE(s)"`
  817. RepoID int64 `xorm:"UNIQUE(s)"`
  818. }
  819. func hasTeamRepo(e Engine, orgID, teamID, repoID int64) bool {
  820. has, _ := e.Where("org_id=?", orgID).And("team_id=?", teamID).And("repo_id=?", repoID).Get(new(TeamRepo))
  821. return has
  822. }
  823. // HasTeamRepo returns true if given repository belongs to team.
  824. func HasTeamRepo(orgID, teamID, repoID int64) bool {
  825. return hasTeamRepo(x, orgID, teamID, repoID)
  826. }
  827. func addTeamRepo(e Engine, orgID, teamID, repoID int64) error {
  828. _, err := e.InsertOne(&TeamRepo{
  829. OrgID: orgID,
  830. TeamID: teamID,
  831. RepoID: repoID,
  832. })
  833. return err
  834. }
  835. // AddTeamRepo adds new repository relation to team.
  836. func AddTeamRepo(orgID, teamID, repoID int64) error {
  837. return addTeamRepo(x, orgID, teamID, repoID)
  838. }
  839. func removeTeamRepo(e Engine, teamID, repoID int64) error {
  840. _, err := e.Delete(&TeamRepo{
  841. TeamID: teamID,
  842. RepoID: repoID,
  843. })
  844. return err
  845. }
  846. // RemoveTeamRepo deletes repository relation to team.
  847. func RemoveTeamRepo(teamID, repoID int64) error {
  848. return removeTeamRepo(x, teamID, repoID)
  849. }
  850. func removeOrgRepo(e Engine, orgID, repoID int64) error {
  851. _, err := e.Delete(&TeamRepo{
  852. OrgID: orgID,
  853. RepoID: repoID,
  854. })
  855. return err
  856. }
  857. // RemoveOrgRepo removes all team-repository relations of given organization.
  858. func RemoveOrgRepo(orgID, repoID int64) error {
  859. return removeOrgRepo(x, orgID, repoID)
  860. }