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.

793 lines
20 KiB

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