From d725c41b56e072122faf539d5a14d36c18f5c312 Mon Sep 17 00:00:00 2001 From: skyblue Date: Fri, 21 Mar 2014 22:35:43 +0800 Subject: [PATCH 1/6] add CR in C++ gitignore And try if I can commit. --- conf/gitignore/C++ | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/gitignore/C++ b/conf/gitignore/C++ index 5a1b6ec431..620d3dc8a4 100644 --- a/conf/gitignore/C++ +++ b/conf/gitignore/C++ @@ -10,4 +10,4 @@ # Compiled Static libraries *.lai *.la -*.a \ No newline at end of file +*.a From 8e47ae21024bc35a82215e16f1e586f94ae622c9 Mon Sep 17 00:00:00 2001 From: skyblue Date: Sun, 23 Mar 2014 12:24:09 +0800 Subject: [PATCH 2/6] add avatar inorder to view code on github --- modules/avatar/avatar.go | 136 ++++++++++++++++++++++++++++++++++ modules/avatar/avatar_test.go | 35 +++++++++ 2 files changed, 171 insertions(+) create mode 100644 modules/avatar/avatar.go create mode 100644 modules/avatar/avatar_test.go diff --git a/modules/avatar/avatar.go b/modules/avatar/avatar.go new file mode 100644 index 0000000000..93f842eaef --- /dev/null +++ b/modules/avatar/avatar.go @@ -0,0 +1,136 @@ +package avatar + +import ( + "crypto/md5" + "encoding/hex" + "fmt" + "io" + "log" + "net/http" + "net/url" + "os" + "path/filepath" + "strings" + "sync" + "time" +) + +var gravatar = "http://www.gravatar.com/avatar" + +// hash email to md5 string +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 + cacheDir string // image save dir + reqParams string + imagePath string +} + +func New(hash string, cacheDir string) *Avatar { + return &Avatar{ + Hash: hash, + cacheDir: cacheDir, + reqParams: url.Values{ + "d": {"retro"}, + "size": {"200"}, + "r": {"pg"}}.Encode(), + imagePath: filepath.Join(cacheDir, hash+".jpg"), + } +} + +// get image from gravatar.com +func (this *Avatar) Update() { + thunder.Fetch(gravatar+"/"+this.Hash+"?"+this.reqParams, + this.Hash+".jpg") +} + +func (this *Avatar) UpdateTimeout(timeout time.Duration) { + select { + case <-time.After(timeout): + log.Println("timeout") + case <-thunder.GoFetch(gravatar+"/"+this.Hash+"?"+this.reqParams, + this.Hash+".jpg"): + } +} + +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() +} + +func (this *thunderTask) fetch() error { + resp, err := http.Get(this.Url) + if err != nil { + return err + } + defer resp.Body.Close() + if resp.StatusCode != 200 { + return fmt.Errorf("status code: %d", resp.StatusCode) + } + fd, err := os.Create(this.SaveFile) + if err != nil { + return err + } + defer fd.Close() + _, err = io.Copy(fd, resp.Body) + if err != nil { + return err + } + return nil +} diff --git a/modules/avatar/avatar_test.go b/modules/avatar/avatar_test.go new file mode 100644 index 0000000000..49f8f91f35 --- /dev/null +++ b/modules/avatar/avatar_test.go @@ -0,0 +1,35 @@ +package avatar + +import ( + "log" + "strconv" + "testing" + "time" +) + +func TestFetch(t *testing.T) { + hash := HashEmail("ssx205@gmail.com") + avatar := New(hash, "./") + //avatar.Update() + avatar.UpdateTimeout(time.Millisecond * 200) + time.Sleep(5 * time.Second) +} + +func TestFetchMany(t *testing.T) { + log.Println("start") + var n = 50 + ch := make(chan bool, n) + for i := 0; i < n; i++ { + go func(i int) { + hash := HashEmail(strconv.Itoa(i) + "ssx205@gmail.com") + avatar := New(hash, "./") + avatar.Update() + log.Println("finish", hash) + ch <- true + }(i) + } + for i := 0; i < n; i++ { + <-ch + } + log.Println("end") +} From 79604f553f45af658a884544187b00fb9fa3169c Mon Sep 17 00:00:00 2001 From: skyblue Date: Sun, 23 Mar 2014 15:55:27 +0800 Subject: [PATCH 3/6] fix download part problem, add png support --- modules/avatar/avatar.go | 179 +++++++++++++++++++++++++++++++++++---- 1 file changed, 162 insertions(+), 17 deletions(-) diff --git a/modules/avatar/avatar.go b/modules/avatar/avatar.go index 93f842eaef..55d1e13d94 100644 --- a/modules/avatar/avatar.go +++ b/modules/avatar/avatar.go @@ -3,7 +3,11 @@ package avatar import ( "crypto/md5" "encoding/hex" + "errors" "fmt" + "image" + "image/jpeg" + "image/png" "io" "log" "net/http" @@ -13,9 +17,14 @@ import ( "strings" "sync" "time" + + "github.com/nfnt/resize" ) -var gravatar = "http://www.gravatar.com/avatar" +var ( + gravatar = "http://www.gravatar.com/avatar" + defaultImagePath = "./default.jpg" +) // hash email to md5 string func HashEmail(email string) string { @@ -25,37 +34,145 @@ func HashEmail(email string) string { } type Avatar struct { - Hash string - cacheDir string // image save dir - reqParams string - imagePath string + Hash string + 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, + Hash: hash, + cacheDir: cacheDir, + expireDuration: time.Minute * 10, reqParams: url.Values{ "d": {"retro"}, "size": {"200"}, "r": {"pg"}}.Encode(), - imagePath: filepath.Join(cacheDir, hash+".jpg"), + imagePath: filepath.Join(cacheDir, hash+".image"), //maybe png or jpeg } } +func (this *Avatar) InCache() 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 { + if !this.InCache() { + return true + } + fileInfo, err := os.Stat(this.imagePath) + return err != nil || time.Since(fileInfo.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.InCache() { + imgPath = defaultImagePath + } + 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.Hash+".jpg") + this.imagePath) } -func (this *Avatar) UpdateTimeout(timeout time.Duration) { +func (this *Avatar) UpdateTimeout(timeout time.Duration) error { + var err error select { case <-time.After(timeout): - log.Println("timeout") - case <-thunder.GoFetch(gravatar+"/"+this.Hash+"?"+this.reqParams, - this.Hash+".jpg"): + err = errors.New("get gravatar image timeout") + case err = <-thunder.GoFetch(gravatar+"/"+this.Hash+"?"+this.reqParams, + this.imagePath): } + return err +} + +func init() { + log.SetFlags(log.Lshortfile | log.LstdFlags) +} + +// http.Handle("/avatar/", avatar.HttpHandler("./cache")) +func HttpHandler(cacheDir string) func(w http.ResponseWriter, r *http.Request) { + MustInt := func(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 + } + + return func(w http.ResponseWriter, r *http.Request) { + urlPath := r.URL.Path + hash := urlPath[strings.LastIndex(urlPath, "/")+1:] + hash = HashEmail(hash) + size := MustInt(r, 80, "s", "size") // size = 80*80 + + avatar := New(hash, cacheDir) + if avatar.Expired() { + err := avatar.UpdateTimeout(time.Millisecond * 500) + if err != nil { + log.Println(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.Println(err) + w.WriteHeader(500) + } + } +} + +func init() { + http.HandleFunc("/", HttpHandler("./")) + log.Fatal(http.ListenAndServe(":8001", nil)) } var thunder = &Thunder{QueueSize: 10} @@ -114,8 +231,17 @@ func (this *thunderTask) Fetch() { this.Done() } +var client = &http.Client{} + func (this *thunderTask) fetch() error { - resp, err := http.Get(this.Url) + 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 } @@ -123,14 +249,33 @@ func (this *thunderTask) fetch() error { if resp.StatusCode != 200 { return fmt.Errorf("status code: %d", resp.StatusCode) } - fd, err := os.Create(this.SaveFile) + + /* + 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 } - defer fd.Close() _, err = io.Copy(fd, resp.Body) + fd.Close() if err != nil { + os.Remove(tmpFile) return err } - return nil + return os.Rename(tmpFile, this.SaveFile) } From 964e537479c497a5ba42799a1c1a7c430720e990 Mon Sep 17 00:00:00 2001 From: Gogs Date: Sun, 23 Mar 2014 18:13:23 +0800 Subject: [PATCH 4/6] append route to web --- conf/app.ini | 8 +- models/user.go | 2 +- modules/avatar/avatar.go | 137 +++++++++++++++++++--------------- modules/avatar/avatar_test.go | 41 +++++++--- modules/base/tool.go | 2 +- public/img/avatar/default.jpg | Bin 0 -> 17379 bytes web.go | 5 +- 7 files changed, 118 insertions(+), 77 deletions(-) create mode 100644 public/img/avatar/default.jpg diff --git a/conf/app.ini b/conf/app.ini index ecb0d2511f..160aef0ffe 100644 --- a/conf/app.ini +++ b/conf/app.ini @@ -7,7 +7,7 @@ RUN_USER = lunny RUN_MODE = dev [repository] -ROOT = /Users/%(RUN_USER)s/git/gogs-repositories +ROOT = /home/work/%(RUN_USER)s/git/gogs-repositories LANG_IGNS = Google Go|C|C++|Python|Ruby|C Sharp LICENSES = Apache v2 License|GPL v2|MIT License|Affero GPL|Artistic License 2.0|BSD (3-Clause) License @@ -15,7 +15,7 @@ LICENSES = Apache v2 License|GPL v2|MIT License|Affero GPL|Artistic License 2.0| DOMAIN = localhost ROOT_URL = http://%(DOMAIN)s:%(HTTP_PORT)s/ HTTP_ADDR = -HTTP_PORT = 3000 +HTTP_PORT = 8002 [database] ; Either "mysql", "postgres" or "sqlite3"(binary release only), it's your choice @@ -23,7 +23,7 @@ DB_TYPE = mysql HOST = NAME = gogs USER = root -PASSWD = +PASSWD = toor ; For "postgres" only, either "disable", "require" or "verify-full" SSL_MODE = disable ; For "sqlite3" only @@ -120,4 +120,4 @@ HOST = USER = PASSWD = ; Receivers, can be one or more, e.g. ["1@example.com","2@example.com"] -RECEIVERS = \ No newline at end of file +RECEIVERS = diff --git a/models/user.go b/models/user.go index 3c11091285..cedf342496 100644 --- a/models/user.go +++ b/models/user.go @@ -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. diff --git a/modules/avatar/avatar.go b/modules/avatar/avatar.go index 55d1e13d94..1a18d8a7ec 100644 --- a/modules/avatar/avatar.go +++ b/modules/avatar/avatar.go @@ -1,3 +1,8 @@ +// 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 ( @@ -22,11 +27,17 @@ import ( ) var ( - gravatar = "http://www.gravatar.com/avatar" - defaultImagePath = "./default.jpg" + 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))) @@ -35,6 +46,7 @@ func HashEmail(email string) string { type Avatar struct { Hash string + AlterImage string // image path cacheDir string // image save dir reqParams string imagePath string @@ -54,7 +66,7 @@ func New(hash string, cacheDir string) *Avatar { } } -func (this *Avatar) InCache() bool { +func (this *Avatar) HasCache() bool { fileInfo, err := os.Stat(this.imagePath) return err == nil && fileInfo.Mode().IsRegular() } @@ -68,11 +80,8 @@ func (this *Avatar) Modtime() (modtime time.Time, err error) { } func (this *Avatar) Expired() bool { - if !this.InCache() { - return true - } - fileInfo, err := os.Stat(this.imagePath) - return err != nil || time.Since(fileInfo.ModTime()) > this.expireDuration + modtime, err := this.Modtime() + return err != nil || time.Since(modtime) > this.expireDuration } // default image format: jpeg @@ -92,8 +101,11 @@ func (this *Avatar) Encode(wr io.Writer, size int) (err error) { return } imgPath := this.imagePath - if !this.InCache() { - imgPath = defaultImagePath + 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 { @@ -120,61 +132,66 @@ func (this *Avatar) UpdateTimeout(timeout time.Duration) error { return err } -func init() { - log.SetFlags(log.Lshortfile | log.LstdFlags) +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) func(w http.ResponseWriter, r *http.Request) { - MustInt := func(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 - } - - return func(w http.ResponseWriter, r *http.Request) { - urlPath := r.URL.Path - hash := urlPath[strings.LastIndex(urlPath, "/")+1:] - hash = HashEmail(hash) - size := MustInt(r, 80, "s", "size") // size = 80*80 - - avatar := New(hash, cacheDir) - if avatar.Expired() { - err := avatar.UpdateTimeout(time.Millisecond * 500) - if err != nil { - log.Println(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.Println(err) - w.WriteHeader(500) - } +func HttpHandler(cacheDir string, defaultImgPath string) http.Handler { + return &avatarHandler{ + cacheDir: cacheDir, + altImage: defaultImgPath, } } -func init() { - http.HandleFunc("/", HttpHandler("./")) - log.Fatal(http.ListenAndServe(":8001", nil)) -} - +// thunder downloader var thunder = &Thunder{QueueSize: 10} type Thunder struct { @@ -234,7 +251,7 @@ func (this *thunderTask) Fetch() { var client = &http.Client{} func (this *thunderTask) fetch() error { - log.Println("thunder, fetch", this.Url) + //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") diff --git a/modules/avatar/avatar_test.go b/modules/avatar/avatar_test.go index 49f8f91f35..a337959c6f 100644 --- a/modules/avatar/avatar_test.go +++ b/modules/avatar/avatar_test.go @@ -1,29 +1,41 @@ -package avatar +// 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) { - hash := HashEmail("ssx205@gmail.com") - avatar := New(hash, "./") - //avatar.Update() - avatar.UpdateTimeout(time.Millisecond * 200) - time.Sleep(5 * time.Second) + 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 = 50 + var n = 5 ch := make(chan bool, n) for i := 0; i < n; i++ { go func(i int) { - hash := HashEmail(strconv.Itoa(i) + "ssx205@gmail.com") - avatar := New(hash, "./") - avatar.Update() + hash := avatar.HashEmail(strconv.Itoa(i) + "ssx205@gmail.com") + a := avatar.New(hash, TMPDIR) + a.Update() log.Println("finish", hash) ch <- true }(i) @@ -33,3 +45,12 @@ func TestFetchMany(t *testing.T) { } 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) +} +*/ diff --git a/modules/base/tool.go b/modules/base/tool.go index 8fabb8c531..8d0d38216d 100644 --- a/modules/base/tool.go +++ b/modules/base/tool.go @@ -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 diff --git a/public/img/avatar/default.jpg b/public/img/avatar/default.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c5a698da91f00405ca92b87252def7a5425ecd4b GIT binary patch literal 17379 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 DbPBAW literal 0 HcmV?d00001 diff --git a/web.go b/web.go index bb316a6724..637ee7ce95 100644 --- a/web.go +++ b/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,7 +140,6 @@ 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) From 0d39c18b6ad715a68144d3d9e7f9ea3893f07d4f Mon Sep 17 00:00:00 2001 From: Gogs Date: Sun, 23 Mar 2014 18:19:24 +0800 Subject: [PATCH 5/6] rollback conf/app.ini --- conf/app.ini | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/conf/app.ini b/conf/app.ini index 160aef0ffe..ecb0d2511f 100644 --- a/conf/app.ini +++ b/conf/app.ini @@ -7,7 +7,7 @@ RUN_USER = lunny RUN_MODE = dev [repository] -ROOT = /home/work/%(RUN_USER)s/git/gogs-repositories +ROOT = /Users/%(RUN_USER)s/git/gogs-repositories LANG_IGNS = Google Go|C|C++|Python|Ruby|C Sharp LICENSES = Apache v2 License|GPL v2|MIT License|Affero GPL|Artistic License 2.0|BSD (3-Clause) License @@ -15,7 +15,7 @@ LICENSES = Apache v2 License|GPL v2|MIT License|Affero GPL|Artistic License 2.0| DOMAIN = localhost ROOT_URL = http://%(DOMAIN)s:%(HTTP_PORT)s/ HTTP_ADDR = -HTTP_PORT = 8002 +HTTP_PORT = 3000 [database] ; Either "mysql", "postgres" or "sqlite3"(binary release only), it's your choice @@ -23,7 +23,7 @@ DB_TYPE = mysql HOST = NAME = gogs USER = root -PASSWD = toor +PASSWD = ; For "postgres" only, either "disable", "require" or "verify-full" SSL_MODE = disable ; For "sqlite3" only @@ -120,4 +120,4 @@ HOST = USER = PASSWD = ; Receivers, can be one or more, e.g. ["1@example.com","2@example.com"] -RECEIVERS = +RECEIVERS = \ No newline at end of file From b9302749ddc0e0a10911a83bf80e165b792c8c1e Mon Sep 17 00:00:00 2001 From: skyblue Date: Sun, 23 Mar 2014 22:19:19 +0800 Subject: [PATCH 6/6] update default image --- public/img/avatar/default.jpg | Bin 17379 -> 6951 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/public/img/avatar/default.jpg b/public/img/avatar/default.jpg index c5a698da91f00405ca92b87252def7a5425ecd4b..728ec5af6c197ae10062f55331348756f9e52fc6 100644 GIT binary patch literal 6951 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 ZT^bA^OIX3GkAey!kwAxLkgEFsHvz6*zTp4> literal 17379 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 DbPBAW