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

org.go 26 kB

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