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.

380 lines
10 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
8 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 routers
  6. import (
  7. "bytes"
  8. "net/url"
  9. "strings"
  10. "code.gitea.io/gitea/models"
  11. "code.gitea.io/gitea/modules/base"
  12. "code.gitea.io/gitea/modules/context"
  13. "code.gitea.io/gitea/modules/log"
  14. "code.gitea.io/gitea/modules/search"
  15. "code.gitea.io/gitea/modules/setting"
  16. "code.gitea.io/gitea/modules/util"
  17. "code.gitea.io/gitea/routers/user"
  18. "github.com/Unknwon/paginater"
  19. )
  20. const (
  21. // tplHome home page template
  22. tplHome base.TplName = "home"
  23. // tplExploreRepos explore repositories page template
  24. tplExploreRepos base.TplName = "explore/repos"
  25. // tplExploreUsers explore users page template
  26. tplExploreUsers base.TplName = "explore/users"
  27. // tplExploreOrganizations explore organizations page template
  28. tplExploreOrganizations base.TplName = "explore/organizations"
  29. // tplExploreCode explore code page template
  30. tplExploreCode base.TplName = "explore/code"
  31. )
  32. // Home render home page
  33. func Home(ctx *context.Context) {
  34. if ctx.IsSigned {
  35. if !ctx.User.IsActive && setting.Service.RegisterEmailConfirm {
  36. ctx.Data["Title"] = ctx.Tr("auth.active_your_account")
  37. ctx.HTML(200, user.TplActivate)
  38. } else if !ctx.User.IsActive || ctx.User.ProhibitLogin {
  39. log.Info("Failed authentication attempt for %s from %s", ctx.User.Name, ctx.RemoteAddr())
  40. ctx.Data["Title"] = ctx.Tr("auth.prohibit_login")
  41. ctx.HTML(200, "user/auth/prohibit_login")
  42. } else if ctx.User.MustChangePassword {
  43. ctx.Data["Title"] = ctx.Tr("auth.must_change_password")
  44. ctx.Data["ChangePasscodeLink"] = setting.AppSubURL + "/user/change_password"
  45. ctx.SetCookie("redirect_to", url.QueryEscape(setting.AppSubURL+ctx.Req.RequestURI), 0, setting.AppSubURL)
  46. ctx.Redirect(setting.AppSubURL + "/user/settings/change_password")
  47. } else {
  48. user.Dashboard(ctx)
  49. }
  50. return
  51. // Check non-logged users landing page.
  52. } else if setting.LandingPageURL != setting.LandingPageHome {
  53. ctx.Redirect(setting.AppSubURL + string(setting.LandingPageURL))
  54. return
  55. }
  56. // Check auto-login.
  57. uname := ctx.GetCookie(setting.CookieUserName)
  58. if len(uname) != 0 {
  59. ctx.Redirect(setting.AppSubURL + "/user/login")
  60. return
  61. }
  62. ctx.Data["PageIsHome"] = true
  63. ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
  64. ctx.HTML(200, tplHome)
  65. }
  66. // RepoSearchOptions when calling search repositories
  67. type RepoSearchOptions struct {
  68. OwnerID int64
  69. Private bool
  70. PageSize int
  71. TplName base.TplName
  72. }
  73. var (
  74. nullByte = []byte{0x00}
  75. )
  76. func isKeywordValid(keyword string) bool {
  77. return !bytes.Contains([]byte(keyword), nullByte)
  78. }
  79. // RenderRepoSearch render repositories search page
  80. func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) {
  81. page := ctx.QueryInt("page")
  82. if page <= 0 {
  83. page = 1
  84. }
  85. var (
  86. repos []*models.Repository
  87. count int64
  88. err error
  89. orderBy models.SearchOrderBy
  90. )
  91. ctx.Data["SortType"] = ctx.Query("sort")
  92. switch ctx.Query("sort") {
  93. case "newest":
  94. orderBy = models.SearchOrderByNewest
  95. case "oldest":
  96. orderBy = models.SearchOrderByOldest
  97. case "recentupdate":
  98. orderBy = models.SearchOrderByRecentUpdated
  99. case "leastupdate":
  100. orderBy = models.SearchOrderByLeastUpdated
  101. case "reversealphabetically":
  102. orderBy = models.SearchOrderByAlphabeticallyReverse
  103. case "alphabetically":
  104. orderBy = models.SearchOrderByAlphabetically
  105. case "reversesize":
  106. orderBy = models.SearchOrderBySizeReverse
  107. case "size":
  108. orderBy = models.SearchOrderBySize
  109. case "moststars":
  110. orderBy = models.SearchOrderByStarsReverse
  111. case "feweststars":
  112. orderBy = models.SearchOrderByStars
  113. case "mostforks":
  114. orderBy = models.SearchOrderByForksReverse
  115. case "fewestforks":
  116. orderBy = models.SearchOrderByForks
  117. default:
  118. ctx.Data["SortType"] = "recentupdate"
  119. orderBy = models.SearchOrderByRecentUpdated
  120. }
  121. keyword := strings.Trim(ctx.Query("q"), " ")
  122. topicOnly := ctx.QueryBool("topic")
  123. repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{
  124. Page: page,
  125. PageSize: opts.PageSize,
  126. OrderBy: orderBy,
  127. Private: opts.Private,
  128. Keyword: keyword,
  129. OwnerID: opts.OwnerID,
  130. AllPublic: true,
  131. TopicOnly: topicOnly,
  132. })
  133. if err != nil {
  134. ctx.ServerError("SearchRepositoryByName", err)
  135. return
  136. }
  137. ctx.Data["Keyword"] = keyword
  138. ctx.Data["Total"] = count
  139. ctx.Data["Page"] = paginater.New(int(count), opts.PageSize, page, 5)
  140. ctx.Data["Repos"] = repos
  141. ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
  142. ctx.HTML(200, opts.TplName)
  143. }
  144. // ExploreRepos render explore repositories page
  145. func ExploreRepos(ctx *context.Context) {
  146. ctx.Data["Title"] = ctx.Tr("explore")
  147. ctx.Data["PageIsExplore"] = true
  148. ctx.Data["PageIsExploreRepositories"] = true
  149. ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
  150. var ownerID int64
  151. if ctx.User != nil && !ctx.User.IsAdmin {
  152. ownerID = ctx.User.ID
  153. }
  154. RenderRepoSearch(ctx, &RepoSearchOptions{
  155. PageSize: setting.UI.ExplorePagingNum,
  156. OwnerID: ownerID,
  157. Private: ctx.User != nil,
  158. TplName: tplExploreRepos,
  159. })
  160. }
  161. // RenderUserSearch render user search page
  162. func RenderUserSearch(ctx *context.Context, opts *models.SearchUserOptions, tplName base.TplName) {
  163. opts.Page = ctx.QueryInt("page")
  164. if opts.Page <= 1 {
  165. opts.Page = 1
  166. }
  167. var (
  168. users []*models.User
  169. count int64
  170. err error
  171. orderBy models.SearchOrderBy
  172. )
  173. ctx.Data["SortType"] = ctx.Query("sort")
  174. switch ctx.Query("sort") {
  175. case "newest":
  176. orderBy = models.SearchOrderByIDReverse
  177. case "oldest":
  178. orderBy = models.SearchOrderByID
  179. case "recentupdate":
  180. orderBy = models.SearchOrderByRecentUpdated
  181. case "leastupdate":
  182. orderBy = models.SearchOrderByLeastUpdated
  183. case "reversealphabetically":
  184. orderBy = models.SearchOrderByAlphabeticallyReverse
  185. case "alphabetically":
  186. orderBy = models.SearchOrderByAlphabetically
  187. default:
  188. ctx.Data["SortType"] = "alphabetically"
  189. orderBy = models.SearchOrderByAlphabetically
  190. }
  191. opts.Keyword = strings.Trim(ctx.Query("q"), " ")
  192. opts.OrderBy = orderBy
  193. if len(opts.Keyword) == 0 || isKeywordValid(opts.Keyword) {
  194. users, count, err = models.SearchUsers(opts)
  195. if err != nil {
  196. ctx.ServerError("SearchUsers", err)
  197. return
  198. }
  199. }
  200. ctx.Data["Keyword"] = opts.Keyword
  201. ctx.Data["Total"] = count
  202. ctx.Data["Page"] = paginater.New(int(count), opts.PageSize, opts.Page, 5)
  203. ctx.Data["Users"] = users
  204. ctx.Data["ShowUserEmail"] = setting.UI.ShowUserEmail
  205. ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
  206. ctx.HTML(200, tplName)
  207. }
  208. // ExploreUsers render explore users page
  209. func ExploreUsers(ctx *context.Context) {
  210. ctx.Data["Title"] = ctx.Tr("explore")
  211. ctx.Data["PageIsExplore"] = true
  212. ctx.Data["PageIsExploreUsers"] = true
  213. ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
  214. RenderUserSearch(ctx, &models.SearchUserOptions{
  215. Type: models.UserTypeIndividual,
  216. PageSize: setting.UI.ExplorePagingNum,
  217. IsActive: util.OptionalBoolTrue,
  218. Private: true,
  219. }, tplExploreUsers)
  220. }
  221. // ExploreOrganizations render explore organizations page
  222. func ExploreOrganizations(ctx *context.Context) {
  223. ctx.Data["Title"] = ctx.Tr("explore")
  224. ctx.Data["PageIsExplore"] = true
  225. ctx.Data["PageIsExploreOrganizations"] = true
  226. ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
  227. var ownerID int64
  228. if ctx.User != nil && !ctx.User.IsAdmin {
  229. ownerID = ctx.User.ID
  230. }
  231. RenderUserSearch(ctx, &models.SearchUserOptions{
  232. Type: models.UserTypeOrganization,
  233. PageSize: setting.UI.ExplorePagingNum,
  234. Private: ctx.User != nil,
  235. OwnerID: ownerID,
  236. }, tplExploreOrganizations)
  237. }
  238. // ExploreCode render explore code page
  239. func ExploreCode(ctx *context.Context) {
  240. if !setting.Indexer.RepoIndexerEnabled {
  241. ctx.Redirect("/explore", 302)
  242. return
  243. }
  244. ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
  245. ctx.Data["Title"] = ctx.Tr("explore")
  246. ctx.Data["PageIsExplore"] = true
  247. ctx.Data["PageIsExploreCode"] = true
  248. keyword := strings.TrimSpace(ctx.Query("q"))
  249. page := ctx.QueryInt("page")
  250. if page <= 0 {
  251. page = 1
  252. }
  253. var (
  254. repoIDs []int64
  255. err error
  256. isAdmin bool
  257. userID int64
  258. )
  259. if ctx.User != nil {
  260. userID = ctx.User.ID
  261. isAdmin = ctx.User.IsAdmin
  262. }
  263. // guest user or non-admin user
  264. if ctx.User == nil || !isAdmin {
  265. repoIDs, err = models.FindUserAccessibleRepoIDs(userID)
  266. if err != nil {
  267. ctx.ServerError("SearchResults", err)
  268. return
  269. }
  270. }
  271. var (
  272. total int
  273. searchResults []*search.Result
  274. )
  275. // if non-admin login user, we need check UnitTypeCode at first
  276. if ctx.User != nil && len(repoIDs) > 0 {
  277. repoMaps, err := models.GetRepositoriesMapByIDs(repoIDs)
  278. if err != nil {
  279. ctx.ServerError("SearchResults", err)
  280. return
  281. }
  282. var rightRepoMap = make(map[int64]*models.Repository, len(repoMaps))
  283. repoIDs = make([]int64, 0, len(repoMaps))
  284. for id, repo := range repoMaps {
  285. if repo.CheckUnitUser(userID, isAdmin, models.UnitTypeCode) {
  286. rightRepoMap[id] = repo
  287. repoIDs = append(repoIDs, id)
  288. }
  289. }
  290. ctx.Data["RepoMaps"] = rightRepoMap
  291. total, searchResults, err = search.PerformSearch(repoIDs, keyword, page, setting.UI.RepoSearchPagingNum)
  292. if err != nil {
  293. ctx.ServerError("SearchResults", err)
  294. return
  295. }
  296. // if non-login user or isAdmin, no need to check UnitTypeCode
  297. } else if (ctx.User == nil && len(repoIDs) > 0) || isAdmin {
  298. total, searchResults, err = search.PerformSearch(repoIDs, keyword, page, setting.UI.RepoSearchPagingNum)
  299. if err != nil {
  300. ctx.ServerError("SearchResults", err)
  301. return
  302. }
  303. var loadRepoIDs = make([]int64, 0, len(searchResults))
  304. for _, result := range searchResults {
  305. var find bool
  306. for _, id := range loadRepoIDs {
  307. if id == result.RepoID {
  308. find = true
  309. break
  310. }
  311. }
  312. if !find {
  313. loadRepoIDs = append(loadRepoIDs, result.RepoID)
  314. }
  315. }
  316. repoMaps, err := models.GetRepositoriesMapByIDs(loadRepoIDs)
  317. if err != nil {
  318. ctx.ServerError("SearchResults", err)
  319. return
  320. }
  321. ctx.Data["RepoMaps"] = repoMaps
  322. }
  323. ctx.Data["Keyword"] = keyword
  324. pager := paginater.New(total, setting.UI.RepoSearchPagingNum, page, 5)
  325. ctx.Data["Page"] = pager
  326. ctx.Data["SearchResults"] = searchResults
  327. ctx.Data["RequireHighlightJS"] = true
  328. ctx.Data["PageIsViewCode"] = true
  329. ctx.HTML(200, tplExploreCode)
  330. }
  331. // NotFound render 404 page
  332. func NotFound(ctx *context.Context) {
  333. ctx.Data["Title"] = "Page Not Found"
  334. ctx.NotFound("home.NotFound", nil)
  335. }