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 12KB

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