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

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021
  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 HasTeamRepo(t.OrgID, t.ID, 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. }