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.

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