Browse Source

Add comment of issue

pull/40/head
Unknown 11 years ago
parent
commit
4b9eef50c9
  1. 3
      README.md
  2. 22
      models/issue.go
  3. 2
      models/models.go
  4. 68
      routers/repo/issue.go
  5. 44
      templates/issue/view.tmpl
  6. 1
      web.go

3
README.md

@ -1,3 +1,6 @@
Gogs - Go Git Service [![wercker status](https://app.wercker.com/status/ad0bdb0bc450ac6f09bc56b9640a50aa/s/ "wercker status")](https://app.wercker.com/project/bykey/ad0bdb0bc450ac6f09bc56b9640a50aa) [![Build Status](https://drone.io/github.com/gogits/gogs/status.png)](https://drone.io/github.com/gogits/gogs/latest)
=====================
Gogs(Go Git Service) is a Self Hosted Git Service in the Go Programming Language. Gogs(Go Git Service) is a Self Hosted Git Service in the Go Programming Language.
![Demo](http://gowalker.org/public/gogs_demo.gif) ![Demo](http://gowalker.org/public/gogs_demo.gif)

22
models/issue.go

@ -163,9 +163,29 @@ type Milestone struct {
type Comment struct { type Comment struct {
Id int64 Id int64
PosterId int64 PosterId int64
Poster *User `xorm:"-"`
IssueId int64 IssueId int64
CommitId int64 CommitId int64
Line int Line int64
Content string Content string
Created time.Time `xorm:"created"` Created time.Time `xorm:"created"`
} }
// CreateComment creates comment of issue or commit.
func CreateComment(userId, issueId, commitId, line int64, content string) error {
_, err := orm.Insert(&Comment{
PosterId: userId,
IssueId: issueId,
CommitId: commitId,
Line: line,
Content: content,
})
return err
}
// GetIssueComments returns list of comment by given issue id.
func GetIssueComments(issueId int64) ([]Comment, error) {
comments := make([]Comment, 0, 10)
err := orm.Asc("created").Find(&comments, &Comment{IssueId: issueId})
return comments, err
}

2
models/models.go

@ -72,7 +72,7 @@ func setEngine() {
func NewEngine() { func NewEngine() {
setEngine() setEngine()
if err := orm.Sync(new(User), new(PublicKey), new(Repository), new(Watch), if err := orm.Sync(new(User), new(PublicKey), new(Repository), new(Watch),
new(Action), new(Access), new(Issue)); err != nil { new(Action), new(Access), new(Issue), new(Comment)); err != nil {
fmt.Printf("sync database struct error: %v\n", err) fmt.Printf("sync database struct error: %v\n", err)
os.Exit(2) os.Exit(2)
} }

68
routers/repo/issue.go

@ -113,8 +113,34 @@ func ViewIssue(ctx *middleware.Context, params martini.Params) {
return return
} }
// Get posters.
u, err := models.GetUserById(issue.PosterId)
if err != nil {
ctx.Handle(200, "issue.ViewIssue(get poster): %v", err)
return
}
issue.Poster = u
// Get comments.
comments, err := models.GetIssueComments(issue.Id)
if err != nil {
ctx.Handle(200, "issue.ViewIssue(get comments): %v", err)
return
}
// Get posters.
for i := range comments {
u, err := models.GetUserById(comments[i].PosterId)
if err != nil {
ctx.Handle(200, "issue.ViewIssue(get poster): %v", err)
return
}
comments[i].Poster = u
}
ctx.Data["Title"] = issue.Name ctx.Data["Title"] = issue.Name
ctx.Data["Issue"] = issue ctx.Data["Issue"] = issue
ctx.Data["Comments"] = comments
ctx.Data["IsRepoToolbarIssues"] = true ctx.Data["IsRepoToolbarIssues"] = true
ctx.Data["IsRepoToolbarIssuesList"] = false ctx.Data["IsRepoToolbarIssuesList"] = false
ctx.HTML(200, "issue/view") ctx.HTML(200, "issue/view")
@ -132,7 +158,7 @@ func UpdateIssue(ctx *middleware.Context, params martini.Params, form auth.Creat
if err == models.ErrIssueNotExist { if err == models.ErrIssueNotExist {
ctx.Handle(404, "issue.UpdateIssue", err) ctx.Handle(404, "issue.UpdateIssue", err)
} else { } else {
ctx.Handle(200, "issue.UpdateIssue", err) ctx.Handle(200, "issue.UpdateIssue(get issue)", err)
} }
return return
} }
@ -148,10 +174,48 @@ func UpdateIssue(ctx *middleware.Context, params martini.Params, form auth.Creat
issue.Labels = form.Labels issue.Labels = form.Labels
issue.Content = form.Content issue.Content = form.Content
if err = models.UpdateIssue(issue); err != nil { if err = models.UpdateIssue(issue); err != nil {
ctx.Handle(200, "issue.UpdateIssue", err) ctx.Handle(200, "issue.UpdateIssue(update issue)", err)
return return
} }
ctx.Data["Title"] = issue.Name ctx.Data["Title"] = issue.Name
ctx.Data["Issue"] = issue ctx.Data["Issue"] = issue
} }
func Comment(ctx *middleware.Context, params martini.Params) {
index, err := base.StrTo(ctx.Query("issueIndex")).Int()
if err != nil {
ctx.Handle(404, "issue.Comment", err)
return
}
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, int64(index))
if err != nil {
if err == models.ErrIssueNotExist {
ctx.Handle(404, "issue.Comment", err)
} else {
ctx.Handle(200, "issue.Comment(get issue)", err)
}
return
}
content := ctx.Query("content")
if len(content) == 0 {
ctx.Handle(404, "issue.Comment", err)
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)
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))
}

44
templates/issue/view.tmpl

@ -6,52 +6,39 @@
<div id="issue"> <div id="issue">
<div id="issue-id" class="issue-whole"> <div id="issue-id" class="issue-whole">
<div class="issue-head clearfix"> <div class="issue-head clearfix">
<div class="number pull-right">#448</div> <div class="number pull-right">#{{.Issue.Index}}</div>
<span class="author pull-left"><img class="avatar" src="#" alt="" width="30"/></span> <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">[Request]关于context中的Download方法</h1> <h1 class="title pull-left">{{.Issue.Name}}</h1>
<p class="info pull-left"> <p class="info pull-left">
<span class="status label label-success">Open</span> <span class="status label label-{{if .Issue.IsClosed}}danger{{else}}success{{end}}">{{if .Issue.IsClosed}}Closed{{else}}Open{{end}}</span>
<a href="#" class="author"><strong>linbaozhong</strong></a> opened this issue <a href="/user/{{.Issue.Poster.Name}}" class="author"><strong>{{.Issue.Poster.Name}}</strong></a> opened this issue
<span class="time">2 months ago</span> · 1 comment <span class="time">{{TimeSince .Issue.Created}}</span> · {{.Issue.NumComments}} comments
</p> </p>
</div> </div>
<div class="issue-main"> <div class="issue-main">
<div class="panel panel-default issue-content"> <div class="panel panel-default issue-content">
<div class="panel-body markdown"> <div class="panel-body markdown">
<p>context中的Download方法:</p> <p>{{.Issue.Content}}</p>
<p>func (output *BeegoOutput) Download(file string)</p>
<p>建议在file参数后面增加一个可选参数filename.</p>
<p>如果filename不存在或为空,output.Header("Content-Disposition", "attachment; filename="+filepath.Base(file))</p>
<p>如果filename不为空,output.Header("Content-Disposition", "attachment; filename="+filename)</p>
<p>因为有时候,多数情况下,要下载的真实的文件名与显示和保存的本地的文件名是不一样的,希望显示的文件名更友好些</p>
</div> </div>
</div> </div>
{{range .Comments}}
<div class="issue-child"> <div class="issue-child">
<a class="user pull-left" href="#"><img class="avatar" src="#" alt=""/></a> <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="issue-content panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<a href="#" class="user">phpqinsir</a> commented <span class="time">3 days ago</span> <a href="/user/{{.Poster.Name}}" class="user">{{.Poster.Name}}</a> commented <span class="time">{{TimeSince .Created}}</span>
</div> </div>
<div class="panel-body markdown"> <div class="panel-body markdown">
<p>@slene 看来也只能这样了。最主要是数组与切片的用法,我感觉不科学。因为要知道个数,然后个数与问号个数要对应。不能像PHP YII框架那样,直接传入一个数组,自己在里面把参数组装成1,2,3,4这种格式。希望,Beego框架能加上。那就太完美了。谢谢。</p> <p>{{.Content}}</p>
</div>
</div>
</div>
<div class="issue-child">
<a class="user pull-left" href="#"><img class="avatar" src="#" alt=""/></a>
<div class="issue-content panel panel-default">
<div class="panel-heading">
<a href="#" class="user">phpqinsir</a> commented <span class="time">3 days ago</span>
</div>
<div class="panel-body markdown">
<p>@slene 看来也只能这样了。最主要是数组与切片的用法,我感觉不科学。因为要知道个数,然后个数与问号个数要对应。不能像PHP YII框架那样,直接传入一个数组,自己在里面把参数组装成1,2,3,4这种格式。希望,Beego框架能加上。那就太完美了。谢谢。</p>
</div> </div>
</div> </div>
</div> </div>
{{end}}
<hr class="issue-line"/> <hr class="issue-line"/>
<div class="issue-child issue-reply"> <div class="issue-child issue-reply">
<a class="user pull-left" href="#"><img class="avatar" src="#" alt=""/></a> <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=""> <form class="panel panel-default issue-content" action="/{{.RepositoryLink}}/comment/new" method="post">
{{.CsrfTokenHtml}}
<div class="panel-body"> <div class="panel-body">
<div class="form-group"> <div class="form-group">
<div class="md-help pull-right"><!-- todo help link --> <div class="md-help pull-right"><!-- todo help link -->
@ -64,6 +51,7 @@
<div class="tab-content"> <div class="tab-content">
<div class="tab-pane" id="issue-textarea"> <div class="tab-pane" id="issue-textarea">
<div class="form-group"> <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">{{.content}}</textarea> <textarea class="form-control" name="content" id="issue-content" rows="10" placeholder="Write some content">{{.content}}</textarea>
</div> </div>
</div> </div>

1
web.go

@ -144,6 +144,7 @@ func runWeb(*cli.Context) {
r.Get("/action/:action", repo.Action) r.Get("/action/:action", repo.Action)
r.Any("/issues/new", binding.BindIgnErr(auth.CreateIssueForm{}), repo.CreateIssue) r.Any("/issues/new", binding.BindIgnErr(auth.CreateIssueForm{}), repo.CreateIssue)
r.Post("/issues/:index", binding.BindIgnErr(auth.CreateIssueForm{}), repo.UpdateIssue) r.Post("/issues/:index", binding.BindIgnErr(auth.CreateIssueForm{}), repo.UpdateIssue)
r.Post("/comment/:action", repo.Comment)
}, reqSignIn, middleware.RepoAssignment(true)) }, reqSignIn, middleware.RepoAssignment(true))
m.Group("/:username/:reponame", func(r martini.Router) { m.Group("/:username/:reponame", func(r martini.Router) {
r.Get("/commits/:branchname", repo.Commits) r.Get("/commits/:branchname", repo.Commits)

Loading…
Cancel
Save