Merge branch 'master' of github.com:shxsun/gogs
This commit is contained in:
		
						commit
						d945d0911b
					
				
					 12 changed files with 430 additions and 18 deletions
				
			
		|  | @ -9,13 +9,12 @@ github.com/Unknwon/com= | |||
| github.com/Unknwon/cae= | ||||
| github.com/Unknwon/goconfig= | ||||
| github.com/dchest/scrypt= | ||||
| github.com/go-sql-driver/mysql= | ||||
| github.com/lib/pq= | ||||
| github.com/lunny/xorm= | ||||
| github.com/gogits/logs= | ||||
| github.com/gogits/binding= | ||||
| github.com/gogits/git= | ||||
| github.com/gogits/gfm= | ||||
| github.com/gogits/cache= | ||||
| 
 | ||||
| [res] | ||||
| include=templates|public|conf | ||||
|  |  | |||
|  | @ -262,6 +262,17 @@ func initRepository(f string, user *User, repo *Repository, initReadme bool, rep | |||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	// hook/post-update
 | ||||
| 	pu2, err := os.OpenFile(filepath.Join(repoPath, "hooks", "post-receive"), os.O_CREATE|os.O_WRONLY, 0777) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	defer pu2.Close() | ||||
| 	// TODO: Windows .bat
 | ||||
| 	if _, err = pu2.WriteString("#!/usr/bin/env bash\ngit update-server-info\n"); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	// Initialize repository according to user's choice.
 | ||||
| 	fileName := map[string]string{} | ||||
| 	if initReadme { | ||||
|  |  | |||
|  | @ -72,7 +72,7 @@ func (user *User) HomeLink() string { | |||
| 
 | ||||
| // AvatarLink returns the user gravatar link.
 | ||||
| func (user *User) AvatarLink() string { | ||||
| 	return "http://1.gravatar.com/avatar/" + user.Avatar | ||||
| 	return "/avatar/" + user.Avatar | ||||
| } | ||||
| 
 | ||||
| // NewGitSig generates and returns the signature of given user.
 | ||||
|  |  | |||
							
								
								
									
										298
									
								
								modules/avatar/avatar.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										298
									
								
								modules/avatar/avatar.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,298 @@ | |||
| // 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.
 | ||||
| 
 | ||||
| // for www.gravatar.com image cache
 | ||||
| package avatar | ||||
| 
 | ||||
| import ( | ||||
| 	"crypto/md5" | ||||
| 	"encoding/hex" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"image" | ||||
| 	"image/jpeg" | ||||
| 	"image/png" | ||||
| 	"io" | ||||
| 	"log" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/nfnt/resize" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	gravatar = "http://www.gravatar.com/avatar" | ||||
| ) | ||||
| 
 | ||||
| func debug(a ...interface{}) { | ||||
| 	if true { | ||||
| 		log.Println(a...) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // hash email to md5 string
 | ||||
| // keep this func in order to make this package indenpent
 | ||||
| func HashEmail(email string) string { | ||||
| 	h := md5.New() | ||||
| 	h.Write([]byte(strings.ToLower(email))) | ||||
| 	return hex.EncodeToString(h.Sum(nil)) | ||||
| } | ||||
| 
 | ||||
| type Avatar struct { | ||||
| 	Hash           string | ||||
| 	AlterImage     string // image path
 | ||||
| 	cacheDir       string // image save dir
 | ||||
| 	reqParams      string | ||||
| 	imagePath      string | ||||
| 	expireDuration time.Duration | ||||
| } | ||||
| 
 | ||||
| func New(hash string, cacheDir string) *Avatar { | ||||
| 	return &Avatar{ | ||||
| 		Hash:           hash, | ||||
| 		cacheDir:       cacheDir, | ||||
| 		expireDuration: time.Minute * 10, | ||||
| 		reqParams: url.Values{ | ||||
| 			"d":    {"retro"}, | ||||
| 			"size": {"200"}, | ||||
| 			"r":    {"pg"}}.Encode(), | ||||
| 		imagePath: filepath.Join(cacheDir, hash+".image"), //maybe png or jpeg
 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (this *Avatar) HasCache() bool { | ||||
| 	fileInfo, err := os.Stat(this.imagePath) | ||||
| 	return err == nil && fileInfo.Mode().IsRegular() | ||||
| } | ||||
| 
 | ||||
| func (this *Avatar) Modtime() (modtime time.Time, err error) { | ||||
| 	fileInfo, err := os.Stat(this.imagePath) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	return fileInfo.ModTime(), nil | ||||
| } | ||||
| 
 | ||||
| func (this *Avatar) Expired() bool { | ||||
| 	modtime, err := this.Modtime() | ||||
| 	return err != nil || time.Since(modtime) > this.expireDuration | ||||
| } | ||||
| 
 | ||||
| // default image format: jpeg
 | ||||
| func (this *Avatar) Encode(wr io.Writer, size int) (err error) { | ||||
| 	var img image.Image | ||||
| 	decodeImageFile := func(file string) (img image.Image, err error) { | ||||
| 		fd, err := os.Open(file) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		defer fd.Close() | ||||
| 		img, err = jpeg.Decode(fd) | ||||
| 		if err != nil { | ||||
| 			fd.Seek(0, os.SEEK_SET) | ||||
| 			img, err = png.Decode(fd) | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
| 	imgPath := this.imagePath | ||||
| 	if !this.HasCache() { | ||||
| 		if this.AlterImage == "" { | ||||
| 			return errors.New("request image failed, and no alt image offered") | ||||
| 		} | ||||
| 		imgPath = this.AlterImage | ||||
| 	} | ||||
| 	img, err = decodeImageFile(imgPath) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	m := resize.Resize(uint(size), 0, img, resize.Lanczos3) | ||||
| 	return jpeg.Encode(wr, m, nil) | ||||
| } | ||||
| 
 | ||||
| // get image from gravatar.com
 | ||||
| func (this *Avatar) Update() { | ||||
| 	thunder.Fetch(gravatar+"/"+this.Hash+"?"+this.reqParams, | ||||
| 		this.imagePath) | ||||
| } | ||||
| 
 | ||||
| func (this *Avatar) UpdateTimeout(timeout time.Duration) error { | ||||
| 	var err error | ||||
| 	select { | ||||
| 	case <-time.After(timeout): | ||||
| 		err = errors.New("get gravatar image timeout") | ||||
| 	case err = <-thunder.GoFetch(gravatar+"/"+this.Hash+"?"+this.reqParams, | ||||
| 		this.imagePath): | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| type avatarHandler struct { | ||||
| 	cacheDir string | ||||
| 	altImage string | ||||
| } | ||||
| 
 | ||||
| func (this *avatarHandler) mustInt(r *http.Request, defaultValue int, keys ...string) int { | ||||
| 	var v int | ||||
| 	for _, k := range keys { | ||||
| 		if _, err := fmt.Sscanf(r.FormValue(k), "%d", &v); err == nil { | ||||
| 			defaultValue = v | ||||
| 		} | ||||
| 	} | ||||
| 	return defaultValue | ||||
| } | ||||
| 
 | ||||
| func (this *avatarHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||||
| 	urlPath := r.URL.Path | ||||
| 	hash := urlPath[strings.LastIndex(urlPath, "/")+1:] | ||||
| 	//hash = HashEmail(hash)
 | ||||
| 	size := this.mustInt(r, 80, "s", "size") // size = 80*80
 | ||||
| 
 | ||||
| 	avatar := New(hash, this.cacheDir) | ||||
| 	avatar.AlterImage = this.altImage | ||||
| 	if avatar.Expired() { | ||||
| 		err := avatar.UpdateTimeout(time.Millisecond * 500) | ||||
| 		if err != nil { | ||||
| 			debug(err) | ||||
| 			//log.Trace("avatar update error: %v", err)
 | ||||
| 		} | ||||
| 	} | ||||
| 	if modtime, err := avatar.Modtime(); err == nil { | ||||
| 		etag := fmt.Sprintf("size(%d)", size) | ||||
| 		if t, err := time.Parse(http.TimeFormat, r.Header.Get("If-Modified-Since")); err == nil && modtime.Before(t.Add(1*time.Second)) && etag == r.Header.Get("If-None-Match") { | ||||
| 			h := w.Header() | ||||
| 			delete(h, "Content-Type") | ||||
| 			delete(h, "Content-Length") | ||||
| 			w.WriteHeader(http.StatusNotModified) | ||||
| 			return | ||||
| 		} | ||||
| 		w.Header().Set("Last-Modified", modtime.UTC().Format(http.TimeFormat)) | ||||
| 		w.Header().Set("ETag", etag) | ||||
| 	} | ||||
| 	w.Header().Set("Content-Type", "image/jpeg") | ||||
| 	err := avatar.Encode(w, size) | ||||
| 	if err != nil { | ||||
| 		//log.Warn("avatar encode error: %v", err) // will panic when err != nil
 | ||||
| 		debug(err) | ||||
| 		w.WriteHeader(500) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // http.Handle("/avatar/", avatar.HttpHandler("./cache"))
 | ||||
| func HttpHandler(cacheDir string, defaultImgPath string) http.Handler { | ||||
| 	return &avatarHandler{ | ||||
| 		cacheDir: cacheDir, | ||||
| 		altImage: defaultImgPath, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // thunder downloader
 | ||||
| var thunder = &Thunder{QueueSize: 10} | ||||
| 
 | ||||
| type Thunder struct { | ||||
| 	QueueSize int // download queue size
 | ||||
| 	q         chan *thunderTask | ||||
| 	once      sync.Once | ||||
| } | ||||
| 
 | ||||
| func (t *Thunder) init() { | ||||
| 	if t.QueueSize < 1 { | ||||
| 		t.QueueSize = 1 | ||||
| 	} | ||||
| 	t.q = make(chan *thunderTask, t.QueueSize) | ||||
| 	for i := 0; i < t.QueueSize; i++ { | ||||
| 		go func() { | ||||
| 			for { | ||||
| 				task := <-t.q | ||||
| 				task.Fetch() | ||||
| 			} | ||||
| 		}() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (t *Thunder) Fetch(url string, saveFile string) error { | ||||
| 	t.once.Do(t.init) | ||||
| 	task := &thunderTask{ | ||||
| 		Url:      url, | ||||
| 		SaveFile: saveFile, | ||||
| 	} | ||||
| 	task.Add(1) | ||||
| 	t.q <- task | ||||
| 	task.Wait() | ||||
| 	return task.err | ||||
| } | ||||
| 
 | ||||
| func (t *Thunder) GoFetch(url, saveFile string) chan error { | ||||
| 	c := make(chan error) | ||||
| 	go func() { | ||||
| 		c <- t.Fetch(url, saveFile) | ||||
| 	}() | ||||
| 	return c | ||||
| } | ||||
| 
 | ||||
| // thunder download
 | ||||
| type thunderTask struct { | ||||
| 	Url      string | ||||
| 	SaveFile string | ||||
| 	sync.WaitGroup | ||||
| 	err error | ||||
| } | ||||
| 
 | ||||
| func (this *thunderTask) Fetch() { | ||||
| 	this.err = this.fetch() | ||||
| 	this.Done() | ||||
| } | ||||
| 
 | ||||
| var client = &http.Client{} | ||||
| 
 | ||||
| func (this *thunderTask) fetch() error { | ||||
| 	//log.Println("thunder, fetch", this.Url)
 | ||||
| 	req, _ := http.NewRequest("GET", this.Url, nil) | ||||
| 	req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8") | ||||
| 	req.Header.Set("Accept-Encoding", "gzip,deflate,sdch") | ||||
| 	req.Header.Set("Accept-Language", "zh-CN,zh;q=0.8") | ||||
| 	req.Header.Set("Cache-Control", "no-cache") | ||||
| 	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.154 Safari/537.36") | ||||
| 	resp, err := client.Do(req) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
| 	if resp.StatusCode != 200 { | ||||
| 		return fmt.Errorf("status code: %d", resp.StatusCode) | ||||
| 	} | ||||
| 
 | ||||
| 	/* | ||||
| 		log.Println("headers:", resp.Header) | ||||
| 		switch resp.Header.Get("Content-Type") { | ||||
| 		case "image/jpeg": | ||||
| 			this.SaveFile += ".jpeg" | ||||
| 		case "image/png": | ||||
| 			this.SaveFile += ".png" | ||||
| 		} | ||||
| 	*/ | ||||
| 	/* | ||||
| 		imgType := resp.Header.Get("Content-Type") | ||||
| 		if imgType != "image/jpeg" && imgType != "image/png" { | ||||
| 			return errors.New("not png or jpeg") | ||||
| 		} | ||||
| 	*/ | ||||
| 
 | ||||
| 	tmpFile := this.SaveFile + ".part" // mv to destination when finished
 | ||||
| 	fd, err := os.Create(tmpFile) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	_, err = io.Copy(fd, resp.Body) | ||||
| 	fd.Close() | ||||
| 	if err != nil { | ||||
| 		os.Remove(tmpFile) | ||||
| 		return err | ||||
| 	} | ||||
| 	return os.Rename(tmpFile, this.SaveFile) | ||||
| } | ||||
							
								
								
									
										56
									
								
								modules/avatar/avatar_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								modules/avatar/avatar_test.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,56 @@ | |||
| // 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 avatar_test | ||||
| 
 | ||||
| import ( | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"strconv" | ||||
| 	"testing" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/gogits/gogs/modules/avatar" | ||||
| ) | ||||
| 
 | ||||
| const TMPDIR = "test-avatar" | ||||
| 
 | ||||
| func TestFetch(t *testing.T) { | ||||
| 	os.Mkdir(TMPDIR, 0755) | ||||
| 	defer os.RemoveAll(TMPDIR) | ||||
| 
 | ||||
| 	hash := avatar.HashEmail("ssx205@gmail.com") | ||||
| 	a := avatar.New(hash, TMPDIR) | ||||
| 	a.UpdateTimeout(time.Millisecond * 200) | ||||
| } | ||||
| 
 | ||||
| func TestFetchMany(t *testing.T) { | ||||
| 	os.Mkdir(TMPDIR, 0755) | ||||
| 	defer os.RemoveAll(TMPDIR) | ||||
| 
 | ||||
| 	log.Println("start") | ||||
| 	var n = 5 | ||||
| 	ch := make(chan bool, n) | ||||
| 	for i := 0; i < n; i++ { | ||||
| 		go func(i int) { | ||||
| 			hash := avatar.HashEmail(strconv.Itoa(i) + "ssx205@gmail.com") | ||||
| 			a := avatar.New(hash, TMPDIR) | ||||
| 			a.Update() | ||||
| 			log.Println("finish", hash) | ||||
| 			ch <- true | ||||
| 		}(i) | ||||
| 	} | ||||
| 	for i := 0; i < n; i++ { | ||||
| 		<-ch | ||||
| 	} | ||||
| 	log.Println("end") | ||||
| } | ||||
| 
 | ||||
| // cat
 | ||||
| // wget http://www.artsjournal.com/artfulmanager/wp/wp-content/uploads/2013/12/200x200xmirror_cat.jpg.pagespeed.ic.GOZSv6v1_H.jpg -O default.jpg
 | ||||
| /* | ||||
| func TestHttp(t *testing.T) { | ||||
| 	http.Handle("/", avatar.HttpHandler("./", "default.jpg")) | ||||
| 	http.ListenAndServe(":8001", nil) | ||||
| } | ||||
| */ | ||||
|  | @ -43,6 +43,9 @@ var ( | |||
| 	Cache        cache.Cache | ||||
| 	CacheAdapter string | ||||
| 	CacheConfig  string | ||||
| 
 | ||||
| 	LogMode   string | ||||
| 	LogConfig string | ||||
| ) | ||||
| 
 | ||||
| var Service struct { | ||||
|  | @ -83,15 +86,15 @@ func newService() { | |||
| 
 | ||||
| func newLogService() { | ||||
| 	// Get and check log mode.
 | ||||
| 	mode := Cfg.MustValue("log", "MODE", "console") | ||||
| 	modeSec := "log." + mode | ||||
| 	LogMode = Cfg.MustValue("log", "MODE", "console") | ||||
| 	modeSec := "log." + LogMode | ||||
| 	if _, err := Cfg.GetSection(modeSec); err != nil { | ||||
| 		fmt.Printf("Unknown log mode: %s\n", mode) | ||||
| 		fmt.Printf("Unknown log mode: %s\n", LogMode) | ||||
| 		os.Exit(2) | ||||
| 	} | ||||
| 
 | ||||
| 	// Log level.
 | ||||
| 	levelName := Cfg.MustValue("log."+mode, "LEVEL", "Trace") | ||||
| 	levelName := Cfg.MustValue("log."+LogMode, "LEVEL", "Trace") | ||||
| 	level, ok := logLevels[levelName] | ||||
| 	if !ok { | ||||
| 		fmt.Printf("Unknown log level: %s\n", levelName) | ||||
|  | @ -99,14 +102,13 @@ func newLogService() { | |||
| 	} | ||||
| 
 | ||||
| 	// Generate log configuration.
 | ||||
| 	var config string | ||||
| 	switch mode { | ||||
| 	switch LogMode { | ||||
| 	case "console": | ||||
| 		config = fmt.Sprintf(`{"level":%s}`, level) | ||||
| 		LogConfig = fmt.Sprintf(`{"level":%s}`, level) | ||||
| 	case "file": | ||||
| 		logPath := Cfg.MustValue(modeSec, "FILE_NAME", "log/gogs.log") | ||||
| 		os.MkdirAll(path.Dir(logPath), os.ModePerm) | ||||
| 		config = fmt.Sprintf( | ||||
| 		LogConfig = fmt.Sprintf( | ||||
| 			`{"level":%s,"filename":%s,"rotate":%v,"maxlines":%d,"maxsize",%d,"daily":%v,"maxdays":%d}`, level, | ||||
| 			logPath, | ||||
| 			Cfg.MustBool(modeSec, "LOG_ROTATE", true), | ||||
|  | @ -115,13 +117,13 @@ func newLogService() { | |||
| 			Cfg.MustBool(modeSec, "DAILY_ROTATE", true), | ||||
| 			Cfg.MustInt(modeSec, "MAX_DAYS", 7)) | ||||
| 	case "conn": | ||||
| 		config = fmt.Sprintf(`{"level":%s,"reconnectOnMsg":%v,"reconnect":%v,"net":%s,"addr":%s}`, level, | ||||
| 		LogConfig = fmt.Sprintf(`{"level":%s,"reconnectOnMsg":%v,"reconnect":%v,"net":%s,"addr":%s}`, level, | ||||
| 			Cfg.MustBool(modeSec, "RECONNECT_ON_MSG", false), | ||||
| 			Cfg.MustBool(modeSec, "RECONNECT", false), | ||||
| 			Cfg.MustValue(modeSec, "PROTOCOL", "tcp"), | ||||
| 			Cfg.MustValue(modeSec, "ADDR", ":7020")) | ||||
| 	case "smtp": | ||||
| 		config = fmt.Sprintf(`{"level":%s,"username":%s,"password":%s,"host":%s,"sendTos":%s,"subject":%s}`, level, | ||||
| 		LogConfig = fmt.Sprintf(`{"level":%s,"username":%s,"password":%s,"host":%s,"sendTos":%s,"subject":%s}`, level, | ||||
| 			Cfg.MustValue(modeSec, "USER", "example@example.com"), | ||||
| 			Cfg.MustValue(modeSec, "PASSWD", "******"), | ||||
| 			Cfg.MustValue(modeSec, "HOST", "127.0.0.1:25"), | ||||
|  | @ -129,8 +131,8 @@ func newLogService() { | |||
| 			Cfg.MustValue(modeSec, "SUBJECT", "Diagnostic message from serve")) | ||||
| 	} | ||||
| 
 | ||||
| 	log.NewLogger(Cfg.MustInt64("log", "BUFFER_LEN", 10000), mode, config) | ||||
| 	log.Info("Log Mode: %s(%s)", strings.Title(mode), levelName) | ||||
| 	log.NewLogger(Cfg.MustInt64("log", "BUFFER_LEN", 10000), LogMode, LogConfig) | ||||
| 	log.Info("Log Mode: %s(%s)", strings.Title(LogMode), levelName) | ||||
| } | ||||
| 
 | ||||
| func newCacheService() { | ||||
|  |  | |||
|  | @ -98,7 +98,7 @@ func CreateTimeLimitCode(data string, minutes int, startInf interface{}) string | |||
| 
 | ||||
| // AvatarLink returns avatar link by given e-mail.
 | ||||
| func AvatarLink(email string) string { | ||||
| 	return "http://1.gravatar.com/avatar/" + EncodeMd5(email) | ||||
| 	return "/avatar/" + EncodeMd5(email) | ||||
| } | ||||
| 
 | ||||
| // Seconds-based time units
 | ||||
|  |  | |||
							
								
								
									
										
											BIN
										
									
								
								public/img/avatar/default.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/img/avatar/default.jpg
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 17 KiB | 
|  | @ -70,5 +70,8 @@ func Config(ctx *middleware.Context) { | |||
| 	ctx.Data["CacheAdapter"] = base.CacheAdapter | ||||
| 	ctx.Data["CacheConfig"] = base.CacheConfig | ||||
| 
 | ||||
| 	ctx.Data["LogMode"] = base.LogMode | ||||
| 	ctx.Data["LogConfig"] = base.LogConfig | ||||
| 
 | ||||
| 	ctx.HTML(200, "admin/config") | ||||
| } | ||||
|  |  | |||
|  | @ -11,6 +11,7 @@ import ( | |||
| 	"github.com/codegangsta/martini" | ||||
| 
 | ||||
| 	"github.com/gogits/git" | ||||
| 	"github.com/gogits/webdav" | ||||
| 
 | ||||
| 	"github.com/gogits/gogs/models" | ||||
| 	"github.com/gogits/gogs/modules/base" | ||||
|  | @ -192,6 +193,29 @@ func Single(ctx *middleware.Context, params martini.Params) { | |||
| 	ctx.HTML(200, "repo/single") | ||||
| } | ||||
| 
 | ||||
| func Http(ctx *middleware.Context, params martini.Params) { | ||||
| 	/*if !ctx.Repo.IsValid { | ||||
| 		return | ||||
| 	}*/ | ||||
| 
 | ||||
| 	// TODO: access check
 | ||||
| 
 | ||||
| 	username := params["username"] | ||||
| 	reponame := params["reponame"] | ||||
| 	if strings.HasSuffix(reponame, ".git") { | ||||
| 		reponame = reponame[:len(reponame)-4] | ||||
| 	} | ||||
| 
 | ||||
| 	prefix := path.Join("/", username, params["reponame"]) | ||||
| 	server := &webdav.Server{ | ||||
| 		Fs:         webdav.Dir(models.RepoPath(username, reponame)), | ||||
| 		TrimPrefix: prefix, | ||||
| 		Listings:   true, | ||||
| 	} | ||||
| 
 | ||||
| 	server.ServeHTTP(ctx.ResponseWriter, ctx.Req) | ||||
| } | ||||
| 
 | ||||
| func Setting(ctx *middleware.Context, params martini.Params) { | ||||
| 	if !ctx.Repo.IsOwner { | ||||
| 		ctx.Error(404) | ||||
|  |  | |||
|  | @ -71,7 +71,21 @@ | |||
| 
 | ||||
|             <div class="panel-body"> | ||||
|                 <div><b>Cache Adapter:</b> {{.CacheAdapter}}</div> | ||||
|                 <div><b>Cache Config:</b> <code>{{.CacheConfig}}</code></div> | ||||
|                 <div><b>Cache Config:</b></div> | ||||
|                 <div style="padding-top: 5px;"><pre>{{.CacheConfig}}</pre></div> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="panel panel-default"> | ||||
|             <div class="panel-heading"> | ||||
|                 Log Configuration | ||||
|             </div> | ||||
| 
 | ||||
|             <div class="panel-body"> | ||||
|                 <div><b>Log Mode:</b> {{.LogMode}}</div> | ||||
|                 <div><b>Log Config:</b></div> | ||||
|                 <div style="padding-top: 5px;"><pre>{{.LogConfig}}</pre></div> | ||||
|                  | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
|  |  | |||
							
								
								
									
										7
									
								
								web.go
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								web.go
									
									
									
									
									
								
							|  | @ -18,6 +18,7 @@ import ( | |||
| 
 | ||||
| 	"github.com/gogits/gogs/models" | ||||
| 	"github.com/gogits/gogs/modules/auth" | ||||
| 	"github.com/gogits/gogs/modules/avatar" | ||||
| 	"github.com/gogits/gogs/modules/base" | ||||
| 	"github.com/gogits/gogs/modules/log" | ||||
| 	"github.com/gogits/gogs/modules/mailer" | ||||
|  | @ -114,6 +115,9 @@ func runWeb(*cli.Context) { | |||
| 
 | ||||
| 	m.Get("/help", routers.Help) | ||||
| 
 | ||||
| 	avatarHandler := avatar.HttpHandler("public/img/avatar", "public/img/avatar/default.jpg") | ||||
| 	m.Get("/avatar/:hash", avatarHandler.ServeHTTP) | ||||
| 
 | ||||
| 	adminReq := middleware.AdminRequire() | ||||
| 	m.Get("/admin", reqSignIn, adminReq, admin.Dashboard) | ||||
| 	m.Get("/admin/users", reqSignIn, adminReq, admin.Users) | ||||
|  | @ -136,9 +140,10 @@ func runWeb(*cli.Context) { | |||
| 		ignSignIn, middleware.RepoAssignment(true), repo.Single) | ||||
| 	m.Get("/:username/:reponame/commit/:commitid/**", ignSignIn, middleware.RepoAssignment(true), repo.Single) | ||||
| 	m.Get("/:username/:reponame/commit/:commitid", ignSignIn, middleware.RepoAssignment(true), repo.Single) | ||||
| 
 | ||||
| 	m.Get("/:username/:reponame", ignSignIn, middleware.RepoAssignment(true), repo.Single) | ||||
| 
 | ||||
| 	m.Any("/:username/:reponame/**", ignSignIn, repo.Http) | ||||
| 
 | ||||
| 	if martini.Env == martini.Dev { | ||||
| 		m.Get("/template/**", dev.TemplatePreview) | ||||
| 	} | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue