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.

1097 lines
25 KiB

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, t.Id, repo.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 == 0 {
  448. access.Mode = mode
  449. if _, err = sess.Insert(access); err != nil {
  450. sess.Rollback()
  451. return fmt.Errorf("fail to insert access: %v", err)
  452. }
  453. } else if auth < t.Authorize {
  454. if err = addAccessWithAuthorize(sess, access, mode); err != nil {
  455. sess.Rollback()
  456. return err
  457. }
  458. }
  459. if err = WatchRepo(u.Id, repo.Id, true); err != nil {
  460. sess.Rollback()
  461. return err
  462. }
  463. }
  464. return sess.Commit()
  465. }
  466. // RemoveRepository removes repository from team of organization.
  467. func (t *Team) RemoveRepository(repoId int64) error {
  468. idStr := "$" + com.ToStr(repoId) + "|"
  469. if !strings.Contains(t.RepoIds, idStr) {
  470. return nil
  471. }
  472. repo, err := GetRepositoryById(repoId)
  473. if err != nil {
  474. return err
  475. }
  476. if err = repo.GetOwner(); err != nil {
  477. return err
  478. } else if err = t.GetMembers(); err != nil {
  479. return err
  480. }
  481. sess := x.NewSession()
  482. defer sess.Close()
  483. if err = sess.Begin(); err != nil {
  484. return err
  485. }
  486. t.NumRepos--
  487. t.RepoIds = strings.Replace(t.RepoIds, idStr, "", 1)
  488. if _, err = sess.Id(t.Id).AllCols().Update(t); err != nil {
  489. sess.Rollback()
  490. return err
  491. }
  492. // Remove access to team members.
  493. for _, u := range t.Members {
  494. auth, err := GetHighestAuthorize(t.OrgId, u.Id, t.Id, repo.Id)
  495. if err != nil {
  496. sess.Rollback()
  497. return err
  498. }
  499. access := &Access{
  500. UserName: u.LowerName,
  501. RepoName: path.Join(repo.Owner.LowerName, repo.LowerName),
  502. }
  503. if auth == 0 {
  504. if _, err = sess.Delete(access); err != nil {
  505. sess.Rollback()
  506. return fmt.Errorf("fail to delete access: %v", err)
  507. } else if err = WatchRepo(u.Id, repo.Id, false); err != nil {
  508. sess.Rollback()
  509. return err
  510. }
  511. } else if auth < t.Authorize {
  512. if err = addAccessWithAuthorize(sess, access, AuthorizeToAccessType(auth)); err != nil {
  513. sess.Rollback()
  514. return err
  515. }
  516. }
  517. }
  518. return sess.Commit()
  519. }
  520. // NewTeam creates a record of new team.
  521. // It's caller's responsibility to assign organization ID.
  522. func NewTeam(t *Team) error {
  523. if !IsLegalName(t.Name) {
  524. return ErrTeamNameIllegal
  525. }
  526. has, err := x.Id(t.OrgId).Get(new(User))
  527. if err != nil {
  528. return err
  529. } else if !has {
  530. return ErrOrgNotExist
  531. }
  532. t.LowerName = strings.ToLower(t.Name)
  533. has, err = x.Where("org_id=?", t.OrgId).And("lower_name=?", t.LowerName).Get(new(Team))
  534. if err != nil {
  535. return err
  536. } else if has {
  537. return ErrTeamAlreadyExist
  538. }
  539. sess := x.NewSession()
  540. defer sess.Close()
  541. if err = sess.Begin(); err != nil {
  542. return err
  543. }
  544. if _, err = sess.Insert(t); err != nil {
  545. sess.Rollback()
  546. return err
  547. }
  548. // Update organization number of teams.
  549. if _, err = sess.Exec("UPDATE `user` SET num_teams = num_teams + 1 WHERE id = ?", t.OrgId); err != nil {
  550. sess.Rollback()
  551. return err
  552. }
  553. return sess.Commit()
  554. }
  555. // GetTeam returns team by given team name and organization.
  556. func GetTeam(orgId int64, name string) (*Team, error) {
  557. t := &Team{
  558. OrgId: orgId,
  559. LowerName: strings.ToLower(name),
  560. }
  561. has, err := x.Get(t)
  562. if err != nil {
  563. return nil, err
  564. } else if !has {
  565. return nil, ErrTeamNotExist
  566. }
  567. return t, nil
  568. }
  569. // GetTeamById returns team by given ID.
  570. func GetTeamById(teamId int64) (*Team, error) {
  571. t := new(Team)
  572. has, err := x.Id(teamId).Get(t)
  573. if err != nil {
  574. return nil, err
  575. } else if !has {
  576. return nil, ErrTeamNotExist
  577. }
  578. return t, nil
  579. }
  580. // GetHighestAuthorize returns highest repository authorize level for given user and team.
  581. func GetHighestAuthorize(orgId, uid, teamId, repoId int64) (AuthorizeType, error) {
  582. ts, err := GetUserTeams(orgId, uid)
  583. if err != nil {
  584. return 0, err
  585. }
  586. var auth AuthorizeType = 0
  587. for _, t := range ts {
  588. // Not current team and has given repository.
  589. if t.Id != teamId && strings.Contains(t.RepoIds, "$"+com.ToStr(repoId)+"|") {
  590. // Fast return.
  591. if t.Authorize == ORG_WRITABLE {
  592. return ORG_WRITABLE, nil
  593. }
  594. if t.Authorize > auth {
  595. auth = t.Authorize
  596. }
  597. }
  598. }
  599. return auth, nil
  600. }
  601. // UpdateTeam updates information of team.
  602. func UpdateTeam(t *Team, authChanged bool) (err error) {
  603. if !IsLegalName(t.Name) {
  604. return ErrTeamNameIllegal
  605. }
  606. if len(t.Description) > 255 {
  607. t.Description = t.Description[:255]
  608. }
  609. sess := x.NewSession()
  610. defer sess.Close()
  611. if err = sess.Begin(); err != nil {
  612. return err
  613. }
  614. // Update access for team members if needed.
  615. if authChanged && !t.IsOwnerTeam() {
  616. if err = t.GetRepositories(); err != nil {
  617. return err
  618. } else if err = t.GetMembers(); err != nil {
  619. return err
  620. }
  621. // Get organization.
  622. org, err := GetUserById(t.OrgId)
  623. if err != nil {
  624. return err
  625. }
  626. // Update access.
  627. mode := AuthorizeToAccessType(t.Authorize)
  628. for _, repo := range t.Repos {
  629. for _, u := range t.Members {
  630. // ORG_WRITABLE is the highest authorize level for now.
  631. // Skip checking others if current team has this level.
  632. if t.Authorize < ORG_WRITABLE {
  633. auth, err := GetHighestAuthorize(org.Id, u.Id, t.Id, repo.Id)
  634. if err != nil {
  635. sess.Rollback()
  636. return err
  637. }
  638. if auth >= t.Authorize {
  639. continue // Other team has higher or same authorize level.
  640. }
  641. }
  642. access := &Access{
  643. UserName: u.LowerName,
  644. RepoName: path.Join(org.LowerName, repo.LowerName),
  645. }
  646. if err = addAccessWithAuthorize(sess, access, mode); err != nil {
  647. sess.Rollback()
  648. return err
  649. }
  650. }
  651. }
  652. }
  653. t.LowerName = strings.ToLower(t.Name)
  654. if _, err = sess.Id(t.Id).AllCols().Update(t); err != nil {
  655. sess.Rollback()
  656. return err
  657. }
  658. return sess.Commit()
  659. }
  660. // DeleteTeam deletes given team.
  661. // It's caller's responsibility to assign organization ID.
  662. func DeleteTeam(t *Team) error {
  663. if err := t.GetRepositories(); err != nil {
  664. return err
  665. } else if err = t.GetMembers(); err != nil {
  666. return err
  667. }
  668. // Get organization.
  669. org, err := GetUserById(t.OrgId)
  670. if err != nil {
  671. return err
  672. }
  673. sess := x.NewSession()
  674. defer sess.Close()
  675. if err = sess.Begin(); err != nil {
  676. return err
  677. }
  678. // Delete all accesses.
  679. for _, repo := range t.Repos {
  680. for _, u := range t.Members {
  681. auth, err := GetHighestAuthorize(org.Id, u.Id, t.Id, repo.Id)
  682. if err != nil {
  683. sess.Rollback()
  684. return err
  685. }
  686. access := &Access{
  687. UserName: u.LowerName,
  688. RepoName: path.Join(org.LowerName, repo.LowerName),
  689. }
  690. if auth == 0 {
  691. if _, err = sess.Delete(access); err != nil {
  692. sess.Rollback()
  693. return fmt.Errorf("fail to delete access: %v", err)
  694. }
  695. } else if auth < t.Authorize {
  696. // Downgrade authorize level.
  697. if err = addAccessWithAuthorize(sess, access, AuthorizeToAccessType(auth)); err != nil {
  698. sess.Rollback()
  699. return err
  700. }
  701. }
  702. }
  703. }
  704. // Delete team-user.
  705. if _, err = sess.Where("org_id=?", org.Id).Where("team_id=?", t.Id).Delete(new(TeamUser)); err != nil {
  706. sess.Rollback()
  707. return err
  708. }
  709. // Delete team.
  710. if _, err = sess.Id(t.Id).Delete(new(Team)); err != nil {
  711. sess.Rollback()
  712. return err
  713. }
  714. // Update organization number of teams.
  715. if _, err = sess.Exec("UPDATE `user` SET num_teams = num_teams - 1 WHERE id = ?", t.OrgId); err != nil {
  716. sess.Rollback()
  717. return err
  718. }
  719. return sess.Commit()
  720. }
  721. // ___________ ____ ___
  722. // \__ ___/___ _____ _____ | | \______ ___________
  723. // | |_/ __ \\__ \ / \| | / ___// __ \_ __ \
  724. // | |\ ___/ / __ \| Y Y \ | /\___ \\ ___/| | \/
  725. // |____| \___ >____ /__|_| /______//____ >\___ >__|
  726. // \/ \/ \/ \/ \/
  727. // TeamUser represents an team-user relation.
  728. type TeamUser struct {
  729. Id int64
  730. Uid int64
  731. OrgId int64 `xorm:"INDEX"`
  732. TeamId int64
  733. }
  734. // IsTeamMember returns true if given user is a member of team.
  735. func IsTeamMember(orgId, teamId, uid int64) bool {
  736. has, _ := x.Where("uid=?", uid).And("org_id=?", orgId).And("team_id=?", teamId).Get(new(TeamUser))
  737. return has
  738. }
  739. // GetTeamMembers returns all members in given team of organization.
  740. func GetTeamMembers(orgId, teamId int64) ([]*User, error) {
  741. tus := make([]*TeamUser, 0, 10)
  742. err := x.Where("org_id=?", orgId).And("team_id=?", teamId).Find(&tus)
  743. if err != nil {
  744. return nil, err
  745. }
  746. us := make([]*User, len(tus))
  747. for i, tu := range tus {
  748. us[i], err = GetUserById(tu.Uid)
  749. if err != nil {
  750. return nil, err
  751. }
  752. }
  753. return us, nil
  754. }
  755. // GetUserTeams returns all teams that user belongs to in given origanization.
  756. func GetUserTeams(orgId, uid int64) ([]*Team, error) {
  757. tus := make([]*TeamUser, 0, 5)
  758. if err := x.Where("uid=?", uid).And("org_id=?", orgId).Find(&tus); err != nil {
  759. return nil, err
  760. }
  761. ts := make([]*Team, len(tus))
  762. for i, tu := range tus {
  763. t := new(Team)
  764. has, err := x.Id(tu.TeamId).Get(t)
  765. if err != nil {
  766. return nil, err
  767. } else if !has {
  768. return nil, ErrTeamNotExist
  769. }
  770. ts[i] = t
  771. }
  772. return ts, nil
  773. }
  774. // AddTeamMember adds new member to given team of given organization.
  775. func AddTeamMember(orgId, teamId, uid int64) error {
  776. if IsTeamMember(orgId, teamId, uid) {
  777. return nil
  778. }
  779. if err := AddOrgUser(orgId, uid); err != nil {
  780. return err
  781. }
  782. // Get team and its repositories.
  783. t, err := GetTeamById(teamId)
  784. if err != nil {
  785. return err
  786. }
  787. t.NumMembers++
  788. if err = t.GetRepositories(); err != nil {
  789. return err
  790. }
  791. // Get organization.
  792. org, err := GetUserById(orgId)
  793. if err != nil {
  794. return err
  795. }
  796. // Get user.
  797. u, err := GetUserById(uid)
  798. if err != nil {
  799. return err
  800. }
  801. sess := x.NewSession()
  802. defer sess.Close()
  803. if err = sess.Begin(); err != nil {
  804. return err
  805. }
  806. tu := &TeamUser{
  807. Uid: uid,
  808. OrgId: orgId,
  809. TeamId: teamId,
  810. }
  811. if _, err = sess.Insert(tu); err != nil {
  812. sess.Rollback()
  813. return err
  814. } else if _, err = sess.Id(t.Id).Update(t); err != nil {
  815. sess.Rollback()
  816. return err
  817. }
  818. // Give access to team repositories.
  819. mode := AuthorizeToAccessType(t.Authorize)
  820. for _, repo := range t.Repos {
  821. auth, err := GetHighestAuthorize(orgId, uid, teamId, repo.Id)
  822. if err != nil {
  823. sess.Rollback()
  824. return err
  825. }
  826. access := &Access{
  827. UserName: u.LowerName,
  828. RepoName: path.Join(org.LowerName, repo.LowerName),
  829. }
  830. // Equal 0 means given access doesn't exist.
  831. if auth == 0 {
  832. access.Mode = mode
  833. if _, err = sess.Insert(access); err != nil {
  834. sess.Rollback()
  835. return fmt.Errorf("fail to insert access: %v", err)
  836. }
  837. } else if auth < t.Authorize {
  838. if err = addAccessWithAuthorize(sess, access, mode); err != nil {
  839. sess.Rollback()
  840. return err
  841. }
  842. }
  843. }
  844. // We make sure it exists before.
  845. ou := new(OrgUser)
  846. _, err = sess.Where("uid=?", uid).And("org_id=?", orgId).Get(ou)
  847. if err != nil {
  848. sess.Rollback()
  849. return err
  850. }
  851. ou.NumTeams++
  852. if t.IsOwnerTeam() {
  853. ou.IsOwner = true
  854. }
  855. if _, err = sess.Id(ou.Id).AllCols().Update(ou); err != nil {
  856. sess.Rollback()
  857. return err
  858. }
  859. return sess.Commit()
  860. }
  861. func removeTeamMemberWithSess(orgId, teamId, uid int64, sess *xorm.Session) error {
  862. if !IsTeamMember(orgId, teamId, uid) {
  863. return nil
  864. }
  865. // Get team and its repositories.
  866. t, err := GetTeamById(teamId)
  867. if err != nil {
  868. return err
  869. }
  870. // Check if the user to delete is the last member in owner team.
  871. if t.IsOwnerTeam() && t.NumMembers == 1 {
  872. return ErrLastOrgOwner
  873. }
  874. t.NumMembers--
  875. if err = t.GetRepositories(); err != nil {
  876. return err
  877. }
  878. // Get organization.
  879. org, err := GetUserById(orgId)
  880. if err != nil {
  881. return err
  882. }
  883. // Get user.
  884. u, err := GetUserById(uid)
  885. if err != nil {
  886. return err
  887. }
  888. tu := &TeamUser{
  889. Uid: uid,
  890. OrgId: orgId,
  891. TeamId: teamId,
  892. }
  893. if _, err := sess.Delete(tu); err != nil {
  894. sess.Rollback()
  895. return err
  896. } else if _, err = sess.Id(t.Id).AllCols().Update(t); err != nil {
  897. sess.Rollback()
  898. return err
  899. }
  900. // Delete access to team repositories.
  901. for _, repo := range t.Repos {
  902. auth, err := GetHighestAuthorize(orgId, uid, teamId, repo.Id)
  903. if err != nil {
  904. sess.Rollback()
  905. return err
  906. }
  907. access := &Access{
  908. UserName: u.LowerName,
  909. RepoName: path.Join(org.LowerName, repo.LowerName),
  910. }
  911. // Delete access if this is the last team user belongs to.
  912. if auth == 0 {
  913. if _, err = sess.Delete(access); err != nil {
  914. sess.Rollback()
  915. return fmt.Errorf("fail to delete access: %v", err)
  916. } else if err = WatchRepo(u.Id, repo.Id, false); err != nil {
  917. sess.Rollback()
  918. return err
  919. }
  920. } else if auth < t.Authorize {
  921. // Downgrade authorize level.
  922. if err = addAccessWithAuthorize(sess, access, AuthorizeToAccessType(auth)); err != nil {
  923. sess.Rollback()
  924. return err
  925. }
  926. }
  927. }
  928. // This must exist.
  929. ou := new(OrgUser)
  930. _, err = sess.Where("uid=?", uid).And("org_id=?", org.Id).Get(ou)
  931. if err != nil {
  932. sess.Rollback()
  933. return err
  934. }
  935. ou.NumTeams--
  936. if t.IsOwnerTeam() {
  937. ou.IsOwner = false
  938. }
  939. if _, err = sess.Id(ou.Id).AllCols().Update(ou); err != nil {
  940. sess.Rollback()
  941. return err
  942. }
  943. return nil
  944. }
  945. // RemoveTeamMember removes member from given team of given organization.
  946. func RemoveTeamMember(orgId, teamId, uid int64) error {
  947. sess := x.NewSession()
  948. defer sess.Close()
  949. if err := sess.Begin(); err != nil {
  950. return err
  951. }
  952. if err := removeTeamMemberWithSess(orgId, teamId, uid, sess); err != nil {
  953. return err
  954. }
  955. return sess.Commit()
  956. }