From f0d5c3992b03f4d6a82b272ac513d2989ffb8d81 Mon Sep 17 00:00:00 2001 From: FuXiaoHei <fuxiaohei@hexiaz.com> Date: Sat, 29 Mar 2014 20:46:36 +0800 Subject: [PATCH 01/14] issue ajax edit --- public/js/app.js | 55 ++++++++++++++++++++++++++++++++++++--- templates/issue/view.tmpl | 9 ++++--- 2 files changed, 56 insertions(+), 8 deletions(-) diff --git a/public/js/app.js b/public/js/app.js index 9299a6b7aa..b03d9070a7 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -56,6 +56,43 @@ var Gogits = { }, toggleShow: function () { $(this).removeClass("hidden"); + }, + toggleAjax: function (successCallback) { + var url = $(this).data("ajax"); + var method = $(this).data('ajax-method') || 'get'; + var ajaxName = $(this).data('ajax-name'); + var data = {}; + $('[data-ajax-rel=' + ajaxName + ']').each(function () { + var field = $(this).data("ajax-field"); + var t = $(this).data("ajax-val"); + if (t == "val") { + data[field] = $(this).val(); + return true; + } + if (t == "txt") { + data[field] = $(this).text(); + return true; + } + if (t == "html") { + data[field] = $(this).html(); + return true; + } + if (t == "data") { + data[field] = $(this).data("ajax-data"); + return true; + } + return true; + }); + $.ajax({ + url: url, + method: method.toUpperCase(), + data: data, + success: function (d) { + if (successCallback) { + successCallback(d); + } + } + }) } }) }(jQuery)); @@ -386,11 +423,11 @@ function initIssue() { var $openBtn = $('#issue-open-btn'); $('#issue-reply-content').on("keyup", function () { if ($(this).val().length) { - $closeBtn.text($closeBtn.data("text")); - $openBtn.text($openBtn.data("text")); + $closeBtn.val($closeBtn.data("text")); + $openBtn.val($openBtn.data("text")); } else { - $closeBtn.text($closeBtn.data("origin")); - $openBtn.text($openBtn.data("origin")); + $closeBtn.val($closeBtn.data("origin")); + $openBtn.val($openBtn.data("origin")); } }); }()); @@ -406,6 +443,16 @@ function initIssue() { $('#issue-edit-title,#issue-edit-content,.issue-edit-cancel,.issue-edit-save').toggleHide(); }) }()); + + // issue ajax update + $('.issue-edit-save').on("click", function () { + $(this).toggleAjax(function(json){ + if(json.ok){ + $('.issue-head h1.title').text(json.title); + $('.issue-main > .issue-content .content').html(json.content); + } + }); + }); } (function ($) { diff --git a/templates/issue/view.tmpl b/templates/issue/view.tmpl index 516206da96..4266bcbf44 100644 --- a/templates/issue/view.tmpl +++ b/templates/issue/view.tmpl @@ -9,11 +9,12 @@ <div class="number pull-right">#{{.Issue.Index}}</div> <a class="author pull-left" href="/user/{{.Issue.Poster.Name}}"><img class="avatar" src="{{.Issue.Poster.AvatarLink}}" alt="" width="30"/></a> <h1 class="title pull-left">{{.Issue.Name}}</h1> - <input id="issue-edit-title" class="form-control input-lg pull-left hidden" type="text" value="{issue.title}" data-ajax-rel="issue-save"/> + <input id="issue-edit-title" class="form-control input-lg pull-left hidden" type="text" value="{issue.title}" data-ajax-rel="issue-edit-save" data-ajax-val="val" data-ajax-field="title"/> + <input type="hidden" value="{issue.id}" data-ajax-rel="issue-edit-save" data-ajax-val="val" data-ajax-field="issue_id"/> <p class="info pull-left"> - <!-- <a class="btn btn-default pull-right issue-edit" href="#" id="issue-edit-btn">Edit</a> --> + <a class="btn btn-default pull-right issue-edit" href="#" id="issue-edit-btn">Edit</a> <a class="btn btn-danger pull-right issue-edit-cancel hidden" href="#">Cancel</a> - <a class="btn btn-primary pull-right issue-edit-save hidden" href="#" data-ajax="{issue.save.link}" data-ajax-name="issue-save">Save</a> + <a class="btn btn-primary pull-right issue-edit-save hidden" href="#" data-ajax="{issue.edit.save.link}" data-ajax-name="issue-edit-save" data-ajax-method="post">Save</a> <span class="status label label-{{if .Issue.IsClosed}}danger{{else}}success{{end}}">{{if .Issue.IsClosed}}Closed{{else}}Open{{end}}</span> <a href="/user/{{.Issue.Poster.Name}}" class="author"><strong>{{.Issue.Poster.Name}}</strong></a> opened this issue <span class="time">{{TimeSince .Issue.Created}}</span> · {{.Issue.NumComments}} comments @@ -25,7 +26,7 @@ <div class="content"> {{str2html .Issue.Content}} </div> - <textarea class="form-control hidden" name="content" id="issue-edit-content" rows="10" data-ajax-rel="issue-save">content</textarea> + <textarea class="form-control hidden" name="content" id="issue-edit-content" rows="10" data-ajax-rel="issue-edit-save" data-ajax-val="val" data-ajax-field="content">{issue.content}</textarea> </div> </div> {{range .Comments}} From ecce694d77756264864b03e6b06077592ed1676a Mon Sep 17 00:00:00 2001 From: FuXiaoHei <fuxiaohei@hexiaz.com> Date: Sat, 29 Mar 2014 21:16:06 +0800 Subject: [PATCH 02/14] issue content ajax preview --- public/js/app.js | 61 +++++++++++++++++++++++++------------ routers/preview.go | 17 +++++++++++ templates/issue/create.tmpl | 8 ++--- templates/issue/view.tmpl | 8 ++--- web.go | 1 + 5 files changed, 67 insertions(+), 28 deletions(-) create mode 100644 routers/preview.go diff --git a/public/js/app.js b/public/js/app.js index b03d9070a7..58bda9895e 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -399,21 +399,24 @@ function initRepository() { function initInstall() { // database type change - $('#install-database').on("change", function () { - var val = $(this).val(); - if (val != "sqlite") { - $('.server-sql').show(); - $('.sqlite-setting').addClass("hide"); - if (val == "pgsql") { - $('.pgsql-setting').removeClass("hide"); + (function () { + $('#install-database').on("change", function () { + var val = $(this).val(); + if (val != "sqlite") { + $('.server-sql').show(); + $('.sqlite-setting').addClass("hide"); + if (val == "pgsql") { + $('.pgsql-setting').removeClass("hide"); + } else { + $('.pgsql-setting').addClass("hide"); + } } else { - $('.pgsql-setting').addClass("hide"); + $('.server-sql').hide(); + $('.sqlite-setting').removeClass("hide"); } - } else { - $('.server-sql').hide(); - $('.sqlite-setting').removeClass("hide"); - } - }); + }); + }()); + } function initIssue() { @@ -445,14 +448,32 @@ function initIssue() { }()); // issue ajax update - $('.issue-edit-save').on("click", function () { - $(this).toggleAjax(function(json){ - if(json.ok){ - $('.issue-head h1.title').text(json.title); - $('.issue-main > .issue-content .content').html(json.content); - } + (function () { + $('.issue-edit-save').on("click", function () { + $(this).toggleAjax(function (json) { + if (json.ok) { + $('.issue-head h1.title').text(json.title); + $('.issue-main > .issue-content .content').html(json.content); + } + }); }); - }); + }()); + + // issue ajax preview + (function () { + $('[data-ajax-name=issue-preview]').on("click", function () { + var $this = $(this); + $this.toggleAjax(function (json) { + if (json.ok) { + $($this.data("preview")).html(json.content); + } + }) + }); + $('.issue-write a[data-toggle]').on("click", function () { + $('.issue-preview-content').html("loading..."); + }); + }()) + } (function ($) { diff --git a/routers/preview.go b/routers/preview.go new file mode 100644 index 0000000000..cc34c8fa02 --- /dev/null +++ b/routers/preview.go @@ -0,0 +1,17 @@ +// 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 routers + +import "github.com/gogits/gogs/modules/middleware" + +func Preview(ctx *middleware.Context) { + content := ctx.Query("content") + // todo : gfm render content + // content = Markdown(content) + ctx.Render.JSON(200, map[string]interface{}{ + "ok": true, + "content": "preview : " + content, + }) +} diff --git a/templates/issue/create.tmpl b/templates/issue/create.tmpl index cbc21f6ce0..b8a533a198 100644 --- a/templates/issue/create.tmpl +++ b/templates/issue/create.tmpl @@ -18,16 +18,16 @@ Content with <a href="#">Markdown</a> </div> <ul class="nav nav-tabs" data-init="tabs"> - <li class="active"><a href="#issue-textarea" data-toggle="tab">Write</a></li> - <li><a href="#issue-preview" data-toggle="tab">Preview</a></li> + <li class="active issue-write"><a href="#issue-textarea" data-toggle="tab">Write</a></li> + <li class="issue-preview"><a href="#issue-preview" data-toggle="tab" data-ajax="/preview?repo=repo_id&issue=new" data-ajax-name="issue-preview" data-ajax-method="post" data-preview="#issue-preview">Preview</a></li> </ul> <div class="tab-content"> <div class="tab-pane" id="issue-textarea"> <div class="form-group"> - <textarea class="form-control" name="content" id="issue-content" rows="10" placeholder="Write some content">{{.content}}</textarea> + <textarea class="form-control" name="content" id="issue-content" rows="10" placeholder="Write some content" data-ajax-rel="issue-preview" data-ajax-val="val" data-ajax-field="content">{{.content}}</textarea> </div> </div> - <div class="tab-pane" id="issue-preview">preview</div> + <div class="tab-pane issue-preview-content" id="issue-preview">loading...</div> </div> </div> <div class="text-right panel-body"> diff --git a/templates/issue/view.tmpl b/templates/issue/view.tmpl index 4266bcbf44..431b1d1042 100644 --- a/templates/issue/view.tmpl +++ b/templates/issue/view.tmpl @@ -72,17 +72,17 @@ Content with <a href="#">Markdown</a> </div> <ul class="nav nav-tabs" data-init="tabs"> - <li class="active"><a href="#issue-textarea" data-toggle="tab">Write</a></li> - <li><a href="#issue-preview" data-toggle="tab">Preview</a></li> + <li class="active issue-write"><a href="#issue-textarea" data-toggle="tab">Write</a></li> + <li class="issue-preview"><a href="#issue-preview" data-toggle="tab" data-ajax="/preview?repo=repo_id&issue=issue_id&comment=new" data-ajax-name="issue-preview" data-ajax-method="post" data-preview="#issue-preview">Preview</a></li> </ul> <div class="tab-content"> <div class="tab-pane" id="issue-textarea"> <div class="form-group"> <input type="hidden" value="{{.Issue.Index}}" name="issueIndex"/> - <textarea class="form-control" name="content" id="issue-reply-content" rows="10" placeholder="Write some content">{{.content}}</textarea> + <textarea class="form-control" name="content" id="issue-content" rows="10" placeholder="Write some content" data-ajax-rel="issue-preview" data-ajax-val="val" data-ajax-field="content">{{.content}}</textarea> </div> </div> - <div class="tab-pane" id="issue-preview">preview</div> + <div class="tab-pane issue-preview-content" id="issue-preview">loading...</div> </div> </div> <div class="text-right"> diff --git a/web.go b/web.go index 35695f0bfb..451e52ff8c 100644 --- a/web.go +++ b/web.go @@ -95,6 +95,7 @@ func runWeb(*cli.Context) { m.Get("/pulls", reqSignIn, user.Pulls) m.Get("/stars", reqSignIn, user.Stars) m.Get("/help", routers.Help) + m.Post("/preview", routers.Preview) avt := avatar.CacheServer("public/img/avatar/", "public/img/avatar_default.jpg") m.Get("/avatar/:hash", avt.ServeHTTP) From 2c073afbec4b9845e8ddd10a4d3f469874fdcd37 Mon Sep 17 00:00:00 2001 From: Unknown <joe2010xtmf@163.com> Date: Sat, 29 Mar 2014 10:01:52 -0400 Subject: [PATCH 03/14] Mirror fix and update --- README.md | 2 ++ models/repo.go | 13 ++++++++++--- routers/{preview.go => api/v1/miscellaneous.go} | 13 +++++++------ templates/issue/create.tmpl | 4 ++-- templates/issue/view.tmpl | 4 ++-- templates/user/signin.tmpl | 2 +- web.go | 7 ++++++- 7 files changed, 30 insertions(+), 15 deletions(-) rename routers/{preview.go => api/v1/miscellaneous.go} (56%) diff --git a/README.md b/README.md index 7d688506d6..e88a247705 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ Gogs(Go Git Service) is a Self Hosted Git Service in the Go Programming Language ##### Current version: 0.1.9 Alpha +#### Due to testing purpose, data of [try.gogits.org](http://try.gogits.org) has been reset in March 29, 2014 and will reset multiple times after. Please do NOT put your important data on the site. + #### Other language version - [简体中文](README_ZH.md) diff --git a/models/repo.go b/models/repo.go index 4be655d287..a848694da6 100644 --- a/models/repo.go +++ b/models/repo.go @@ -198,12 +198,19 @@ func CreateRepository(user *User, repoName, desc, repoLang, license string, priv c := exec.Command("git", "update-server-info") c.Dir = repoPath - err = c.Run() - if err != nil { + if err = c.Run(); err != nil { log.Error("repo.CreateRepository(exec update-server-info): %v", err) } - return repo, NewRepoAction(user, repo) + if err = NewRepoAction(user, repo); err != nil { + log.Error("repo.CreateRepository(NewRepoAction): %v", err) + } + + if err = WatchRepo(user.Id, repo.Id, true); err != nil { + log.Error("repo.CreateRepository(WatchRepo): %v", err) + } + + return repo, nil } // extractGitBareZip extracts git-bare.zip to repository path. diff --git a/routers/preview.go b/routers/api/v1/miscellaneous.go similarity index 56% rename from routers/preview.go rename to routers/api/v1/miscellaneous.go index cc34c8fa02..0ff1eb04a0 100644 --- a/routers/preview.go +++ b/routers/api/v1/miscellaneous.go @@ -2,16 +2,17 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package routers +package v1 -import "github.com/gogits/gogs/modules/middleware" +import ( + "github.com/gogits/gogs/modules/base" + "github.com/gogits/gogs/modules/middleware" +) -func Preview(ctx *middleware.Context) { +func Markdown(ctx *middleware.Context) { content := ctx.Query("content") - // todo : gfm render content - // content = Markdown(content) ctx.Render.JSON(200, map[string]interface{}{ "ok": true, - "content": "preview : " + content, + "content": string(base.RenderMarkdown([]byte(content), "")), }) } diff --git a/templates/issue/create.tmpl b/templates/issue/create.tmpl index b8a533a198..f5cec0c05a 100644 --- a/templates/issue/create.tmpl +++ b/templates/issue/create.tmpl @@ -15,11 +15,11 @@ </div> <div class="form-group panel-body"> <div class="md-help pull-right"><!-- todo help link --> - Content with <a href="#">Markdown</a> + Content with <a href="https://help.github.com/articles/markdown-basics">Markdown</a> </div> <ul class="nav nav-tabs" data-init="tabs"> <li class="active issue-write"><a href="#issue-textarea" data-toggle="tab">Write</a></li> - <li class="issue-preview"><a href="#issue-preview" data-toggle="tab" data-ajax="/preview?repo=repo_id&issue=new" data-ajax-name="issue-preview" data-ajax-method="post" data-preview="#issue-preview">Preview</a></li> + <li class="issue-preview"><a href="#issue-preview" data-toggle="tab" data-ajax="/api/v1/markdown?repo=repo_id&issue=new" data-ajax-name="issue-preview" data-ajax-method="post" data-preview="#issue-preview">Preview</a></li> </ul> <div class="tab-content"> <div class="tab-pane" id="issue-textarea"> diff --git a/templates/issue/view.tmpl b/templates/issue/view.tmpl index 431b1d1042..c357f5354c 100644 --- a/templates/issue/view.tmpl +++ b/templates/issue/view.tmpl @@ -69,11 +69,11 @@ <div class="panel-body"> <div class="form-group"> <div class="md-help pull-right"><!-- todo help link --> - Content with <a href="#">Markdown</a> + Content with <a href="https://help.github.com/articles/markdown-basics">Markdown</a> </div> <ul class="nav nav-tabs" data-init="tabs"> <li class="active issue-write"><a href="#issue-textarea" data-toggle="tab">Write</a></li> - <li class="issue-preview"><a href="#issue-preview" data-toggle="tab" data-ajax="/preview?repo=repo_id&issue=issue_id&comment=new" data-ajax-name="issue-preview" data-ajax-method="post" data-preview="#issue-preview">Preview</a></li> + <li class="issue-preview"><a href="#issue-preview" data-toggle="tab" data-ajax="/api/v1/markdown?repo=repo_id&issue=issue_id&comment=new" data-ajax-name="issue-preview" data-ajax-method="post" data-preview="#issue-preview">Preview</a></li> </ul> <div class="tab-content"> <div class="tab-pane" id="issue-textarea"> diff --git a/templates/user/signin.tmpl b/templates/user/signin.tmpl index 49a2262633..b6c39af1b8 100644 --- a/templates/user/signin.tmpl +++ b/templates/user/signin.tmpl @@ -44,7 +44,7 @@ </div> <div class="form-group text-center" id="social-login"> - <a class="btn btn-danger btn-lg">Register new account</a> + <a class="btn btn-danger btn-lg" href="/user/sign_up">Register new account</a> </div> </form> </div> diff --git a/web.go b/web.go index 451e52ff8c..7725791e84 100644 --- a/web.go +++ b/web.go @@ -24,6 +24,7 @@ import ( "github.com/gogits/gogs/modules/middleware" "github.com/gogits/gogs/routers" "github.com/gogits/gogs/routers/admin" + "github.com/gogits/gogs/routers/api/v1" "github.com/gogits/gogs/routers/dev" "github.com/gogits/gogs/routers/repo" "github.com/gogits/gogs/routers/user" @@ -72,6 +73,7 @@ func newMartini() *martini.ClassicMartini { } func runWeb(*cli.Context) { + fmt.Println("Server is running...") globalInit() base.NewServices() checkRunMode() @@ -95,7 +97,10 @@ func runWeb(*cli.Context) { m.Get("/pulls", reqSignIn, user.Pulls) m.Get("/stars", reqSignIn, user.Stars) m.Get("/help", routers.Help) - m.Post("/preview", routers.Preview) + + m.Group("/api/v1", func(r martini.Router) { + r.Post("/markdown", v1.Markdown) + }) avt := avatar.CacheServer("public/img/avatar/", "public/img/avatar_default.jpg") m.Get("/avatar/:hash", avt.ServeHTTP) From ffa59739b609ce00ce21344531f27d4003dfc688 Mon Sep 17 00:00:00 2001 From: Unknown <joe2010xtmf@163.com> Date: Sat, 29 Mar 2014 10:24:42 -0400 Subject: [PATCH 04/14] Add edit issue --- models/issue.go | 35 ++++++++++++++++++----------------- routers/repo/issue.go | 10 +++++++--- templates/issue/view.tmpl | 14 +++++++------- 3 files changed, 32 insertions(+), 27 deletions(-) diff --git a/models/issue.go b/models/issue.go index 39558ae225..9fd1b905a5 100644 --- a/models/issue.go +++ b/models/issue.go @@ -18,23 +18,24 @@ var ( // Issue represents an issue or pull request of repository. type Issue struct { - Id int64 - Index int64 // Index in one repository. - Name string - RepoId int64 `xorm:"index"` - Repo *Repository `xorm:"-"` - PosterId int64 - Poster *User `xorm:"-"` - MilestoneId int64 - AssigneeId int64 - IsPull bool // Indicates whether is a pull request or not. - IsClosed bool - Labels string `xorm:"TEXT"` - Mentions string `xorm:"TEXT"` - Content string `xorm:"TEXT"` - NumComments int - Created time.Time `xorm:"created"` - Updated time.Time `xorm:"updated"` + Id int64 + Index int64 // Index in one repository. + Name string + RepoId int64 `xorm:"index"` + Repo *Repository `xorm:"-"` + PosterId int64 + Poster *User `xorm:"-"` + MilestoneId int64 + AssigneeId int64 + IsPull bool // Indicates whether is a pull request or not. + IsClosed bool + Labels string `xorm:"TEXT"` + Mentions string `xorm:"TEXT"` + Content string `xorm:"TEXT"` + RenderedContent string `xorm:"-"` + NumComments int + Created time.Time `xorm:"created"` + Updated time.Time `xorm:"updated"` } // CreateIssue creates new issue for repository. diff --git a/routers/repo/issue.go b/routers/repo/issue.go index c89c8b5685..b38967f717 100644 --- a/routers/repo/issue.go +++ b/routers/repo/issue.go @@ -152,7 +152,7 @@ func ViewIssue(ctx *middleware.Context, params martini.Params) { return } issue.Poster = u - issue.Content = string(base.RenderMarkdown([]byte(issue.Content), "")) + issue.RenderedContent = string(base.RenderMarkdown([]byte(issue.Content), "")) // Get comments. comments, err := models.GetIssueComments(issue.Id) @@ -216,8 +216,12 @@ func UpdateIssue(ctx *middleware.Context, params martini.Params, form auth.Creat return } - ctx.Data["Title"] = issue.Name - ctx.Data["Issue"] = issue + ctx.JSON(200, map[string]interface{}{ + "ok": true, + "title": issue.Name, + "content": string(base.RenderMarkdown([]byte(issue.Content), "")), + "raw_content": issue.Content, + }) } func Comment(ctx *middleware.Context, params martini.Params) { diff --git a/templates/issue/view.tmpl b/templates/issue/view.tmpl index c357f5354c..c6f1444e46 100644 --- a/templates/issue/view.tmpl +++ b/templates/issue/view.tmpl @@ -4,17 +4,17 @@ {{template "repo/toolbar" .}} <div id="body" class="container"> <div id="issue"> - <div id="issue-{issue.id}" class="issue-whole issue-is-opening"> + <div id="issue-{{.Issue.Id}}" class="issue-whole issue-is-opening"> <div class="issue-head clearfix"> <div class="number pull-right">#{{.Issue.Index}}</div> <a class="author pull-left" href="/user/{{.Issue.Poster.Name}}"><img class="avatar" src="{{.Issue.Poster.AvatarLink}}" alt="" width="30"/></a> <h1 class="title pull-left">{{.Issue.Name}}</h1> - <input id="issue-edit-title" class="form-control input-lg pull-left hidden" type="text" value="{issue.title}" data-ajax-rel="issue-edit-save" data-ajax-val="val" data-ajax-field="title"/> - <input type="hidden" value="{issue.id}" data-ajax-rel="issue-edit-save" data-ajax-val="val" data-ajax-field="issue_id"/> + <input id="issue-edit-title" class="form-control input-lg pull-left hidden" type="text" value="{{.Issue.Name}}" data-ajax-rel="issue-edit-save" data-ajax-val="val" data-ajax-field="title"/> + <input type="hidden" value="{{.Issue.Id}}" data-ajax-rel="issue-edit-save" data-ajax-val="val" data-ajax-field="issue_id"/> <p class="info pull-left"> <a class="btn btn-default pull-right issue-edit" href="#" id="issue-edit-btn">Edit</a> <a class="btn btn-danger pull-right issue-edit-cancel hidden" href="#">Cancel</a> - <a class="btn btn-primary pull-right issue-edit-save hidden" href="#" data-ajax="{issue.edit.save.link}" data-ajax-name="issue-edit-save" data-ajax-method="post">Save</a> + <a class="btn btn-primary pull-right issue-edit-save hidden" href="#" data-ajax="/{{.RepositoryLink}}/issues/{{.Issue.Index}}" data-ajax-name="issue-edit-save" data-ajax-method="post">Save</a> <span class="status label label-{{if .Issue.IsClosed}}danger{{else}}success{{end}}">{{if .Issue.IsClosed}}Closed{{else}}Open{{end}}</span> <a href="/user/{{.Issue.Poster.Name}}" class="author"><strong>{{.Issue.Poster.Name}}</strong></a> opened this issue <span class="time">{{TimeSince .Issue.Created}}</span> · {{.Issue.NumComments}} comments @@ -24,13 +24,13 @@ <div class="panel panel-default issue-content"> <div class="panel-body markdown"> <div class="content"> - {{str2html .Issue.Content}} + {{str2html .Issue.RenderedContent}} </div> - <textarea class="form-control hidden" name="content" id="issue-edit-content" rows="10" data-ajax-rel="issue-edit-save" data-ajax-val="val" data-ajax-field="content">{issue.content}</textarea> + <textarea class="form-control hidden" name="content" id="issue-edit-content" rows="10" data-ajax-rel="issue-edit-save" data-ajax-val="val" data-ajax-field="content">{{.Issue.Content}}</textarea> </div> </div> {{range .Comments}} - <div class="issue-child" id="issue-comment-{issue.comment.id}"> + <div class="issue-child" id="issue-comment-{{.Id}}"> <a class="user pull-left" href="/user/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt=""/></a> <div class="issue-content panel panel-default"> <div class="panel-heading"> From be45057c3aef74c4b8bdc28ebd84c7297d1a7b62 Mon Sep 17 00:00:00 2001 From: FuXiaoHei <fuxiaohei@hexiaz.com> Date: Sat, 29 Mar 2014 23:03:01 +0800 Subject: [PATCH 05/14] fix issue ajax update --- public/js/app.js | 1 + 1 file changed, 1 insertion(+) diff --git a/public/js/app.js b/public/js/app.js index 58bda9895e..5181933d24 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -454,6 +454,7 @@ function initIssue() { if (json.ok) { $('.issue-head h1.title').text(json.title); $('.issue-main > .issue-content .content').html(json.content); + $('.issue-edit-cancel').trigger("click"); } }); }); From 5ab3962b125a6759501507e3202515f807ea95ee Mon Sep 17 00:00:00 2001 From: FuXiaoHei <fuxiaohei@hexiaz.com> Date: Sat, 29 Mar 2014 23:54:33 +0800 Subject: [PATCH 06/14] fix issue button text change --- templates/issue/view.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/issue/view.tmpl b/templates/issue/view.tmpl index c6f1444e46..042cbdaf45 100644 --- a/templates/issue/view.tmpl +++ b/templates/issue/view.tmpl @@ -79,7 +79,7 @@ <div class="tab-pane" id="issue-textarea"> <div class="form-group"> <input type="hidden" value="{{.Issue.Index}}" name="issueIndex"/> - <textarea class="form-control" name="content" id="issue-content" rows="10" placeholder="Write some content" data-ajax-rel="issue-preview" data-ajax-val="val" data-ajax-field="content">{{.content}}</textarea> + <textarea class="form-control" name="content" id="issue-reply-content" rows="10" placeholder="Write some content" data-ajax-rel="issue-preview" data-ajax-val="val" data-ajax-field="content">{{.content}}</textarea> </div> </div> <div class="tab-pane issue-preview-content" id="issue-preview">loading...</div> From cad2ced3945401243d7b644cb613432e1712ab41 Mon Sep 17 00:00:00 2001 From: Unknown <joe2010xtmf@163.com> Date: Sat, 29 Mar 2014 11:56:00 -0400 Subject: [PATCH 07/14] Bug fix --- routers/repo/issue.go | 8 ++++---- templates/install.tmpl | 2 +- templates/issue/view.tmpl | 8 ++++---- web.go | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/routers/repo/issue.go b/routers/repo/issue.go index b38967f717..337bd4bf1c 100644 --- a/routers/repo/issue.go +++ b/routers/repo/issue.go @@ -175,6 +175,7 @@ func ViewIssue(ctx *middleware.Context, params martini.Params) { ctx.Data["Title"] = issue.Name ctx.Data["Issue"] = issue ctx.Data["Comments"] = comments + ctx.Data["IsIssueOwner"] = issue.PosterId == ctx.User.Id ctx.Data["IsRepoToolbarIssues"] = true ctx.Data["IsRepoToolbarIssuesList"] = false ctx.HTML(200, "issue/view") @@ -217,10 +218,9 @@ func UpdateIssue(ctx *middleware.Context, params martini.Params, form auth.Creat } ctx.JSON(200, map[string]interface{}{ - "ok": true, - "title": issue.Name, - "content": string(base.RenderMarkdown([]byte(issue.Content), "")), - "raw_content": issue.Content, + "ok": true, + "title": issue.Name, + "content": string(base.RenderMarkdown([]byte(issue.Content), "")), }) } diff --git a/templates/install.tmpl b/templates/install.tmpl index d8f05fcaa7..a456ac5f2c 100644 --- a/templates/install.tmpl +++ b/templates/install.tmpl @@ -133,7 +133,7 @@ <hr/> <div class="form-group text-center"> - <button class="btn btn-primary btn-lg">Test Configuration</button> + <!-- <button class="btn btn-primary btn-lg">Test Configuration</button> --> <button class="btn btn-danger btn-lg">Install Gogs</button> <button class="btn btn-default btn-sm" type="button" data-toggle="modal" data-target="#advance-options-modal"> Advanced Options diff --git a/templates/issue/view.tmpl b/templates/issue/view.tmpl index c6f1444e46..2c00e8996b 100644 --- a/templates/issue/view.tmpl +++ b/templates/issue/view.tmpl @@ -12,9 +12,9 @@ <input id="issue-edit-title" class="form-control input-lg pull-left hidden" type="text" value="{{.Issue.Name}}" data-ajax-rel="issue-edit-save" data-ajax-val="val" data-ajax-field="title"/> <input type="hidden" value="{{.Issue.Id}}" data-ajax-rel="issue-edit-save" data-ajax-val="val" data-ajax-field="issue_id"/> <p class="info pull-left"> - <a class="btn btn-default pull-right issue-edit" href="#" id="issue-edit-btn">Edit</a> + {{if .IsIssueOwner}}<a class="btn btn-default pull-right issue-edit" href="#" id="issue-edit-btn">Edit</a> <a class="btn btn-danger pull-right issue-edit-cancel hidden" href="#">Cancel</a> - <a class="btn btn-primary pull-right issue-edit-save hidden" href="#" data-ajax="/{{.RepositoryLink}}/issues/{{.Issue.Index}}" data-ajax-name="issue-edit-save" data-ajax-method="post">Save</a> + <a class="btn btn-primary pull-right issue-edit-save hidden" href="#" data-ajax="/{{.RepositoryLink}}/issues/{{.Issue.Index}}" data-ajax-name="issue-edit-save" data-ajax-method="post">Save</a>{{end}} <span class="status label label-{{if .Issue.IsClosed}}danger{{else}}success{{end}}">{{if .Issue.IsClosed}}Closed{{else}}Open{{end}}</span> <a href="/user/{{.Issue.Poster.Name}}" class="author"><strong>{{.Issue.Poster.Name}}</strong></a> opened this issue <span class="time">{{TimeSince .Issue.Created}}</span> · {{.Issue.NumComments}} comments @@ -62,7 +62,7 @@ </div> </div> --> <hr class="issue-line"/> - <div class="issue-child issue-reply"> + {{if .SignedUser}}<div class="issue-child issue-reply"> <a class="user pull-left" href="/user/{{.SignedUser.Name}}"><img class="avatar" src="{{.SignedUser.AvatarLink}}" alt=""/></a> <form class="panel panel-default issue-content" action="/{{.RepositoryLink}}/comment/new" method="post"> {{.CsrfTokenHtml}} @@ -95,7 +95,7 @@ </div> </div> </form> - </div> + </div>{{else}}<div class="alert alert-warning"><a class="btn btn-success btn-lg" href="/user/sign_up">Sign up for free</a> to join this conversation. Already have an account? <a href="/user/login">Sign in to comment</a></div>{{end}} </div><!-- <div class="col-md-3"> label assignment milestone dashboard diff --git a/web.go b/web.go index 7725791e84..7098717a05 100644 --- a/web.go +++ b/web.go @@ -92,7 +92,7 @@ func runWeb(*cli.Context) { // Routers. m.Get("/", ignSignIn, routers.Home) - m.Any("/install", routers.Install) + m.Any("/install", binding.BindIgnErr(auth.InstallForm{}), routers.Install) m.Get("/issues", reqSignIn, user.Issues) m.Get("/pulls", reqSignIn, user.Pulls) m.Get("/stars", reqSignIn, user.Stars) From 107a1eadac72e610a9bcb68498751ca51ec8f51a Mon Sep 17 00:00:00 2001 From: Unknown <joe2010xtmf@163.com> Date: Sat, 29 Mar 2014 17:50:51 -0400 Subject: [PATCH 08/14] Finish close and reopen issue, install page, ready going to test stage of v0.2.0 --- README.md | 2 +- README_ZH.md | 2 +- gogs.go | 2 +- models/issue.go | 36 ++++++++-- models/models.go | 24 +++---- models/repo.go | 25 +++---- modules/auth/auth.go | 1 + modules/base/conf.go | 7 +- public/css/gogs.css | 6 +- routers/install.go | 141 ++++++++++++++++++++++++++++++++++++-- routers/repo/issue.go | 62 ++++++++++++----- routers/user/user.go | 14 ++-- templates/install.tmpl | 59 ++++++++-------- templates/issue/view.tmpl | 67 +++++++++--------- web.go | 28 +------- 15 files changed, 315 insertions(+), 161 deletions(-) diff --git a/README.md b/README.md index e88a247705..1d3aaf3e8a 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.1.9 Alpha +##### Current version: 0.2.0 Alpha #### Due to testing purpose, data of [try.gogits.org](http://try.gogits.org) has been reset in March 29, 2014 and will reset multiple times after. Please do NOT put your important data on the site. diff --git a/README_ZH.md b/README_ZH.md index 8e187c7364..4590e36b1d 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -5,7 +5,7 @@ Gogs(Go Git Service) 是一个由 Go 语言编写的自助 Git 托管服务。  -##### 当前版本:0.1.9 Alpha +##### 当前版本:0.2.0 Alpha ## 开发目的 diff --git a/gogs.go b/gogs.go index f1372f0cfc..2ef35ca4da 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.1.9.0329 Alpha" +const APP_VER = "0.2.0.0329 Alpha" func init() { base.AppVer = APP_VER diff --git a/models/issue.go b/models/issue.go index 9fd1b905a5..f14030df5e 100644 --- a/models/issue.go +++ b/models/issue.go @@ -170,9 +170,17 @@ type Milestone struct { Created time.Time `xorm:"created"` } +// Issue types. +const ( + IT_PLAIN = iota // Pure comment. + IT_REOPEN // Issue reopen status change prompt. + IT_CLOSE // Issue close status change prompt. +) + // Comment represents a comment in commit and issue page. type Comment struct { Id int64 + Type int PosterId int64 Poster *User `xorm:"-"` IssueId int64 @@ -183,21 +191,37 @@ type Comment struct { } // CreateComment creates comment of issue or commit. -func CreateComment(userId, issueId, commitId, line int64, content string) error { +func CreateComment(userId, repoId, issueId, commitId, line int64, cmtType int, content string) error { sess := orm.NewSession() defer sess.Close() sess.Begin() - if _, err := orm.Insert(&Comment{PosterId: userId, IssueId: issueId, + if _, err := orm.Insert(&Comment{PosterId: userId, Type: cmtType, IssueId: issueId, CommitId: commitId, Line: line, Content: content}); err != nil { sess.Rollback() return err } - rawSql := "UPDATE `issue` SET num_comments = num_comments + 1 WHERE id = ?" - if _, err := sess.Exec(rawSql, issueId); err != nil { - sess.Rollback() - return err + // Check comment type. + switch cmtType { + case IT_PLAIN: + rawSql := "UPDATE `issue` SET num_comments = num_comments + 1 WHERE id = ?" + if _, err := sess.Exec(rawSql, issueId); err != nil { + sess.Rollback() + return err + } + case IT_REOPEN: + rawSql := "UPDATE `repository` SET num_closed_issues = num_closed_issues - 1 WHERE id = ?" + if _, err := sess.Exec(rawSql, repoId); err != nil { + sess.Rollback() + return err + } + case IT_CLOSE: + rawSql := "UPDATE `repository` SET num_closed_issues = num_closed_issues + 1 WHERE id = ?" + if _, err := sess.Exec(rawSql, repoId); err != nil { + sess.Rollback() + return err + } } return sess.Commit() } diff --git a/models/models.go b/models/models.go index bafa1747e8..825730c5a8 100644 --- a/models/models.go +++ b/models/models.go @@ -34,8 +34,7 @@ func LoadModelsConfig() { DbCfg.Path = base.Cfg.MustValue("database", "PATH", "data/gogs.db") } -func SetEngine() { - var err error +func SetEngine() (err error) { switch DbCfg.Type { case "mysql": orm, err = xorm.NewEngine("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8", @@ -47,12 +46,10 @@ func SetEngine() { os.MkdirAll(path.Dir(DbCfg.Path), os.ModePerm) orm, err = xorm.NewEngine("sqlite3", DbCfg.Path) default: - fmt.Printf("Unknown database type: %s\n", DbCfg.Type) - os.Exit(2) + return fmt.Errorf("Unknown database type: %s\n", DbCfg.Type) } if err != nil { - fmt.Printf("models.init(fail to conntect database): %v\n", err) - os.Exit(2) + return fmt.Errorf("models.init(fail to conntect database): %v\n", err) } // WARNNING: for serv command, MUST remove the output to os.stdout, @@ -62,20 +59,21 @@ func SetEngine() { //orm.ShowErr = true f, err := os.Create("xorm.log") if err != nil { - fmt.Printf("models.init(fail to create xorm.log): %v\n", err) - os.Exit(2) + return fmt.Errorf("models.init(fail to create xorm.log): %v\n", err) } orm.Logger = f orm.ShowSQL = true + return nil } -func NewEngine() { - SetEngine() - if err := orm.Sync(new(User), new(PublicKey), new(Repository), new(Watch), +func NewEngine() (err error) { + if err = SetEngine(); err != nil { + return err + } else if err = orm.Sync(new(User), new(PublicKey), new(Repository), new(Watch), new(Action), new(Access), new(Issue), new(Comment)); err != nil { - fmt.Printf("sync database struct error: %v\n", err) - os.Exit(2) + return fmt.Errorf("sync database struct error: %v\n", err) } + return nil } type Statistic struct { diff --git a/models/repo.go b/models/repo.go index a848694da6..0b2bbe4862 100644 --- a/models/repo.go +++ b/models/repo.go @@ -11,7 +11,6 @@ import ( "os" "os/exec" "path/filepath" - "regexp" "strings" "time" "unicode/utf8" @@ -59,15 +58,6 @@ func NewRepoContext() { os.Exit(2) } } - - // Initialize illegal patterns. - for i := range illegalPatterns[1:] { - pattern := "" - for j := range illegalPatterns[i+1] { - pattern += "[" + string(illegalPatterns[i+1][j]-32) + string(illegalPatterns[i+1][j]) + "]" - } - illegalPatterns[i+1] = pattern - } } // Repository represents a git repository. @@ -105,15 +95,20 @@ func IsRepositoryExist(user *User, repoName string) (bool, error) { } var ( - // Define as all lower case!! - illegalPatterns = []string{"[.][Gg][Ii][Tt]", "raw", "user", "help", "stars", "issues", "pulls", "commits", "repo", "template", "admin"} + illegalEquals = []string{"raw", "install", "api", "avatar", "user", "help", "stars", "issues", "pulls", "commits", "repo", "template", "admin"} + illegalSuffixs = []string{".git"} ) // IsLegalName returns false if name contains illegal characters. func IsLegalName(repoName string) bool { - for _, pattern := range illegalPatterns { - has, _ := regexp.MatchString(pattern, repoName) - if has { + repoName = strings.ToLower(repoName) + for _, char := range illegalEquals { + if repoName == char { + return false + } + } + for _, char := range illegalSuffixs { + if strings.HasSuffix(repoName, char) { return false } } diff --git a/modules/auth/auth.go b/modules/auth/auth.go index ac03a8f126..361f55b2d3 100644 --- a/modules/auth/auth.go +++ b/modules/auth/auth.go @@ -172,6 +172,7 @@ type InstallForm struct { DatabasePath string `form:"database_path"` RepoRootPath string `form:"repo_path"` RunUser string `form:"run_user"` + Domain string `form:"domain"` AppUrl string `form:"app_url"` AdminName string `form:"admin_name" binding:"Required"` AdminPasswd string `form:"admin_pwd" binding:"Required;MinSize(6);MaxSize(30)"` diff --git a/modules/base/conf.go b/modules/base/conf.go index fd77cfd3ce..f696d083f7 100644 --- a/modules/base/conf.go +++ b/modules/base/conf.go @@ -272,18 +272,19 @@ func NewConfigContext() { Domain = Cfg.MustValue("server", "DOMAIN") SecretKey = Cfg.MustValue("security", "SECRET_KEY") + InstallLock = Cfg.MustBool("security", "INSTALL_LOCK", false) + RunUser = Cfg.MustValue("", "RUN_USER") curUser := os.Getenv("USERNAME") if len(curUser) == 0 { curUser = os.Getenv("USER") } - if RunUser != curUser { + // Does not check run user when the install lock is off. + if InstallLock && RunUser != curUser { fmt.Printf("Expect user(%s) but current user is: %s\n", RunUser, curUser) os.Exit(2) } - InstallLock = Cfg.MustBool("security", "INSTALL_LOCK", false) - LogInRememberDays = Cfg.MustInt("security", "LOGIN_REMEMBER_DAYS") CookieUserName = Cfg.MustValue("security", "COOKIE_USERNAME") CookieRememberName = Cfg.MustValue("security", "COOKIE_REMEMBER_NAME") diff --git a/public/css/gogs.css b/public/css/gogs.css index d6c117c846..965c90962c 100755 --- a/public/css/gogs.css +++ b/public/css/gogs.css @@ -1197,13 +1197,13 @@ html, body { line-height: 42px; } -#issue .issue-closed{ - border-bottom: 3px solid #CCC; +#issue .issue-closed, #issue .issue-opened { + border-bottom: 2px solid #CCC; margin-bottom: 24px; padding-bottom: 24px; } -#issue .issue-closed .btn-danger,#issue .issue-opened .btn-success{ +#issue .issue-closed .label-danger,#issue .issue-opened .label-success{ margin: 0 .8em; } diff --git a/routers/install.go b/routers/install.go index b5c3a9364b..407705b73a 100644 --- a/routers/install.go +++ b/routers/install.go @@ -6,13 +6,46 @@ package routers import ( "errors" + "os" + "strings" + + "github.com/Unknwon/goconfig" + "github.com/codegangsta/martini" "github.com/gogits/gogs/models" "github.com/gogits/gogs/modules/auth" "github.com/gogits/gogs/modules/base" + "github.com/gogits/gogs/modules/log" + "github.com/gogits/gogs/modules/mailer" "github.com/gogits/gogs/modules/middleware" ) +// Check run mode(Default of martini is Dev). +func checkRunMode() { + switch base.Cfg.MustValue("", "RUN_MODE") { + case "prod": + martini.Env = martini.Prod + case "test": + martini.Env = martini.Test + } + log.Info("Run Mode: %s", strings.Title(martini.Env)) +} + +// GlobalInit is for global configuration reload-able. +func GlobalInit() { + base.NewConfigContext() + mailer.NewMailerContext() + models.LoadModelsConfig() + models.LoadRepoConfig() + models.NewRepoContext() + if err := models.NewEngine(); err != nil && base.InstallLock { + log.Error("%v", err) + os.Exit(2) + } + base.NewServices() + checkRunMode() +} + func Install(ctx *middleware.Context, form auth.InstallForm) { if base.InstallLock { ctx.Handle(404, "install.Install", errors.New("Installation is prohibited")) @@ -20,14 +53,114 @@ func Install(ctx *middleware.Context, form auth.InstallForm) { } ctx.Data["Title"] = "Install" - ctx.Data["DbCfg"] = models.DbCfg - ctx.Data["RepoRootPath"] = base.RepoRootPath - ctx.Data["RunUser"] = base.RunUser - ctx.Data["AppUrl"] = base.AppUrl ctx.Data["PageIsInstall"] = true + // Get and assign value to install form. + if len(form.Host) == 0 { + form.Host = models.DbCfg.Host + } + if len(form.User) == 0 { + form.User = models.DbCfg.User + } + if len(form.Passwd) == 0 { + form.Passwd = models.DbCfg.Pwd + } + if len(form.DatabaseName) == 0 { + form.DatabaseName = models.DbCfg.Name + } + if len(form.DatabasePath) == 0 { + form.DatabasePath = models.DbCfg.Path + } + + if len(form.RepoRootPath) == 0 { + form.RepoRootPath = base.RepoRootPath + } + if len(form.RunUser) == 0 { + form.RunUser = base.RunUser + } + if len(form.Domain) == 0 { + form.Domain = base.Domain + } + if len(form.AppUrl) == 0 { + form.AppUrl = base.AppUrl + } + + auth.AssignForm(form, ctx.Data) + if ctx.Req.Method == "GET" { ctx.HTML(200, "install") return } + + if ctx.HasError() { + ctx.HTML(200, "install") + return + } + + // Pass basic check, now test configuration. + // Test database setting. + dbTypes := map[string]string{"mysql": "mysql", "pgsql": "postgres", "sqlite": "sqlite3"} + models.DbCfg.Type = dbTypes[form.Database] + models.DbCfg.Host = form.Host + models.DbCfg.User = form.User + models.DbCfg.Pwd = form.Passwd + models.DbCfg.Name = form.DatabaseName + models.DbCfg.SslMode = form.SslMode + models.DbCfg.Path = form.DatabasePath + + if err := models.NewEngine(); err != nil { + ctx.RenderWithErr("Database setting is not correct: "+err.Error(), "install", &form) + return + } + + // Test repository root path. + if err := os.MkdirAll(form.RepoRootPath, os.ModePerm); err != nil { + ctx.RenderWithErr("Repository root path is invalid: "+err.Error(), "install", &form) + return + } + + // Create admin account. + if _, err := models.RegisterUser(&models.User{Name: form.AdminName, Email: form.AdminEmail, Passwd: form.AdminPasswd, + IsAdmin: true, IsActive: true}); err != nil { + if err != models.ErrUserAlreadyExist { + ctx.RenderWithErr("Admin account setting is invalid: "+err.Error(), "install", &form) + return + } + } + + // Save settings. + base.Cfg.SetValue("database", "DB_TYPE", models.DbCfg.Type) + base.Cfg.SetValue("database", "HOST", models.DbCfg.Host) + base.Cfg.SetValue("database", "NAME", models.DbCfg.Name) + base.Cfg.SetValue("database", "USER", models.DbCfg.User) + base.Cfg.SetValue("database", "PASSWD", models.DbCfg.Pwd) + base.Cfg.SetValue("database", "SSL_MODE", models.DbCfg.SslMode) + base.Cfg.SetValue("database", "PATH", models.DbCfg.Path) + + base.Cfg.SetValue("repository", "ROOT", form.RepoRootPath) + base.Cfg.SetValue("", "RUN_USER", form.RunUser) + base.Cfg.SetValue("server", "DOMAIN", form.Domain) + base.Cfg.SetValue("server", "ROOT_URL", form.AppUrl) + + if len(form.Host) > 0 { + base.Cfg.SetValue("mailer", "ENABLED", "true") + base.Cfg.SetValue("mailer", "HOST", form.SmtpHost) + base.Cfg.SetValue("mailer", "USER", form.SmtpEmail) + base.Cfg.SetValue("mailer", "PASSWD", form.SmtpPasswd) + + base.Cfg.SetValue("service", "REGISTER_EMAIL_CONFIRM", base.ToStr(form.RegisterConfirm == "on")) + base.Cfg.SetValue("service", "ENABLE_NOTIFY_MAIL", base.ToStr(form.MailNotify == "on")) + } + + base.Cfg.SetValue("security", "INSTALL_LOCK", "true") + + if err := goconfig.SaveConfigFile(base.Cfg, "custom/conf/app.ini"); err != nil { + ctx.RenderWithErr("Fail to save configuration: "+err.Error(), "install", &form) + return + } + + GlobalInit() + + log.Info("First-time run install finished!") + ctx.Redirect("/user/login") } diff --git a/routers/repo/issue.go b/routers/repo/issue.go index 337bd4bf1c..3506e90163 100644 --- a/routers/repo/issue.go +++ b/routers/repo/issue.go @@ -7,6 +7,7 @@ package repo import ( "fmt" "net/url" + "strings" "github.com/codegangsta/martini" @@ -175,7 +176,7 @@ func ViewIssue(ctx *middleware.Context, params martini.Params) { ctx.Data["Title"] = issue.Name ctx.Data["Issue"] = issue ctx.Data["Comments"] = comments - ctx.Data["IsIssueOwner"] = issue.PosterId == ctx.User.Id + ctx.Data["IsIssueOwner"] = ctx.Repo.IsOwner || issue.PosterId == ctx.User.Id ctx.Data["IsRepoToolbarIssues"] = true ctx.Data["IsRepoToolbarIssuesList"] = false ctx.HTML(200, "issue/view") @@ -225,24 +226,17 @@ func UpdateIssue(ctx *middleware.Context, params martini.Params, form auth.Creat } func Comment(ctx *middleware.Context, params martini.Params) { - fmt.Println(ctx.Query("change_status")) if !ctx.Repo.IsValid { ctx.Handle(404, "issue.Comment(invalid repo):", nil) } - index, err := base.StrTo(ctx.Query("issueIndex")).Int() + index, err := base.StrTo(ctx.Query("issueIndex")).Int64() if err != nil { - ctx.Handle(404, "issue.Comment", err) + ctx.Handle(404, "issue.Comment(get index)", err) return } - content := ctx.Query("content") - if len(content) == 0 { - ctx.Redirect(fmt.Sprintf("/%s/%s/issues/%d", ctx.User.Name, ctx.Repo.Repository.Name, index)) - return - } - - issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, int64(index)) + issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, index) if err != nil { if err == models.ErrIssueNotExist { ctx.Handle(404, "issue.Comment", err) @@ -252,16 +246,46 @@ func Comment(ctx *middleware.Context, params martini.Params) { return } - switch params["action"] { - case "new": - if err = models.CreateComment(ctx.User.Id, issue.Id, 0, 0, content); err != nil { - ctx.Handle(500, "issue.Comment(create comment)", err) + // Check if issue owner changes the status of issue. + var newStatus string + if ctx.Repo.IsOwner || issue.PosterId == ctx.User.Id { + newStatus = ctx.Query("change_status") + } + if len(newStatus) > 0 { + if (strings.Contains(newStatus, "Reopen") && issue.IsClosed) || + (strings.Contains(newStatus, "Close") && !issue.IsClosed) { + issue.IsClosed = !issue.IsClosed + if err = models.UpdateIssue(issue); err != nil { + ctx.Handle(200, "issue.Comment(update issue status)", err) + return + } + + cmtType := models.IT_CLOSE + if !issue.IsClosed { + cmtType = models.IT_REOPEN + } + + if err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.Id, 0, 0, cmtType, ""); err != nil { + ctx.Handle(200, "issue.Comment(create status change comment)", err) + return + } + log.Trace("%s Issue(%d) status changed: %v", ctx.Req.RequestURI, issue.Id, !issue.IsClosed) + } + } + + content := ctx.Query("content") + if len(content) > 0 { + switch params["action"] { + case "new": + if err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.Id, 0, 0, models.IT_PLAIN, content); err != nil { + ctx.Handle(500, "issue.Comment(create comment)", err) + return + } + log.Trace("%s Comment created: %d", ctx.Req.RequestURI, issue.Id) + default: + ctx.Handle(404, "issue.Comment", err) return } - log.Trace("%s Comment created: %d", ctx.Req.RequestURI, issue.Id) - default: - ctx.Handle(404, "issue.Comment", err) - return } ctx.Redirect(fmt.Sprintf("/%s/%s/issues/%d", ctx.User.Name, ctx.Repo.Repository.Name, index)) diff --git a/routers/user/user.go b/routers/user/user.go index 114169e606..aeaf91c97d 100644 --- a/routers/user/user.go +++ b/routers/user/user.go @@ -120,7 +120,7 @@ func SignIn(ctx *middleware.Context, form auth.LogInForm) { return } - if hasErr, ok := ctx.Data["HasError"]; ok && hasErr.(bool) { + if ctx.HasError() { ctx.HTML(200, "user/signin") return } @@ -308,17 +308,19 @@ func Issues(ctx *middleware.Context) { showRepos := make([]models.Repository, 0, len(repos)) - var closedIssueCount, createdByCount int + isShowClosed := ctx.Query("state") == "closed" + var closedIssueCount, createdByCount, allIssueCount int // Get all issues. allIssues := make([]models.Issue, 0, 5*len(repos)) for i, repo := range repos { - issues, err := models.GetIssues(0, repo.Id, posterId, 0, page, false, false, "", "") + issues, err := models.GetIssues(0, repo.Id, posterId, 0, page, isShowClosed, false, "", "") if err != nil { ctx.Handle(200, "user.Issues(get issues)", err) return } + allIssueCount += repo.NumIssues closedIssueCount += repo.NumClosedIssues // Set repository information to issues. @@ -330,12 +332,10 @@ func Issues(ctx *middleware.Context) { repos[i].NumOpenIssues = repo.NumIssues - repo.NumClosedIssues if repos[i].NumOpenIssues > 0 { showRepos = append(showRepos, repos[i]) - } } showIssues := make([]models.Issue, 0, len(allIssues)) - isShowClosed := ctx.Query("state") == "closed" ctx.Data["IsShowClosed"] = isShowClosed // Get posters and filter issues. @@ -361,9 +361,9 @@ func Issues(ctx *middleware.Context) { ctx.Data["Repos"] = showRepos ctx.Data["Issues"] = showIssues - ctx.Data["AllIssueCount"] = len(allIssues) + ctx.Data["AllIssueCount"] = allIssueCount ctx.Data["ClosedIssueCount"] = closedIssueCount - ctx.Data["OpenIssueCount"] = len(allIssues) - closedIssueCount + ctx.Data["OpenIssueCount"] = allIssueCount - closedIssueCount ctx.Data["CreatedByCount"] = createdByCount ctx.HTML(200, "issue/user") } diff --git a/templates/install.tmpl b/templates/install.tmpl index a456ac5f2c..20bd502da2 100644 --- a/templates/install.tmpl +++ b/templates/install.tmpl @@ -3,9 +3,8 @@ <form action="/install" method="post" class="form-horizontal card" id="install-card"> {{.CsrfTokenHtml}} <h3>Install Steps For First-time Run</h3> - <div class="alert alert-danger form-error{{if .HasError}}{{else}} hidden{{end}}">{{.ErrorMsg}}</div> - <p class="help-block text-center">Gogs requires MySQL or PostgreSQL based on your choice</p> + <p class="help-block text-center">Gogs requires MySQL or PostgreSQL, SQLite3 only available for official binary version</p> <div class="form-group"> <label class="col-md-3 control-label">Database Type: </label> <div class="col-md-8"> @@ -16,26 +15,28 @@ </select> </div> </div> + <div class="server-sql"> <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, leave blank to keep default" value="{{.DbCfg.Host}}" required="required"> + <input name="host" class="form-control" placeholder="Type database server host" value="{{.host}}" required="required"> </div> </div> + <div class="form-group"> <label class="col-md-3 control-label">User: </label> <div class="col-md-8"> - <input name="user" class="form-control" placeholder="Type database username" required="required" value="{{.DbCfg.User}}"> + <input name="user" class="form-control" placeholder="Type database username" required="required" value="{{.user}}"> </div> </div> + <div class="form-group"> <label class="col-md-3 control-label">Password: </label> <div class="col-md-8"> - <input name="passwd" type="password" class="form-control" placeholder="Type database password" required="required" value="{{.DbCfg.Pwd}}"> + <input name="passwd" type="password" class="form-control" placeholder="Type database password" required="required" value="{{.passwd}}"> </div> </div> @@ -43,7 +44,7 @@ <label class="col-md-3 control-label">Database Name: </label> <div class="col-md-8"> - <input name="database_name" type="text" class="form-control" placeholder="Type mysql database name" value="{{.DbCfg.Name}}" required="required"> + <input name="database_name" type="text" class="form-control" placeholder="Type mysql database name" value="{{.database_name}}" required="required"> <p class="help-block">Recommend use INNODB engine with utf8_general_ci charset.</p> </div> </div> @@ -59,12 +60,13 @@ </div> </div> </div> + <div class="sqlite-setting hide"> <div class="form-group"> <label class="col-md-3 control-label">Path: </label> <div class="col-md-8"> - <input name="database_path" class="form-control" placeholder="Type sqlite3 file path" value="{{.DbCfg.Path}}"> + <input name="database_path" class="form-control" placeholder="Type sqlite3 file path" value="{{.database_path}}"> <p class="help-block">The file path of SQLite3 database.</p> </div> </div> @@ -73,12 +75,11 @@ <hr/> <p class="help-block text-center">General Settings of Gogs</p> - <div class="form-group"> <label class="col-md-3 control-label">Repository Path: </label> <div class="col-md-8"> - <input name="repo_path" type="text" class="form-control" placeholder="Type your repository directory" value="{{.RepoRootPath}}" required="required"> + <input name="repo_path" type="text" class="form-control" placeholder="Type your repository directory" value="{{.repo_path}}" required="required"> <p class="help-block">The git copy of each repository is saved in this directory.</p> </div> @@ -88,16 +89,25 @@ <label class="col-md-3 control-label">Run User: </label> <div class="col-md-8"> - <input name="run_user" type="text" class="form-control" placeholder="Type system user name" value="{{.RunUser}}" required="required"> + <input name="run_user" type="text" class="form-control" placeholder="Type system user name" value="{{.run_user}}" required="required"> <p class="help-block">The user has access to visit and run Gogs.</p> </div> </div> + <div class="form-group"> + <label class="col-md-3 control-label">Domain: </label> + + <div class="col-md-8"> + <input name="domain" type="text" class="form-control" placeholder="Type your domain name" value="{{.domain}}" required="required"> + <p class="help-block">This affects SSH clone URL.</p> + </div> + </div> + <div class="form-group"> <label class="col-md-3 control-label">App URL: </label> <div class="col-md-8"> - <input name="app_url" type="text" class="form-control" placeholder="Type app root URL " value="{{.AppUrl}}" required="required"> + <input name="app_url" type="text" class="form-control" placeholder="Type app root URL" value="{{.app_url}}" required="required"> <p class="help-block">This affects HTTP/HTTPS clone URL and somewhere in e-mail.</p> </div> </div> @@ -105,35 +115,30 @@ <hr/> <p class="help-block text-center">Admin Account Settings</p> - <div class="form-group"> <label class="col-md-3 control-label">Username: </label> - <div class="col-md-8"> - <input name="admin_name" type="text" class="form-control" placeholder="Type admin user name" value="admin" required="required"> + <input name="admin_name" type="text" class="form-control" placeholder="Type admin user name" value="{{.admin_name}}" required="required"> </div> </div> - <div class="form-group"> + <div class="form-group {{if .Err_AdminPasswd}}has-error has-feedback{{end}}"> <label class="col-md-3 control-label">Password: </label> - <div class="col-md-8"> - <input name="admin_pwd" type="password" class="form-control" placeholder="Type admin user password" required="required"> + <input name="admin_pwd" type="password" class="form-control" placeholder="Type admin user password" value="{{.admin_pwd}}" required="required"> </div> </div> - <div class="form-group"> + <div class="form-group {{if .Err_AdminEmail}}has-error has-feedback{{end}}"> <label class="col-md-3 control-label">E-mail: </label> - <div class="col-md-8"> - <input name="admin_email" type="text" class="form-control" placeholder="Type admin user e-mail" required="required"> + <input name="admin_email" type="text" class="form-control" placeholder="Type admin user e-mail" value="{{.admin_email}}" required="required"> </div> </div> <hr/> <div class="form-group text-center"> - <!-- <button class="btn btn-primary btn-lg">Test Configuration</button> --> <button class="btn btn-danger btn-lg">Install Gogs</button> <button class="btn btn-default btn-sm" type="button" data-toggle="modal" data-target="#advance-options-modal"> Advanced Options @@ -151,21 +156,21 @@ <label class="col-md-3 control-label">SMTP Host: </label> <div class="col-md-8"> - <input name="smtp_host" type="text" class="form-control" placeholder="Type SMTP host address"> + <input name="smtp_host" type="text" class="form-control" placeholder="Type SMTP host address" value="{{.smtp_host}}"> </div> </div> <div class="form-group"> <label class="col-md-3 control-label">Email: </label> <div class="col-md-8"> - <input name="mailer_user" type="text" class="form-control" placeholder="Type SMTP user e-mail address"> + <input name="mailer_user" type="text" class="form-control" placeholder="Type SMTP user e-mail address" value="{{.mailer_user}}"> </div> </div> <div class="form-group"> <label class="col-md-3 control-label">Password: </label> <div class="col-md-8"> - <input name="mailer_pwd" type="password" class="form-control" placeholder="Type SMTP user password"> + <input name="mailer_pwd" type="password" class="form-control" placeholder="Type SMTP user password" value="{{.mailer_pwd}}"> </div> </div> <hr/> @@ -175,7 +180,7 @@ <div class="col-md-offset-3 col-md-7"> <div class="checkbox"> <label> - <input name="register_confirm" type="checkbox"> + <input name="register_confirm" type="checkbox" {{if .register_confirm}}checked{{end}}> <strong>Enable Register Confirmation</strong> </label> </div> @@ -186,7 +191,7 @@ <div class="col-md-offset-3 col-md-7"> <div class="checkbox"> <label> - <input name="mail_notify" type="checkbox"> + <input name="mail_notify" type="checkbox" {{if .mail_notify}}checked{{end}}> <strong>Enable Mail Notification</strong> </label> </div> diff --git a/templates/issue/view.tmpl b/templates/issue/view.tmpl index 0481a33b40..91e5250ca3 100644 --- a/templates/issue/view.tmpl +++ b/templates/issue/view.tmpl @@ -30,37 +30,37 @@ </div> </div> {{range .Comments}} - <div class="issue-child" id="issue-comment-{{.Id}}"> - <a class="user pull-left" href="/user/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt=""/></a> - <div class="issue-content panel panel-default"> - <div class="panel-heading"> - <a href="/user/{{.Poster.Name}}" class="user">{{.Poster.Name}}</a> commented <span class="time">{{TimeSince .Created}}</span> - <!-- <a class="issue-comment-del pull-right issue-action" href="#" title="Edit Comment"><i class="fa fa-times-circle"></i></a> - <a class="issue-comment-edit pull-right issue-action" href="#" title="Remove Comment" data-url="{remove-link}"><i class="fa fa-edit"></i></a> --> - <span class="role label label-default pull-right">Owner</span> - </div> - <div class="panel-body markdown"> - {{str2html .Content}} - </div> - </div> - </div> + {{if eq .Type 0}} + <div class="issue-child" id="issue-comment-{{.Id}}"> + <a class="user pull-left" href="/user/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt=""/></a> + <div class="issue-content panel panel-default"> + <div class="panel-heading"> + <a href="/user/{{.Poster.Name}}" class="user">{{.Poster.Name}}</a> commented <span class="time">{{TimeSince .Created}}</span> + <!-- <a class="issue-comment-del pull-right issue-action" href="#" title="Edit Comment"><i class="fa fa-times-circle"></i></a> + <a class="issue-comment-edit pull-right issue-action" href="#" title="Remove Comment" data-url="{remove-link}"><i class="fa fa-edit"></i></a> --> + <span class="role label label-default pull-right">Owner</span> + </div> + <div class="panel-body markdown"> + {{str2html .Content}} + </div> + </div> + </div> + {{else if eq .Type 1}} + <div class="issue-child issue-opened"> + <a class="user pull-left" href="/user/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt="" /></a> + <div class="issue-content"> + <a class="user pull-left" href="/user/{{.Poster.Name}}">{{.Poster.Name}}</a> <span class="label label-success">Reopened</span> this issue <span class="time">{{TimeSince .Created}}</span> + </div> + </div> + {{else if eq .Type 2}} + <div class="issue-child issue-closed"> + <a class="user pull-left" href="/user/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt=""/></a> + <div class="issue-content"> + <a class="user pull-left" href="/user/{{.Poster.Name}}">{{.Poster.Name}}</a> <span class="label label-danger">Closed</span> this issue <span class="time">{{TimeSince .Created}}</span> + </div> + </div> + {{end}} {{end}} - <!-- <div class="issue-child issue-closed"> - <a class="user pull-left" href="{user.link}"><img class="avatar" src="{user.avatar}" alt=""/></a> - <div class="issue-content"> - <a class="user pull-left" href="{user.link}">{user.name}</a> - <span class="btn btn-danger">Closed</span> this - <span class="time">{close.time}</span> - </div> - </div> - <div class="issue-child issue-opened"> - <a class="user pull-left" href="{user.link}"><img class="avatar" src="{user.avatar}" alt=""/></a> - <div class="issue-content"> - <a class="user pull-left" href="{user.link}">{user.name}</a> - <span class="btn btn-success">Reopened</span> this - <span class="time">{close.time}</span> - </div> - </div> --> <hr class="issue-line"/> {{if .SignedUser}}<div class="issue-child issue-reply"> <a class="user pull-left" href="/user/{{.SignedUser.Name}}"><img class="avatar" src="{{.SignedUser.AvatarLink}}" alt=""/></a> @@ -68,8 +68,7 @@ {{.CsrfTokenHtml}} <div class="panel-body"> <div class="form-group"> - <div class="md-help pull-right"><!-- todo help link --> - Content with <a href="https://help.github.com/articles/markdown-basics">Markdown</a> + <div class="md-help pull-right">Content with <a href="https://help.github.com/articles/markdown-basics">Markdown</a> </div> <ul class="nav nav-tabs" data-init="tabs"> <li class="active issue-write"><a href="#issue-textarea" data-toggle="tab">Write</a></li> @@ -82,13 +81,13 @@ <textarea class="form-control" name="content" id="issue-reply-content" rows="10" placeholder="Write some content" data-ajax-rel="issue-preview" data-ajax-val="val" data-ajax-field="content">{{.content}}</textarea> </div> </div> - <div class="tab-pane issue-preview-content" id="issue-preview">loading...</div> + <div class="tab-pane issue-preview-content" id="issue-preview">Loading...</div> </div> </div> <div class="text-right"> <div class="form-group"> {{if .Issue.IsClosed}} - <input type="submit" class="btn-default btn issue-open" id="issue-open-btn" data-origin="Re-Open" data-text="Re-Open & Comment" name="change_status" value="Reopen"/>{{else}} + <input type="submit" class="btn-default btn issue-open" id="issue-open-btn" data-origin="Reopen" data-text="Reopen & Comment" name="change_status" value="Reopen"/>{{else}} <input type="submit" class="btn-default btn issue-close" id="issue-close-btn" data-origin="Close" data-text="Close & Comment" name="change_status" value="Close"/>{{end}} <button class="btn-success btn" id="issue-reply-btn">Comment</button> </div> diff --git a/web.go b/web.go index 7098717a05..6aabc0e909 100644 --- a/web.go +++ b/web.go @@ -8,19 +8,16 @@ import ( "fmt" "html/template" "net/http" - "strings" "github.com/codegangsta/cli" "github.com/codegangsta/martini" "github.com/gogits/binding" - "github.com/gogits/gogs/models" "github.com/gogits/gogs/modules/auth" "github.com/gogits/gogs/modules/avatar" "github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/log" - "github.com/gogits/gogs/modules/mailer" "github.com/gogits/gogs/modules/middleware" "github.com/gogits/gogs/routers" "github.com/gogits/gogs/routers/admin" @@ -40,27 +37,6 @@ and it takes care of all the other things for you`, Flags: []cli.Flag{}, } -// globalInit is for global configuration reload-able. -func globalInit() { - base.NewConfigContext() - mailer.NewMailerContext() - models.LoadModelsConfig() - models.LoadRepoConfig() - models.NewRepoContext() - models.NewEngine() -} - -// Check run mode(Default of martini is Dev). -func checkRunMode() { - switch base.Cfg.MustValue("", "RUN_MODE") { - case "prod": - martini.Env = martini.Prod - case "test": - martini.Env = martini.Test - } - log.Info("Run Mode: %s", strings.Title(martini.Env)) -} - func newMartini() *martini.ClassicMartini { r := martini.NewRouter() m := martini.New() @@ -74,9 +50,7 @@ func newMartini() *martini.ClassicMartini { func runWeb(*cli.Context) { fmt.Println("Server is running...") - globalInit() - base.NewServices() - checkRunMode() + routers.GlobalInit() log.Info("%s %s", base.AppName, base.AppVer) m := newMartini() From 3f657607393e35c96a3519ac589778cb021b8b95 Mon Sep 17 00:00:00 2001 From: slene <vslene@gmail.com> Date: Sun, 30 Mar 2014 10:05:39 +0800 Subject: [PATCH 09/14] NewLogger set to display line number --- modules/log/log.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/log/log.go b/modules/log/log.go index e1bab8ae4a..f00675481d 100644 --- a/modules/log/log.go +++ b/modules/log/log.go @@ -15,13 +15,14 @@ var ( ) func init() { - logger = logs.NewLogger(10000) - logger.SetLogger("console", `{"level": 0}`) + NewLogger(10000, "console", `{"level": 0}`) } func NewLogger(bufLen int64, mode, config string) { Mode, Config = mode, config logger = logs.NewLogger(bufLen) + logger.EnableFuncCallDepth(true) + logger.SetLogFuncCallDepth(4) logger.SetLogger(mode, config) } From 66b697a51345bfed8cc472cb894a6edc7845397f Mon Sep 17 00:00:00 2001 From: slene <vslene@gmail.com> Date: Sun, 30 Mar 2014 10:05:54 +0800 Subject: [PATCH 10/14] add ShortSha template func --- modules/base/template.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/modules/base/template.go b/modules/base/template.go index dca76fafdc..dfcae93147 100644 --- a/modules/base/template.go +++ b/modules/base/template.go @@ -33,6 +33,13 @@ func List(l *list.List) chan interface{} { return c } +func ShortSha(sha1 string) string { + if len(sha1) == 40 { + return sha1[:10] + } + return sha1 +} + var mailDomains = map[string]string{ "gmail.com": "gmail.com", } @@ -72,4 +79,5 @@ var TemplateFuncs template.FuncMap = map[string]interface{}{ }, "DiffTypeToStr": DiffTypeToStr, "DiffLineTypeToStr": DiffLineTypeToStr, + "ShortSha": ShortSha, } From e60676aec607471ebfff3a463a7cd7050d645672 Mon Sep 17 00:00:00 2001 From: slene <vslene@gmail.com> Date: Sun, 30 Mar 2014 10:06:53 +0800 Subject: [PATCH 11/14] remove repeat routers & change commitd to branchname --- web.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/web.go b/web.go index 6aabc0e909..465d7da7aa 100644 --- a/web.go +++ b/web.go @@ -130,8 +130,8 @@ func runWeb(*cli.Context) { r.Post("/issues/:index", binding.BindIgnErr(auth.CreateIssueForm{}), repo.UpdateIssue) r.Post("/comment/:action", repo.Comment) }, reqSignIn, middleware.RepoAssignment(true)) + m.Group("/:username/:reponame", func(r martini.Router) { - r.Get("/commits/:branchname", repo.Commits) r.Get("/issues", repo.Issues) r.Get("/issues/:index", repo.ViewIssue) r.Get("/pulls", repo.Pulls) @@ -140,11 +140,10 @@ func runWeb(*cli.Context) { r.Get("/src/:branchname/**", repo.Single) r.Get("/raw/:branchname/**", repo.SingleDownload) r.Get("/commits/:branchname", repo.Commits) - r.Get("/commits/:branchname", repo.Commits) }, ignSignIn, middleware.RepoAssignment(true)) - m.Get("/:username/:reponame/commit/:commitid/**", ignSignIn, middleware.RepoAssignment(true), repo.Diff) - m.Get("/:username/:reponame/commit/:commitid", ignSignIn, middleware.RepoAssignment(true), repo.Diff) + m.Get("/:username/:reponame/commit/:branchname/**", ignSignIn, middleware.RepoAssignment(true), repo.Diff) + m.Get("/:username/:reponame/commit/:branchname", ignSignIn, middleware.RepoAssignment(true), repo.Diff) m.Group("/:username", func(r martini.Router) { r.Get("/:reponame", middleware.RepoAssignment(true), repo.Single) From 105f97e61ce3d9f2bc8ce178d0ffcbf531bd91b3 Mon Sep 17 00:00:00 2001 From: slene <vslene@gmail.com> Date: Sun, 30 Mar 2014 10:09:59 +0800 Subject: [PATCH 12/14] remove Context.IsValid & verify repo in middleware repo.go --- modules/middleware/context.go | 14 ++++++- modules/middleware/repo.go | 74 ++++++++++++++++++++++++++++------- 2 files changed, 72 insertions(+), 16 deletions(-) diff --git a/modules/middleware/context.go b/modules/middleware/context.go index d81ab999bf..a6aa58eebc 100644 --- a/modules/middleware/context.go +++ b/modules/middleware/context.go @@ -18,6 +18,7 @@ import ( "github.com/codegangsta/martini" "github.com/gogits/cache" + "github.com/gogits/git" "github.com/gogits/session" "github.com/gogits/gogs/models" @@ -41,11 +42,18 @@ type Context struct { csrfToken string Repo struct { - IsValid bool IsOwner bool IsWatching bool + IsBranch bool + IsTag bool + IsCommit bool Repository *models.Repository Owner *models.User + Commit *git.Commit + GitRepo *git.Repository + BranchName string + CommitId string + RepoLink string CloneLink struct { SSH string HTTPS string @@ -98,6 +106,10 @@ func (ctx *Context) Handle(status int, title string, err error) { ctx.HTML(status, fmt.Sprintf("status/%d", status)) } +func (ctx *Context) Debug(msg string, args ...interface{}) { + log.Debug(msg, args...) +} + func (ctx *Context) GetCookie(name string) string { cookie, err := ctx.Req.Cookie(name) if err != nil { diff --git a/modules/middleware/repo.go b/modules/middleware/repo.go index 54b735af07..d1b68b052c 100644 --- a/modules/middleware/repo.go +++ b/modules/middleware/repo.go @@ -11,6 +11,8 @@ import ( "github.com/codegangsta/martini" + "github.com/gogits/git" + "github.com/gogits/gogs/models" "github.com/gogits/gogs/modules/base" ) @@ -25,8 +27,12 @@ func RepoAssignment(redirect bool) martini.Handler { err error ) + userName := params["username"] + repoName := params["reponame"] + branchName := params["branchname"] + // get repository owner - ctx.Repo.IsOwner = ctx.IsSigned && ctx.User.LowerName == strings.ToLower(params["username"]) + ctx.Repo.IsOwner = ctx.IsSigned && ctx.User.LowerName == strings.ToLower(userName) if !ctx.Repo.IsOwner { user, err = models.GetUserByName(params["username"]) @@ -51,10 +57,8 @@ func RepoAssignment(redirect bool) martini.Handler { return } - ctx.Repo.Owner = user - // get repository - repo, err := models.GetRepositoryByName(user.Id, params["reponame"]) + repo, err := models.GetRepositoryByName(user.Id, repoName) if err != nil { if err == models.ErrRepoNotExist { ctx.Handle(404, "RepoAssignment", err) @@ -62,29 +66,69 @@ func RepoAssignment(redirect bool) martini.Handler { ctx.Redirect("/") return } - ctx.Handle(200, "RepoAssignment", err) + ctx.Handle(404, "RepoAssignment", err) return } + ctx.Repo.Repository = repo - ctx.Repo.IsValid = true - if ctx.User != nil { + gitRepo, err := git.OpenRepository(models.RepoPath(userName, repoName)) + if err != nil { + ctx.Handle(404, "RepoAssignment Invalid repo", err) + return + } + ctx.Repo.GitRepo = gitRepo + + detect: + if len(branchName) > 0 { + // TODO check tag + if models.IsBranchExist(user.Name, repoName, branchName) { + ctx.Repo.IsBranch = true + ctx.Repo.BranchName = branchName + + ctx.Repo.Commit, err = gitRepo.GetCommitOfBranch(branchName) + if err != nil { + ctx.Handle(404, "RepoAssignment invalid branch", nil) + return + } + + ctx.Repo.CommitId = ctx.Repo.Commit.Oid.String() + + } else if len(branchName) == 40 { + ctx.Repo.IsCommit = true + ctx.Repo.CommitId = branchName + ctx.Repo.BranchName = branchName + + ctx.Repo.Commit, err = gitRepo.GetCommit(branchName) + if err != nil { + ctx.Handle(404, "RepoAssignment invalid commit", nil) + return + } + } else { + ctx.Handle(404, "RepoAssignment invalid repo", nil) + return + } + + } else { + branchName = "master" + goto detect + } + + if ctx.IsSigned { ctx.Repo.IsWatching = models.IsWatching(ctx.User.Id, repo.Id) } - ctx.Repo.Repository = repo + + ctx.Repo.Owner = user ctx.Repo.CloneLink.SSH = fmt.Sprintf("%s@%s:%s/%s.git", base.RunUser, base.Domain, user.LowerName, repo.LowerName) ctx.Repo.CloneLink.HTTPS = fmt.Sprintf("%s%s/%s.git", base.AppUrl, user.LowerName, repo.LowerName) + ctx.Repo.RepoLink = "/" + user.Name + "/" + repo.Name - if len(params["branchname"]) == 0 { - params["branchname"] = "master" - } - ctx.Data["Branchname"] = params["branchname"] - - ctx.Data["IsRepositoryValid"] = true + ctx.Data["BranchName"] = ctx.Repo.BranchName + ctx.Data["CommitId"] = ctx.Repo.CommitId ctx.Data["Repository"] = repo ctx.Data["Owner"] = user ctx.Data["Title"] = user.Name + "/" + repo.Name ctx.Data["CloneLink"] = ctx.Repo.CloneLink - ctx.Data["RepositoryLink"] = ctx.Data["Title"] + ctx.Data["RepoLink"] = ctx.Repo.RepoLink ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner ctx.Data["IsRepositoryWatching"] = ctx.Repo.IsWatching } From 41ca0ed30212367389099cfefa41587ec80d85f5 Mon Sep 17 00:00:00 2001 From: slene <vslene@gmail.com> Date: Sun, 30 Mar 2014 10:12:42 +0800 Subject: [PATCH 13/14] remove ctx.Repo.IsValid --- routers/repo/issue.go | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/routers/repo/issue.go b/routers/repo/issue.go index 3506e90163..b2253e9f48 100644 --- a/routers/repo/issue.go +++ b/routers/repo/issue.go @@ -20,10 +20,6 @@ import ( ) func Issues(ctx *middleware.Context) { - if !ctx.Repo.IsValid { - ctx.Handle(404, "issue.Issues(invalid repo):", nil) - } - ctx.Data["Title"] = "Issues" ctx.Data["IsRepoToolbarIssues"] = true ctx.Data["IsRepoToolbarIssuesList"] = true @@ -80,10 +76,6 @@ func Issues(ctx *middleware.Context) { } func CreateIssue(ctx *middleware.Context, params martini.Params, form auth.CreateIssueForm) { - if !ctx.Repo.IsValid { - ctx.Handle(404, "issue.CreateIssue(invalid repo):", nil) - } - ctx.Data["Title"] = "Create issue" ctx.Data["IsRepoToolbarIssues"] = true ctx.Data["IsRepoToolbarIssuesList"] = false @@ -126,10 +118,6 @@ func CreateIssue(ctx *middleware.Context, params martini.Params, form auth.Creat } func ViewIssue(ctx *middleware.Context, params martini.Params) { - if !ctx.Repo.IsValid { - ctx.Handle(404, "issue.ViewIssue(invalid repo):", nil) - } - index, err := base.StrTo(params["index"]).Int() if err != nil { ctx.Handle(404, "issue.ViewIssue", err) @@ -183,10 +171,6 @@ func ViewIssue(ctx *middleware.Context, params martini.Params) { } func UpdateIssue(ctx *middleware.Context, params martini.Params, form auth.CreateIssueForm) { - if !ctx.Repo.IsValid { - ctx.Handle(404, "issue.UpdateIssue(invalid repo):", nil) - } - index, err := base.StrTo(params["index"]).Int() if err != nil { ctx.Handle(404, "issue.UpdateIssue", err) @@ -226,10 +210,6 @@ func UpdateIssue(ctx *middleware.Context, params martini.Params, form auth.Creat } func Comment(ctx *middleware.Context, params martini.Params) { - if !ctx.Repo.IsValid { - ctx.Handle(404, "issue.Comment(invalid repo):", nil) - } - index, err := base.StrTo(ctx.Query("issueIndex")).Int64() if err != nil { ctx.Handle(404, "issue.Comment(get index)", err) From b27c34f39acee3bf7b6594a1f0db2183b343326c Mon Sep 17 00:00:00 2001 From: slene <vslene@gmail.com> Date: Sun, 30 Mar 2014 10:13:02 +0800 Subject: [PATCH 14/14] update git api. fix link... and so on --- models/git.go | 26 ++++++++++++++----- models/repo.go | 2 +- routers/repo/branch.go | 10 ++------ routers/repo/commit.go | 18 +++++-------- routers/repo/repo.go | 51 +++++++++---------------------------- templates/issue/create.tmpl | 4 +-- templates/issue/list.tmpl | 12 ++++----- templates/issue/view.tmpl | 4 +-- templates/repo/diff.tmpl | 3 +-- templates/repo/single.tmpl | 4 +-- templates/repo/toolbar.tmpl | 20 +++++++-------- 11 files changed, 63 insertions(+), 91 deletions(-) diff --git a/models/git.go b/models/git.go index 34f0267f65..d3bad6e0ce 100644 --- a/models/git.go +++ b/models/git.go @@ -70,9 +70,12 @@ func GetTargetFile(userName, repoName, branchName, commitId, rpath string) (*Rep return nil, err } - commit, err := repo.GetCommit(branchName, commitId) + commit, err := repo.GetCommitOfBranch(branchName) if err != nil { - return nil, err + commit, err = repo.GetCommit(commitId) + if err != nil { + return nil, err + } } parts := strings.Split(path.Clean(rpath), "/") @@ -110,13 +113,22 @@ func GetTargetFile(userName, repoName, branchName, commitId, rpath string) (*Rep } // GetReposFiles returns a list of file object in given directory of repository. -func GetReposFiles(userName, repoName, branchName, commitId, rpath string) ([]*RepoFile, error) { +// func GetReposFilesOfBranch(userName, repoName, branchName, rpath string) ([]*RepoFile, error) { +// return getReposFiles(userName, repoName, commitId, rpath) +// } + +// GetReposFiles returns a list of file object in given directory of repository. +func GetReposFiles(userName, repoName, commitId, rpath string) ([]*RepoFile, error) { + return getReposFiles(userName, repoName, commitId, rpath) +} + +func getReposFiles(userName, repoName, commitId string, rpath string) ([]*RepoFile, error) { repo, err := git.OpenRepository(RepoPath(userName, repoName)) if err != nil { return nil, err } - commit, err := repo.GetCommit(branchName, commitId) + commit, err := repo.GetCommit(commitId) if err != nil { return nil, err } @@ -216,13 +228,13 @@ func GetReposFiles(userName, repoName, branchName, commitId, rpath string) ([]*R return append(repodirs, repofiles...), nil } -func GetCommit(userName, repoName, branchname, commitid string) (*git.Commit, error) { +func GetCommit(userName, repoName, commitId string) (*git.Commit, error) { repo, err := git.OpenRepository(RepoPath(userName, repoName)) if err != nil { return nil, err } - return repo.GetCommit(branchname, commitid) + return repo.GetCommit(commitId) } // GetCommitsByBranch returns all commits of given branch of repository. @@ -397,7 +409,7 @@ func GetDiff(repoPath, commitid string) (*Diff, error) { return nil, err } - commit, err := repo.GetCommit("", commitid) + commit, err := repo.GetCommit(commitid) if err != nil { return nil, err } diff --git a/models/repo.go b/models/repo.go index 0b2bbe4862..4110548362 100644 --- a/models/repo.go +++ b/models/repo.go @@ -364,7 +364,7 @@ func GetRepos(num, offset int) ([]UserRepo, error) { } func RepoPath(userName, repoName string) string { - return filepath.Join(UserPath(userName), repoName+".git") + return filepath.Join(UserPath(userName), strings.ToLower(repoName)+".git") } func UpdateRepository(repo *Repository) error { diff --git a/routers/repo/branch.go b/routers/repo/branch.go index aed77cfaa5..c598db436c 100644 --- a/routers/repo/branch.go +++ b/routers/repo/branch.go @@ -11,21 +11,15 @@ import ( ) func Branches(ctx *middleware.Context, params martini.Params) { - if !ctx.Repo.IsValid { - return - } - - brs, err := models.GetBranches(params["username"], params["reponame"]) + brs, err := models.GetBranches(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name) if err != nil { - ctx.Handle(200, "repo.Branches", err) + ctx.Handle(404, "repo.Branches", err) return } else if len(brs) == 0 { ctx.Handle(404, "repo.Branches", nil) return } - ctx.Data["Username"] = params["username"] - ctx.Data["Reponame"] = params["reponame"] ctx.Data["Branches"] = brs ctx.Data["IsRepoToolbarBranches"] = true diff --git a/routers/repo/commit.go b/routers/repo/commit.go index afc1ffda29..449f644391 100644 --- a/routers/repo/commit.go +++ b/routers/repo/commit.go @@ -50,16 +50,12 @@ func Commits(ctx *middleware.Context, params martini.Params) { } func Diff(ctx *middleware.Context, params martini.Params) { - userName := params["username"] - repoName := params["reponame"] - branchName := params["branchname"] - commitId := params["commitid"] + userName := ctx.Repo.Owner.Name + repoName := ctx.Repo.Repository.Name + branchName := ctx.Repo.BranchName + commitId := ctx.Repo.CommitId - commit, err := models.GetCommit(userName, repoName, branchName, commitId) - if err != nil { - ctx.Handle(404, "repo.Diff", err) - return - } + commit := ctx.Repo.Commit diff, err := models.GetDiff(models.RepoPath(userName, repoName), commitId) if err != nil { @@ -85,11 +81,9 @@ func Diff(ctx *middleware.Context, params martini.Params) { return isImage } - shortSha := params["commitid"][:10] ctx.Data["IsImageFile"] = isImageFile - ctx.Data["Title"] = commit.Message() + " · " + shortSha + ctx.Data["Title"] = commit.Message() + " · " + base.ShortSha(commitId) ctx.Data["Commit"] = commit - ctx.Data["ShortSha"] = shortSha ctx.Data["Diff"] = diff ctx.Data["IsRepoToolbarCommits"] = true ctx.Data["SourcePath"] = "/" + path.Join(userName, repoName, "src", commitId) diff --git a/routers/repo/repo.go b/routers/repo/repo.go index b9ac1f1c42..c9c9af1e41 100644 --- a/routers/repo/repo.go +++ b/routers/repo/repo.go @@ -53,20 +53,20 @@ func Create(ctx *middleware.Context, form auth.CreateRepoForm) { } func Single(ctx *middleware.Context, params martini.Params) { - if !ctx.Repo.IsValid { - return - } + branchName := ctx.Repo.BranchName + commitId := ctx.Repo.CommitId + userName := ctx.Repo.Owner.Name + repoName := ctx.Repo.Repository.Name - branchName := params["branchname"] - userName := params["username"] - repoName := params["reponame"] + repoLink := ctx.Repo.RepoLink + branchLink := ctx.Repo.RepoLink + "/src/" + branchName + rawLink := ctx.Repo.RepoLink + "/raw/" + branchName // Get tree path treename := params["_1"] if len(treename) > 0 && treename[len(treename)-1] == '/' { - ctx.Redirect("/" + ctx.Repo.Owner.LowerName + "/" + - ctx.Repo.Repository.Name + "/src/" + branchName + "/" + treename[:len(treename)-1]) + ctx.Redirect(repoLink + "/src/" + branchName + "/" + treename[:len(treename)-1]) return } @@ -84,23 +84,17 @@ func Single(ctx *middleware.Context, params martini.Params) { } ctx.Data["Branches"] = brs - var commitId string - isViewBranch := models.IsBranchExist(userName, repoName, branchName) - if !isViewBranch { - commitId = branchName - } + isViewBranch := ctx.Repo.IsBranch ctx.Data["IsViewBranch"] = isViewBranch repoFile, err := models.GetTargetFile(userName, repoName, branchName, commitId, treename) + if err != nil && err != models.ErrRepoFileNotExist { ctx.Handle(404, "repo.Single(GetTargetFile)", err) return } - branchLink := "/" + ctx.Repo.Owner.LowerName + "/" + ctx.Repo.Repository.Name + "/src/" + branchName - rawLink := "/" + ctx.Repo.Owner.LowerName + "/" + ctx.Repo.Repository.Name + "/raw/" + branchName - if len(treename) != 0 && repoFile == nil { ctx.Handle(404, "repo.Single", nil) return @@ -142,8 +136,7 @@ func Single(ctx *middleware.Context, params martini.Params) { } else { // Directory and file list. - files, err := models.GetReposFiles(userName, repoName, - branchName, commitId, treename) + files, err := models.GetReposFiles(userName, repoName, ctx.Repo.CommitId, treename) if err != nil { ctx.Handle(404, "repo.Single(GetReposFiles)", err) return @@ -200,18 +193,7 @@ func Single(ctx *middleware.Context, params martini.Params) { } } - // Get latest commit according username and repo name. - commit, err := models.GetCommit(userName, repoName, - branchName, commitId) - if err != nil { - log.Error("repo.Single(GetCommit): %v", err) - ctx.Handle(404, "repo.Single(GetCommit)", err) - return - } - ctx.Data["LastCommit"] = commit - - ctx.Data["CommitId"] = commitId - + ctx.Data["LastCommit"] = ctx.Repo.Commit ctx.Data["Paths"] = Paths ctx.Data["Treenames"] = treenames ctx.Data["BranchLink"] = branchLink @@ -219,11 +201,6 @@ func Single(ctx *middleware.Context, params martini.Params) { } func SingleDownload(ctx *middleware.Context, params martini.Params) { - if !ctx.Repo.IsValid { - ctx.Handle(404, "repo.SingleDownload", nil) - return - } - // Get tree path treename := params["_1"] @@ -263,10 +240,6 @@ func SingleDownload(ctx *middleware.Context, params martini.Params) { } func Http(ctx *middleware.Context, params martini.Params) { - /*if !ctx.Repo.IsValid { - return - }*/ - // TODO: access check username := params["username"] diff --git a/templates/issue/create.tmpl b/templates/issue/create.tmpl index f5cec0c05a..01784cd21e 100644 --- a/templates/issue/create.tmpl +++ b/templates/issue/create.tmpl @@ -4,7 +4,7 @@ {{template "repo/toolbar" .}} <div id="body" class="container"> <div id="issue"> - <form class="form" action="/{{.RepositoryLink}}/issues/new" method="post" id="issue-create-form"> + <form class="form" action="{{.RepoLink}}/issues/new" method="post" id="issue-create-form"> {{.CsrfTokenHtml}} <div class="col-md-1"> <img class="avatar" src="{{.SignedUser.AvatarLink}}" alt=""/> @@ -40,4 +40,4 @@ </form> </div> </div> -{{template "base/footer" .}} \ No newline at end of file +{{template "base/footer" .}} diff --git a/templates/issue/list.tmpl b/templates/issue/list.tmpl index 7622a4c172..de25b0e37f 100644 --- a/templates/issue/list.tmpl +++ b/templates/issue/list.tmpl @@ -6,24 +6,24 @@ <div id="issue"> <div class="col-md-3 filter-list"> <ul class="list-unstyled"> - <li><a href="/{{.RepositoryLink}}/issues"{{if eq .ViewType "all"}} class="active"{{end}}>All Issues <strong class="pull-right">{{.IssueCount}}</strong></a></li> + <li><a href="{{.RepoLink}}/issues"{{if eq .ViewType "all"}} class="active"{{end}}>All Issues <strong class="pull-right">{{.IssueCount}}</strong></a></li> <!-- <li><a href="#">Assigned to you</a></li> --> - <li><a href="/{{.RepositoryLink}}/issues?type=created_by"{{if eq .ViewType "created_by"}} class="active"{{end}}>Created by you <strong class="pull-right">{{.IssueCreatedCount}}</strong></a></li> + <li><a href="{{.RepoLink}}/issues?type=created_by"{{if eq .ViewType "created_by"}} class="active"{{end}}>Created by you <strong class="pull-right">{{.IssueCreatedCount}}</strong></a></li> <!-- <li><a href="#">Mentioned</a></li> --> </ul> </div> <div class="col-md-9"> <div class="filter-option"> <div class="btn-group"> - <a class="btn btn-default issue-open{{if not .IsShowClosed}} active{{end}}" href="/{{.RepositoryLink}}/issues?type={{.ViewType}}">{{.OpenCount}} Open</a> - <a class="btn btn-default issue-close{{if .IsShowClosed}} active{{end}}" href="/{{.RepositoryLink}}/issues?state=closed&type={{.ViewType}}">{{.ClosedCount}} Closed</a> + <a class="btn btn-default issue-open{{if not .IsShowClosed}} active{{end}}" href="{{.RepoLink}}/issues?type={{.ViewType}}">{{.OpenCount}} Open</a> + <a class="btn btn-default issue-close{{if .IsShowClosed}} active{{end}}" href="{{.RepoLink}}/issues?state=closed&type={{.ViewType}}">{{.ClosedCount}} Closed</a> </div> </div> <div class="issues list-group"> {{range .Issues}} <div class="list-group-item issue-item" id="issue-{{.Id}}"> <span class="number pull-right">#{{.Index}}</span> - <h5 class="title"><a href="/{{$.RepositoryLink}}/issues/{{.Index}}">{{.Name}}</a></h5> + <h5 class="title"><a href="{{$.RepoLink}}/issues/{{.Index}}">{{.Name}}</a></h5> <p class="info"> <span class="author"><img class="avatar" src="{{.Poster.AvatarLink}}" alt="" width="20"/> <a href="/user/{{.Poster.Name}}">{{.Poster.Name}}</a></span> @@ -37,4 +37,4 @@ </div> </div> </div> -{{template "base/footer" .}} \ No newline at end of file +{{template "base/footer" .}} diff --git a/templates/issue/view.tmpl b/templates/issue/view.tmpl index 91e5250ca3..df8b660769 100644 --- a/templates/issue/view.tmpl +++ b/templates/issue/view.tmpl @@ -64,7 +64,7 @@ <hr class="issue-line"/> {{if .SignedUser}}<div class="issue-child issue-reply"> <a class="user pull-left" href="/user/{{.SignedUser.Name}}"><img class="avatar" src="{{.SignedUser.AvatarLink}}" alt=""/></a> - <form class="panel panel-default issue-content" action="/{{.RepositoryLink}}/comment/new" method="post"> + <form class="panel panel-default issue-content" action="{{.RepoLink}}/comment/new" method="post"> {{.CsrfTokenHtml}} <div class="panel-body"> <div class="form-group"> @@ -102,4 +102,4 @@ </div> </div> </div> -{{template "base/footer" .}} \ No newline at end of file +{{template "base/footer" .}} diff --git a/templates/repo/diff.tmpl b/templates/repo/diff.tmpl index e58f2d664e..5c95ddefde 100644 --- a/templates/repo/diff.tmpl +++ b/templates/repo/diff.tmpl @@ -1,7 +1,6 @@ {{template "base/head" .}} {{template "base/navbar" .}} {{template "repo/nav" .}} -{{template "repo/toolbar" .}} <div id="body" class="container" data-page="repo"> <div id="source"> <div class="panel panel-info diff-box diff-head-box"> @@ -11,7 +10,7 @@ </div> <div class="panel-body"> <span class="pull-right"> - commit <span class="label label-default sha">{{.ShortSha}}</span> + commit <span class="label label-default sha">{{ShortSha .CommitId}}</span> </span> <p class="author"> <img class="avatar" src="{{AvatarLink .Commit.Author.Email}}" alt=""/> diff --git a/templates/repo/single.tmpl b/templates/repo/single.tmpl index 4c9406762c..abaa4e8936 100644 --- a/templates/repo/single.tmpl +++ b/templates/repo/single.tmpl @@ -11,11 +11,11 @@ {{ $n := len .Treenames}} {{if not .IsFile}}<button class="btn btn-default pull-right hidden"><i class="fa fa-plus-square"></i>Add File</button>{{end}} <div class="dropdown branch-switch"> - <a href="#" class="btn btn-success dropdown-toggle" data-toggle="dropdown"><i class="fa fa-chain"></i>{{if .CommitId}}{{SubStr .CommitId 0 10}}{{else}}{{.Branchname}}{{end}} + <a href="#" class="btn btn-success dropdown-toggle" data-toggle="dropdown"><i class="fa fa-chain"></i>{{if .CommitId}}{{ShortSha .CommitId}}{{else}}{{.BranchName}}{{end}} <b class="caret"></b></a> <ul class="dropdown-menu"> {{range .Branches}} - <li><a {{if eq . $.Branchname}}class="current" {{end}}href="/{{$.Username}}/{{$.Reponame}}/src/{{.}}">{{.}}</a></li> + <li><a {{if eq . $.BranchName}}class="current" {{end}}href="/{{$.Username}}/{{$.Reponame}}/src/{{.}}">{{.}}</a></li> {{end}} </ul> </div> diff --git a/templates/repo/toolbar.tmpl b/templates/repo/toolbar.tmpl index 75f1efdc8e..3c7c8a50e1 100644 --- a/templates/repo/toolbar.tmpl +++ b/templates/repo/toolbar.tmpl @@ -3,24 +3,24 @@ <nav class="navbar navbar-toolbar navbar-default" role="navigation"> <div class="collapse navbar-collapse"> <ul class="nav navbar-nav"> - <li class="{{if .IsRepoToolbarSource}}active{{end}}"><a href="/{{.RepositoryLink}}">Source</a></li> + <li class="{{if .IsRepoToolbarSource}}active{{end}}"><a href="{{.RepoLink}}{{if ne .BranchName `master`}}/src/{{.BranchName}}{{end}}">Source</a></li> {{if not .IsBareRepo}} - <li class="{{if .IsRepoToolbarCommits}}active{{end}}"><a href="/{{.RepositoryLink}}/commits/{{.Branchname}}">Commits</a></li> - <!-- <li class="{{if .IsRepoToolbarBranches}}active{{end}}"><a href="/{{.RepositoryLink}}/branches">Branches</a></li> --> - <!-- <li class="{{if .IsRepoToolbarPulls}}active{{end}}"><a href="/{{.RepositoryLink}}/pulls">Pull Requests</a></li> --> - <li class="{{if .IsRepoToolbarIssues}}active{{end}}"><a href="/{{.RepositoryLink}}/issues">Issues <!--<span class="badge">42</span>--></a></li> + <li class="{{if .IsRepoToolbarCommits}}active{{end}}"><a href="{{.RepoLink}}/commits/{{.BranchName}}">Commits</a></li> + <!-- <li class="{{if .IsRepoToolbarBranches}}active{{end}}"><a href="{{.RepoLink}}/branches">Branches</a></li> --> + <!-- <li class="{{if .IsRepoToolbarPulls}}active{{end}}"><a href="{{.RepoLink}}/pulls">Pull Requests</a></li> --> + <li class="{{if .IsRepoToolbarIssues}}active{{end}}"><a href="{{.RepoLink}}/issues">Issues <!--<span class="badge">42</span>--></a></li> {{if .IsRepoToolbarIssues}} - <li class="tmp">{{if .IsRepoToolbarIssuesList}}<a href="/{{.RepositoryLink}}/issues/new"> + <li class="tmp">{{if .IsRepoToolbarIssuesList}}<a href="{{.RepoLink}}/issues/new"> <button class="btn btn-primary btn-sm">New Issue</button> - </a>{{else}}<a href="/{{.RepositoryLink}}/issues"> + </a>{{else}}<a href="{{.RepoLink}}/issues"> <button class="btn btn-primary btn-sm">Issues List</button> </a>{{end}}</li> {{end}} <!-- <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown">More <b class="caret"></b></a> <ul class="dropdown-menu"> - <li><a href="/{{.RepositoryLink}}/release">Release</a></li> - <li><a href="//{{.RepositoryLink}}/wiki">Wiki</a></li> + <li><a href="{{.RepoLink}}/release">Release</a></li> + <li><a href="{{.RepoLink}}/wiki">Wiki</a></li> </ul> </li> -->{{end}} </ul> @@ -34,7 +34,7 @@ <li><a href="#">Network</a></li> </ul> </li> -->{{end}}{{if .IsRepositoryOwner}} - <li class="{{if .IsRepoToolbarSetting}}active{{end}}"><a href="/{{.RepositoryLink}}/settings">Settings</a> + <li class="{{if .IsRepoToolbarSetting}}active{{end}}"><a href="{{.RepoLink}}/settings">Settings</a> </li>{{end}} </ul> </div>