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