mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-10-31 06:21:11 +00:00 
			
		
		
		
	fix
This commit is contained in:
		
					parent
					
						
							
								f3ed11d177
							
						
					
				
			
			
				commit
				
					
						a4cbe79567
					
				
			
		
					 165 changed files with 18302 additions and 0 deletions
				
			
		
							
								
								
									
										63
									
								
								modules/middleware/auth.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								modules/middleware/auth.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,63 @@ | |||
| // 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 middleware | ||||
| 
 | ||||
| import ( | ||||
| 	"net/url" | ||||
| 
 | ||||
| 	"github.com/go-martini/martini" | ||||
| 
 | ||||
| 	"github.com/gogits/gogs/modules/base" | ||||
| ) | ||||
| 
 | ||||
| type ToggleOptions struct { | ||||
| 	SignInRequire  bool | ||||
| 	SignOutRequire bool | ||||
| 	AdminRequire   bool | ||||
| 	DisableCsrf    bool | ||||
| } | ||||
| 
 | ||||
| func Toggle(options *ToggleOptions) martini.Handler { | ||||
| 	return func(ctx *Context) { | ||||
| 		if !base.InstallLock { | ||||
| 			ctx.Redirect("/install") | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		if options.SignOutRequire && ctx.IsSigned && ctx.Req.RequestURI != "/" { | ||||
| 			ctx.Redirect("/") | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		if !options.DisableCsrf { | ||||
| 			if ctx.Req.Method == "POST" { | ||||
| 				if !ctx.CsrfTokenValid() { | ||||
| 					ctx.Error(403, "CSRF token does not match") | ||||
| 					return | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if options.SignInRequire { | ||||
| 			if !ctx.IsSigned { | ||||
| 				ctx.SetCookie("redirect_to", "/"+url.QueryEscape(ctx.Req.RequestURI)) | ||||
| 				ctx.Redirect("/user/login") | ||||
| 				return | ||||
| 			} else if !ctx.User.IsActive && base.Service.RegisterEmailConfirm { | ||||
| 				ctx.Data["Title"] = "Activate Your Account" | ||||
| 				ctx.HTML(200, "user/active") | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if options.AdminRequire { | ||||
| 			if !ctx.User.IsAdmin { | ||||
| 				ctx.Error(403) | ||||
| 				return | ||||
| 			} | ||||
| 			ctx.Data["PageIsAdmin"] = true | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										286
									
								
								modules/middleware/context.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										286
									
								
								modules/middleware/context.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,286 @@ | |||
| // 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 middleware | ||||
| 
 | ||||
| import ( | ||||
| 	"crypto/hmac" | ||||
| 	"crypto/sha1" | ||||
| 	"encoding/base64" | ||||
| 	"fmt" | ||||
| 	"html/template" | ||||
| 	"net/http" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/go-martini/martini" | ||||
| 
 | ||||
| 	"github.com/gogits/cache" | ||||
| 	"github.com/gogits/git" | ||||
| 	"github.com/gogits/session" | ||||
| 
 | ||||
| 	"github.com/gogits/gogs/models" | ||||
| 	"github.com/gogits/gogs/modules/auth" | ||||
| 	"github.com/gogits/gogs/modules/base" | ||||
| 	"github.com/gogits/gogs/modules/log" | ||||
| ) | ||||
| 
 | ||||
| // Context represents context of a request. | ||||
| type Context struct { | ||||
| 	*Render | ||||
| 	c        martini.Context | ||||
| 	p        martini.Params | ||||
| 	Req      *http.Request | ||||
| 	Res      http.ResponseWriter | ||||
| 	Session  session.SessionStore | ||||
| 	Cache    cache.Cache | ||||
| 	User     *models.User | ||||
| 	IsSigned bool | ||||
| 
 | ||||
| 	csrfToken string | ||||
| 
 | ||||
| 	Repo struct { | ||||
| 		IsOwner    bool | ||||
| 		IsWatching bool | ||||
| 		IsBranch   bool | ||||
| 		IsTag      bool | ||||
| 		IsCommit   bool | ||||
| 		Repository *models.Repository | ||||
| 		Owner      *models.User | ||||
| 		Commit     *git.Commit | ||||
| 		GitRepo    *git.Repository | ||||
| 		BranchName string | ||||
| 		CommitId   string | ||||
| 		RepoLink   string | ||||
| 		CloneLink  struct { | ||||
| 			SSH   string | ||||
| 			HTTPS string | ||||
| 			Git   string | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Query querys form parameter. | ||||
| func (ctx *Context) Query(name string) string { | ||||
| 	ctx.Req.ParseForm() | ||||
| 	return ctx.Req.Form.Get(name) | ||||
| } | ||||
| 
 | ||||
| // func (ctx *Context) Param(name string) string { | ||||
| // 	return ctx.p[name] | ||||
| // } | ||||
| 
 | ||||
| // HasError returns true if error occurs in form validation. | ||||
| func (ctx *Context) HasError() bool { | ||||
| 	hasErr, ok := ctx.Data["HasError"] | ||||
| 	if !ok { | ||||
| 		return false | ||||
| 	} | ||||
| 	return hasErr.(bool) | ||||
| } | ||||
| 
 | ||||
| // HTML calls render.HTML underlying but reduce one argument. | ||||
| func (ctx *Context) HTML(status int, name string, htmlOpt ...HTMLOptions) { | ||||
| 	ctx.Render.HTML(status, name, ctx.Data, htmlOpt...) | ||||
| } | ||||
| 
 | ||||
| // RenderWithErr used for page has form validation but need to prompt error to users. | ||||
| func (ctx *Context) RenderWithErr(msg, tpl string, form auth.Form) { | ||||
| 	ctx.Data["HasError"] = true | ||||
| 	ctx.Data["ErrorMsg"] = msg | ||||
| 	if form != nil { | ||||
| 		auth.AssignForm(form, ctx.Data) | ||||
| 	} | ||||
| 	ctx.HTML(200, tpl) | ||||
| } | ||||
| 
 | ||||
| // Handle handles and logs error by given status. | ||||
| func (ctx *Context) Handle(status int, title string, err error) { | ||||
| 	log.Error("%s: %v", title, err) | ||||
| 	if martini.Dev == martini.Prod { | ||||
| 		ctx.HTML(500, "status/500") | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	ctx.Data["ErrorMsg"] = err | ||||
| 	ctx.HTML(status, fmt.Sprintf("status/%d", status)) | ||||
| } | ||||
| 
 | ||||
| func (ctx *Context) Debug(msg string, args ...interface{}) { | ||||
| 	log.Debug(msg, args...) | ||||
| } | ||||
| 
 | ||||
| func (ctx *Context) GetCookie(name string) string { | ||||
| 	cookie, err := ctx.Req.Cookie(name) | ||||
| 	if err != nil { | ||||
| 		return "" | ||||
| 	} | ||||
| 	return cookie.Value | ||||
| } | ||||
| 
 | ||||
| func (ctx *Context) SetCookie(name string, value string, others ...interface{}) { | ||||
| 	cookie := http.Cookie{} | ||||
| 	cookie.Name = name | ||||
| 	cookie.Value = value | ||||
| 
 | ||||
| 	if len(others) > 0 { | ||||
| 		switch v := others[0].(type) { | ||||
| 		case int: | ||||
| 			cookie.MaxAge = v | ||||
| 		case int64: | ||||
| 			cookie.MaxAge = int(v) | ||||
| 		case int32: | ||||
| 			cookie.MaxAge = int(v) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// default "/" | ||||
| 	if len(others) > 1 { | ||||
| 		if v, ok := others[1].(string); ok && len(v) > 0 { | ||||
| 			cookie.Path = v | ||||
| 		} | ||||
| 	} else { | ||||
| 		cookie.Path = "/" | ||||
| 	} | ||||
| 
 | ||||
| 	// default empty | ||||
| 	if len(others) > 2 { | ||||
| 		if v, ok := others[2].(string); ok && len(v) > 0 { | ||||
| 			cookie.Domain = v | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// default empty | ||||
| 	if len(others) > 3 { | ||||
| 		switch v := others[3].(type) { | ||||
| 		case bool: | ||||
| 			cookie.Secure = v | ||||
| 		default: | ||||
| 			if others[3] != nil { | ||||
| 				cookie.Secure = true | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// default false. for session cookie default true | ||||
| 	if len(others) > 4 { | ||||
| 		if v, ok := others[4].(bool); ok && v { | ||||
| 			cookie.HttpOnly = true | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	ctx.Res.Header().Add("Set-Cookie", cookie.String()) | ||||
| } | ||||
| 
 | ||||
| // Get secure cookie from request by a given key. | ||||
| func (ctx *Context) GetSecureCookie(Secret, key string) (string, bool) { | ||||
| 	val := ctx.GetCookie(key) | ||||
| 	if val == "" { | ||||
| 		return "", false | ||||
| 	} | ||||
| 
 | ||||
| 	parts := strings.SplitN(val, "|", 3) | ||||
| 
 | ||||
| 	if len(parts) != 3 { | ||||
| 		return "", false | ||||
| 	} | ||||
| 
 | ||||
| 	vs := parts[0] | ||||
| 	timestamp := parts[1] | ||||
| 	sig := parts[2] | ||||
| 
 | ||||
| 	h := hmac.New(sha1.New, []byte(Secret)) | ||||
| 	fmt.Fprintf(h, "%s%s", vs, timestamp) | ||||
| 
 | ||||
| 	if fmt.Sprintf("%02x", h.Sum(nil)) != sig { | ||||
| 		return "", false | ||||
| 	} | ||||
| 	res, _ := base64.URLEncoding.DecodeString(vs) | ||||
| 	return string(res), true | ||||
| } | ||||
| 
 | ||||
| // Set Secure cookie for response. | ||||
| func (ctx *Context) SetSecureCookie(Secret, name, value string, others ...interface{}) { | ||||
| 	vs := base64.URLEncoding.EncodeToString([]byte(value)) | ||||
| 	timestamp := strconv.FormatInt(time.Now().UnixNano(), 10) | ||||
| 	h := hmac.New(sha1.New, []byte(Secret)) | ||||
| 	fmt.Fprintf(h, "%s%s", vs, timestamp) | ||||
| 	sig := fmt.Sprintf("%02x", h.Sum(nil)) | ||||
| 	cookie := strings.Join([]string{vs, timestamp, sig}, "|") | ||||
| 	ctx.SetCookie(name, cookie, others...) | ||||
| } | ||||
| 
 | ||||
| func (ctx *Context) CsrfToken() string { | ||||
| 	if len(ctx.csrfToken) > 0 { | ||||
| 		return ctx.csrfToken | ||||
| 	} | ||||
| 
 | ||||
| 	token := ctx.GetCookie("_csrf") | ||||
| 	if len(token) == 0 { | ||||
| 		token = base.GetRandomString(30) | ||||
| 		ctx.SetCookie("_csrf", token) | ||||
| 	} | ||||
| 	ctx.csrfToken = token | ||||
| 	return token | ||||
| } | ||||
| 
 | ||||
| func (ctx *Context) CsrfTokenValid() bool { | ||||
| 	token := ctx.Query("_csrf") | ||||
| 	if token == "" { | ||||
| 		token = ctx.Req.Header.Get("X-Csrf-Token") | ||||
| 	} | ||||
| 	if token == "" { | ||||
| 		return false | ||||
| 	} else if ctx.csrfToken != token { | ||||
| 		return false | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| // InitContext initializes a classic context for a request. | ||||
| func InitContext() martini.Handler { | ||||
| 	return func(res http.ResponseWriter, r *http.Request, c martini.Context, rd *Render) { | ||||
| 
 | ||||
| 		ctx := &Context{ | ||||
| 			c: c, | ||||
| 			// p:      p, | ||||
| 			Req:    r, | ||||
| 			Res:    res, | ||||
| 			Cache:  base.Cache, | ||||
| 			Render: rd, | ||||
| 		} | ||||
| 
 | ||||
| 		ctx.Data["PageStartTime"] = time.Now() | ||||
| 
 | ||||
| 		// start session | ||||
| 		ctx.Session = base.SessionManager.SessionStart(res, r) | ||||
| 		rw := res.(martini.ResponseWriter) | ||||
| 		rw.Before(func(martini.ResponseWriter) { | ||||
| 			ctx.Session.SessionRelease(res) | ||||
| 		}) | ||||
| 
 | ||||
| 		// Get user from session if logined. | ||||
| 		user := auth.SignedInUser(ctx.Session) | ||||
| 		ctx.User = user | ||||
| 		ctx.IsSigned = user != nil | ||||
| 
 | ||||
| 		ctx.Data["IsSigned"] = ctx.IsSigned | ||||
| 
 | ||||
| 		if user != nil { | ||||
| 			ctx.Data["SignedUser"] = user | ||||
| 			ctx.Data["SignedUserId"] = user.Id | ||||
| 			ctx.Data["SignedUserName"] = user.Name | ||||
| 			ctx.Data["IsAdmin"] = ctx.User.IsAdmin | ||||
| 		} | ||||
| 
 | ||||
| 		// get or create csrf token | ||||
| 		ctx.Data["CsrfToken"] = ctx.CsrfToken() | ||||
| 		ctx.Data["CsrfTokenHtml"] = template.HTML(`<input type="hidden" name="_csrf" value="` + ctx.csrfToken + `">`) | ||||
| 
 | ||||
| 		c.Map(ctx) | ||||
| 
 | ||||
| 		c.Next() | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										46
									
								
								modules/middleware/logger.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								modules/middleware/logger.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,46 @@ | |||
| // 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 middleware | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"log" | ||||
| 	"net/http" | ||||
| 	"runtime" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/go-martini/martini" | ||||
| ) | ||||
| 
 | ||||
| var isWindows bool | ||||
| 
 | ||||
| func init() { | ||||
| 	isWindows = runtime.GOOS == "windows" | ||||
| } | ||||
| 
 | ||||
| func Logger() martini.Handler { | ||||
| 	return func(res http.ResponseWriter, req *http.Request, ctx martini.Context, log *log.Logger) { | ||||
| 		start := time.Now() | ||||
| 		log.Printf("Started %s %s", req.Method, req.URL.Path) | ||||
| 
 | ||||
| 		rw := res.(martini.ResponseWriter) | ||||
| 		ctx.Next() | ||||
| 
 | ||||
| 		content := fmt.Sprintf("Completed %v %s in %v", rw.Status(), http.StatusText(rw.Status()), time.Since(start)) | ||||
| 		if !isWindows { | ||||
| 			switch rw.Status() { | ||||
| 			case 200: | ||||
| 				content = fmt.Sprintf("\033[1;32m%s\033[0m", content) | ||||
| 			case 304: | ||||
| 				content = fmt.Sprintf("\033[1;33m%s\033[0m", content) | ||||
| 			case 404: | ||||
| 				content = fmt.Sprintf("\033[1;31m%s\033[0m", content) | ||||
| 			case 500: | ||||
| 				content = fmt.Sprintf("\033[1;36m%s\033[0m", content) | ||||
| 			} | ||||
| 		} | ||||
| 		log.Println(content) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										289
									
								
								modules/middleware/render.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										289
									
								
								modules/middleware/render.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,289 @@ | |||
| // 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. | ||||
| 
 | ||||
| // foked from https://github.com/martini-contrib/render/blob/master/render.go | ||||
| package middleware | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"html/template" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"net/http" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/go-martini/martini" | ||||
| 
 | ||||
| 	"github.com/gogits/gogs/modules/base" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	ContentType    = "Content-Type" | ||||
| 	ContentLength  = "Content-Length" | ||||
| 	ContentJSON    = "application/json" | ||||
| 	ContentHTML    = "text/html" | ||||
| 	ContentXHTML   = "application/xhtml+xml" | ||||
| 	defaultCharset = "UTF-8" | ||||
| ) | ||||
| 
 | ||||
| var helperFuncs = template.FuncMap{ | ||||
| 	"yield": func() (string, error) { | ||||
| 		return "", fmt.Errorf("yield called with no layout defined") | ||||
| 	}, | ||||
| } | ||||
| 
 | ||||
| type Delims struct { | ||||
| 	Left string | ||||
| 
 | ||||
| 	Right string | ||||
| } | ||||
| 
 | ||||
| type RenderOptions struct { | ||||
| 	Directory string | ||||
| 
 | ||||
| 	Layout string | ||||
| 
 | ||||
| 	Extensions []string | ||||
| 
 | ||||
| 	Funcs []template.FuncMap | ||||
| 
 | ||||
| 	Delims Delims | ||||
| 
 | ||||
| 	Charset string | ||||
| 
 | ||||
| 	IndentJSON bool | ||||
| 
 | ||||
| 	HTMLContentType string | ||||
| } | ||||
| 
 | ||||
| type HTMLOptions struct { | ||||
| 	Layout string | ||||
| } | ||||
| 
 | ||||
| func Renderer(options ...RenderOptions) martini.Handler { | ||||
| 	opt := prepareOptions(options) | ||||
| 	cs := prepareCharset(opt.Charset) | ||||
| 	t := compile(opt) | ||||
| 	return func(res http.ResponseWriter, req *http.Request, c martini.Context) { | ||||
| 		var tc *template.Template | ||||
| 		if martini.Env == martini.Dev { | ||||
| 
 | ||||
| 			tc = compile(opt) | ||||
| 		} else { | ||||
| 
 | ||||
| 			tc, _ = t.Clone() | ||||
| 		} | ||||
| 
 | ||||
| 		rd := &Render{res, req, tc, opt, cs, base.TmplData{}, time.Time{}} | ||||
| 
 | ||||
| 		rd.Data["TmplLoadTimes"] = func() string { | ||||
| 			if rd.startTime.IsZero() { | ||||
| 				return "" | ||||
| 			} | ||||
| 			return fmt.Sprint(time.Since(rd.startTime).Nanoseconds()/1e6) + "ms" | ||||
| 		} | ||||
| 
 | ||||
| 		c.Map(rd.Data) | ||||
| 		c.Map(rd) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func prepareCharset(charset string) string { | ||||
| 	if len(charset) != 0 { | ||||
| 		return "; charset=" + charset | ||||
| 	} | ||||
| 
 | ||||
| 	return "; charset=" + defaultCharset | ||||
| } | ||||
| 
 | ||||
| func prepareOptions(options []RenderOptions) RenderOptions { | ||||
| 	var opt RenderOptions | ||||
| 	if len(options) > 0 { | ||||
| 		opt = options[0] | ||||
| 	} | ||||
| 
 | ||||
| 	if len(opt.Directory) == 0 { | ||||
| 		opt.Directory = "templates" | ||||
| 	} | ||||
| 	if len(opt.Extensions) == 0 { | ||||
| 		opt.Extensions = []string{".tmpl"} | ||||
| 	} | ||||
| 	if len(opt.HTMLContentType) == 0 { | ||||
| 		opt.HTMLContentType = ContentHTML | ||||
| 	} | ||||
| 
 | ||||
| 	return opt | ||||
| } | ||||
| 
 | ||||
| func compile(options RenderOptions) *template.Template { | ||||
| 	dir := options.Directory | ||||
| 	t := template.New(dir) | ||||
| 	t.Delims(options.Delims.Left, options.Delims.Right) | ||||
| 
 | ||||
| 	template.Must(t.Parse("Martini")) | ||||
| 
 | ||||
| 	filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { | ||||
| 		r, err := filepath.Rel(dir, path) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		ext := filepath.Ext(r) | ||||
| 		for _, extension := range options.Extensions { | ||||
| 			if ext == extension { | ||||
| 
 | ||||
| 				buf, err := ioutil.ReadFile(path) | ||||
| 				if err != nil { | ||||
| 					panic(err) | ||||
| 				} | ||||
| 
 | ||||
| 				name := (r[0 : len(r)-len(ext)]) | ||||
| 				tmpl := t.New(filepath.ToSlash(name)) | ||||
| 
 | ||||
| 				for _, funcs := range options.Funcs { | ||||
| 					tmpl = tmpl.Funcs(funcs) | ||||
| 				} | ||||
| 
 | ||||
| 				template.Must(tmpl.Funcs(helperFuncs).Parse(string(buf))) | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		return nil | ||||
| 	}) | ||||
| 
 | ||||
| 	return t | ||||
| } | ||||
| 
 | ||||
| type Render struct { | ||||
| 	http.ResponseWriter | ||||
| 	req             *http.Request | ||||
| 	t               *template.Template | ||||
| 	opt             RenderOptions | ||||
| 	compiledCharset string | ||||
| 
 | ||||
| 	Data base.TmplData | ||||
| 
 | ||||
| 	startTime time.Time | ||||
| } | ||||
| 
 | ||||
| func (r *Render) JSON(status int, v interface{}) { | ||||
| 	var result []byte | ||||
| 	var err error | ||||
| 	if r.opt.IndentJSON { | ||||
| 		result, err = json.MarshalIndent(v, "", "  ") | ||||
| 	} else { | ||||
| 		result, err = json.Marshal(v) | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		http.Error(r, err.Error(), 500) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	r.Header().Set(ContentType, ContentJSON+r.compiledCharset) | ||||
| 	r.WriteHeader(status) | ||||
| 	r.Write(result) | ||||
| } | ||||
| 
 | ||||
| func (r *Render) JSONString(v interface{}) (string, error) { | ||||
| 	var result []byte | ||||
| 	var err error | ||||
| 	if r.opt.IndentJSON { | ||||
| 		result, err = json.MarshalIndent(v, "", "  ") | ||||
| 	} else { | ||||
| 		result, err = json.Marshal(v) | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	return string(result), nil | ||||
| } | ||||
| 
 | ||||
| func (r *Render) renderBytes(name string, binding interface{}, htmlOpt ...HTMLOptions) (*bytes.Buffer, error) { | ||||
| 	opt := r.prepareHTMLOptions(htmlOpt) | ||||
| 
 | ||||
| 	if len(opt.Layout) > 0 { | ||||
| 		r.addYield(name, binding) | ||||
| 		name = opt.Layout | ||||
| 	} | ||||
| 
 | ||||
| 	out, err := r.execute(name, binding) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return out, nil | ||||
| } | ||||
| 
 | ||||
| func (r *Render) HTML(status int, name string, binding interface{}, htmlOpt ...HTMLOptions) { | ||||
| 	r.startTime = time.Now() | ||||
| 
 | ||||
| 	out, err := r.renderBytes(name, binding, htmlOpt...) | ||||
| 	if err != nil { | ||||
| 		http.Error(r, err.Error(), http.StatusInternalServerError) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	r.Header().Set(ContentType, r.opt.HTMLContentType+r.compiledCharset) | ||||
| 	r.WriteHeader(status) | ||||
| 	io.Copy(r, out) | ||||
| } | ||||
| 
 | ||||
| func (r *Render) HTMLString(name string, binding interface{}, htmlOpt ...HTMLOptions) (string, error) { | ||||
| 	if out, err := r.renderBytes(name, binding, htmlOpt...); err != nil { | ||||
| 		return "", err | ||||
| 	} else { | ||||
| 		return out.String(), nil | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (r *Render) Error(status int, message ...string) { | ||||
| 	r.WriteHeader(status) | ||||
| 	if len(message) > 0 { | ||||
| 		r.Write([]byte(message[0])) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (r *Render) Redirect(location string, status ...int) { | ||||
| 	code := http.StatusFound | ||||
| 	if len(status) == 1 { | ||||
| 		code = status[0] | ||||
| 	} | ||||
| 
 | ||||
| 	http.Redirect(r, r.req, location, code) | ||||
| } | ||||
| 
 | ||||
| func (r *Render) Template() *template.Template { | ||||
| 	return r.t | ||||
| } | ||||
| 
 | ||||
| func (r *Render) execute(name string, binding interface{}) (*bytes.Buffer, error) { | ||||
| 	buf := new(bytes.Buffer) | ||||
| 	return buf, r.t.ExecuteTemplate(buf, name, binding) | ||||
| } | ||||
| 
 | ||||
| func (r *Render) addYield(name string, binding interface{}) { | ||||
| 	funcs := template.FuncMap{ | ||||
| 		"yield": func() (template.HTML, error) { | ||||
| 			buf, err := r.execute(name, binding) | ||||
| 
 | ||||
| 			return template.HTML(buf.String()), err | ||||
| 		}, | ||||
| 	} | ||||
| 	r.t.Funcs(funcs) | ||||
| } | ||||
| 
 | ||||
| func (r *Render) prepareHTMLOptions(htmlOpt []HTMLOptions) HTMLOptions { | ||||
| 	if len(htmlOpt) > 0 { | ||||
| 		return htmlOpt[0] | ||||
| 	} | ||||
| 
 | ||||
| 	return HTMLOptions{ | ||||
| 		Layout: r.opt.Layout, | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										163
									
								
								modules/middleware/repo.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								modules/middleware/repo.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,163 @@ | |||
| // 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 middleware | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/go-martini/martini" | ||||
| 
 | ||||
| 	"github.com/gogits/git" | ||||
| 
 | ||||
| 	"github.com/gogits/gogs/models" | ||||
| 	"github.com/gogits/gogs/modules/base" | ||||
| ) | ||||
| 
 | ||||
| func RepoAssignment(redirect bool, args ...bool) martini.Handler { | ||||
| 	return func(ctx *Context, params martini.Params) { | ||||
| 		// valid brachname | ||||
| 		var validBranch bool | ||||
| 		// display bare quick start if it is a bare repo | ||||
| 		var displayBare bool | ||||
| 
 | ||||
| 		if len(args) >= 1 { | ||||
| 			validBranch = args[0] | ||||
| 		} | ||||
| 
 | ||||
| 		if len(args) >= 2 { | ||||
| 			displayBare = args[1] | ||||
| 		} | ||||
| 
 | ||||
| 		var ( | ||||
| 			user *models.User | ||||
| 			err  error | ||||
| 		) | ||||
| 
 | ||||
| 		userName := params["username"] | ||||
| 		repoName := params["reponame"] | ||||
| 		branchName := params["branchname"] | ||||
| 
 | ||||
| 		// get repository owner | ||||
| 		ctx.Repo.IsOwner = ctx.IsSigned && ctx.User.LowerName == strings.ToLower(userName) | ||||
| 
 | ||||
| 		if !ctx.Repo.IsOwner { | ||||
| 			user, err = models.GetUserByName(params["username"]) | ||||
| 			if err != nil { | ||||
| 				if redirect { | ||||
| 					ctx.Redirect("/") | ||||
| 					return | ||||
| 				} | ||||
| 				ctx.Handle(200, "RepoAssignment", err) | ||||
| 				return | ||||
| 			} | ||||
| 		} else { | ||||
| 			user = ctx.User | ||||
| 		} | ||||
| 
 | ||||
| 		if user == nil { | ||||
| 			if redirect { | ||||
| 				ctx.Redirect("/") | ||||
| 				return | ||||
| 			} | ||||
| 			ctx.Handle(200, "RepoAssignment", errors.New("invliad user account for single repository")) | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		// get repository | ||||
| 		repo, err := models.GetRepositoryByName(user.Id, repoName) | ||||
| 		if err != nil { | ||||
| 			if err == models.ErrRepoNotExist { | ||||
| 				ctx.Handle(404, "RepoAssignment", err) | ||||
| 			} else if redirect { | ||||
| 				ctx.Redirect("/") | ||||
| 				return | ||||
| 			} | ||||
| 			ctx.Handle(404, "RepoAssignment", err) | ||||
| 			return | ||||
| 		} | ||||
| 		repo.NumOpenIssues = repo.NumIssues - repo.NumClosedIssues | ||||
| 		ctx.Repo.Repository = repo | ||||
| 
 | ||||
| 		ctx.Data["IsBareRepo"] = ctx.Repo.Repository.IsBare | ||||
| 
 | ||||
| 		gitRepo, err := git.OpenRepository(models.RepoPath(userName, repoName)) | ||||
| 		if err != nil { | ||||
| 			ctx.Handle(404, "RepoAssignment Invalid repo "+models.RepoPath(userName, repoName), err) | ||||
| 			return | ||||
| 		} | ||||
| 		ctx.Repo.GitRepo = gitRepo | ||||
| 
 | ||||
| 		ctx.Repo.Owner = user | ||||
| 		ctx.Repo.RepoLink = "/" + user.Name + "/" + repo.Name | ||||
| 
 | ||||
| 		ctx.Data["Title"] = user.Name + "/" + repo.Name | ||||
| 		ctx.Data["Repository"] = repo | ||||
| 		ctx.Data["Owner"] = user | ||||
| 		ctx.Data["RepoLink"] = ctx.Repo.RepoLink | ||||
| 		ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner | ||||
| 		ctx.Data["BranchName"] = "" | ||||
| 
 | ||||
| 		ctx.Repo.CloneLink.SSH = fmt.Sprintf("%s@%s:%s/%s.git", base.RunUser, base.Domain, user.LowerName, repo.LowerName) | ||||
| 		ctx.Repo.CloneLink.HTTPS = fmt.Sprintf("%s%s/%s.git", base.AppUrl, user.LowerName, repo.LowerName) | ||||
| 		ctx.Data["CloneLink"] = ctx.Repo.CloneLink | ||||
| 
 | ||||
| 		// when repo is bare, not valid branch | ||||
| 		if !ctx.Repo.Repository.IsBare && validBranch { | ||||
| 		detect: | ||||
| 			if len(branchName) > 0 { | ||||
| 				// TODO check tag | ||||
| 				if models.IsBranchExist(user.Name, repoName, branchName) { | ||||
| 					ctx.Repo.IsBranch = true | ||||
| 					ctx.Repo.BranchName = branchName | ||||
| 
 | ||||
| 					ctx.Repo.Commit, err = gitRepo.GetCommitOfBranch(branchName) | ||||
| 					if err != nil { | ||||
| 						ctx.Handle(404, "RepoAssignment invalid branch", nil) | ||||
| 						return | ||||
| 					} | ||||
| 
 | ||||
| 					ctx.Repo.CommitId = ctx.Repo.Commit.Oid.String() | ||||
| 
 | ||||
| 				} else if len(branchName) == 40 { | ||||
| 					ctx.Repo.IsCommit = true | ||||
| 					ctx.Repo.CommitId = branchName | ||||
| 					ctx.Repo.BranchName = branchName | ||||
| 
 | ||||
| 					ctx.Repo.Commit, err = gitRepo.GetCommit(branchName) | ||||
| 					if err != nil { | ||||
| 						ctx.Handle(404, "RepoAssignment invalid commit", nil) | ||||
| 						return | ||||
| 					} | ||||
| 				} else { | ||||
| 					ctx.Handle(404, "RepoAssignment invalid repo", nil) | ||||
| 					return | ||||
| 				} | ||||
| 
 | ||||
| 			} else { | ||||
| 				branchName = "master" | ||||
| 				goto detect | ||||
| 			} | ||||
| 
 | ||||
| 			ctx.Data["IsBranch"] = ctx.Repo.IsBranch | ||||
| 			ctx.Data["IsCommit"] = ctx.Repo.IsCommit | ||||
| 		} | ||||
| 
 | ||||
| 		// repo is bare and display enable | ||||
| 		if displayBare && ctx.Repo.Repository.IsBare { | ||||
| 			ctx.HTML(200, "repo/single_bare") | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		if ctx.IsSigned { | ||||
| 			ctx.Repo.IsWatching = models.IsWatching(ctx.User.Id, repo.Id) | ||||
| 		} | ||||
| 
 | ||||
| 		ctx.Data["BranchName"] = ctx.Repo.BranchName | ||||
| 		ctx.Data["CommitId"] = ctx.Repo.CommitId | ||||
| 		ctx.Data["IsRepositoryWatching"] = ctx.Repo.IsWatching | ||||
| 	} | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue