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.

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