org.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  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/go-xorm/xorm"
  11. "github.com/gogits/gogs/modules/base"
  12. "github.com/gogits/gogs/modules/log"
  13. )
  14. var (
  15. ErrOrgNotExist = errors.New("Organization does not exist")
  16. ErrTeamNotExist = errors.New("Team does not exist")
  17. )
  18. // IsOwnedBy returns true if given user is in the owner team.
  19. func (org *User) IsOwnedBy(uid int64) bool {
  20. return IsOrganizationOwner(org.ID, uid)
  21. }
  22. // IsOrgMember returns true if given user is member of organization.
  23. func (org *User) IsOrgMember(uid int64) bool {
  24. return org.IsOrganization() && IsOrganizationMember(org.ID, uid)
  25. }
  26. func (org *User) getTeam(e Engine, name string) (*Team, error) {
  27. return getTeam(e, org.ID, name)
  28. }
  29. // GetTeam returns named team of organization.
  30. func (org *User) GetTeam(name string) (*Team, error) {
  31. return org.getTeam(x, name)
  32. }
  33. func (org *User) getOwnerTeam(e Engine) (*Team, error) {
  34. return org.getTeam(e, OWNER_TEAM)
  35. }
  36. // GetOwnerTeam returns owner team of organization.
  37. func (org *User) GetOwnerTeam() (*Team, error) {
  38. return org.getOwnerTeam(x)
  39. }
  40. func (org *User) getTeams(e Engine) error {
  41. return e.Where("org_id=?", org.ID).Find(&org.Teams)
  42. }
  43. // GetTeams returns all teams that belong to organization.
  44. func (org *User) GetTeams() error {
  45. return org.getTeams(x)
  46. }
  47. // GetMembers returns all members of organization.
  48. func (org *User) GetMembers() error {
  49. ous, err := GetOrgUsersByOrgID(org.ID)
  50. if err != nil {
  51. return err
  52. }
  53. org.Members = make([]*User, len(ous))
  54. for i, ou := range ous {
  55. org.Members[i], err = GetUserByID(ou.Uid)
  56. if err != nil {
  57. return err
  58. }
  59. }
  60. return nil
  61. }
  62. // AddMember adds new member to organization.
  63. func (org *User) AddMember(uid int64) error {
  64. return AddOrgUser(org.ID, uid)
  65. }
  66. // RemoveMember removes member from organization.
  67. func (org *User) RemoveMember(uid int64) error {
  68. return RemoveOrgUser(org.ID, uid)
  69. }
  70. func (org *User) removeOrgRepo(e Engine, repoID int64) error {
  71. return removeOrgRepo(e, org.ID, repoID)
  72. }
  73. // RemoveOrgRepo removes all team-repository relations of organization.
  74. func (org *User) RemoveOrgRepo(repoID int64) error {
  75. return org.removeOrgRepo(x, repoID)
  76. }
  77. // CreateOrganization creates record of a new organization.
  78. func CreateOrganization(org, owner *User) (err error) {
  79. if err = IsUsableUsername(org.Name); err != nil {
  80. return err
  81. }
  82. isExist, err := IsUserExist(0, org.Name)
  83. if err != nil {
  84. return err
  85. } else if isExist {
  86. return ErrUserAlreadyExist{org.Name}
  87. }
  88. org.LowerName = strings.ToLower(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: USER_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, showAll bool) ([]*User, error) {
  216. orgs := make([]*User, 0, 10)
  217. if !showAll {
  218. sess.And("`org_user`.is_public=?", true)
  219. }
  220. return orgs, sess.And("`org_user`.uid=?", userID).
  221. Join("INNER", "`org_user`", "`org_user`.org_id=`user`.id").Find(&orgs)
  222. }
  223. // GetOrgsByUserID returns a list of organizations that the given user ID
  224. // has joined.
  225. func GetOrgsByUserID(userID int64, showAll bool) ([]*User, error) {
  226. return getOrgsByUserID(x.NewSession(), userID, showAll)
  227. }
  228. // GetOrgsByUserIDDesc returns a list of organizations that the given user ID
  229. // has joined, ordered descending by the given condition.
  230. func GetOrgsByUserIDDesc(userID int64, desc string, showAll bool) ([]*User, error) {
  231. return getOrgsByUserID(x.NewSession().Desc(desc), userID, showAll)
  232. }
  233. func getOwnedOrgsByUserID(sess *xorm.Session, userID int64) ([]*User, error) {
  234. orgs := make([]*User, 0, 10)
  235. return orgs, sess.Where("`org_user`.uid=?", userID).And("`org_user`.is_owner=?", true).
  236. Join("INNER", "`org_user`", "`org_user`.org_id=`user`.id").Find(&orgs)
  237. }
  238. // GetOwnedOrgsByUserID returns a list of organizations are owned by given user ID.
  239. func GetOwnedOrgsByUserID(userID int64) ([]*User, error) {
  240. sess := x.NewSession()
  241. return getOwnedOrgsByUserID(sess, userID)
  242. }
  243. // GetOwnedOrganizationsByUserIDDesc returns a list of organizations are owned by
  244. // given user ID, ordered descending by the given condition.
  245. func GetOwnedOrgsByUserIDDesc(userID int64, desc string) ([]*User, error) {
  246. sess := x.NewSession()
  247. return getOwnedOrgsByUserID(sess.Desc(desc), userID)
  248. }
  249. // GetOrgUsersByUserID returns all organization-user relations by user ID.
  250. func GetOrgUsersByUserID(uid int64, all bool) ([]*OrgUser, error) {
  251. ous := make([]*OrgUser, 0, 10)
  252. sess := x.Where("uid=?", uid)
  253. if !all {
  254. // Only show public organizations
  255. sess.And("is_public=?", true)
  256. }
  257. err := sess.Find(&ous)
  258. return ous, err
  259. }
  260. // GetOrgUsersByOrgID returns all organization-user relations by organization ID.
  261. func GetOrgUsersByOrgID(orgID int64) ([]*OrgUser, error) {
  262. ous := make([]*OrgUser, 0, 10)
  263. err := x.Where("org_id=?", orgID).Find(&ous)
  264. return ous, err
  265. }
  266. // ChangeOrgUserStatus changes public or private membership status.
  267. func ChangeOrgUserStatus(orgID, uid int64, public bool) error {
  268. ou := new(OrgUser)
  269. has, err := x.Where("uid=?", uid).And("org_id=?", orgID).Get(ou)
  270. if err != nil {
  271. return err
  272. } else if !has {
  273. return nil
  274. }
  275. ou.IsPublic = public
  276. _, err = x.Id(ou.ID).AllCols().Update(ou)
  277. return err
  278. }
  279. // AddOrgUser adds new user to given organization.
  280. func AddOrgUser(orgID, uid int64) error {
  281. if IsOrganizationMember(orgID, uid) {
  282. return nil
  283. }
  284. sess := x.NewSession()
  285. defer sess.Close()
  286. if err := sess.Begin(); err != nil {
  287. return err
  288. }
  289. ou := &OrgUser{
  290. Uid: uid,
  291. OrgID: orgID,
  292. }
  293. if _, err := sess.Insert(ou); err != nil {
  294. sess.Rollback()
  295. return err
  296. } else if _, err = sess.Exec("UPDATE `user` SET num_members = num_members + 1 WHERE id = ?", orgID); err != nil {
  297. sess.Rollback()
  298. return err
  299. }
  300. return sess.Commit()
  301. }
  302. // RemoveOrgUser removes user from given organization.
  303. func RemoveOrgUser(orgID, userID int64) error {
  304. ou := new(OrgUser)
  305. has, err := x.Where("uid=?", userID).And("org_id=?", orgID).Get(ou)
  306. if err != nil {
  307. return fmt.Errorf("get org-user: %v", err)
  308. } else if !has {
  309. return nil
  310. }
  311. user, err := GetUserByID(userID)
  312. if err != nil {
  313. return fmt.Errorf("GetUserByID [%d]: %v", userID, err)
  314. }
  315. org, err := GetUserByID(orgID)
  316. if err != nil {
  317. return fmt.Errorf("GetUserByID [%d]: %v", orgID, err)
  318. }
  319. // FIXME: only need to get IDs here, not all fields of repository.
  320. repos, _, err := org.GetUserRepositories(user.ID, 1, org.NumRepos)
  321. if err != nil {
  322. return fmt.Errorf("GetUserRepositories [%d]: %v", user.ID, err)
  323. }
  324. // Check if the user to delete is the last member in owner team.
  325. if IsOrganizationOwner(orgID, userID) {
  326. t, err := org.GetOwnerTeam()
  327. if err != nil {
  328. return err
  329. }
  330. if t.NumMembers == 1 {
  331. return ErrLastOrgOwner{UID: userID}
  332. }
  333. }
  334. sess := x.NewSession()
  335. defer sessionRelease(sess)
  336. if err := sess.Begin(); err != nil {
  337. return err
  338. }
  339. if _, err := sess.Id(ou.ID).Delete(ou); err != nil {
  340. return err
  341. } else if _, err = sess.Exec("UPDATE `user` SET num_members=num_members-1 WHERE id=?", orgID); err != nil {
  342. return err
  343. }
  344. // Delete all repository accesses and unwatch them.
  345. repoIDs := make([]int64, len(repos))
  346. for i := range repos {
  347. repoIDs = append(repoIDs, repos[i].ID)
  348. if err = watchRepo(sess, user.ID, repos[i].ID, false); err != nil {
  349. return err
  350. }
  351. }
  352. if _, err = sess.Where("user_id = ?", user.ID).In("repo_id", repoIDs).Delete(new(Access)); err != nil {
  353. return err
  354. }
  355. // Delete member in his/her teams.
  356. teams, err := getUserTeams(sess, org.ID, user.ID)
  357. if err != nil {
  358. return err
  359. }
  360. for _, t := range teams {
  361. if err = removeTeamMember(sess, org.ID, t.ID, user.ID); err != nil {
  362. return err
  363. }
  364. }
  365. return sess.Commit()
  366. }
  367. func removeOrgRepo(e Engine, orgID, repoID int64) error {
  368. _, err := e.Delete(&TeamRepo{
  369. OrgID: orgID,
  370. RepoID: repoID,
  371. })
  372. return err
  373. }
  374. // RemoveOrgRepo removes all team-repository relations of given organization.
  375. func RemoveOrgRepo(orgID, repoID int64) error {
  376. return removeOrgRepo(x, orgID, repoID)
  377. }
  378. func (org *User) getUserTeams(e Engine, userID int64, cols ...string) ([]*Team, error) {
  379. teams := make([]*Team, 0, org.NumTeams)
  380. return teams, e.Where("team_user.org_id = ?", org.ID).
  381. And("team_user.uid = ?", userID).
  382. Join("INNER", "team_user", "team_user.team_id = team.id").
  383. Cols(cols...).Find(&teams)
  384. }
  385. // GetUserTeamIDs returns of all team IDs of the organization that user is memeber of.
  386. func (org *User) GetUserTeamIDs(userID int64) ([]int64, error) {
  387. teams, err := org.getUserTeams(x, userID, "team.id")
  388. if err != nil {
  389. return nil, fmt.Errorf("getUserTeams [%d]: %v", userID, err)
  390. }
  391. teamIDs := make([]int64, len(teams))
  392. for i := range teams {
  393. teamIDs[i] = teams[i].ID
  394. }
  395. return teamIDs, nil
  396. }
  397. // GetTeams returns all teams that belong to organization,
  398. // and that the user has joined.
  399. func (org *User) GetUserTeams(userID int64) ([]*Team, error) {
  400. return org.getUserTeams(x, userID)
  401. }
  402. // GetUserRepositories returns a range of repositories in organization
  403. // that the user with the given userID has access to,
  404. // and total number of records based on given condition.
  405. func (org *User) GetUserRepositories(userID int64, page, pageSize int) ([]*Repository, int64, error) {
  406. teamIDs, err := org.GetUserTeamIDs(userID)
  407. if err != nil {
  408. return nil, 0, fmt.Errorf("GetUserTeamIDs: %v", err)
  409. }
  410. if len(teamIDs) == 0 {
  411. // user has no team but "IN ()" is invalid SQL
  412. teamIDs = []int64{-1} // there is no repo with id=-1
  413. }
  414. if page <= 0 {
  415. page = 1
  416. }
  417. repos := make([]*Repository, 0, pageSize)
  418. // FIXME: use XORM chain operations instead of raw SQL.
  419. if err = x.Sql(fmt.Sprintf(`SELECT repository.* FROM repository
  420. INNER JOIN team_repo
  421. ON team_repo.repo_id = repository.id
  422. WHERE (repository.owner_id = ? AND repository.is_private = ?) OR team_repo.team_id IN (%s)
  423. GROUP BY repository.id
  424. ORDER BY updated_unix DESC
  425. LIMIT %d OFFSET %d`,
  426. strings.Join(base.Int64sToStrings(teamIDs), ","), pageSize, (page-1)*pageSize),
  427. org.ID, false).Find(&repos); err != nil {
  428. return nil, 0, fmt.Errorf("get repositories: %v", err)
  429. }
  430. results, err := x.Query(fmt.Sprintf(`SELECT repository.id FROM repository
  431. INNER JOIN team_repo
  432. ON team_repo.repo_id = repository.id
  433. WHERE (repository.owner_id = ? AND repository.is_private = ?) OR team_repo.team_id IN (%s)
  434. GROUP BY repository.id
  435. ORDER BY updated_unix DESC`,
  436. strings.Join(base.Int64sToStrings(teamIDs), ",")),
  437. org.ID, false)
  438. if err != nil {
  439. log.Error(4, "count user repositories in organization: %v", err)
  440. }
  441. return repos, int64(len(results)), nil
  442. }
  443. // GetUserRepositories returns mirror repositories of the organization
  444. // that the user with the given userID has access to.
  445. func (org *User) GetUserMirrorRepositories(userID int64) ([]*Repository, error) {
  446. teamIDs, err := org.GetUserTeamIDs(userID)
  447. if err != nil {
  448. return nil, fmt.Errorf("GetUserTeamIDs: %v", err)
  449. }
  450. if len(teamIDs) == 0 {
  451. teamIDs = []int64{-1}
  452. }
  453. repos := make([]*Repository, 0, 10)
  454. if err = x.Sql(fmt.Sprintf(`SELECT repository.* FROM repository
  455. INNER JOIN team_repo
  456. ON team_repo.repo_id = repository.id AND repository.is_mirror = ?
  457. WHERE (repository.owner_id = ? AND repository.is_private = ?) OR team_repo.team_id IN (%s)
  458. GROUP BY repository.id
  459. ORDER BY updated_unix DESC`,
  460. strings.Join(base.Int64sToStrings(teamIDs), ",")),
  461. true, org.ID, false).Find(&repos); err != nil {
  462. return nil, fmt.Errorf("get repositories: %v", err)
  463. }
  464. return repos, nil
  465. }