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.

1103 lines
25 KiB

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