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.

home.go 11KB

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