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

10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
9 vuotta sitten
9 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
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. }