diff --git a/cmd/web.go b/cmd/web.go
index 74da86d40..0b8c9b11b 100644
--- a/cmd/web.go
+++ b/cmd/web.go
@@ -43,7 +43,7 @@ func newMartini() *martini.ClassicMartini {
m := martini.New()
m.Use(middleware.Logger())
m.Use(martini.Recovery())
- m.Use(martini.Static("public", martini.StaticOptions{SkipLogging: !base.RouterLog}))
+ m.Use(martini.Static("public", martini.StaticOptions{SkipLogging: !base.DisableRouterLog}))
m.MapTo(r, (*martini.Routes)(nil))
m.Action(r.Handle)
return &martini.ClassicMartini{m, r}
diff --git a/conf/app.ini b/conf/app.ini
index 77b808611..4f76db4de 100644
--- a/conf/app.ini
+++ b/conf/app.ini
@@ -20,7 +20,7 @@ HTTP_ADDR =
HTTP_PORT = 3000
; Disable CDN even in "prod" mode
OFFLINE_MODE = false
-ROUTER_LOG = true
+DISABLE_ROUTER_LOG = false
; Generate steps:
; $ cd path/to/gogs/custom/https
; $ go run $GOROOT/src/pkg/crypto/tls/generate_cert.go -ca=true -duration=8760h0m0s -host=myhost.example.com
diff --git a/models/action.go b/models/action.go
index 231a7a548..ef9e260a0 100644
--- a/models/action.go
+++ b/models/action.go
@@ -30,14 +30,15 @@ const (
OP_PULL_REQUEST
OP_TRANSFER_REPO
OP_PUSH_TAG
+ OP_COMMENT_ISSUE
)
// Action represents user operation type and other information to repository.,
// it implemented interface base.Actioner so that can be used in template render.
type Action struct {
Id int64
- UserId int64 // Receiver user id.
- OpType int // Operations: CREATE DELETE STAR ...
+ UserId int64 // Receiver user id.
+ OpType int
ActUserId int64 // Action user id.
ActUserName string // Action user name.
ActEmail string
diff --git a/models/oauth2.go b/models/oauth2.go
index 97ba519c5..61044d688 100644
--- a/models/oauth2.go
+++ b/models/oauth2.go
@@ -80,3 +80,9 @@ func DeleteOauth2ById(id int64) error {
_, err := orm.Delete(&Oauth2{Id: id})
return err
}
+
+// CleanUnbindOauth deletes all unbind OAuthes.
+func CleanUnbindOauth() error {
+ _, err := orm.Delete(&Oauth2{Uid: -1})
+ return err
+}
diff --git a/modules/base/conf.go b/modules/base/conf.go
index 73552732b..cbd6532ba 100644
--- a/modules/base/conf.go
+++ b/modules/base/conf.go
@@ -45,16 +45,16 @@ type Oauther struct {
}
var (
- AppVer string
- AppName string
- AppLogo string
- AppUrl string
- OfflineMode bool
- RouterLog bool
- ProdMode bool
- Domain string
- SecretKey string
- RunUser string
+ AppVer string
+ AppName string
+ AppLogo string
+ AppUrl string
+ OfflineMode bool
+ DisableRouterLog bool
+ ProdMode bool
+ Domain string
+ SecretKey string
+ RunUser string
RepoRootPath string
ScriptType string
@@ -330,7 +330,7 @@ func NewConfigContext() {
AppUrl = Cfg.MustValue("server", "ROOT_URL")
Domain = Cfg.MustValue("server", "DOMAIN")
OfflineMode = Cfg.MustBool("server", "OFFLINE_MODE", false)
- RouterLog = Cfg.MustBool("server", "ROUTER_LOG", true)
+ DisableRouterLog = Cfg.MustBool("server", "DISABLE_ROUTER_LOG", false)
SecretKey = Cfg.MustValue("security", "SECRET_KEY")
InstallLock = Cfg.MustBool("security", "INSTALL_LOCK", false)
diff --git a/modules/base/template.go b/modules/base/template.go
index a69a54618..135be107f 100644
--- a/modules/base/template.go
+++ b/modules/base/template.go
@@ -117,6 +117,8 @@ func ActionIcon(opType int) string {
return "exclamation-circle"
case 8: // Transfer repository.
return "share"
+ case 10: // Comment issue.
+ return "comment"
default:
return "invalid type"
}
@@ -130,6 +132,8 @@ const (
%s
`
TPL_TRANSFER_REPO = `%s transfered repository %s
to %s`
TPL_PUSH_TAG = `%s pushed tag %s at %s`
+ TPL_COMMENT_ISSUE = `%s commented on issue %s#%s
+ %s
`
)
type PushCommit struct {
@@ -179,6 +183,10 @@ func ActionDesc(act Actioner) string {
return fmt.Sprintf(TPL_TRANSFER_REPO, actUserName, actUserName, repoLink, newRepoLink, newRepoLink)
case 9: // Push tag.
return fmt.Sprintf(TPL_PUSH_TAG, actUserName, actUserName, repoLink, branch, branch, repoLink, repoLink)
+ case 10: // Comment issue.
+ infos := strings.SplitN(content, "|", 2)
+ return fmt.Sprintf(TPL_COMMENT_ISSUE, actUserName, actUserName, repoLink, infos[0], repoLink, infos[0],
+ AvatarLink(email), infos[1])
default:
return "invalid type"
}
diff --git a/modules/hooks/hooks.go b/modules/hooks/hooks.go
index 2b53dbfbb..a3a59454e 100644
--- a/modules/hooks/hooks.go
+++ b/modules/hooks/hooks.go
@@ -77,7 +77,7 @@ func handleQueue() {
log.Error("hooks.handleQueue: Fail to deliver hook: %v", err)
continue
}
- log.Info("Hook delivered")
+ log.Info("Hook delivered: %s", string(data))
}
}
}
diff --git a/modules/middleware/logger.go b/modules/middleware/logger.go
index d815b90c2..1ee030a08 100644
--- a/modules/middleware/logger.go
+++ b/modules/middleware/logger.go
@@ -24,7 +24,7 @@ func init() {
func Logger() martini.Handler {
return func(res http.ResponseWriter, req *http.Request, ctx martini.Context, log *log.Logger) {
- if !base.RouterLog {
+ if base.DisableRouterLog {
return
}
diff --git a/routers/admin/admin.go b/routers/admin/admin.go
index 96721bfde..910027881 100644
--- a/routers/admin/admin.go
+++ b/routers/admin/admin.go
@@ -98,9 +98,36 @@ func updateSystemStatus() {
sysStatus.NumGC = m.NumGC
}
+// Operation types.
+const (
+ OT_CLEAN_OAUTH = iota + 1
+)
+
func Dashboard(ctx *middleware.Context) {
ctx.Data["Title"] = "Admin Dashboard"
ctx.Data["PageIsDashboard"] = true
+
+ // Run operation.
+ op, _ := base.StrTo(ctx.Query("op")).Int()
+ if op > 0 {
+ var err error
+ var success string
+
+ switch op {
+ case OT_CLEAN_OAUTH:
+ success = "All unbind OAuthes have been deleted."
+ err = models.CleanUnbindOauth()
+ }
+
+ if err != nil {
+ ctx.Flash.Error(err.Error())
+ } else {
+ ctx.Flash.Success(success)
+ }
+ ctx.Redirect("/admin")
+ return
+ }
+
ctx.Data["Stats"] = models.GetStatistic()
updateSystemStatus()
ctx.Data["SysStatus"] = sysStatus
@@ -153,7 +180,7 @@ func Config(ctx *middleware.Context) {
ctx.Data["AppUrl"] = base.AppUrl
ctx.Data["Domain"] = base.Domain
ctx.Data["OfflineMode"] = base.OfflineMode
- ctx.Data["RouterLog"] = base.RouterLog
+ ctx.Data["DisableRouterLog"] = base.DisableRouterLog
ctx.Data["RunUser"] = base.RunUser
ctx.Data["RunMode"] = strings.Title(martini.Env)
ctx.Data["RepoRootPath"] = base.RepoRootPath
diff --git a/routers/repo/issue.go b/routers/repo/issue.go
index 4e2076620..2bd2f33a1 100644
--- a/routers/repo/issue.go
+++ b/routers/repo/issue.go
@@ -295,5 +295,39 @@ func Comment(ctx *middleware.Context, params martini.Params) {
}
}
+ // Notify watchers.
+ if err = models.NotifyWatchers(&models.Action{ActUserId: ctx.User.Id, ActUserName: ctx.User.Name, ActEmail: ctx.User.Email,
+ OpType: models.OP_COMMENT_ISSUE, Content: fmt.Sprintf("%d|%s", issue.Index, strings.Split(content, "\n")[0]),
+ RepoId: ctx.Repo.Repository.Id, RepoName: ctx.Repo.Repository.Name, RefName: ""}); err != nil {
+ ctx.Handle(500, "issue.CreateIssue(NotifyWatchers)", err)
+ return
+ }
+
+ // Mail watchers and mentions.
+ if base.Service.NotifyMail {
+ issue.Content = content
+ tos, err := mailer.SendIssueNotifyMail(ctx.User, ctx.Repo.Owner, ctx.Repo.Repository, issue)
+ if err != nil {
+ ctx.Handle(500, "issue.Comment(SendIssueNotifyMail)", err)
+ return
+ }
+
+ tos = append(tos, ctx.User.LowerName)
+ ms := base.MentionPattern.FindAllString(issue.Content, -1)
+ newTos := make([]string, 0, len(ms))
+ for _, m := range ms {
+ if com.IsSliceContainsStr(tos, m[1:]) {
+ continue
+ }
+
+ newTos = append(newTos, m[1:])
+ }
+ if err = mailer.SendIssueMentionMail(ctx.Render, ctx.User, ctx.Repo.Owner,
+ ctx.Repo.Repository, issue, models.GetUserEmailsByNames(newTos)); err != nil {
+ ctx.Handle(500, "issue.Comment(SendIssueMentionMail)", err)
+ return
+ }
+ }
+
ctx.Redirect(fmt.Sprintf("%s/issues/%d", ctx.Repo.RepoLink, index))
}
diff --git a/templates/admin/config.tmpl b/templates/admin/config.tmpl
index 8ba6b60cd..96565bac8 100644
--- a/templates/admin/config.tmpl
+++ b/templates/admin/config.tmpl
@@ -20,8 +20,8 @@
{{.Domain}}
Offline Mode
- Router Log
-
+ Disable Router Log
+
Run User
{{.RunUser}}
diff --git a/templates/admin/dashboard.tmpl b/templates/admin/dashboard.tmpl
index 76539842d..e8dca09e5 100644
--- a/templates/admin/dashboard.tmpl
+++ b/templates/admin/dashboard.tmpl
@@ -3,6 +3,7 @@
{{template "admin/nav" .}}
+ {{template "base/alert" .}}
Statistic
@@ -13,6 +14,29 @@
+
+
+ Operations
+
+
+
+
+
+
+ Name |
+ Op. |
+
+
+
+
+ Clean unbind OAuthes |
+ Run |
+
+
+
+
+
+