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

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