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.

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