diff options
-rw-r--r-- | models/repo.go | 6 | ||||
-rw-r--r-- | models/user.go | 2 | ||||
-rw-r--r-- | modules/log/conn.go | 104 | ||||
-rw-r--r-- | modules/log/console.go | 6 | ||||
-rw-r--r-- | modules/log/database.go | 68 | ||||
-rw-r--r-- | modules/log/log.go | 16 | ||||
-rw-r--r-- | modules/log/smtp.go | 87 | ||||
-rw-r--r-- | public/ng/css/gogs.css | 21 | ||||
-rw-r--r-- | routers/install.go | 5 | ||||
-rw-r--r-- | routers/user/home.go | 4 | ||||
-rw-r--r-- | templates/org/home.tmpl | 2 | ||||
-rw-r--r-- | templates/repo/home.tmpl | 6 | ||||
-rw-r--r-- | templates/repo/view_file.tmpl | 8 | ||||
-rw-r--r-- | templates/user/dashboard/dashboard.tmpl | 48 | ||||
-rw-r--r-- | templates/user/dashboard/nav.tmpl | 2 | ||||
-rw-r--r-- | templates/user/dashboard/repo_list.tmpl | 12 |
16 files changed, 359 insertions, 38 deletions
diff --git a/models/repo.go b/models/repo.go index da0813e3b4..1e899c182b 100644 --- a/models/repo.go +++ b/models/repo.go @@ -11,6 +11,7 @@ import ( "html/template" "io/ioutil" "os" + "os/exec" "path" "path/filepath" "regexp" @@ -84,6 +85,11 @@ func LoadRepoConfig() { func NewRepoContext() { zip.Verbose = false + // Check Git installation. + if _, err := exec.LookPath("git"); err != nil { + log.Fatal(4, "Fail to test 'git' command: %v (forgotten install?)", err) + } + // Check Git version. ver, err := git.GetVersion() if err != nil { diff --git a/models/user.go b/models/user.go index 540f4b6af4..ca772556b7 100644 --- a/models/user.go +++ b/models/user.go @@ -81,7 +81,7 @@ type User struct { // DashboardLink returns the user dashboard page link. func (u *User) DashboardLink() string { if u.IsOrganization() { - return "/org/" + u.Name + "/dashboard" + return "/org/" + u.Name + "/dashboard/" } return "/" } diff --git a/modules/log/conn.go b/modules/log/conn.go new file mode 100644 index 0000000000..c104a16c93 --- /dev/null +++ b/modules/log/conn.go @@ -0,0 +1,104 @@ +// 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 log + +import ( + "encoding/json" + "io" + "log" + "net" +) + +// ConnWriter implements LoggerInterface. +// it writes messages in keep-live tcp connection. +type ConnWriter struct { + lg *log.Logger + innerWriter io.WriteCloser + ReconnectOnMsg bool `json:"reconnectOnMsg"` + Reconnect bool `json:"reconnect"` + Net string `json:"net"` + Addr string `json:"addr"` + Level int `json:"level"` +} + +// create new ConnWrite returning as LoggerInterface. +func NewConn() LoggerInterface { + conn := new(ConnWriter) + conn.Level = TRACE + return conn +} + +// init connection writer with json config. +// json config only need key "level". +func (cw *ConnWriter) Init(jsonconfig string) error { + return json.Unmarshal([]byte(jsonconfig), cw) +} + +// write message in connection. +// if connection is down, try to re-connect. +func (cw *ConnWriter) WriteMsg(msg string, skip, level int) error { + if cw.Level > level { + return nil + } + if cw.neddedConnectOnMsg() { + if err := cw.connect(); err != nil { + return err + } + } + + if cw.ReconnectOnMsg { + defer cw.innerWriter.Close() + } + cw.lg.Println(msg) + return nil +} + +func (_ *ConnWriter) Flush() { +} + +// destroy connection writer and close tcp listener. +func (cw *ConnWriter) Destroy() { + if cw.innerWriter == nil { + return + } + cw.innerWriter.Close() +} + +func (cw *ConnWriter) connect() error { + if cw.innerWriter != nil { + cw.innerWriter.Close() + cw.innerWriter = nil + } + + conn, err := net.Dial(cw.Net, cw.Addr) + if err != nil { + return err + } + + if tcpConn, ok := conn.(*net.TCPConn); ok { + tcpConn.SetKeepAlive(true) + } + + cw.innerWriter = conn + cw.lg = log.New(conn, "", log.Ldate|log.Ltime) + return nil +} + +func (cw *ConnWriter) neddedConnectOnMsg() bool { + if cw.Reconnect { + cw.Reconnect = false + return true + } + + if cw.innerWriter == nil { + return true + } + + return cw.ReconnectOnMsg +} + +func init() { + Register("conn", NewConn) +} diff --git a/modules/log/console.go b/modules/log/console.go index 92d6c2a406..f5a8b96fd7 100644 --- a/modules/log/console.go +++ b/modules/log/console.go @@ -61,13 +61,13 @@ func (cw *ConsoleWriter) WriteMsg(msg string, skip, level int) error { return nil } -func (_ *ConsoleWriter) Destroy() { -} - func (_ *ConsoleWriter) Flush() { } +func (_ *ConsoleWriter) Destroy() { +} + func init() { Register("console", NewConsole) } diff --git a/modules/log/database.go b/modules/log/database.go new file mode 100644 index 0000000000..5857cb6d66 --- /dev/null +++ b/modules/log/database.go @@ -0,0 +1,68 @@ +// 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 log + +import ( + "encoding/json" + + "github.com/go-xorm/xorm" +) + +type Log struct { + Id int64 + Level int + Msg string `xorm:"TEXT"` +} + +// DatabaseWriter implements LoggerInterface and is used to log into database. +type DatabaseWriter struct { + Driver string `json:"driver"` + Conn string `json:"conn"` + Level int `json:"level"` + x *xorm.Engine +} + +func NewDatabase() LoggerInterface { + return &DatabaseWriter{Level: TRACE} +} + +// init database writer with json config. +// config like: +// { +// "driver": "mysql" +// "conn":"root:root@tcp(127.0.0.1:3306)/gogs?charset=utf8", +// "level": 0 +// } +// connection string is based on xorm. +func (d *DatabaseWriter) Init(jsonconfig string) (err error) { + if err = json.Unmarshal([]byte(jsonconfig), d); err != nil { + return err + } + d.x, err = xorm.NewEngine(d.Driver, d.Conn) + if err != nil { + return err + } + return d.x.Sync(new(Log)) +} + +// write message in database writer. +func (d *DatabaseWriter) WriteMsg(msg string, skip, level int) error { + if level < d.Level { + return nil + } + + _, err := d.x.Insert(&Log{Level: level, Msg: msg}) + return err +} + +func (_ *DatabaseWriter) Flush() { +} + +func (_ *DatabaseWriter) Destroy() { +} + +func init() { + Register("database", NewDatabase) +} diff --git a/modules/log/log.go b/modules/log/log.go index 6ca6b5b0b1..00f777e72a 100644 --- a/modules/log/log.go +++ b/modules/log/log.go @@ -87,12 +87,12 @@ func Fatal(skip int, format string, v ...interface{}) { os.Exit(1) } -// .___ _______________________________________________________ _________ ___________ -// | |\ \__ ___/\_ _____/\______ \_ _____/ _ \ \_ ___ \\_ _____/ -// | |/ | \| | | __)_ | _/| __)/ /_\ \/ \ \/ | __)_ -// | / | \ | | \ | | \| \/ | \ \____| \ -// |___\____|__ /____| /_______ / |____|_ /\___ /\____|__ /\______ /_______ / -// \/ \/ \/ \/ \/ \/ \/ +// .___ __ _____ +// | | _____/ |_ ____________/ ____\____ ____ ____ +// | |/ \ __\/ __ \_ __ \ __\\__ \ _/ ___\/ __ \ +// | | | \ | \ ___/| | \/| | / __ \\ \__\ ___/ +// |___|___| /__| \___ >__| |__| (____ /\___ >___ > +// \/ \/ \/ \/ \/ type LogLevel int @@ -168,7 +168,7 @@ func (l *Logger) SetLogger(adapter string, config string) error { l.outputs[adapter] = lg l.adapter = adapter } else { - panic("log: unknown adapter \"" + adapter + "\" (forgotten Register?)") + panic("log: unknown adapter \"" + adapter + "\" (forgotten register?)") } return nil } @@ -181,7 +181,7 @@ func (l *Logger) DelLogger(adapter string) error { lg.Destroy() delete(l.outputs, adapter) } else { - panic("log: unknown adapter \"" + adapter + "\" (forgotten Register?)") + panic("log: unknown adapter \"" + adapter + "\" (forgotten register?)") } return nil } diff --git a/modules/log/smtp.go b/modules/log/smtp.go new file mode 100644 index 0000000000..0a10e56a63 --- /dev/null +++ b/modules/log/smtp.go @@ -0,0 +1,87 @@ +// 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 log + +import ( + "encoding/json" + "fmt" + "net/smtp" + "strings" + "time" +) + +const ( + subjectPhrase = "Diagnostic message from server" +) + +// smtpWriter implements LoggerInterface and is used to send emails via given SMTP-server. +type SmtpWriter struct { + Username string `json:"Username"` + Password string `json:"password"` + Host string `json:"Host"` + Subject string `json:"subject"` + RecipientAddresses []string `json:"sendTos"` + Level int `json:"level"` +} + +// create smtp writer. +func NewSmtpWriter() LoggerInterface { + return &SmtpWriter{Level: TRACE} +} + +// init smtp writer with json config. +// config like: +// { +// "Username":"example@gmail.com", +// "password:"password", +// "host":"smtp.gmail.com:465", +// "subject":"email title", +// "sendTos":["email1","email2"], +// "level":LevelError +// } +func (sw *SmtpWriter) Init(jsonconfig string) error { + return json.Unmarshal([]byte(jsonconfig), sw) +} + +// write message in smtp writer. +// it will send an email with subject and only this message. +func (s *SmtpWriter) WriteMsg(msg string, skip, level int) error { + if level < s.Level { + return nil + } + + hp := strings.Split(s.Host, ":") + + // Set up authentication information. + auth := smtp.PlainAuth( + "", + s.Username, + s.Password, + hp[0], + ) + // Connect to the server, authenticate, set the sender and recipient, + // and send the email all in one step. + content_type := "Content-Type: text/plain" + "; charset=UTF-8" + mailmsg := []byte("To: " + strings.Join(s.RecipientAddresses, ";") + "\r\nFrom: " + s.Username + "<" + s.Username + + ">\r\nSubject: " + s.Subject + "\r\n" + content_type + "\r\n\r\n" + fmt.Sprintf(".%s", time.Now().Format("2006-01-02 15:04:05")) + msg) + + return smtp.SendMail( + s.Host, + auth, + s.Username, + s.RecipientAddresses, + mailmsg, + ) +} + +func (_ *SmtpWriter) Flush() { +} + +func (_ *SmtpWriter) Destroy() { +} + +func init() { + Register("smtp", NewSmtpWriter) +} diff --git a/public/ng/css/gogs.css b/public/ng/css/gogs.css index 96cf77a639..d352f0bf68 100644 --- a/public/ng/css/gogs.css +++ b/public/ng/css/gogs.css @@ -660,32 +660,41 @@ The dashboard page style #dashboard-sidebar-menu > li.last > a { border-top-right-radius: .3em; } +#dashboard-my-org li, #dashboard-my-repo li { border-bottom: 1px solid #EAEAEA; } +#dashboard-my-org li.private, #dashboard-my-repo li.private { background-color: #fcf8e9; } +#dashboard-my-org li:last-child, #dashboard-my-repo li:last-child { border-bottom: none; } +#dashboard-my-org li a, #dashboard-my-repo li a { padding: 6px 1.2em; display: block; } +#dashboard-my-org li a .octicon, #dashboard-my-repo li a .octicon { margin-right: 6px; color: #888; } +#dashboard-my-org li a:hover .repo-name, #dashboard-my-repo li a:hover .repo-name { text-decoration: underline; } +#dashboard-my-org .repo-name, #dashboard-my-repo .repo-name { font-size: 1.1em; } +#dashboard-my-org .repo-star, #dashboard-my-repo .repo-star { color: #888; } +#dashboard-my-org .repo-contrib-header, #dashboard-my-repo .repo-contrib-header { border-top: 1px solid #d6d6d6; } @@ -1139,6 +1148,17 @@ The register and sign-in page style overflow: auto; overflow-x: auto; overflow-y: hidden; + background: white; +} +.code-view .view-raw { + min-height: 40px; + text-align: center; + padding-top: 20px; +} +.code-view .view-raw .btn { + font-size: 1.05em; + line-height: 16px; + padding: 6px 8px; } .code-view table { width: 100%; @@ -1163,7 +1183,6 @@ The register and sign-in page style } .code-view .lines-code > pre { border: none; - background: none; border-left: 1px solid #ddd; } .code-view .lines-code > pre > ol.linenums > li { diff --git a/routers/install.go b/routers/install.go index 516d11e4aa..c63ac6909c 100644 --- a/routers/install.go +++ b/routers/install.go @@ -54,11 +54,12 @@ func GlobalInit() { log.Trace("Log path: %s", setting.LogRootPath) mailer.NewMailerContext() models.LoadModelsConfig() - models.LoadRepoConfig() - models.NewRepoContext() NewServices() if setting.InstallLock { + models.LoadRepoConfig() + models.NewRepoContext() + if err := models.NewEngine(); err != nil { log.Fatal(4, "Fail to initialize ORM engine: %v", err) } diff --git a/routers/user/home.go b/routers/user/home.go index b5a789ae0e..186cbe41a7 100644 --- a/routers/user/home.go +++ b/routers/user/home.go @@ -32,7 +32,6 @@ func Dashboard(ctx *middleware.Context) { ctx.Handle(500, "home.Dashboard(GetOrganizations)", err) return } - ctx.Data["Orgs"] = ctx.User.Orgs ctx.Data["ContextUser"] = ctx.User repos, err := models.GetRepositories(ctx.User.Id, true) @@ -40,9 +39,6 @@ func Dashboard(ctx *middleware.Context) { ctx.Handle(500, "GetRepositories", err) return } - for _, repo := range repos { - repo.Owner = ctx.User - } ctx.Data["Repos"] = repos ctx.Data["CollaborativeRepos"], err = models.GetCollaborativeRepos(ctx.User.Name) diff --git a/templates/org/home.tmpl b/templates/org/home.tmpl index a3c2326230..b6675d3059 100644 --- a/templates/org/home.tmpl +++ b/templates/org/home.tmpl @@ -34,7 +34,7 @@ </div> <h3 class="org-repo-name"><a href="/{{$.Org.Name}}/{{.Name}}">{{.Name}}</a></h3> <p class="org-repo-description">{{.Description}}</p> - <p class="org-repo-update">Updated {{TimeSince .Updated}}</p> + <p class="org-repo-update">Updated {{TimeSince .Updated $.Lang}}</p> </div> {{end}} </div> diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index 1958c40998..5f16a7baf0 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -74,7 +74,7 @@ <a href="#"> <button class="btn btn-gray btn-small btn-radius"> <i class="octicon octicon-git-branch"></i> Branch : - <strong id="repo-branch-current">{{.BranchName}}</strong> + <strong id="repo-branch-current">{{if .IsViewBranch}}{{.BranchName}}{{else}}{{ShortSha .BranchName}}{{end}}</strong> </button> </a> <div class="drop-down panel"> @@ -87,7 +87,7 @@ </ul> <ul class="menu menu-vertical switching-list" id="repo-branch-list"> {{range .Branches}} - <li {{if eq . $.BranchName}}class="checked"{{end}}><a href="{{$.RepoLink}}/src/{{.}}"><i class="octicon octicon-check"></i>master</a></li> + <li {{if eq . $.BranchName}}class="checked"{{end}}><a href="{{$.RepoLink}}/src/{{.}}"><i class="octicon octicon-check"></i>{{.}}</a></li> {{end}} </ul> <ul class="menu menu-vertical switching-list" id="repo-tag-list"> @@ -137,7 +137,7 @@ <a class="radius" href="{{.RepoLink}}/pulls"><i class="octicon octicon-git-pull-request"></i>Pull Requests<span class="num right label label-blue label-radius">{{.Repository.NumOpenPulls}}</span></a> </li> <li class="border-bottom"></li> - <li class="head">{{.BranchName}}</li> + <li class="head">{{if .IsViewBranch}}{{.BranchName}}{{else}}{{ShortSha .BranchName}}{{end}}</li> <li> <a class="radius" href="{{.RepoLink}}/commits/{{.BranchName}}"><i class="octicon octicon-history"></i>Commits <span class="num right label label-gray label-radius">{{.CommitsCount}}</span></a> </li> diff --git a/templates/repo/view_file.tmpl b/templates/repo/view_file.tmpl index be54419404..fb05945b9f 100644 --- a/templates/repo/view_file.tmpl +++ b/templates/repo/view_file.tmpl @@ -15,6 +15,14 @@ <div class="{{if .ReadmeExist}}panel-content markdown{{end}} code-view"> {{if .ReadmeExist}} {{.FileContent | Str2html}} + {{else if not .IsFileText}} + <div class="view-raw"> + {{if .IsImageFile}} + <img src="{{.FileLink}}"> + {{else}} + <a href="{{.FileLink}}" rel="nofollow" class="btn btn-gray btn-radius">View Raw</a> + {{end}} + </div> {{else if .FileSize}} <table> <tbody> diff --git a/templates/user/dashboard/dashboard.tmpl b/templates/user/dashboard/dashboard.tmpl index 209a495b58..b472953136 100644 --- a/templates/user/dashboard/dashboard.tmpl +++ b/templates/user/dashboard/dashboard.tmpl @@ -48,7 +48,9 @@ <div id="dashboard-sidebar" class="right grid-1-3"> <ul id="dashboard-sidebar-menu" class="menu menu-line"> <li class="js-tab-nav js-tab-nav-show first" data-tab-target="#dashboard-my-repo"><a href="#">{{.i18n.Tr "repository"}}</a></li> + {{if not .ContextUser.IsOrganization}} <li class="js-tab-nav" data-tab-target="#dashboard-my-org"><a href="#">{{.i18n.Tr "organization"}}</a></li> + {{end}} <li class="js-tab-nav last" data-tab-target="#dashboard-my-mirror"><a href="#">{{.i18n.Tr "mirror"}}</a></li> <li class="drop right"> <button class="btn btn-green text-bold" id="dashboard-new-repo"> @@ -70,26 +72,68 @@ <div class="panel-body"> <ul class="list-no-style"> {{range .Repos}} - {{template "user/dashboard/repo_list" .}} + <li {{if .IsPrivate}}class="private"{{end}}> + <a href="{{$.ContextUser.Name}}/{{.Name}}"> + <i class="octicon octicon-{{if .IsPrivate}}lock{{else if .IsFork}}repo-forked{{else if .IsMirror}}repo-clone{{else}}repo{{end}}"></i> + <span class="repo-name"> + <strong class="repo">{{.Name}}</strong> + </span> + <span class="right repo-star"> + <i class="octicon octicon-star"></i>{{.NumStars}} + </span> + </a> + </li> {{end}} </ul> </div> + {{if not .ContextUser.IsOrganization}} <div class="panel-header repo-contrib-header"> <h4 class="text-bold">{{.i18n.Tr "home.collaborative_repos"}}</h4> </div> <div class="panel-body"> <ul class="list-no-style"> {{range .CollaborativeRepos}} - {{template "user/dashboard/repo_list" .}} + <li {{if .IsPrivate}}class="private"{{end}}> + <a href="{{.Owner.Name}}/{{.Name}}"> + <i class="octicon octicon-{{if .IsPrivate}}lock{{else if .IsFork}}repo-forked{{else if .IsMirror}}repo-clone{{else}}repo{{end}}"></i> + <span class="repo-name"> + <span class="repo-name-prefix">{{.Owner.Name}} / </span> + <strong class="repo">{{.Name}}</strong> + </span> + <span class="right repo-star"> + <i class="octicon octicon-star"></i>{{.NumStars}} + </span> + </a> + </li> {{end}} </ul> </div> + {{end}} </div> + {{if not .ContextUser.IsOrganization}} <div class="panel" id="dashboard-my-org"> <div class="panel-header"> <h4 class="text-bold">{{.i18n.Tr "home.my_orgs"}}</h4> </div> + <div class="panel-body"> + <ul class="list-no-style"> + {{range .ContextUser.Orgs}} + <li> + <a href="/{{.Name}}"> + <i class="octicon octicon-organization"></i> + <span class="repo-name"> + <strong class="repo">{{.Name}}</strong> + </span> + <span class="right repo-star"> + <i class="octicon octicon-repo"></i>{{.NumRepos}} + </span> + </a> + </li> + {{end}} + </ul> + </div> </div> + {{end}} <div class="panel" id="dashboard-my-mirror"> <div class="panel-header"> <h4 class="text-bold">{{.i18n.Tr "home.my_mirrors"}}</h4> diff --git a/templates/user/dashboard/nav.tmpl b/templates/user/dashboard/nav.tmpl index 6064f35692..a2d990fa7d 100644 --- a/templates/user/dashboard/nav.tmpl +++ b/templates/user/dashboard/nav.tmpl @@ -15,7 +15,7 @@ {{.SignedUser.Name}} </a> </li> - {{range .Orgs}} + {{range .ContextUser.Orgs}} <li class="org {{if eq $.ContextUser.Id .Id}}checked{{end}}"> <a href="{{.DashboardLink}}"> <i class="octicon octicon-check"></i> diff --git a/templates/user/dashboard/repo_list.tmpl b/templates/user/dashboard/repo_list.tmpl deleted file mode 100644 index e3d35e8ecc..0000000000 --- a/templates/user/dashboard/repo_list.tmpl +++ /dev/null @@ -1,12 +0,0 @@ -<li {{if .IsPrivate}}class="private"{{end}}> - <a href="{{.Owner.Name}}/{{.Name}}"> - <i class="octicon octicon-{{if .IsPrivate}}lock{{else if .IsFork}}repo-forked{{else if .IsMirror}}repo-clone{{else}}repo{{end}}"></i> - <span class="repo-name"> - <!-- <span class="repo-name-prefix">gogits / </span> --> - <strong class="repo">{{.Name}}</strong> - </span> - <span class="right repo-star"> - <i class="octicon octicon-star"></i>{{.NumStars}} - </span> - </a> -</li>
\ No newline at end of file |