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.

1074 lines
24 KiB

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