2014-03-22 21:50:50 +04:00
// 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 repo
2014-07-26 10:28:04 +04:00
import (
"errors"
"fmt"
"net/http"
"net/url"
"strings"
"time"
"github.com/Unknwon/com"
2015-07-27 22:14:37 +03:00
"github.com/Unknwon/paginater"
2014-07-26 10:28:04 +04:00
"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"
"github.com/gogits/gogs/modules/setting"
)
const (
2015-08-09 10:23:02 +03:00
ISSUES base . TplName = "repo/issue/list"
ISSUE_NEW base . TplName = "repo/issue/new"
ISSUE_VIEW base . TplName = "repo/issue/view"
2014-07-26 10:28:04 +04:00
2015-07-24 16:02:49 +03:00
LABELS base . TplName = "repo/issue/labels"
2015-08-05 10:24:26 +03:00
MILESTONE base . TplName = "repo/issue/milestones"
2014-07-26 10:28:04 +04:00
MILESTONE_NEW base . TplName = "repo/issue/milestone_new"
MILESTONE_EDIT base . TplName = "repo/issue/milestone_edit"
)
var (
ErrFileTypeForbidden = errors . New ( "File type is not allowed" )
ErrTooManyFiles = errors . New ( "Maximum number of files to upload exceeded" )
)
2015-12-05 05:30:33 +03:00
func MustEnableIssues ( ctx * middleware . Context ) {
if ! ctx . Repo . Repository . EnableIssues {
ctx . Handle ( 404 , "MustEnableIssues" , nil )
}
}
func MustEnablePulls ( ctx * middleware . Context ) {
if ! ctx . Repo . Repository . EnablePulls {
ctx . Handle ( 404 , "MustEnablePulls" , nil )
}
2015-12-20 06:07:06 +03:00
ctx . Data [ "HasForkedRepo" ] = ctx . IsSigned && ctx . User . HasForkedRepo ( ctx . Repo . Repository . ID )
2015-12-05 05:30:33 +03:00
}
2015-07-24 16:02:49 +03:00
func RetrieveLabels ( ctx * middleware . Context ) {
2015-08-10 09:42:50 +03:00
labels , err := models . GetLabelsByRepoID ( ctx . Repo . Repository . ID )
2015-07-24 16:02:49 +03:00
if err != nil {
ctx . Handle ( 500 , "RetrieveLabels.GetLabels: %v" , err )
return
}
for _ , l := range labels {
l . CalOpenIssues ( )
}
ctx . Data [ "Labels" ] = labels
ctx . Data [ "NumLabels" ] = len ( labels )
}
2014-07-26 10:28:04 +04:00
func Issues ( ctx * middleware . Context ) {
2015-09-02 23:18:09 +03:00
isPullList := ctx . Params ( ":type" ) == "pulls"
if isPullList {
2015-12-20 06:07:06 +03:00
MustEnablePulls ( ctx )
if ctx . Written ( ) {
return
}
2015-09-02 23:18:09 +03:00
ctx . Data [ "Title" ] = ctx . Tr ( "repo.pulls" )
ctx . Data [ "PageIsPullList" ] = true
2015-12-05 05:30:33 +03:00
2015-09-02 23:18:09 +03:00
} else {
2015-12-05 05:30:33 +03:00
MustEnableIssues ( ctx )
if ctx . Written ( ) {
return
}
2015-09-02 23:18:09 +03:00
ctx . Data [ "Title" ] = ctx . Tr ( "repo.issues" )
ctx . Data [ "PageIsIssueList" ] = true
}
2014-07-26 10:28:04 +04:00
viewType := ctx . Query ( "type" )
2015-08-15 07:07:08 +03:00
sortType := ctx . Query ( "sort" )
2014-07-26 10:28:04 +04:00
types := [ ] string { "assigned" , "created_by" , "mentioned" }
if ! com . IsSliceContainsStr ( types , viewType ) {
viewType = "all"
}
2015-07-24 11:42:47 +03:00
// Must sign in to see issues about you.
2014-07-26 10:28:04 +04:00
if viewType != "all" && ! ctx . IsSigned {
2014-09-21 16:07:00 +04:00
ctx . SetCookie ( "redirect_to" , "/" + url . QueryEscape ( setting . AppSubUrl + ctx . Req . RequestURI ) , 0 , setting . AppSubUrl )
2014-09-20 04:11:34 +04:00
ctx . Redirect ( setting . AppSubUrl + "/user/login" )
2014-07-26 10:28:04 +04:00
return
}
2015-08-15 07:07:08 +03:00
var (
assigneeID = ctx . QueryInt64 ( "assignee" )
posterID int64
)
2015-07-24 21:52:25 +03:00
filterMode := models . FM_ALL
2014-07-26 10:28:04 +04:00
switch viewType {
case "assigned" :
filterMode = models . FM_ASSIGN
2015-08-25 17:58:34 +03:00
assigneeID = ctx . User . Id
2014-07-26 10:28:04 +04:00
case "created_by" :
filterMode = models . FM_CREATE
2015-08-25 17:58:34 +03:00
posterID = ctx . User . Id
2014-07-26 10:28:04 +04:00
case "mentioned" :
filterMode = models . FM_MENTION
}
2015-07-24 21:52:25 +03:00
var uid int64 = - 1
if ctx . IsSigned {
uid = ctx . User . Id
2014-07-26 10:28:04 +04:00
}
2015-07-24 21:52:25 +03:00
repo := ctx . Repo . Repository
2015-07-25 02:59:54 +03:00
selectLabels := ctx . Query ( "labels" )
2015-07-24 21:52:25 +03:00
milestoneID := ctx . QueryInt64 ( "milestone" )
2015-08-04 17:24:04 +03:00
isShowClosed := ctx . Query ( "state" ) == "closed"
2015-09-02 23:18:09 +03:00
issueStats := models . GetIssueStats ( & models . IssueStatsOptions {
RepoID : repo . ID ,
UserID : uid ,
LabelID : com . StrTo ( selectLabels ) . MustInt64 ( ) ,
MilestoneID : milestoneID ,
AssigneeID : assigneeID ,
FilterMode : filterMode ,
IsPull : isPullList ,
} )
2015-07-25 02:59:54 +03:00
2015-07-24 11:42:47 +03:00
page := ctx . QueryInt ( "page" )
if page <= 1 {
page = 1
}
2015-07-27 22:14:37 +03:00
var total int
if ! isShowClosed {
total = int ( issueStats . OpenCount )
} else {
total = int ( issueStats . ClosedCount )
2015-07-24 11:42:47 +03:00
}
2015-11-04 18:16:50 +03:00
pager := paginater . New ( total , setting . IssuePagingNum , page , 5 )
ctx . Data [ "Page" ] = pager
2014-07-26 10:28:04 +04:00
// Get issues.
2015-09-02 23:18:09 +03:00
issues , err := models . Issues ( & models . IssuesOptions {
UserID : uid ,
AssigneeID : assigneeID ,
RepoID : repo . ID ,
PosterID : posterID ,
MilestoneID : milestoneID ,
2015-11-04 18:16:50 +03:00
Page : pager . Current ( ) ,
2015-09-02 23:18:09 +03:00
IsClosed : isShowClosed ,
IsMention : filterMode == models . FM_MENTION ,
IsPull : isPullList ,
Labels : selectLabels ,
SortType : sortType ,
} )
2014-07-26 10:28:04 +04:00
if err != nil {
2015-08-10 17:45:49 +03:00
ctx . Handle ( 500 , "Issues: %v" , err )
2014-07-26 10:28:04 +04:00
return
}
2015-08-10 17:45:49 +03:00
// Get issue-user relations.
pairs , err := models . GetIssueUsers ( repo . ID , posterID , isShowClosed )
2014-07-26 10:28:04 +04:00
if err != nil {
2015-08-10 17:45:49 +03:00
ctx . Handle ( 500 , "GetIssueUsers: %v" , err )
2014-07-26 10:28:04 +04:00
return
}
// Get posters.
for i := range issues {
2015-07-24 21:52:25 +03:00
if err = issues [ i ] . GetPoster ( ) ; err != nil {
ctx . Handle ( 500 , "GetPoster" , fmt . Errorf ( "[#%d]%v" , issues [ i ] . ID , err ) )
return
}
2014-07-26 10:28:04 +04:00
if err = issues [ i ] . GetLabels ( ) ; err != nil {
2015-07-24 16:02:49 +03:00
ctx . Handle ( 500 , "GetLabels" , fmt . Errorf ( "[#%d]%v" , issues [ i ] . ID , err ) )
2014-07-26 10:28:04 +04:00
return
}
2015-07-24 21:52:25 +03:00
if ! ctx . IsSigned {
issues [ i ] . IsRead = true
continue
2014-07-26 10:28:04 +04:00
}
2015-07-24 21:52:25 +03:00
// Check read status.
idx := models . PairsContains ( pairs , issues [ i ] . ID , ctx . User . Id )
if idx > - 1 {
issues [ i ] . IsRead = pairs [ idx ] . IsRead
} else {
issues [ i ] . IsRead = true
2014-07-26 10:28:04 +04:00
}
}
2015-08-05 15:23:08 +03:00
ctx . Data [ "Issues" ] = issues
// Get milestones.
2015-08-15 06:24:41 +03:00
ctx . Data [ "Milestones" ] , err = models . GetAllRepoMilestones ( repo . ID )
2015-08-05 15:23:08 +03:00
if err != nil {
ctx . Handle ( 500 , "GetAllRepoMilestones: %v" , err )
return
}
2015-08-15 06:24:41 +03:00
// Get assignees.
ctx . Data [ "Assignees" ] , err = repo . GetAssignees ( )
if err != nil {
ctx . Handle ( 500 , "GetAssignees: %v" , err )
return
}
2014-07-26 10:28:04 +04:00
ctx . Data [ "IssueStats" ] = issueStats
2015-07-24 11:42:47 +03:00
ctx . Data [ "SelectLabels" ] = com . StrTo ( selectLabels ) . MustInt64 ( )
2014-07-26 10:28:04 +04:00
ctx . Data [ "ViewType" ] = viewType
2015-08-15 07:07:08 +03:00
ctx . Data [ "SortType" ] = sortType
2015-08-05 15:23:08 +03:00
ctx . Data [ "MilestoneID" ] = milestoneID
2015-08-15 06:24:41 +03:00
ctx . Data [ "AssigneeID" ] = assigneeID
2014-07-26 10:28:04 +04:00
ctx . Data [ "IsShowClosed" ] = isShowClosed
if isShowClosed {
ctx . Data [ "State" ] = "closed"
} else {
2015-07-24 21:52:25 +03:00
ctx . Data [ "State" ] = "open"
2014-07-26 10:28:04 +04:00
}
2015-07-24 21:52:25 +03:00
2014-07-26 10:28:04 +04:00
ctx . HTML ( 200 , ISSUES )
}
2015-08-12 12:04:23 +03:00
func renderAttachmentSettings ( ctx * middleware . Context ) {
2015-09-02 02:07:02 +03:00
ctx . Data [ "RequireDropzone" ] = true
2015-08-12 12:04:23 +03:00
ctx . Data [ "IsAttachmentEnabled" ] = setting . AttachmentEnabled
ctx . Data [ "AttachmentAllowedTypes" ] = setting . AttachmentAllowedTypes
2015-09-02 23:18:09 +03:00
ctx . Data [ "AttachmentMaxSize" ] = setting . AttachmentMaxSize
2015-08-12 12:04:23 +03:00
ctx . Data [ "AttachmentMaxFiles" ] = setting . AttachmentMaxFiles
}
2015-09-02 02:07:02 +03:00
func RetrieveRepoMilestonesAndAssignees ( ctx * middleware . Context , repo * models . Repository ) {
var err error
ctx . Data [ "OpenMilestones" ] , err = models . GetMilestones ( repo . ID , - 1 , false )
if err != nil {
ctx . Handle ( 500 , "GetMilestones: %v" , err )
return
}
ctx . Data [ "ClosedMilestones" ] , err = models . GetMilestones ( repo . ID , - 1 , true )
if err != nil {
ctx . Handle ( 500 , "GetMilestones: %v" , err )
return
}
ctx . Data [ "Assignees" ] , err = repo . GetAssignees ( )
if err != nil {
ctx . Handle ( 500 , "GetAssignees: %v" , err )
return
}
}
2015-08-31 10:24:28 +03:00
func RetrieveRepoMetas ( ctx * middleware . Context , repo * models . Repository ) [ ] * models . Label {
if ! ctx . Repo . IsAdmin ( ) {
return nil
}
labels , err := models . GetLabelsByRepoID ( repo . ID )
if err != nil {
ctx . Handle ( 500 , "GetLabelsByRepoID: %v" , err )
return nil
}
ctx . Data [ "Labels" ] = labels
2015-09-02 02:07:02 +03:00
RetrieveRepoMilestonesAndAssignees ( ctx , repo )
if ctx . Written ( ) {
2015-08-31 10:24:28 +03:00
return nil
}
return labels
}
2015-08-09 10:23:02 +03:00
func NewIssue ( ctx * middleware . Context ) {
ctx . Data [ "Title" ] = ctx . Tr ( "repo.issues.new" )
ctx . Data [ "PageIsIssueList" ] = true
2015-08-12 12:04:23 +03:00
renderAttachmentSettings ( ctx )
2015-08-09 10:23:02 +03:00
2015-08-31 10:24:28 +03:00
RetrieveRepoMetas ( ctx , ctx . Repo . Repository )
if ctx . Written ( ) {
return
2015-08-10 13:57:57 +03:00
}
2015-08-09 10:23:02 +03:00
2016-02-01 22:52:47 +03:00
ctx . Data [ "RequireHighlightJS" ] = true
2015-08-09 10:23:02 +03:00
ctx . HTML ( 200 , ISSUE_NEW )
2014-07-26 10:28:04 +04:00
}
2015-09-02 02:07:02 +03:00
func ValidateRepoMetas ( ctx * middleware . Context , form auth . CreateIssueForm ) ( [ ] int64 , int64 , int64 ) {
var (
repo = ctx . Repo . Repository
err error
)
labels := RetrieveRepoMetas ( ctx , ctx . Repo . Repository )
if ctx . Written ( ) {
return nil , 0 , 0
}
if ! ctx . Repo . IsAdmin ( ) {
return nil , 0 , 0
}
// Check labels.
labelIDs := base . StringsToInt64s ( strings . Split ( form . LabelIDs , "," ) )
labelIDMark := base . Int64sToMap ( labelIDs )
hasSelected := false
for i := range labels {
if labelIDMark [ labels [ i ] . ID ] {
labels [ i ] . IsChecked = true
hasSelected = true
}
}
ctx . Data [ "HasSelectedLabel" ] = hasSelected
ctx . Data [ "label_ids" ] = form . LabelIDs
ctx . Data [ "Labels" ] = labels
// Check milestone.
milestoneID := form . MilestoneID
if milestoneID > 0 {
ctx . Data [ "Milestone" ] , err = repo . GetMilestoneByID ( milestoneID )
if err != nil {
ctx . Handle ( 500 , "GetMilestoneByID: %v" , err )
return nil , 0 , 0
}
ctx . Data [ "milestone_id" ] = milestoneID
}
// Check assignee.
assigneeID := form . AssigneeID
if assigneeID > 0 {
ctx . Data [ "Assignee" ] , err = repo . GetAssigneeByID ( assigneeID )
if err != nil {
ctx . Handle ( 500 , "GetAssigneeByID: %v" , err )
return nil , 0 , 0
}
ctx . Data [ "assignee_id" ] = assigneeID
}
return labelIDs , milestoneID , assigneeID
}
2015-12-10 19:18:56 +03:00
func notifyWatchersAndMentions ( ctx * middleware . Context , issue * models . Issue ) {
// Update mentions
2015-10-30 03:40:57 +03:00
mentions := base . MentionPattern . FindAllString ( issue . Content , - 1 )
if len ( mentions ) > 0 {
for i := range mentions {
mentions [ i ] = strings . TrimSpace ( mentions [ i ] ) [ 1 : ]
}
if err := models . UpdateMentions ( mentions , issue . ID ) ; err != nil {
ctx . Handle ( 500 , "UpdateMentions" , err )
return
}
}
repo := ctx . Repo . Repository
// Mail watchers and mentions.
if setting . Service . EnableNotifyMail {
tos , err := mailer . SendIssueNotifyMail ( ctx . User , ctx . Repo . Owner , repo , issue )
if err != nil {
ctx . Handle ( 500 , "SendIssueNotifyMail" , err )
return
}
tos = append ( tos , ctx . User . LowerName )
newTos := make ( [ ] string , 0 , len ( mentions ) )
for _ , m := range mentions {
if com . IsSliceContainsStr ( tos , m ) {
continue
}
newTos = append ( newTos , m )
}
if err = mailer . SendIssueMentionMail ( ctx . Render , ctx . User , ctx . Repo . Owner ,
repo , issue , models . GetUserEmailsByNames ( newTos ) ) ; err != nil {
ctx . Handle ( 500 , "SendIssueMentionMail" , err )
return
}
}
}
2015-08-09 10:23:02 +03:00
func NewIssuePost ( ctx * middleware . Context , form auth . CreateIssueForm ) {
ctx . Data [ "Title" ] = ctx . Tr ( "repo.issues.new" )
ctx . Data [ "PageIsIssueList" ] = true
2015-08-12 12:04:23 +03:00
renderAttachmentSettings ( ctx )
2014-07-26 10:28:04 +04:00
2015-08-10 11:52:08 +03:00
var (
2015-08-10 13:57:57 +03:00
repo = ctx . Repo . Repository
2015-08-11 18:24:40 +03:00
attachments [ ] string
2015-08-10 11:52:08 +03:00
)
2015-08-31 10:24:28 +03:00
2015-09-02 02:07:02 +03:00
labelIDs , milestoneID , assigneeID := ValidateRepoMetas ( ctx , form )
if ctx . Written ( ) {
return
2015-08-10 11:52:08 +03:00
}
2015-08-11 18:24:40 +03:00
if setting . AttachmentEnabled {
2015-08-13 11:07:11 +03:00
attachments = form . Attachments
2015-08-11 18:24:40 +03:00
}
2014-07-26 10:28:04 +04:00
if ctx . HasError ( ) {
2015-08-09 10:23:02 +03:00
ctx . HTML ( 200 , ISSUE_NEW )
2014-07-26 10:28:04 +04:00
return
}
issue := & models . Issue {
2015-08-10 13:57:57 +03:00
RepoID : ctx . Repo . Repository . ID ,
2015-09-03 10:49:50 +03:00
Index : repo . NextIssueIndex ( ) ,
2015-11-06 19:17:46 +03:00
Name : strings . TrimSpace ( form . Title ) ,
2015-08-10 13:57:57 +03:00
PosterID : ctx . User . Id ,
2015-08-10 18:31:59 +03:00
Poster : ctx . User ,
2015-08-10 13:57:57 +03:00
MilestoneID : milestoneID ,
2015-08-10 16:47:23 +03:00
AssigneeID : assigneeID ,
Content : form . Content ,
2014-07-26 10:28:04 +04:00
}
2015-08-11 18:24:40 +03:00
if err := models . NewIssue ( repo , issue , labelIDs , attachments ) ; err != nil {
2015-08-09 10:23:02 +03:00
ctx . Handle ( 500 , "NewIssue" , err )
2014-07-26 10:28:04 +04:00
return
}
2015-12-10 19:18:56 +03:00
notifyWatchersAndMentions ( ctx , issue )
2015-10-30 03:40:57 +03:00
if ctx . Written ( ) {
return
2015-08-10 18:31:59 +03:00
}
2015-09-02 02:07:02 +03:00
log . Trace ( "Issue created: %d/%d" , repo . ID , issue . ID )
2015-08-10 18:31:59 +03:00
ctx . Redirect ( ctx . Repo . RepoLink + "/issues/" + com . ToStr ( issue . Index ) )
2014-07-26 10:28:04 +04:00
}
2015-08-11 18:24:40 +03:00
func UploadIssueAttachment ( ctx * middleware . Context ) {
if ! setting . AttachmentEnabled {
ctx . Error ( 404 , "attachment is not enabled" )
return
}
allowedTypes := strings . Split ( setting . AttachmentAllowedTypes , "," )
file , header , err := ctx . Req . FormFile ( "file" )
if err != nil {
ctx . Error ( 500 , fmt . Sprintf ( "FormFile: %v" , err ) )
return
}
defer file . Close ( )
buf := make ( [ ] byte , 1024 )
n , _ := file . Read ( buf )
if n > 0 {
buf = buf [ : n ]
}
fileType := http . DetectContentType ( buf )
allowed := false
for _ , t := range allowedTypes {
t := strings . Trim ( t , " " )
if t == "*/*" || t == fileType {
allowed = true
break
}
}
if ! allowed {
ctx . Error ( 400 , ErrFileTypeForbidden . Error ( ) )
return
}
attach , err := models . NewAttachment ( header . Filename , buf , file )
if err != nil {
ctx . Error ( 500 , fmt . Sprintf ( "NewAttachment: %v" , err ) )
return
}
log . Trace ( "New attachment uploaded: %s" , attach . UUID )
2015-08-11 12:54:00 +03:00
ctx . JSON ( 200 , map [ string ] string {
2015-08-11 18:24:40 +03:00
"uuid" : attach . UUID ,
2015-08-11 12:54:00 +03:00
} )
}
2014-07-26 10:28:04 +04:00
func ViewIssue ( ctx * middleware . Context ) {
2015-08-12 12:04:23 +03:00
ctx . Data [ "RequireDropzone" ] = true
renderAttachmentSettings ( ctx )
2014-07-26 10:28:04 +04:00
2015-08-12 12:04:23 +03:00
issue , err := models . GetIssueByIndex ( ctx . Repo . Repository . ID , ctx . ParamsInt64 ( ":index" ) )
2014-07-26 10:28:04 +04:00
if err != nil {
2015-08-12 12:04:23 +03:00
if models . IsErrIssueNotExist ( err ) {
2015-08-05 13:26:18 +03:00
ctx . Handle ( 404 , "GetIssueByIndex" , err )
2014-07-26 10:28:04 +04:00
} else {
2015-08-05 13:26:18 +03:00
ctx . Handle ( 500 , "GetIssueByIndex" , err )
2014-07-26 10:28:04 +04:00
}
return
}
2015-08-12 12:04:23 +03:00
ctx . Data [ "Title" ] = issue . Name
2014-07-26 10:28:04 +04:00
2015-09-02 02:07:02 +03:00
// Make sure type and URL matches.
if ctx . Params ( ":type" ) == "issues" && issue . IsPull {
ctx . Redirect ( ctx . Repo . RepoLink + "/pulls/" + com . ToStr ( issue . Index ) )
return
} else if ctx . Params ( ":type" ) == "pulls" && ! issue . IsPull {
ctx . Redirect ( ctx . Repo . RepoLink + "/issues/" + com . ToStr ( issue . Index ) )
return
}
2015-09-02 11:08:05 +03:00
if issue . IsPull {
2015-10-25 10:10:22 +03:00
if err = issue . GetPullRequest ( ) ; err != nil {
ctx . Handle ( 500 , "GetPullRequest" , err )
return
}
2015-09-02 11:08:05 +03:00
ctx . Data [ "PageIsPullList" ] = true
ctx . Data [ "PageIsPullConversation" ] = true
2015-11-16 19:20:11 +03:00
ctx . Data [ "HasForkedRepo" ] = ctx . IsSigned && ctx . User . HasForkedRepo ( ctx . Repo . Repository . ID )
2015-09-02 11:08:05 +03:00
} else {
2015-12-05 05:30:33 +03:00
MustEnableIssues ( ctx )
if ctx . Written ( ) {
return
}
2015-09-02 11:08:05 +03:00
ctx . Data [ "PageIsIssueList" ] = true
}
2014-07-26 10:28:04 +04:00
if err = issue . GetPoster ( ) ; err != nil {
2015-08-13 21:43:40 +03:00
ctx . Handle ( 500 , "GetPoster" , err )
2014-07-26 10:28:04 +04:00
return
}
2015-12-05 05:30:33 +03:00
issue . RenderedContent = string ( base . RenderMarkdown ( [ ] byte ( issue . Content ) , ctx . Repo . RepoLink ,
ctx . Repo . Repository . ComposeMetas ( ) ) )
2014-07-26 10:28:04 +04:00
2015-08-14 19:42:43 +03:00
repo := ctx . Repo . Repository
2015-09-02 02:07:02 +03:00
// Get more information if it's a pull request.
if issue . IsPull {
2015-09-02 16:26:56 +03:00
if issue . HasMerged {
ctx . Data [ "DisableStatusChange" ] = issue . HasMerged
PrepareMergedViewPullInfo ( ctx , issue )
} else {
PrepareViewPullInfo ( ctx , issue )
}
2015-09-02 11:08:05 +03:00
if ctx . Written ( ) {
2015-09-02 02:07:02 +03:00
return
}
}
2015-08-12 12:04:23 +03:00
// Metas.
2015-08-14 19:42:43 +03:00
// Check labels.
2015-08-12 12:04:23 +03:00
if err = issue . GetLabels ( ) ; err != nil {
ctx . Handle ( 500 , "GetLabels" , err )
return
2014-07-26 10:28:04 +04:00
}
2015-08-14 19:42:43 +03:00
labelIDMark := make ( map [ int64 ] bool )
for i := range issue . Labels {
labelIDMark [ issue . Labels [ i ] . ID ] = true
}
labels , err := models . GetLabelsByRepoID ( repo . ID )
if err != nil {
ctx . Handle ( 500 , "GetLabelsByRepoID: %v" , err )
return
}
hasSelected := false
for i := range labels {
if labelIDMark [ labels [ i ] . ID ] {
labels [ i ] . IsChecked = true
hasSelected = true
}
}
ctx . Data [ "HasSelectedLabel" ] = hasSelected
ctx . Data [ "Labels" ] = labels
// Check milestone and assignee.
if ctx . Repo . IsAdmin ( ) {
2015-09-02 02:07:02 +03:00
RetrieveRepoMilestonesAndAssignees ( ctx , repo )
if ctx . Written ( ) {
2015-08-14 19:42:43 +03:00
return
}
}
2014-07-26 10:28:04 +04:00
2015-08-12 12:04:23 +03:00
if ctx . IsSigned {
2015-08-12 13:44:09 +03:00
// Update issue-user.
if err = issue . ReadBy ( ctx . User . Id ) ; err != nil {
2015-08-13 21:43:40 +03:00
ctx . Handle ( 500 , "ReadBy" , err )
2015-08-12 13:44:09 +03:00
return
}
2015-08-12 12:04:23 +03:00
}
2015-08-13 21:43:40 +03:00
var (
2016-01-19 16:04:24 +03:00
tag models . CommentTag
ok bool
marked = make ( map [ int64 ] models . CommentTag )
comment * models . Comment
2016-02-02 04:55:12 +03:00
participants = make ( [ ] * models . User , 1 , 10 )
2015-08-13 21:43:40 +03:00
)
2016-02-02 04:55:12 +03:00
// Render comments and and fetch participants.
participants [ 0 ] = issue . Poster
2015-08-13 21:43:40 +03:00
for _ , comment = range issue . Comments {
if comment . Type == models . COMMENT_TYPE_COMMENT {
2015-12-05 05:30:33 +03:00
comment . RenderedContent = string ( base . RenderMarkdown ( [ ] byte ( comment . Content ) , ctx . Repo . RepoLink ,
ctx . Repo . Repository . ComposeMetas ( ) ) )
2015-08-13 21:43:40 +03:00
// Check tag.
tag , ok = marked [ comment . PosterID ]
if ok {
comment . ShowTag = tag
continue
}
if repo . IsOwnedBy ( comment . PosterID ) ||
( repo . Owner . IsOrganization ( ) && repo . Owner . IsOwnedBy ( comment . PosterID ) ) {
comment . ShowTag = models . COMMENT_TAG_OWNER
} else if comment . Poster . IsAdminOfRepo ( repo ) {
comment . ShowTag = models . COMMENT_TAG_ADMIN
} else if comment . PosterID == issue . PosterID {
comment . ShowTag = models . COMMENT_TAG_POSTER
}
marked [ comment . PosterID ] = comment . ShowTag
2016-01-19 16:04:24 +03:00
2016-01-27 22:11:07 +03:00
isAdded := false
2016-01-19 16:04:24 +03:00
for j := range participants {
if comment . Poster == participants [ j ] {
2016-01-27 22:11:07 +03:00
isAdded = true
2016-01-20 18:16:39 +03:00
break
2016-01-19 16:04:24 +03:00
}
}
2016-01-27 22:11:07 +03:00
if ! isAdded && ! issue . IsPoster ( comment . Poster . Id ) {
2016-01-19 16:04:24 +03:00
participants = append ( participants , comment . Poster )
}
2015-08-13 11:07:11 +03:00
}
}
2014-07-26 10:28:04 +04:00
2016-01-19 16:04:24 +03:00
ctx . Data [ "Participants" ] = participants
2016-02-02 04:55:12 +03:00
ctx . Data [ "NumParticipants" ] = len ( participants )
2014-07-26 10:28:04 +04:00
ctx . Data [ "Issue" ] = issue
2015-08-14 21:48:05 +03:00
ctx . Data [ "IsIssueOwner" ] = ctx . Repo . IsAdmin ( ) || ( ctx . IsSigned && issue . IsPoster ( ctx . User . Id ) )
2015-08-28 14:15:25 +03:00
ctx . Data [ "SignInLink" ] = setting . AppSubUrl + "/user/login"
2016-02-01 22:52:47 +03:00
ctx . Data [ "RequireHighlightJS" ] = true
2014-07-26 10:28:04 +04:00
ctx . HTML ( 200 , ISSUE_VIEW )
}
2015-08-19 18:14:57 +03:00
func getActionIssue ( ctx * middleware . Context ) * models . Issue {
issue , err := models . GetIssueByIndex ( ctx . Repo . Repository . ID , ctx . ParamsInt64 ( ":index" ) )
2014-07-26 10:28:04 +04:00
if err != nil {
2015-08-12 12:04:23 +03:00
if models . IsErrIssueNotExist ( err ) {
2015-08-19 18:14:57 +03:00
ctx . Error ( 404 , "GetIssueByIndex" )
2014-07-26 10:28:04 +04:00
} else {
2015-08-19 18:14:57 +03:00
ctx . Handle ( 500 , "GetIssueByIndex" , err )
2014-07-26 10:28:04 +04:00
}
2015-08-19 18:14:57 +03:00
return nil
}
return issue
}
func UpdateIssueTitle ( ctx * middleware . Context ) {
issue := getActionIssue ( ctx )
if ctx . Written ( ) {
2014-07-26 10:28:04 +04:00
return
}
2015-08-19 23:31:28 +03:00
if ! ctx . IsSigned || ( ctx . User . Id != issue . PosterID && ! ctx . Repo . IsAdmin ( ) ) {
2014-07-26 10:28:04 +04:00
ctx . Error ( 403 )
return
}
2015-11-06 19:17:46 +03:00
issue . Name = ctx . QueryTrim ( "title" )
2015-08-19 23:31:28 +03:00
if len ( issue . Name ) == 0 {
ctx . Error ( 204 )
2015-08-19 18:14:57 +03:00
return
2014-07-26 10:28:04 +04:00
}
2015-08-19 18:14:57 +03:00
if err := models . UpdateIssue ( issue ) ; err != nil {
ctx . Handle ( 500 , "UpdateIssue" , err )
2014-07-26 10:28:04 +04:00
return
}
ctx . JSON ( 200 , map [ string ] interface { } {
2015-08-19 18:14:57 +03:00
"title" : issue . Name ,
2014-07-26 10:28:04 +04:00
} )
}
2015-08-19 23:31:28 +03:00
func UpdateIssueContent ( ctx * middleware . Context ) {
issue := getActionIssue ( ctx )
if ctx . Written ( ) {
return
}
if ! ctx . IsSigned || ( ctx . User . Id != issue . PosterID && ! ctx . Repo . IsAdmin ( ) ) {
ctx . Error ( 403 )
return
}
issue . Content = ctx . Query ( "content" )
if err := models . UpdateIssue ( issue ) ; err != nil {
ctx . Handle ( 500 , "UpdateIssue" , err )
return
}
ctx . JSON ( 200 , map [ string ] interface { } {
2015-12-05 05:30:33 +03:00
"content" : string ( base . RenderMarkdown ( [ ] byte ( issue . Content ) , ctx . Query ( "context" ) , ctx . Repo . Repository . ComposeMetas ( ) ) ) ,
2015-08-19 23:31:28 +03:00
} )
}
2015-08-14 19:42:43 +03:00
func UpdateIssueLabel ( ctx * middleware . Context ) {
issue := getActionIssue ( ctx )
if ctx . Written ( ) {
2014-07-26 10:28:04 +04:00
return
}
2015-08-14 19:42:43 +03:00
if ctx . Query ( "action" ) == "clear" {
if err := issue . ClearLabels ( ) ; err != nil {
ctx . Handle ( 500 , "ClearLabels" , err )
return
2014-07-26 10:28:04 +04:00
}
} else {
2015-08-14 19:42:43 +03:00
isAttach := ctx . Query ( "action" ) == "attach"
label , err := models . GetLabelByID ( ctx . QueryInt64 ( "id" ) )
if err != nil {
if models . IsErrLabelNotExist ( err ) {
ctx . Error ( 404 , "GetLabelByID" )
} else {
ctx . Handle ( 500 , "GetLabelByID" , err )
2015-08-10 09:42:50 +03:00
}
2014-07-26 10:28:04 +04:00
return
}
2015-08-14 19:42:43 +03:00
if isAttach && ! issue . HasLabel ( label . ID ) {
if err = issue . AddLabel ( label ) ; err != nil {
ctx . Handle ( 500 , "AddLabel" , err )
return
2014-07-26 10:28:04 +04:00
}
2015-08-14 19:42:43 +03:00
} else if ! isAttach && issue . HasLabel ( label . ID ) {
if err = issue . RemoveLabel ( label ) ; err != nil {
ctx . Handle ( 500 , "RemoveLabel" , err )
return
2014-07-26 10:28:04 +04:00
}
}
}
2015-08-14 19:42:43 +03:00
2014-07-26 10:28:04 +04:00
ctx . JSON ( 200 , map [ string ] interface { } {
"ok" : true ,
} )
}
func UpdateIssueMilestone ( ctx * middleware . Context ) {
2015-08-14 19:42:43 +03:00
issue := getActionIssue ( ctx )
if ctx . Written ( ) {
2014-07-26 10:28:04 +04:00
return
}
2015-08-05 15:23:08 +03:00
oldMid := issue . MilestoneID
2015-08-14 19:42:43 +03:00
mid := ctx . QueryInt64 ( "id" )
2014-07-26 10:28:04 +04:00
if oldMid == mid {
ctx . JSON ( 200 , map [ string ] interface { } {
"ok" : true ,
} )
return
}
// Not check for invalid milestone id and give responsibility to owners.
2015-08-05 15:23:08 +03:00
issue . MilestoneID = mid
2015-08-14 19:42:43 +03:00
if err := models . ChangeMilestoneAssign ( oldMid , issue ) ; err != nil {
ctx . Handle ( 500 , "ChangeMilestoneAssign" , err )
2014-07-26 10:28:04 +04:00
return
}
ctx . JSON ( 200 , map [ string ] interface { } {
"ok" : true ,
} )
}
2015-08-14 19:42:43 +03:00
func UpdateIssueAssignee ( ctx * middleware . Context ) {
issue := getActionIssue ( ctx )
if ctx . Written ( ) {
2014-07-26 10:28:04 +04:00
return
}
2015-08-14 19:42:43 +03:00
aid := ctx . QueryInt64 ( "id" )
if issue . AssigneeID == aid {
ctx . JSON ( 200 , map [ string ] interface { } {
"ok" : true ,
} )
2014-07-26 10:28:04 +04:00
return
}
2014-12-07 04:22:48 +03:00
// Not check for invalid assignee id and give responsibility to owners.
2015-08-05 15:23:08 +03:00
issue . AssigneeID = aid
2015-08-14 19:42:43 +03:00
if err := models . UpdateIssueUserByAssignee ( issue ) ; err != nil {
ctx . Handle ( 500 , "UpdateIssueUserByAssignee: %v" , err )
2014-07-26 10:28:04 +04:00
return
}
ctx . JSON ( 200 , map [ string ] interface { } {
"ok" : true ,
} )
}
2015-08-13 11:07:11 +03:00
func NewComment ( ctx * middleware . Context , form auth . CreateCommentForm ) {
issue , err := models . GetIssueByIndex ( ctx . Repo . Repository . ID , ctx . ParamsInt64 ( ":index" ) )
2014-07-26 10:28:04 +04:00
if err != nil {
2015-08-12 12:04:23 +03:00
if models . IsErrIssueNotExist ( err ) {
2015-08-13 11:07:11 +03:00
ctx . Handle ( 404 , "GetIssueByIndex" , err )
2014-07-26 10:28:04 +04:00
} else {
2015-08-13 11:07:11 +03:00
ctx . Handle ( 500 , "GetIssueByIndex" , err )
2014-07-26 10:28:04 +04:00
}
return
}
2015-10-25 10:10:22 +03:00
if issue . IsPull {
if err = issue . GetPullRequest ( ) ; err != nil {
ctx . Handle ( 500 , "GetPullRequest" , err )
return
}
}
2014-07-26 10:28:04 +04:00
2015-08-13 11:07:11 +03:00
var attachments [ ] string
if setting . AttachmentEnabled {
attachments = form . Attachments
2014-07-26 10:28:04 +04:00
}
2015-08-13 11:07:11 +03:00
if ctx . HasError ( ) {
ctx . Flash . Error ( ctx . Data [ "ErrorMsg" ] . ( string ) )
ctx . Redirect ( fmt . Sprintf ( "%s/issues/%d" , ctx . Repo . RepoLink , issue . Index ) )
return
2014-07-26 10:28:04 +04:00
}
2015-10-19 02:30:39 +03:00
var comment * models . Comment
2015-09-13 18:26:25 +03:00
defer func ( ) {
2015-11-01 01:59:07 +03:00
// Check if issue admin/poster changes the status of issue.
if ( ctx . Repo . IsAdmin ( ) || ( ctx . IsSigned && issue . IsPoster ( ctx . User . Id ) ) ) &&
2015-09-13 18:26:25 +03:00
( form . Status == "reopen" || form . Status == "close" ) &&
! ( issue . IsPull && issue . HasMerged ) {
2015-10-19 02:30:39 +03:00
2015-10-25 10:10:22 +03:00
// Duplication and conflict check should apply to reopen pull request.
2015-10-19 02:30:39 +03:00
var pr * models . PullRequest
2015-10-23 17:31:13 +03:00
if form . Status == "reopen" && issue . IsPull {
2015-10-19 02:30:39 +03:00
pull := issue . PullRequest
pr , err = models . GetUnmergedPullRequest ( pull . HeadRepoID , pull . BaseRepoID , pull . HeadBranch , pull . BaseBranch )
if err != nil {
if ! models . IsErrPullRequestNotExist ( err ) {
ctx . Handle ( 500 , "GetUnmergedPullRequest" , err )
return
}
}
2015-10-25 10:10:22 +03:00
// Regenerate patch and test conflict.
if pr == nil {
if err = issue . UpdatePatch ( ) ; err != nil {
ctx . Handle ( 500 , "UpdatePatch" , err )
return
}
issue . AddToTaskQueue ( )
}
2015-10-19 02:30:39 +03:00
}
if pr != nil {
ctx . Flash . Info ( ctx . Tr ( "repo.pulls.open_unmerged_pull_exists" , pr . Index ) )
2015-09-13 18:26:25 +03:00
} else {
2015-10-19 02:30:39 +03:00
issue . Repo = ctx . Repo . Repository
if err = issue . ChangeStatus ( ctx . User , form . Status == "close" ) ; err != nil {
log . Error ( 4 , "ChangeStatus: %v" , err )
} else {
2015-10-23 19:54:19 +03:00
log . Trace ( "Issue[%d] status changed to closed: %v" , issue . ID , issue . IsClosed )
2015-10-19 02:30:39 +03:00
}
2015-09-13 18:26:25 +03:00
}
}
2015-10-19 02:30:39 +03:00
// Redirect to comment hashtag if there is any actual content.
typeName := "issues"
if issue . IsPull {
typeName = "pulls"
}
if comment != nil {
ctx . Redirect ( fmt . Sprintf ( "%s/%s/%d#%s" , ctx . Repo . RepoLink , typeName , issue . Index , comment . HashTag ( ) ) )
} else {
ctx . Redirect ( fmt . Sprintf ( "%s/%s/%d" , ctx . Repo . RepoLink , typeName , issue . Index ) )
}
2015-09-13 18:26:25 +03:00
} ( )
2015-08-13 11:07:11 +03:00
// Fix #321: Allow empty comments, as long as we have attachments.
if len ( form . Content ) == 0 && len ( attachments ) == 0 {
return
2014-07-26 10:28:04 +04:00
}
2015-10-19 02:30:39 +03:00
comment , err = models . CreateIssueComment ( ctx . User , ctx . Repo . Repository , issue , form . Content , attachments )
2015-08-13 11:07:11 +03:00
if err != nil {
ctx . Handle ( 500 , "CreateIssueComment" , err )
2014-07-26 10:28:04 +04:00
return
}
2015-12-10 19:18:56 +03:00
notifyWatchersAndMentions ( ctx , & models . Issue {
2015-10-30 03:40:57 +03:00
ID : issue . ID ,
Index : issue . Index ,
Name : issue . Name ,
Content : form . Content ,
} )
if ctx . Written ( ) {
return
2015-08-13 11:07:11 +03:00
}
log . Trace ( "Comment created: %d/%d/%d" , ctx . Repo . Repository . ID , issue . ID , comment . ID )
2014-07-26 10:28:04 +04:00
}
2015-08-19 23:31:28 +03:00
func UpdateCommentContent ( ctx * middleware . Context ) {
comment , err := models . GetCommentByID ( ctx . ParamsInt64 ( ":id" ) )
if err != nil {
if models . IsErrCommentNotExist ( err ) {
ctx . Error ( 404 , "GetCommentByID" )
} else {
ctx . Handle ( 500 , "GetCommentByID" , err )
}
return
}
if ! ctx . IsSigned || ( ctx . User . Id != comment . PosterID && ! ctx . Repo . IsAdmin ( ) ) {
ctx . Error ( 403 )
return
} else if comment . Type != models . COMMENT_TYPE_COMMENT {
ctx . Error ( 204 )
return
}
comment . Content = ctx . Query ( "content" )
if len ( comment . Content ) == 0 {
ctx . JSON ( 200 , map [ string ] interface { } {
"content" : "" ,
} )
return
}
if err := models . UpdateComment ( comment ) ; err != nil {
ctx . Handle ( 500 , "UpdateComment" , err )
return
}
ctx . JSON ( 200 , map [ string ] interface { } {
2015-12-05 05:30:33 +03:00
"content" : string ( base . RenderMarkdown ( [ ] byte ( comment . Content ) , ctx . Query ( "context" ) , ctx . Repo . Repository . ComposeMetas ( ) ) ) ,
2015-08-19 23:31:28 +03:00
} )
}
2015-07-24 16:02:49 +03:00
func Labels ( ctx * middleware . Context ) {
ctx . Data [ "Title" ] = ctx . Tr ( "repo.labels" )
2015-12-03 04:56:26 +03:00
ctx . Data [ "PageIsIssueList" ] = true
2015-07-24 16:02:49 +03:00
ctx . Data [ "PageIsLabels" ] = true
2015-08-11 12:54:00 +03:00
ctx . Data [ "RequireMinicolors" ] = true
2015-07-24 16:02:49 +03:00
ctx . HTML ( 200 , LABELS )
}
2014-07-26 10:28:04 +04:00
func NewLabel ( ctx * middleware . Context , form auth . CreateLabelForm ) {
2015-07-24 16:02:49 +03:00
ctx . Data [ "Title" ] = ctx . Tr ( "repo.labels" )
ctx . Data [ "PageIsLabels" ] = true
2014-07-26 10:28:04 +04:00
if ctx . HasError ( ) {
2015-07-24 16:02:49 +03:00
ctx . Flash . Error ( ctx . Data [ "ErrorMsg" ] . ( string ) )
ctx . Redirect ( ctx . Repo . RepoLink + "/labels" )
2014-07-26 10:28:04 +04:00
return
}
l := & models . Label {
2015-08-10 09:42:50 +03:00
RepoID : ctx . Repo . Repository . ID ,
2014-07-26 10:28:04 +04:00
Name : form . Title ,
Color : form . Color ,
}
if err := models . NewLabel ( l ) ; err != nil {
2015-07-24 16:02:49 +03:00
ctx . Handle ( 500 , "NewLabel" , err )
2014-07-26 10:28:04 +04:00
return
}
2015-07-24 16:02:49 +03:00
ctx . Redirect ( ctx . Repo . RepoLink + "/labels" )
2014-07-26 10:28:04 +04:00
}
func UpdateLabel ( ctx * middleware . Context , form auth . CreateLabelForm ) {
2015-08-10 09:42:50 +03:00
l , err := models . GetLabelByID ( form . ID )
2015-07-24 18:13:42 +03:00
if err != nil {
2015-08-10 09:42:50 +03:00
switch {
case models . IsErrLabelNotExist ( err ) :
2015-07-24 18:13:42 +03:00
ctx . Error ( 404 )
default :
ctx . Handle ( 500 , "UpdateLabel" , err )
}
2014-07-26 10:28:04 +04:00
return
}
2015-09-18 13:18:31 +03:00
fmt . Println ( form . Title , form . Color )
2015-07-24 18:13:42 +03:00
l . Name = form . Title
l . Color = form . Color
2014-07-26 10:28:04 +04:00
if err := models . UpdateLabel ( l ) ; err != nil {
2015-07-24 18:13:42 +03:00
ctx . Handle ( 500 , "UpdateLabel" , err )
2014-07-26 10:28:04 +04:00
return
}
2015-07-24 18:13:42 +03:00
ctx . Redirect ( ctx . Repo . RepoLink + "/labels" )
2014-07-26 10:28:04 +04:00
}
func DeleteLabel ( ctx * middleware . Context ) {
2015-08-08 17:43:14 +03:00
if err := models . DeleteLabel ( ctx . Repo . Repository . ID , ctx . QueryInt64 ( "id" ) ) ; err != nil {
2015-08-05 15:23:08 +03:00
ctx . Flash . Error ( "DeleteLabel: " + err . Error ( ) )
} else {
ctx . Flash . Success ( ctx . Tr ( "repo.issues.label_deletion_success" ) )
2014-07-26 10:28:04 +04:00
}
ctx . JSON ( 200 , map [ string ] interface { } {
2015-07-24 18:13:42 +03:00
"redirect" : ctx . Repo . RepoLink + "/labels" ,
2014-07-26 10:28:04 +04:00
} )
2015-07-24 18:13:42 +03:00
return
2014-07-26 10:28:04 +04:00
}
func Milestones ( ctx * middleware . Context ) {
2015-08-03 12:42:09 +03:00
ctx . Data [ "Title" ] = ctx . Tr ( "repo.milestones" )
2015-12-03 04:56:26 +03:00
ctx . Data [ "PageIsIssueList" ] = true
2015-08-03 12:42:09 +03:00
ctx . Data [ "PageIsMilestones" ] = true
2014-07-26 10:28:04 +04:00
isShowClosed := ctx . Query ( "state" ) == "closed"
2015-08-08 17:43:14 +03:00
openCount , closedCount := models . MilestoneStats ( ctx . Repo . Repository . ID )
2015-08-04 17:24:04 +03:00
ctx . Data [ "OpenCount" ] = openCount
ctx . Data [ "ClosedCount" ] = closedCount
page := ctx . QueryInt ( "page" )
if page <= 1 {
page = 1
}
var total int
if ! isShowClosed {
total = int ( openCount )
} else {
total = int ( closedCount )
}
ctx . Data [ "Page" ] = paginater . New ( total , setting . IssuePagingNum , page , 5 )
2014-07-26 10:28:04 +04:00
2015-08-08 17:43:14 +03:00
miles , err := models . GetMilestones ( ctx . Repo . Repository . ID , page , isShowClosed )
2014-07-26 10:28:04 +04:00
if err != nil {
2015-07-30 15:00:57 +03:00
ctx . Handle ( 500 , "GetMilestones" , err )
2014-07-26 10:28:04 +04:00
return
}
for _ , m := range miles {
2015-12-05 05:30:33 +03:00
m . RenderedContent = string ( base . RenderMarkdown ( [ ] byte ( m . Content ) , ctx . Repo . RepoLink , ctx . Repo . Repository . ComposeMetas ( ) ) )
2014-07-26 10:28:04 +04:00
m . CalOpenIssues ( )
}
ctx . Data [ "Milestones" ] = miles
if isShowClosed {
ctx . Data [ "State" ] = "closed"
} else {
ctx . Data [ "State" ] = "open"
}
2015-08-03 12:42:09 +03:00
ctx . Data [ "IsShowClosed" ] = isShowClosed
2014-07-26 10:28:04 +04:00
ctx . HTML ( 200 , MILESTONE )
}
func NewMilestone ( ctx * middleware . Context ) {
2015-08-05 10:24:26 +03:00
ctx . Data [ "Title" ] = ctx . Tr ( "repo.milestones.new" )
2015-12-03 04:56:26 +03:00
ctx . Data [ "PageIsIssueList" ] = true
2015-08-05 10:24:26 +03:00
ctx . Data [ "PageIsMilestones" ] = true
2015-08-11 12:54:00 +03:00
ctx . Data [ "RequireDatetimepicker" ] = true
2015-08-05 10:24:26 +03:00
ctx . Data [ "DateLang" ] = setting . DateLang ( ctx . Locale . Language ( ) )
2014-07-26 10:28:04 +04:00
ctx . HTML ( 200 , MILESTONE_NEW )
}
func NewMilestonePost ( ctx * middleware . Context , form auth . CreateMilestoneForm ) {
2015-08-05 10:24:26 +03:00
ctx . Data [ "Title" ] = ctx . Tr ( "repo.milestones.new" )
2015-12-03 04:56:26 +03:00
ctx . Data [ "PageIsIssueList" ] = true
2015-08-05 10:24:26 +03:00
ctx . Data [ "PageIsMilestones" ] = true
2015-08-11 12:54:00 +03:00
ctx . Data [ "RequireDatetimepicker" ] = true
2015-08-05 10:24:26 +03:00
ctx . Data [ "DateLang" ] = setting . DateLang ( ctx . Locale . Language ( ) )
2014-07-26 10:28:04 +04:00
if ctx . HasError ( ) {
ctx . HTML ( 200 , MILESTONE_NEW )
return
}
if len ( form . Deadline ) == 0 {
2015-08-05 15:37:14 +03:00
form . Deadline = "9999-12-31"
2014-07-26 10:28:04 +04:00
}
2016-02-06 02:10:32 +03:00
deadline , err := time . ParseInLocation ( "2006-01-02" , form . Deadline , time . Local )
2014-07-26 10:28:04 +04:00
if err != nil {
2015-08-05 10:24:26 +03:00
ctx . Data [ "Err_Deadline" ] = true
ctx . RenderWithErr ( ctx . Tr ( "repo.milestones.invalid_due_date_format" ) , MILESTONE_NEW , & form )
2014-07-26 10:28:04 +04:00
return
}
2015-08-05 10:24:26 +03:00
if err = models . NewMilestone ( & models . Milestone {
2015-08-08 17:43:14 +03:00
RepoID : ctx . Repo . Repository . ID ,
2014-07-26 10:28:04 +04:00
Name : form . Title ,
Content : form . Content ,
Deadline : deadline ,
2015-08-05 10:24:26 +03:00
} ) ; err != nil {
2015-07-30 15:00:57 +03:00
ctx . Handle ( 500 , "NewMilestone" , err )
2014-07-26 10:28:04 +04:00
return
}
2015-08-05 10:24:26 +03:00
ctx . Flash . Success ( ctx . Tr ( "repo.milestones.create_success" , form . Title ) )
2015-07-30 15:00:57 +03:00
ctx . Redirect ( ctx . Repo . RepoLink + "/milestones" )
2014-07-26 10:28:04 +04:00
}
2015-08-05 13:26:18 +03:00
func EditMilestone ( ctx * middleware . Context ) {
ctx . Data [ "Title" ] = ctx . Tr ( "repo.milestones.edit" )
ctx . Data [ "PageIsMilestones" ] = true
ctx . Data [ "PageIsEditMilestone" ] = true
2015-08-11 12:54:00 +03:00
ctx . Data [ "RequireDatetimepicker" ] = true
2015-08-05 13:26:18 +03:00
ctx . Data [ "DateLang" ] = setting . DateLang ( ctx . Locale . Language ( ) )
2015-08-06 18:25:35 +03:00
m , err := models . GetMilestoneByID ( ctx . ParamsInt64 ( ":id" ) )
2015-08-05 13:26:18 +03:00
if err != nil {
if models . IsErrMilestoneNotExist ( err ) {
2015-08-06 18:25:35 +03:00
ctx . Handle ( 404 , "GetMilestoneByID" , nil )
2015-08-05 13:26:18 +03:00
} else {
2015-08-06 18:25:35 +03:00
ctx . Handle ( 500 , "GetMilestoneByID" , err )
2015-08-05 13:26:18 +03:00
}
return
}
ctx . Data [ "title" ] = m . Name
ctx . Data [ "content" ] = m . Content
if len ( m . DeadlineString ) > 0 {
ctx . Data [ "deadline" ] = m . DeadlineString
}
ctx . HTML ( 200 , MILESTONE_NEW )
}
func EditMilestonePost ( ctx * middleware . Context , form auth . CreateMilestoneForm ) {
ctx . Data [ "Title" ] = ctx . Tr ( "repo.milestones.edit" )
ctx . Data [ "PageIsMilestones" ] = true
ctx . Data [ "PageIsEditMilestone" ] = true
2015-08-11 12:54:00 +03:00
ctx . Data [ "RequireDatetimepicker" ] = true
2015-08-05 13:26:18 +03:00
ctx . Data [ "DateLang" ] = setting . DateLang ( ctx . Locale . Language ( ) )
if ctx . HasError ( ) {
ctx . HTML ( 200 , MILESTONE_NEW )
return
}
if len ( form . Deadline ) == 0 {
form . Deadline = "9999-12-31"
}
2016-02-06 02:10:32 +03:00
deadline , err := time . ParseInLocation ( "2006-01-02" , form . Deadline , time . Local )
2015-08-05 13:26:18 +03:00
if err != nil {
ctx . Data [ "Err_Deadline" ] = true
ctx . RenderWithErr ( ctx . Tr ( "repo.milestones.invalid_due_date_format" ) , MILESTONE_NEW , & form )
return
}
2015-08-06 18:25:35 +03:00
m , err := models . GetMilestoneByID ( ctx . ParamsInt64 ( ":id" ) )
2015-08-05 13:26:18 +03:00
if err != nil {
if models . IsErrMilestoneNotExist ( err ) {
2015-08-06 18:25:35 +03:00
ctx . Handle ( 404 , "GetMilestoneByID" , nil )
2015-08-05 13:26:18 +03:00
} else {
2015-08-06 18:25:35 +03:00
ctx . Handle ( 500 , "GetMilestoneByID" , err )
2015-08-05 13:26:18 +03:00
}
return
}
m . Name = form . Title
m . Content = form . Content
m . Deadline = deadline
if err = models . UpdateMilestone ( m ) ; err != nil {
ctx . Handle ( 500 , "UpdateMilestone" , err )
return
}
ctx . Flash . Success ( ctx . Tr ( "repo.milestones.edit_success" , m . Name ) )
ctx . Redirect ( ctx . Repo . RepoLink + "/milestones" )
}
2015-08-04 17:24:04 +03:00
2015-08-05 15:23:08 +03:00
func ChangeMilestonStatus ( ctx * middleware . Context ) {
2015-08-06 18:25:35 +03:00
m , err := models . GetMilestoneByID ( ctx . ParamsInt64 ( ":id" ) )
2014-07-26 10:28:04 +04:00
if err != nil {
2015-08-05 13:26:18 +03:00
if models . IsErrMilestoneNotExist ( err ) {
2015-08-06 18:25:35 +03:00
ctx . Handle ( 404 , "GetMilestoneByID" , err )
2014-07-26 10:28:04 +04:00
} else {
2015-08-06 18:25:35 +03:00
ctx . Handle ( 500 , "GetMilestoneByID" , err )
2014-07-26 10:28:04 +04:00
}
return
}
2015-08-05 15:23:08 +03:00
switch ctx . Params ( ":action" ) {
case "open" :
if m . IsClosed {
if err = models . ChangeMilestoneStatus ( m , false ) ; err != nil {
ctx . Handle ( 500 , "ChangeMilestoneStatus" , err )
return
2014-07-26 10:28:04 +04:00
}
2015-08-05 15:23:08 +03:00
}
ctx . Redirect ( ctx . Repo . RepoLink + "/milestones?state=open" )
case "close" :
if ! m . IsClosed {
m . ClosedDate = time . Now ( )
if err = models . ChangeMilestoneStatus ( m , true ) ; err != nil {
ctx . Handle ( 500 , "ChangeMilestoneStatus" , err )
2014-07-26 10:28:04 +04:00
return
}
}
2015-08-05 15:23:08 +03:00
ctx . Redirect ( ctx . Repo . RepoLink + "/milestones?state=closed" )
default :
2015-07-30 15:00:57 +03:00
ctx . Redirect ( ctx . Repo . RepoLink + "/milestones" )
2014-07-26 10:28:04 +04:00
}
}
2015-08-05 15:23:08 +03:00
func DeleteMilestone ( ctx * middleware . Context ) {
if err := models . DeleteMilestoneByID ( ctx . QueryInt64 ( "id" ) ) ; err != nil {
2015-08-18 22:36:16 +03:00
ctx . Flash . Error ( "DeleteMilestoneByID: " + err . Error ( ) )
2015-08-05 15:23:08 +03:00
} else {
ctx . Flash . Success ( ctx . Tr ( "repo.milestones.deletion_success" ) )
2014-07-26 10:28:04 +04:00
}
2015-08-05 15:23:08 +03:00
ctx . JSON ( 200 , map [ string ] interface { } {
"redirect" : ctx . Repo . RepoLink + "/milestones" ,
} )
2014-07-26 10:28:04 +04:00
}