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 25 kB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085
  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. "path"
  10. "strings"
  11. "github.com/Unknwon/com"
  12. "github.com/go-xorm/xorm"
  13. "github.com/gogits/gogs/modules/base"
  14. )
  15. var (
  16. ErrOrgNotExist = errors.New("Organization does not exist")
  17. ErrTeamAlreadyExist = errors.New("Team already exist")
  18. ErrTeamNotExist = errors.New("Team does not exist")
  19. ErrTeamNameIllegal = errors.New("Team name contains illegal characters")
  20. ErrLastOrgOwner = errors.New("The user to remove is the last member in owner team")
  21. )
  22. // IsOrgOwner returns true if given user is in the owner team.
  23. func (org *User) IsOrgOwner(uid int64) bool {
  24. return IsOrganizationOwner(org.Id, uid)
  25. }
  26. // IsOrgMember returns true if given user is member of organization.
  27. func (org *User) IsOrgMember(uid int64) bool {
  28. return IsOrganizationMember(org.Id, uid)
  29. }
  30. // GetTeam returns named team of organization.
  31. func (org *User) GetTeam(name string) (*Team, error) {
  32. return GetTeam(org.Id, name)
  33. }
  34. // GetOwnerTeam returns owner team of organization.
  35. func (org *User) GetOwnerTeam() (*Team, error) {
  36. return org.GetTeam(OWNER_TEAM)
  37. }
  38. // GetTeams returns all teams that belong to organization.
  39. func (org *User) GetTeams() error {
  40. return x.Where("org_id=?", org.Id).Find(&org.Teams)
  41. }
  42. // GetMembers returns all members of organization.
  43. func (org *User) GetMembers() error {
  44. ous, err := GetOrgUsersByOrgId(org.Id)
  45. if err != nil {
  46. return err
  47. }
  48. org.Members = make([]*User, len(ous))
  49. for i, ou := range ous {
  50. org.Members[i], err = GetUserById(ou.Uid)
  51. if err != nil {
  52. return err
  53. }
  54. }
  55. return nil
  56. }
  57. // AddMember adds new member to organization.
  58. func (org *User) AddMember(uid int64) error {
  59. return AddOrgUser(org.Id, uid)
  60. }
  61. // RemoveMember removes member from organization.
  62. func (org *User) RemoveMember(uid int64) error {
  63. return RemoveOrgUser(org.Id, uid)
  64. }
  65. // IsOrgEmailUsed returns true if the e-mail has been used in organization account.
  66. func IsOrgEmailUsed(email string) (bool, error) {
  67. if len(email) == 0 {
  68. return false, nil
  69. }
  70. return x.Get(&User{
  71. Email: email,
  72. Type: ORGANIZATION,
  73. })
  74. }
  75. // CreateOrganization creates record of a new organization.
  76. func CreateOrganization(org, owner *User) (*User, error) {
  77. if !IsLegalName(org.Name) {
  78. return nil, ErrUserNameIllegal
  79. }
  80. isExist, err := IsUserExist(org.Name)
  81. if err != nil {
  82. return nil, err
  83. } else if isExist {
  84. return nil, ErrUserAlreadyExist
  85. }
  86. isExist, err = IsOrgEmailUsed(org.Email)
  87. if err != nil {
  88. return nil, err
  89. } else if isExist {
  90. return nil, ErrEmailAlreadyUsed
  91. }
  92. org.LowerName = strings.ToLower(org.Name)
  93. org.FullName = org.Name
  94. org.Avatar = base.EncodeMd5(org.Email)
  95. org.AvatarEmail = org.Email
  96. // No password for organization.
  97. org.NumTeams = 1
  98. org.NumMembers = 1
  99. sess := x.NewSession()
  100. defer sess.Close()
  101. if err = sess.Begin(); err != nil {
  102. return nil, err
  103. }
  104. if _, err = sess.Insert(org); err != nil {
  105. sess.Rollback()
  106. return nil, err
  107. }
  108. if err = os.MkdirAll(UserPath(org.Name), os.ModePerm); err != nil {
  109. sess.Rollback()
  110. return nil, err
  111. }
  112. // Create default owner team.
  113. t := &Team{
  114. OrgId: org.Id,
  115. LowerName: strings.ToLower(OWNER_TEAM),
  116. Name: OWNER_TEAM,
  117. Authorize: ORG_ADMIN,
  118. NumMembers: 1,
  119. }
  120. if _, err = sess.Insert(t); err != nil {
  121. sess.Rollback()
  122. return nil, err
  123. }
  124. // Add initial creator to organization and owner team.
  125. ou := &OrgUser{
  126. Uid: owner.Id,
  127. OrgId: org.Id,
  128. IsOwner: true,
  129. NumTeams: 1,
  130. }
  131. if _, err = sess.Insert(ou); err != nil {
  132. sess.Rollback()
  133. return nil, err
  134. }
  135. tu := &TeamUser{
  136. Uid: owner.Id,
  137. OrgId: org.Id,
  138. TeamId: t.Id,
  139. }
  140. if _, err = sess.Insert(tu); err != nil {
  141. sess.Rollback()
  142. return nil, err
  143. }
  144. return org, sess.Commit()
  145. }
  146. // CountOrganizations returns number of organizations.
  147. func CountOrganizations() int64 {
  148. count, _ := x.Where("type=1").Count(new(User))
  149. return count
  150. }
  151. // GetOrganizations returns given number of organizations with offset.
  152. func GetOrganizations(num, offset int) ([]*User, error) {
  153. orgs := make([]*User, 0, num)
  154. err := x.Limit(num, offset).Where("type=1").Asc("id").Find(&orgs)
  155. return orgs, err
  156. }
  157. // TODO: need some kind of mechanism to record failure.
  158. // DeleteOrganization completely and permanently deletes everything of organization.
  159. func DeleteOrganization(org *User) (err error) {
  160. if err := DeleteUser(org); err != nil {
  161. return err
  162. }
  163. sess := x.NewSession()
  164. defer sess.Close()
  165. if err = sess.Begin(); err != nil {
  166. return err
  167. }
  168. if _, err = sess.Delete(&Team{OrgId: org.Id}); err != nil {
  169. sess.Rollback()
  170. return err
  171. }
  172. if _, err = sess.Delete(&OrgUser{OrgId: org.Id}); err != nil {
  173. sess.Rollback()
  174. return err
  175. }
  176. if _, err = sess.Delete(&TeamUser{OrgId: org.Id}); err != nil {
  177. sess.Rollback()
  178. return err
  179. }
  180. return sess.Commit()
  181. }
  182. // ________ ____ ___
  183. // \_____ \_______ ____ | | \______ ___________
  184. // / | \_ __ \/ ___\| | / ___// __ \_ __ \
  185. // / | \ | \/ /_/ > | /\___ \\ ___/| | \/
  186. // \_______ /__| \___ /|______//____ >\___ >__|
  187. // \/ /_____/ \/ \/
  188. // OrgUser represents an organization-user relation.
  189. type OrgUser struct {
  190. Id int64
  191. Uid int64 `xorm:"INDEX UNIQUE(s)"`
  192. OrgId int64 `xorm:"INDEX UNIQUE(s)"`
  193. IsPublic bool
  194. IsOwner bool
  195. NumTeams int
  196. }
  197. // IsOrganizationOwner returns true if given user is in the owner team.
  198. func IsOrganizationOwner(orgId, uid int64) bool {
  199. has, _ := x.Where("is_owner=?", true).And("uid=?", uid).And("org_id=?", orgId).Get(new(OrgUser))
  200. return has
  201. }
  202. // IsOrganizationMember returns true if given user is member of organization.
  203. func IsOrganizationMember(orgId, uid int64) bool {
  204. has, _ := x.Where("uid=?", uid).And("org_id=?", orgId).Get(new(OrgUser))
  205. return has
  206. }
  207. // IsPublicMembership returns ture if given user public his/her membership.
  208. func IsPublicMembership(orgId, uid int64) bool {
  209. has, _ := x.Where("uid=?", uid).And("org_id=?", orgId).And("is_public=?", true).Get(new(OrgUser))
  210. return has
  211. }
  212. // GetOrgUsersByUserId returns all organization-user relations by user ID.
  213. func GetOrgUsersByUserId(uid int64) ([]*OrgUser, error) {
  214. ous := make([]*OrgUser, 0, 10)
  215. err := x.Where("uid=?", uid).Find(&ous)
  216. return ous, err
  217. }
  218. // GetOrgUsersByOrgId returns all organization-user relations by organization ID.
  219. func GetOrgUsersByOrgId(orgId int64) ([]*OrgUser, error) {
  220. ous := make([]*OrgUser, 0, 10)
  221. err := x.Where("org_id=?", orgId).Find(&ous)
  222. return ous, err
  223. }
  224. // ChangeOrgUserStatus changes public or private membership status.
  225. func ChangeOrgUserStatus(orgId, uid int64, public bool) error {
  226. ou := new(OrgUser)
  227. has, err := x.Where("uid=?", uid).And("org_id=?", orgId).Get(ou)
  228. if err != nil {
  229. return err
  230. } else if !has {
  231. return nil
  232. }
  233. ou.IsPublic = public
  234. _, err = x.Id(ou.Id).AllCols().Update(ou)
  235. return err
  236. }
  237. // AddOrgUser adds new user to given organization.
  238. func AddOrgUser(orgId, uid int64) error {
  239. if IsOrganizationMember(orgId, uid) {
  240. return nil
  241. }
  242. sess := x.NewSession()
  243. defer sess.Close()
  244. if err := sess.Begin(); err != nil {
  245. return err
  246. }
  247. ou := &OrgUser{
  248. Uid: uid,
  249. OrgId: orgId,
  250. }
  251. if _, err := sess.Insert(ou); err != nil {
  252. sess.Rollback()
  253. return err
  254. } else if _, err = sess.Exec("UPDATE `user` SET num_members = num_members + 1 WHERE id = ?", orgId); err != nil {
  255. sess.Rollback()
  256. return err
  257. }
  258. return sess.Commit()
  259. }
  260. // RemoveOrgUser removes user from given organization.
  261. func RemoveOrgUser(orgId, uid int64) error {
  262. ou := new(OrgUser)
  263. has, err := x.Where("uid=?", uid).And("org_id=?", orgId).Get(ou)
  264. if err != nil {
  265. return err
  266. } else if !has {
  267. return nil
  268. }
  269. u, err := GetUserById(uid)
  270. if err != nil {
  271. return err
  272. }
  273. org, err := GetUserById(orgId)
  274. if err != nil {
  275. return err
  276. }
  277. // Check if the user to delete is the last member in owner team.
  278. if IsOrganizationOwner(orgId, uid) {
  279. t, err := org.GetOwnerTeam()
  280. if err != nil {
  281. return err
  282. }
  283. if t.NumMembers == 1 {
  284. return ErrLastOrgOwner
  285. }
  286. }
  287. sess := x.NewSession()
  288. defer sess.Close()
  289. if err := sess.Begin(); err != nil {
  290. return err
  291. }
  292. if _, err := sess.Id(ou.Id).Delete(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. // Delete all repository accesses.
  300. if err = org.GetRepositories(); err != nil {
  301. sess.Rollback()
  302. return err
  303. }
  304. access := &Access{
  305. UserName: u.LowerName,
  306. }
  307. for _, repo := range org.Repos {
  308. access.RepoName = path.Join(org.LowerName, repo.LowerName)
  309. if _, err = sess.Delete(access); err != nil {
  310. sess.Rollback()
  311. return err
  312. } else if err = WatchRepo(u.Id, repo.Id, false); err != nil {
  313. sess.Rollback()
  314. return err
  315. }
  316. }
  317. // Delete member in his/her teams.
  318. ts, err := GetUserTeams(org.Id, u.Id)
  319. if err != nil {
  320. return err
  321. }
  322. for _, t := range ts {
  323. if err = removeTeamMemberWithSess(org.Id, t.Id, u.Id, sess); err != nil {
  324. return err
  325. }
  326. }
  327. return sess.Commit()
  328. }
  329. // ___________
  330. // \__ ___/___ _____ _____
  331. // | |_/ __ \\__ \ / \
  332. // | |\ ___/ / __ \| Y Y \
  333. // |____| \___ >____ /__|_| /
  334. // \/ \/ \/
  335. type AuthorizeType int
  336. const (
  337. ORG_READABLE AuthorizeType = iota + 1
  338. ORG_WRITABLE
  339. ORG_ADMIN
  340. )
  341. func AuthorizeToAccessType(auth AuthorizeType) AccessType {
  342. if auth == ORG_READABLE {
  343. return READABLE
  344. }
  345. return WRITABLE
  346. }
  347. const OWNER_TEAM = "Owners"
  348. // Team represents a organization team.
  349. type Team struct {
  350. Id int64
  351. OrgId int64 `xorm:"INDEX"`
  352. LowerName string
  353. Name string
  354. Description string
  355. Authorize AuthorizeType
  356. RepoIds string `xorm:"TEXT"`
  357. Repos []*Repository `xorm:"-"`
  358. Members []*User `xorm:"-"`
  359. NumRepos int
  360. NumMembers int
  361. }
  362. // IsOwnerTeam returns true if team is owner team.
  363. func (t *Team) IsOwnerTeam() bool {
  364. return t.Name == OWNER_TEAM
  365. }
  366. // IsTeamMember returns true if given user is a member of team.
  367. func (t *Team) IsMember(uid int64) bool {
  368. return IsTeamMember(t.OrgId, t.Id, uid)
  369. }
  370. // GetRepositories returns all repositories in team of organization.
  371. func (t *Team) GetRepositories() error {
  372. idStrs := strings.Split(t.RepoIds, "|")
  373. t.Repos = make([]*Repository, 0, len(idStrs))
  374. for _, str := range idStrs {
  375. if len(str) == 0 {
  376. continue
  377. }
  378. id := com.StrTo(str[1:]).MustInt64()
  379. if id == 0 {
  380. continue
  381. }
  382. repo, err := GetRepositoryById(id)
  383. if err != nil {
  384. return err
  385. }
  386. t.Repos = append(t.Repos, repo)
  387. }
  388. return nil
  389. }
  390. // GetMembers returns all members in team of organization.
  391. func (t *Team) GetMembers() (err error) {
  392. t.Members, err = GetTeamMembers(t.OrgId, t.Id)
  393. return err
  394. }
  395. // AddMember adds new member to team of organization.
  396. func (t *Team) AddMember(uid int64) error {
  397. return AddTeamMember(t.OrgId, t.Id, uid)
  398. }
  399. // RemoveMember removes member from team of organization.
  400. func (t *Team) RemoveMember(uid int64) error {
  401. return RemoveTeamMember(t.OrgId, t.Id, uid)
  402. }
  403. // addAccessWithAuthorize inserts or updates access with given mode.
  404. func addAccessWithAuthorize(sess *xorm.Session, access *Access, mode AccessType) error {
  405. has, err := x.Get(access)
  406. if err != nil {
  407. return fmt.Errorf("fail to get access: %v", err)
  408. }
  409. access.Mode = mode
  410. if has {
  411. if _, err = sess.Id(access.Id).Update(access); err != nil {
  412. return fmt.Errorf("fail to update access: %v", err)
  413. }
  414. } else {
  415. if _, err = sess.Insert(access); err != nil {
  416. return fmt.Errorf("fail to insert access: %v", err)
  417. }
  418. }
  419. return nil
  420. }
  421. // AddRepository adds new repository to team of organization.
  422. func (t *Team) AddRepository(repo *Repository) (err error) {
  423. idStr := "$" + com.ToStr(repo.Id) + "|"
  424. if repo.OwnerId != t.OrgId {
  425. return errors.New("Repository not belong to organization")
  426. } else if strings.Contains(t.RepoIds, idStr) {
  427. return nil
  428. }
  429. if err = repo.GetOwner(); err != nil {
  430. return err
  431. } else if err = t.GetMembers(); err != nil {
  432. return err
  433. }
  434. sess := x.NewSession()
  435. defer sess.Close()
  436. if err = sess.Begin(); err != nil {
  437. return err
  438. }
  439. t.NumRepos++
  440. t.RepoIds += idStr
  441. if _, err = sess.Id(t.Id).AllCols().Update(t); err != nil {
  442. sess.Rollback()
  443. return err
  444. }
  445. // Give access to team members.
  446. mode := AuthorizeToAccessType(t.Authorize)
  447. for _, u := range t.Members {
  448. auth, err := GetHighestAuthorize(t.OrgId, u.Id, repo.Id, t.Id)
  449. if err != nil {
  450. sess.Rollback()
  451. return err
  452. }
  453. access := &Access{
  454. UserName: u.LowerName,
  455. RepoName: path.Join(repo.Owner.LowerName, repo.LowerName),
  456. }
  457. if auth < t.Authorize {
  458. if err = addAccessWithAuthorize(sess, access, mode); err != nil {
  459. sess.Rollback()
  460. return err
  461. }
  462. }
  463. if err = WatchRepo(u.Id, repo.Id, true); err != nil {
  464. sess.Rollback()
  465. return err
  466. }
  467. }
  468. return sess.Commit()
  469. }
  470. // RemoveRepository removes repository from team of organization.
  471. func (t *Team) RemoveRepository(repoId int64) error {
  472. idStr := "$" + com.ToStr(repoId) + "|"
  473. if !strings.Contains(t.RepoIds, idStr) {
  474. return nil
  475. }
  476. repo, err := GetRepositoryById(repoId)
  477. if err != nil {
  478. return err
  479. }
  480. if err = repo.GetOwner(); err != nil {
  481. return err
  482. } else if err = t.GetMembers(); err != nil {
  483. return err
  484. }
  485. sess := x.NewSession()
  486. defer sess.Close()
  487. if err = sess.Begin(); err != nil {
  488. return err
  489. }
  490. t.NumRepos--
  491. t.RepoIds = strings.Replace(t.RepoIds, idStr, "", 1)
  492. if _, err = sess.Id(t.Id).AllCols().Update(t); err != nil {
  493. sess.Rollback()
  494. return err
  495. }
  496. // Remove access to team members.
  497. for _, u := range t.Members {
  498. auth, err := GetHighestAuthorize(t.OrgId, u.Id, repo.Id, t.Id)
  499. if err != nil {
  500. sess.Rollback()
  501. return err
  502. }
  503. access := &Access{
  504. UserName: u.LowerName,
  505. RepoName: path.Join(repo.Owner.LowerName, repo.LowerName),
  506. }
  507. if auth == 0 {
  508. if _, err = sess.Delete(access); err != nil {
  509. sess.Rollback()
  510. return fmt.Errorf("fail to delete access: %v", err)
  511. } else if err = WatchRepo(u.Id, repo.Id, false); err != nil {
  512. sess.Rollback()
  513. return err
  514. }
  515. } else if auth < t.Authorize {
  516. if err = addAccessWithAuthorize(sess, access, AuthorizeToAccessType(auth)); err != nil {
  517. sess.Rollback()
  518. return err
  519. }
  520. }
  521. }
  522. return sess.Commit()
  523. }
  524. // NewTeam creates a record of new team.
  525. // It's caller's responsibility to assign organization ID.
  526. func NewTeam(t *Team) error {
  527. if !IsLegalName(t.Name) {
  528. return ErrTeamNameIllegal
  529. }
  530. has, err := x.Id(t.OrgId).Get(new(User))
  531. if err != nil {
  532. return err
  533. } else if !has {
  534. return ErrOrgNotExist
  535. }
  536. t.LowerName = strings.ToLower(t.Name)
  537. has, err = x.Where("org_id=?", t.OrgId).And("lower_name=?", t.LowerName).Get(new(Team))
  538. if err != nil {
  539. return err
  540. } else if has {
  541. return ErrTeamAlreadyExist
  542. }
  543. sess := x.NewSession()
  544. defer sess.Close()
  545. if err = sess.Begin(); err != nil {
  546. return err
  547. }
  548. if _, err = sess.Insert(t); err != nil {
  549. sess.Rollback()
  550. return err
  551. }
  552. // Update organization number of teams.
  553. if _, err = sess.Exec("UPDATE `user` SET num_teams = num_teams + 1 WHERE id = ?", t.OrgId); err != nil {
  554. sess.Rollback()
  555. return err
  556. }
  557. return sess.Commit()
  558. }
  559. // GetTeam returns team by given team name and organization.
  560. func GetTeam(orgId int64, name string) (*Team, error) {
  561. t := &Team{
  562. OrgId: orgId,
  563. LowerName: strings.ToLower(name),
  564. }
  565. has, err := x.Get(t)
  566. if err != nil {
  567. return nil, err
  568. } else if !has {
  569. return nil, ErrTeamNotExist
  570. }
  571. return t, nil
  572. }
  573. // GetTeamById returns team by given ID.
  574. func GetTeamById(teamId int64) (*Team, error) {
  575. t := new(Team)
  576. has, err := x.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. // GetHighestAuthorize returns highest repository authorize level for given user and team.
  585. func GetHighestAuthorize(orgId, uid, repoId, teamId int64) (AuthorizeType, error) {
  586. ts, err := GetUserTeams(orgId, uid)
  587. if err != nil {
  588. return 0, err
  589. }
  590. var auth AuthorizeType = 0
  591. for _, t := range ts {
  592. // Not current team and has given repository.
  593. if t.Id != teamId && strings.Contains(t.RepoIds, "$"+com.ToStr(repoId)+"|") {
  594. // Fast return.
  595. if t.Authorize == ORG_WRITABLE {
  596. return ORG_WRITABLE, nil
  597. }
  598. if t.Authorize > auth {
  599. auth = t.Authorize
  600. }
  601. }
  602. }
  603. return auth, nil
  604. }
  605. // UpdateTeam updates information of team.
  606. func UpdateTeam(t *Team, authChanged bool) (err error) {
  607. if !IsLegalName(t.Name) {
  608. return ErrTeamNameIllegal
  609. }
  610. if len(t.Description) > 255 {
  611. t.Description = t.Description[:255]
  612. }
  613. sess := x.NewSession()
  614. defer sess.Close()
  615. if err = sess.Begin(); err != nil {
  616. return err
  617. }
  618. // Update access for team members if needed.
  619. if authChanged && !t.IsOwnerTeam() {
  620. if err = t.GetRepositories(); err != nil {
  621. return err
  622. } else if err = t.GetMembers(); err != nil {
  623. return err
  624. }
  625. // Get organization.
  626. org, err := GetUserById(t.OrgId)
  627. if err != nil {
  628. return err
  629. }
  630. // Update access.
  631. mode := AuthorizeToAccessType(t.Authorize)
  632. for _, repo := range t.Repos {
  633. for _, u := range t.Members {
  634. // ORG_WRITABLE is the highest authorize level for now.
  635. // Skip checking others if current team has this level.
  636. if t.Authorize < ORG_WRITABLE {
  637. auth, err := GetHighestAuthorize(t.OrgId, u.Id, repo.Id, t.Id)
  638. if err != nil {
  639. sess.Rollback()
  640. return err
  641. }
  642. if auth >= t.Authorize {
  643. continue // Other team has higher or same authorize level.
  644. }
  645. }
  646. access := &Access{
  647. UserName: u.LowerName,
  648. RepoName: path.Join(org.LowerName, repo.LowerName),
  649. }
  650. if err = addAccessWithAuthorize(sess, access, mode); err != nil {
  651. sess.Rollback()
  652. return err
  653. }
  654. }
  655. }
  656. }
  657. t.LowerName = strings.ToLower(t.Name)
  658. if _, err = sess.Id(t.Id).AllCols().Update(t); err != nil {
  659. sess.Rollback()
  660. return err
  661. }
  662. return sess.Commit()
  663. }
  664. // DeleteTeam deletes given team.
  665. // It's caller's responsibility to assign organization ID.
  666. func DeleteTeam(t *Team) error {
  667. if err := t.GetRepositories(); err != nil {
  668. return err
  669. } else if err = t.GetMembers(); err != nil {
  670. return err
  671. }
  672. // Get organization.
  673. org, err := GetUserById(t.OrgId)
  674. if err != nil {
  675. return err
  676. }
  677. sess := x.NewSession()
  678. defer sess.Close()
  679. if err = sess.Begin(); err != nil {
  680. return err
  681. }
  682. // Delete all accesses.
  683. for _, repo := range t.Repos {
  684. for _, u := range t.Members {
  685. auth, err := GetHighestAuthorize(t.OrgId, u.Id, repo.Id, t.Id)
  686. if err != nil {
  687. sess.Rollback()
  688. return err
  689. }
  690. access := &Access{
  691. UserName: u.LowerName,
  692. RepoName: path.Join(org.LowerName, repo.LowerName),
  693. }
  694. if auth == 0 {
  695. if _, err = sess.Delete(access); err != nil {
  696. sess.Rollback()
  697. return fmt.Errorf("fail to delete access: %v", err)
  698. }
  699. } else if auth < t.Authorize {
  700. // Downgrade authorize level.
  701. if err = addAccessWithAuthorize(sess, access, AuthorizeToAccessType(auth)); err != nil {
  702. sess.Rollback()
  703. return err
  704. }
  705. }
  706. }
  707. }
  708. // Delete team-user.
  709. if _, err = sess.Where("org_id=?", org.Id).Where("team_id=?", t.Id).Delete(new(TeamUser)); err != nil {
  710. sess.Rollback()
  711. return err
  712. }
  713. // Delete team.
  714. if _, err = sess.Id(t.Id).Delete(new(Team)); err != nil {
  715. sess.Rollback()
  716. return err
  717. }
  718. // Update organization number of teams.
  719. if _, err = sess.Exec("UPDATE `user` SET num_teams = num_teams - 1 WHERE id = ?", t.OrgId); err != nil {
  720. sess.Rollback()
  721. return err
  722. }
  723. return sess.Commit()
  724. }
  725. // ___________ ____ ___
  726. // \__ ___/___ _____ _____ | | \______ ___________
  727. // | |_/ __ \\__ \ / \| | / ___// __ \_ __ \
  728. // | |\ ___/ / __ \| Y Y \ | /\___ \\ ___/| | \/
  729. // |____| \___ >____ /__|_| /______//____ >\___ >__|
  730. // \/ \/ \/ \/ \/
  731. // TeamUser represents an team-user relation.
  732. type TeamUser struct {
  733. Id int64
  734. Uid int64
  735. OrgId int64 `xorm:"INDEX"`
  736. TeamId int64
  737. }
  738. // IsTeamMember returns true if given user is a member of team.
  739. func IsTeamMember(orgId, teamId, uid int64) bool {
  740. has, _ := x.Where("uid=?", uid).And("org_id=?", orgId).And("team_id=?", teamId).Get(new(TeamUser))
  741. return has
  742. }
  743. // GetTeamMembers returns all members in given team of organization.
  744. func GetTeamMembers(orgId, teamId int64) ([]*User, error) {
  745. us := make([]*User, 0, 10)
  746. err := x.Sql("SELECT * FROM `user` JOIN `team_user` ON `team_user`.`team_id` = ? AND `team_user`.`uid` = `user`.`id`", teamId).Find(&us)
  747. return us, err
  748. }
  749. // GetUserTeams returns all teams that user belongs to in given origanization.
  750. func GetUserTeams(orgId, uid int64) ([]*Team, error) {
  751. tus := make([]*TeamUser, 0, 5)
  752. if err := x.Where("uid=?", uid).And("org_id=?", orgId).Find(&tus); err != nil {
  753. return nil, err
  754. }
  755. ts := make([]*Team, len(tus))
  756. for i, tu := range tus {
  757. t := new(Team)
  758. has, err := x.Id(tu.TeamId).Get(t)
  759. if err != nil {
  760. return nil, err
  761. } else if !has {
  762. return nil, ErrTeamNotExist
  763. }
  764. ts[i] = t
  765. }
  766. return ts, nil
  767. }
  768. // AddTeamMember adds new member to given team of given organization.
  769. func AddTeamMember(orgId, teamId, uid int64) error {
  770. if IsTeamMember(orgId, teamId, uid) {
  771. return nil
  772. }
  773. if err := AddOrgUser(orgId, uid); err != nil {
  774. return err
  775. }
  776. // Get team and its repositories.
  777. t, err := GetTeamById(teamId)
  778. if err != nil {
  779. return err
  780. }
  781. t.NumMembers++
  782. if err = t.GetRepositories(); err != nil {
  783. return err
  784. }
  785. // Get organization.
  786. org, err := GetUserById(orgId)
  787. if err != nil {
  788. return err
  789. }
  790. // Get user.
  791. u, err := GetUserById(uid)
  792. if err != nil {
  793. return err
  794. }
  795. sess := x.NewSession()
  796. defer sess.Close()
  797. if err = sess.Begin(); err != nil {
  798. return err
  799. }
  800. tu := &TeamUser{
  801. Uid: uid,
  802. OrgId: orgId,
  803. TeamId: teamId,
  804. }
  805. if _, err = sess.Insert(tu); err != nil {
  806. sess.Rollback()
  807. return err
  808. } else if _, err = sess.Id(t.Id).Update(t); err != nil {
  809. sess.Rollback()
  810. return err
  811. }
  812. // Give access to team repositories.
  813. mode := AuthorizeToAccessType(t.Authorize)
  814. for _, repo := range t.Repos {
  815. auth, err := GetHighestAuthorize(t.OrgId, u.Id, repo.Id, teamId)
  816. if err != nil {
  817. sess.Rollback()
  818. return err
  819. }
  820. access := &Access{
  821. UserName: u.LowerName,
  822. RepoName: path.Join(org.LowerName, repo.LowerName),
  823. }
  824. if auth < t.Authorize {
  825. if err = addAccessWithAuthorize(sess, access, mode); err != nil {
  826. sess.Rollback()
  827. return err
  828. }
  829. }
  830. }
  831. // We make sure it exists before.
  832. ou := new(OrgUser)
  833. _, err = sess.Where("uid=?", uid).And("org_id=?", orgId).Get(ou)
  834. if err != nil {
  835. sess.Rollback()
  836. return err
  837. }
  838. ou.NumTeams++
  839. if t.IsOwnerTeam() {
  840. ou.IsOwner = true
  841. }
  842. if _, err = sess.Id(ou.Id).AllCols().Update(ou); err != nil {
  843. sess.Rollback()
  844. return err
  845. }
  846. return sess.Commit()
  847. }
  848. func removeTeamMemberWithSess(orgId, teamId, uid int64, sess *xorm.Session) error {
  849. if !IsTeamMember(orgId, teamId, uid) {
  850. return nil
  851. }
  852. // Get team and its repositories.
  853. t, err := GetTeamById(teamId)
  854. if err != nil {
  855. return err
  856. }
  857. // Check if the user to delete is the last member in owner team.
  858. if t.IsOwnerTeam() && t.NumMembers == 1 {
  859. return ErrLastOrgOwner
  860. }
  861. t.NumMembers--
  862. if err = t.GetRepositories(); err != nil {
  863. return err
  864. }
  865. // Get organization.
  866. org, err := GetUserById(orgId)
  867. if err != nil {
  868. return err
  869. }
  870. // Get user.
  871. u, err := GetUserById(uid)
  872. if err != nil {
  873. return err
  874. }
  875. tu := &TeamUser{
  876. Uid: uid,
  877. OrgId: orgId,
  878. TeamId: teamId,
  879. }
  880. if _, err := sess.Delete(tu); err != nil {
  881. sess.Rollback()
  882. return err
  883. } else if _, err = sess.Id(t.Id).AllCols().Update(t); err != nil {
  884. sess.Rollback()
  885. return err
  886. }
  887. // Delete access to team repositories.
  888. for _, repo := range t.Repos {
  889. auth, err := GetHighestAuthorize(t.OrgId, u.Id, repo.Id, teamId)
  890. if err != nil {
  891. sess.Rollback()
  892. return err
  893. }
  894. access := &Access{
  895. UserName: u.LowerName,
  896. RepoName: path.Join(org.LowerName, repo.LowerName),
  897. }
  898. // Delete access if this is the last team user belongs to.
  899. if auth == 0 {
  900. if _, err = sess.Delete(access); err != nil {
  901. sess.Rollback()
  902. return fmt.Errorf("fail to delete access: %v", err)
  903. } else if err = WatchRepo(u.Id, repo.Id, false); err != nil {
  904. sess.Rollback()
  905. return err
  906. }
  907. } else if auth < t.Authorize {
  908. // Downgrade authorize level.
  909. if err = addAccessWithAuthorize(sess, access, AuthorizeToAccessType(auth)); err != nil {
  910. sess.Rollback()
  911. return err
  912. }
  913. }
  914. }
  915. // This must exist.
  916. ou := new(OrgUser)
  917. _, err = sess.Where("uid=?", uid).And("org_id=?", org.Id).Get(ou)
  918. if err != nil {
  919. sess.Rollback()
  920. return err
  921. }
  922. ou.NumTeams--
  923. if t.IsOwnerTeam() {
  924. ou.IsOwner = false
  925. }
  926. if _, err = sess.Id(ou.Id).AllCols().Update(ou); err != nil {
  927. sess.Rollback()
  928. return err
  929. }
  930. return nil
  931. }
  932. // RemoveTeamMember removes member from given team of given organization.
  933. func RemoveTeamMember(orgId, teamId, uid int64) error {
  934. sess := x.NewSession()
  935. defer sess.Close()
  936. if err := sess.Begin(); err != nil {
  937. return err
  938. }
  939. if err := removeTeamMemberWithSess(orgId, teamId, uid, sess); err != nil {
  940. return err
  941. }
  942. return sess.Commit()
  943. }