| @@ -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> | |||