diff options
Diffstat (limited to 'modules/context/context.go')
-rw-r--r-- | modules/context/context.go | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/modules/context/context.go b/modules/context/context.go new file mode 100644 index 00000000..348de325 --- /dev/null +++ b/modules/context/context.go @@ -0,0 +1,186 @@ +// Copyright 2014 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package context + +import ( + "fmt" + "html/template" + "io" + "net/http" + "strings" + "time" + + "github.com/go-macaron/cache" + "github.com/go-macaron/csrf" + "github.com/go-macaron/i18n" + "github.com/go-macaron/session" + "gopkg.in/macaron.v1" + + "github.com/gogits/gogs/models" + "github.com/gogits/gogs/modules/auth" + "github.com/gogits/gogs/modules/base" + "github.com/gogits/gogs/modules/log" + "github.com/gogits/gogs/modules/setting" +) + +// Context represents context of a request. +type Context struct { + *macaron.Context + Cache cache.Cache + csrf csrf.CSRF + Flash *session.Flash + Session session.Store + + User *models.User + IsSigned bool + IsBasicAuth bool + + Repo *Repository + Org *Organization +} + +// HasError returns true if error occurs in form validation. +func (ctx *Context) HasApiError() bool { + hasErr, ok := ctx.Data["HasError"] + if !ok { + return false + } + return hasErr.(bool) +} + +func (ctx *Context) GetErrMsg() string { + return ctx.Data["ErrorMsg"].(string) +} + +// HasError returns true if error occurs in form validation. +func (ctx *Context) HasError() bool { + hasErr, ok := ctx.Data["HasError"] + if !ok { + return false + } + ctx.Flash.ErrorMsg = ctx.Data["ErrorMsg"].(string) + ctx.Data["Flash"] = ctx.Flash + return hasErr.(bool) +} + +// HasValue returns true if value of given name exists. +func (ctx *Context) HasValue(name string) bool { + _, ok := ctx.Data[name] + return ok +} + +// HTML calls Context.HTML and converts template name to string. +func (ctx *Context) HTML(status int, name base.TplName) { + log.Debug("Template: %s", name) + ctx.Context.HTML(status, string(name)) +} + +// RenderWithErr used for page has form validation but need to prompt error to users. +func (ctx *Context) RenderWithErr(msg string, tpl base.TplName, form interface{}) { + if form != nil { + auth.AssignForm(form, ctx.Data) + } + ctx.Flash.ErrorMsg = msg + ctx.Data["Flash"] = ctx.Flash + ctx.HTML(200, tpl) +} + +// Handle handles and logs error by given status. +func (ctx *Context) Handle(status int, title string, err error) { + if err != nil { + log.Error(4, "%s: %v", title, err) + if macaron.Env != macaron.PROD { + ctx.Data["ErrorMsg"] = err + } + } + + switch status { + case 404: + ctx.Data["Title"] = "Page Not Found" + case 500: + ctx.Data["Title"] = "Internal Server Error" + } + ctx.HTML(status, base.TplName(fmt.Sprintf("status/%d", status))) +} + +func (ctx *Context) HandleText(status int, title string) { + if (status/100 == 4) || (status/100 == 5) { + log.Error(4, "%s", title) + } + ctx.PlainText(status, []byte(title)) +} + +func (ctx *Context) ServeContent(name string, r io.ReadSeeker, params ...interface{}) { + modtime := time.Now() + for _, p := range params { + switch v := p.(type) { + case time.Time: + modtime = v + } + } + ctx.Resp.Header().Set("Content-Description", "File Transfer") + ctx.Resp.Header().Set("Content-Type", "application/octet-stream") + ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+name) + ctx.Resp.Header().Set("Content-Transfer-Encoding", "binary") + ctx.Resp.Header().Set("Expires", "0") + ctx.Resp.Header().Set("Cache-Control", "must-revalidate") + ctx.Resp.Header().Set("Pragma", "public") + http.ServeContent(ctx.Resp, ctx.Req.Request, name, modtime, r) +} + +// Contexter initializes a classic context for a request. +func Contexter() macaron.Handler { + return func(c *macaron.Context, l i18n.Locale, cache cache.Cache, sess session.Store, f *session.Flash, x csrf.CSRF) { + ctx := &Context{ + Context: c, + Cache: cache, + csrf: x, + Flash: f, + Session: sess, + Repo: &Repository{ + PullRequest: &PullRequest{}, + }, + Org: &Organization{}, + } + // Compute current URL for real-time change language. + ctx.Data["Link"] = setting.AppSubUrl + strings.TrimSuffix(ctx.Req.URL.Path, "/") + + ctx.Data["PageStartTime"] = time.Now() + + // Get user from session if logined. + ctx.User, ctx.IsBasicAuth = auth.SignedInUser(ctx.Context, ctx.Session) + + if ctx.User != nil { + ctx.IsSigned = true + ctx.Data["IsSigned"] = ctx.IsSigned + ctx.Data["SignedUser"] = ctx.User + ctx.Data["SignedUserID"] = ctx.User.Id + ctx.Data["SignedUserName"] = ctx.User.Name + ctx.Data["IsAdmin"] = ctx.User.IsAdmin + } else { + ctx.Data["SignedUserID"] = 0 + ctx.Data["SignedUserName"] = "" + } + + // If request sends files, parse them here otherwise the Query() can't be parsed and the CsrfToken will be invalid. + if ctx.Req.Method == "POST" && strings.Contains(ctx.Req.Header.Get("Content-Type"), "multipart/form-data") { + if err := ctx.Req.ParseMultipartForm(setting.AttachmentMaxSize << 20); err != nil && !strings.Contains(err.Error(), "EOF") { // 32MB max size + ctx.Handle(500, "ParseMultipartForm", err) + return + } + } + + ctx.Data["CsrfToken"] = x.GetToken() + ctx.Data["CsrfTokenHtml"] = template.HTML(`<input type="hidden" name="_csrf" value="` + x.GetToken() + `">`) + log.Debug("Session ID: %s", sess.ID()) + log.Debug("CSRF Token: %v", ctx.Data["CsrfToken"]) + + ctx.Data["ShowRegistrationButton"] = setting.Service.ShowRegistrationButton + ctx.Data["ShowFooterBranding"] = setting.ShowFooterBranding + ctx.Data["ShowFooterVersion"] = setting.ShowFooterVersion + + c.Map(ctx) + } +} |