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

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