You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

context.go 7.3 kB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package middleware
  5. import (
  6. "fmt"
  7. "html/template"
  8. "io"
  9. "net/http"
  10. "strings"
  11. "time"
  12. "github.com/go-macaron/cache"
  13. "github.com/go-macaron/csrf"
  14. "github.com/go-macaron/i18n"
  15. "github.com/go-macaron/session"
  16. "gopkg.in/macaron.v1"
  17. "github.com/gogits/git-module"
  18. "github.com/gogits/gogs/models"
  19. "github.com/gogits/gogs/modules/auth"
  20. "github.com/gogits/gogs/modules/base"
  21. "github.com/gogits/gogs/modules/log"
  22. "github.com/gogits/gogs/modules/setting"
  23. )
  24. type PullRequestContext struct {
  25. BaseRepo *models.Repository
  26. Allowed bool
  27. SameRepo bool
  28. HeadInfo string // [<user>:]<branch>
  29. }
  30. type RepoContext struct {
  31. AccessMode models.AccessMode
  32. IsWatching bool
  33. IsViewBranch bool
  34. IsViewTag bool
  35. IsViewCommit bool
  36. Repository *models.Repository
  37. Owner *models.User
  38. Commit *git.Commit
  39. Tag *git.Tag
  40. GitRepo *git.Repository
  41. BranchName string
  42. TagName string
  43. TreeName string
  44. CommitID string
  45. RepoLink string
  46. CloneLink models.CloneLink
  47. CommitsCount int64
  48. Mirror *models.Mirror
  49. PullRequest *PullRequestContext
  50. }
  51. // Context represents context of a request.
  52. type Context struct {
  53. *macaron.Context
  54. Cache cache.Cache
  55. csrf csrf.CSRF
  56. Flash *session.Flash
  57. Session session.Store
  58. User *models.User
  59. IsSigned bool
  60. IsBasicAuth bool
  61. Repo *RepoContext
  62. Org struct {
  63. IsOwner bool
  64. IsMember bool
  65. IsTeamMember bool // Is member of team.
  66. IsTeamAdmin bool // In owner team or team that has admin permission level.
  67. Organization *models.User
  68. OrgLink string
  69. Team *models.Team
  70. }
  71. }
  72. // IsOwner returns true if current user is the owner of repository.
  73. func (r *RepoContext) IsOwner() bool {
  74. return r.AccessMode >= models.ACCESS_MODE_OWNER
  75. }
  76. // IsAdmin returns true if current user has admin or higher access of repository.
  77. func (r *RepoContext) IsAdmin() bool {
  78. return r.AccessMode >= models.ACCESS_MODE_ADMIN
  79. }
  80. // IsWriter returns true if current user has write or higher access of repository.
  81. func (r *RepoContext) IsWriter() bool {
  82. return r.AccessMode >= models.ACCESS_MODE_WRITE
  83. }
  84. // HasAccess returns true if the current user has at least read access for this repository
  85. func (r *RepoContext) HasAccess() bool {
  86. return r.AccessMode >= models.ACCESS_MODE_READ
  87. }
  88. // HasError returns true if error occurs in form validation.
  89. func (ctx *Context) HasApiError() bool {
  90. hasErr, ok := ctx.Data["HasError"]
  91. if !ok {
  92. return false
  93. }
  94. return hasErr.(bool)
  95. }
  96. func (ctx *Context) GetErrMsg() string {
  97. return ctx.Data["ErrorMsg"].(string)
  98. }
  99. // HasError returns true if error occurs in form validation.
  100. func (ctx *Context) HasError() bool {
  101. hasErr, ok := ctx.Data["HasError"]
  102. if !ok {
  103. return false
  104. }
  105. ctx.Flash.ErrorMsg = ctx.Data["ErrorMsg"].(string)
  106. ctx.Data["Flash"] = ctx.Flash
  107. return hasErr.(bool)
  108. }
  109. // HasValue returns true if value of given name exists.
  110. func (ctx *Context) HasValue(name string) bool {
  111. _, ok := ctx.Data[name]
  112. return ok
  113. }
  114. // HTML calls Context.HTML and converts template name to string.
  115. func (ctx *Context) HTML(status int, name base.TplName) {
  116. log.Debug("Template: %s", name)
  117. ctx.Context.HTML(status, string(name))
  118. }
  119. // RenderWithErr used for page has form validation but need to prompt error to users.
  120. func (ctx *Context) RenderWithErr(msg string, tpl base.TplName, form interface{}) {
  121. if form != nil {
  122. auth.AssignForm(form, ctx.Data)
  123. }
  124. ctx.Flash.ErrorMsg = msg
  125. ctx.Data["Flash"] = ctx.Flash
  126. ctx.HTML(200, tpl)
  127. }
  128. // Handle handles and logs error by given status.
  129. func (ctx *Context) Handle(status int, title string, err error) {
  130. if err != nil {
  131. log.Error(4, "%s: %v", title, err)
  132. if macaron.Env != macaron.PROD {
  133. ctx.Data["ErrorMsg"] = err
  134. }
  135. }
  136. switch status {
  137. case 404:
  138. ctx.Data["Title"] = "Page Not Found"
  139. case 500:
  140. ctx.Data["Title"] = "Internal Server Error"
  141. }
  142. ctx.HTML(status, base.TplName(fmt.Sprintf("status/%d", status)))
  143. }
  144. func (ctx *Context) HandleText(status int, title string) {
  145. if (status/100 == 4) || (status/100 == 5) {
  146. log.Error(4, "%s", title)
  147. }
  148. ctx.PlainText(status, []byte(title))
  149. }
  150. // APIError logs error with title if status is 500.
  151. func (ctx *Context) APIError(status int, title string, obj interface{}) {
  152. var message string
  153. if err, ok := obj.(error); ok {
  154. message = err.Error()
  155. } else {
  156. message = obj.(string)
  157. }
  158. if status == 500 {
  159. log.Error(4, "%s: %s", title, message)
  160. }
  161. ctx.JSON(status, map[string]string{
  162. "message": message,
  163. "url": base.DOC_URL,
  164. })
  165. }
  166. func (ctx *Context) ServeContent(name string, r io.ReadSeeker, params ...interface{}) {
  167. modtime := time.Now()
  168. for _, p := range params {
  169. switch v := p.(type) {
  170. case time.Time:
  171. modtime = v
  172. }
  173. }
  174. ctx.Resp.Header().Set("Content-Description", "File Transfer")
  175. ctx.Resp.Header().Set("Content-Type", "application/octet-stream")
  176. ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+name)
  177. ctx.Resp.Header().Set("Content-Transfer-Encoding", "binary")
  178. ctx.Resp.Header().Set("Expires", "0")
  179. ctx.Resp.Header().Set("Cache-Control", "must-revalidate")
  180. ctx.Resp.Header().Set("Pragma", "public")
  181. http.ServeContent(ctx.Resp, ctx.Req.Request, name, modtime, r)
  182. }
  183. // Contexter initializes a classic context for a request.
  184. func Contexter() macaron.Handler {
  185. return func(c *macaron.Context, l i18n.Locale, cache cache.Cache, sess session.Store, f *session.Flash, x csrf.CSRF) {
  186. ctx := &Context{
  187. Context: c,
  188. Cache: cache,
  189. csrf: x,
  190. Flash: f,
  191. Session: sess,
  192. Repo: &RepoContext{
  193. PullRequest: &PullRequestContext{},
  194. },
  195. }
  196. // Compute current URL for real-time change language.
  197. ctx.Data["Link"] = setting.AppSubUrl + strings.TrimSuffix(ctx.Req.URL.Path, "/")
  198. ctx.Data["PageStartTime"] = time.Now()
  199. // Get user from session if logined.
  200. ctx.User, ctx.IsBasicAuth = auth.SignedInUser(ctx.Context, ctx.Session)
  201. if ctx.User != nil {
  202. ctx.IsSigned = true
  203. ctx.Data["IsSigned"] = ctx.IsSigned
  204. ctx.Data["SignedUser"] = ctx.User
  205. ctx.Data["SignedUserID"] = ctx.User.Id
  206. ctx.Data["SignedUserName"] = ctx.User.Name
  207. ctx.Data["IsAdmin"] = ctx.User.IsAdmin
  208. } else {
  209. ctx.Data["SignedUserID"] = 0
  210. ctx.Data["SignedUserName"] = ""
  211. }
  212. // If request sends files, parse them here otherwise the Query() can't be parsed and the CsrfToken will be invalid.
  213. if ctx.Req.Method == "POST" && strings.Contains(ctx.Req.Header.Get("Content-Type"), "multipart/form-data") {
  214. if err := ctx.Req.ParseMultipartForm(setting.AttachmentMaxSize << 20); err != nil && !strings.Contains(err.Error(), "EOF") { // 32MB max size
  215. ctx.Handle(500, "ParseMultipartForm", err)
  216. return
  217. }
  218. }
  219. ctx.Data["CsrfToken"] = x.GetToken()
  220. ctx.Data["CsrfTokenHtml"] = template.HTML(`<input type="hidden" name="_csrf" value="` + x.GetToken() + `">`)
  221. log.Debug("Session ID: %s", sess.ID())
  222. log.Debug("CSRF Token: %v", ctx.Data["CsrfToken"])
  223. ctx.Data["ShowRegistrationButton"] = setting.Service.ShowRegistrationButton
  224. ctx.Data["ShowFooterBranding"] = setting.ShowFooterBranding
  225. ctx.Data["ShowFooterVersion"] = setting.ShowFooterVersion
  226. c.Map(ctx)
  227. }
  228. }