// GitFsck calls 'git fsck' to check repository health. func GitFsck() { if isGitFscking { return } isGitFscking = true defer func() { isGitFscking = false }() log.Trace("Doing: GitFsck") args := append([]string{"fsck"}, setting.Cron.RepoHealthCheck.Args...) if err := x.Where("id>0").Iterate(new(Repository), func(idx int, bean interface{}) error { repo := bean.(*Repository) repoPath, err := repo.RepoPath() if err != nil { return fmt.Errorf("RepoPath: %v", err) } _, _, err = process.ExecDir(-1, repoPath, "Repository health check", "git", args...) if err != nil { desc := fmt.Sprintf("Fail to health check repository(%s)", repoPath) log.Warn(desc) if err = CreateRepositoryNotice(desc); err != nil { log.Error(4, "CreateRepositoryNotice: %v", err) } } return nil }); err != nil { log.Error(4, "GitFsck: %v", err) } }
func (t *HookTask) AfterSet(colName string, _ xorm.Cell) { var err error switch colName { case "delivered": t.DeliveredString = time.Unix(0, t.Delivered).Format("2006-01-02 15:04:05 MST") case "request_content": if len(t.RequestContent) == 0 { return } t.RequestInfo = &HookRequest{} if err = json.Unmarshal([]byte(t.RequestContent), t.RequestInfo); err != nil { log.Error(3, "Unmarshal[%d]: %v", t.ID, err) } case "response_content": if len(t.ResponseContent) == 0 { return } t.ResponseInfo = &HookResponse{} if err = json.Unmarshal([]byte(t.ResponseContent), t.ResponseInfo); err != nil { log.Error(3, "Unmarshal[%d]: %v", t.ID, err) } } }
func createRepo(ctx *middleware.Context, owner *models.User, opt api.CreateRepoOption) { repo, err := models.CreateRepository(owner, models.CreateRepoOptions{ Name: opt.Name, Description: opt.Description, Gitignores: opt.Gitignores, License: opt.License, Readme: opt.Readme, IsPrivate: opt.Private, AutoInit: opt.AutoInit, }) if err != nil { if models.IsErrRepoAlreadyExist(err) || models.IsErrNameReserved(err) || models.IsErrNamePatternNotAllowed(err) { ctx.JSON(422, &base.ApiJsonErr{err.Error(), base.DOC_URL}) } else { log.Error(4, "CreateRepository: %v", err) if repo != nil { if err = models.DeleteRepository(ctx.User.Id, repo.ID); err != nil { log.Error(4, "DeleteRepository: %v", err) } } ctx.Error(500) } return } ctx.JSON(201, ToApiRepository(owner, repo, api.Permission{true, true, true})) }
func handleServerConn(keyId string, chans <-chan ssh.NewChannel) { for newChan := range chans { if newChan.ChannelType() != "session" { newChan.Reject(ssh.UnknownChannelType, "unknown channel type") continue } channel, requests, err := newChan.Accept() if err != nil { log.Error(3, "Could not accept channel: %v", err) continue } go func(in <-chan *ssh.Request) { defer channel.Close() for req := range in { ok, payload := false, strings.TrimLeft(string(req.Payload), "\x00&") fmt.Println("Request:", req.Type, req.WantReply, payload) if req.WantReply { fmt.Println(req.Reply(true, nil)) } switch req.Type { case "env": args := strings.Split(strings.Replace(payload, "\x00", "", -1), "\v") if len(args) != 2 { break } args[0] = strings.TrimLeft(args[0], "\x04") _, _, err := com.ExecCmdBytes("env", args[0]+"="+args[1]) if err != nil { log.Error(3, "env: %v", err) channel.Stderr().Write([]byte(err.Error())) break } ok = true case "exec": os.Setenv("SSH_ORIGINAL_COMMAND", strings.TrimLeft(payload, "'(")) log.Info("Payload: %v", strings.TrimLeft(payload, "'(")) cmd := exec.Command("/Users/jiahuachen/Applications/Go/src/github.com/pecastro/gogs/gogs", "serv", "key-"+keyId) cmd.Stdout = channel cmd.Stdin = channel cmd.Stderr = channel.Stderr() if err := cmd.Run(); err != nil { log.Error(3, "exec: %v", err) } else { ok = true } } fmt.Println("Done:", ok) } fmt.Println("Done!!!") }(requests) } }
// MirrorUpdate checks and updates mirror repositories. func MirrorUpdate() { if isMirrorUpdating { return } isMirrorUpdating = true defer func() { isMirrorUpdating = false }() log.Trace("Doing: MirrorUpdate") mirrors := make([]*Mirror, 0, 10) if err := x.Iterate(new(Mirror), func(idx int, bean interface{}) error { m := bean.(*Mirror) if m.NextUpdate.After(time.Now()) { return nil } if m.Repo == nil { log.Error(4, "Disconnected mirror repository found: %d", m.ID) return nil } repoPath, err := m.Repo.RepoPath() if err != nil { return fmt.Errorf("Repo.RepoPath: %v", err) } if _, stderr, err := process.ExecDir(10*time.Minute, repoPath, fmt.Sprintf("MirrorUpdate: %s", repoPath), "git", "remote", "update", "--prune"); err != nil { desc := fmt.Sprintf("Fail to update mirror repository(%s): %s", repoPath, stderr) log.Error(4, desc) if err = CreateRepositoryNotice(desc); err != nil { log.Error(4, "CreateRepositoryNotice: %v", err) } return nil } m.NextUpdate = time.Now().Add(time.Duration(m.Interval) * time.Hour) mirrors = append(mirrors, m) return nil }); err != nil { log.Error(4, "MirrorUpdate: %v", err) } for i := range mirrors { if err := UpdateMirror(mirrors[i]); err != nil { log.Error(4, "UpdateMirror[%d]: %v", mirrors[i].ID, err) } } }
func repoStatsCheck(checker *repoChecker) { results, err := x.Query(checker.querySQL) if err != nil { log.Error(4, "Select %s: %v", checker.desc, err) return } for _, result := range results { id := com.StrTo(result["id"]).MustInt64() log.Trace("Updating %s: %d", checker.desc, id) _, err = x.Exec(checker.correctSQL, id, id) if err != nil { log.Error(4, "Update %s[%d]: %v", checker.desc, id, err) } } }
func (w *Webhook) GetSlackHook() *SlackMeta { s := &SlackMeta{} if err := json.Unmarshal([]byte(w.Meta), s); err != nil { log.Error(4, "webhook.GetSlackHook(%d): %v", w.ID, err) } return s }
func (t *HookTask) MarshalJSON(v interface{}) string { p, err := json.Marshal(v) if err != nil { log.Error(3, "Marshal[%d]: %v", t.ID, err) } return string(p) }
func TeamsRepoAction(ctx *middleware.Context) { if !ctx.Org.IsOwner { ctx.Error(404) return } var err error switch ctx.Params(":action") { case "add": repoName := path.Base(ctx.Query("repo-name")) var repo *models.Repository repo, err = models.GetRepositoryByName(ctx.Org.Organization.Id, repoName) if err != nil { if models.IsErrRepoNotExist(err) { ctx.Flash.Error(ctx.Tr("org.teams.add_nonexistent_repo")) ctx.Redirect(ctx.Org.OrgLink + "/teams/" + ctx.Org.Team.LowerName + "/repositories") return } ctx.Handle(500, "GetRepositoryByName", err) return } err = ctx.Org.Team.AddRepository(repo) case "remove": err = ctx.Org.Team.RemoveRepository(com.StrTo(ctx.Query("repoid")).MustInt64()) } if err != nil { log.Error(3, "Action(%s): '%s' %v", ctx.Params(":action"), ctx.Org.Team.Name, err) ctx.Handle(500, "TeamsRepoAction", err) return } ctx.Redirect(ctx.Org.OrgLink + "/teams/" + ctx.Org.Team.LowerName + "/repositories") }
// saveAuthorizedKeyFile writes SSH key content to authorized_keys file. func saveAuthorizedKeyFile(keys ...*PublicKey) error { sshOpLocker.Lock() defer sshOpLocker.Unlock() fpath := filepath.Join(SSHPath, "authorized_keys") f, err := os.OpenFile(fpath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600) if err != nil { return err } defer f.Close() fi, err := f.Stat() if err != nil { return err } // FIXME: following command does not support in Windows. if !setting.IsWindows { // .ssh directory should have mode 700, and authorized_keys file should have mode 600. if fi.Mode().Perm() > 0600 { log.Error(4, "authorized_keys file has unusual permission flags: %s - setting to -rw-------", fi.Mode().Perm().String()) if err = f.Chmod(0600); err != nil { return err } } } for _, key := range keys { if _, err = f.WriteString(key.GetAuthorizedString()); err != nil { return err } } return nil }
// GetAccessibleRepositories finds all repositories where a user has access to, // besides he/she owns. func (u *User) GetAccessibleRepositories() (map[*Repository]AccessMode, error) { accesses := make([]*Access, 0, 10) if err := x.Find(&accesses, &Access{UserID: u.Id}); err != nil { return nil, err } repos := make(map[*Repository]AccessMode, len(accesses)) for _, access := range accesses { repo, err := GetRepositoryByID(access.RepoID) if err != nil { if IsErrRepoNotExist(err) { log.Error(4, "%v", err) continue } return nil, err } if err = repo.GetOwner(); err != nil { return nil, err } else if repo.OwnerID == u.Id { continue } repos[repo] = access.Mode } // FIXME: should we generate an ordered list here? Random looks weird. return repos, nil }
func MigratePost(ctx *middleware.Context, form auth.MigrateRepoForm) { ctx.Data["Title"] = ctx.Tr("new_migrate") ctxUser := checkContextUser(ctx, form.Uid) if ctx.Written() { return } ctx.Data["ContextUser"] = ctxUser if ctx.HasError() { ctx.HTML(200, MIGRATE) return } // Remote address can be HTTP/HTTPS/Git URL or local path. // Note: remember to change api/v1/repo.go: MigrateRepo // FIXME: merge these two functions with better error handling remoteAddr := form.CloneAddr if strings.HasPrefix(form.CloneAddr, "http://") || strings.HasPrefix(form.CloneAddr, "https://") || strings.HasPrefix(form.CloneAddr, "git://") { u, err := url.Parse(form.CloneAddr) if err != nil { ctx.Data["Err_CloneAddr"] = true ctx.RenderWithErr(ctx.Tr("form.url_error"), MIGRATE, &form) return } if len(form.AuthUsername) > 0 || len(form.AuthPassword) > 0 { u.User = url.UserPassword(form.AuthUsername, form.AuthPassword) } remoteAddr = u.String() } else if !com.IsDir(remoteAddr) { ctx.Data["Err_CloneAddr"] = true ctx.RenderWithErr(ctx.Tr("repo.migrate.invalid_local_path"), MIGRATE, &form) return } repo, err := models.MigrateRepository(ctxUser, form.RepoName, form.Description, form.Private, form.Mirror, remoteAddr) if err == nil { log.Trace("Repository migrated: %s/%s", ctxUser.Name, form.RepoName) ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + form.RepoName) return } if repo != nil { if errDelete := models.DeleteRepository(ctxUser.Id, repo.ID); errDelete != nil { log.Error(4, "DeleteRepository: %v", errDelete) } } if strings.Contains(err.Error(), "Authentication failed") || strings.Contains(err.Error(), " not found") { ctx.Data["Err_Auth"] = true ctx.RenderWithErr(ctx.Tr("form.auth_failed", strings.Replace(err.Error(), ":"+form.AuthPassword+"@", ":<password>@", 1)), MIGRATE, &form) return } handleCreateError(ctx, err, "MigratePost", MIGRATE, &form) }
func (ls Ldapsource) FindUserDN(name string) (string, bool) { l, err := ldapDial(ls) if err != nil { log.Error(4, "LDAP Connect error, %s:%v", ls.Host, err) ls.Enabled = false return "", false } defer l.Close() log.Trace("Search for LDAP user: %s", name) if ls.BindDN != "" && ls.BindPassword != "" { err = l.Bind(ls.BindDN, ls.BindPassword) if err != nil { log.Debug("Failed to bind as BindDN[%s]: %v", ls.BindDN, err) return "", false } log.Trace("Bound as BindDN %s", ls.BindDN) } else { log.Trace("Proceeding with anonymous LDAP search.") } // A search for the user. userFilter := fmt.Sprintf(ls.Filter, name) log.Trace("Searching using filter %s", userFilter) search := ldap.NewSearchRequest( ls.UserBase, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, userFilter, []string{}, nil) // Ensure we found a user sr, err := l.Search(search) if err != nil || len(sr.Entries) < 1 { log.Debug("Failed search using filter[%s]: %v", userFilter, err) return "", false } else if len(sr.Entries) > 1 { log.Debug("Filter '%s' returned more than one user.", userFilter) return "", false } userDN := sr.Entries[0].DN if userDN == "" { log.Error(4, "LDAP search was succesful, but found no DN!") return "", false } return userDN, true }
func MembersAction(ctx *middleware.Context) { uid := com.StrTo(ctx.Query("uid")).MustInt64() if uid == 0 { ctx.Redirect(ctx.Org.OrgLink + "/members") return } org := ctx.Org.Organization var err error switch ctx.Params(":action") { case "private": if ctx.User.Id != uid && !ctx.Org.IsOwner { ctx.Error(404) return } err = models.ChangeOrgUserStatus(org.Id, uid, false) case "public": if ctx.User.Id != uid { ctx.Error(404) return } err = models.ChangeOrgUserStatus(org.Id, uid, true) case "remove": if !ctx.Org.IsOwner { ctx.Error(404) return } err = org.RemoveMember(uid) if models.IsErrLastOrgOwner(err) { ctx.Flash.Error(ctx.Tr("form.last_org_owner")) ctx.Redirect(ctx.Org.OrgLink + "/members") return } case "leave": err = org.RemoveMember(ctx.User.Id) if models.IsErrLastOrgOwner(err) { ctx.Flash.Error(ctx.Tr("form.last_org_owner")) ctx.Redirect(ctx.Org.OrgLink + "/members") return } } if err != nil { log.Error(4, "Action(%s): %v", ctx.Params(":action"), err) ctx.JSON(200, map[string]interface{}{ "ok": false, "err": err.Error(), }) return } if ctx.Params(":action") != "leave" { ctx.Redirect(ctx.Org.OrgLink + "/members") } else { ctx.Redirect(setting.AppSubUrl + "/") } }
func GetDiffRange(repoPath, beforeCommitId string, afterCommitId string, maxlines int) (*Diff, error) { repo, err := git.OpenRepository(repoPath) if err != nil { return nil, err } commit, err := repo.GetCommit(afterCommitId) if err != nil { return nil, err } rd, wr := io.Pipe() var cmd *exec.Cmd // if "after" commit given if beforeCommitId == "" { // First commit of repository. if commit.ParentCount() == 0 { cmd = exec.Command("git", "show", afterCommitId) } else { c, _ := commit.Parent(0) cmd = exec.Command("git", "diff", c.Id.String(), afterCommitId) } } else { cmd = exec.Command("git", "diff", beforeCommitId, afterCommitId) } cmd.Dir = repoPath cmd.Stdout = wr cmd.Stdin = os.Stdin cmd.Stderr = os.Stderr done := make(chan error) go func() { cmd.Start() done <- cmd.Wait() wr.Close() }() defer rd.Close() desc := fmt.Sprintf("GetDiffRange(%s)", repoPath) pid := process.Add(desc, cmd) go func() { // In case process became zombie. select { case <-time.After(5 * time.Minute): if errKill := process.Kill(pid); errKill != nil { log.Error(4, "git_diff.ParsePatch(Kill): %v", err) } <-done // return "", ErrExecTimeout.Error(), ErrExecTimeout case err = <-done: process.Remove(pid) } }() return ParsePatch(pid, maxlines, cmd, rd) }
func (m *Mirror) AfterSet(colName string, _ xorm.Cell) { var err error switch colName { case "repo_id": m.Repo, err = GetRepositoryByID(m.RepoID) if err != nil { log.Error(3, "GetRepositoryByID[%d]: %v", m.ID, err) } } }
// SignedInId returns the id of signed in user. func SignedInId(req *http.Request, sess session.Store) int64 { if !models.HasEngine { return 0 } // API calls need to check access token. if IsAPIPath(req.URL.Path) { auHead := req.Header.Get("Authorization") if len(auHead) > 0 { auths := strings.Fields(auHead) if len(auths) == 2 && auths[0] == "token" { t, err := models.GetAccessTokenBySHA(auths[1]) if err != nil { if err != models.ErrAccessTokenNotExist { log.Error(4, "GetAccessTokenBySHA: %v", err) } return 0 } t.Updated = time.Now() if err = models.UpdateAccessToekn(t); err != nil { log.Error(4, "UpdateAccessToekn: %v", err) } return t.UID } } } uid := sess.Get("uid") if uid == nil { return 0 } if id, ok := uid.(int64); ok { if _, err := models.GetUserByID(id); err != nil { if !models.IsErrUserNotExist(err) { log.Error(4, "GetUserById: %v", err) } return 0 } return id } return 0 }
func (w *Webhook) AfterSet(colName string, _ xorm.Cell) { var err error switch colName { case "events": w.HookEvent = &HookEvent{} if err = json.Unmarshal([]byte(w.Events), w.HookEvent); err != nil { log.Error(3, "Unmarshal[%d]: %v", w.ID, err) } case "created": w.Created = regulateTimeZone(w.Created) } }
// DeliverHooks checks and delivers undelivered hooks. func DeliverHooks() { tasks := make([]*HookTask, 0, 10) x.Where("is_delivered=?", false).Iterate(new(HookTask), func(idx int, bean interface{}) error { t := bean.(*HookTask) deliverHook(t) tasks = append(tasks, t) return nil }) // Update hook task status. for _, t := range tasks { if err := UpdateHookTask(t); err != nil { log.Error(4, "UpdateHookTask(%d): %v", t.ID, err) } } HookQueue = &hookQueue{ lock: sync.Mutex{}, repoIDs: make(map[int64]bool), queue: make(chan int64, setting.Webhook.QueueLength), } // Start listening on new hook requests. for repoID := range HookQueue.queue { HookQueue.removeRepoID(repoID) tasks = make([]*HookTask, 0, 5) if err := x.Where("repo_id=? AND is_delivered=?", repoID, false).Find(&tasks); err != nil { log.Error(4, "Get repository(%d) hook tasks: %v", repoID, err) continue } for _, t := range tasks { deliverHook(t) if err := UpdateHookTask(t); err != nil { log.Error(4, "UpdateHookTask(%d): %v", t.ID, err) } } } }
func Activate(ctx *middleware.Context) { code := ctx.Query("code") if len(code) == 0 { ctx.Data["IsActivatePage"] = true if ctx.User.IsActive { ctx.Error(404) return } // Resend confirmation e-mail. if setting.Service.RegisterEmailConfirm { if ctx.Cache.IsExist("MailResendLimit_" + ctx.User.LowerName) { ctx.Data["ResendLimited"] = true } else { ctx.Data["Hours"] = setting.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(4, "Set cache(MailResendLimit) fail: %v", err) } } } else { ctx.Data["ServiceNotEnabled"] = true } ctx.HTML(200, ACTIVATE) return } // Verify code. if user := models.VerifyUserActiveCode(code); user != nil { user.IsActive = true user.Rands = models.GetUserSalt() if err := models.UpdateUser(user); err != nil { if models.IsErrUserNotExist(err) { ctx.Error(404) } else { ctx.Handle(500, "UpdateUser", err) } return } log.Trace("User activated: %s", user.Name) ctx.Session.Set("uid", user.Id) ctx.Session.Set("uname", user.Name) ctx.Redirect(setting.AppSubUrl + "/") return } ctx.Data["IsActivateFailed"] = true ctx.HTML(200, ACTIVATE) }
func listen(config *ssh.ServerConfig, port string) { listener, err := net.Listen("tcp", "0.0.0.0:"+port) if err != nil { panic(err) } for { // Once a ServerConfig has been configured, connections can be accepted. conn, err := listener.Accept() if err != nil { log.Error(3, "Fail to accept incoming connection: %v", err) continue } // Before use, a handshake must be performed on the incoming net.Conn. sConn, chans, reqs, err := ssh.NewServerConn(conn, config) if err != nil { log.Error(3, "Fail to handshake: %v", err) continue } // The incoming Request channel must be serviced. go ssh.DiscardRequests(reqs) go handleServerConn(sConn.Permissions.Extensions["key-id"], chans) } }
func (c *Comment) AfterSet(colName string, _ xorm.Cell) { var err error switch colName { case "id": c.Attachments, err = GetAttachmentsByCommentID(c.ID) if err != nil { log.Error(3, "GetAttachmentsByCommentID[%d]: %v", c.ID, err) } case "poster_id": c.Poster, err = GetUserByID(c.PosterID) if err != nil { if IsErrUserNotExist(err) { c.PosterID = -1 c.Poster = NewFakeUser() } else { log.Error(3, "GetUserByID[%d]: %v", c.ID, err) } } case "created": c.Created = regulateTimeZone(c.Created) } }
func (repo *Repository) AfterSet(colName string, _ xorm.Cell) { switch colName { case "is_fork": forkInfo := new(ForkInfo) has, err := x.Where("repo_id=?", repo.ID).Get(forkInfo) if err != nil { log.Error(3, "get fork in[%d]: %v", repo.ID, err) return } else if has { repo.ForkInfo = forkInfo } case "updated": repo.Updated = regulateTimeZone(repo.Updated) } }
func (i *Issue) AfterSet(colName string, _ xorm.Cell) { var err error switch colName { case "id": i.Attachments, err = GetAttachmentsByIssueID(i.ID) if err != nil { log.Error(3, "GetAttachmentsByIssueID[%d]: %v", i.ID, err) } i.Comments, err = GetCommentsByIssueID(i.ID) if err != nil { log.Error(3, "GetCommentsByIssueID[%d]: %v", i.ID, err) } case "milestone_id": if i.MilestoneID == 0 { return } i.Milestone, err = GetMilestoneByID(i.MilestoneID) if err != nil { log.Error(3, "GetMilestoneById[%d]: %v", i.ID, err) } case "assignee_id": if i.AssigneeID == 0 { return } i.Assignee, err = GetUserByID(i.AssigneeID) if err != nil { log.Error(3, "GetUserByID[%d]: %v", i.ID, err) } case "created": i.Created = regulateTimeZone(i.Created) } }
// Handle handles and logs error by given status. func (ctx *Context) Handle(status int, title string, err error) { if err != nil { log.Error(4, "%s: %v", title, err) if macaron.Env != macaron.PROD { ctx.Data["ErrorMsg"] = err } } switch status { case 404: ctx.Data["Title"] = "Page Not Found" case 500: ctx.Data["Title"] = "Internal Server Error" } ctx.HTML(status, base.TplName(fmt.Sprintf("status/%d", status))) }
// Send user register mail with active code func SendRegisterMail(r macaron.Render, u *models.User) { code := CreateUserActiveCode(u, nil) subject := "Register success, Welcome" data := GetMailTmplData(u) data["Code"] = code body, err := r.HTMLString(string(AUTH_REGISTER_SUCCESS), data) if err != nil { log.Error(4, "mail.SendRegisterMail(fail to render): %v", err) return } msg := NewMailMessage([]string{u.Email}, subject, body) msg.Info = fmt.Sprintf("UID: %d, send register mail", u.Id) SendAsync(&msg) }
// ToApiRepository converts repository to API format. func ToApiRepository(owner *models.User, repo *models.Repository, permission api.Permission) *api.Repository { cl, err := repo.CloneLink() if err != nil { log.Error(4, "CloneLink: %v", err) } return &api.Repository{ Id: repo.ID, Owner: *ToApiUser(owner), FullName: owner.Name + "/" + repo.Name, Private: repo.IsPrivate, Fork: repo.IsFork, HtmlUrl: setting.AppUrl + owner.Name + "/" + repo.Name, CloneUrl: cl.HTTPS, SshUrl: cl.SSH, Permissions: permission, } }
// Send email verify active email. func SendActiveMail(r macaron.Render, u *models.User) { code := CreateUserActiveCode(u, nil) subject := "Verify your e-mail address" data := GetMailTmplData(u) data["Code"] = code body, err := r.HTMLString(string(AUTH_ACTIVE), data) if err != nil { log.Error(4, "mail.SendActiveMail(fail to render): %v", err) return } msg := NewMailMessage([]string{u.Email}, subject, body) msg.Info = fmt.Sprintf("UID: %d, send active mail", u.Id) SendAsync(&msg) }
// Send reset password email. func SendResetPasswdMail(r macaron.Render, u *models.User) { code := CreateUserActiveCode(u, nil) subject := "Reset your password" data := GetMailTmplData(u) data["Code"] = code body, err := r.HTMLString(string(AUTH_RESET_PASSWORD), data) if err != nil { log.Error(4, "mail.SendResetPasswdMail(fail to render): %v", err) return } msg := NewMailMessage([]string{u.Email}, subject, body) msg.Info = fmt.Sprintf("UID: %d, send reset password email", u.Id) SendAsync(&msg) }
func processMailQueue() { for { select { case msg := <-mailQueue: num, err := Send(msg) tos := strings.Join(msg.To, "; ") info := "" if err != nil { if len(msg.Info) > 0 { info = ", info: " + msg.Info } log.Error(4, fmt.Sprintf("Async sent email %d succeed, not send emails: %s%s err: %s", num, tos, info, err)) } else { log.Trace(fmt.Sprintf("Async sent email %d succeed, sent emails: %s%s", num, tos, info)) } } } }