@ -5,9 +5,12 @@
package models
package models
import (
import (
"bytes"
"errors"
"errors"
"strings"
"strings"
"time"
"time"
"github.com/gogits/gogs/modules/base"
)
)
var (
var (
@ -25,6 +28,7 @@ type Issue struct {
Poster * User ` xorm:"-" `
Poster * User ` xorm:"-" `
MilestoneId int64
MilestoneId int64
AssigneeId int64
AssigneeId int64
IsRead bool ` xorm:"-" `
IsPull bool // Indicates whether is a pull request or not.
IsPull bool // Indicates whether is a pull request or not.
IsClosed bool
IsClosed bool
Labels string ` xorm:"TEXT" `
Labels string ` xorm:"TEXT" `
@ -42,18 +46,6 @@ func (i *Issue) GetPoster() (err error) {
return err
return err
}
}
// IssseUser represents an issue-user relation.
type IssseUser struct {
Id int64
Iid int64 // Issue ID.
Rid int64 // Repository ID.
Uid int64 // User ID.
IsRead bool
IsAssigned bool
IsMentioned bool
IsClosed bool
}
// CreateIssue creates new issue for repository.
// CreateIssue creates new issue for repository.
func NewIssue ( issue * Issue ) ( err error ) {
func NewIssue ( issue * Issue ) ( err error ) {
sess := orm . NewSession ( )
sess := orm . NewSession ( )
@ -87,6 +79,18 @@ func GetIssueByIndex(rid, index int64) (*Issue, error) {
return issue , nil
return issue , nil
}
}
// GetIssueById returns an issue by ID.
func GetIssueById ( id int64 ) ( * Issue , error ) {
issue := & Issue { Id : id }
has , err := orm . Get ( issue )
if err != nil {
return nil , err
} else if ! has {
return nil , ErrIssueNotExist
}
return issue , nil
}
// GetIssues returns a list of issues by given conditions.
// GetIssues returns a list of issues by given conditions.
func GetIssues ( uid , rid , pid , mid int64 , page int , isClosed bool , labels , sortType string ) ( [ ] Issue , error ) {
func GetIssues ( uid , rid , pid , mid int64 , page int , isClosed bool , labels , sortType string ) ( [ ] Issue , error ) {
sess := orm . Limit ( 20 , ( page - 1 ) * 20 )
sess := orm . Limit ( 20 , ( page - 1 ) * 20 )
@ -133,27 +137,115 @@ func GetIssues(uid, rid, pid, mid int64, page int, isClosed bool, labels, sortTy
return issues , err
return issues , err
}
}
// GetIssueCountByPoster returns number of issues of repository by poster.
func GetIssueCountByPoster ( uid , rid int64 , isClosed bool ) int64 {
count , _ := orm . Where ( "repo_id=?" , rid ) . And ( "poster_id=?" , uid ) . And ( "is_closed=?" , isClosed ) . Count ( new ( Issue ) )
return count
}
// IssueUser represents an issue-user relation.
type IssueUser struct {
Id int64
Uid int64 // User ID.
IssueId int64
RepoId int64
IsRead bool
IsAssigned bool
IsMentioned bool
IsPoster bool
IsClosed bool
}
// NewIssueUserPairs adds new issue-user pairs for new issue of repository.
func NewIssueUserPairs ( rid , iid , oid , uid , aid int64 ) ( err error ) {
iu := & IssueUser { IssueId : iid , RepoId : rid }
ws , err := GetWatchers ( rid )
if err != nil {
return err
}
// TODO: check collaborators.
// Add owner.
ids := [ ] int64 { oid }
for _ , id := range ids {
if IsWatching ( id , rid ) {
continue
}
// In case owner is not watching.
ws = append ( ws , & Watch { Uid : id } )
}
for _ , w := range ws {
if w . Uid == 0 {
continue
}
iu . Uid = w . Uid
iu . IsPoster = iu . Uid == uid
iu . IsAssigned = iu . Uid == aid
if _ , err = orm . Insert ( iu ) ; err != nil {
return err
}
}
return nil
}
// PairsContains returns true when pairs list contains given issue.
// PairsContains returns true when pairs list contains given issue.
func PairsContains ( ius [ ] * IssseUser , issueId int64 ) bool {
func PairsContains ( ius [ ] * Issu eUser , issueId int64 ) int {
for i := range ius {
for i := range ius {
if ius [ i ] . Iid == issueId {
if ius [ i ] . IssueI d == issueId {
return true
return i
}
}
}
}
return false
return - 1
}
}
// GetIssueUserPairs returns all issue-user pairs by given repository and user.
// GetIssueUserPairs returns issue-user pairs by given repository and user.
func GetIssueUserPairs ( rid , uid int64 , isClosed bool ) ( [ ] * IssseUser , error ) {
func GetIssueUserPairs ( rid , uid int64 , isClosed bool ) ( [ ] * Issu eUser , error ) {
ius := make ( [ ] * IssseUser , 0 , 10 )
ius := make ( [ ] * Issu eUser , 0 , 10 )
err := orm . Find ( & ius , & IssseUser { Rid : rid , Uid : uid , IsClosed : isClosed } )
err := orm . Where ( "is_closed=?" , isClosed ) . Find ( & ius , & IssueUser { RepoId : rid , Ui d: u id} )
return ius , err
return ius , err
}
}
// GetUserIssueCount returns the number of issues that were created by given user in repository.
// GetIssueUserPairsByRepoIds returns issue-user pairs by given repository IDs.
func GetUserIssueCount ( uid , rid int64 ) int64 {
func GetIssueUserPairsByRepoIds ( rids [ ] int64 , isClosed bool , page int ) ( [ ] * IssueUser , error ) {
count , _ := orm . Where ( "poster_id=?" , uid ) . And ( "repo_id=?" , rid ) . Count ( new ( Issue ) )
buf := bytes . NewBufferString ( "" )
return count
for _ , rid := range rids {
buf . WriteString ( "repo_id=" )
buf . WriteString ( base . ToStr ( rid ) )
buf . WriteString ( " OR " )
}
cond := strings . TrimSuffix ( buf . String ( ) , " OR " )
ius := make ( [ ] * IssueUser , 0 , 10 )
sess := orm . Limit ( 20 , ( page - 1 ) * 20 ) . Where ( "is_closed=?" , isClosed )
if len ( cond ) > 0 {
sess . And ( cond )
}
err := sess . Find ( & ius )
return ius , err
}
// GetIssueUserPairsByMode returns issue-user pairs by given repository and user.
func GetIssueUserPairsByMode ( uid , rid int64 , isClosed bool , page , filterMode int ) ( [ ] * IssueUser , error ) {
ius := make ( [ ] * IssueUser , 0 , 10 )
sess := orm . Limit ( 20 , ( page - 1 ) * 20 ) . Where ( "uid=?" , uid ) . And ( "is_closed=?" , isClosed )
if rid > 0 {
sess . And ( "repo_id=?" , rid )
}
switch filterMode {
case FM_ASSIGN :
sess . And ( "is_assigned=?" , true )
case FM_CREATE :
sess . And ( "is_poster=?" , true )
default :
return ius , nil
}
err := sess . Find ( & ius )
return ius , err
}
}
// IssueStats represents issue statistic information.
// IssueStats represents issue statistic information.
@ -172,7 +264,7 @@ const (
FM_MENTION
FM_MENTION
)
)
// GetIssueStats returns issue statistic information by given condition.
// GetIssueStats returns issue statistic information by given conditions .
func GetIssueStats ( rid , uid int64 , isShowClosed bool , filterMode int ) * IssueStats {
func GetIssueStats ( rid , uid int64 , isShowClosed bool , filterMode int ) * IssueStats {
stats := & IssueStats { }
stats := & IssueStats { }
issue := new ( Issue )
issue := new ( Issue )
@ -203,48 +295,23 @@ func GetIssueStats(rid, uid int64, isShowClosed bool, filterMode int) *IssueStat
* tmpSess = * sess
* tmpSess = * sess
stats . ClosedCount , _ = tmpSess . And ( "is_closed=?" , true ) . Count ( issue )
stats . ClosedCount , _ = tmpSess . And ( "is_closed=?" , true ) . Count ( issue )
} else {
} else {
sess := orm . Where ( "rid=?" , rid ) . And ( "uid=?" , uid ) . And ( "is_mentioned=?" , true )
sess := orm . Where ( "repo_id=?" , rid ) . And ( "uid=?" , uid ) . And ( "is_mentioned=?" , true )
tmpSess := sess
stats . OpenCount , _ = tmpSess . And ( "is_closed=?" , false ) . Count ( new ( IssseUser ) )
* tmpSess = * sess
* tmpSess = * sess
stats . ClosedCount , _ = tmpSess . And ( "is_closed=?" , true ) . Count ( new ( IssseUser ) )
stats . OpenCount , _ = tmpSess . And ( "is_closed=?" , false ) . Count ( new ( IssueUser ) )
* tmpSess = * sess
stats . ClosedCount , _ = tmpSess . And ( "is_closed=?" , true ) . Count ( new ( IssueUser ) )
}
}
nofilter :
nofilter :
stats . AssignCount , _ = orm . Where ( "repo_id=?" , rid ) . And ( "is_closed=?" , isShowClosed ) . And ( "assignee_id=?" , uid ) . Count ( issue )
stats . AssignCount , _ = orm . Where ( "repo_id=?" , rid ) . And ( "is_closed=?" , isShowClosed ) . And ( "assignee_id=?" , uid ) . Count ( issue )
stats . CreateCount , _ = orm . Where ( "repo_id=?" , rid ) . And ( "is_closed=?" , isShowClosed ) . And ( "poster_id=?" , uid ) . Count ( issue )
stats . CreateCount , _ = orm . Where ( "repo_id=?" , rid ) . And ( "is_closed=?" , isShowClosed ) . And ( "poster_id=?" , uid ) . Count ( issue )
stats . MentionCount , _ = orm . Where ( "rid=?" , rid ) . And ( "uid=?" , uid ) . And ( "is_closed=?" , isShowClosed ) . And ( "is_mentioned=?" , true ) . Count ( new ( Isss eUser ) )
stats . MentionCount , _ = orm . Where ( "repo_ id=?" , rid ) . And ( "uid=?" , uid ) . And ( "is_closed=?" , isShowClosed ) . And ( "is_mentioned=?" , true ) . Count ( new ( Issu eUser ) )
return stats
return stats
}
}
// GetUserIssueStats returns issue statistic information for dashboard by given condition.
// GetUserIssueStats returns issue statistic information for dashboard by given conditions .
func GetUserIssueStats ( uid int64 , filterMode int ) * IssueStats {
func GetUserIssueStats ( uid int64 , filterMode int ) * IssueStats {
stats := & IssueStats { }
stats := & IssueStats { }
issue := new ( Issue )
issue := new ( Issue )
iu := new ( IssseUser )
sess := orm . Where ( "uid=?" , uid )
tmpSess := sess
if filterMode == 0 {
stats . OpenCount , _ = tmpSess . And ( "is_closed=?" , false ) . Count ( iu )
* tmpSess = * sess
stats . ClosedCount , _ = tmpSess . And ( "is_closed=?" , true ) . Count ( iu )
}
switch filterMode {
case FM_ASSIGN :
sess . And ( "is_assigned=?" , true )
* tmpSess = * sess
stats . OpenCount , _ = tmpSess . And ( "is_closed=?" , false ) . Count ( iu )
* tmpSess = * sess
stats . ClosedCount , _ = tmpSess . And ( "is_closed=?" , true ) . Count ( iu )
case FM_CREATE :
sess . Where ( "poster_id=?" , uid )
* tmpSess = * sess
stats . OpenCount , _ = tmpSess . And ( "is_closed=?" , false ) . Count ( issue )
* tmpSess = * sess
stats . ClosedCount , _ = tmpSess . And ( "is_closed=?" , true ) . Count ( issue )
}
stats . AssignCount , _ = orm . Where ( "assignee_id=?" , uid ) . And ( "is_closed=?" , false ) . Count ( issue )
stats . AssignCount , _ = orm . Where ( "assignee_id=?" , uid ) . And ( "is_closed=?" , false ) . Count ( issue )
stats . CreateCount , _ = orm . Where ( "poster_id=?" , uid ) . And ( "is_closed=?" , false ) . Count ( issue )
stats . CreateCount , _ = orm . Where ( "poster_id=?" , uid ) . And ( "is_closed=?" , false ) . Count ( issue )
return stats
return stats
@ -252,28 +319,69 @@ func GetUserIssueStats(uid int64, filterMode int) *IssueStats {
// UpdateIssue updates information of issue.
// UpdateIssue updates information of issue.
func UpdateIssue ( issue * Issue ) error {
func UpdateIssue ( issue * Issue ) error {
_ , err := orm . AllCols ( ) . Update ( issue )
_ , err := orm . Id ( issue . Id ) . AllCols ( ) . Update ( issue )
return err
return err
}
}
// Label represents a list of labels of repository for issues.
// UpdateIssueUserByStatus updates issue-user pairs by issue status.
func UpdateIssueUserPairsByStatus ( iid int64 , isClosed bool ) error {
rawSql := "UPDATE `issue_user` SET is_closed = ? WHERE issue_id = ?"
_ , err := orm . Exec ( rawSql , isClosed , iid )
return err
}
// UpdateIssueUserPairByRead updates issue-user pair for reading.
func UpdateIssueUserPairByRead ( uid , iid int64 ) error {
rawSql := "UPDATE `issue_user` SET is_read = ? WHERE uid = ? AND issue_id = ?"
_ , err := orm . Exec ( rawSql , true , uid , iid )
return err
}
// UpdateIssueUserPairsByMentions updates issue-user pairs by mentioning.
func UpdateIssueUserPairsByMentions ( uids [ ] int64 , iid int64 ) error {
for _ , uid := range uids {
iu := & IssueUser { Uid : uid , IssueId : iid }
has , err := orm . Get ( iu )
if err != nil {
return err
}
iu . IsMentioned = true
if has {
_ , err = orm . Id ( iu . Id ) . AllCols ( ) . Update ( iu )
} else {
_ , err = orm . Insert ( iu )
}
if err != nil {
return err
}
}
return nil
}
// Label represents a label of repository for issues.
type Label struct {
type Label struct {
Id int64
Id int64
RepoId int64 ` xorm:"INDEX" `
Rid int64 ` xorm:"INDEX" `
Names string
Name string
Colors string
Color string
NumIssues int
NumClosedIssues int
NumOpenIssues int ` xorm:"-" `
}
}
// Milestone represents a milestone of repository.
// Milestone represents a milestone of repository.
type Milestone struct {
type Milestone struct {
Id int64
Id int64
Rid int64 ` xorm:"INDEX" `
Name string
Name string
RepoId int64 ` xorm:"INDEX" `
IsClosed bool
Content string
Content string
IsClosed bool
NumIssues int
NumIssues int
DueDate time . Time
NumClosedIssues int
Created time . Time ` xorm:"CREATED" `
Completeness int // Percentage(1-100).
Deadline time . Time
ClosedDate time . Time
}
}
// Issue types.
// Issue types.
@ -300,7 +408,9 @@ type Comment struct {
func CreateComment ( userId , repoId , issueId , commitId , line int64 , cmtType int , content string ) error {
func CreateComment ( userId , repoId , issueId , commitId , line int64 , cmtType int , content string ) error {
sess := orm . NewSession ( )
sess := orm . NewSession ( )
defer sess . Close ( )
defer sess . Close ( )
sess . Begin ( )
if err := sess . Begin ( ) ; err != nil {
return err
}
if _ , err := sess . Insert ( & Comment { PosterId : userId , Type : cmtType , IssueId : issueId ,
if _ , err := sess . Insert ( & Comment { PosterId : userId , Type : cmtType , IssueId : issueId ,
CommitId : commitId , Line : line , Content : content } ) ; err != nil {
CommitId : commitId , Line : line , Content : content } ) ; err != nil {