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.

229 lines
6.1 KiB

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