From d0f887a1edf3937a495c54d9a345a36018041b79 Mon Sep 17 00:00:00 2001 From: Steven Pav <shabbychef@gmail.com> Date: Fri, 25 Apr 2014 15:21:48 -0700 Subject: [PATCH 01/13] explicitly install sudo ```deploy.sh``` in the docker container requires ```sudo```; this should resolve #127. --- dockerfiles/images/gogits/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dockerfiles/images/gogits/Dockerfile b/dockerfiles/images/gogits/Dockerfile index 25d1dd5e5c..7f1514efeb 100644 --- a/dockerfiles/images/gogits/Dockerfile +++ b/dockerfiles/images/gogits/Dockerfile @@ -13,7 +13,7 @@ ENV GOROOT /usr/local/go ENV GOPATH /go RUN apt-get update && apt-get install --yes --force-yes curl git mercurial zip wget ca-certificates build-essential -RUN apt-get install -yq vim +RUN apt-get install -yq vim sudo RUN curl -s http://docker.u.qiniudn.com/go1.2.1.src.tar.gz | tar -v -C /usr/local -xz RUN cd /usr/local/go/src && ./make.bash --no-clean 2>&1 From 1b734501bdbec3a0ff04458944683eae0990d9ae Mon Sep 17 00:00:00 2001 From: Lunny Xiao <xiaolunwen@gmail.com> Date: Sat, 26 Apr 2014 14:14:48 +0800 Subject: [PATCH 02/13] bug fixed --- modules/base/conf.go | 8 ++++---- serve.go | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/base/conf.go b/modules/base/conf.go index 5724504503..04c1245774 100644 --- a/modules/base/conf.go +++ b/modules/base/conf.go @@ -316,7 +316,7 @@ func NewConfigContext() { // load LDAP authentication configuration if present LdapAuth = Cfg.MustBool("security", "LDAP_AUTH", false) if LdapAuth { - log.Debug("LDAP AUTHENTICATION activated") + qlog.Debug("LDAP AUTHENTICATION activated") nbsrc := 0 for _, v := range Cfg.GetSectionList() { if matched, _ := regexp.MatchString("(?i)^LDAPSOURCE.*", v); matched { @@ -329,15 +329,15 @@ func NewConfigContext() { ldapmsadsaformat := Cfg.MustValue(v, "MSADSAFORMAT", "%s") ldap.AddSource(ldapname, ldaphost, ldapport, ldapbasedn, ldapattribute, ldapfilter, ldapmsadsaformat) nbsrc += 1 - log.Debug("%s added as LDAP source", ldapname) + qlog.Debug("%s added as LDAP source", ldapname) } } if nbsrc == 0 { - log.Debug("No valide LDAP found, LDAP AUTHENTICATION NOT activated") + qlog.Debug("No valide LDAP found, LDAP AUTHENTICATION NOT activated") LdapAuth = false } } else { - log.Debug("LDAP AUTHENTICATION NOT activated") + qlog.Debug("LDAP AUTHENTICATION NOT activated") } PictureService = Cfg.MustValue("picture", "SERVICE") diff --git a/serve.go b/serve.go index 7f8c267c78..e3197a23de 100644 --- a/serve.go +++ b/serve.go @@ -53,6 +53,7 @@ func newLogger(execDir string) { } qlog.SetOutput(f) + //qlog.SetOutputLevel(qlog.Ldebug) qlog.Info("Start logging serv...") } From 9dfb7de3715c11e9569de62cd03b7787e58d0d91 Mon Sep 17 00:00:00 2001 From: Unknown <joe2010xtmf@163.com> Date: Sat, 26 Apr 2014 01:22:22 -0600 Subject: [PATCH 03/13] Fix #102 --- README.md | 5 ++ README_ZH.md | 6 +++ doc/install_gogs_from_binary_on_ubuntu.md | 4 +- gogs.go | 2 +- modules/base/conf.go | 58 ++++++++++++----------- 5 files changed, 45 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 0387807219..d188508ec6 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,11 @@ More importantly, Gogs only needs one binary to setup your own project hosting o - Supports MySQL, PostgreSQL and SQLite3. - Social account login(GitHub, Google, QQ, Weibo) +## System Requirements + +- A cheap Raspberry Pi is powerful enough to match the minimal requirement. +- 4 CPU Cores and 1GB RAM would be the baseline for teamwork. + ## Installation Make sure you install [Prerequirements](https://github.com/gogits/gogs/wiki/Prerequirements) first. diff --git a/README_ZH.md b/README_ZH.md index 6d7553a684..bbf461ddf6 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -33,6 +33,12 @@ Gogs 完全使用 Go 语言来实现对 Git 数据的操作,实现 **零** 依 - 支持 MySQL、PostgreSQL 以及 SQLite3 数据库 - 社交帐号登录(GitHub、Google、QQ、微博) +## 系统要求 + +- 最低的系统硬件要求为一个廉价的树莓派 +- 如果用于团队项目,建议使用 4 核 CPU 及 1GB 内存 + + ## 安装部署 在安装 Gogs 之前,您需要先安装 [基本环境](https://github.com/gogits/gogs/wiki/Prerequirements)。 diff --git a/doc/install_gogs_from_binary_on_ubuntu.md b/doc/install_gogs_from_binary_on_ubuntu.md index 6d004106cf..3b406b3643 100644 --- a/doc/install_gogs_from_binary_on_ubuntu.md +++ b/doc/install_gogs_from_binary_on_ubuntu.md @@ -18,8 +18,8 @@ ### install the gogs - mkdir gogs - cd gogs -- curl -L http://gobuild.io/github.com/gogits/gogs/v0.2.0/linux/amd64 -o v0.2.0.zip -- unzip v0.2.0.zip +- curl -L http://gobuild.io/github.com/gogits/gogs/v0.3.0/linux/amd64 -o v0.3.0.zip +- unzip v0.3.0.zip - ./start.sh > The up-to-date binary could be found at diff --git a/gogs.go b/gogs.go index b06c80064c..caa8cf63db 100644 --- a/gogs.go +++ b/gogs.go @@ -19,7 +19,7 @@ import ( // Test that go1.2 tag above is included in builds. main.go refers to this definition. const go12tag = true -const APP_VER = "0.3.0.0422 Alpha" +const APP_VER = "0.3.0.0426 Alpha" func init() { base.AppVer = APP_VER diff --git a/modules/base/conf.go b/modules/base/conf.go index 04c1245774..e89c67bc1b 100644 --- a/modules/base/conf.go +++ b/modules/base/conf.go @@ -178,6 +178,36 @@ func newLogService() { log.Info("Log Mode: %s(%s)", strings.Title(LogMode), levelName) } +func newLdapService() { + LdapAuth = Cfg.MustBool("security", "LDAP_AUTH", false) + if !LdapAuth { + return + } + + nbsrc := 0 + for _, v := range Cfg.GetSectionList() { + if matched, _ := regexp.MatchString("(?i)^LDAPSOURCE.*", v); matched { + ldapname := Cfg.MustValue(v, "name", v) + ldaphost := Cfg.MustValue(v, "host") + ldapport := Cfg.MustInt(v, "port", 389) + ldapbasedn := Cfg.MustValue(v, "basedn", "dc=*,dc=*") + ldapattribute := Cfg.MustValue(v, "attribute", "mail") + ldapfilter := Cfg.MustValue(v, "filter", "(*)") + ldapmsadsaformat := Cfg.MustValue(v, "MSADSAFORMAT", "%s") + ldap.AddSource(ldapname, ldaphost, ldapport, ldapbasedn, ldapattribute, ldapfilter, ldapmsadsaformat) + nbsrc++ + log.Debug("%s added as LDAP source", ldapname) + } + } + if nbsrc == 0 { + log.Warn("No valide LDAP found, LDAP Authentication NOT enabled") + LdapAuth = false + return + } + + log.Info("LDAP Authentication Enabled") +} + func newCacheService() { CacheAdapter = Cfg.MustValue("cache", "ADAPTER", "memory") if EnableRedis { @@ -313,33 +343,6 @@ func NewConfigContext() { CookieUserName = Cfg.MustValue("security", "COOKIE_USERNAME") CookieRememberName = Cfg.MustValue("security", "COOKIE_REMEMBER_NAME") - // load LDAP authentication configuration if present - LdapAuth = Cfg.MustBool("security", "LDAP_AUTH", false) - if LdapAuth { - qlog.Debug("LDAP AUTHENTICATION activated") - nbsrc := 0 - for _, v := range Cfg.GetSectionList() { - if matched, _ := regexp.MatchString("(?i)^LDAPSOURCE.*", v); matched { - ldapname := Cfg.MustValue(v, "name", v) - ldaphost := Cfg.MustValue(v, "host") - ldapport := Cfg.MustInt(v, "port", 389) - ldapbasedn := Cfg.MustValue(v, "basedn", "dc=*,dc=*") - ldapattribute := Cfg.MustValue(v, "attribute", "mail") - ldapfilter := Cfg.MustValue(v, "filter", "(*)") - ldapmsadsaformat := Cfg.MustValue(v, "MSADSAFORMAT", "%s") - ldap.AddSource(ldapname, ldaphost, ldapport, ldapbasedn, ldapattribute, ldapfilter, ldapmsadsaformat) - nbsrc += 1 - qlog.Debug("%s added as LDAP source", ldapname) - } - } - if nbsrc == 0 { - qlog.Debug("No valide LDAP found, LDAP AUTHENTICATION NOT activated") - LdapAuth = false - } - } else { - qlog.Debug("LDAP AUTHENTICATION NOT activated") - } - PictureService = Cfg.MustValue("picture", "SERVICE") // Determine and create root git reposiroty path. @@ -357,6 +360,7 @@ func NewConfigContext() { func NewBaseServices() { newService() newLogService() + newLdapService() newCacheService() newSessionService() newMailService() From cfa09681919f9075063e8f8d84ee8bab20108791 Mon Sep 17 00:00:00 2001 From: fundon <cfddream@gmail.com> Date: Sun, 27 Apr 2014 01:55:22 +0800 Subject: [PATCH 04/13] Fixed codename match issue, when using `FROM ubuntu` wil be pulled latest image --- dockerfiles/images/postgres/Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dockerfiles/images/postgres/Dockerfile b/dockerfiles/images/postgres/Dockerfile index 44e82b7d88..0188dd78fb 100644 --- a/dockerfiles/images/postgres/Dockerfile +++ b/dockerfiles/images/postgres/Dockerfile @@ -9,7 +9,8 @@ RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys B97B0AFCAA # Add PostgreSQL's repository. It contains the most recent stable release # of PostgreSQL, ``9.3``. -RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ precise-pgdg main" > /etc/apt/sources.list.d/pgdg.list +# See http://apt.postgresql.org/pub/repos/apt/README +RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list # Update the Ubuntu and PostgreSQL repository indexes RUN apt-get update From 1badb2bbccfe81303f69f8dedf57c22fb89d4b99 Mon Sep 17 00:00:00 2001 From: Unknown <joe2010xtmf@163.com> Date: Sat, 26 Apr 2014 19:06:59 -0600 Subject: [PATCH 05/13] Fix #107 --- models/repo.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/models/repo.go b/models/repo.go index 2011ed7de1..2457174372 100644 --- a/models/repo.go +++ b/models/repo.go @@ -403,10 +403,11 @@ func initRepository(f string, user *User, repo *Repository, initReadme bool, rep return err } + rp := strings.NewReplacer("\\", "/", " ", "\\ ") // hook/post-update if err := createHookUpdate(filepath.Join(repoPath, "hooks", "update"), fmt.Sprintf("#!/usr/bin/env %s\n%s update $1 $2 $3\n", base.ScriptType, - strings.Replace(appPath, "\\", "/", -1))); err != nil { + rp.Replace(appPath))); err != nil { return err } From 59d0e73c3507296b31c8e741b44afc7bfe1eb695 Mon Sep 17 00:00:00 2001 From: Unknown <joe2010xtmf@163.com> Date: Sat, 26 Apr 2014 22:34:48 -0600 Subject: [PATCH 06/13] Batch mirror fix --- .gopmfile | 1 + CONTRIBUTING.md | 2 ++ modules/base/conf.go | 8 +++--- modules/middleware/repo.go | 7 +++-- public/js/app.js | 4 +-- routers/install.go | 16 +++++++++++- routers/user/user.go | 8 +++--- templates/base/footer.tmpl | 5 +++- templates/install.tmpl | 13 +++++----- templates/repo/single_file.tmpl | 45 +++++++++++++++++---------------- tests/.travel.yml | 9 ------- tests/README.md | 13 ---------- tests/default_test.go | 17 ------------- 13 files changed, 68 insertions(+), 80 deletions(-) delete mode 100644 tests/.travel.yml delete mode 100644 tests/README.md delete mode 100644 tests/default_test.go diff --git a/.gopmfile b/.gopmfile index 296d02367e..c58f4299d4 100644 --- a/.gopmfile +++ b/.gopmfile @@ -19,6 +19,7 @@ github.com/lib/pq = github.com/nfnt/resize = github.com/qiniu/log = github.com/robfig/cron = +github.com/juju2013/goldap = [res] include = templates|public|conf diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cfc6c14f21..6cc88515f7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,6 +10,8 @@ Want to hack on Gogs? Awesome! Here are instructions to get you started. They ar ### Pull requests are always welcome +**ALL PULL REQUESTS MUST SEND TO `DEV` BRANCH** + We are always thrilled to receive pull requests, and do our best to process them as fast as possible. Not sure if that typo is worth a pull request? Do it! We will appreciate it. If your pull request is not accepted on the first try, don't be discouraged! If there's a problem with the implementation, hopefully you received feedback on what to improve. diff --git a/modules/base/conf.go b/modules/base/conf.go index 9a9adfdac6..17b55316a8 100644 --- a/modules/base/conf.go +++ b/modules/base/conf.go @@ -53,7 +53,6 @@ var ( Domain string SecretKey string RunUser string - LdapAuth bool RepoRootPath string ScriptType string @@ -93,6 +92,7 @@ var Service struct { NotifyMail bool ActiveCodeLives int ResetPwdCodeLives int + LdapAuth bool } func ExecDir() (string, error) { @@ -179,8 +179,8 @@ func newLogService() { } func newLdapService() { - LdapAuth = Cfg.MustBool("security", "LDAP_AUTH", false) - if !LdapAuth { + Service.LdapAuth = Cfg.MustBool("security", "LDAP_AUTH", false) + if !Service.LdapAuth { return } @@ -201,7 +201,7 @@ func newLdapService() { } if nbsrc == 0 { log.Warn("No valide LDAP found, LDAP Authentication NOT enabled") - LdapAuth = false + Service.LdapAuth = false return } diff --git a/modules/middleware/repo.go b/modules/middleware/repo.go index 34144fe3d8..2d2778cb00 100644 --- a/modules/middleware/repo.go +++ b/modules/middleware/repo.go @@ -26,11 +26,14 @@ func RepoAssignment(redirect bool, args ...bool) martini.Handler { var displayBare bool if len(args) >= 1 { - validBranch = args[0] + // Note: argument has wrong value in Go1.3 martini. + // validBranch = args[0] + validBranch = true } if len(args) >= 2 { - displayBare = args[1] + // displayBare = args[1] + displayBare = true } var ( diff --git a/public/js/app.js b/public/js/app.js index a5c79a3987..b7b5deb83b 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -470,10 +470,10 @@ function initInstall() { (function () { $('#install-database').on("change", function () { var val = $(this).val(); - if (val != "sqlite") { + if (val != "SQLite3") { $('.server-sql').show(); $('.sqlite-setting').addClass("hide"); - if (val == "pgsql") { + if (val == "PostgreSQL") { $('.pgsql-setting').removeClass("hide"); } else { $('.pgsql-setting').addClass("hide"); diff --git a/routers/install.go b/routers/install.go index 12182ad300..8ffa9b5d1a 100644 --- a/routers/install.go +++ b/routers/install.go @@ -65,6 +65,10 @@ func GlobalInit() { checkRunMode() } +func renderDbOption(ctx *middleware.Context) { + ctx.Data["DbOptions"] = []string{"MySQL", "PostgreSQL", "SQLite3"} +} + func Install(ctx *middleware.Context, form auth.InstallForm) { if base.InstallLock { ctx.Handle(404, "install.Install", errors.New("Installation is prohibited")) @@ -104,6 +108,13 @@ func Install(ctx *middleware.Context, form auth.InstallForm) { form.AppUrl = base.AppUrl } + renderDbOption(ctx) + curDbValue := "" + if models.EnableSQLite3 { + curDbValue = "SQLite3" // Default when enabled. + } + ctx.Data["CurDbValue"] = curDbValue + auth.AssignForm(form, ctx.Data) ctx.HTML(200, "install") } @@ -117,6 +128,9 @@ func InstallPost(ctx *middleware.Context, form auth.InstallForm) { ctx.Data["Title"] = "Install" ctx.Data["PageIsInstall"] = true + renderDbOption(ctx) + ctx.Data["CurDbValue"] = form.Database + if ctx.HasError() { ctx.HTML(200, "install") return @@ -129,7 +143,7 @@ func InstallPost(ctx *middleware.Context, form auth.InstallForm) { // Pass basic check, now test configuration. // Test database setting. - dbTypes := map[string]string{"mysql": "mysql", "pgsql": "postgres", "sqlite": "sqlite3"} + dbTypes := map[string]string{"MySQL": "mysql", "PostgreSQL": "postgres", "SQLite3": "sqlite3"} models.DbCfg.Type = dbTypes[form.Database] models.DbCfg.Host = form.Host models.DbCfg.User = form.User diff --git a/routers/user/user.go b/routers/user/user.go index 75314237dd..fe53896e41 100644 --- a/routers/user/user.go +++ b/routers/user/user.go @@ -91,12 +91,14 @@ func SignInPost(ctx *middleware.Context, form auth.LogInForm) { var user *models.User var err error - // try to login against LDAP if defined - if base.LdapAuth { + if base.Service.LdapAuth { user, err = models.LoginUserLdap(form.UserName, form.Password) + if err != nil { + log.Error("Fail to login through LDAP: %v", err) + } } // try local if not LDAP or it's failed - if (!base.LdapAuth) || (err != nil) { + if !base.Service.LdapAuth || err != nil { user, err = models.LoginUserPlain(form.UserName, form.Password) } if err != nil { diff --git a/templates/base/footer.tmpl b/templates/base/footer.tmpl index 6c2da63e5d..30f068913c 100644 --- a/templates/base/footer.tmpl +++ b/templates/base/footer.tmpl @@ -13,7 +13,10 @@ <div class="col-md-1" style="margin: -5px;"> <a target="_blank" href="https://github.com/gogits/gogs"><i class="fa fa-github fa-2x"></i></a> </div> - <p class="desc"></p> + + <div class="col-md-5"> + <p class="desc"></p> + </div> </div> </div> </footer> diff --git a/templates/install.tmpl b/templates/install.tmpl index 2ed7e569d1..8fe678e509 100644 --- a/templates/install.tmpl +++ b/templates/install.tmpl @@ -9,14 +9,15 @@ <label class="col-md-3 control-label">Database Type: </label> <div class="col-md-8"> <select name="database" id="install-database" class="form-control"> - <option value="mysql">MySQL</option> - <option value="pgsql">PostgreSQL</option> - <option value="sqlite">SQLite3</option> + {{if .CurDbValue}}<option value="{{.CurDbValue}}">{{.CurDbValue}}</option>{{end}} + {{range .DbOptions}} + {{if not (eq $.CurDbValue .)}}<option value="{{.}}">{{.}}</option>{{end}} + {{end}} </select> </div> </div> - <div class="server-sql"> + <div class="server-sql {{if eq .CurDbValue "SQLite3"}}hide{{end}}"> <div class="form-group"> <label class="col-md-3 control-label">Host: </label> <div class="col-md-8"> @@ -49,7 +50,7 @@ </div> </div> - <div class="form-group pgsql-setting hide"> + <div class="form-group pgsql-setting {{if not (eq .CurDbValue "PostgreSQL")}}hide{{end}}"> <label class="col-md-3 control-label">SSL Mode: </label> <div class="col-md-8"> <select name="ssl_mode" class="form-control"> @@ -61,7 +62,7 @@ </div> </div> - <div class="sqlite-setting hide"> + <div class="sqlite-setting {{if not (eq .CurDbValue "SQLite3")}}hide{{end}}"> <div class="form-group"> <label class="col-md-3 control-label">Path: </label> diff --git a/templates/repo/single_file.tmpl b/templates/repo/single_file.tmpl index 9199ca91f7..b8205024c5 100644 --- a/templates/repo/single_file.tmpl +++ b/templates/repo/single_file.tmpl @@ -21,30 +21,31 @@ </div> {{end}} </div> + {{if not .FileIsText}} - <div class="panel-footer text-center"> - {{if .IsImageFile}} - <img src="{{.FileLink}}"> - {{else}} - <a href="{{.FileLink}}" class="btn btn-default">View Raw</a> - {{end}} - </div> - {{else}} - {{if .ReadmeExist}} - <div class="panel-body file-body markdown"> - {{.FileContent|str2html}} - </div> + <div class="panel-body file-body file-code code-view"> + {{if .IsImageFile}} + <img src="{{.FileLink}}"> {{else}} - <div class="panel-body file-body file-code code-view"> - <table> - <tbody> - <tr> - <td class="lines-num"></td> - <td class="lines-code markdown"><pre class="prettyprint linenums{{if .FileExt}} lang-{{.FileExt}}{{end}}">{{.FileContent}}</pre></td> - </tr> - </tbody> - </table> - </div> + <a href="{{.FileLink}}" class="btn btn-default">View Raw</a> {{end}} + </div> + {{else}} + {{if .ReadmeExist}} + <div class="panel-body file-body markdown"> + {{.FileContent|str2html}} + </div> + {{else}} + <div class="panel-body file-body file-code code-view"> + <table> + <tbody> + <tr> + <td class="lines-num"></td> + <td class="lines-code markdown"><pre class="prettyprint linenums{{if .FileExt}} lang-{{.FileExt}}{{end}}">{{.FileContent}}</pre></td> + </tr> + </tbody> + </table> + </div> + {{end}} {{end}} </div> diff --git a/tests/.travel.yml b/tests/.travel.yml deleted file mode 100644 index 09a5752bfb..0000000000 --- a/tests/.travel.yml +++ /dev/null @@ -1,9 +0,0 @@ -command: go test -v {} -include: ^.+_test\.go$ -path: ./ -depth: 1 -verbose: true -timeout: 1m -reload: false -html: test.html -notify: [] diff --git a/tests/README.md b/tests/README.md deleted file mode 100644 index e51b251037..0000000000 --- a/tests/README.md +++ /dev/null @@ -1,13 +0,0 @@ -## Gogs Test - -This is for developers. - -## Prepare Environment - - go get -u github.com/shxsun/travelexec - # start gogs server - gogs web - -## Start Testing - - travelexec diff --git a/tests/default_test.go b/tests/default_test.go deleted file mode 100644 index d6f3a03be6..0000000000 --- a/tests/default_test.go +++ /dev/null @@ -1,17 +0,0 @@ -package test - -import ( - "net/http" - "testing" -) - -func TestMain(t *testing.T) { - r, err := http.Get("http://localhost:3000/") - if err != nil { - t.Fatal(err) - } - defer r.Body.Close() - if r.StatusCode != http.StatusOK { - t.Error(r.StatusCode) - } -} From 8a8f84d245ed7b5cd007b43747098663019654c7 Mon Sep 17 00:00:00 2001 From: Chris Lee <clee@mg8.org> Date: Sun, 27 Apr 2014 06:46:03 +0000 Subject: [PATCH 07/13] Use commit summaries instead of full messages --- routers/repo/commit.go | 2 +- templates/repo/commits.tmpl | 2 +- templates/repo/single_list.tmpl | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/routers/repo/commit.go b/routers/repo/commit.go index 6e20a7b7f4..9ecc697d27 100644 --- a/routers/repo/commit.go +++ b/routers/repo/commit.go @@ -92,7 +92,7 @@ func Diff(ctx *middleware.Context, params martini.Params) { } ctx.Data["IsImageFile"] = isImageFile - ctx.Data["Title"] = commit.Message() + " · " + base.ShortSha(commitId) + ctx.Data["Title"] = commit.Summary() + " · " + base.ShortSha(commitId) ctx.Data["Commit"] = commit ctx.Data["Diff"] = diff ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0 diff --git a/templates/repo/commits.tmpl b/templates/repo/commits.tmpl index b14c6bc8c6..cf665b6b70 100644 --- a/templates/repo/commits.tmpl +++ b/templates/repo/commits.tmpl @@ -33,7 +33,7 @@ <tr> <td class="author"><img class="avatar" src="{{AvatarLink .Author.Email}}" alt=""/><a href="/user/email2user?email={{.Author.Email}}">{{.Author.Name}}</a></td> <td class="sha"><a rel="nofollow" class="label label-success" href="/{{$username}}/{{$reponame}}/commit/{{.Id}} ">{{SubStr .Id.String 0 10}} </a></td> - <td class="message">{{.Message}} </td> + <td class="message">{{.Summary}} </td> <td class="date">{{TimeSince .Author.When}}</td> </tr> {{end}} diff --git a/templates/repo/single_list.tmpl b/templates/repo/single_list.tmpl index 7b6c6e5e9c..9c157d1b19 100644 --- a/templates/repo/single_list.tmpl +++ b/templates/repo/single_list.tmpl @@ -1,6 +1,6 @@ <div class="panel panel-default info-box"> <div class="panel-heading info-head"> - <a href="/{{.Username}}/{{.Reponame}}/commit/{{.LastCommit.Id}}">{{.LastCommit.Message}}</a> + <a href="/{{.Username}}/{{.Reponame}}/commit/{{.LastCommit.Id}}">{{.LastCommit.Summary}}</a> </div> <div class="panel-body info-content"> <a href="/user/{{.LastCommit.Author.Name}}">{{.LastCommit.Author.Name}}</a> <span class="text-muted">{{TimeSince .LastCommit.Author.When}}</span> @@ -36,7 +36,7 @@ </span> </td> <td class="text"> - <span class="wrap"><a rel="nofollow" href="/{{$.Username}}/{{$.Reponame}}/commit/{{$commit.Id}}">{{$commit.Message}}</a></span> + <span class="wrap"><a rel="nofollow" href="/{{$.Username}}/{{$.Reponame}}/commit/{{$commit.Id}}">{{$commit.Summary}}</a></span> </td> <td class="date"> <span class="wrap">{{TimeSince $commit.Committer.When}}</span> From 62d23e91541550d0478c4884696e918a0e818b4f Mon Sep 17 00:00:00 2001 From: Unknown <joe2010xtmf@163.com> Date: Sun, 27 Apr 2014 01:05:13 -0600 Subject: [PATCH 08/13] HTTP no follow and offline mode --- conf/app.ini | 2 ++ gogs.go | 2 +- models/repo.go | 16 ++------------- models/update.go | 10 +++++++-- modules/base/conf.go | 18 +++++++++-------- modules/base/template.go | 10 ++++----- routers/admin/admin.go | 2 ++ routers/install.go | 2 +- templates/admin/config.tmpl | 4 ++++ templates/base/head.tmpl | 2 +- templates/base/navbar.tmpl | 6 +++--- templates/release/list.tmpl | 36 ++++++--------------------------- templates/repo/commits.tmpl | 4 ++-- templates/repo/nav.tmpl | 4 ++-- templates/repo/single_file.tmpl | 4 ++-- templates/repo/single_list.tmpl | 2 +- templates/user/profile.tmpl | 6 +++--- 17 files changed, 55 insertions(+), 75 deletions(-) diff --git a/conf/app.ini b/conf/app.ini index 25fd41091f..e7174e2251 100644 --- a/conf/app.ini +++ b/conf/app.ini @@ -16,6 +16,8 @@ LICENSES = Apache v2 License|GPL v2|MIT License|Affero GPL|Artistic License 2.0| PROTOCOL = http DOMAIN = localhost ROOT_URL = %(PROTOCOL)s://%(DOMAIN)s:%(HTTP_PORT)s/ +; Disable CDN even in "prod" mode +OFFLINE_MODE = false HTTP_ADDR = HTTP_PORT = 3000 ; Generate steps: diff --git a/gogs.go b/gogs.go index caa8cf63db..1a8b4d1312 100644 --- a/gogs.go +++ b/gogs.go @@ -19,7 +19,7 @@ import ( // Test that go1.2 tag above is included in builds. main.go refers to this definition. const go12tag = true -const APP_VER = "0.3.0.0426 Alpha" +const APP_VER = "0.3.0.0427 Alpha" func init() { base.AppVer = APP_VER diff --git a/models/repo.go b/models/repo.go index 2457174372..5f66bca86d 100644 --- a/models/repo.go +++ b/models/repo.go @@ -159,9 +159,7 @@ func MirrorUpdate() { repoPath := filepath.Join(base.RepoRootPath, m.RepoName+".git") _, stderr, err := com.ExecCmdDir(repoPath, "git", "remote", "update") if err != nil { - return err - } else if strings.Contains(stderr, "fatal:") { - return errors.New(stderr) + return errors.New("git remote update: " + stderr) } else if err = git.UnpackRefs(repoPath); err != nil { return err } @@ -177,9 +175,7 @@ func MirrorUpdate() { func MirrorRepository(repoId int64, userName, repoName, repoPath, url string) error { _, stderr, err := com.ExecCmd("git", "clone", "--mirror", url, repoPath) if err != nil { - return err - } else if strings.Contains(stderr, "fatal:") { - return errors.New(stderr) + return errors.New("git clone --mirror: " + stderr) } if _, err = orm.InsertOne(&Mirror{ @@ -219,23 +215,17 @@ func MigrateRepository(user *User, name, desc string, private, mirror bool, url // Clone from local repository. _, stderr, err := com.ExecCmd("git", "clone", repoPath, tmpDir) if err != nil { - return repo, err - } else if strings.Contains(stderr, "fatal:") { return repo, errors.New("git clone: " + stderr) } // Pull data from source. _, stderr, err = com.ExecCmdDir(tmpDir, "git", "pull", url) if err != nil { - return repo, err - } else if strings.Contains(stderr, "fatal:") { return repo, errors.New("git pull: " + stderr) } // Push data to local repository. if _, stderr, err = com.ExecCmdDir(tmpDir, "git", "push", "origin", "master"); err != nil { - return repo, err - } else if strings.Contains(stderr, "fatal:") { return repo, errors.New("git push: " + stderr) } @@ -429,8 +419,6 @@ func initRepository(f string, user *User, repo *Repository, initReadme bool, rep _, stderr, err := com.ExecCmd("git", "clone", repoPath, tmpDir) if err != nil { - return err - } else if strings.Contains(stderr, "fatal:") { return errors.New("git clone: " + stderr) } diff --git a/models/update.go b/models/update.go index 2f59547b72..648c45f160 100644 --- a/models/update.go +++ b/models/update.go @@ -1,3 +1,7 @@ +// 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 models import ( @@ -5,9 +9,11 @@ import ( "os/exec" "strings" - "github.com/gogits/git" - "github.com/gogits/gogs/modules/base" qlog "github.com/qiniu/log" + + "github.com/gogits/git" + + "github.com/gogits/gogs/modules/base" ) func Update(refName, oldCommitId, newCommitId, userName, repoName string, userId int64) { diff --git a/modules/base/conf.go b/modules/base/conf.go index 17b55316a8..cfc85ff51e 100644 --- a/modules/base/conf.go +++ b/modules/base/conf.go @@ -45,14 +45,15 @@ type Oauther struct { } var ( - AppVer string - AppName string - AppLogo string - AppUrl string - IsProdMode bool - Domain string - SecretKey string - RunUser string + AppVer string + AppName string + AppLogo string + AppUrl string + OfflineMode bool + ProdMode bool + Domain string + SecretKey string + RunUser string RepoRootPath string ScriptType string @@ -325,6 +326,7 @@ func NewConfigContext() { AppLogo = Cfg.MustValue("", "APP_LOGO", "img/favicon.png") AppUrl = Cfg.MustValue("server", "ROOT_URL") Domain = Cfg.MustValue("server", "DOMAIN") + OfflineMode = Cfg.MustBool("server", "OFFLINE_MODE", 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 79aeeb9d77..dd98df75b1 100644 --- a/modules/base/template.go +++ b/modules/base/template.go @@ -56,8 +56,8 @@ var TemplateFuncs template.FuncMap = map[string]interface{}{ "AppDomain": func() string { return Domain }, - "IsProdMode": func() bool { - return IsProdMode + "CdnMode": func() bool { + return ProdMode && !OfflineMode }, "LoadTimes": func(startTime time.Time) string { return fmt.Sprint(time.Since(startTime).Nanoseconds()/1e6) + "ms" @@ -124,11 +124,11 @@ func ActionIcon(opType int) string { const ( TPL_CREATE_REPO = `<a href="/user/%s">%s</a> created repository <a href="/%s">%s</a>` TPL_COMMIT_REPO = `<a href="/user/%s">%s</a> pushed to <a href="/%s/src/%s">%s</a> at <a href="/%s">%s</a>%s` - TPL_COMMIT_REPO_LI = `<div><img src="%s?s=16" alt="user-avatar"/> <a href="/%s/commit/%s">%s</a> %s</div>` + TPL_COMMIT_REPO_LI = `<div><img src="%s?s=16" alt="user-avatar"/> <a href="/%s/commit/%s" rel="nofollow">%s</a> %s</div>` TPL_CREATE_ISSUE = `<a href="/user/%s">%s</a> opened issue <a href="/%s/issues/%s">%s#%s</a> <div><img src="%s?s=16" alt="user-avatar"/> %s</div>` TPL_TRANSFER_REPO = `<a href="/user/%s">%s</a> transfered repository <code>%s</code> to <a href="/%s">%s</a>` - TPL_PUSH_TAG = `<a href="/user/%s">%s</a> pushed tag <a href="/%s/src/%s">%s</a> at <a href="/%s">%s</a>` + TPL_PUSH_TAG = `<a href="/user/%s">%s</a> pushed tag <a href="/%s/src/%s" rel="nofollow">%s</a> at <a href="/%s">%s</a>` ) type PushCommit struct { @@ -165,7 +165,7 @@ func ActionDesc(act Actioner) string { buf.WriteString(fmt.Sprintf(TPL_COMMIT_REPO_LI, AvatarLink(commit.AuthorEmail), repoLink, commit.Sha1, commit.Sha1[:7], commit.Message) + "\n") } if push.Len > 3 { - buf.WriteString(fmt.Sprintf(`<div><a href="/%s/%s/commits/%s">%d other commits >></a></div>`, actUserName, repoName, branch, push.Len)) + buf.WriteString(fmt.Sprintf(`<div><a href="/%s/%s/commits/%s" rel="nofollow">%d other commits >></a></div>`, actUserName, repoName, branch, push.Len)) } return fmt.Sprintf(TPL_COMMIT_REPO, actUserName, actUserName, repoLink, branch, branch, repoLink, repoLink, buf.String()) diff --git a/routers/admin/admin.go b/routers/admin/admin.go index d0f737e645..fddd830185 100644 --- a/routers/admin/admin.go +++ b/routers/admin/admin.go @@ -139,9 +139,11 @@ func Config(ctx *middleware.Context) { ctx.Data["AppUrl"] = base.AppUrl ctx.Data["Domain"] = base.Domain + ctx.Data["OfflineMode"] = base.OfflineMode ctx.Data["RunUser"] = base.RunUser ctx.Data["RunMode"] = strings.Title(martini.Env) ctx.Data["RepoRootPath"] = base.RepoRootPath + ctx.Data["ScriptType"] = base.ScriptType ctx.Data["Service"] = base.Service diff --git a/routers/install.go b/routers/install.go index 8ffa9b5d1a..38bf896f4e 100644 --- a/routers/install.go +++ b/routers/install.go @@ -30,7 +30,7 @@ func checkRunMode() { switch base.Cfg.MustValue("", "RUN_MODE") { case "prod": martini.Env = martini.Prod - base.IsProdMode = true + base.ProdMode = true case "test": martini.Env = martini.Test } diff --git a/templates/admin/config.tmpl b/templates/admin/config.tmpl index d25d40275a..b2b25e90f6 100644 --- a/templates/admin/config.tmpl +++ b/templates/admin/config.tmpl @@ -18,6 +18,8 @@ <dd>{{.AppUrl}}</dd> <dt>Domain</dt> <dd>{{.Domain}}</dd> + <dt>Offline Mode</dt> + <dd><i class="fa fa{{if .OfflineMode}}-check{{end}}-square-o"></i></dd> <hr/> <dt>Run User</dt> <dd>{{.RunUser}}</dd> @@ -26,6 +28,8 @@ <hr/> <dt>Repository Root Path</dt> <dd>{{.RepoRootPath}}</dd> + <dt>Script Type</dt> + <dd>{{.ScriptType}}</dd> </dl> </div> </div> diff --git a/templates/base/head.tmpl b/templates/base/head.tmpl index 68231391c0..6794b0171e 100644 --- a/templates/base/head.tmpl +++ b/templates/base/head.tmpl @@ -12,7 +12,7 @@ {{if .Repository.IsGoget}}<meta name="go-import" content="{{.GoGetImport}} git {{.CloneLink.HTTPS}}">{{end}} <!-- Stylesheets --> - {{if IsProdMode}} + {{if CdnMode}} <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css"> <link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet"> diff --git a/templates/base/navbar.tmpl b/templates/base/navbar.tmpl index 932cae36d4..b8cba5faa6 100644 --- a/templates/base/navbar.tmpl +++ b/templates/base/navbar.tmpl @@ -3,7 +3,7 @@ <nav class="nav"> <a id="nav-logo" class="nav-item pull-left{{if .PageIsHome}} active{{end}}" href="/"><img src="/img/favicon.png" alt="Gogs Logo" id="logo"></a> <a class="nav-item pull-left{{if .PageIsUserDashboard}} active{{end}}" href="/">Dashboard</a> - <a class="nav-item pull-left{{if .PageIsHelp}} active{{end}}" href="https://github.com/gogits/gogs/wiki">Help</a>{{if .IsSigned}} + <a class="nav-item pull-left{{if .PageIsHelp}} active{{end}}" target="_blank" href="https://github.com/gogits/gogs/wiki">Help</a>{{if .IsSigned}} {{if .HasAccess}}<!-- <form class="nav-item pull-left{{if .PageIsNewRepo}} active{{end}}" id="nav-search-form"> <div class="input-group"> <div class="input-group-btn"> @@ -33,8 +33,8 @@ </ul> </div> </div> - {{else}}<a id="nav-signin" class="nav-item navbar-right navbar-btn btn btn-danger" href="/user/login/">Sign In</a> - <a id="nav-signup" class="nav-item navbar-right" href="/user/sign_up/">Sign Up</a>{{end}} + {{else}}<a id="nav-signin" class="nav-item navbar-right navbar-btn btn btn-danger" href="/user/login/" rel="nofollow">Sign In</a> + <a id="nav-signup" class="nav-item navbar-right" href="/user/sign_up/" rel="nofollow">Sign Up</a>{{end}} </nav> </div> </div> diff --git a/templates/release/list.tmpl b/templates/release/list.tmpl index dd37e9c1a2..11f96aa548 100644 --- a/templates/release/list.tmpl +++ b/templates/release/list.tmpl @@ -15,8 +15,8 @@ {{if .PublisherId}} <div class="col-md-2 text-right"> {{if .IsPrerelease}}<span class="btn btn-warning status pre-release">Pre-Release</span>{{else}}<span class="btn btn-success status stable">Stable</span>{{end}} - <a class="tag" href="{{$.RepoLink}}/src/{{.TagName}}"><i class="fa fa-tag"></i>{{.TagName}}</a> - <a class="commit" href="{{$.RepoLink}}/src/{{.SHA1}}"><i class="fa fa-code"></i>{{ShortSha .SHA1}}</a> + <a class="tag" href="{{$.RepoLink}}/src/{{.TagName}}" rel="nofollow"><i class="fa fa-tag"></i>{{.TagName}}</a> + <a class="commit" href="{{$.RepoLink}}/src/{{.SHA1}}" rel="nofollow"><i class="fa fa-code"></i>{{ShortSha .SHA1}}</a> </div> <div class="col-md-10"> <h4 class="title"><a href="{{$.RepoLink}}/src/{{.TagName}}">{{.Title}}</a></h4> @@ -30,19 +30,19 @@ {{str2html .Note}} </div> <p class="download"> - <a class="btn btn-default" href="{{$.RepoLink}}/archive/{{.TagName}}/{{$.Repository.Name}}.zip"><i class="fa fa-download"></i>Source Code (ZIP)</a> + <a class="btn btn-default" href="{{$.RepoLink}}/archive/{{.TagName}}/{{$.Repository.Name}}.zip" rel="nofollow"><i class="fa fa-download"></i>Source Code (ZIP)</a> <!-- <a class="btn btn-default" href="{release_download_link}"><i class="fa fa-download"></i>Source Code (TAR.GZ)</a> --> </p> <span class="dot"> </span> </div> {{else}} <div class="col-md-2 text-right"> - <a class="commit" href="{{$.RepoLink}}/src/{{.SHA1}}"><i class="fa fa-code"></i>{{ShortSha .SHA1}}</a> + <a class="commit" href="{{$.RepoLink}}/src/{{.SHA1}}" rel="nofollow"><i class="fa fa-code"></i>{{ShortSha .SHA1}}</a> </div> <div class="col-md-10"> - <h5 class="title"><a href="{{$.RepoLink}}/src/{{.TagName}}">{{.TagName}}</a><i class="fa fa-tag"></i></h5> + <h5 class="title"><a href="{{$.RepoLink}}/src/{{.TagName}}" rel="nofollow">{{.TagName}}</a><i class="fa fa-tag"></i></h5> <p class="download"> - <a class="download-link" href="{{$.RepoLink}}/archive/{{.TagName}}/{{$.Repository.Name}}.zip"><i class="fa fa-download"></i>zip</a> + <a class="download-link" href="{{$.RepoLink}}/archive/{{.TagName}}/{{$.Repository.Name}}.zip" rel="nofollow"><i class="fa fa-download"></i>zip</a> <!-- <a class="download-link" href="{release_download_link}"><i class="fa fa-download"></i>tar.gz</a> --> </p> <span class="dot"> </span> @@ -50,30 +50,6 @@ {{end}} </li> {{end}} - <!-- <li class="release-item clearfix" id="release-{release_id}"> - <div class="col-md-2 text-right"> - <span class="btn btn-warning status pre-release">Pre-Release</span> - <a class="tag" href="{commit_link}"><i class="fa fa-tag"></i>release tag</a> - <a class="commit" href="{commit_link}"><i class="fa fa-code"></i>commit-sha</a> - </div> - <div class="col-md-10"> - <h4 class="title"><a href="{release_single_link}">Release Title</a></h4> - <p class="info"> - <span class="author"><img class="avatar" src="http://1.gravatar.com/avatar/f72f7454ce9d710baa506394f68f4132" alt="" width="20"> - <a href="/user/fuxiaohei">fuxiaohei</a></span> - <span class="time">1 week ago</span> - <span class="ahead"><strong>0</strong> commits since this tag</span> - </p> - <div class="markdown desc"> - release descriptions, support markdown content - </div> - <p class="download"> - <a class="btn btn-default" href="{release_download_link}"><i class="fa fa-download"></i>Source Code (ZIP)</a> - <a class="btn btn-default" href="{release_download_link}"><i class="fa fa-download"></i>Source Code (TAR.GZ)</a> - </p> - <span class="dot"> </span> - </div> - </li> --> </ul> </div> </div> diff --git a/templates/repo/commits.tmpl b/templates/repo/commits.tmpl index b14c6bc8c6..bfc0bf21bf 100644 --- a/templates/repo/commits.tmpl +++ b/templates/repo/commits.tmpl @@ -41,8 +41,8 @@ </table> </div> {{if not .IsSearchPage}}<ul class="pagination" id="commits-pager"> - {{if .LastPageNum}}<li><a href="{{.RepoLink}}/commits/{{.BranchName}}?p={{.LastPageNum}}">« Newer</a></li>{{end}} - {{if .NextPageNum}}<li><a href="{{.RepoLink}}/commits/{{.BranchName}}?p={{.NextPageNum}}">» Older</a></li>{{end}} + {{if .LastPageNum}}<li><a href="{{.RepoLink}}/commits/{{.BranchName}}?p={{.LastPageNum}}" rel="nofollow">« Newer</a></li>{{end}} + {{if .NextPageNum}}<li><a href="{{.RepoLink}}/commits/{{.BranchName}}?p={{.NextPageNum}}" rel="nofollow">» Older</a></li>{{end}} </ul>{{end}} </div> </div> diff --git a/templates/repo/nav.tmpl b/templates/repo/nav.tmpl index ce9c112b8d..48fe31a619 100644 --- a/templates/repo/nav.tmpl +++ b/templates/repo/nav.tmpl @@ -23,10 +23,10 @@ <button class="btn btn-default" type="button" data-toggle="tooltip" title="copy to clipboard" data-placement="top" data-init="copy" data-copy-val="val" data-copy-from="#repo-clone-ipt"><i class="fa fa-copy"></i></button> </span> </div> - <p class="help-block text-center">Need help cloning? Visit <a href="#">Help</a>!</p> + <p class="help-block text-center">Need help cloning? Visit <a target="_blank" href="https://help.github.com/articles/fork-a-repo">Help</a>!</p> <hr/> <div class="clone-zip text-center"> - <a class="btn btn-success btn-lg" href="{{.RepoLink}}/archive/{{.BranchName}}/{{.Repository.Name}}.zip"><i class="fa fa-suitcase"></i>Download ZIP</a> + <a class="btn btn-success btn-lg" href="{{.RepoLink}}/archive/{{.BranchName}}/{{.Repository.Name}}.zip" rel="nofollow"><i class="fa fa-suitcase"></i>Download ZIP</a> </div> </div> </div> diff --git a/templates/repo/single_file.tmpl b/templates/repo/single_file.tmpl index b8205024c5..95c41b7017 100644 --- a/templates/repo/single_file.tmpl +++ b/templates/repo/single_file.tmpl @@ -14,7 +14,7 @@ {{if not .ReadmeInSingle}} <div class="btn-group pull-right"> <a class="btn btn-default hidden" href="#">Edit</a> - <a class="btn btn-default" href="{{.FileLink}}">Raw</a> + <a class="btn btn-default" href="{{.FileLink}}" rel="nofollow">Raw</a> <a class="btn btn-default hidden" href="#">Blame</a> <a class="btn btn-default hidden" href="#">History</a> <a class="btn btn-danger hidden" href="#">Delete</a> @@ -27,7 +27,7 @@ {{if .IsImageFile}} <img src="{{.FileLink}}"> {{else}} - <a href="{{.FileLink}}" class="btn btn-default">View Raw</a> + <a href="{{.FileLink}}" rel="nofollow" class="btn btn-default">View Raw</a> {{end}} </div> {{else}} diff --git a/templates/repo/single_list.tmpl b/templates/repo/single_list.tmpl index 7b6c6e5e9c..49a0ec5af4 100644 --- a/templates/repo/single_list.tmpl +++ b/templates/repo/single_list.tmpl @@ -1,6 +1,6 @@ <div class="panel panel-default info-box"> <div class="panel-heading info-head"> - <a href="/{{.Username}}/{{.Reponame}}/commit/{{.LastCommit.Id}}">{{.LastCommit.Message}}</a> + <a href="/{{.Username}}/{{.Reponame}}/commit/{{.LastCommit.Id}}" rel="nofollow">{{.LastCommit.Message}}</a> </div> <div class="panel-body info-content"> <a href="/user/{{.LastCommit.Author.Name}}">{{.LastCommit.Author.Name}}</a> <span class="text-muted">{{TimeSince .LastCommit.Author.When}}</span> diff --git a/templates/user/profile.tmpl b/templates/user/profile.tmpl index 0319f46c2e..15d2a0bd5a 100644 --- a/templates/user/profile.tmpl +++ b/templates/user/profile.tmpl @@ -11,13 +11,13 @@ <div class="profile-info"> <ul class="list-group"> {{if .Owner.Location}} - <li class="list-group-item"><i class="fa fa-thumb-tack"></i>{{.Owner.Location}}</li> + <li class="list-group-item"><i class="fa fa-thumb-tack"></i>{{.Owner.Location}}</li> {{end}} {{if .Owner.Email}} - <li class="list-group-item"><i class="fa fa-envelope"></i><a href="mailto:{{.Owner.Email}}">{{.Owner.Email}}</a></li> + <li class="list-group-item"><i class="fa fa-envelope"></i><a href="mailto:{{.Owner.Email}}" rel="nofollow">{{.Owner.Email}}</a></li> {{end}} {{if .Owner.Website}} - <li class="list-group-item"><i class="fa fa-link"></i><a target="_blank" href="{{.Owner.Website}}">{{.Owner.Website}}</a></li> + <li class="list-group-item"><i class="fa fa-link"></i><a target="_blank" href="{{.Owner.Website}}">{{.Owner.Website}}</a></li> {{end}} <li class="list-group-item"><i class="fa fa-clock-o"></i>Joined on {{DateFormat .Owner.Created "M d, Y"}}</li> <!-- <hr> --> From 62240b6bc12abfe257224bb554a75a5712803059 Mon Sep 17 00:00:00 2001 From: Unknown <joe2010xtmf@163.com> Date: Sun, 27 Apr 2014 01:54:08 -0600 Subject: [PATCH 09/13] Add login by email --- models/user.go | 18 ++++++++++++------ modules/auth/auth.go | 2 +- routers/user/user.go | 21 --------------------- templates/user/signin.tmpl | 2 +- 4 files changed, 14 insertions(+), 29 deletions(-) diff --git a/models/user.go b/models/user.go index df1eb985c2..661eff2fdd 100644 --- a/models/user.go +++ b/models/user.go @@ -410,21 +410,27 @@ func GetUserByEmail(email string) (*User, error) { } // LoginUserPlain validates user by raw user name and password. -func LoginUserPlain(name, passwd string) (*User, error) { - user := User{LowerName: strings.ToLower(name)} - has, err := orm.Get(&user) +func LoginUserPlain(uname, passwd string) (*User, error) { + var u *User + if strings.Contains(uname, "@") { + u = &User{Email: uname} + } else { + u = &User{LowerName: strings.ToLower(uname)} + } + + has, err := orm.Get(u) if err != nil { return nil, err } else if !has { return nil, ErrUserNotExist } - newUser := &User{Passwd: passwd, Salt: user.Salt} + newUser := &User{Passwd: passwd, Salt: u.Salt} newUser.EncodePasswd() - if user.Passwd != newUser.Passwd { + if u.Passwd != newUser.Passwd { return nil, ErrUserNotExist } - return &user, nil + return u, nil } // Follow is connection request for receiving user notifycation. diff --git a/modules/auth/auth.go b/modules/auth/auth.go index 350ef4fcbf..e493faefe7 100644 --- a/modules/auth/auth.go +++ b/modules/auth/auth.go @@ -57,7 +57,7 @@ func (f *RegisterForm) Validate(errors *base.BindingErrors, req *http.Request, c } type LogInForm struct { - UserName string `form:"username" binding:"Required;AlphaDash;MaxSize(30)"` + UserName string `form:"username" binding:"Required;MaxSize(35)"` Password string `form:"passwd" binding:"Required;MinSize(6);MaxSize(30)"` Remember string `form:"remember"` } diff --git a/routers/user/user.go b/routers/user/user.go index fe53896e41..9cce4e719d 100644 --- a/routers/user/user.go +++ b/routers/user/user.go @@ -144,27 +144,6 @@ func SignInPost(ctx *middleware.Context, form auth.LogInForm) { ctx.Redirect("/") } -func oauthSignInPost(ctx *middleware.Context, sid int64) { - ctx.Data["Title"] = "OAuth Sign Up" - ctx.Data["PageIsSignUp"] = true - - if _, err := models.GetOauth2ById(sid); err != nil { - if err == models.ErrOauth2RecordNotExist { - ctx.Handle(404, "user.oauthSignUp(GetOauth2ById)", err) - } else { - ctx.Handle(500, "user.oauthSignUp(GetOauth2ById)", err) - } - return - } - - ctx.Data["IsSocialLogin"] = true - ctx.Data["username"] = ctx.Session.Get("socialName") - ctx.Data["email"] = ctx.Session.Get("socialEmail") - log.Trace("user.oauthSignUp(social ID): %v", ctx.Session.Get("socialId")) - - ctx.HTML(200, "user/signup") -} - func SignOut(ctx *middleware.Context) { ctx.Session.Delete("userId") ctx.Session.Delete("userName") diff --git a/templates/user/signin.tmpl b/templates/user/signin.tmpl index 955c82f430..09ce249f7f 100644 --- a/templates/user/signin.tmpl +++ b/templates/user/signin.tmpl @@ -10,7 +10,7 @@ {{end}} {{template "base/alert" .}} <div class="form-group {{if .Err_UserName}}has-error has-feedback{{end}}"> - <label class="col-md-4 control-label">Username: </label> + <label class="col-md-4 control-label">Username or e-mail: </label> <div class="col-md-6"> <input name="username" class="form-control" placeholder="Type your username" value="{{.username}}" required="required"> </div> From 41b0a7b97c2cc1ffd8751fd12690642968961d0e Mon Sep 17 00:00:00 2001 From: Unknown <joe2010xtmf@163.com> Date: Sun, 27 Apr 2014 17:01:39 -0400 Subject: [PATCH 10/13] Mirror fix on public key --- models/publickey.go | 14 +++++++------- routers/user/setting.go | 3 ++- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/models/publickey.go b/models/publickey.go index ed47ff209d..b80412812b 100644 --- a/models/publickey.go +++ b/models/publickey.go @@ -77,12 +77,12 @@ func init() { // PublicKey represents a SSH key of user. type PublicKey struct { Id int64 - OwnerId int64 `xorm:"unique(s) index not null"` - Name string `xorm:"unique(s) not null"` + OwnerId int64 `xorm:"UNIQUE(s) INDEX NOT NULL"` + Name string `xorm:"UNIQUE(s) NOT NULL"` Fingerprint string - Content string `xorm:"TEXT not null"` - Created time.Time `xorm:"created"` - Updated time.Time `xorm:"updated"` + Content string `xorm:"TEXT NOT NULL"` + Created time.Time `xorm:"CREATED"` + Updated time.Time `xorm:"UPDATED"` } // GenAuthorizedKey returns formatted public key string. @@ -107,9 +107,9 @@ func AddPublicKey(key *PublicKey) (err error) { if err = ioutil.WriteFile(tmpPath, []byte(key.Content), os.ModePerm); err != nil { return err } - stdout, _, err := com.ExecCmd("ssh-keygen", "-l", "-f", tmpPath) + stdout, stderr, err := com.ExecCmd("ssh-keygen", "-l", "-f", tmpPath) if err != nil { - return err + return errors.New("ssh-keygen -l -f: " + stderr) } else if len(stdout) < 2 { return errors.New("Not enough output for calculating fingerprint") } diff --git a/routers/user/setting.go b/routers/user/setting.go index 019044c53d..a55e617f44 100644 --- a/routers/user/setting.go +++ b/routers/user/setting.go @@ -166,7 +166,8 @@ func SettingSSHKeys(ctx *middleware.Context, form auth.AddSSHKeyForm) { return } - k := &models.PublicKey{OwnerId: ctx.User.Id, + k := &models.PublicKey{ + OwnerId: ctx.User.Id, Name: form.KeyName, Content: form.KeyContent, } From 67002575589c1b77c86ecacd6edb5a05e81015cb Mon Sep 17 00:00:00 2001 From: Chris Lee <clee@mg8.org> Date: Sun, 27 Apr 2014 23:43:14 +0000 Subject: [PATCH 11/13] Show parents in commit diff page --- routers/repo/commit.go | 12 ++++++++++++ templates/repo/diff.tmpl | 9 ++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/routers/repo/commit.go b/routers/repo/commit.go index 9ecc697d27..d73669923b 100644 --- a/routers/repo/commit.go +++ b/routers/repo/commit.go @@ -91,10 +91,22 @@ func Diff(ctx *middleware.Context, params martini.Params) { return isImage } + parents := make([]string, commit.ParentCount()) + for i := 0; i < commit.ParentCount(); i++ { + sha, err := commit.ParentId(i) + parents[i] = sha.String() + if err != nil { + ctx.Handle(404, "repo.Diff", err) + } + } + + ctx.Data["Username"] = userName + ctx.Data["Reponame"] = repoName ctx.Data["IsImageFile"] = isImageFile ctx.Data["Title"] = commit.Summary() + " · " + base.ShortSha(commitId) ctx.Data["Commit"] = commit ctx.Data["Diff"] = diff + ctx.Data["Parents"] = parents ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0 ctx.Data["IsRepoToolbarCommits"] = true ctx.Data["SourcePath"] = "/" + path.Join(userName, repoName, "src", commitId) diff --git a/templates/repo/diff.tmpl b/templates/repo/diff.tmpl index 0dce405337..38fe3fee2c 100644 --- a/templates/repo/diff.tmpl +++ b/templates/repo/diff.tmpl @@ -8,9 +8,16 @@ <a class="pull-right btn btn-primary btn-sm" rel="nofollow" href="{{.SourcePath}}">Browse Source</a> <h4>{{.Commit.Message}}</h4> </div> + {{ $username := .Username }} + {{ $reponame := .Reponame }} <div class="panel-body"> <span class="pull-right"> - commit <span class="label label-default sha">{{ShortSha .CommitId}}</span> + <ul class="list-unstyled"> + {{range .Parents}} + <li>parent <a href="/{{$username}}/{{$reponame}}/commit/{{.}}"><span class="label label-default sha">{{ShortSha .}}</span></a></li> + {{end}} + <li>commit <span class="label label-default sha">{{ShortSha .CommitId}}</span></li> + </ul> </span> <p class="author"> <img class="avatar" src="{{AvatarLink .Commit.Author.Email}}" alt=""/> From 2401e68d7ed7d53425293ad32d231542d03bbef3 Mon Sep 17 00:00:00 2001 From: Unknown <joe2010xtmf@163.com> Date: Mon, 28 Apr 2014 21:53:40 -0400 Subject: [PATCH 12/13] Prepare for v0.3.1 hotfix --- README.md | 2 +- README_ZH.md | 2 +- gogs.go | 2 +- public/img/favicon.bak.png | Bin 0 -> 15949 bytes public/img/favicon.png | Bin 15949 -> 10889 bytes routers/repo/commit.go | 1 + templates/repo/diff.tmpl | 4 +--- 7 files changed, 5 insertions(+), 6 deletions(-) create mode 100644 public/img/favicon.bak.png diff --git a/README.md b/README.md index d188508ec6..c16f721aa6 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Gogs(Go Git Service) is a Self Hosted Git Service in the Go Programming Language  -##### Current version: 0.3.0 Alpha +##### Current version: 0.3.1 Alpha ### NOTICES diff --git a/README_ZH.md b/README_ZH.md index bbf461ddf6..b827822357 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -5,7 +5,7 @@ Gogs(Go Git Service) 是一个由 Go 语言编写的自助 Git 托管服务。  -##### 当前版本:0.3.0 Alpha +##### 当前版本:0.3.1 Alpha ## 开发目的 diff --git a/gogs.go b/gogs.go index 1a8b4d1312..d723aa33a0 100644 --- a/gogs.go +++ b/gogs.go @@ -19,7 +19,7 @@ import ( // Test that go1.2 tag above is included in builds. main.go refers to this definition. const go12tag = true -const APP_VER = "0.3.0.0427 Alpha" +const APP_VER = "0.3.1.0427 Alpha" func init() { base.AppVer = APP_VER diff --git a/public/img/favicon.bak.png b/public/img/favicon.bak.png new file mode 100644 index 0000000000000000000000000000000000000000..ba9bd037561dc68c9678516ca2c9b39ecb80a723 GIT binary patch literal 15949 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 literal 0 HcmV?d00001 diff --git a/public/img/favicon.png b/public/img/favicon.png index ba9bd037561dc68c9678516ca2c9b39ecb80a723..87282f9a781647294f5376619eecb0bfd2b22ce2 100644 GIT binary patch literal 10889 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 literal 15949 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 diff --git a/routers/repo/commit.go b/routers/repo/commit.go index d73669923b..bc33fe4473 100644 --- a/routers/repo/commit.go +++ b/routers/repo/commit.go @@ -97,6 +97,7 @@ func Diff(ctx *middleware.Context, params martini.Params) { parents[i] = sha.String() if err != nil { ctx.Handle(404, "repo.Diff", err) + return } } diff --git a/templates/repo/diff.tmpl b/templates/repo/diff.tmpl index 38fe3fee2c..0b6d4f722e 100644 --- a/templates/repo/diff.tmpl +++ b/templates/repo/diff.tmpl @@ -8,13 +8,11 @@ <a class="pull-right btn btn-primary btn-sm" rel="nofollow" href="{{.SourcePath}}">Browse Source</a> <h4>{{.Commit.Message}}</h4> </div> - {{ $username := .Username }} - {{ $reponame := .Reponame }} <div class="panel-body"> <span class="pull-right"> <ul class="list-unstyled"> {{range .Parents}} - <li>parent <a href="/{{$username}}/{{$reponame}}/commit/{{.}}"><span class="label label-default sha">{{ShortSha .}}</span></a></li> + <li>parent <a href="{{$.RepoLink}}/commit/{{.}}"><span class="label label-default sha">{{ShortSha .}}</span></a></li> {{end}} <li>commit <span class="label label-default sha">{{ShortSha .CommitId}}</span></li> </ul> From 494e5fd40c6c6f035c9d7a7e2737259afcb8424c Mon Sep 17 00:00:00 2001 From: Robert Speicher <rspeicher@gmail.com> Date: Tue, 29 Apr 2014 16:35:25 -0400 Subject: [PATCH 13/13] Install: Set the default host string based on database type --- public/js/app.js | 15 +++++++++++++++ templates/install.tmpl | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/public/js/app.js b/public/js/app.js index b7b5deb83b..30e9d5d0bb 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -468,6 +468,9 @@ function initRepository() { function initInstall() { // database type change (function () { + var mysql_default = '127.0.0.1:3306' + var postgres_default = '127.0.0.1:5432' + $('#install-database').on("change", function () { var val = $(this).val(); if (val != "SQLite3") { @@ -475,6 +478,18 @@ function initInstall() { $('.sqlite-setting').addClass("hide"); if (val == "PostgreSQL") { $('.pgsql-setting').removeClass("hide"); + + // Change the host value to the Postgres default, but only + // if the user hasn't already changed it from the MySQL + // default. + if ($('#database-host').val() == mysql_default) { + $('#database-host').val(postgres_default); + } + } else if (val == 'MySQL') { + $('.pgsql-setting').addClass("hide"); + if ($('#database-host').val() == postgres_default) { + $('#database-host').val(mysql_default); + } } else { $('.pgsql-setting').addClass("hide"); } diff --git a/templates/install.tmpl b/templates/install.tmpl index 8fe678e509..eb6327d205 100644 --- a/templates/install.tmpl +++ b/templates/install.tmpl @@ -21,7 +21,7 @@ <div class="form-group"> <label class="col-md-3 control-label">Host: </label> <div class="col-md-8"> - <input name="host" class="form-control" placeholder="Type database server host" value="{{.host}}"> + <input name="host" id="database-host" class="form-control" placeholder="Type database server host" value="{{.host}}"> </div> </div>