diff options
Diffstat (limited to 'routers')
-rw-r--r-- | routers/install.go | 7 | ||||
-rw-r--r-- | routers/repo/git.go | 55 | ||||
-rw-r--r-- | routers/repo/http.go | 471 | ||||
-rw-r--r-- | routers/repo/repo.go | 116 | ||||
-rw-r--r-- | routers/user/social.go | 99 | ||||
-rw-r--r-- | routers/user/user.go | 14 |
6 files changed, 646 insertions, 116 deletions
diff --git a/routers/install.go b/routers/install.go index 1c4e6181..5d6c65ef 100644 --- a/routers/install.go +++ b/routers/install.go @@ -7,6 +7,7 @@ package routers import ( "errors" "os" + "os/exec" "strings" "github.com/Unknwon/goconfig" @@ -27,6 +28,7 @@ func checkRunMode() { switch base.Cfg.MustValue("", "RUN_MODE") { case "prod": martini.Env = martini.Prod + base.IsProdMode = true case "test": martini.Env = martini.Test } @@ -102,6 +104,11 @@ func Install(ctx *middleware.Context, form auth.InstallForm) { return } + if _, err := exec.LookPath("git"); err != nil { + ctx.RenderWithErr("Fail to test 'git' command: "+err.Error(), "install", &form) + return + } + // Pass basic check, now test configuration. // Test database setting. dbTypes := map[string]string{"mysql": "mysql", "pgsql": "postgres", "sqlite": "sqlite3"} diff --git a/routers/repo/git.go b/routers/repo/git.go new file mode 100644 index 00000000..30c1042e --- /dev/null +++ b/routers/repo/git.go @@ -0,0 +1,55 @@ +package repo + +import ( + "fmt" + "strings" +) + +const advertise_refs = "--advertise-refs" + +func command(cmd string, opts ...string) string { + return fmt.Sprintf("git %s %s", cmd, strings.Join(opts, " ")) +} + +/*func upload_pack(repository_path string, opts ...string) string { + cmd = "upload-pack" + opts = append(opts, "--stateless-rpc", repository_path) + return command(cmd, opts...) +} + +func receive_pack(repository_path string, opts ...string) string { + cmd = "receive-pack" + opts = append(opts, "--stateless-rpc", repository_path) + return command(cmd, opts...) +}*/ + +/*func update_server_info(repository_path, opts = {}, &block) + cmd = "update-server-info" + args = [] + opts.each {|k,v| args << command_options[k] if command_options.has_key?(k) } + opts[:args] = args + Dir.chdir(repository_path) do # "git update-server-info" does not take a parameter to specify the repository, so set the working directory to the repository + self.command(cmd, opts, &block) + end + end + + def get_config_setting(repository_path, key) + path = get_config_location(repository_path) + raise "Config file could not be found for repository in #{repository_path}." unless path + self.command("config", {:args => ["-f #{path}", key]}).chomp + end + + def get_config_location(repository_path) + non_bare = File.join(repository_path,'.git') # This is where the config file will be if the repository is non-bare + if File.exists?(non_bare) then # The repository is non-bare + non_bare_config = File.join(non_bare, 'config') + return non_bare_config if File.exists?(non_bare_config) + else # We are dealing with a bare repository + bare_config = File.join(repository_path, "config") + return bare_config if File.exists?(bare_config) + end + return nil + end + + end +*/ diff --git a/routers/repo/http.go b/routers/repo/http.go new file mode 100644 index 00000000..5aa3139f --- /dev/null +++ b/routers/repo/http.go @@ -0,0 +1,471 @@ +package repo + +import ( + "fmt" + "io" + "io/ioutil" + "log" + "net/http" + "os" + "os/exec" + "path" + "regexp" + "strconv" + "strings" + "time" + + "github.com/go-martini/martini" + "github.com/gogits/gogs/models" + "github.com/gogits/gogs/modules/base" + "github.com/gogits/gogs/modules/middleware" +) + +func Http(ctx *middleware.Context, params martini.Params) { + username := params["username"] + reponame := params["reponame"] + if strings.HasSuffix(reponame, ".git") { + reponame = reponame[:len(reponame)-4] + } + + var isPull bool + service := ctx.Query("service") + if service == "git-receive-pack" || + strings.HasSuffix(ctx.Req.URL.Path, "git-receive-pack") { + isPull = false + } else if service == "git-upload-pack" || + strings.HasSuffix(ctx.Req.URL.Path, "git-upload-pack") { + isPull = true + } else { + isPull = (ctx.Req.Method == "GET") + } + + repoUser, err := models.GetUserByName(username) + if err != nil { + ctx.Handle(500, "repo.GetUserByName", nil) + return + } + + repo, err := models.GetRepositoryByName(repoUser.Id, reponame) + if err != nil { + ctx.Handle(500, "repo.GetRepositoryByName", nil) + return + } + + // only public pull don't need auth + var askAuth = !(!repo.IsPrivate && isPull) + + // check access + if askAuth { + baHead := ctx.Req.Header.Get("Authorization") + if baHead == "" { + // ask auth + authRequired(ctx) + return + } + + auths := strings.Fields(baHead) + // currently check basic auth + // TODO: support digit auth + if len(auths) != 2 || auths[0] != "Basic" { + ctx.Handle(401, "no basic auth and digit auth", nil) + return + } + authUsername, passwd, err := basicDecode(auths[1]) + if err != nil { + ctx.Handle(401, "no basic auth and digit auth", nil) + return + } + + authUser, err := models.GetUserByName(authUsername) + if err != nil { + ctx.Handle(401, "no basic auth and digit auth", nil) + return + } + + newUser := &models.User{Passwd: passwd, Salt: authUser.Salt} + + newUser.EncodePasswd() + if authUser.Passwd != newUser.Passwd { + ctx.Handle(401, "no basic auth and digit auth", nil) + return + } + + var tp = models.AU_WRITABLE + if isPull { + tp = models.AU_READABLE + } + + has, err := models.HasAccess(authUsername, username+"/"+reponame, tp) + if err != nil { + ctx.Handle(401, "no basic auth and digit auth", nil) + return + } else if !has { + if tp == models.AU_READABLE { + has, err = models.HasAccess(authUsername, username+"/"+reponame, models.AU_WRITABLE) + if err != nil || !has { + ctx.Handle(401, "no basic auth and digit auth", nil) + return + } + } else { + ctx.Handle(401, "no basic auth and digit auth", nil) + return + } + } + } + + config := Config{base.RepoRootPath, "git", true, true, func(rpc string, input []byte) { + //fmt.Println("rpc:", rpc) + //fmt.Println("input:", string(input)) + }} + + handler := HttpBackend(&config) + handler(ctx.ResponseWriter, ctx.Req) + + /* Webdav + dir := models.RepoPath(username, reponame) + + prefix := path.Join("/", username, params["reponame"]) + server := webdav.NewServer( + dir, prefix, true) + + server.ServeHTTP(ctx.ResponseWriter, ctx.Req) + */ +} + +type route struct { + cr *regexp.Regexp + method string + handler func(handler) +} + +type Config struct { + ReposRoot string + GitBinPath string + UploadPack bool + ReceivePack bool + OnSucceed func(rpc string, input []byte) +} + +type handler struct { + *Config + w http.ResponseWriter + r *http.Request + Dir string + File string +} + +var routes = []route{ + {regexp.MustCompile("(.*?)/git-upload-pack$"), "POST", serviceUploadPack}, + {regexp.MustCompile("(.*?)/git-receive-pack$"), "POST", serviceReceivePack}, + {regexp.MustCompile("(.*?)/info/refs$"), "GET", getInfoRefs}, + {regexp.MustCompile("(.*?)/HEAD$"), "GET", getTextFile}, + {regexp.MustCompile("(.*?)/objects/info/alternates$"), "GET", getTextFile}, + {regexp.MustCompile("(.*?)/objects/info/http-alternates$"), "GET", getTextFile}, + {regexp.MustCompile("(.*?)/objects/info/packs$"), "GET", getInfoPacks}, + {regexp.MustCompile("(.*?)/objects/info/[^/]*$"), "GET", getTextFile}, + {regexp.MustCompile("(.*?)/objects/[0-9a-f]{2}/[0-9a-f]{38}$"), "GET", getLooseObject}, + {regexp.MustCompile("(.*?)/objects/pack/pack-[0-9a-f]{40}\\.pack$"), "GET", getPackFile}, + {regexp.MustCompile("(.*?)/objects/pack/pack-[0-9a-f]{40}\\.idx$"), "GET", getIdxFile}, +} + +// Request handling function +func HttpBackend(config *Config) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + //log.Printf("%s %s %s %s", r.RemoteAddr, r.Method, r.URL.Path, r.Proto) + for _, route := range routes { + if m := route.cr.FindStringSubmatch(r.URL.Path); m != nil { + if route.method != r.Method { + renderMethodNotAllowed(w, r) + return + } + + file := strings.Replace(r.URL.Path, m[1]+"/", "", 1) + dir, err := getGitDir(config, m[1]) + + if err != nil { + log.Print(err) + renderNotFound(w) + return + } + + hr := handler{config, w, r, dir, file} + route.handler(hr) + return + } + } + renderNotFound(w) + return + } +} + +// Actual command handling functions + +func serviceUploadPack(hr handler) { + serviceRpc("upload-pack", hr) +} + +func serviceReceivePack(hr handler) { + serviceRpc("receive-pack", hr) +} + +func serviceRpc(rpc string, hr handler) { + w, r, dir := hr.w, hr.r, hr.Dir + access := hasAccess(r, hr.Config, dir, rpc, true) + + if access == false { + renderNoAccess(w) + return + } + + input, _ := ioutil.ReadAll(r.Body) + + w.Header().Set("Content-Type", fmt.Sprintf("application/x-git-%s-result", rpc)) + w.WriteHeader(http.StatusOK) + + args := []string{rpc, "--stateless-rpc", dir} + cmd := exec.Command(hr.Config.GitBinPath, args...) + cmd.Dir = dir + in, err := cmd.StdinPipe() + if err != nil { + log.Print(err) + return + } + + stdout, err := cmd.StdoutPipe() + if err != nil { + log.Print(err) + return + } + + err = cmd.Start() + if err != nil { + log.Print(err) + return + } + + in.Write(input) + io.Copy(w, stdout) + cmd.Wait() + + if hr.Config.OnSucceed != nil { + hr.Config.OnSucceed(rpc, input) + } +} + +func getInfoRefs(hr handler) { + w, r, dir := hr.w, hr.r, hr.Dir + serviceName := getServiceType(r) + access := hasAccess(r, hr.Config, dir, serviceName, false) + + if access { + args := []string{serviceName, "--stateless-rpc", "--advertise-refs", "."} + refs := gitCommand(hr.Config.GitBinPath, dir, args...) + + hdrNocache(w) + w.Header().Set("Content-Type", fmt.Sprintf("application/x-git-%s-advertisement", serviceName)) + w.WriteHeader(http.StatusOK) + w.Write(packetWrite("# service=git-" + serviceName + "\n")) + w.Write(packetFlush()) + w.Write(refs) + } else { + updateServerInfo(hr.Config.GitBinPath, dir) + hdrNocache(w) + sendFile("text/plain; charset=utf-8", hr) + } +} + +func getInfoPacks(hr handler) { + hdrCacheForever(hr.w) + sendFile("text/plain; charset=utf-8", hr) +} + +func getLooseObject(hr handler) { + hdrCacheForever(hr.w) + sendFile("application/x-git-loose-object", hr) +} + +func getPackFile(hr handler) { + hdrCacheForever(hr.w) + sendFile("application/x-git-packed-objects", hr) +} + +func getIdxFile(hr handler) { + hdrCacheForever(hr.w) + sendFile("application/x-git-packed-objects-toc", hr) +} + +func getTextFile(hr handler) { + hdrNocache(hr.w) + sendFile("text/plain", hr) +} + +// Logic helping functions + +func sendFile(contentType string, hr handler) { + w, r := hr.w, hr.r + reqFile := path.Join(hr.Dir, hr.File) + + //fmt.Println("sendFile:", reqFile) + + f, err := os.Stat(reqFile) + if os.IsNotExist(err) { + renderNotFound(w) + return + } + + w.Header().Set("Content-Type", contentType) + w.Header().Set("Content-Length", fmt.Sprintf("%d", f.Size())) + w.Header().Set("Last-Modified", f.ModTime().Format(http.TimeFormat)) + http.ServeFile(w, r, reqFile) +} + +func getGitDir(config *Config, filePath string) (string, error) { + root := config.ReposRoot + + if root == "" { + cwd, err := os.Getwd() + + if err != nil { + log.Print(err) + return "", err + } + + root = cwd + } + + f := path.Join(root, filePath) + if _, err := os.Stat(f); os.IsNotExist(err) { + return "", err + } + + return f, nil +} + +func getServiceType(r *http.Request) string { + serviceType := r.FormValue("service") + + if s := strings.HasPrefix(serviceType, "git-"); !s { + return "" + } + + return strings.Replace(serviceType, "git-", "", 1) +} + +func hasAccess(r *http.Request, config *Config, dir string, rpc string, checkContentType bool) bool { + if checkContentType { + if r.Header.Get("Content-Type") != fmt.Sprintf("application/x-git-%s-request", rpc) { + return false + } + } + + if !(rpc == "upload-pack" || rpc == "receive-pack") { + return false + } + if rpc == "receive-pack" { + return config.ReceivePack + } + if rpc == "upload-pack" { + return config.UploadPack + } + + return getConfigSetting(config.GitBinPath, rpc, dir) +} + +func getConfigSetting(gitBinPath, serviceName string, dir string) bool { + serviceName = strings.Replace(serviceName, "-", "", -1) + setting := getGitConfig(gitBinPath, "http."+serviceName, dir) + + if serviceName == "uploadpack" { + return setting != "false" + } + + return setting == "true" +} + +func getGitConfig(gitBinPath, configName string, dir string) string { + args := []string{"config", configName} + out := string(gitCommand(gitBinPath, dir, args...)) + return out[0 : len(out)-1] +} + +func updateServerInfo(gitBinPath, dir string) []byte { + args := []string{"update-server-info"} + return gitCommand(gitBinPath, dir, args...) +} + +func gitCommand(gitBinPath, dir string, args ...string) []byte { + command := exec.Command(gitBinPath, args...) + command.Dir = dir + out, err := command.Output() + + if err != nil { + log.Print(err) + } + + return out +} + +// HTTP error response handling functions + +func renderMethodNotAllowed(w http.ResponseWriter, r *http.Request) { + if r.Proto == "HTTP/1.1" { + w.WriteHeader(http.StatusMethodNotAllowed) + w.Write([]byte("Method Not Allowed")) + } else { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte("Bad Request")) + } +} + +func renderNotFound(w http.ResponseWriter) { + w.WriteHeader(http.StatusNotFound) + w.Write([]byte("Not Found")) +} + +func renderNoAccess(w http.ResponseWriter) { + w.WriteHeader(http.StatusForbidden) + w.Write([]byte("Forbidden")) +} + +// Packet-line handling function + +func packetFlush() []byte { + return []byte("0000") +} + +func packetWrite(str string) []byte { + s := strconv.FormatInt(int64(len(str)+4), 16) + + if len(s)%4 != 0 { + s = strings.Repeat("0", 4-len(s)%4) + s + } + + return []byte(s + str) +} + +// Header writing functions + +func hdrNocache(w http.ResponseWriter) { + w.Header().Set("Expires", "Fri, 01 Jan 1980 00:00:00 GMT") + w.Header().Set("Pragma", "no-cache") + w.Header().Set("Cache-Control", "no-cache, max-age=0, must-revalidate") +} + +func hdrCacheForever(w http.ResponseWriter) { + now := time.Now().Unix() + expires := now + 31536000 + w.Header().Set("Date", fmt.Sprintf("%d", now)) + w.Header().Set("Expires", fmt.Sprintf("%d", expires)) + w.Header().Set("Cache-Control", "public, max-age=31536000") +} + +// Main +/* +func main() { + http.HandleFunc("/", requestHandler()) + + err := http.ListenAndServe(":8080", nil) + if err != nil { + log.Fatal("ListenAndServe: ", err) + } +}*/ diff --git a/routers/repo/repo.go b/routers/repo/repo.go index d223600c..d4d52ba0 100644 --- a/routers/repo/repo.go +++ b/routers/repo/repo.go @@ -14,8 +14,6 @@ import ( "github.com/go-martini/martini" - "github.com/gogits/webdav" - "github.com/gogits/gogs/models" "github.com/gogits/gogs/modules/auth" "github.com/gogits/gogs/modules/base" @@ -55,6 +53,36 @@ func Create(ctx *middleware.Context, form auth.CreateRepoForm) { ctx.Handle(200, "repo.Create", err) } +func Mirror(ctx *middleware.Context, form auth.CreateRepoForm) { + ctx.Data["Title"] = "Mirror repository" + ctx.Data["PageIsNewRepo"] = true // For navbar arrow. + + if ctx.Req.Method == "GET" { + ctx.HTML(200, "repo/mirror") + return + } + + if ctx.HasError() { + ctx.HTML(200, "repo/mirror") + return + } + + _, err := models.CreateRepository(ctx.User, form.RepoName, form.Description, + "", form.License, form.Visibility == "private", false) + if err == nil { + log.Trace("%s Repository created: %s/%s", ctx.Req.RequestURI, ctx.User.LowerName, form.RepoName) + ctx.Redirect("/" + ctx.User.Name + "/" + form.RepoName) + return + } else if err == models.ErrRepoAlreadyExist { + ctx.RenderWithErr("Repository name has already been used", "repo/mirror", &form) + return + } else if err == models.ErrRepoNameIllegal { + ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), "repo/mirror", &form) + return + } + ctx.Handle(200, "repo.Mirror", err) +} + func Single(ctx *middleware.Context, params martini.Params) { branchName := ctx.Repo.BranchName commitId := ctx.Repo.CommitId @@ -266,89 +294,6 @@ func authRequired(ctx *middleware.Context) { ctx.HTML(401, fmt.Sprintf("status/401")) } -func Http(ctx *middleware.Context, params martini.Params) { - username := params["username"] - reponame := params["reponame"] - if strings.HasSuffix(reponame, ".git") { - reponame = reponame[:len(reponame)-4] - } - - //fmt.Println("req:", ctx.Req.Header) - - repoUser, err := models.GetUserByName(username) - if err != nil { - ctx.Handle(500, "repo.GetUserByName", nil) - return - } - - repo, err := models.GetRepositoryByName(repoUser.Id, reponame) - if err != nil { - ctx.Handle(500, "repo.GetRepositoryByName", nil) - return - } - - isPull := webdav.IsPullMethod(ctx.Req.Method) - var askAuth = !(!repo.IsPrivate && isPull) - - //authRequired(ctx) - //return - - // check access - if askAuth { - // check digit auth - - // check basic auth - baHead := ctx.Req.Header.Get("Authorization") - if baHead == "" { - authRequired(ctx) - return - } - - auths := strings.Fields(baHead) - if len(auths) != 2 || auths[0] != "Basic" { - ctx.Handle(401, "no basic auth and digit auth", nil) - return - } - authUsername, passwd, err := basicDecode(auths[1]) - if err != nil { - ctx.Handle(401, "no basic auth and digit auth", nil) - return - } - - authUser, err := models.GetUserByName(authUsername) - if err != nil { - ctx.Handle(401, "no basic auth and digit auth", nil) - return - } - - newUser := &models.User{Passwd: passwd} - newUser.EncodePasswd() - if authUser.Passwd != newUser.Passwd { - ctx.Handle(401, "no basic auth and digit auth", nil) - return - } - - var tp = models.AU_WRITABLE - if isPull { - tp = models.AU_READABLE - } - - has, err := models.HasAccess(authUsername, username+"/"+reponame, tp) - if err != nil || !has { - ctx.Handle(401, "no basic auth and digit auth", nil) - return - } - } - - dir := models.RepoPath(username, reponame) - - prefix := path.Join("/", username, params["reponame"]) - server := webdav.NewServer( - dir, prefix, true) - - server.ServeHTTP(ctx.ResponseWriter, ctx.Req) -} - func Setting(ctx *middleware.Context, params martini.Params) { if !ctx.Repo.IsOwner { ctx.Handle(404, "repo.Setting", nil) @@ -397,6 +342,7 @@ func SettingPost(ctx *middleware.Context) { ctx.Repo.Repository.Description = ctx.Query("desc") ctx.Repo.Repository.Website = ctx.Query("site") + ctx.Repo.Repository.IsGoget = ctx.Query("goget") == "on" if err := models.UpdateRepository(ctx.Repo.Repository); err != nil { ctx.Handle(404, "repo.SettingPost(update)", err) return diff --git a/routers/user/social.go b/routers/user/social.go index 08cfcd83..b87c313f 100644 --- a/routers/user/social.go +++ b/routers/user/social.go @@ -6,7 +6,10 @@ package user import ( "encoding/json" + "net/http" + "net/url" "strconv" + "strings" "code.google.com/p/goauth2/oauth" @@ -70,53 +73,87 @@ func (s *SocialGithub) Update() error { return json.NewDecoder(r.Body).Decode(&s.data) } +func extractPath(next string) string { + n, err := url.Parse(next) + if err != nil { + return "/" + } + return n.Path +} + // github && google && ... func SocialSignIn(ctx *middleware.Context, tokens oauth2.Tokens) { - gh := &SocialGithub{ - WebToken: &oauth.Token{ - AccessToken: tokens.Access(), - RefreshToken: tokens.Refresh(), - Expiry: tokens.ExpiryTime(), - Extra: tokens.ExtraData(), - }, + var socid int64 + var ok bool + next := extractPath(ctx.Query("next")) + log.Debug("social signed check %s", next) + if socid, ok = ctx.Session.Get("socialId").(int64); ok && socid != 0 { + // already login + ctx.Redirect(next) + log.Info("login soc id: %v", socid) + return + } + config := &oauth.Config{ + //ClientId: base.OauthService.Github.ClientId, + //ClientSecret: base.OauthService.Github.ClientSecret, // FIXME: I don't know why compile error here + ClientId: "09383403ff2dc16daaa1", + ClientSecret: "0e4aa0c3630df396cdcea01a9d45cacf79925fea", + RedirectURL: strings.TrimSuffix(base.AppUrl, "/") + ctx.Req.URL.RequestURI(), + Scope: base.OauthService.GitHub.Scopes, + AuthURL: "https://github.com/login/oauth/authorize", + TokenURL: "https://github.com/login/oauth/access_token", + } + transport := &oauth.Transport{ + Config: config, + Transport: http.DefaultTransport, } - if len(tokens.Access()) == 0 { - log.Error("empty access") + code := ctx.Query("code") + if code == "" { + // redirect to social login page + ctx.Redirect(config.AuthCodeURL(next)) return } - var err error - var u *models.User + + // handle call back + tk, err := transport.Exchange(code) + if err != nil { + log.Error("oauth2 handle callback error: %v", err) + return // FIXME, need error page 501 + } + next = extractPath(ctx.Query("state")) + log.Debug("success token: %v", tk) + + gh := &SocialGithub{WebToken: tk} if err = gh.Update(); err != nil { - // FIXME: handle error page + // FIXME: handle error page 501 log.Error("connect with github error: %s", err) return } var soc SocialConnector = gh log.Info("login: %s", soc.Name()) - // FIXME: login here, user email to check auth, if not registe, then generate a uniq username - if u, err = models.GetOauth2User(soc.Identity()); err != nil { - u = &models.User{ - Name: soc.Name(), - Email: soc.Email(), - Passwd: "123456", - IsActive: !base.Service.RegisterEmailConfirm, - } - if u, err = models.RegisterUser(u); err != nil { - log.Error("register user: %v", err) - return - } - oa := &models.Oauth2{} - oa.Uid = u.Id + oa, err := models.GetOauth2(soc.Identity()) + switch err { + case nil: + ctx.Session.Set("userId", oa.User.Id) + ctx.Session.Set("userName", oa.User.Name) + case models.ErrOauth2RecordNotExists: + oa = &models.Oauth2{} + oa.Uid = 0 oa.Type = soc.Type() oa.Token = soc.Token() oa.Identity = soc.Identity() - log.Info("oa: %v", oa) + log.Debug("oa: %v", oa) if err = models.AddOauth2(oa); err != nil { - log.Error("add oauth2 %v", err) + log.Error("add oauth2 %v", err) // 501 return } + case models.ErrOauth2NotAssociatedWithUser: + // ignore it. judge in /usr/login page + default: + log.Error(err.Error()) // FIXME: handle error page + return } - ctx.Session.Set("userId", u.Id) - ctx.Session.Set("userName", u.Name) - ctx.Redirect("/") + ctx.Session.Set("socialId", oa.Id) + log.Debug("socialId: %v", oa.Id) + ctx.Redirect(next) } diff --git a/routers/user/user.go b/routers/user/user.go index f6a39b86..084d0bbd 100644 --- a/routers/user/user.go +++ b/routers/user/user.go @@ -396,6 +396,10 @@ func Activate(ctx *middleware.Context) { } else { ctx.Data["Hours"] = base.Service.ActiveCodeLives / 60 mailer.SendActiveMail(ctx.Render, ctx.User) + + if err := ctx.Cache.Put("MailResendLimit_"+ctx.User.LowerName, ctx.User.LowerName, 180); err != nil { + log.Error("Set cache(MailResendLimit) fail: %v", err) + } } } else { ctx.Data["ServiceNotEnabled"] = true @@ -451,7 +455,17 @@ func ForgotPasswd(ctx *middleware.Context) { return } + if ctx.Cache.IsExist("MailResendLimit_" + u.LowerName) { + ctx.Data["ResendLimited"] = true + ctx.HTML(200, "user/forgot_passwd") + return + } + mailer.SendResetPasswdMail(ctx.Render, u) + if err = ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil { + log.Error("Set cache(MailResendLimit) fail: %v", err) + } + ctx.Data["Email"] = email ctx.Data["Hours"] = base.Service.ActiveCodeLives / 60 ctx.Data["IsResetSent"] = true |