org.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  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. "os"
  8. "path"
  9. "strings"
  10. "github.com/Unknwon/com"
  11. "github.com/gogits/gogs/modules/base"
  12. )
  13. var (
  14. ErrOrgNotExist = errors.New("Organization does not exist")
  15. ErrTeamAlreadyExist = errors.New("Team already exist")
  16. ErrTeamNotExist = errors.New("Team does not exist")
  17. ErrTeamNameIllegal = errors.New("Team name contains illegal characters")
  18. ErrLastOrgOwner = errors.New("The user to remove is the last member in owner team")
  19. )
  20. // IsOrgOwner returns true if given user is in the owner team.
  21. func (org *User) IsOrgOwner(uid int64) bool {
  22. return IsOrganizationOwner(org.Id, uid)
  23. }
  24. // IsOrgMember returns true if given user is member of organization.
  25. func (org *User) IsOrgMember(uid int64) bool {
  26. return IsOrganizationMember(org.Id, uid)
  27. }
  28. // GetTeam returns named team of organization.
  29. func (org *User) GetTeam(name string) (*Team, error) {
  30. return GetTeam(org.Id, name)
  31. }
  32. // GetOwnerTeam returns owner team of organization.
  33. func (org *User) GetOwnerTeam() (*Team, error) {
  34. return org.GetTeam(OWNER_TEAM)
  35. }
  36. // GetTeams returns all teams that belong to organization.
  37. func (org *User) GetTeams() error {
  38. return x.Where("org_id=?", org.Id).Find(&org.Teams)
  39. }
  40. // GetMembers returns all members of organization.
  41. func (org *User) GetMembers() error {
  42. ous, err := GetOrgUsersByOrgId(org.Id)
  43. if err != nil {
  44. return err
  45. }
  46. org.Members = make([]*User, len(ous))
  47. for i, ou := range ous {
  48. org.Members[i], err = GetUserById(ou.Uid)
  49. if err != nil {
  50. return err
  51. }
  52. }
  53. return nil
  54. }
  55. // AddMember adds new member to organization.
  56. func (org *User) AddMember(uid int64) error {
  57. return AddOrgUser(org.Id, uid)
  58. }
  59. // RemoveMember removes member from organization.
  60. func (org *User) RemoveMember(uid int64) error {
  61. return RemoveOrgUser(org.Id, uid)
  62. }
  63. // CreateOrganization creates record of a new organization.
  64. func CreateOrganization(org, owner *User) (*User, error) {
  65. if !IsLegalName(org.Name) {
  66. return nil, ErrUserNameIllegal
  67. }
  68. isExist, err := IsUserExist(org.Name)
  69. if err != nil {
  70. return nil, err
  71. } else if isExist {
  72. return nil, ErrUserAlreadyExist
  73. }
  74. isExist, err = IsEmailUsed(org.Email)
  75. if err != nil {
  76. return nil, err
  77. } else if isExist {
  78. return nil, ErrEmailAlreadyUsed
  79. }
  80. org.LowerName = strings.ToLower(org.Name)
  81. org.FullName = org.Name
  82. org.Avatar = base.EncodeMd5(org.Email)
  83. org.AvatarEmail = org.Email
  84. // No password for organization.
  85. org.NumTeams = 1
  86. org.NumMembers = 1
  87. sess := x.NewSession()
  88. defer sess.Close()
  89. if err = sess.Begin(); err != nil {
  90. return nil, err
  91. }
  92. if _, err = sess.Insert(org); err != nil {
  93. sess.Rollback()
  94. return nil, err
  95. }
  96. if err = os.MkdirAll(UserPath(org.Name), os.ModePerm); err != nil {
  97. sess.Rollback()
  98. return nil, err
  99. }
  100. // Create default owner team.
  101. t := &Team{
  102. OrgId: org.Id,
  103. LowerName: strings.ToLower(OWNER_TEAM),
  104. Name: OWNER_TEAM,
  105. Authorize: ORG_ADMIN,
  106. NumMembers: 1,
  107. }
  108. if _, err = sess.Insert(t); err != nil {
  109. sess.Rollback()
  110. return nil, err
  111. }
  112. // Add initial creator to organization and owner team.
  113. ou := &OrgUser{
  114. Uid: owner.Id,
  115. OrgId: org.Id,
  116. IsOwner: true,
  117. NumTeam: 1,
  118. }
  119. if _, err = sess.Insert(ou); err != nil {
  120. sess.Rollback()
  121. return nil, err
  122. }
  123. tu := &TeamUser{
  124. Uid: owner.Id,
  125. OrgId: org.Id,
  126. TeamId: t.Id,
  127. }
  128. if _, err = sess.Insert(tu); err != nil {
  129. sess.Rollback()
  130. return nil, err
  131. }
  132. return org, sess.Commit()
  133. }
  134. // TODO: need some kind of mechanism to record failure.
  135. // DeleteOrganization completely and permanently deletes everything of organization.
  136. func DeleteOrganization(org *User) (err error) {
  137. if err := DeleteUser(org); err != nil {
  138. return err
  139. }
  140. sess := x.NewSession()
  141. defer sess.Close()
  142. if err = sess.Begin(); err != nil {
  143. return err
  144. }
  145. if _, err = sess.Delete(&Team{OrgId: org.Id}); err != nil {
  146. sess.Rollback()
  147. return err
  148. }
  149. if _, err = sess.Delete(&OrgUser{OrgId: org.Id}); err != nil {
  150. sess.Rollback()
  151. return err
  152. }
  153. if _, err = sess.Delete(&TeamUser{OrgId: org.Id}); err != nil {
  154. sess.Rollback()
  155. return err
  156. }
  157. return sess.Commit()
  158. }
  159. // ________ ____ ___
  160. // \_____ \_______ ____ | | \______ ___________
  161. // / | \_ __ \/ ___\| | / ___// __ \_ __ \
  162. // / | \ | \/ /_/ > | /\___ \\ ___/| | \/
  163. // \_______ /__| \___ /|______//____ >\___ >__|
  164. // \/ /_____/ \/ \/
  165. // OrgUser represents an organization-user relation.
  166. type OrgUser struct {
  167. Id int64
  168. Uid int64 `xorm:"INDEX UNIQUE(s)"`
  169. OrgId int64 `xorm:"INDEX UNIQUE(s)"`
  170. IsPublic bool
  171. IsOwner bool
  172. NumTeam int
  173. }
  174. // IsOrganizationOwner returns true if given user is in the owner team.
  175. func IsOrganizationOwner(orgId, uid int64) bool {
  176. has, _ := x.Where("is_owner=?", true).And("uid=?", uid).And("org_id=?", orgId).Get(new(OrgUser))
  177. return has
  178. }
  179. // IsOrganizationMember returns true if given user is member of organization.
  180. func IsOrganizationMember(orgId, uid int64) bool {
  181. has, _ := x.Where("uid=?", uid).And("org_id=?", orgId).Get(new(OrgUser))
  182. return has
  183. }
  184. // IsPublicMembership returns ture if given user public his/her membership.
  185. func IsPublicMembership(orgId, uid int64) bool {
  186. has, _ := x.Where("uid=?", uid).And("org_id=?", orgId).And("is_public=?", true).Get(new(OrgUser))
  187. return has
  188. }
  189. // GetOrgUsersByUserId returns all organization-user relations by user ID.
  190. func GetOrgUsersByUserId(uid int64) ([]*OrgUser, error) {
  191. ous := make([]*OrgUser, 0, 10)
  192. err := x.Where("uid=?", uid).Find(&ous)
  193. return ous, err
  194. }
  195. // GetOrgUsersByOrgId returns all organization-user relations by organization ID.
  196. func GetOrgUsersByOrgId(orgId int64) ([]*OrgUser, error) {
  197. ous := make([]*OrgUser, 0, 10)
  198. err := x.Where("org_id=?", orgId).Find(&ous)
  199. return ous, err
  200. }
  201. // ChangeOrgUserStatus changes public or private membership status.
  202. func ChangeOrgUserStatus(orgId, uid int64, public bool) error {
  203. ou := new(OrgUser)
  204. has, err := x.Where("uid=?", uid).And("org_id=?", orgId).Get(ou)
  205. if err != nil {
  206. return err
  207. } else if !has {
  208. return nil
  209. }
  210. ou.IsPublic = public
  211. _, err = x.Id(ou.Id).AllCols().Update(ou)
  212. return err
  213. }
  214. // AddOrgUser adds new user to given organization.
  215. func AddOrgUser(orgId, uid int64) error {
  216. if IsOrganizationMember(orgId, uid) {
  217. return nil
  218. }
  219. ou := &OrgUser{
  220. Uid: uid,
  221. OrgId: orgId,
  222. }
  223. sess := x.NewSession()
  224. defer sess.Close()
  225. if err := sess.Begin(); err != nil {
  226. return err
  227. }
  228. if _, err := sess.Insert(ou); err != nil {
  229. sess.Rollback()
  230. return err
  231. } else if _, err = sess.Exec("UPDATE `user` SET num_members = num_members + 1 WHERE id = ?", orgId); err != nil {
  232. sess.Rollback()
  233. return err
  234. }
  235. return sess.Commit()
  236. }
  237. // RemoveOrgUser removes user from given organization.
  238. func RemoveOrgUser(orgId, uid int64) error {
  239. ou := new(OrgUser)
  240. has, err := x.Where("uid=?", uid).And("org_id=?", orgId).Get(ou)
  241. if err != nil {
  242. return err
  243. } else if !has {
  244. return nil
  245. }
  246. // Check if the user to delete is the last member in owner team.
  247. if IsOrganizationOwner(orgId, uid) {
  248. org, err := GetUserById(orgId)
  249. if err != nil {
  250. return err
  251. }
  252. t, err := org.GetOwnerTeam()
  253. if err != nil {
  254. return err
  255. }
  256. if t.NumMembers == 1 {
  257. return ErrLastOrgOwner
  258. }
  259. }
  260. sess := x.NewSession()
  261. defer sess.Close()
  262. if err := sess.Begin(); err != nil {
  263. return err
  264. }
  265. if _, err := sess.Id(ou.Id).Delete(ou); err != nil {
  266. sess.Rollback()
  267. return err
  268. } else if _, err = sess.Exec("UPDATE `user` SET num_members = num_members - 1 WHERE id = ?", orgId); err != nil {
  269. sess.Rollback()
  270. return err
  271. }
  272. return sess.Commit()
  273. }
  274. // ___________
  275. // \__ ___/___ _____ _____
  276. // | |_/ __ \\__ \ / \
  277. // | |\ ___/ / __ \| Y Y \
  278. // |____| \___ >____ /__|_| /
  279. // \/ \/ \/
  280. type AuthorizeType int
  281. const (
  282. ORG_READABLE AuthorizeType = iota + 1
  283. ORG_WRITABLE
  284. ORG_ADMIN
  285. )
  286. const OWNER_TEAM = "Owners"
  287. // Team represents a organization team.
  288. type Team struct {
  289. Id int64
  290. OrgId int64 `xorm:"INDEX"`
  291. LowerName string
  292. Name string
  293. Description string
  294. Authorize AuthorizeType
  295. RepoIds string `xorm:"TEXT"`
  296. Repos []*Repository `xorm:"-"`
  297. Members []*User `xorm:"-"`
  298. NumRepos int
  299. NumMembers int
  300. }
  301. // IsTeamMember returns true if given user is a member of team.
  302. func (t *Team) IsMember(uid int64) bool {
  303. return IsTeamMember(t.OrgId, t.Id, uid)
  304. }
  305. // GetRepositories returns all repositories in team of organization.
  306. func (t *Team) GetRepositories() error {
  307. idStrs := strings.Split(t.RepoIds, "|")
  308. t.Repos = make([]*Repository, 0, len(idStrs))
  309. for _, str := range idStrs {
  310. id := com.StrTo(str).MustInt64()
  311. if id == 0 {
  312. continue
  313. }
  314. repo, err := GetRepositoryById(id)
  315. if err != nil {
  316. return err
  317. }
  318. t.Repos = append(t.Repos, repo)
  319. }
  320. return nil
  321. }
  322. // GetMembers returns all members in team of organization.
  323. func (t *Team) GetMembers() (err error) {
  324. t.Members, err = GetTeamMembers(t.OrgId, t.Id)
  325. return err
  326. }
  327. // AddMember adds new member to team of organization.
  328. func (t *Team) AddMember(uid int64) error {
  329. return AddTeamMember(t.OrgId, t.Id, uid)
  330. }
  331. // RemoveMember removes member from team of organization.
  332. func (t *Team) RemoveMember(uid int64) error {
  333. return RemoveTeamMember(t.OrgId, t.Id, uid)
  334. }
  335. // NewTeam creates a record of new team.
  336. // It's caller's responsibility to assign organization ID.
  337. func NewTeam(t *Team) error {
  338. if !IsLegalName(t.Name) {
  339. return ErrTeamNameIllegal
  340. }
  341. has, err := x.Id(t.OrgId).Get(new(User))
  342. if err != nil {
  343. return err
  344. } else if !has {
  345. return ErrOrgNotExist
  346. }
  347. t.LowerName = strings.ToLower(t.Name)
  348. has, err = x.Where("org_id=?", t.OrgId).And("lower_name=?", t.LowerName).Get(new(Team))
  349. if err != nil {
  350. return err
  351. } else if has {
  352. return ErrTeamAlreadyExist
  353. }
  354. sess := x.NewSession()
  355. defer sess.Close()
  356. if err = sess.Begin(); err != nil {
  357. return err
  358. }
  359. if _, err = sess.Insert(t); err != nil {
  360. sess.Rollback()
  361. return err
  362. }
  363. // Update organization number of teams.
  364. if _, err = sess.Exec("UPDATE `user` SET num_teams = num_teams + 1 WHERE id = ?", t.OrgId); err != nil {
  365. sess.Rollback()
  366. return err
  367. }
  368. return sess.Commit()
  369. }
  370. // GetTeam returns team by given team name and organization.
  371. func GetTeam(orgId int64, name string) (*Team, error) {
  372. t := &Team{
  373. OrgId: orgId,
  374. LowerName: strings.ToLower(name),
  375. }
  376. has, err := x.Get(t)
  377. if err != nil {
  378. return nil, err
  379. } else if !has {
  380. return nil, ErrTeamNotExist
  381. }
  382. return t, nil
  383. }
  384. // GetTeamById returns team by given ID.
  385. func GetTeamById(teamId int64) (*Team, error) {
  386. t := new(Team)
  387. has, err := x.Id(teamId).Get(t)
  388. if err != nil {
  389. return nil, err
  390. } else if !has {
  391. return nil, ErrTeamNotExist
  392. }
  393. return t, nil
  394. }
  395. // UpdateTeam updates information of team.
  396. func UpdateTeam(t *Team) error {
  397. if len(t.Description) > 255 {
  398. t.Description = t.Description[:255]
  399. }
  400. t.LowerName = strings.ToLower(t.Name)
  401. _, err := x.Id(t.Id).AllCols().Update(t)
  402. return err
  403. }
  404. // ___________ ____ ___
  405. // \__ ___/___ _____ _____ | | \______ ___________
  406. // | |_/ __ \\__ \ / \| | / ___// __ \_ __ \
  407. // | |\ ___/ / __ \| Y Y \ | /\___ \\ ___/| | \/
  408. // |____| \___ >____ /__|_| /______//____ >\___ >__|
  409. // \/ \/ \/ \/ \/
  410. // TeamUser represents an team-user relation.
  411. type TeamUser struct {
  412. Id int64
  413. Uid int64
  414. OrgId int64 `xorm:"INDEX"`
  415. TeamId int64
  416. }
  417. // IsTeamMember returns true if given user is a member of team.
  418. func IsTeamMember(orgId, teamId, uid int64) bool {
  419. has, _ := x.Where("uid=?", uid).And("org_id=?", orgId).And("team_id=?", teamId).Get(new(TeamUser))
  420. return has
  421. }
  422. // GetTeamMembers returns all members in given team of organization.
  423. func GetTeamMembers(orgId, teamId int64) ([]*User, error) {
  424. tus := make([]*TeamUser, 0, 10)
  425. err := x.Where("org_id=?", orgId).And("team_id=?", teamId).Find(&tus)
  426. if err != nil {
  427. return nil, err
  428. }
  429. us := make([]*User, len(tus))
  430. for i, tu := range tus {
  431. us[i], err = GetUserById(tu.Uid)
  432. if err != nil {
  433. return nil, err
  434. }
  435. }
  436. return us, nil
  437. }
  438. // AddTeamMember adds new member to given team of given organization.
  439. func AddTeamMember(orgId, teamId, uid int64) error {
  440. if !IsOrganizationMember(orgId, uid) || IsTeamMember(orgId, teamId, uid) {
  441. return nil
  442. }
  443. // Get team and its repositories.
  444. t, err := GetTeamById(teamId)
  445. if err != nil {
  446. return err
  447. }
  448. t.NumMembers++
  449. if err = t.GetRepositories(); err != nil {
  450. return err
  451. }
  452. // Get organization.
  453. org, err := GetUserById(orgId)
  454. if err != nil {
  455. return err
  456. }
  457. // Get user.
  458. u, err := GetUserById(uid)
  459. if err != nil {
  460. return err
  461. }
  462. sess := x.NewSession()
  463. defer sess.Close()
  464. if err = sess.Begin(); err != nil {
  465. return err
  466. }
  467. tu := &TeamUser{
  468. Uid: uid,
  469. OrgId: orgId,
  470. TeamId: teamId,
  471. }
  472. mode := READABLE
  473. if t.Authorize > ORG_READABLE {
  474. mode = WRITABLE
  475. }
  476. access := &Access{
  477. UserName: u.LowerName,
  478. Mode: mode,
  479. }
  480. if _, err = sess.Insert(tu); err != nil {
  481. sess.Rollback()
  482. return err
  483. } else if _, err = sess.Id(t.Id).Update(t); err != nil {
  484. sess.Rollback()
  485. return err
  486. }
  487. // Give access to team repositories.
  488. for _, repo := range t.Repos {
  489. access.RepoName = path.Join(org.LowerName, repo.LowerName)
  490. if _, err = sess.Insert(access); err != nil {
  491. sess.Rollback()
  492. return err
  493. }
  494. }
  495. return sess.Commit()
  496. }
  497. // RemoveTeamMember removes member from given team of given organization.
  498. func RemoveTeamMember(orgId, teamId, uid int64) error {
  499. if !IsTeamMember(orgId, teamId, uid) {
  500. return nil
  501. }
  502. // Get team and its repositories.
  503. t, err := GetTeamById(teamId)
  504. if err != nil {
  505. return err
  506. }
  507. t.NumMembers--
  508. if err = t.GetRepositories(); err != nil {
  509. return err
  510. }
  511. // Get organization.
  512. org, err := GetUserById(orgId)
  513. if err != nil {
  514. return err
  515. }
  516. // Get user.
  517. u, err := GetUserById(uid)
  518. if err != nil {
  519. return err
  520. }
  521. sess := x.NewSession()
  522. defer sess.Close()
  523. if err := sess.Begin(); err != nil {
  524. return err
  525. }
  526. tu := &TeamUser{
  527. Uid: uid,
  528. OrgId: orgId,
  529. TeamId: teamId,
  530. }
  531. access := &Access{
  532. UserName: u.LowerName,
  533. }
  534. if _, err := sess.Delete(tu); err != nil {
  535. sess.Rollback()
  536. return err
  537. } else if _, err = sess.Id(t.Id).AllCols().Update(t); err != nil {
  538. sess.Rollback()
  539. return err
  540. }
  541. // Delete access to team repositories.
  542. for _, repo := range t.Repos {
  543. access.RepoName = path.Join(org.LowerName, repo.LowerName)
  544. if _, err = sess.Delete(access); err != nil {
  545. sess.Rollback()
  546. return err
  547. }
  548. }
  549. return sess.Commit()
  550. }