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

org.go 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Copyright 2019 The Gitea Authors. All rights reserved.
  3. // Use of this source code is governed by a MIT-style
  4. // license that can be found in the LICENSE file.
  5. package models
  6. import (
  7. "fmt"
  8. "os"
  9. "strings"
  10. "code.gitea.io/gitea/modules/log"
  11. "code.gitea.io/gitea/modules/setting"
  12. "code.gitea.io/gitea/modules/structs"
  13. "github.com/unknwon/com"
  14. "xorm.io/builder"
  15. "xorm.io/xorm"
  16. )
  17. // IsOwnedBy returns true if given user is in the owner team.
  18. func (org *User) IsOwnedBy(uid int64) (bool, error) {
  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, error) {
  23. return 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, ownerTeamName)
  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.
  41. Where("org_id=?", org.ID).
  42. OrderBy("CASE WHEN name LIKE '" + ownerTeamName + "' THEN '' ELSE name END").
  43. Find(&org.Teams)
  44. }
  45. // GetTeams returns all teams that belong to organization.
  46. func (org *User) GetTeams() error {
  47. return org.getTeams(x)
  48. }
  49. // GetMembers returns all members of organization.
  50. func (org *User) GetMembers() error {
  51. ous, err := GetOrgUsersByOrgID(org.ID)
  52. if err != nil {
  53. return err
  54. }
  55. var ids = make([]int64, len(ous))
  56. var idsIsPublic = make(map[int64]bool, len(ous))
  57. for i, ou := range ous {
  58. ids[i] = ou.UID
  59. idsIsPublic[ou.UID] = ou.IsPublic
  60. }
  61. org.MembersIsPublic = idsIsPublic
  62. org.Members, err = GetUsersByIDs(ids)
  63. return err
  64. }
  65. // AddMember adds new member to organization.
  66. func (org *User) AddMember(uid int64) error {
  67. return AddOrgUser(org.ID, uid)
  68. }
  69. // RemoveMember removes member from organization.
  70. func (org *User) RemoveMember(uid int64) error {
  71. return RemoveOrgUser(org.ID, uid)
  72. }
  73. func (org *User) removeOrgRepo(e Engine, repoID int64) error {
  74. return removeOrgRepo(e, org.ID, repoID)
  75. }
  76. // RemoveOrgRepo removes all team-repository relations of organization.
  77. func (org *User) RemoveOrgRepo(repoID int64) error {
  78. return org.removeOrgRepo(x, repoID)
  79. }
  80. // CreateOrganization creates record of a new organization.
  81. func CreateOrganization(org, owner *User) (err error) {
  82. if !owner.CanCreateOrganization() {
  83. return ErrUserNotAllowedCreateOrg{}
  84. }
  85. if err = IsUsableUsername(org.Name); err != nil {
  86. return err
  87. }
  88. isExist, err := IsUserExist(0, org.Name)
  89. if err != nil {
  90. return err
  91. } else if isExist {
  92. return ErrUserAlreadyExist{org.Name}
  93. }
  94. org.LowerName = strings.ToLower(org.Name)
  95. if org.Rands, err = GetUserSalt(); err != nil {
  96. return err
  97. }
  98. if org.Salt, err = GetUserSalt(); err != nil {
  99. return err
  100. }
  101. org.UseCustomAvatar = true
  102. org.MaxRepoCreation = -1
  103. org.NumTeams = 1
  104. org.NumMembers = 1
  105. org.Type = UserTypeOrganization
  106. sess := x.NewSession()
  107. defer sess.Close()
  108. if err = sess.Begin(); err != nil {
  109. return err
  110. }
  111. if _, err = sess.Insert(org); err != nil {
  112. return fmt.Errorf("insert organization: %v", err)
  113. }
  114. if err = org.generateRandomAvatar(sess); err != nil {
  115. return fmt.Errorf("generate random avatar: %v", err)
  116. }
  117. // Add initial creator to organization and owner team.
  118. if _, err = sess.Insert(&OrgUser{
  119. UID: owner.ID,
  120. OrgID: org.ID,
  121. }); err != nil {
  122. return fmt.Errorf("insert org-user relation: %v", err)
  123. }
  124. // Create default owner team.
  125. t := &Team{
  126. OrgID: org.ID,
  127. LowerName: strings.ToLower(ownerTeamName),
  128. Name: ownerTeamName,
  129. Authorize: AccessModeOwner,
  130. NumMembers: 1,
  131. }
  132. if _, err = sess.Insert(t); err != nil {
  133. return fmt.Errorf("insert owner team: %v", err)
  134. }
  135. // insert units for team
  136. var units = make([]TeamUnit, 0, len(AllRepoUnitTypes))
  137. for _, tp := range AllRepoUnitTypes {
  138. units = append(units, TeamUnit{
  139. OrgID: org.ID,
  140. TeamID: t.ID,
  141. Type: tp,
  142. })
  143. }
  144. if _, err = sess.Insert(&units); err != nil {
  145. if err := sess.Rollback(); err != nil {
  146. log.Error("CreateOrganization: sess.Rollback: %v", err)
  147. }
  148. return err
  149. }
  150. if _, err = sess.Insert(&TeamUser{
  151. UID: owner.ID,
  152. OrgID: org.ID,
  153. TeamID: t.ID,
  154. }); err != nil {
  155. return fmt.Errorf("insert team-user relation: %v", err)
  156. }
  157. return sess.Commit()
  158. }
  159. // GetOrgByName returns organization by given name.
  160. func GetOrgByName(name string) (*User, error) {
  161. if len(name) == 0 {
  162. return nil, ErrOrgNotExist{0, name}
  163. }
  164. u := &User{
  165. LowerName: strings.ToLower(name),
  166. Type: UserTypeOrganization,
  167. }
  168. has, err := x.Get(u)
  169. if err != nil {
  170. return nil, err
  171. } else if !has {
  172. return nil, ErrOrgNotExist{0, name}
  173. }
  174. return u, nil
  175. }
  176. // CountOrganizations returns number of organizations.
  177. func CountOrganizations() int64 {
  178. count, _ := x.
  179. Where("type=1").
  180. Count(new(User))
  181. return count
  182. }
  183. // DeleteOrganization completely and permanently deletes everything of organization.
  184. func DeleteOrganization(org *User) (err error) {
  185. sess := x.NewSession()
  186. defer sess.Close()
  187. if err = sess.Begin(); err != nil {
  188. return err
  189. }
  190. if err = deleteOrg(sess, org); err != nil {
  191. if IsErrUserOwnRepos(err) {
  192. return err
  193. } else if err != nil {
  194. return fmt.Errorf("deleteOrg: %v", err)
  195. }
  196. }
  197. return sess.Commit()
  198. }
  199. func deleteOrg(e *xorm.Session, u *User) error {
  200. if !u.IsOrganization() {
  201. return fmt.Errorf("You can't delete none organization user: %s", u.Name)
  202. }
  203. // Check ownership of repository.
  204. count, err := getRepositoryCount(e, u)
  205. if err != nil {
  206. return fmt.Errorf("GetRepositoryCount: %v", err)
  207. } else if count > 0 {
  208. return ErrUserOwnRepos{UID: u.ID}
  209. }
  210. if err := deleteBeans(e,
  211. &Team{OrgID: u.ID},
  212. &OrgUser{OrgID: u.ID},
  213. &TeamUser{OrgID: u.ID},
  214. &TeamUnit{OrgID: u.ID},
  215. ); err != nil {
  216. return fmt.Errorf("deleteBeans: %v", err)
  217. }
  218. if _, err = e.ID(u.ID).Delete(new(User)); err != nil {
  219. return fmt.Errorf("Delete: %v", err)
  220. }
  221. // FIXME: system notice
  222. // Note: There are something just cannot be roll back,
  223. // so just keep error logs of those operations.
  224. path := UserPath(u.Name)
  225. if err := os.RemoveAll(path); err != nil {
  226. return fmt.Errorf("Failed to RemoveAll %s: %v", path, err)
  227. }
  228. if len(u.Avatar) > 0 {
  229. avatarPath := u.CustomAvatarPath()
  230. if com.IsExist(avatarPath) {
  231. if err := os.Remove(avatarPath); err != nil {
  232. return fmt.Errorf("Failed to remove %s: %v", avatarPath, err)
  233. }
  234. }
  235. }
  236. return nil
  237. }
  238. // ________ ____ ___
  239. // \_____ \_______ ____ | | \______ ___________
  240. // / | \_ __ \/ ___\| | / ___// __ \_ __ \
  241. // / | \ | \/ /_/ > | /\___ \\ ___/| | \/
  242. // \_______ /__| \___ /|______//____ >\___ >__|
  243. // \/ /_____/ \/ \/
  244. // OrgUser represents an organization-user relation.
  245. type OrgUser struct {
  246. ID int64 `xorm:"pk autoincr"`
  247. UID int64 `xorm:"INDEX UNIQUE(s)"`
  248. OrgID int64 `xorm:"INDEX UNIQUE(s)"`
  249. IsPublic bool `xorm:"INDEX"`
  250. }
  251. func isOrganizationOwner(e Engine, orgID, uid int64) (bool, error) {
  252. ownerTeam, err := getOwnerTeam(e, orgID)
  253. if err != nil {
  254. if IsErrTeamNotExist(err) {
  255. log.Error("Organization does not have owner team: %d", orgID)
  256. return false, nil
  257. }
  258. return false, err
  259. }
  260. return isTeamMember(e, orgID, ownerTeam.ID, uid)
  261. }
  262. // IsOrganizationOwner returns true if given user is in the owner team.
  263. func IsOrganizationOwner(orgID, uid int64) (bool, error) {
  264. return isOrganizationOwner(x, orgID, uid)
  265. }
  266. // IsOrganizationMember returns true if given user is member of organization.
  267. func IsOrganizationMember(orgID, uid int64) (bool, error) {
  268. return isOrganizationMember(x, orgID, uid)
  269. }
  270. func isOrganizationMember(e Engine, orgID, uid int64) (bool, error) {
  271. return e.
  272. Where("uid=?", uid).
  273. And("org_id=?", orgID).
  274. Table("org_user").
  275. Exist()
  276. }
  277. // IsPublicMembership returns true if given user public his/her membership.
  278. func IsPublicMembership(orgID, uid int64) (bool, error) {
  279. return x.
  280. Where("uid=?", uid).
  281. And("org_id=?", orgID).
  282. And("is_public=?", true).
  283. Table("org_user").
  284. Exist()
  285. }
  286. func getOrgsByUserID(sess *xorm.Session, userID int64, showAll bool) ([]*User, error) {
  287. orgs := make([]*User, 0, 10)
  288. if !showAll {
  289. sess.And("`org_user`.is_public=?", true)
  290. }
  291. return orgs, sess.
  292. And("`org_user`.uid=?", userID).
  293. Join("INNER", "`org_user`", "`org_user`.org_id=`user`.id").
  294. Asc("`user`.name").
  295. Find(&orgs)
  296. }
  297. // GetOrgsByUserID returns a list of organizations that the given user ID
  298. // has joined.
  299. func GetOrgsByUserID(userID int64, showAll bool) ([]*User, error) {
  300. sess := x.NewSession()
  301. defer sess.Close()
  302. return getOrgsByUserID(sess, userID, showAll)
  303. }
  304. func getOwnedOrgsByUserID(sess *xorm.Session, userID int64) ([]*User, error) {
  305. orgs := make([]*User, 0, 10)
  306. return orgs, sess.
  307. Join("INNER", "`team_user`", "`team_user`.org_id=`user`.id").
  308. Join("INNER", "`team`", "`team`.id=`team_user`.team_id").
  309. Where("`team_user`.uid=?", userID).
  310. And("`team`.authorize=?", AccessModeOwner).
  311. Asc("`user`.name").
  312. Find(&orgs)
  313. }
  314. // HasOrgVisible tells if the given user can see the given org
  315. func HasOrgVisible(org *User, user *User) bool {
  316. return hasOrgVisible(x, org, user)
  317. }
  318. func hasOrgVisible(e Engine, org *User, user *User) bool {
  319. // Not SignedUser
  320. if user == nil {
  321. return org.Visibility == structs.VisibleTypePublic
  322. }
  323. if user.IsAdmin {
  324. return true
  325. }
  326. if org.Visibility == structs.VisibleTypePrivate && !org.isUserPartOfOrg(e, user.ID) {
  327. return false
  328. }
  329. return true
  330. }
  331. // HasOrgsVisible tells if the given user can see at least one of the orgs provided
  332. func HasOrgsVisible(orgs []*User, user *User) bool {
  333. if len(orgs) == 0 {
  334. return false
  335. }
  336. for _, org := range orgs {
  337. if HasOrgVisible(org, user) {
  338. return true
  339. }
  340. }
  341. return false
  342. }
  343. // GetOwnedOrgsByUserID returns a list of organizations are owned by given user ID.
  344. func GetOwnedOrgsByUserID(userID int64) ([]*User, error) {
  345. sess := x.NewSession()
  346. defer sess.Close()
  347. return getOwnedOrgsByUserID(sess, userID)
  348. }
  349. // GetOwnedOrgsByUserIDDesc returns a list of organizations are owned by
  350. // given user ID, ordered descending by the given condition.
  351. func GetOwnedOrgsByUserIDDesc(userID int64, desc string) ([]*User, error) {
  352. return getOwnedOrgsByUserID(x.Desc(desc), userID)
  353. }
  354. // GetOrgUsersByUserID returns all organization-user relations by user ID.
  355. func GetOrgUsersByUserID(uid int64, all bool) ([]*OrgUser, error) {
  356. ous := make([]*OrgUser, 0, 10)
  357. sess := x.
  358. Join("LEFT", "`user`", "`org_user`.org_id=`user`.id").
  359. Where("`org_user`.uid=?", uid)
  360. if !all {
  361. // Only show public organizations
  362. sess.And("is_public=?", true)
  363. }
  364. err := sess.
  365. Asc("`user`.name").
  366. Find(&ous)
  367. return ous, err
  368. }
  369. // GetOrgUsersByOrgID returns all organization-user relations by organization ID.
  370. func GetOrgUsersByOrgID(orgID int64) ([]*OrgUser, error) {
  371. return getOrgUsersByOrgID(x, orgID)
  372. }
  373. func getOrgUsersByOrgID(e Engine, orgID int64) ([]*OrgUser, error) {
  374. ous := make([]*OrgUser, 0, 10)
  375. err := e.
  376. Where("org_id=?", orgID).
  377. Find(&ous)
  378. return ous, err
  379. }
  380. // ChangeOrgUserStatus changes public or private membership status.
  381. func ChangeOrgUserStatus(orgID, uid int64, public bool) error {
  382. ou := new(OrgUser)
  383. has, err := x.
  384. Where("uid=?", uid).
  385. And("org_id=?", orgID).
  386. Get(ou)
  387. if err != nil {
  388. return err
  389. } else if !has {
  390. return nil
  391. }
  392. ou.IsPublic = public
  393. _, err = x.ID(ou.ID).Cols("is_public").Update(ou)
  394. return err
  395. }
  396. // AddOrgUser adds new user to given organization.
  397. func AddOrgUser(orgID, uid int64) error {
  398. isAlreadyMember, err := IsOrganizationMember(orgID, uid)
  399. if err != nil || isAlreadyMember {
  400. return err
  401. }
  402. sess := x.NewSession()
  403. defer sess.Close()
  404. if err := sess.Begin(); err != nil {
  405. return err
  406. }
  407. ou := &OrgUser{
  408. UID: uid,
  409. OrgID: orgID,
  410. IsPublic: setting.Service.DefaultOrgMemberVisible,
  411. }
  412. if _, err := sess.Insert(ou); err != nil {
  413. if err := sess.Rollback(); err != nil {
  414. log.Error("AddOrgUser: sess.Rollback: %v", err)
  415. }
  416. return err
  417. } else if _, err = sess.Exec("UPDATE `user` SET num_members = num_members + 1 WHERE id = ?", orgID); err != nil {
  418. if err := sess.Rollback(); err != nil {
  419. log.Error("AddOrgUser: sess.Rollback: %v", err)
  420. }
  421. return err
  422. }
  423. return sess.Commit()
  424. }
  425. func removeOrgUser(sess *xorm.Session, orgID, userID int64) error {
  426. ou := new(OrgUser)
  427. has, err := sess.
  428. Where("uid=?", userID).
  429. And("org_id=?", orgID).
  430. Get(ou)
  431. if err != nil {
  432. return fmt.Errorf("get org-user: %v", err)
  433. } else if !has {
  434. return nil
  435. }
  436. org, err := getUserByID(sess, orgID)
  437. if err != nil {
  438. return fmt.Errorf("GetUserByID [%d]: %v", orgID, err)
  439. }
  440. // Check if the user to delete is the last member in owner team.
  441. if isOwner, err := isOrganizationOwner(sess, orgID, userID); err != nil {
  442. return err
  443. } else if isOwner {
  444. t, err := org.getOwnerTeam(sess)
  445. if err != nil {
  446. return err
  447. }
  448. if t.NumMembers == 1 {
  449. if err := t.getMembers(sess); err != nil {
  450. return err
  451. }
  452. if t.Members[0].ID == userID {
  453. return ErrLastOrgOwner{UID: userID}
  454. }
  455. }
  456. }
  457. if _, err := sess.ID(ou.ID).Delete(ou); err != nil {
  458. return err
  459. } else if _, err = sess.Exec("UPDATE `user` SET num_members=num_members-1 WHERE id=?", orgID); err != nil {
  460. return err
  461. }
  462. // Delete all repository accesses and unwatch them.
  463. env, err := org.accessibleReposEnv(sess, userID)
  464. if err != nil {
  465. return fmt.Errorf("AccessibleReposEnv: %v", err)
  466. }
  467. repoIDs, err := env.RepoIDs(1, org.NumRepos)
  468. if err != nil {
  469. return fmt.Errorf("GetUserRepositories [%d]: %v", userID, err)
  470. }
  471. for _, repoID := range repoIDs {
  472. if err = watchRepo(sess, userID, repoID, false); err != nil {
  473. return err
  474. }
  475. }
  476. if len(repoIDs) > 0 {
  477. if _, err = sess.
  478. Where("user_id = ?", userID).
  479. In("repo_id", repoIDs).
  480. Delete(new(Access)); err != nil {
  481. return err
  482. }
  483. }
  484. // Delete member in his/her teams.
  485. teams, err := getUserOrgTeams(sess, org.ID, userID)
  486. if err != nil {
  487. return err
  488. }
  489. for _, t := range teams {
  490. if err = removeTeamMember(sess, t, userID); err != nil {
  491. return err
  492. }
  493. }
  494. return nil
  495. }
  496. // RemoveOrgUser removes user from given organization.
  497. func RemoveOrgUser(orgID, userID int64) error {
  498. sess := x.NewSession()
  499. defer sess.Close()
  500. if err := sess.Begin(); err != nil {
  501. return err
  502. }
  503. if err := removeOrgUser(sess, orgID, userID); err != nil {
  504. return err
  505. }
  506. return sess.Commit()
  507. }
  508. func removeOrgRepo(e Engine, orgID, repoID int64) error {
  509. teamRepos := make([]*TeamRepo, 0, 10)
  510. if err := e.Find(&teamRepos, &TeamRepo{OrgID: orgID, RepoID: repoID}); err != nil {
  511. return err
  512. }
  513. if len(teamRepos) == 0 {
  514. return nil
  515. }
  516. if _, err := e.Delete(&TeamRepo{
  517. OrgID: orgID,
  518. RepoID: repoID,
  519. }); err != nil {
  520. return err
  521. }
  522. teamIDs := make([]int64, len(teamRepos))
  523. for i, teamRepo := range teamRepos {
  524. teamIDs[i] = teamRepo.TeamID
  525. }
  526. _, err := e.Decr("num_repos").In("id", teamIDs).Update(new(Team))
  527. return err
  528. }
  529. func (org *User) getUserTeams(e Engine, userID int64, cols ...string) ([]*Team, error) {
  530. teams := make([]*Team, 0, org.NumTeams)
  531. return teams, e.
  532. Where("`team_user`.org_id = ?", org.ID).
  533. Join("INNER", "team_user", "`team_user`.team_id = team.id").
  534. Join("INNER", "`user`", "`user`.id=team_user.uid").
  535. And("`team_user`.uid = ?", userID).
  536. Asc("`user`.name").
  537. Cols(cols...).
  538. Find(&teams)
  539. }
  540. func (org *User) getUserTeamIDs(e Engine, userID int64) ([]int64, error) {
  541. teamIDs := make([]int64, 0, org.NumTeams)
  542. return teamIDs, e.
  543. Table("team").
  544. Cols("team.id").
  545. Where("`team_user`.org_id = ?", org.ID).
  546. Join("INNER", "team_user", "`team_user`.team_id = team.id").
  547. And("`team_user`.uid = ?", userID).
  548. Find(&teamIDs)
  549. }
  550. // TeamsWithAccessToRepo returns all teamsthat have given access level to the repository.
  551. func (org *User) TeamsWithAccessToRepo(repoID int64, mode AccessMode) ([]*Team, error) {
  552. return GetTeamsWithAccessToRepo(org.ID, repoID, mode)
  553. }
  554. // GetUserTeamIDs returns of all team IDs of the organization that user is member of.
  555. func (org *User) GetUserTeamIDs(userID int64) ([]int64, error) {
  556. return org.getUserTeamIDs(x, userID)
  557. }
  558. // GetUserTeams returns all teams that belong to user,
  559. // and that the user has joined.
  560. func (org *User) GetUserTeams(userID int64) ([]*Team, error) {
  561. return org.getUserTeams(x, userID)
  562. }
  563. // AccessibleReposEnvironment operations involving the repositories that are
  564. // accessible to a particular user
  565. type AccessibleReposEnvironment interface {
  566. CountRepos() (int64, error)
  567. RepoIDs(page, pageSize int) ([]int64, error)
  568. Repos(page, pageSize int) ([]*Repository, error)
  569. MirrorRepos() ([]*Repository, error)
  570. AddKeyword(keyword string)
  571. SetSort(SearchOrderBy)
  572. }
  573. type accessibleReposEnv struct {
  574. org *User
  575. userID int64
  576. teamIDs []int64
  577. e Engine
  578. keyword string
  579. orderBy SearchOrderBy
  580. }
  581. // AccessibleReposEnv an AccessibleReposEnvironment for the repositories in `org`
  582. // that are accessible to the specified user.
  583. func (org *User) AccessibleReposEnv(userID int64) (AccessibleReposEnvironment, error) {
  584. return org.accessibleReposEnv(x, userID)
  585. }
  586. func (org *User) accessibleReposEnv(e Engine, userID int64) (AccessibleReposEnvironment, error) {
  587. teamIDs, err := org.getUserTeamIDs(e, userID)
  588. if err != nil {
  589. return nil, err
  590. }
  591. return &accessibleReposEnv{
  592. org: org,
  593. userID: userID,
  594. teamIDs: teamIDs,
  595. e: e,
  596. orderBy: SearchOrderByRecentUpdated,
  597. }, nil
  598. }
  599. func (env *accessibleReposEnv) cond() builder.Cond {
  600. var cond builder.Cond = builder.Eq{
  601. "`repository`.owner_id": env.org.ID,
  602. "`repository`.is_private": false,
  603. }
  604. if len(env.teamIDs) > 0 {
  605. cond = cond.Or(builder.In("team_repo.team_id", env.teamIDs))
  606. }
  607. if env.keyword != "" {
  608. cond = cond.And(builder.Like{"`repository`.lower_name", strings.ToLower(env.keyword)})
  609. }
  610. return cond
  611. }
  612. func (env *accessibleReposEnv) CountRepos() (int64, error) {
  613. repoCount, err := env.e.
  614. Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id").
  615. Where(env.cond()).
  616. Distinct("`repository`.id").
  617. Count(&Repository{})
  618. if err != nil {
  619. return 0, fmt.Errorf("count user repositories in organization: %v", err)
  620. }
  621. return repoCount, nil
  622. }
  623. func (env *accessibleReposEnv) RepoIDs(page, pageSize int) ([]int64, error) {
  624. if page <= 0 {
  625. page = 1
  626. }
  627. repoIDs := make([]int64, 0, pageSize)
  628. return repoIDs, env.e.
  629. Table("repository").
  630. Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id").
  631. Where(env.cond()).
  632. GroupBy("`repository`.id,`repository`."+strings.Fields(string(env.orderBy))[0]).
  633. OrderBy(string(env.orderBy)).
  634. Limit(pageSize, (page-1)*pageSize).
  635. Cols("`repository`.id").
  636. Find(&repoIDs)
  637. }
  638. func (env *accessibleReposEnv) Repos(page, pageSize int) ([]*Repository, error) {
  639. repoIDs, err := env.RepoIDs(page, pageSize)
  640. if err != nil {
  641. return nil, fmt.Errorf("GetUserRepositoryIDs: %v", err)
  642. }
  643. repos := make([]*Repository, 0, len(repoIDs))
  644. if len(repoIDs) == 0 {
  645. return repos, nil
  646. }
  647. return repos, env.e.
  648. In("`repository`.id", repoIDs).
  649. OrderBy(string(env.orderBy)).
  650. Find(&repos)
  651. }
  652. func (env *accessibleReposEnv) MirrorRepoIDs() ([]int64, error) {
  653. repoIDs := make([]int64, 0, 10)
  654. return repoIDs, env.e.
  655. Table("repository").
  656. Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id AND `repository`.is_mirror=?", true).
  657. Where(env.cond()).
  658. GroupBy("`repository`.id, `repository`.updated_unix").
  659. OrderBy(string(env.orderBy)).
  660. Cols("`repository`.id").
  661. Find(&repoIDs)
  662. }
  663. func (env *accessibleReposEnv) MirrorRepos() ([]*Repository, error) {
  664. repoIDs, err := env.MirrorRepoIDs()
  665. if err != nil {
  666. return nil, fmt.Errorf("MirrorRepoIDs: %v", err)
  667. }
  668. repos := make([]*Repository, 0, len(repoIDs))
  669. if len(repoIDs) == 0 {
  670. return repos, nil
  671. }
  672. return repos, env.e.
  673. In("`repository`.id", repoIDs).
  674. Find(&repos)
  675. }
  676. func (env *accessibleReposEnv) AddKeyword(keyword string) {
  677. env.keyword = keyword
  678. }
  679. func (env *accessibleReposEnv) SetSort(orderBy SearchOrderBy) {
  680. env.orderBy = orderBy
  681. }