org.go 28 KB

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