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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  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. var (
  177. users []*models.User
  178. count int64
  179. err error
  180. orderBy models.SearchOrderBy
  181. )
  182. ctx.Data["SortType"] = ctx.Query("sort")
  183. switch ctx.Query("sort") {
  184. case "newest":
  185. orderBy = models.SearchOrderByIDReverse
  186. case "oldest":
  187. orderBy = models.SearchOrderByID
  188. case "recentupdate":
  189. orderBy = models.SearchOrderByRecentUpdated
  190. case "leastupdate":
  191. orderBy = models.SearchOrderByLeastUpdated
  192. case "reversealphabetically":
  193. orderBy = models.SearchOrderByAlphabeticallyReverse
  194. case "alphabetically":
  195. orderBy = models.SearchOrderByAlphabetically
  196. default:
  197. ctx.Data["SortType"] = "alphabetically"
  198. orderBy = models.SearchOrderByAlphabetically
  199. }
  200. opts.Keyword = strings.Trim(ctx.Query("q"), " ")
  201. opts.OrderBy = orderBy
  202. if len(opts.Keyword) == 0 || isKeywordValid(opts.Keyword) {
  203. users, count, err = models.SearchUsers(opts)
  204. if err != nil {
  205. ctx.ServerError("SearchUsers", err)
  206. return
  207. }
  208. }
  209. ctx.Data["Keyword"] = opts.Keyword
  210. ctx.Data["Total"] = count
  211. ctx.Data["Users"] = users
  212. ctx.Data["ShowUserEmail"] = setting.UI.ShowUserEmail
  213. ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
  214. pager := context.NewPagination(int(count), opts.PageSize, opts.Page, 5)
  215. pager.SetDefaultParams(ctx)
  216. ctx.Data["Page"] = pager
  217. ctx.HTML(200, tplName)
  218. }
  219. // ExploreUsers render explore users page
  220. func ExploreUsers(ctx *context.Context) {
  221. ctx.Data["Title"] = ctx.Tr("explore")
  222. ctx.Data["PageIsExplore"] = true
  223. ctx.Data["PageIsExploreUsers"] = true
  224. ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
  225. RenderUserSearch(ctx, &models.SearchUserOptions{
  226. Actor: ctx.User,
  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. Actor: ctx.User,
  245. Type: models.UserTypeOrganization,
  246. ListOptions: models.ListOptions{PageSize: setting.UI.ExplorePagingNum},
  247. Visible: visibleTypes,
  248. }, tplExploreOrganizations)
  249. }
  250. // ExploreCode render explore code page
  251. func ExploreCode(ctx *context.Context) {
  252. if !setting.Indexer.RepoIndexerEnabled {
  253. ctx.Redirect(setting.AppSubURL+"/explore", 302)
  254. return
  255. }
  256. ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
  257. ctx.Data["Title"] = ctx.Tr("explore")
  258. ctx.Data["PageIsExplore"] = true
  259. ctx.Data["PageIsExploreCode"] = true
  260. language := strings.TrimSpace(ctx.Query("l"))
  261. keyword := strings.TrimSpace(ctx.Query("q"))
  262. page := ctx.QueryInt("page")
  263. if page <= 0 {
  264. page = 1
  265. }
  266. var (
  267. repoIDs []int64
  268. err error
  269. isAdmin bool
  270. userID int64
  271. )
  272. if ctx.User != nil {
  273. userID = ctx.User.ID
  274. isAdmin = ctx.User.IsAdmin
  275. }
  276. // guest user or non-admin user
  277. if ctx.User == nil || !isAdmin {
  278. repoIDs, err = models.FindUserAccessibleRepoIDs(ctx.User)
  279. if err != nil {
  280. ctx.ServerError("SearchResults", err)
  281. return
  282. }
  283. }
  284. var (
  285. total int
  286. searchResults []*code_indexer.Result
  287. searchResultLanguages []*code_indexer.SearchResultLanguages
  288. )
  289. // if non-admin login user, we need check UnitTypeCode at first
  290. if ctx.User != nil && len(repoIDs) > 0 {
  291. repoMaps, err := models.GetRepositoriesMapByIDs(repoIDs)
  292. if err != nil {
  293. ctx.ServerError("SearchResults", err)
  294. return
  295. }
  296. var rightRepoMap = make(map[int64]*models.Repository, len(repoMaps))
  297. repoIDs = make([]int64, 0, len(repoMaps))
  298. for id, repo := range repoMaps {
  299. if repo.CheckUnitUser(userID, isAdmin, models.UnitTypeCode) {
  300. rightRepoMap[id] = repo
  301. repoIDs = append(repoIDs, id)
  302. }
  303. }
  304. ctx.Data["RepoMaps"] = rightRepoMap
  305. total, searchResults, searchResultLanguages, err = code_indexer.PerformSearch(repoIDs, language, keyword, page, setting.UI.RepoSearchPagingNum)
  306. if err != nil {
  307. ctx.ServerError("SearchResults", err)
  308. return
  309. }
  310. // if non-login user or isAdmin, no need to check UnitTypeCode
  311. } else if (ctx.User == nil && len(repoIDs) > 0) || isAdmin {
  312. total, searchResults, searchResultLanguages, err = code_indexer.PerformSearch(repoIDs, language, keyword, page, setting.UI.RepoSearchPagingNum)
  313. if err != nil {
  314. ctx.ServerError("SearchResults", err)
  315. return
  316. }
  317. var loadRepoIDs = make([]int64, 0, len(searchResults))
  318. for _, result := range searchResults {
  319. var find bool
  320. for _, id := range loadRepoIDs {
  321. if id == result.RepoID {
  322. find = true
  323. break
  324. }
  325. }
  326. if !find {
  327. loadRepoIDs = append(loadRepoIDs, result.RepoID)
  328. }
  329. }
  330. repoMaps, err := models.GetRepositoriesMapByIDs(loadRepoIDs)
  331. if err != nil {
  332. ctx.ServerError("SearchResults", err)
  333. return
  334. }
  335. ctx.Data["RepoMaps"] = repoMaps
  336. }
  337. ctx.Data["Keyword"] = keyword
  338. ctx.Data["Language"] = language
  339. ctx.Data["SearchResults"] = searchResults
  340. ctx.Data["SearchResultLanguages"] = searchResultLanguages
  341. ctx.Data["RequireHighlightJS"] = true
  342. ctx.Data["PageIsViewCode"] = true
  343. pager := context.NewPagination(total, setting.UI.RepoSearchPagingNum, page, 5)
  344. pager.SetDefaultParams(ctx)
  345. pager.AddParam(ctx, "l", "Language")
  346. ctx.Data["Page"] = pager
  347. ctx.HTML(200, tplExploreCode)
  348. }
  349. // NotFound render 404 page
  350. func NotFound(ctx *context.Context) {
  351. ctx.Data["Title"] = "Page Not Found"
  352. ctx.NotFound("home.NotFound", nil)
  353. }