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.0 kB

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