org.go 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095
  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. "strconv"
  11. "github.com/go-xorm/xorm"
  12. )
  13. var (
  14. ErrOrgNotExist = errors.New("Organization does not exist")
  15. ErrTeamNotExist = errors.New("Team does not exist")
  16. )
  17. // IsOwnedBy returns true if given user is in the owner team.
  18. func (org *User) IsOwnedBy(uid int64) bool {
  19. return IsOrganizationOwner(org.Id, uid)
  20. }
  21. // IsOrgMember returns true if given user is member of organization.
  22. func (org *User) IsOrgMember(uid int64) bool {
  23. return org.IsOrganization() && IsOrganizationMember(org.Id, uid)
  24. }
  25. func (org *User) getTeam(e Engine, name string) (*Team, error) {
  26. return getTeam(e, org.Id, name)
  27. }
  28. // GetTeam returns named team of organization.
  29. func (org *User) GetTeam(name string) (*Team, error) {
  30. return org.getTeam(x, name)
  31. }
  32. func (org *User) getOwnerTeam(e Engine) (*Team, error) {
  33. return org.getTeam(e, OWNER_TEAM)
  34. }
  35. // GetOwnerTeam returns owner team of organization.
  36. func (org *User) GetOwnerTeam() (*Team, error) {
  37. return org.getOwnerTeam(x)
  38. }
  39. func (org *User) getTeams(e Engine) error {
  40. return e.Where("org_id=?", org.Id).Find(&org.Teams)
  41. }
  42. // GetTeams returns all teams that belong to organization.
  43. func (org *User) GetTeams() error {
  44. return org.getTeams(x)
  45. }
  46. // GetMembers returns all members of organization.
  47. func (org *User) GetMembers() error {
  48. ous, err := GetOrgUsersByOrgId(org.Id)
  49. if err != nil {
  50. return err
  51. }
  52. org.Members = make([]*User, len(ous))
  53. for i, ou := range ous {
  54. org.Members[i], err = GetUserByID(ou.Uid)
  55. if err != nil {
  56. return err
  57. }
  58. }
  59. return nil
  60. }
  61. // AddMember adds new member to organization.
  62. func (org *User) AddMember(uid int64) error {
  63. return AddOrgUser(org.Id, uid)
  64. }
  65. // RemoveMember removes member from organization.
  66. func (org *User) RemoveMember(uid int64) error {
  67. return RemoveOrgUser(org.Id, uid)
  68. }
  69. func (org *User) removeOrgRepo(e Engine, repoID int64) error {
  70. return removeOrgRepo(e, org.Id, repoID)
  71. }
  72. // RemoveOrgRepo removes all team-repository relations of organization.
  73. func (org *User) RemoveOrgRepo(repoID int64) error {
  74. return org.removeOrgRepo(x, repoID)
  75. }
  76. // CreateOrganization creates record of a new organization.
  77. func CreateOrganization(org, owner *User) (err error) {
  78. if err = IsUsableName(org.Name); err != nil {
  79. return err
  80. }
  81. isExist, err := IsUserExist(0, org.Name)
  82. if err != nil {
  83. return err
  84. } else if isExist {
  85. return ErrUserAlreadyExist{org.Name}
  86. }
  87. org.LowerName = strings.ToLower(org.Name)
  88. org.FullName = org.Name
  89. org.Rands = GetUserSalt()
  90. org.Salt = GetUserSalt()
  91. org.UseCustomAvatar = true
  92. org.MaxRepoCreation = -1
  93. org.NumTeams = 1
  94. org.NumMembers = 1
  95. sess := x.NewSession()
  96. defer sessionRelease(sess)
  97. if err = sess.Begin(); err != nil {
  98. return err
  99. }
  100. if _, err = sess.Insert(org); err != nil {
  101. return fmt.Errorf("insert organization: %v", err)
  102. }
  103. org.GenerateRandomAvatar()
  104. // Add initial creator to organization and owner team.
  105. if _, err = sess.Insert(&OrgUser{
  106. Uid: owner.Id,
  107. OrgID: org.Id,
  108. IsOwner: true,
  109. NumTeams: 1,
  110. }); err != nil {
  111. return fmt.Errorf("insert org-user relation: %v", err)
  112. }
  113. // Create default owner team.
  114. t := &Team{
  115. OrgID: org.Id,
  116. LowerName: strings.ToLower(OWNER_TEAM),
  117. Name: OWNER_TEAM,
  118. Authorize: ACCESS_MODE_OWNER,
  119. NumMembers: 1,
  120. }
  121. if _, err = sess.Insert(t); err != nil {
  122. return fmt.Errorf("insert owner team: %v", err)
  123. }
  124. if _, err = sess.Insert(&TeamUser{
  125. Uid: owner.Id,
  126. OrgID: org.Id,
  127. TeamID: t.ID,
  128. }); err != nil {
  129. return fmt.Errorf("insert team-user relation: %v", err)
  130. }
  131. if err = os.MkdirAll(UserPath(org.Name), os.ModePerm); err != nil {
  132. return fmt.Errorf("create directory: %v", err)
  133. }
  134. return sess.Commit()
  135. }
  136. // GetOrgByName returns organization by given name.
  137. func GetOrgByName(name string) (*User, error) {
  138. if len(name) == 0 {
  139. return nil, ErrOrgNotExist
  140. }
  141. u := &User{
  142. LowerName: strings.ToLower(name),
  143. Type: ORGANIZATION,
  144. }
  145. has, err := x.Get(u)
  146. if err != nil {
  147. return nil, err
  148. } else if !has {
  149. return nil, ErrOrgNotExist
  150. }
  151. return u, nil
  152. }
  153. // CountOrganizations returns number of organizations.
  154. func CountOrganizations() int64 {
  155. count, _ := x.Where("type=1").Count(new(User))
  156. return count
  157. }
  158. // Organizations returns number of organizations in given page.
  159. func Organizations(page, pageSize int) ([]*User, error) {
  160. orgs := make([]*User, 0, pageSize)
  161. return orgs, x.Limit(pageSize, (page-1)*pageSize).Where("type=1").Asc("id").Find(&orgs)
  162. }
  163. // DeleteOrganization completely and permanently deletes everything of organization.
  164. func DeleteOrganization(org *User) (err error) {
  165. if err := DeleteUser(org); err != nil {
  166. return err
  167. }
  168. sess := x.NewSession()
  169. defer sessionRelease(sess)
  170. if err = sess.Begin(); err != nil {
  171. return err
  172. }
  173. if err = deleteBeans(sess,
  174. &Team{OrgID: org.Id},
  175. &OrgUser{OrgID: org.Id},
  176. &TeamUser{OrgID: org.Id},
  177. ); err != nil {
  178. return fmt.Errorf("deleteBeans: %v", err)
  179. }
  180. if err = deleteUser(sess, org); err != nil {
  181. return fmt.Errorf("deleteUser: %v", err)
  182. }
  183. return sess.Commit()
  184. }
  185. // ________ ____ ___
  186. // \_____ \_______ ____ | | \______ ___________
  187. // / | \_ __ \/ ___\| | / ___// __ \_ __ \
  188. // / | \ | \/ /_/ > | /\___ \\ ___/| | \/
  189. // \_______ /__| \___ /|______//____ >\___ >__|
  190. // \/ /_____/ \/ \/
  191. // OrgUser represents an organization-user relation.
  192. type OrgUser struct {
  193. ID int64 `xorm:"pk autoincr"`
  194. Uid int64 `xorm:"INDEX UNIQUE(s)"`
  195. OrgID int64 `xorm:"INDEX UNIQUE(s)"`
  196. IsPublic bool
  197. IsOwner bool
  198. NumTeams int
  199. }
  200. // IsOrganizationOwner returns true if given user is in the owner team.
  201. func IsOrganizationOwner(orgId, uid int64) bool {
  202. has, _ := x.Where("is_owner=?", true).And("uid=?", uid).And("org_id=?", orgId).Get(new(OrgUser))
  203. return has
  204. }
  205. // IsOrganizationMember returns true if given user is member of organization.
  206. func IsOrganizationMember(orgId, uid int64) bool {
  207. has, _ := x.Where("uid=?", uid).And("org_id=?", orgId).Get(new(OrgUser))
  208. return has
  209. }
  210. // IsPublicMembership returns true if given user public his/her membership.
  211. func IsPublicMembership(orgId, uid int64) bool {
  212. has, _ := x.Where("uid=?", uid).And("org_id=?", orgId).And("is_public=?", true).Get(new(OrgUser))
  213. return has
  214. }
  215. func getOwnedOrgsByUserID(sess *xorm.Session, userID int64) ([]*User, error) {
  216. orgs := make([]*User, 0, 10)
  217. return orgs, sess.Where("`org_user`.uid=?", userID).And("`org_user`.is_owner=?", true).
  218. Join("INNER", "`org_user`", "`org_user`.org_id=`user`.id").Find(&orgs)
  219. }
  220. // GetOwnedOrgsByUserID returns a list of organizations are owned by given user ID.
  221. func GetOwnedOrgsByUserID(userID int64) ([]*User, error) {
  222. sess := x.NewSession()
  223. return getOwnedOrgsByUserID(sess, userID)
  224. }
  225. // GetOwnedOrganizationsByUserIDDesc returns a list of organizations are owned by
  226. // given user ID and descring order by given condition.
  227. func GetOwnedOrgsByUserIDDesc(userID int64, desc string) ([]*User, error) {
  228. sess := x.NewSession()
  229. return getOwnedOrgsByUserID(sess.Desc(desc), userID)
  230. }
  231. // GetOrgUsersByUserID returns all organization-user relations by user ID.
  232. func GetOrgUsersByUserID(uid int64, all bool) ([]*OrgUser, error) {
  233. ous := make([]*OrgUser, 0, 10)
  234. sess := x.Where("uid=?", uid)
  235. if !all {
  236. // Only show public organizations
  237. sess.And("is_public=?", true)
  238. }
  239. err := sess.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) error {
  505. if len(t.Name) == 0 {
  506. return errors.New("empty team name")
  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{t.OrgID, t.LowerName}
  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 len(t.Name) == 0 {
  571. return errors.New("empty team name")
  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. has, err := x.Where("org_id=?", t.OrgID).And("lower_name=?", t.LowerName).And("id!=?", t.ID).Get(new(Team))
  583. if err != nil {
  584. return err
  585. } else if has {
  586. return ErrTeamAlreadyExist{t.OrgID, t.LowerName}
  587. }
  588. if _, err = sess.Id(t.ID).AllCols().Update(t); err != nil {
  589. return fmt.Errorf("update: %v", err)
  590. }
  591. // Update access for team members if needed.
  592. if authChanged {
  593. if err = t.getRepositories(sess); err != nil {
  594. return fmt.Errorf("getRepositories:%v", err)
  595. }
  596. for _, repo := range t.Repos {
  597. if err = repo.recalculateTeamAccesses(sess, 0); err != nil {
  598. return fmt.Errorf("recalculateTeamAccesses: %v", err)
  599. }
  600. }
  601. }
  602. return sess.Commit()
  603. }
  604. // DeleteTeam deletes given team.
  605. // It's caller's responsibility to assign organization ID.
  606. func DeleteTeam(t *Team) error {
  607. if err := t.GetRepositories(); err != nil {
  608. return err
  609. }
  610. // Get organization.
  611. org, err := GetUserByID(t.OrgID)
  612. if err != nil {
  613. return err
  614. }
  615. sess := x.NewSession()
  616. defer sessionRelease(sess)
  617. if err = sess.Begin(); err != nil {
  618. return err
  619. }
  620. // Delete all accesses.
  621. for _, repo := range t.Repos {
  622. if err = repo.recalculateTeamAccesses(sess, t.ID); err != nil {
  623. return err
  624. }
  625. }
  626. // Delete team-user.
  627. if _, err = sess.Where("org_id=?", org.Id).Where("team_id=?", t.ID).Delete(new(TeamUser)); err != nil {
  628. return err
  629. }
  630. // Delete team.
  631. if _, err = sess.Id(t.ID).Delete(new(Team)); err != nil {
  632. return err
  633. }
  634. // Update organization number of teams.
  635. if _, err = sess.Exec("UPDATE `user` SET num_teams=num_teams-1 WHERE id=?", t.OrgID); err != nil {
  636. return err
  637. }
  638. return sess.Commit()
  639. }
  640. // ___________ ____ ___
  641. // \__ ___/___ _____ _____ | | \______ ___________
  642. // | |_/ __ \\__ \ / \| | / ___// __ \_ __ \
  643. // | |\ ___/ / __ \| Y Y \ | /\___ \\ ___/| | \/
  644. // |____| \___ >____ /__|_| /______//____ >\___ >__|
  645. // \/ \/ \/ \/ \/
  646. // TeamUser represents an team-user relation.
  647. type TeamUser struct {
  648. ID int64 `xorm:"pk autoincr"`
  649. OrgID int64 `xorm:"INDEX"`
  650. TeamID int64 `xorm:"UNIQUE(s)"`
  651. Uid int64 `xorm:"UNIQUE(s)"`
  652. }
  653. func isTeamMember(e Engine, orgID, teamID, uid int64) bool {
  654. has, _ := e.Where("org_id=?", orgID).And("team_id=?", teamID).And("uid=?", uid).Get(new(TeamUser))
  655. return has
  656. }
  657. // IsTeamMember returns true if given user is a member of team.
  658. func IsTeamMember(orgID, teamID, uid int64) bool {
  659. return isTeamMember(x, orgID, teamID, uid)
  660. }
  661. func getTeamMembers(e Engine, teamID int64) (_ []*User, err error) {
  662. teamUsers := make([]*TeamUser, 0, 10)
  663. if err = e.Where("team_id=?", teamID).Find(&teamUsers); err != nil {
  664. return nil, fmt.Errorf("get team-users: %v", err)
  665. }
  666. members := make([]*User, 0, len(teamUsers))
  667. for i := range teamUsers {
  668. member := new(User)
  669. if _, err = e.Id(teamUsers[i].Uid).Get(member); err != nil {
  670. return nil, fmt.Errorf("get user '%d': %v", teamUsers[i].Uid, err)
  671. }
  672. members = append(members, member)
  673. }
  674. return members, nil
  675. }
  676. // GetTeamMembers returns all members in given team of organization.
  677. func GetTeamMembers(teamID int64) ([]*User, error) {
  678. return getTeamMembers(x, teamID)
  679. }
  680. func getUserTeams(e Engine, orgId, uid int64) ([]*Team, error) {
  681. tus := make([]*TeamUser, 0, 5)
  682. if err := e.Where("uid=?", uid).And("org_id=?", orgId).Find(&tus); err != nil {
  683. return nil, err
  684. }
  685. ts := make([]*Team, len(tus))
  686. for i, tu := range tus {
  687. t := new(Team)
  688. has, err := e.Id(tu.TeamID).Get(t)
  689. if err != nil {
  690. return nil, err
  691. } else if !has {
  692. return nil, ErrTeamNotExist
  693. }
  694. ts[i] = t
  695. }
  696. return ts, nil
  697. }
  698. // GetUserTeams returns all teams that user belongs to in given organization.
  699. func GetUserTeams(orgId, uid int64) ([]*Team, error) {
  700. return getUserTeams(x, orgId, uid)
  701. }
  702. // AddTeamMember adds new member to given team of given organization.
  703. func AddTeamMember(orgId, teamId, uid int64) error {
  704. if IsTeamMember(orgId, teamId, uid) {
  705. return nil
  706. }
  707. if err := AddOrgUser(orgId, uid); err != nil {
  708. return err
  709. }
  710. // Get team and its repositories.
  711. t, err := GetTeamById(teamId)
  712. if err != nil {
  713. return err
  714. }
  715. t.NumMembers++
  716. if err = t.GetRepositories(); err != nil {
  717. return err
  718. }
  719. sess := x.NewSession()
  720. defer sessionRelease(sess)
  721. if err = sess.Begin(); err != nil {
  722. return err
  723. }
  724. tu := &TeamUser{
  725. Uid: uid,
  726. OrgID: orgId,
  727. TeamID: teamId,
  728. }
  729. if _, err = sess.Insert(tu); err != nil {
  730. return err
  731. } else if _, err = sess.Id(t.ID).Update(t); err != nil {
  732. return err
  733. }
  734. // Give access to team repositories.
  735. for _, repo := range t.Repos {
  736. if err = repo.recalculateTeamAccesses(sess, 0); err != nil {
  737. return err
  738. }
  739. }
  740. // We make sure it exists before.
  741. ou := new(OrgUser)
  742. if _, err = sess.Where("uid=?", uid).And("org_id=?", orgId).Get(ou); err != nil {
  743. return err
  744. }
  745. ou.NumTeams++
  746. if t.IsOwnerTeam() {
  747. ou.IsOwner = true
  748. }
  749. if _, err = sess.Id(ou.ID).AllCols().Update(ou); err != nil {
  750. return err
  751. }
  752. return sess.Commit()
  753. }
  754. func removeTeamMember(e Engine, orgId, teamId, uid int64) error {
  755. if !isTeamMember(e, orgId, teamId, uid) {
  756. return nil
  757. }
  758. // Get team and its repositories.
  759. t, err := getTeamById(e, teamId)
  760. if err != nil {
  761. return err
  762. }
  763. // Check if the user to delete is the last member in owner team.
  764. if t.IsOwnerTeam() && t.NumMembers == 1 {
  765. return ErrLastOrgOwner{UID: uid}
  766. }
  767. t.NumMembers--
  768. if err = t.getRepositories(e); err != nil {
  769. return err
  770. }
  771. // Get organization.
  772. org, err := getUserByID(e, orgId)
  773. if err != nil {
  774. return err
  775. }
  776. tu := &TeamUser{
  777. Uid: uid,
  778. OrgID: orgId,
  779. TeamID: teamId,
  780. }
  781. if _, err := e.Delete(tu); err != nil {
  782. return err
  783. } else if _, err = e.Id(t.ID).AllCols().Update(t); err != nil {
  784. return err
  785. }
  786. // Delete access to team repositories.
  787. for _, repo := range t.Repos {
  788. if err = repo.recalculateTeamAccesses(e, 0); err != nil {
  789. return err
  790. }
  791. }
  792. // This must exist.
  793. ou := new(OrgUser)
  794. _, err = e.Where("uid=?", uid).And("org_id=?", org.Id).Get(ou)
  795. if err != nil {
  796. return err
  797. }
  798. ou.NumTeams--
  799. if t.IsOwnerTeam() {
  800. ou.IsOwner = false
  801. }
  802. if _, err = e.Id(ou.ID).AllCols().Update(ou); err != nil {
  803. return err
  804. }
  805. return nil
  806. }
  807. // RemoveTeamMember removes member from given team of given organization.
  808. func RemoveTeamMember(orgId, teamId, uid int64) error {
  809. sess := x.NewSession()
  810. defer sessionRelease(sess)
  811. if err := sess.Begin(); err != nil {
  812. return err
  813. }
  814. if err := removeTeamMember(sess, orgId, teamId, uid); err != nil {
  815. return err
  816. }
  817. return sess.Commit()
  818. }
  819. // ___________ __________
  820. // \__ ___/___ _____ _____\______ \ ____ ______ ____
  821. // | |_/ __ \\__ \ / \| _// __ \\____ \ / _ \
  822. // | |\ ___/ / __ \| Y Y \ | \ ___/| |_> > <_> )
  823. // |____| \___ >____ /__|_| /____|_ /\___ > __/ \____/
  824. // \/ \/ \/ \/ \/|__|
  825. // TeamRepo represents an team-repository relation.
  826. type TeamRepo struct {
  827. ID int64 `xorm:"pk autoincr"`
  828. OrgID int64 `xorm:"INDEX"`
  829. TeamID int64 `xorm:"UNIQUE(s)"`
  830. RepoID int64 `xorm:"UNIQUE(s)"`
  831. }
  832. func hasTeamRepo(e Engine, orgID, teamID, repoID int64) bool {
  833. has, _ := e.Where("org_id=?", orgID).And("team_id=?", teamID).And("repo_id=?", repoID).Get(new(TeamRepo))
  834. return has
  835. }
  836. // HasTeamRepo returns true if given repository belongs to team.
  837. func HasTeamRepo(orgID, teamID, repoID int64) bool {
  838. return hasTeamRepo(x, orgID, teamID, repoID)
  839. }
  840. func addTeamRepo(e Engine, orgID, teamID, repoID int64) error {
  841. _, err := e.InsertOne(&TeamRepo{
  842. OrgID: orgID,
  843. TeamID: teamID,
  844. RepoID: repoID,
  845. })
  846. return err
  847. }
  848. // AddTeamRepo adds new repository relation to team.
  849. func AddTeamRepo(orgID, teamID, repoID int64) error {
  850. return addTeamRepo(x, orgID, teamID, repoID)
  851. }
  852. func removeTeamRepo(e Engine, teamID, repoID int64) error {
  853. _, err := e.Delete(&TeamRepo{
  854. TeamID: teamID,
  855. RepoID: repoID,
  856. })
  857. return err
  858. }
  859. // RemoveTeamRepo deletes repository relation to team.
  860. func RemoveTeamRepo(teamID, repoID int64) error {
  861. return removeTeamRepo(x, teamID, repoID)
  862. }
  863. func removeOrgRepo(e Engine, orgID, repoID int64) error {
  864. _, err := e.Delete(&TeamRepo{
  865. OrgID: orgID,
  866. RepoID: repoID,
  867. })
  868. return err
  869. }
  870. // RemoveOrgRepo removes all team-repository relations of given organization.
  871. func RemoveOrgRepo(orgID, repoID int64) error {
  872. return removeOrgRepo(x, orgID, repoID)
  873. }
  874. func (org *User) getUserRepositories(userID int64) (err error) {
  875. teams := make([]*Team, 0, 10)
  876. if err := x.Cols("`team`.id").
  877. Where("`team_user`.org_id=?", org.Id).
  878. And("`team_user`.uid=?", userID).
  879. Join("INNER", "`team_user`", "`team_user`.team_id=`team`.id").
  880. Find(&teams); err != nil {
  881. return fmt.Errorf("getUserRepositories: get teams: %v", err)
  882. }
  883. var teamIDs []string
  884. for _, team := range teams {
  885. teamIDs = append(teamIDs, strconv.FormatInt(team.ID, 10))
  886. }
  887. if len(teamIDs) == 0 {
  888. // user has no team but "IN ()" is invalid SQL
  889. teamIDs = append(teamIDs, "-1") // there is no repo with id=-1
  890. }
  891. // Due to a bug in xorm using IN() together with OR() is impossible.
  892. // As a workaround, we have to build the IN statement on our own, until this is fixed.
  893. // https://github.com/go-xorm/xorm/issues/342
  894. if err := x.Cols("`repository`.*").
  895. Join("INNER", "`team_repo`", "`team_repo`.repo_id=`repository`.id").
  896. Where("`repository`.owner_id=?", org.Id).
  897. And("`repository`.is_private=?", false).
  898. Or("`team_repo`.team_id=(?)", strings.Join(teamIDs, ",")).
  899. GroupBy("`repository`.id").
  900. Find(&org.Repos); err != nil {
  901. return fmt.Errorf("getUserRepositories: get repositories: %v", err)
  902. }
  903. org.NumRepos = len(org.Repos)
  904. return
  905. }
  906. // GetUserRepositories gets all repositories of an organization,
  907. // that the user with the given userID has access to.
  908. func (org *User) GetUserRepositories(userID int64) error {
  909. return org.getUserRepositories(userID)
  910. }
  911. func (org *User) getUserTeams(userID int64) (err error) {
  912. if err := x.Cols("`team`.*").
  913. Where("`team_user`.org_id=?", org.Id).
  914. And("`team_user`.uid=?", userID).
  915. Join("INNER", "`team_user`", "`team_user`.team_id=`team`.id").
  916. Find(&org.Teams); err != nil {
  917. return fmt.Errorf("getUserTeams: %v", err)
  918. }
  919. org.NumTeams = len(org.Teams)
  920. return
  921. }
  922. // GetTeams returns all teams that belong to organization,
  923. // and that the user has joined.
  924. func (org *User) GetUserTeams(userID int64) error {
  925. return org.getUserTeams(userID)
  926. }