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.

org.go 21KB

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