@@ -419,8 +419,8 @@ func runWeb(ctx *cli.Context) { | |||
m.Get("/action/:action", repo.Action) | |||
m.Group("/issues", func() { | |||
m.Get("/new", repo.CreateIssue) | |||
m.Post("/new", bindIgnErr(auth.CreateIssueForm{}), repo.CreateIssuePost) | |||
m.Combo("/new").Get(repo.NewIssue). | |||
Post(bindIgnErr(auth.CreateIssueForm{}), repo.NewIssuePost) | |||
m.Post("/:index", bindIgnErr(auth.CreateIssueForm{}), repo.UpdateIssue) | |||
m.Post("/:index/label", repo.UpdateIssueLabel) | |||
m.Post("/:index/milestone", repo.UpdateIssueMilestone) |
@@ -367,6 +367,7 @@ commits.older = Older | |||
commits.newer = Newer | |||
issues.new = New Issue | |||
issues.create = Create Issue | |||
issues.new_label = New Label | |||
issues.new_label_placeholder = Label name... | |||
issues.open_tab = %d Open |
@@ -388,6 +388,26 @@ | |||
"strictMath": 0, | |||
"strictUnits": 0 | |||
}, | |||
"\/public\/less\/_markdown.less": { | |||
"allowInsecureImports": 0, | |||
"createSourceMap": 0, | |||
"disableJavascript": 0, | |||
"fileType": 1, | |||
"ieCompatibility": 1, | |||
"ignore": 1, | |||
"ignoreWasSetByUser": 0, | |||
"inputAbbreviatedPath": "\/public\/less\/_markdown.less", | |||
"outputAbbreviatedPath": "\/public\/css\/_markdown.css", | |||
"outputPathIsOutsideProject": 0, | |||
"outputPathIsSetByUser": 0, | |||
"outputStyle": 0, | |||
"relativeURLS": 0, | |||
"shouldRunAutoprefixer": 0, | |||
"shouldRunBless": 0, | |||
"strictImports": 0, | |||
"strictMath": 0, | |||
"strictUnits": 0 | |||
}, | |||
"\/public\/less\/_octicons.less": { | |||
"allowInsecureImports": 0, | |||
"createSourceMap": 0, |
@@ -17,7 +17,7 @@ import ( | |||
"github.com/gogits/gogs/modules/setting" | |||
) | |||
const APP_VER = "0.6.4.0808 Beta" | |||
const APP_VER = "0.6.4.0809 Beta" | |||
func init() { | |||
runtime.GOMAXPROCS(runtime.NumCPU()) |
@@ -38,7 +38,7 @@ type Issue struct { | |||
Repo *Repository `xorm:"-"` | |||
PosterID int64 | |||
Poster *User `xorm:"-"` | |||
LabelIds string `xorm:"TEXT"` | |||
LabelIDs string `xorm:"label_ids TEXT"` | |||
Labels []*Label `xorm:"-"` | |||
MilestoneID int64 | |||
Milestone *Milestone `xorm:"-"` | |||
@@ -77,11 +77,11 @@ func (i *Issue) GetPoster() (err error) { | |||
} | |||
func (i *Issue) GetLabels() error { | |||
if len(i.LabelIds) < 3 { | |||
if len(i.LabelIDs) < 3 { | |||
return nil | |||
} | |||
strIds := strings.Split(strings.TrimSuffix(i.LabelIds[1:], "|"), "|$") | |||
strIds := strings.Split(strings.TrimSuffix(i.LabelIDs[1:], "|"), "|$") | |||
i.Labels = make([]*Label, 0, len(strIds)) | |||
for _, strId := range strIds { | |||
id := com.StrTo(strId).MustInt64() | |||
@@ -134,7 +134,7 @@ func NewIssue(issue *Issue) (err error) { | |||
if _, err = sess.Insert(issue); err != nil { | |||
return err | |||
} else if _, err = sess.Exec("UPDATE `repository` SET num_issues = num_issues + 1 WHERE id = ?", issue.RepoID); err != nil { | |||
} else if _, err = sess.Exec("UPDATE `repository` SET num_issues=num_issues+1 WHERE id=?", issue.RepoID); err != nil { | |||
return err | |||
} | |||
@@ -296,14 +296,14 @@ type IssueUser struct { | |||
// FIXME: organization | |||
// NewIssueUserPairs adds new issue-user pairs for new issue of repository. | |||
func NewIssueUserPairs(repo *Repository, issueID, orgID, posterID, assigneeID int64) error { | |||
func NewIssueUserPairs(repo *Repository, issue *Issue) error { | |||
users, err := repo.GetCollaborators() | |||
if err != nil { | |||
return err | |||
} | |||
iu := &IssueUser{ | |||
IssueId: issueID, | |||
IssueId: issue.ID, | |||
RepoId: repo.ID, | |||
} | |||
@@ -311,30 +311,30 @@ func NewIssueUserPairs(repo *Repository, issueID, orgID, posterID, assigneeID in | |||
for _, u := range users { | |||
iu.Id = 0 | |||
iu.Uid = u.Id | |||
iu.IsPoster = iu.Uid == posterID | |||
iu.IsPoster = iu.Uid == issue.PosterID | |||
if isNeedAddPoster && iu.IsPoster { | |||
isNeedAddPoster = false | |||
} | |||
iu.IsAssigned = iu.Uid == assigneeID | |||
iu.IsAssigned = iu.Uid == issue.AssigneeID | |||
if _, err = x.Insert(iu); err != nil { | |||
return err | |||
} | |||
} | |||
if isNeedAddPoster { | |||
iu.Id = 0 | |||
iu.Uid = posterID | |||
iu.Uid = issue.PosterID | |||
iu.IsPoster = true | |||
iu.IsAssigned = iu.Uid == assigneeID | |||
iu.IsAssigned = iu.Uid == issue.AssigneeID | |||
if _, err = x.Insert(iu); err != nil { | |||
return err | |||
} | |||
} | |||
// Add owner's as well. | |||
if repo.OwnerID != posterID { | |||
if repo.OwnerID != issue.PosterID { | |||
iu.Id = 0 | |||
iu.Uid = repo.OwnerID | |||
iu.IsAssigned = iu.Uid == assigneeID | |||
iu.IsAssigned = iu.Uid == issue.AssigneeID | |||
if _, err = x.Insert(iu); err != nil { | |||
return err | |||
} | |||
@@ -621,7 +621,7 @@ func DeleteLabel(repoID, labelID int64) error { | |||
} | |||
for _, issue := range issues { | |||
issue.LabelIds = strings.Replace(issue.LabelIds, "$"+com.ToStr(labelID)+"|", "", -1) | |||
issue.LabelIDs = strings.Replace(issue.LabelIDs, "$"+com.ToStr(labelID)+"|", "", -1) | |||
if _, err = sess.Id(issue.ID).AllCols().Update(issue); err != nil { | |||
return err | |||
} |
@@ -14,9 +14,9 @@ import ( | |||
) | |||
type MarkdownForm struct { | |||
Text string `form:"text"` | |||
Mode string `form:"mode"` | |||
Context string `form:"context"` | |||
Text string | |||
Mode string | |||
Context string | |||
} | |||
func (f *MarkdownForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { |
@@ -98,11 +98,11 @@ func (f *NewSlackHookForm) Validate(ctx *macaron.Context, errs binding.Errors) b | |||
// \/ \/ \/ | |||
type CreateIssueForm struct { | |||
IssueName string `form:"title" binding:"Required;MaxSize(255)"` | |||
MilestoneId int64 `form:"milestoneid"` | |||
AssigneeId int64 `form:"assigneeid"` | |||
Labels string `form:"labels"` | |||
Content string `form:"content"` | |||
Title string `binding:"Required;MaxSize(255)"` | |||
LabelIDs []int64 `form:"label_id"` | |||
MilestoneID int64 | |||
AssigneeID int64 | |||
Content string | |||
} | |||
func (f *CreateIssueForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { |
@@ -123,6 +123,26 @@ $(document).ready(function () { | |||
}); | |||
$('.poping.up').popup(); | |||
// Comment form | |||
$('.comment.form .tabular.menu .item').tab(); | |||
$('.comment.form .tabular.menu .item[data-tab="preview"]').click(function () { | |||
var $this = $(this); | |||
console.log($('.comment.form .tab.segment[data-tab="write"] textarea').val()) | |||
console.log($('.comment.form .tab.segment[data-tab="preview"]').html()) | |||
$.post($this.data('url'), { | |||
"_csrf": csrf, | |||
"mode": "gfm", | |||
"context": $this.data('context'), | |||
"text": $('.comment.form .tab.segment[data-tab="write"] textarea').val() | |||
}, | |||
function (data) { | |||
console.log(data) | |||
$('.comment.form .tab.segment[data-tab="preview"]').html(data); | |||
} | |||
) | |||
; | |||
}) | |||
// Helpers. | |||
$('.delete-button').click(function () { | |||
var $this = $(this); |
@@ -0,0 +1,594 @@ | |||
.markdown { | |||
overflow:hidden; | |||
font-family:"Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; | |||
font-size:16px; | |||
line-height:1.6; | |||
word-wrap:break-word; | |||
>*:first-child { | |||
margin-top:0 !important; | |||
} | |||
>*:last-child { | |||
margin-bottom:0 !important; | |||
} | |||
a:not([href]) { | |||
color:inherit; | |||
text-decoration:none; | |||
} | |||
.absent { | |||
color:#c00; | |||
} | |||
.anchor { | |||
position:absolute; | |||
top:0; | |||
left:0; | |||
display:block; | |||
padding-right:6px; | |||
padding-left:30px; | |||
margin-left:-30px; | |||
} | |||
.anchor:focus { | |||
outline:none; | |||
} | |||
h1, | |||
h2, | |||
h3, | |||
h4, | |||
h5, | |||
h6 { | |||
position:relative; | |||
margin-top:1em; | |||
margin-bottom:16px; | |||
font-weight:bold; | |||
line-height:1.4; | |||
} | |||
h1 .octicon-link, | |||
h2 .octicon-link, | |||
h3 .octicon-link, | |||
h4 .octicon-link, | |||
h5 .octicon-link, | |||
h6 .octicon-link { | |||
display:none; | |||
color:#000; | |||
vertical-align:middle; | |||
} | |||
h1:hover .anchor, | |||
h2:hover .anchor, | |||
h3:hover .anchor, | |||
h4:hover .anchor, | |||
h5:hover .anchor, | |||
h6:hover .anchor { | |||
padding-left:8px; | |||
margin-left:-30px; | |||
text-decoration:none; | |||
} | |||
h1:hover .anchor .octicon-link, | |||
h2:hover .anchor .octicon-link, | |||
h3:hover .anchor .octicon-link, | |||
h4:hover .anchor .octicon-link, | |||
h5:hover .anchor .octicon-link, | |||
h6:hover .anchor .octicon-link { | |||
display:inline-block; | |||
} | |||
h1 tt, | |||
h1 code, | |||
h2 tt, | |||
h2 code, | |||
h3 tt, | |||
h3 code, | |||
h4 tt, | |||
h4 code, | |||
h5 tt, | |||
h5 code, | |||
h6 tt, | |||
h6 code { | |||
font-size:inherit; | |||
} | |||
h1 { | |||
padding-bottom:0.3em; | |||
font-size:2.25em; | |||
line-height:1.2; | |||
border-bottom:1px solid #eee; | |||
} | |||
h1 .anchor { | |||
line-height:1; | |||
} | |||
h2 { | |||
padding-bottom:0.3em; | |||
font-size:1.75em; | |||
line-height:1.225; | |||
border-bottom:1px solid #eee; | |||
} | |||
h2 .anchor { | |||
line-height:1; | |||
} | |||
h3 { | |||
font-size:1.5em; | |||
line-height:1.43; | |||
} | |||
h3 .anchor { | |||
line-height:1.2; | |||
} | |||
h4 { | |||
font-size:1.25em; | |||
} | |||
h4 .anchor { | |||
line-height:1.2; | |||
} | |||
h5 { | |||
font-size:1em; | |||
} | |||
h5 .anchor { | |||
line-height:1.1; | |||
} | |||
h6 { | |||
font-size:1em;color:#777; | |||
} | |||
h6 .anchor { | |||
line-height:1.1; | |||
} | |||
p, | |||
blockquote, | |||
ul, | |||
ol, | |||
dl, | |||
table, | |||
pre { | |||
margin-top:0; | |||
margin-bottom:16px; | |||
} | |||
hr { | |||
height:4px; | |||
padding:0; | |||
margin:16px 0; | |||
background-color:#e7e7e7; | |||
border:0 none; | |||
} | |||
ul, | |||
ol { | |||
padding-left:2em; | |||
} | |||
ul.no-list, | |||
ol.no-list { | |||
padding:0; | |||
list-style-type:none; | |||
} | |||
ul ul, | |||
ul ol, | |||
ol ol, | |||
ol ul { | |||
margin-top:0; | |||
margin-bottom:0; | |||
} | |||
ol ol, | |||
ul ol { | |||
list-style-type: lower-roman; | |||
} | |||
li>p { | |||
margin-top:16px; | |||
} | |||
dl { | |||
padding:0; | |||
} | |||
dl dt { | |||
padding:0; | |||
margin-top:16px; | |||
font-size:1em; | |||
font-style:italic; | |||
font-weight:bold; | |||
} | |||
dl dd { | |||
padding:0 16px; | |||
margin-bottom:16px; | |||
} | |||
blockquote { | |||
padding:0 15px; | |||
color:#777; | |||
border-left:4px solid #ddd; | |||
} | |||
blockquote>:first-child { | |||
margin-top:0; | |||
} | |||
blockquote>:last-child { | |||
margin-bottom:0; | |||
} | |||
table { | |||
display:block; | |||
width:100%; | |||
overflow:auto; | |||
word-break:normal; | |||
word-break:keep-all; | |||
} | |||
table th { | |||
font-weight:bold; | |||
} | |||
table th, | |||
table td { | |||
padding:6px 13px !important; | |||
border:1px solid #ddd; | |||
} | |||
table tr { | |||
background-color:#fff; | |||
border-top:1px solid #ccc; | |||
} | |||
table tr:nth-child(2n) { | |||
background-color:#f8f8f8; | |||
} | |||
img { | |||
max-width:100%; | |||
box-sizing:border-box; | |||
} | |||
.emoji { | |||
max-width:none; | |||
} | |||
span.frame { | |||
display:block; | |||
overflow:hidden; | |||
} | |||
span.frame>span { | |||
display:block; | |||
float:left; | |||
width:auto; | |||
padding:7px; | |||
margin:13px 0 0; | |||
overflow:hidden; | |||
border:1px solid #ddd; | |||
} | |||
span.frame span img { | |||
display:block; | |||
float:left; | |||
} | |||
span.frame span span { | |||
display:block; | |||
padding:5px 0 0; | |||
clear:both; | |||
color:#333; | |||
} | |||
span.align-center { | |||
display:block; | |||
overflow:hidden; | |||
clear:both; | |||
} | |||
span.align-center>span { | |||
display:block; | |||
margin:13px auto 0; | |||
overflow:hidden; | |||
text-align:center; | |||
} | |||
span.align-center span img { | |||
margin:0 auto; | |||
text-align:center; | |||
} | |||
span.align-right { | |||
display:block; | |||
overflow:hidden; | |||
clear:both; | |||
} | |||
span.align-right>span { | |||
display:block; | |||
margin:13px 0 0; | |||
overflow:hidden; | |||
text-align:right; | |||
} | |||
span.align-right span img { | |||
margin:0; | |||
text-align:right; | |||
} | |||
span.float-left { | |||
display:block; | |||
float:left; | |||
margin-right:13px; | |||
overflow:hidden; | |||
} | |||
span.float-left span { | |||
margin:13px 0 0; | |||
} | |||
span.float-right { | |||
display:block; | |||
float:right; | |||
margin-left:13px; | |||
overflow:hidden; | |||
} | |||
span.float-right>span { | |||
display:block; | |||
margin:13px auto 0; | |||
overflow:hidden; | |||
text-align:right; | |||
} | |||
code, | |||
tt { | |||
padding:0; | |||
padding-top:0.2em; | |||
padding-bottom:0.2em; | |||
margin:0; | |||
font-size:85%; | |||
background-color:rgba(0,0,0,0.04); | |||
border-radius:3px; | |||
} | |||
code:before, | |||
code:after, | |||
tt:before, | |||
tt:after { | |||
letter-spacing:-0.2em; | |||
content:"\00a0"; | |||
} | |||
code br, | |||
tt br { | |||
display:none; | |||
} | |||
del code { | |||
text-decoration:inherit; | |||
} | |||
pre>code { | |||
padding:0; | |||
margin:0; | |||
font-size:100%; | |||
word-break:normal; | |||
white-space:pre; | |||
background:transparent; | |||
border:0; | |||
} | |||
.highlight { | |||
margin-bottom:16px; | |||
} | |||
.highlight pre, | |||
pre { | |||
padding:16px; | |||
overflow:auto; | |||
font-size:85%; | |||
line-height:1.45; | |||
background-color:#f7f7f7; | |||
border-radius:3px; | |||
} | |||
.highlight pre { | |||
margin-bottom:0; | |||
word-break:normal; | |||
} | |||
pre { | |||
word-wrap:normal; | |||
} | |||
pre code, | |||
pre tt { | |||
display:inline; | |||
max-width:initial; | |||
padding:0; | |||
margin:0; | |||
overflow:initial; | |||
line-height:inherit; | |||
word-wrap:normal; | |||
background-color:transparent; | |||
border:0; | |||
} | |||
pre code:before, | |||
pre code:after, | |||
pre tt:before, | |||
pre tt:after { | |||
content:normal; | |||
} | |||
kbd { | |||
display:inline-block; | |||
padding:3px 5px; | |||
font-size:11px; | |||
line-height:10px; | |||
color:#555; | |||
vertical-align:middle; | |||
background-color:#fcfcfc; | |||
border:solid 1px #ccc; | |||
border-bottom-color:#bbb; | |||
border-radius:3px; | |||
box-shadow:inset 0 -1px 0 #bbb; | |||
} | |||
.csv-data td, | |||
.csv-data th { | |||
padding:5px; | |||
overflow:hidden; | |||
font-size:12px; | |||
line-height:1; | |||
text-align:left; | |||
white-space:nowrap; | |||
} | |||
.csv-data .blob-num { | |||
padding:10px 8px 9px; | |||
text-align:right; | |||
background:#fff;border:0; | |||
} | |||
.csv-data tr { | |||
border-top:0; | |||
} | |||
.csv-data th { | |||
font-weight:bold; | |||
background:#f8f8f8;border-top:0; | |||
} | |||
} | |||
/* Author: jmblog */ | |||
/* Project: https://github.com/jmblog/color-themes-for-google-code-prettify */ | |||
/* GitHub Theme */ | |||
/* Pretty printing styles. Used with prettify.js. */ | |||
/* SPAN elements with the classes below are added by prettyprint. */ | |||
/* plain text */ | |||
.pln { | |||
color: #333333; | |||
} | |||
@media screen { | |||
/* string content */ | |||
.str { | |||
color: #dd1144; | |||
} | |||
/* a keyword */ | |||
.kwd { | |||
color: #333333; | |||
} | |||
/* a comment */ | |||
.com { | |||
color: #999988; | |||
font-style: italic; | |||
} | |||
/* a type name */ | |||
.typ { | |||
color: #445588; | |||
} | |||
/* a literal value */ | |||
.lit { | |||
color: #445588; | |||
} | |||
/* punctuation */ | |||
.pun { | |||
color: #333333; | |||
} | |||
/* lisp open bracket */ | |||
.opn { | |||
color: #333333; | |||
} | |||
/* lisp close bracket */ | |||
.clo { | |||
color: #333333; | |||
} | |||
/* a markup tag name */ | |||
.tag { | |||
color: navy; | |||
} | |||
/* a markup attribute name */ | |||
.atn { | |||
color: teal; | |||
} | |||
/* a markup attribute value */ | |||
.atv { | |||
color: #dd1144; | |||
} | |||
/* a declaration */ | |||
.dec { | |||
color: #333333; | |||
} | |||
/* a variable name */ | |||
.var { | |||
color: teal; | |||
} | |||
/* a function name */ | |||
.fun { | |||
color: #990000; | |||
} | |||
} | |||
/* Use higher contrast and text-weight for printable form. */ | |||
@media print, | |||
projection { | |||
.str { | |||
color: #006600; | |||
} | |||
.kwd { | |||
color: #006; | |||
font-weight: bold; | |||
} | |||
.com { | |||
color: #600; | |||
font-style: italic; | |||
} | |||
.typ { | |||
color: #404; | |||
font-weight: bold; | |||
} | |||
.lit { | |||
color: #004444; | |||
} | |||
.pun, | |||
.opn, | |||
.clo { | |||
color: #444400; | |||
} | |||
.tag { | |||
color: #006; | |||
font-weight: bold; | |||
} | |||
.atn { | |||
color: #440044; | |||
} | |||
.atv { | |||
color: #006600; | |||
} | |||
} | |||
/* Specify class=linenums on a pre to get line numbering */ | |||
ol.linenums { | |||
margin-top: 0; | |||
margin-bottom: 0; | |||
} |
@@ -105,6 +105,7 @@ | |||
.page.buttons { | |||
padding-top: 15px; | |||
} | |||
.issue.list { | |||
clear: both; | |||
list-style: none; | |||
@@ -138,6 +139,32 @@ | |||
} | |||
} | |||
} | |||
&.new.issue { | |||
.comment.form { | |||
.metas { | |||
min-width: 220px; | |||
} | |||
} | |||
} | |||
.comment.form { | |||
.ui.comments { | |||
margin-top: -12px; | |||
max-width: 750px!important; | |||
} | |||
.content { | |||
.field:first-child { | |||
clear: none; | |||
} | |||
.tab.segment { | |||
border: none; | |||
padding: 0; | |||
padding-top: 10px; | |||
} | |||
textarea { | |||
height: 200px; | |||
} | |||
} | |||
} | |||
.label.list { | |||
clear: both; |
@@ -1,5 +1,6 @@ | |||
@import "_octicons"; | |||
@import "_base"; | |||
@import "_markdown"; | |||
@import "_home"; | |||
@import "_install"; | |||
@import "_form"; |
@@ -27,9 +27,9 @@ import ( | |||
) | |||
const ( | |||
ISSUES base.TplName = "repo/issue/list" | |||
ISSUE_CREATE base.TplName = "repo/issue/create" | |||
ISSUE_VIEW base.TplName = "repo/issue/view" | |||
ISSUES base.TplName = "repo/issue/list" | |||
ISSUE_NEW base.TplName = "repo/issue/new" | |||
ISSUE_VIEW base.TplName = "repo/issue/view" | |||
LABELS base.TplName = "repo/issue/labels" | |||
@@ -174,167 +174,198 @@ func Issues(ctx *middleware.Context) { | |||
ctx.HTML(200, ISSUES) | |||
} | |||
func CreateIssue(ctx *middleware.Context) { | |||
ctx.Data["Title"] = "Create issue" | |||
ctx.Data["IsRepoToolbarIssues"] = true | |||
ctx.Data["IsRepoToolbarIssuesList"] = false | |||
ctx.Data["AttachmentsEnabled"] = setting.AttachmentEnabled | |||
var ( | |||
repo = ctx.Repo.Repository | |||
err error | |||
) | |||
// Get all milestones. | |||
ctx.Data["OpenMilestones"], err = models.GetMilestones(repo.ID, -1, false) | |||
if err != nil { | |||
ctx.Handle(500, "GetMilestones.1: %v", err) | |||
return | |||
} | |||
ctx.Data["ClosedMilestones"], err = models.GetMilestones(repo.ID, -1, true) | |||
if err != nil { | |||
ctx.Handle(500, "GetMilestones.2: %v", err) | |||
return | |||
} | |||
us, err := repo.GetCollaborators() | |||
if err != nil { | |||
ctx.Handle(500, "GetCollaborators", err) | |||
return | |||
} | |||
ctx.Data["AllowedTypes"] = setting.AttachmentAllowedTypes | |||
ctx.Data["Collaborators"] = us | |||
ctx.HTML(200, ISSUE_CREATE) | |||
func NewIssue(ctx *middleware.Context) { | |||
ctx.Data["Title"] = ctx.Tr("repo.issues.new") | |||
ctx.Data["PageIsIssueList"] = true | |||
ctx.Data["IsAttachmentEnabled"] = setting.AttachmentEnabled | |||
ctx.Data["AttachmentAllowedTypes"] = setting.AttachmentAllowedTypes | |||
// var ( | |||
// repo = ctx.Repo.Repository | |||
// err error | |||
// ) | |||
// // Get all milestones. | |||
// ctx.Data["OpenMilestones"], err = models.GetMilestones(repo.ID, -1, false) | |||
// if err != nil { | |||
// ctx.Handle(500, "GetMilestones.1: %v", err) | |||
// return | |||
// } | |||
// ctx.Data["ClosedMilestones"], err = models.GetMilestones(repo.ID, -1, true) | |||
// if err != nil { | |||
// ctx.Handle(500, "GetMilestones.2: %v", err) | |||
// return | |||
// } | |||
// us, err := repo.GetCollaborators() | |||
// if err != nil { | |||
// ctx.Handle(500, "GetCollaborators", err) | |||
// return | |||
// } | |||
// ctx.Data["Collaborators"] = us | |||
ctx.HTML(200, ISSUE_NEW) | |||
} | |||
func CreateIssuePost(ctx *middleware.Context, form auth.CreateIssueForm) { | |||
send := func(status int, data interface{}, err error) { | |||
if err != nil { | |||
log.Error(4, "issue.CreateIssuePost(?): %s", err) | |||
ctx.JSON(status, map[string]interface{}{ | |||
"ok": false, | |||
"status": status, | |||
"error": err.Error(), | |||
}) | |||
} else { | |||
ctx.JSON(status, map[string]interface{}{ | |||
"ok": true, | |||
"status": status, | |||
"data": data, | |||
}) | |||
} | |||
} | |||
var err error | |||
// Get all milestones. | |||
_, err = models.GetMilestones(ctx.Repo.Repository.ID, -1, false) | |||
if err != nil { | |||
send(500, nil, err) | |||
return | |||
} | |||
_, err = models.GetMilestones(ctx.Repo.Repository.ID, -1, true) | |||
if err != nil { | |||
send(500, nil, err) | |||
return | |||
} | |||
_, err = ctx.Repo.Repository.GetCollaborators() | |||
if err != nil { | |||
send(500, nil, err) | |||
return | |||
} | |||
func NewIssuePost(ctx *middleware.Context, form auth.CreateIssueForm) { | |||
ctx.Data["Title"] = ctx.Tr("repo.issues.new") | |||
ctx.Data["PageIsIssueList"] = true | |||
ctx.Data["IsAttachmentEnabled"] = setting.AttachmentEnabled | |||
ctx.Data["AttachmentAllowedTypes"] = setting.AttachmentAllowedTypes | |||
if ctx.HasError() { | |||
send(400, nil, errors.New(ctx.Flash.ErrorMsg)) | |||
ctx.HTML(200, ISSUE_NEW) | |||
return | |||
} | |||
// Only collaborators can assign. | |||
if !ctx.Repo.IsOwner() { | |||
form.AssigneeId = 0 | |||
} | |||
issue := &models.Issue{ | |||
RepoID: ctx.Repo.Repository.ID, | |||
Index: int64(ctx.Repo.Repository.NumIssues) + 1, | |||
Name: form.IssueName, | |||
PosterID: ctx.User.Id, | |||
MilestoneID: form.MilestoneId, | |||
AssigneeID: form.AssigneeId, | |||
LabelIds: form.Labels, | |||
Content: form.Content, | |||
RepoID: ctx.Repo.Repository.ID, | |||
Index: int64(ctx.Repo.Repository.NumIssues) + 1, | |||
Name: form.Title, | |||
PosterID: ctx.User.Id, | |||
// MilestoneID: form.MilestoneID, | |||
// AssigneeID: form.AssigneeID, | |||
// LabelIDs: "$" + strings.Join(form.LabelIDs, "|$") + "|", | |||
Content: form.Content, | |||
} | |||
if err := models.NewIssue(issue); err != nil { | |||
send(500, nil, err) | |||
ctx.Handle(500, "NewIssue", err) | |||
return | |||
} else if err := models.NewIssueUserPairs(ctx.Repo.Repository, issue.ID, ctx.Repo.Owner.Id, | |||
ctx.User.Id, form.AssigneeId); err != nil { | |||
send(500, nil, err) | |||
} else if err := models.NewIssueUserPairs(ctx.Repo.Repository, issue); err != nil { | |||
ctx.Handle(500, "NewIssue", err) | |||
return | |||
} | |||
if setting.AttachmentEnabled { | |||
uploadFiles(ctx, issue.ID, 0) | |||
} | |||
// Update mentions. | |||
ms := base.MentionPattern.FindAllString(issue.Content, -1) | |||
if len(ms) > 0 { | |||
for i := range ms { | |||
ms[i] = ms[i][1:] | |||
} | |||
if err := models.UpdateMentions(ms, issue.ID); err != nil { | |||
send(500, nil, err) | |||
return | |||
} | |||
} | |||
act := &models.Action{ | |||
ActUserID: ctx.User.Id, | |||
ActUserName: ctx.User.Name, | |||
ActEmail: ctx.User.Email, | |||
OpType: models.CREATE_ISSUE, | |||
Content: fmt.Sprintf("%d|%s", issue.Index, issue.Name), | |||
RepoID: ctx.Repo.Repository.ID, | |||
RepoUserName: ctx.Repo.Owner.Name, | |||
RepoName: ctx.Repo.Repository.Name, | |||
RefName: ctx.Repo.BranchName, | |||
IsPrivate: ctx.Repo.Repository.IsPrivate, | |||
} | |||
// Notify watchers. | |||
if err := models.NotifyWatchers(act); err != nil { | |||
send(500, nil, err) | |||
return | |||
} | |||
// Mail watchers and mentions. | |||
if setting.Service.EnableNotifyMail { | |||
tos, err := mailer.SendIssueNotifyMail(ctx.User, ctx.Repo.Owner, ctx.Repo.Repository, issue) | |||
if err != nil { | |||
send(500, nil, err) | |||
return | |||
} | |||
tos = append(tos, ctx.User.LowerName) | |||
newTos := make([]string, 0, len(ms)) | |||
for _, m := range ms { | |||
if com.IsSliceContainsStr(tos, m) { | |||
continue | |||
} | |||
newTos = append(newTos, m) | |||
} | |||
if err = mailer.SendIssueMentionMail(ctx.Render, ctx.User, ctx.Repo.Owner, | |||
ctx.Repo.Repository, issue, models.GetUserEmailsByNames(newTos)); err != nil { | |||
send(500, nil, err) | |||
return | |||
} | |||
} | |||
log.Trace("%d Issue created: %d", ctx.Repo.Repository.ID, issue.ID) | |||
ctx.Redirect(ctx.Repo.RepoLink + "/issues/" + com.ToStr(issue.Index)) | |||
} | |||
send(200, fmt.Sprintf("%s/%s/%s/issues/%d", setting.AppSubUrl, ctx.Params(":username"), ctx.Params(":reponame"), issue.Index), nil) | |||
func CreateIssuePost(ctx *middleware.Context, form auth.CreateIssueForm) { | |||
// send := func(status int, data interface{}, err error) { | |||
// if err != nil { | |||
// log.Error(4, "issue.CreateIssuePost(?): %s", err) | |||
// ctx.JSON(status, map[string]interface{}{ | |||
// "ok": false, | |||
// "status": status, | |||
// "error": err.Error(), | |||
// }) | |||
// } else { | |||
// ctx.JSON(status, map[string]interface{}{ | |||
// "ok": true, | |||
// "status": status, | |||
// "data": data, | |||
// }) | |||
// } | |||
// } | |||
// var err error | |||
// // Get all milestones. | |||
// _, err = models.GetMilestones(ctx.Repo.Repository.ID, -1, false) | |||
// if err != nil { | |||
// send(500, nil, err) | |||
// return | |||
// } | |||
// _, err = models.GetMilestones(ctx.Repo.Repository.ID, -1, true) | |||
// if err != nil { | |||
// send(500, nil, err) | |||
// return | |||
// } | |||
// _, err = ctx.Repo.Repository.GetCollaborators() | |||
// if err != nil { | |||
// send(500, nil, err) | |||
// return | |||
// } | |||
// if ctx.HasError() { | |||
// send(400, nil, errors.New(ctx.Flash.ErrorMsg)) | |||
// return | |||
// } | |||
// // Only collaborators can assign. | |||
// if !ctx.Repo.IsOwner() { | |||
// form.AssigneeId = 0 | |||
// } | |||
// issue := &models.Issue{ | |||
// RepoID: ctx.Repo.Repository.ID, | |||
// Index: int64(ctx.Repo.Repository.NumIssues) + 1, | |||
// Name: form.IssueName, | |||
// PosterID: ctx.User.Id, | |||
// MilestoneID: form.MilestoneId, | |||
// AssigneeID: form.AssigneeId, | |||
// LabelIds: form.Labels, | |||
// Content: form.Content, | |||
// } | |||
// if err := models.NewIssue(issue); err != nil { | |||
// send(500, nil, err) | |||
// return | |||
// } else if err := models.NewIssueUserPairs(ctx.Repo.Repository, issue.ID, ctx.Repo.Owner.Id, | |||
// ctx.User.Id, form.AssigneeId); err != nil { | |||
// send(500, nil, err) | |||
// return | |||
// } | |||
// if setting.AttachmentEnabled { | |||
// uploadFiles(ctx, issue.ID, 0) | |||
// } | |||
// // Update mentions. | |||
// ms := base.MentionPattern.FindAllString(issue.Content, -1) | |||
// if len(ms) > 0 { | |||
// for i := range ms { | |||
// ms[i] = ms[i][1:] | |||
// } | |||
// if err := models.UpdateMentions(ms, issue.ID); err != nil { | |||
// send(500, nil, err) | |||
// return | |||
// } | |||
// } | |||
// act := &models.Action{ | |||
// ActUserID: ctx.User.Id, | |||
// ActUserName: ctx.User.Name, | |||
// ActEmail: ctx.User.Email, | |||
// OpType: models.CREATE_ISSUE, | |||
// Content: fmt.Sprintf("%d|%s", issue.Index, issue.Name), | |||
// RepoID: ctx.Repo.Repository.ID, | |||
// RepoUserName: ctx.Repo.Owner.Name, | |||
// RepoName: ctx.Repo.Repository.Name, | |||
// RefName: ctx.Repo.BranchName, | |||
// IsPrivate: ctx.Repo.Repository.IsPrivate, | |||
// } | |||
// // Notify watchers. | |||
// if err := models.NotifyWatchers(act); err != nil { | |||
// send(500, nil, err) | |||
// return | |||
// } | |||
// // Mail watchers and mentions. | |||
// if setting.Service.EnableNotifyMail { | |||
// tos, err := mailer.SendIssueNotifyMail(ctx.User, ctx.Repo.Owner, ctx.Repo.Repository, issue) | |||
// if err != nil { | |||
// send(500, nil, err) | |||
// return | |||
// } | |||
// tos = append(tos, ctx.User.LowerName) | |||
// newTos := make([]string, 0, len(ms)) | |||
// for _, m := range ms { | |||
// if com.IsSliceContainsStr(tos, m) { | |||
// continue | |||
// } | |||
// newTos = append(newTos, m) | |||
// } | |||
// if err = mailer.SendIssueMentionMail(ctx.Render, ctx.User, ctx.Repo.Owner, | |||
// ctx.Repo.Repository, issue, models.GetUserEmailsByNames(newTos)); err != nil { | |||
// send(500, nil, err) | |||
// return | |||
// } | |||
// } | |||
// log.Trace("%d Issue created: %d", ctx.Repo.Repository.ID, issue.ID) | |||
// send(200, fmt.Sprintf("%s/%s/%s/issues/%d", setting.AppSubUrl, ctx.Params(":username"), ctx.Params(":reponame"), issue.Index), nil) | |||
} | |||
func checkLabels(labels, allLabels []*models.Label) { | |||
@@ -484,7 +515,7 @@ func UpdateIssue(ctx *middleware.Context, form auth.CreateIssueForm) { | |||
return | |||
} | |||
issue.Name = form.IssueName | |||
issue.Name = form.Title | |||
//issue.MilestoneId = form.MilestoneId | |||
//issue.AssigneeId = form.AssigneeId | |||
//issue.LabelIds = form.Labels | |||
@@ -540,16 +571,16 @@ func UpdateIssueLabel(ctx *middleware.Context) { | |||
return | |||
} | |||
isHad := strings.Contains(issue.LabelIds, "$"+labelStrId+"|") | |||
isHad := strings.Contains(issue.LabelIDs, "$"+labelStrId+"|") | |||
isNeedUpdate := false | |||
if isAttach { | |||
if !isHad { | |||
issue.LabelIds += "$" + labelStrId + "|" | |||
issue.LabelIDs += "$" + labelStrId + "|" | |||
isNeedUpdate = true | |||
} | |||
} else { | |||
if isHad { | |||
issue.LabelIds = strings.Replace(issue.LabelIds, "$"+labelStrId+"|", "", -1) | |||
issue.LabelIDs = strings.Replace(issue.LabelIDs, "$"+labelStrId+"|", "", -1) | |||
isNeedUpdate = true | |||
} | |||
} |
@@ -1 +1 @@ | |||
0.6.4.0808 Beta | |||
0.6.4.0809 Beta |
@@ -0,0 +1,14 @@ | |||
{{template "base/head" .}} | |||
<div class="repository new issue"> | |||
{{template "repo/header" .}} | |||
<div class="ui middle page grid body"> | |||
<div class="navbar"> | |||
{{template "repo/issue/navbar" .}} | |||
</div> | |||
<div class="ui divider"></div> | |||
<div class="sixteen wide column page grid"> | |||
{{template "repo/issue/new_form" .}} | |||
</div> | |||
</div> | |||
</div> | |||
{{template "base/footer" .}} |
@@ -0,0 +1,88 @@ | |||
<form class="ui comment form grid" action="{{.Link}}" method="post"> | |||
{{.CsrfTokenHtml}} | |||
{{if .Flash}} | |||
<div class="sixteen wide column"> | |||
{{template "base/alert" .}} | |||
</div> | |||
{{end}} | |||
<div class="twelve wide column"> | |||
<div class="ui comments"> | |||
<div class="comment"> | |||
<a class="avatar"> | |||
<img src="{{.SignedUser.AvatarLink}}"> | |||
</a> | |||
<div class="ui segment content"> | |||
<div class="field"> | |||
<input name="title" placeholder="{{.i18n.Tr "repo.milestones.title"}}" value="{{.title}}" autofocus required> | |||
</div> | |||
<div class="field"> | |||
<div class="ui top attached tabular menu"> | |||
<a class="active item" data-tab="write">{{.i18n.Tr "repo.release.write"}}</a> | |||
<a class="item" data-tab="preview" data-url="/api/v1/markdown" data-context="{{.RepoLink}}">{{.i18n.Tr "repo.release.preview"}}</a> | |||
</div> | |||
<div class="ui bottom attached active tab segment" data-tab="write"> | |||
<textarea name="content"></textarea> | |||
</div> | |||
<div class="ui bottom attached tab segment markdown" data-tab="preview"> | |||
{{.i18n.Tr "repo.release.loading"}} | |||
</div> | |||
</div> | |||
<button class="ui right green button"> | |||
{{.i18n.Tr "repo.issues.create"}} | |||
</button> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="four wide column"> | |||
<div class="ui segment metas"> | |||
<div class="ui {{if .Labels}}disabled{{end}} pointing dropdown jump item"> | |||
<span class="text"> | |||
<strong>{{.i18n.Tr "repo.issues.new.labels"}}</strong> | |||
<span class="octicon octicon-gear"></span> | |||
</span> | |||
<div class="menu"> | |||
<a class="item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&state={{$.State}}&milestone={{$.MilestoneID}}">{{.i18n.Tr "repo.issues.filter_label_no_select"}}</a> | |||
{{range .Labels}} | |||
<a class="item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&state={{$.State}}&labels={{.ID}}&milestone={{$.MilestoneID}}"><span class="octicon {{if eq $.SelectLabels .ID}}octicon-check{{end}}"></span><span class="label color" style="background-color: {{.Color}}"></span> {{.Name}}</a> | |||
{{end}} | |||
</div> | |||
</div> | |||
<div class="ui list"> | |||
<span class="item">filter_label_no_select</span> | |||
</div> | |||
<div class="ui divider"></div> | |||
<div class="ui {{if .Labels}}disabled{{end}} pointing dropdown jump item"> | |||
<span class="text"> | |||
<strong>{{.i18n.Tr "repo.issues.new.labels"}}</strong> | |||
<span class="octicon octicon-gear"></span> | |||
</span> | |||
<div class="menu"> | |||
<a class="item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&state={{$.State}}&milestone={{$.MilestoneID}}">{{.i18n.Tr "repo.issues.filter_label_no_select"}}</a> | |||
{{range .Labels}} | |||
<a class="item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&state={{$.State}}&labels={{.ID}}&milestone={{$.MilestoneID}}"><span class="octicon {{if eq $.SelectLabels .ID}}octicon-check{{end}}"></span><span class="label color" style="background-color: {{.Color}}"></span> {{.Name}}</a> | |||
{{end}} | |||
</div> | |||
</div> | |||
<div class="ui list"> | |||
<span class="item">filter_label_no_select</span> | |||
</div> | |||
<div class="ui divider"></div> | |||
<div class="ui {{if .Labels}}disabled{{end}} pointing dropdown jump item"> | |||
<span class="text"> | |||
<strong>{{.i18n.Tr "repo.issues.new.labels"}}</strong> | |||
<span class="octicon octicon-gear"></span> | |||
</span> | |||
<div class="menu"> | |||
<a class="item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&state={{$.State}}&milestone={{$.MilestoneID}}">{{.i18n.Tr "repo.issues.filter_label_no_select"}}</a> | |||
{{range .Labels}} | |||
<a class="item" href="{{$.RepoLink}}/issues?type={{$.ViewType}}&state={{$.State}}&labels={{.ID}}&milestone={{$.MilestoneID}}"><span class="octicon {{if eq $.SelectLabels .ID}}octicon-check{{end}}"></span><span class="label color" style="background-color: {{.Color}}"></span> {{.Name}}</a> | |||
{{end}} | |||
</div> | |||
</div> | |||
<div class="ui list"> | |||
<span class="item">filter_label_no_select</span> | |||
</div> | |||
</div> | |||
</div> | |||
</form> |
@@ -45,6 +45,7 @@ | |||
</div> | |||
</div> | |||
</div> | |||
{{template "repo/issue/new_form" .}} | |||
</div> | |||
</div> | |||
</div> |