You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

org.go 21 kB

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