You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

org.go 28 kB

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