org.go 25 KB

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