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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  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. }