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
import (
2014-03-23 00:00:46 +04:00
"fmt"
2014-03-28 05:15:53 +04:00
"net/url"
2014-03-30 01:50:51 +04:00
"strings"
2014-05-12 22:06:42 +04:00
"time"
2014-03-23 00:00:46 +04:00
2014-04-07 20:56:40 +04:00
"github.com/Unknwon/com"
2014-03-30 20:11:28 +04:00
"github.com/go-martini/martini"
2014-03-22 21:50:50 +04:00
"github.com/gogits/gogs/models"
2014-03-23 00:00:46 +04:00
"github.com/gogits/gogs/modules/auth"
2014-03-22 21:50:50 +04:00
"github.com/gogits/gogs/modules/base"
2014-03-23 00:00:46 +04:00
"github.com/gogits/gogs/modules/log"
2014-03-26 05:37:18 +04:00
"github.com/gogits/gogs/modules/mailer"
2014-03-22 21:50:50 +04:00
"github.com/gogits/gogs/modules/middleware"
)
2014-03-27 20:48:29 +04:00
func Issues ( ctx * middleware . Context ) {
2014-03-23 00:00:46 +04:00
ctx . Data [ "Title" ] = "Issues"
2014-03-22 21:50:50 +04:00
ctx . Data [ "IsRepoToolbarIssues" ] = true
2014-03-26 17:47:20 +04:00
ctx . Data [ "IsRepoToolbarIssuesList" ] = true
2014-03-22 21:50:50 +04:00
2014-05-07 20:09:30 +04:00
viewType := ctx . Query ( "type" )
types := [ ] string { "assigned" , "created_by" , "mentioned" }
if ! com . IsSliceContainsStr ( types , viewType ) {
viewType = "all"
}
2014-03-22 21:50:50 +04:00
2014-05-07 20:09:30 +04:00
isShowClosed := ctx . Query ( "state" ) == "closed"
2014-03-28 04:38:49 +04:00
2014-05-09 04:00:07 +04:00
if viewType != "all" && ! ctx . IsSigned {
ctx . SetCookie ( "redirect_to" , "/" + url . QueryEscape ( ctx . Req . RequestURI ) )
ctx . Redirect ( "/user/login" )
return
2014-03-28 00:31:32 +04:00
}
2014-05-07 20:09:30 +04:00
var assigneeId , posterId int64
var filterMode int
switch viewType {
case "assigned" :
assigneeId = ctx . User . Id
filterMode = models . FM_ASSIGN
case "created_by" :
posterId = ctx . User . Id
filterMode = models . FM_CREATE
case "mentioned" :
filterMode = models . FM_MENTION
}
2014-05-14 19:14:51 +04:00
var mid int64
2014-05-14 18:55:36 +04:00
midx , _ := base . StrTo ( ctx . Query ( "milestone" ) ) . Int64 ( )
2014-05-14 19:14:51 +04:00
if midx > 0 {
mile , err := models . GetMilestoneByIndex ( ctx . Repo . Repository . Id , midx )
if err != nil {
ctx . Handle ( 500 , "issue.Issues(GetMilestoneByIndex): %v" , err )
return
}
mid = mile . Id
2014-05-14 18:55:36 +04:00
}
2014-05-14 21:04:57 +04:00
fmt . Println ( mid )
2014-05-14 18:55:36 +04:00
2014-05-07 20:09:30 +04:00
page , _ := base . StrTo ( ctx . Query ( "page" ) ) . Int ( )
2014-03-25 22:04:57 +04:00
// Get issues.
2014-05-14 19:14:51 +04:00
issues , err := models . GetIssues ( assigneeId , ctx . Repo . Repository . Id , posterId , mid , page ,
2014-05-07 20:09:30 +04:00
isShowClosed , ctx . Query ( "labels" ) , ctx . Query ( "sortType" ) )
2014-03-22 21:50:50 +04:00
if err != nil {
2014-05-07 20:09:30 +04:00
ctx . Handle ( 500 , "issue.Issues(GetIssues): %v" , err )
2014-03-22 21:50:50 +04:00
return
}
2014-03-25 22:04:57 +04:00
2014-05-08 00:51:14 +04:00
// Get issue-user pairs.
2014-05-08 04:36:00 +04:00
pairs , err := models . GetIssueUserPairs ( ctx . Repo . Repository . Id , posterId , isShowClosed )
2014-05-08 00:51:14 +04:00
if err != nil {
ctx . Handle ( 500 , "issue.Issues(GetIssueUserPairs): %v" , err )
return
2014-03-28 17:16:12 +04:00
}
2014-03-25 22:04:57 +04:00
// Get posters.
for i := range issues {
2014-05-08 00:51:14 +04:00
idx := models . PairsContains ( pairs , issues [ i ] . Id )
if filterMode == models . FM_MENTION && ( idx == - 1 || ! pairs [ idx ] . IsMentioned ) {
2014-04-02 18:38:30 +04:00
continue
}
2014-05-07 20:09:30 +04:00
2014-05-08 00:51:14 +04:00
if idx > - 1 {
issues [ i ] . IsRead = pairs [ idx ] . IsRead
} else {
issues [ i ] . IsRead = true
}
2014-05-07 20:09:30 +04:00
if err = issues [ i ] . GetPoster ( ) ; err != nil {
2014-05-09 04:00:07 +04:00
ctx . Handle ( 500 , "issue.Issues(GetPoster)" , fmt . Errorf ( "[#%d]%v" , issues [ i ] . Id , err ) )
2014-05-07 20:09:30 +04:00
return
2014-03-28 17:16:12 +04:00
}
2014-03-25 22:04:57 +04:00
}
2014-05-07 20:09:30 +04:00
var uid int64 = - 1
if ctx . User != nil {
uid = ctx . User . Id
}
issueStats := models . GetIssueStats ( ctx . Repo . Repository . Id , uid , isShowClosed , filterMode )
ctx . Data [ "IssueStats" ] = issueStats
ctx . Data [ "ViewType" ] = viewType
ctx . Data [ "Issues" ] = issues
ctx . Data [ "IsShowClosed" ] = isShowClosed
if isShowClosed {
ctx . Data [ "State" ] = "closed"
ctx . Data [ "ShowCount" ] = issueStats . ClosedCount
} else {
ctx . Data [ "ShowCount" ] = issueStats . OpenCount
}
2014-03-25 20:12:27 +04:00
ctx . HTML ( 200 , "issue/list" )
2014-03-22 21:50:50 +04:00
}
2014-03-22 22:27:03 +04:00
2014-04-11 02:09:57 +04:00
func CreateIssue ( ctx * middleware . Context , params martini . Params ) {
2014-03-23 00:00:46 +04:00
ctx . Data [ "Title" ] = "Create issue"
2014-03-25 14:27:29 +04:00
ctx . Data [ "IsRepoToolbarIssues" ] = true
2014-03-26 16:02:04 +04:00
ctx . Data [ "IsRepoToolbarIssuesList" ] = false
2014-05-08 20:24:11 +04:00
2014-05-14 19:14:51 +04:00
var err error
// Get all milestones.
ctx . Data [ "OpenMilestones" ] , err = models . GetMilestones ( ctx . Repo . Repository . Id , false )
if err != nil {
ctx . Handle ( 500 , "issue.ViewIssue(GetMilestones.1): %v" , err )
return
}
ctx . Data [ "ClosedMilestones" ] , err = models . GetMilestones ( ctx . Repo . Repository . Id , true )
if err != nil {
ctx . Handle ( 500 , "issue.ViewIssue(GetMilestones.2): %v" , err )
return
}
2014-05-08 20:24:11 +04:00
us , err := models . GetCollaborators ( strings . TrimPrefix ( ctx . Repo . RepoLink , "/" ) )
if err != nil {
ctx . Handle ( 500 , "issue.CreateIssue(GetCollaborators)" , err )
return
}
ctx . Data [ "Collaborators" ] = us
2014-04-11 02:09:57 +04:00
ctx . HTML ( 200 , "issue/create" )
}
2014-03-23 00:00:46 +04:00
2014-04-11 02:09:57 +04:00
func CreateIssuePost ( ctx * middleware . Context , params martini . Params , form auth . CreateIssueForm ) {
ctx . Data [ "Title" ] = "Create issue"
ctx . Data [ "IsRepoToolbarIssues" ] = true
ctx . Data [ "IsRepoToolbarIssuesList" ] = false
2014-03-23 00:00:46 +04:00
2014-05-14 19:14:51 +04:00
var err error
// Get all milestones.
ctx . Data [ "OpenMilestones" ] , err = models . GetMilestones ( ctx . Repo . Repository . Id , false )
if err != nil {
ctx . Handle ( 500 , "issue.ViewIssue(GetMilestones.1): %v" , err )
return
}
ctx . Data [ "ClosedMilestones" ] , err = models . GetMilestones ( ctx . Repo . Repository . Id , true )
if err != nil {
ctx . Handle ( 500 , "issue.ViewIssue(GetMilestones.2): %v" , err )
return
}
2014-05-08 20:24:11 +04:00
us , err := models . GetCollaborators ( strings . TrimPrefix ( ctx . Repo . RepoLink , "/" ) )
if err != nil {
ctx . Handle ( 500 , "issue.CreateIssue(GetCollaborators)" , err )
return
}
ctx . Data [ "Collaborators" ] = us
2014-03-23 00:00:46 +04:00
if ctx . HasError ( ) {
ctx . HTML ( 200 , "issue/create" )
return
}
2014-05-09 01:17:45 +04:00
// Only collaborators can assign.
if ! ctx . Repo . IsOwner {
form . AssigneeId = 0
}
2014-05-07 20:09:30 +04:00
issue := & models . Issue {
2014-05-12 22:06:42 +04:00
RepoId : ctx . Repo . Repository . Id ,
2014-05-07 20:09:30 +04:00
Index : int64 ( ctx . Repo . Repository . NumIssues ) + 1 ,
Name : form . IssueName ,
PosterId : ctx . User . Id ,
MilestoneId : form . MilestoneId ,
AssigneeId : form . AssigneeId ,
Labels : form . Labels ,
Content : form . Content ,
}
if err := models . NewIssue ( issue ) ; err != nil {
ctx . Handle ( 500 , "issue.CreateIssue(NewIssue)" , err )
2014-03-23 00:00:46 +04:00
return
2014-05-08 20:24:11 +04:00
} else if err := models . NewIssueUserPairs ( issue . RepoId , issue . Id , ctx . Repo . Owner . Id ,
ctx . User . Id , form . AssigneeId , ctx . Repo . Repository . Name ) ; err != nil {
2014-05-08 00:51:14 +04:00
ctx . Handle ( 500 , "issue.CreateIssue(NewIssueUserPairs)" , err )
return
}
// Update mentions.
ms := base . MentionPattern . FindAllString ( issue . Content , - 1 )
if len ( ms ) > 0 {
for i := range ms {
ms [ i ] = ms [ i ] [ 1 : ]
}
ids := models . GetUserIdsByNames ( ms )
if err := models . UpdateIssueUserPairsByMentions ( ids , issue . Id ) ; err != nil {
ctx . Handle ( 500 , "issue.CreateIssue(UpdateIssueUserPairsByMentions)" , err )
return
}
2014-03-23 00:00:46 +04:00
}
2014-03-25 22:04:57 +04:00
2014-05-09 03:17:43 +04:00
act := & models . Action {
ActUserId : ctx . User . Id ,
ActUserName : ctx . User . Name ,
ActEmail : ctx . User . Email ,
OpType : models . OP_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 ,
}
2014-03-25 22:04:57 +04:00
// Notify watchers.
2014-05-09 03:17:43 +04:00
if err := models . NotifyWatchers ( act ) ; err != nil {
2014-04-11 02:09:57 +04:00
ctx . Handle ( 500 , "issue.CreateIssue(NotifyWatchers)" , err )
2014-03-25 22:04:57 +04:00
return
}
2014-04-07 20:56:40 +04:00
// Mail watchers and mentions.
2014-03-26 05:37:18 +04:00
if base . Service . NotifyMail {
2014-04-07 20:56:40 +04:00
tos , err := mailer . SendIssueNotifyMail ( ctx . User , ctx . Repo . Owner , ctx . Repo . Repository , issue )
if err != nil {
2014-04-11 02:09:57 +04:00
ctx . Handle ( 500 , "issue.CreateIssue(SendIssueNotifyMail)" , err )
2014-04-07 20:56:40 +04:00
return
}
tos = append ( tos , ctx . User . LowerName )
newTos := make ( [ ] string , 0 , len ( ms ) )
for _ , m := range ms {
2014-05-08 00:51:14 +04:00
if com . IsSliceContainsStr ( tos , m ) {
2014-04-07 20:56:40 +04:00
continue
}
2014-05-08 00:51:14 +04:00
newTos = append ( newTos , m )
2014-04-07 20:56:40 +04:00
}
2014-05-05 12:27:28 +04:00
if err = mailer . SendIssueMentionMail ( ctx . Render , ctx . User , ctx . Repo . Owner ,
ctx . Repo . Repository , issue , models . GetUserEmailsByNames ( newTos ) ) ; err != nil {
2014-04-11 02:09:57 +04:00
ctx . Handle ( 500 , "issue.CreateIssue(SendIssueMentionMail)" , err )
2014-03-26 05:37:18 +04:00
return
}
}
2014-03-25 22:04:57 +04:00
log . Trace ( "%d Issue created: %d" , ctx . Repo . Repository . Id , issue . Id )
2014-04-11 02:09:57 +04:00
2014-03-25 22:04:57 +04:00
ctx . Redirect ( fmt . Sprintf ( "/%s/%s/issues/%d" , params [ "username" ] , params [ "reponame" ] , issue . Index ) )
2014-03-23 00:00:46 +04:00
}
func ViewIssue ( ctx * middleware . Context , params martini . Params ) {
2014-05-07 20:09:30 +04:00
idx , _ := base . StrTo ( params [ "index" ] ) . Int64 ( )
if idx == 0 {
ctx . Handle ( 404 , "issue.ViewIssue" , nil )
2014-03-23 00:00:46 +04:00
return
}
2014-05-07 20:09:30 +04:00
issue , err := models . GetIssueByIndex ( ctx . Repo . Repository . Id , idx )
2014-03-23 00:00:46 +04:00
if err != nil {
if err == models . ErrIssueNotExist {
2014-05-09 01:17:45 +04:00
ctx . Handle ( 404 , "issue.ViewIssue(GetIssueByIndex)" , err )
2014-03-23 00:00:46 +04:00
} else {
2014-05-09 01:17:45 +04:00
ctx . Handle ( 500 , "issue.ViewIssue(GetIssueByIndex)" , err )
2014-03-23 00:00:46 +04:00
}
return
}
2014-05-14 18:55:36 +04:00
// Get assigned milestone.
if issue . MilestoneId > 0 {
ctx . Data [ "Milestone" ] , err = models . GetMilestoneById ( issue . MilestoneId )
if err != nil {
if err == models . ErrMilestoneNotExist {
log . Warn ( "issue.ViewIssue(GetMilestoneById): %v" , err )
} else {
ctx . Handle ( 500 , "issue.ViewIssue(GetMilestoneById)" , err )
return
}
}
}
// Get all milestones.
ctx . Data [ "OpenMilestones" ] , err = models . GetMilestones ( ctx . Repo . Repository . Id , false )
if err != nil {
ctx . Handle ( 500 , "issue.ViewIssue(GetMilestones.1): %v" , err )
return
}
ctx . Data [ "ClosedMilestones" ] , err = models . GetMilestones ( ctx . Repo . Repository . Id , true )
if err != nil {
ctx . Handle ( 500 , "issue.ViewIssue(GetMilestones.2): %v" , err )
return
}
// Get all collaborators.
ctx . Data [ "Collaborators" ] , err = models . GetCollaborators ( strings . TrimPrefix ( ctx . Repo . RepoLink , "/" ) )
2014-05-11 21:46:36 +04:00
if err != nil {
ctx . Handle ( 500 , "issue.CreateIssue(GetCollaborators)" , err )
return
2014-05-09 01:17:45 +04:00
}
2014-05-09 14:37:32 +04:00
if ctx . IsSigned {
// Update issue-user.
if err = models . UpdateIssueUserPairByRead ( ctx . User . Id , issue . Id ) ; err != nil {
ctx . Handle ( 500 , "issue.ViewIssue(UpdateIssueUserPairByRead): %v" , err )
return
}
2014-05-08 00:51:14 +04:00
}
2014-05-08 20:24:11 +04:00
// Get poster and Assignee.
if err = issue . GetPoster ( ) ; err != nil {
ctx . Handle ( 500 , "issue.ViewIssue(GetPoster): %v" , err )
return
} else if err = issue . GetAssignee ( ) ; err != nil {
ctx . Handle ( 500 , "issue.ViewIssue(GetAssignee): %v" , err )
2014-03-26 20:31:01 +04:00
return
}
2014-04-07 09:55:22 +04:00
issue . RenderedContent = string ( base . RenderMarkdown ( [ ] byte ( issue . Content ) , ctx . Repo . RepoLink ) )
2014-03-26 20:31:01 +04:00
// Get comments.
comments , err := models . GetIssueComments ( issue . Id )
if err != nil {
2014-05-07 20:09:30 +04:00
ctx . Handle ( 500 , "issue.ViewIssue(GetIssueComments): %v" , err )
2014-03-26 20:31:01 +04:00
return
}
// Get posters.
for i := range comments {
u , err := models . GetUserById ( comments [ i ] . PosterId )
if err != nil {
2014-05-09 01:17:45 +04:00
ctx . Handle ( 500 , "issue.ViewIssue(GetUserById.2): %v" , err )
2014-03-26 20:31:01 +04:00
return
}
comments [ i ] . Poster = u
2014-04-07 09:55:22 +04:00
comments [ i ] . Content = string ( base . RenderMarkdown ( [ ] byte ( comments [ i ] . Content ) , ctx . Repo . RepoLink ) )
2014-03-26 20:31:01 +04:00
}
2014-03-23 00:00:46 +04:00
ctx . Data [ "Title" ] = issue . Name
ctx . Data [ "Issue" ] = issue
2014-03-26 20:31:01 +04:00
ctx . Data [ "Comments" ] = comments
2014-03-31 00:34:23 +04:00
ctx . Data [ "IsIssueOwner" ] = ctx . Repo . IsOwner || ( ctx . IsSigned && issue . PosterId == ctx . User . Id )
2014-03-26 16:02:04 +04:00
ctx . Data [ "IsRepoToolbarIssues" ] = true
ctx . Data [ "IsRepoToolbarIssuesList" ] = false
2014-03-23 00:00:46 +04:00
ctx . HTML ( 200 , "issue/view" )
2014-03-22 22:27:03 +04:00
}
2014-03-24 03:09:11 +04:00
func UpdateIssue ( ctx * middleware . Context , params martini . Params , form auth . CreateIssueForm ) {
2014-05-11 21:46:36 +04:00
idx , err := base . StrTo ( params [ "index" ] ) . Int ( )
2014-03-24 03:09:11 +04:00
if err != nil {
2014-05-11 21:46:36 +04:00
ctx . Error ( 404 )
2014-03-24 03:09:11 +04:00
return
}
2014-05-11 21:46:36 +04:00
issue , err := models . GetIssueByIndex ( ctx . Repo . Repository . Id , int64 ( idx ) )
2014-03-24 03:09:11 +04:00
if err != nil {
if err == models . ErrIssueNotExist {
ctx . Handle ( 404 , "issue.UpdateIssue" , err )
} else {
2014-05-11 21:46:36 +04:00
ctx . Handle ( 500 , "issue.UpdateIssue(GetIssueByIndex)" , err )
2014-03-24 03:09:11 +04:00
}
return
}
2014-04-07 09:55:22 +04:00
if ctx . User . Id != issue . PosterId && ! ctx . Repo . IsOwner {
2014-03-26 15:42:08 +04:00
ctx . Handle ( 404 , "issue.UpdateIssue" , nil )
return
}
2014-03-24 03:09:11 +04:00
issue . Name = form . IssueName
issue . MilestoneId = form . MilestoneId
issue . AssigneeId = form . AssigneeId
issue . Labels = form . Labels
issue . Content = form . Content
if err = models . UpdateIssue ( issue ) ; err != nil {
2014-05-11 21:46:36 +04:00
ctx . Handle ( 500 , "issue.UpdateIssue(UpdateIssue)" , err )
2014-03-24 03:09:11 +04:00
return
}
2014-03-29 18:24:42 +04:00
ctx . JSON ( 200 , map [ string ] interface { } {
2014-03-29 19:56:00 +04:00
"ok" : true ,
"title" : issue . Name ,
2014-04-07 09:55:22 +04:00
"content" : string ( base . RenderMarkdown ( [ ] byte ( issue . Content ) , ctx . Repo . RepoLink ) ) ,
2014-03-29 18:24:42 +04:00
} )
2014-03-24 03:09:11 +04:00
}
2014-03-26 20:31:01 +04:00
2014-05-14 18:55:36 +04:00
func UpdateIssueMilestone ( ctx * middleware . Context ) {
if ! ctx . Repo . IsOwner {
ctx . Error ( 403 )
return
}
issueId , err := base . StrTo ( ctx . Query ( "issue" ) ) . Int64 ( )
if err != nil {
ctx . Error ( 404 )
return
}
issue , err := models . GetIssueById ( issueId )
if err != nil {
if err == models . ErrIssueNotExist {
ctx . Handle ( 404 , "issue.UpdateIssueMilestone(GetIssueById)" , err )
} else {
ctx . Handle ( 500 , "issue.UpdateIssueMilestone(GetIssueById)" , err )
}
return
}
oldMid := issue . MilestoneId
mid , _ := base . StrTo ( ctx . Query ( "milestone" ) ) . Int64 ( )
if oldMid == mid {
ctx . JSON ( 200 , map [ string ] interface { } {
"ok" : true ,
} )
return
}
// Not check for invalid milestone id and give responsibility to owners.
issue . MilestoneId = mid
if err = models . ChangeMilestoneAssign ( oldMid , mid , issue . IsClosed ) ; err != nil {
ctx . Handle ( 500 , "issue.UpdateIssueMilestone(ChangeMilestoneAssign)" , err )
return
} else if err = models . UpdateIssue ( issue ) ; err != nil {
ctx . Handle ( 500 , "issue.UpdateIssueMilestone(UpdateIssue)" , err )
return
}
ctx . JSON ( 200 , map [ string ] interface { } {
"ok" : true ,
} )
}
2014-05-11 21:46:36 +04:00
func UpdateAssignee ( ctx * middleware . Context ) {
if ! ctx . Repo . IsOwner {
ctx . Error ( 403 )
return
}
2014-05-14 16:51:04 +04:00
issueId , err := base . StrTo ( ctx . Query ( "issue" ) ) . Int64 ( )
2014-05-11 21:46:36 +04:00
if err != nil {
ctx . Error ( 404 )
return
}
2014-05-14 16:51:04 +04:00
issue , err := models . GetIssueById ( issueId )
2014-05-11 21:46:36 +04:00
if err != nil {
if err == models . ErrIssueNotExist {
2014-05-14 16:51:04 +04:00
ctx . Handle ( 404 , "issue.UpdateAssignee(GetIssueById)" , err )
2014-05-11 21:46:36 +04:00
} else {
2014-05-14 16:51:04 +04:00
ctx . Handle ( 500 , "issue.UpdateAssignee(GetIssueById)" , err )
2014-05-11 21:46:36 +04:00
}
return
}
aid , _ := base . StrTo ( ctx . Query ( "assigneeid" ) ) . Int64 ( )
// Not check for invalid assignne id and give responsibility to owners.
issue . AssigneeId = aid
if err = models . UpdateIssueUserPairByAssignee ( aid , issue . Id ) ; err != nil {
ctx . Handle ( 500 , "issue.UpdateAssignee(UpdateIssueUserPairByAssignee): %v" , err )
return
} else if err = models . UpdateIssue ( issue ) ; err != nil {
ctx . Handle ( 500 , "issue.UpdateAssignee(UpdateIssue)" , err )
return
}
ctx . JSON ( 200 , map [ string ] interface { } {
"ok" : true ,
} )
}
2014-03-26 20:31:01 +04:00
func Comment ( ctx * middleware . Context , params martini . Params ) {
2014-03-30 01:50:51 +04:00
index , err := base . StrTo ( ctx . Query ( "issueIndex" ) ) . Int64 ( )
2014-03-26 20:31:01 +04:00
if err != nil {
2014-03-30 01:50:51 +04:00
ctx . Handle ( 404 , "issue.Comment(get index)" , err )
2014-03-26 20:31:01 +04:00
return
}
2014-03-30 01:50:51 +04:00
issue , err := models . GetIssueByIndex ( ctx . Repo . Repository . Id , index )
2014-03-26 20:31:01 +04:00
if err != nil {
if err == models . ErrIssueNotExist {
ctx . Handle ( 404 , "issue.Comment" , err )
} else {
ctx . Handle ( 200 , "issue.Comment(get issue)" , err )
}
return
}
2014-03-30 01:50:51 +04:00
// Check if issue owner changes the status of issue.
var newStatus string
if ctx . Repo . IsOwner || issue . PosterId == ctx . User . Id {
newStatus = ctx . Query ( "change_status" )
}
if len ( newStatus ) > 0 {
if ( strings . Contains ( newStatus , "Reopen" ) && issue . IsClosed ) ||
( strings . Contains ( newStatus , "Close" ) && ! issue . IsClosed ) {
issue . IsClosed = ! issue . IsClosed
if err = models . UpdateIssue ( issue ) ; err != nil {
2014-05-08 00:51:14 +04:00
ctx . Handle ( 500 , "issue.Comment(UpdateIssue)" , err )
return
} else if err = models . UpdateIssueUserPairsByStatus ( issue . Id , issue . IsClosed ) ; err != nil {
ctx . Handle ( 500 , "issue.Comment(UpdateIssueUserPairsByStatus)" , err )
2014-03-30 01:50:51 +04:00
return
}
cmtType := models . IT_CLOSE
if ! issue . IsClosed {
cmtType = models . IT_REOPEN
}
if err = models . CreateComment ( ctx . User . Id , ctx . Repo . Repository . Id , issue . Id , 0 , 0 , cmtType , "" ) ; err != nil {
ctx . Handle ( 200 , "issue.Comment(create status change comment)" , err )
return
}
log . Trace ( "%s Issue(%d) status changed: %v" , ctx . Req . RequestURI , issue . Id , ! issue . IsClosed )
}
}
2014-05-08 00:51:14 +04:00
var ms [ ] string
2014-03-30 01:50:51 +04:00
content := ctx . Query ( "content" )
if len ( content ) > 0 {
switch params [ "action" ] {
case "new" :
if err = models . CreateComment ( ctx . User . Id , ctx . Repo . Repository . Id , issue . Id , 0 , 0 , models . IT_PLAIN , content ) ; err != nil {
ctx . Handle ( 500 , "issue.Comment(create comment)" , err )
return
}
2014-05-08 00:51:14 +04:00
// Update mentions.
ms = base . MentionPattern . FindAllString ( issue . Content , - 1 )
if len ( ms ) > 0 {
for i := range ms {
ms [ i ] = ms [ i ] [ 1 : ]
}
ids := models . GetUserIdsByNames ( ms )
if err := models . UpdateIssueUserPairsByMentions ( ids , issue . Id ) ; err != nil {
ctx . Handle ( 500 , "issue.CreateIssue(UpdateIssueUserPairsByMentions)" , err )
return
}
}
2014-03-30 01:50:51 +04:00
log . Trace ( "%s Comment created: %d" , ctx . Req . RequestURI , issue . Id )
default :
ctx . Handle ( 404 , "issue.Comment" , err )
2014-03-26 20:31:01 +04:00
return
}
}
2014-05-06 21:47:47 +04:00
// Notify watchers.
if err = models . NotifyWatchers ( & models . Action { ActUserId : ctx . User . Id , ActUserName : ctx . User . Name , ActEmail : ctx . User . Email ,
OpType : models . OP_COMMENT_ISSUE , Content : fmt . Sprintf ( "%d|%s" , issue . Index , strings . Split ( content , "\n" ) [ 0 ] ) ,
RepoId : ctx . Repo . Repository . Id , RepoName : ctx . Repo . Repository . Name , RefName : "" } ) ; err != nil {
ctx . Handle ( 500 , "issue.CreateIssue(NotifyWatchers)" , err )
return
}
// Mail watchers and mentions.
if base . Service . NotifyMail {
issue . Content = content
tos , err := mailer . SendIssueNotifyMail ( ctx . User , ctx . Repo . Owner , ctx . Repo . Repository , issue )
if err != nil {
ctx . Handle ( 500 , "issue.Comment(SendIssueNotifyMail)" , err )
return
}
tos = append ( tos , ctx . User . LowerName )
newTos := make ( [ ] string , 0 , len ( ms ) )
for _ , m := range ms {
2014-05-08 00:51:14 +04:00
if com . IsSliceContainsStr ( tos , m ) {
2014-05-06 21:47:47 +04:00
continue
}
2014-05-08 00:51:14 +04:00
newTos = append ( newTos , m )
2014-05-06 21:47:47 +04:00
}
if err = mailer . SendIssueMentionMail ( ctx . Render , ctx . User , ctx . Repo . Owner ,
ctx . Repo . Repository , issue , models . GetUserEmailsByNames ( newTos ) ) ; err != nil {
ctx . Handle ( 500 , "issue.Comment(SendIssueMentionMail)" , err )
return
}
}
2014-05-03 01:30:59 +04:00
ctx . Redirect ( fmt . Sprintf ( "%s/issues/%d" , ctx . Repo . RepoLink , index ) )
2014-03-26 20:31:01 +04:00
}
2014-05-07 17:01:00 +04:00
func Milestones ( ctx * middleware . Context ) {
ctx . Data [ "Title" ] = "Milestones"
ctx . Data [ "IsRepoToolbarIssues" ] = true
ctx . Data [ "IsRepoToolbarIssuesList" ] = true
2014-05-12 22:06:42 +04:00
isShowClosed := ctx . Query ( "state" ) == "closed"
miles , err := models . GetMilestones ( ctx . Repo . Repository . Id , isShowClosed )
if err != nil {
ctx . Handle ( 500 , "issue.Milestones(GetMilestones)" , err )
return
}
for _ , m := range miles {
m . RenderedContent = string ( base . RenderSpecialLink ( [ ] byte ( m . Content ) , ctx . Repo . RepoLink ) )
m . CalOpenIssues ( )
}
ctx . Data [ "Milestones" ] = miles
if isShowClosed {
ctx . Data [ "State" ] = "closed"
} else {
ctx . Data [ "State" ] = "open"
}
2014-05-07 17:01:00 +04:00
ctx . HTML ( 200 , "issue/milestone" )
}
2014-05-09 18:33:07 +04:00
2014-05-12 22:06:42 +04:00
func NewMilestone ( ctx * middleware . Context ) {
ctx . Data [ "Title" ] = "New Milestone"
2014-05-09 18:33:07 +04:00
ctx . Data [ "IsRepoToolbarIssues" ] = true
ctx . Data [ "IsRepoToolbarIssuesList" ] = true
ctx . HTML ( 200 , "issue/milestone_new" )
}
2014-05-12 17:51:22 +04:00
2014-05-12 22:06:42 +04:00
func NewMilestonePost ( ctx * middleware . Context , form auth . CreateMilestoneForm ) {
ctx . Data [ "Title" ] = "New Milestone"
ctx . Data [ "IsRepoToolbarIssues" ] = true
ctx . Data [ "IsRepoToolbarIssuesList" ] = true
var deadline time . Time
var err error
if len ( form . Deadline ) == 0 {
2014-05-13 21:28:21 +04:00
form . Deadline = "12/31/9999"
}
deadline , err = time . Parse ( "01/02/2006" , form . Deadline )
if err != nil {
ctx . Handle ( 500 , "issue.NewMilestonePost(time.Parse)" , err )
return
2014-05-12 22:06:42 +04:00
}
2014-05-13 21:28:21 +04:00
mile := & models . Milestone {
2014-05-12 22:06:42 +04:00
RepoId : ctx . Repo . Repository . Id ,
Index : int64 ( ctx . Repo . Repository . NumMilestones ) + 1 ,
Name : form . Title ,
Content : form . Content ,
Deadline : deadline ,
}
2014-05-13 21:28:21 +04:00
if err = models . NewMilestone ( mile ) ; err != nil {
2014-05-12 22:06:42 +04:00
ctx . Handle ( 500 , "issue.NewMilestonePost(NewMilestone)" , err )
return
}
ctx . Redirect ( ctx . Repo . RepoLink + "/issues/milestones" )
}
2014-05-13 21:28:21 +04:00
func UpdateMilestone ( ctx * middleware . Context , params martini . Params ) {
ctx . Data [ "Title" ] = "Update Milestone"
2014-05-12 17:51:22 +04:00
ctx . Data [ "IsRepoToolbarIssues" ] = true
ctx . Data [ "IsRepoToolbarIssuesList" ] = true
2014-05-13 21:28:21 +04:00
idx , _ := base . StrTo ( params [ "index" ] ) . Int64 ( )
if idx == 0 {
ctx . Handle ( 404 , "issue.UpdateMilestone" , nil )
return
}
mile , err := models . GetMilestoneByIndex ( ctx . Repo . Repository . Id , idx )
if err != nil {
if err == models . ErrMilestoneNotExist {
ctx . Handle ( 404 , "issue.UpdateMilestone(GetMilestoneByIndex)" , err )
} else {
ctx . Handle ( 500 , "issue.UpdateMilestone(GetMilestoneByIndex)" , err )
}
return
}
2014-05-14 03:46:48 +04:00
action := params [ "action" ]
if len ( action ) > 0 {
switch action {
case "open" :
if mile . IsClosed {
if err = models . ChangeMilestoneStatus ( mile , false ) ; err != nil {
ctx . Handle ( 500 , "issue.UpdateMilestone(ChangeMilestoneStatus)" , err )
return
}
}
case "close" :
if ! mile . IsClosed {
2014-05-14 18:55:36 +04:00
mile . ClosedDate = time . Now ( )
2014-05-14 03:46:48 +04:00
if err = models . ChangeMilestoneStatus ( mile , true ) ; err != nil {
ctx . Handle ( 500 , "issue.UpdateMilestone(ChangeMilestoneStatus)" , err )
return
}
}
case "delete" :
if err = models . DeleteMilestone ( mile ) ; err != nil {
ctx . Handle ( 500 , "issue.UpdateMilestone(DeleteMilestone)" , err )
return
}
}
ctx . Redirect ( ctx . Repo . RepoLink + "/issues/milestones" )
return
}
2014-05-13 21:28:21 +04:00
mile . DeadlineString = mile . Deadline . UTC ( ) . Format ( "01/02/2006" )
if mile . DeadlineString == "12/31/9999" {
mile . DeadlineString = ""
}
ctx . Data [ "Milestone" ] = mile
2014-05-12 17:51:22 +04:00
ctx . HTML ( 200 , "issue/milestone_edit" )
}
2014-05-13 21:28:21 +04:00
func UpdateMilestonePost ( ctx * middleware . Context , params martini . Params , form auth . CreateMilestoneForm ) {
ctx . Data [ "Title" ] = "Update Milestone"
ctx . Data [ "IsRepoToolbarIssues" ] = true
ctx . Data [ "IsRepoToolbarIssuesList" ] = true
idx , _ := base . StrTo ( params [ "index" ] ) . Int64 ( )
if idx == 0 {
2014-05-14 03:46:48 +04:00
ctx . Handle ( 404 , "issue.UpdateMilestonePost" , nil )
2014-05-13 21:28:21 +04:00
return
}
mile , err := models . GetMilestoneByIndex ( ctx . Repo . Repository . Id , idx )
if err != nil {
if err == models . ErrMilestoneNotExist {
2014-05-14 03:46:48 +04:00
ctx . Handle ( 404 , "issue.UpdateMilestonePost(GetMilestoneByIndex)" , err )
2014-05-13 21:28:21 +04:00
} else {
2014-05-14 03:46:48 +04:00
ctx . Handle ( 500 , "issue.UpdateMilestonePost(GetMilestoneByIndex)" , err )
2014-05-13 21:28:21 +04:00
}
return
}
var deadline time . Time
if len ( form . Deadline ) == 0 {
form . Deadline = "12/31/9999"
}
deadline , err = time . Parse ( "01/02/2006" , form . Deadline )
if err != nil {
ctx . Handle ( 500 , "issue.UpdateMilestonePost(time.Parse)" , err )
return
}
mile . Name = form . Title
mile . Content = form . Content
mile . Deadline = deadline
if err = models . UpdateMilestone ( mile ) ; err != nil {
ctx . Handle ( 500 , "issue.UpdateMilestonePost(UpdateMilestone)" , err )
return
}
ctx . Redirect ( ctx . Repo . RepoLink + "/issues/milestones" )
}