org.go 24 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022
  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. // TODO: need some kind of mechanism to record failure.
  182. // DeleteOrganization completely and permanently deletes everything of organization.
  183. func DeleteOrganization(org *User) (err error) {
  184. if err := DeleteUser(org); err != nil {
  185. return err
  186. }
  187. sess := x.NewSession()
  188. defer sess.Close()
  189. if err = sess.Begin(); err != nil {
  190. return err
  191. }
  192. if _, err = sess.Delete(&Team{OrgID: org.Id}); err != nil {
  193. sess.Rollback()
  194. return err
  195. }
  196. if _, err = sess.Delete(&OrgUser{OrgID: org.Id}); err != nil {
  197. sess.Rollback()
  198. return err
  199. }
  200. if _, err = sess.Delete(&TeamUser{OrgID: org.Id}); err != nil {
  201. sess.Rollback()
  202. return err
  203. }
  204. return sess.Commit()
  205. }
  206. // ________ ____ ___
  207. // \_____ \_______ ____ | | \______ ___________
  208. // / | \_ __ \/ ___\| | / ___// __ \_ __ \
  209. // / | \ | \/ /_/ > | /\___ \\ ___/| | \/
  210. // \_______ /__| \___ /|______//____ >\___ >__|
  211. // \/ /_____/ \/ \/
  212. // OrgUser represents an organization-user relation.
  213. type OrgUser struct {
  214. ID int64 `xorm:"pk autoincr"`
  215. Uid int64 `xorm:"INDEX UNIQUE(s)"`
  216. OrgID int64 `xorm:"INDEX UNIQUE(s)"`
  217. IsPublic bool
  218. IsOwner bool
  219. NumTeams int
  220. }
  221. // IsOrganizationOwner returns true if given user is in the owner team.
  222. func IsOrganizationOwner(orgId, uid int64) bool {
  223. has, _ := x.Where("is_owner=?", true).And("uid=?", uid).And("org_id=?", orgId).Get(new(OrgUser))
  224. return has
  225. }
  226. // IsOrganizationMember returns true if given user is member of organization.
  227. func IsOrganizationMember(orgId, uid int64) bool {
  228. has, _ := x.Where("uid=?", uid).And("org_id=?", orgId).Get(new(OrgUser))
  229. return has
  230. }
  231. // IsPublicMembership returns true if given user public his/her membership.
  232. func IsPublicMembership(orgId, uid int64) bool {
  233. has, _ := x.Where("uid=?", uid).And("org_id=?", orgId).And("is_public=?", true).Get(new(OrgUser))
  234. return has
  235. }
  236. // GetOrgUsersByUserId returns all organization-user relations by user ID.
  237. func GetOrgUsersByUserId(uid int64) ([]*OrgUser, error) {
  238. ous := make([]*OrgUser, 0, 10)
  239. err := x.Where("uid=?", uid).Find(&ous)
  240. return ous, err
  241. }
  242. // GetOrgUsersByOrgId returns all organization-user relations by organization ID.
  243. func GetOrgUsersByOrgId(orgId int64) ([]*OrgUser, error) {
  244. ous := make([]*OrgUser, 0, 10)
  245. err := x.Where("org_id=?", orgId).Find(&ous)
  246. return ous, err
  247. }
  248. // ChangeOrgUserStatus changes public or private membership status.
  249. func ChangeOrgUserStatus(orgId, uid int64, public bool) error {
  250. ou := new(OrgUser)
  251. has, err := x.Where("uid=?", uid).And("org_id=?", orgId).Get(ou)
  252. if err != nil {
  253. return err
  254. } else if !has {
  255. return nil
  256. }
  257. ou.IsPublic = public
  258. _, err = x.Id(ou.ID).AllCols().Update(ou)
  259. return err
  260. }
  261. // AddOrgUser adds new user to given organization.
  262. func AddOrgUser(orgId, uid int64) error {
  263. if IsOrganizationMember(orgId, uid) {
  264. return nil
  265. }
  266. sess := x.NewSession()
  267. defer sess.Close()
  268. if err := sess.Begin(); err != nil {
  269. return err
  270. }
  271. ou := &OrgUser{
  272. Uid: uid,
  273. OrgID: orgId,
  274. }
  275. if _, err := sess.Insert(ou); err != nil {
  276. sess.Rollback()
  277. return err
  278. } else if _, err = sess.Exec("UPDATE `user` SET num_members = num_members + 1 WHERE id = ?", orgId); err != nil {
  279. sess.Rollback()
  280. return err
  281. }
  282. return sess.Commit()
  283. }
  284. // RemoveOrgUser removes user from given organization.
  285. func RemoveOrgUser(orgId, uid int64) error {
  286. ou := new(OrgUser)
  287. has, err := x.Where("uid=?", uid).And("org_id=?", orgId).Get(ou)
  288. if err != nil {
  289. return fmt.Errorf("get org-user: %v", err)
  290. } else if !has {
  291. return nil
  292. }
  293. u, err := GetUserByID(uid)
  294. if err != nil {
  295. return fmt.Errorf("GetUserById: %v", err)
  296. }
  297. org, err := GetUserByID(orgId)
  298. if err != nil {
  299. return fmt.Errorf("get organization: %v", err)
  300. } else if err = org.GetRepositories(); err != nil {
  301. return fmt.Errorf("GetRepositories: %v", err)
  302. }
  303. // Check if the user to delete is the last member in owner team.
  304. if IsOrganizationOwner(orgId, uid) {
  305. t, err := org.GetOwnerTeam()
  306. if err != nil {
  307. return err
  308. }
  309. if t.NumMembers == 1 {
  310. return ErrLastOrgOwner{UID: uid}
  311. }
  312. }
  313. sess := x.NewSession()
  314. defer sessionRelease(sess)
  315. if err := sess.Begin(); err != nil {
  316. return err
  317. }
  318. if _, err := sess.Id(ou.ID).Delete(ou); err != nil {
  319. return err
  320. } else if _, err = sess.Exec("UPDATE `user` SET num_members=num_members-1 WHERE id=?", orgId); err != nil {
  321. return err
  322. }
  323. // Delete all repository accesses.
  324. access := &Access{UserID: u.Id}
  325. for _, repo := range org.Repos {
  326. access.RepoID = repo.ID
  327. if _, err = sess.Delete(access); err != nil {
  328. return err
  329. } else if err = watchRepo(sess, u.Id, repo.ID, false); err != nil {
  330. return err
  331. }
  332. }
  333. // Delete member in his/her teams.
  334. teams, err := getUserTeams(sess, org.Id, u.Id)
  335. if err != nil {
  336. return err
  337. }
  338. for _, t := range teams {
  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. const OWNER_TEAM = "Owners"
  352. // Team represents a organization team.
  353. type Team struct {
  354. ID int64 `xorm:"pk autoincr"`
  355. OrgID int64 `xorm:"INDEX"`
  356. LowerName string
  357. Name string
  358. Description string
  359. Authorize AccessMode
  360. Repos []*Repository `xorm:"-"`
  361. Members []*User `xorm:"-"`
  362. NumRepos int
  363. NumMembers int
  364. }
  365. // IsOwnerTeam returns true if team is owner team.
  366. func (t *Team) IsOwnerTeam() bool {
  367. return t.Name == OWNER_TEAM
  368. }
  369. // IsTeamMember returns true if given user is a member of team.
  370. func (t *Team) IsMember(uid int64) bool {
  371. return IsTeamMember(t.OrgID, t.ID, uid)
  372. }
  373. func (t *Team) getRepositories(e Engine) (err error) {
  374. teamRepos := make([]*TeamRepo, 0, t.NumRepos)
  375. if err = x.Where("team_id=?", t.ID).Find(&teamRepos); err != nil {
  376. return fmt.Errorf("get team-repos: %v", err)
  377. }
  378. t.Repos = make([]*Repository, 0, len(teamRepos))
  379. for i := range teamRepos {
  380. repo, err := getRepositoryByID(e, teamRepos[i].RepoID)
  381. if err != nil {
  382. return fmt.Errorf("getRepositoryById(%d): %v", teamRepos[i].RepoID, err)
  383. }
  384. t.Repos = append(t.Repos, repo)
  385. }
  386. return nil
  387. }
  388. // GetRepositories returns all repositories in team of organization.
  389. func (t *Team) GetRepositories() error {
  390. return t.getRepositories(x)
  391. }
  392. func (t *Team) getMembers(e Engine) (err error) {
  393. t.Members, err = getTeamMembers(e, t.ID)
  394. return err
  395. }
  396. // GetMembers returns all members in team of organization.
  397. func (t *Team) GetMembers() (err error) {
  398. return t.getMembers(x)
  399. }
  400. // AddMember adds new member to team of organization.
  401. func (t *Team) AddMember(uid int64) error {
  402. return AddTeamMember(t.OrgID, t.ID, uid)
  403. }
  404. // RemoveMember removes member from team of organization.
  405. func (t *Team) RemoveMember(uid int64) error {
  406. return RemoveTeamMember(t.OrgID, t.ID, uid)
  407. }
  408. func (t *Team) hasRepository(e Engine, repoID int64) bool {
  409. return hasTeamRepo(e, t.OrgID, t.ID, repoID)
  410. }
  411. // HasRepository returns true if given repository belong to team.
  412. func (t *Team) HasRepository(repoID int64) bool {
  413. return t.hasRepository(x, repoID)
  414. }
  415. func (t *Team) addRepository(e Engine, repo *Repository) (err error) {
  416. if err = addTeamRepo(e, t.OrgID, t.ID, repo.ID); err != nil {
  417. return err
  418. }
  419. t.NumRepos++
  420. if _, err = e.Id(t.ID).AllCols().Update(t); err != nil {
  421. return fmt.Errorf("update team: %v", err)
  422. }
  423. if err = repo.recalculateTeamAccesses(e, 0); err != nil {
  424. return fmt.Errorf("recalculateAccesses: %v", err)
  425. }
  426. if err = t.getMembers(e); err != nil {
  427. return fmt.Errorf("getMembers: %v", err)
  428. }
  429. for _, u := range t.Members {
  430. if err = watchRepo(e, u.Id, repo.ID, true); err != nil {
  431. return fmt.Errorf("watchRepo: %v", err)
  432. }
  433. }
  434. return nil
  435. }
  436. // AddRepository adds new repository to team of organization.
  437. func (t *Team) AddRepository(repo *Repository) (err error) {
  438. if repo.OwnerID != t.OrgID {
  439. return errors.New("Repository does not belong to organization")
  440. } else if t.HasRepository(repo.ID) {
  441. return nil
  442. }
  443. sess := x.NewSession()
  444. defer sessionRelease(sess)
  445. if err = sess.Begin(); err != nil {
  446. return err
  447. }
  448. if err = t.addRepository(sess, repo); err != nil {
  449. return err
  450. }
  451. return sess.Commit()
  452. }
  453. func (t *Team) removeRepository(e Engine, repo *Repository, recalculate bool) (err error) {
  454. if err = removeTeamRepo(e, t.ID, repo.ID); err != nil {
  455. return err
  456. }
  457. t.NumRepos--
  458. if _, err = e.Id(t.ID).AllCols().Update(t); err != nil {
  459. return err
  460. }
  461. // Don't need to recalculate when delete a repository from organization.
  462. if recalculate {
  463. if err = repo.recalculateTeamAccesses(e, t.ID); err != nil {
  464. return err
  465. }
  466. }
  467. if err = t.getMembers(e); err != nil {
  468. return fmt.Errorf("get team members: %v", err)
  469. }
  470. for _, u := range t.Members {
  471. has, err := hasAccess(e, u, repo, ACCESS_MODE_READ)
  472. if err != nil {
  473. return err
  474. } else if has {
  475. continue
  476. }
  477. if err = watchRepo(e, u.Id, repo.ID, false); err != nil {
  478. return err
  479. }
  480. }
  481. return nil
  482. }
  483. // RemoveRepository removes repository from team of organization.
  484. func (t *Team) RemoveRepository(repoID int64) error {
  485. if !t.HasRepository(repoID) {
  486. return nil
  487. }
  488. repo, err := GetRepositoryByID(repoID)
  489. if err != nil {
  490. return err
  491. }
  492. sess := x.NewSession()
  493. defer sessionRelease(sess)
  494. if err = sess.Begin(); err != nil {
  495. return err
  496. }
  497. if err = t.removeRepository(sess, repo, true); err != nil {
  498. return err
  499. }
  500. return sess.Commit()
  501. }
  502. // NewTeam creates a record of new team.
  503. // It's caller's responsibility to assign organization ID.
  504. func NewTeam(t *Team) (err error) {
  505. if err = IsUsableName(t.Name); err != nil {
  506. return err
  507. }
  508. has, err := x.Id(t.OrgID).Get(new(User))
  509. if err != nil {
  510. return err
  511. } else if !has {
  512. return ErrOrgNotExist
  513. }
  514. t.LowerName = strings.ToLower(t.Name)
  515. has, err = x.Where("org_id=?", t.OrgID).And("lower_name=?", t.LowerName).Get(new(Team))
  516. if err != nil {
  517. return err
  518. } else if has {
  519. return ErrTeamAlreadyExist
  520. }
  521. sess := x.NewSession()
  522. defer sess.Close()
  523. if err = sess.Begin(); err != nil {
  524. return err
  525. }
  526. if _, err = sess.Insert(t); err != nil {
  527. sess.Rollback()
  528. return err
  529. }
  530. // Update organization number of teams.
  531. if _, err = sess.Exec("UPDATE `user` SET num_teams=num_teams+1 WHERE id = ?", t.OrgID); err != nil {
  532. sess.Rollback()
  533. return err
  534. }
  535. return sess.Commit()
  536. }
  537. func getTeam(e Engine, orgId int64, name string) (*Team, error) {
  538. t := &Team{
  539. OrgID: orgId,
  540. LowerName: strings.ToLower(name),
  541. }
  542. has, err := e.Get(t)
  543. if err != nil {
  544. return nil, err
  545. } else if !has {
  546. return nil, ErrTeamNotExist
  547. }
  548. return t, nil
  549. }
  550. // GetTeam returns team by given team name and organization.
  551. func GetTeam(orgId int64, name string) (*Team, error) {
  552. return getTeam(x, orgId, name)
  553. }
  554. func getTeamById(e Engine, teamId int64) (*Team, error) {
  555. t := new(Team)
  556. has, err := e.Id(teamId).Get(t)
  557. if err != nil {
  558. return nil, err
  559. } else if !has {
  560. return nil, ErrTeamNotExist
  561. }
  562. return t, nil
  563. }
  564. // GetTeamById returns team by given ID.
  565. func GetTeamById(teamId int64) (*Team, error) {
  566. return getTeamById(x, teamId)
  567. }
  568. // UpdateTeam updates information of team.
  569. func UpdateTeam(t *Team, authChanged bool) (err error) {
  570. if err = IsUsableName(t.Name); err != nil {
  571. return err
  572. }
  573. if len(t.Description) > 255 {
  574. t.Description = t.Description[:255]
  575. }
  576. sess := x.NewSession()
  577. defer sessionRelease(sess)
  578. if err = sess.Begin(); err != nil {
  579. return err
  580. }
  581. t.LowerName = strings.ToLower(t.Name)
  582. if _, err = sess.Id(t.ID).AllCols().Update(t); err != nil {
  583. return fmt.Errorf("update: %v", err)
  584. }
  585. // Update access for team members if needed.
  586. if authChanged {
  587. if err = t.getRepositories(sess); err != nil {
  588. return fmt.Errorf("getRepositories:%v", err)
  589. }
  590. for _, repo := range t.Repos {
  591. if err = repo.recalculateTeamAccesses(sess, 0); err != nil {
  592. return fmt.Errorf("recalculateTeamAccesses: %v", err)
  593. }
  594. }
  595. }
  596. return sess.Commit()
  597. }
  598. // DeleteTeam deletes given team.
  599. // It's caller's responsibility to assign organization ID.
  600. func DeleteTeam(t *Team) error {
  601. if err := t.GetRepositories(); err != nil {
  602. return err
  603. }
  604. // Get organization.
  605. org, err := GetUserByID(t.OrgID)
  606. if err != nil {
  607. return err
  608. }
  609. sess := x.NewSession()
  610. defer sessionRelease(sess)
  611. if err = sess.Begin(); err != nil {
  612. return err
  613. }
  614. // Delete all accesses.
  615. for _, repo := range t.Repos {
  616. if err = repo.recalculateTeamAccesses(sess, t.ID); err != nil {
  617. return err
  618. }
  619. }
  620. // Delete team-user.
  621. if _, err = sess.Where("org_id=?", org.Id).Where("team_id=?", t.ID).Delete(new(TeamUser)); err != nil {
  622. return err
  623. }
  624. // Delete team.
  625. if _, err = sess.Id(t.ID).Delete(new(Team)); err != nil {
  626. return err
  627. }
  628. // Update organization number of teams.
  629. if _, err = sess.Exec("UPDATE `user` SET num_teams=num_teams-1 WHERE id=?", t.OrgID); err != nil {
  630. return err
  631. }
  632. return sess.Commit()
  633. }
  634. // ___________ ____ ___
  635. // \__ ___/___ _____ _____ | | \______ ___________
  636. // | |_/ __ \\__ \ / \| | / ___// __ \_ __ \
  637. // | |\ ___/ / __ \| Y Y \ | /\___ \\ ___/| | \/
  638. // |____| \___ >____ /__|_| /______//____ >\___ >__|
  639. // \/ \/ \/ \/ \/
  640. // TeamUser represents an team-user relation.
  641. type TeamUser struct {
  642. ID int64 `xorm:"pk autoincr"`
  643. OrgID int64 `xorm:"INDEX"`
  644. TeamID int64 `xorm:"UNIQUE(s)"`
  645. Uid int64 `xorm:"UNIQUE(s)"`
  646. }
  647. func isTeamMember(e Engine, orgID, teamID, uid int64) bool {
  648. has, _ := e.Where("org_id=?", orgID).And("team_id=?", teamID).And("uid=?", uid).Get(new(TeamUser))
  649. return has
  650. }
  651. // IsTeamMember returns true if given user is a member of team.
  652. func IsTeamMember(orgID, teamID, uid int64) bool {
  653. return isTeamMember(x, orgID, teamID, uid)
  654. }
  655. func getTeamMembers(e Engine, teamID int64) (_ []*User, err error) {
  656. teamUsers := make([]*TeamUser, 0, 10)
  657. if err = e.Where("team_id=?", teamID).Find(&teamUsers); err != nil {
  658. return nil, fmt.Errorf("get team-users: %v", err)
  659. }
  660. members := make([]*User, 0, len(teamUsers))
  661. for i := range teamUsers {
  662. member := new(User)
  663. if _, err = e.Id(teamUsers[i].Uid).Get(member); err != nil {
  664. return nil, fmt.Errorf("get user '%d': %v", teamUsers[i].Uid, err)
  665. }
  666. members = append(members, member)
  667. }
  668. return members, nil
  669. }
  670. // GetTeamMembers returns all members in given team of organization.
  671. func GetTeamMembers(teamID int64) ([]*User, error) {
  672. return getTeamMembers(x, teamID)
  673. }
  674. func getUserTeams(e Engine, orgId, uid int64) ([]*Team, error) {
  675. tus := make([]*TeamUser, 0, 5)
  676. if err := e.Where("uid=?", uid).And("org_id=?", orgId).Find(&tus); err != nil {
  677. return nil, err
  678. }
  679. ts := make([]*Team, len(tus))
  680. for i, tu := range tus {
  681. t := new(Team)
  682. has, err := e.Id(tu.TeamID).Get(t)
  683. if err != nil {
  684. return nil, err
  685. } else if !has {
  686. return nil, ErrTeamNotExist
  687. }
  688. ts[i] = t
  689. }
  690. return ts, nil
  691. }
  692. // GetUserTeams returns all teams that user belongs to in given organization.
  693. func GetUserTeams(orgId, uid int64) ([]*Team, error) {
  694. return getUserTeams(x, orgId, uid)
  695. }
  696. // AddTeamMember adds new member to given team of given organization.
  697. func AddTeamMember(orgId, teamId, uid int64) error {
  698. if IsTeamMember(orgId, teamId, uid) {
  699. return nil
  700. }
  701. if err := AddOrgUser(orgId, uid); err != nil {
  702. return err
  703. }
  704. // Get team and its repositories.
  705. t, err := GetTeamById(teamId)
  706. if err != nil {
  707. return err
  708. }
  709. t.NumMembers++
  710. if err = t.GetRepositories(); err != nil {
  711. return err
  712. }
  713. sess := x.NewSession()
  714. defer sessionRelease(sess)
  715. if err = sess.Begin(); err != nil {
  716. return err
  717. }
  718. tu := &TeamUser{
  719. Uid: uid,
  720. OrgID: orgId,
  721. TeamID: teamId,
  722. }
  723. if _, err = sess.Insert(tu); err != nil {
  724. return err
  725. } else if _, err = sess.Id(t.ID).Update(t); err != nil {
  726. return err
  727. }
  728. // Give access to team repositories.
  729. for _, repo := range t.Repos {
  730. if err = repo.recalculateTeamAccesses(sess, 0); err != nil {
  731. return err
  732. }
  733. }
  734. // We make sure it exists before.
  735. ou := new(OrgUser)
  736. if _, err = sess.Where("uid=?", uid).And("org_id=?", orgId).Get(ou); err != nil {
  737. return err
  738. }
  739. ou.NumTeams++
  740. if t.IsOwnerTeam() {
  741. ou.IsOwner = true
  742. }
  743. if _, err = sess.Id(ou.ID).AllCols().Update(ou); err != nil {
  744. return err
  745. }
  746. return sess.Commit()
  747. }
  748. func removeTeamMember(e Engine, orgId, teamId, uid int64) error {
  749. if !isTeamMember(e, orgId, teamId, uid) {
  750. return nil
  751. }
  752. // Get team and its repositories.
  753. t, err := getTeamById(e, teamId)
  754. if err != nil {
  755. return err
  756. }
  757. // Check if the user to delete is the last member in owner team.
  758. if t.IsOwnerTeam() && t.NumMembers == 1 {
  759. return ErrLastOrgOwner{UID: uid}
  760. }
  761. t.NumMembers--
  762. if err = t.getRepositories(e); err != nil {
  763. return err
  764. }
  765. // Get organization.
  766. org, err := getUserByID(e, orgId)
  767. if err != nil {
  768. return err
  769. }
  770. tu := &TeamUser{
  771. Uid: uid,
  772. OrgID: orgId,
  773. TeamID: teamId,
  774. }
  775. if _, err := e.Delete(tu); err != nil {
  776. return err
  777. } else if _, err = e.Id(t.ID).AllCols().Update(t); err != nil {
  778. return err
  779. }
  780. // Delete access to team repositories.
  781. for _, repo := range t.Repos {
  782. if err = repo.recalculateTeamAccesses(e, 0); err != nil {
  783. return err
  784. }
  785. }
  786. // This must exist.
  787. ou := new(OrgUser)
  788. _, err = e.Where("uid=?", uid).And("org_id=?", org.Id).Get(ou)
  789. if err != nil {
  790. return err
  791. }
  792. ou.NumTeams--
  793. if t.IsOwnerTeam() {
  794. ou.IsOwner = false
  795. }
  796. if _, err = e.Id(ou.ID).AllCols().Update(ou); err != nil {
  797. return err
  798. }
  799. return nil
  800. }
  801. // RemoveTeamMember removes member from given team of given organization.
  802. func RemoveTeamMember(orgId, teamId, uid int64) error {
  803. sess := x.NewSession()
  804. defer sessionRelease(sess)
  805. if err := sess.Begin(); err != nil {
  806. return err
  807. }
  808. if err := removeTeamMember(sess, orgId, teamId, uid); err != nil {
  809. return err
  810. }
  811. return sess.Commit()
  812. }
  813. // ___________ __________
  814. // \__ ___/___ _____ _____\______ \ ____ ______ ____
  815. // | |_/ __ \\__ \ / \| _// __ \\____ \ / _ \
  816. // | |\ ___/ / __ \| Y Y \ | \ ___/| |_> > <_> )
  817. // |____| \___ >____ /__|_| /____|_ /\___ > __/ \____/
  818. // \/ \/ \/ \/ \/|__|
  819. // TeamRepo represents an team-repository relation.
  820. type TeamRepo struct {
  821. ID int64 `xorm:"pk autoincr"`
  822. OrgID int64 `xorm:"INDEX"`
  823. TeamID int64 `xorm:"UNIQUE(s)"`
  824. RepoID int64 `xorm:"UNIQUE(s)"`
  825. }
  826. func hasTeamRepo(e Engine, orgID, teamID, repoID int64) bool {
  827. has, _ := e.Where("org_id=?", orgID).And("team_id=?", teamID).And("repo_id=?", repoID).Get(new(TeamRepo))
  828. return has
  829. }
  830. // HasTeamRepo returns true if given repository belongs to team.
  831. func HasTeamRepo(orgID, teamID, repoID int64) bool {
  832. return hasTeamRepo(x, orgID, teamID, repoID)
  833. }
  834. func addTeamRepo(e Engine, orgID, teamID, repoID int64) error {
  835. _, err := e.InsertOne(&TeamRepo{
  836. OrgID: orgID,
  837. TeamID: teamID,
  838. RepoID: repoID,
  839. })
  840. return err
  841. }
  842. // AddTeamRepo adds new repository relation to team.
  843. func AddTeamRepo(orgID, teamID, repoID int64) error {
  844. return addTeamRepo(x, orgID, teamID, repoID)
  845. }
  846. func removeTeamRepo(e Engine, teamID, repoID int64) error {
  847. _, err := e.Delete(&TeamRepo{
  848. TeamID: teamID,
  849. RepoID: repoID,
  850. })
  851. return err
  852. }
  853. // RemoveTeamRepo deletes repository relation to team.
  854. func RemoveTeamRepo(teamID, repoID int64) error {
  855. return removeTeamRepo(x, teamID, repoID)
  856. }
  857. func removeOrgRepo(e Engine, orgID, repoID int64) error {
  858. _, err := e.Delete(&TeamRepo{
  859. OrgID: orgID,
  860. RepoID: repoID,
  861. })
  862. return err
  863. }
  864. // RemoveOrgRepo removes all team-repository relations of given organization.
  865. func RemoveOrgRepo(orgID, repoID int64) error {
  866. return removeOrgRepo(x, orgID, repoID)
  867. }