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 25KB

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