diff options
author | Unknown <joe2010xtmf@163.com> | 2014-05-07 12:09:30 -0400 |
---|---|---|
committer | Unknown <joe2010xtmf@163.com> | 2014-05-07 12:09:30 -0400 |
commit | 7407f9caf3e0baf3f9b7894fab021356662eed17 (patch) | |
tree | f8a06f17b900657e4088973e31b24ba93125190e /models | |
parent | 8ca14e210959b9316a4eed6e127de1eb775fda74 (diff) | |
download | gitea-7407f9caf3e0baf3f9b7894fab021356662eed17.tar.gz gitea-7407f9caf3e0baf3f9b7894fab021356662eed17.zip |
Finish issue design
Diffstat (limited to 'models')
-rw-r--r-- | models/issue.go | 204 | ||||
-rw-r--r-- | models/models.go | 2 | ||||
-rw-r--r-- | models/publickey.go | 113 | ||||
-rw-r--r-- | models/repo.go | 4 |
4 files changed, 223 insertions, 100 deletions
diff --git a/models/issue.go b/models/issue.go index 64fc45a61d..eb88190cc8 100644 --- a/models/issue.go +++ b/models/issue.go @@ -8,8 +8,6 @@ import ( "errors" "strings" "time" - - "github.com/gogits/gogs/modules/base" ) var ( @@ -21,7 +19,7 @@ type Issue struct { Id int64 Index int64 // Index in one repository. Name string - RepoId int64 `xorm:"index"` + RepoId int64 `xorm:"INDEX"` Repo *Repository `xorm:"-"` PosterId int64 Poster *User `xorm:"-"` @@ -35,44 +33,51 @@ type Issue struct { Priority int NumComments int Deadline time.Time - Created time.Time `xorm:"created"` - Updated time.Time `xorm:"updated"` + Created time.Time `xorm:"CREATED"` + Updated time.Time `xorm:"UPDATED"` +} + +func (i *Issue) GetPoster() (err error) { + i.Poster, err = GetUserById(i.PosterId) + 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. -func CreateIssue(userId, repoId, milestoneId, assigneeId int64, issueCount int, name, labels, content string, isPull bool) (issue *Issue, err error) { +func NewIssue(issue *Issue) (err error) { sess := orm.NewSession() defer sess.Close() - sess.Begin() - - issue = &Issue{ - Index: int64(issueCount) + 1, - Name: name, - RepoId: repoId, - PosterId: userId, - MilestoneId: milestoneId, - AssigneeId: assigneeId, - IsPull: isPull, - Labels: labels, - Content: content, + if err = sess.Begin(); err != nil { + return err } + if _, err = sess.Insert(issue); err != nil { sess.Rollback() - return nil, err + return err } rawSql := "UPDATE `repository` SET num_issues = num_issues + 1 WHERE id = ?" - if _, err = sess.Exec(rawSql, repoId); err != nil { + if _, err = sess.Exec(rawSql, issue.RepoId); err != nil { sess.Rollback() - return nil, err + return err } - - return issue, sess.Commit() + return sess.Commit() } -// GetIssueById returns issue object by given id. -func GetIssueByIndex(repoId, index int64) (*Issue, error) { - issue := &Issue{RepoId: repoId, Index: index} +// GetIssueByIndex returns issue by given index in repository. +func GetIssueByIndex(rid, index int64) (*Issue, error) { + issue := &Issue{RepoId: rid, Index: index} has, err := orm.Get(issue) if err != nil { return nil, err @@ -83,30 +88,28 @@ func GetIssueByIndex(repoId, index int64) (*Issue, error) { } // GetIssues returns a list of issues by given conditions. -func GetIssues(userId, repoId, posterId, milestoneId int64, page int, isClosed, isMention 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) - if repoId > 0 { - sess.Where("repo_id=?", repoId).And("is_closed=?", isClosed) + if rid > 0 { + sess.Where("repo_id=?", rid).And("is_closed=?", isClosed) } else { sess.Where("is_closed=?", isClosed) } - if userId > 0 { - sess.And("assignee_id=?", userId) - } else if posterId > 0 { - sess.And("poster_id=?", posterId) - } else if isMention { - sess.And("mentions like '%$" + base.ToStr(userId) + "|%'") + if uid > 0 { + sess.And("assignee_id=?", uid) + } else if pid > 0 { + sess.And("poster_id=?", pid) } - if milestoneId > 0 { - sess.And("milestone_id=?", milestoneId) + if mid > 0 { + sess.And("milestone_id=?", mid) } if len(labels) > 0 { for _, label := range strings.Split(labels, ",") { - sess.And("mentions like '%$" + label + "|%'") + sess.And("labels like '%$" + label + "|%'") } } @@ -130,22 +133,133 @@ func GetIssues(userId, repoId, posterId, milestoneId int64, page int, isClosed, return issues, err } +// PairsContains returns true when pairs list contains given issue. +func PairsContains(ius []*IssseUser, issueId int64) bool { + for i := range ius { + if ius[i].Iid == issueId { + return true + } + } + return false +} + +// GetIssueUserPairs returns all issue-user pairs by given repository and user. +func GetIssueUserPairs(rid, uid int64, isClosed bool) ([]*IssseUser, error) { + ius := make([]*IssseUser, 0, 10) + err := orm.Find(&ius, &IssseUser{Rid: rid, Uid: uid, IsClosed: isClosed}) + return ius, err +} + // GetUserIssueCount returns the number of issues that were created by given user in repository. -func GetUserIssueCount(userId, repoId int64) int64 { - count, _ := orm.Where("poster_id=?", userId).And("repo_id=?", repoId).Count(new(Issue)) +func GetUserIssueCount(uid, rid int64) int64 { + count, _ := orm.Where("poster_id=?", uid).And("repo_id=?", rid).Count(new(Issue)) return count } +// IssueStats represents issue statistic information. +type IssueStats struct { + OpenCount, ClosedCount int64 + AllCount int64 + AssignCount int64 + CreateCount int64 + MentionCount int64 +} + +// Filter modes. +const ( + FM_ASSIGN = iota + 1 + FM_CREATE + FM_MENTION +) + +// GetIssueStats returns issue statistic information by given condition. +func GetIssueStats(rid, uid int64, isShowClosed bool, filterMode int) *IssueStats { + stats := &IssueStats{} + issue := new(Issue) + + sess := orm.Where("repo_id=?", rid) + tmpSess := sess + stats.OpenCount, _ = tmpSess.And("is_closed=?", false).Count(issue) + *tmpSess = *sess + stats.ClosedCount, _ = tmpSess.And("is_closed=?", true).Count(issue) + if isShowClosed { + stats.AllCount = stats.ClosedCount + } else { + stats.AllCount = stats.OpenCount + } + + if filterMode != FM_MENTION { + sess = orm.Where("repo_id=?", rid) + switch filterMode { + case FM_ASSIGN: + sess.And("assignee_id=?", uid) + case FM_CREATE: + sess.And("poster_id=?", uid) + default: + goto nofilter + } + *tmpSess = *sess + stats.OpenCount, _ = tmpSess.And("is_closed=?", false).Count(issue) + *tmpSess = *sess + stats.ClosedCount, _ = tmpSess.And("is_closed=?", true).Count(issue) + } else { + sess := orm.Where("rid=?", rid).And("uid=?", uid).And("is_mentioned=?", true) + tmpSess := sess + stats.OpenCount, _ = tmpSess.And("is_closed=?", false).Count(new(IssseUser)) + *tmpSess = *sess + stats.ClosedCount, _ = tmpSess.And("is_closed=?", true).Count(new(IssseUser)) + } +nofilter: + 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.MentionCount, _ = orm.Where("rid=?", rid).And("uid=?", uid).And("is_closed=?", isShowClosed).And("is_mentioned=?", true).Count(new(IssseUser)) + return stats +} + +// GetUserIssueStats returns issue statistic information for dashboard by given condition. +func GetUserIssueStats(uid int64, filterMode int) *IssueStats { + stats := &IssueStats{} + 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.CreateCount, _ = orm.Where("poster_id=?", uid).And("is_closed=?", false).Count(issue) + return stats +} + // UpdateIssue updates information of issue. func UpdateIssue(issue *Issue) error { - _, err := orm.Id(issue.Id).AllCols().Update(issue) + _, err := orm.AllCols().Update(issue) return err } // Label represents a list of labels of repository for issues. type Label struct { Id int64 - RepoId int64 `xorm:"index"` + RepoId int64 `xorm:"INDEX"` Names string Colors string } @@ -154,12 +268,12 @@ type Label struct { type Milestone struct { Id int64 Name string - RepoId int64 `xorm:"index"` + RepoId int64 `xorm:"INDEX"` IsClosed bool Content string NumIssues int DueDate time.Time - Created time.Time `xorm:"created"` + Created time.Time `xorm:"CREATED"` } // Issue types. @@ -179,7 +293,7 @@ type Comment struct { CommitId int64 Line int64 Content string - Created time.Time `xorm:"created"` + Created time.Time `xorm:"CREATED"` } // CreateComment creates comment of issue or commit. diff --git a/models/models.go b/models/models.go index 6e4f7d1022..d7f3629927 100644 --- a/models/models.go +++ b/models/models.go @@ -34,7 +34,7 @@ var ( func init() { tables = append(tables, new(User), new(PublicKey), new(Repository), new(Watch), new(Action), new(Access), new(Issue), new(Comment), new(Oauth2), new(Follow), - new(Mirror), new(Release), new(LoginSource), new(Webhook)) + new(Mirror), new(Release), new(LoginSource), new(Webhook), new(IssseUser)) } func LoadModelsConfig() { diff --git a/models/publickey.go b/models/publickey.go index e594bbe91b..7ef25b9ceb 100644 --- a/models/publickey.go +++ b/models/publickey.go @@ -6,9 +6,9 @@ package models import ( "bufio" - "bytes" "errors" "fmt" + "io" "io/ioutil" "os" "path" @@ -26,7 +26,7 @@ import ( const ( // "### autogenerated by gitgos, DO NOT EDIT\n" - TPL_PUBLICK_KEY = `command="%s serv key-%d",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty %s` + _TPL_PUBLICK_KEY = `command="%s serv key-%d",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty %s` + "\n" ) var ( @@ -64,7 +64,7 @@ func init() { } } -// PublicKey represents a SSH key of user. +// PublicKey represents a SSH key. type PublicKey struct { Id int64 OwnerId int64 `xorm:"UNIQUE(s) INDEX NOT NULL"` @@ -75,14 +75,29 @@ type PublicKey struct { Updated time.Time `xorm:"UPDATED"` } -// GenAuthorizedKey returns formatted public key string. -func GenAuthorizedKey(keyId int64, key string) string { - return fmt.Sprintf(TPL_PUBLICK_KEY+"\n", appPath, keyId, key) +// GetAuthorizedString generates and returns formatted public key string for authorized_keys file. +func (key *PublicKey) GetAuthorizedString() string { + return fmt.Sprintf(_TPL_PUBLICK_KEY, appPath, key.Id, key.Content) } -// AddPublicKey adds new public key to database and SSH key file. +// saveAuthorizedKeyFile writes SSH key content to authorized_keys file. +func saveAuthorizedKeyFile(key *PublicKey) error { + sshOpLocker.Lock() + defer sshOpLocker.Unlock() + + fpath := filepath.Join(sshPath, "authorized_keys") + f, err := os.OpenFile(fpath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600) + if err != nil { + return err + } + defer f.Close() + + _, err = f.WriteString(key.GetAuthorizedString()) + return err +} + +// AddPublicKey adds new public key to database and authorized_keys file. func AddPublicKey(key *PublicKey) (err error) { - // Check if public key name has been used. has, err := orm.Get(key) if err != nil { return err @@ -91,7 +106,7 @@ func AddPublicKey(key *PublicKey) (err error) { } // Calculate fingerprint. - tmpPath := strings.Replace(filepath.Join(os.TempDir(), fmt.Sprintf("%d", time.Now().Nanosecond()), + tmpPath := strings.Replace(path.Join(os.TempDir(), fmt.Sprintf("%d", time.Now().Nanosecond()), "id_rsa.pub"), "\\", "/", -1) os.MkdirAll(path.Dir(tmpPath), os.ModePerm) if err = ioutil.WriteFile(tmpPath, []byte(key.Content), os.ModePerm); err != nil { @@ -108,8 +123,8 @@ func AddPublicKey(key *PublicKey) (err error) { // Save SSH key. if _, err = orm.Insert(key); err != nil { return err - } - if err = SaveAuthorizedKeyFile(key); err != nil { + } else if err = saveAuthorizedKeyFile(key); err != nil { + // Roll back. if _, err2 := orm.Delete(key); err2 != nil { return err2 } @@ -119,6 +134,13 @@ func AddPublicKey(key *PublicKey) (err error) { return nil } +// ListPublicKey returns a list of all public keys that user has. +func ListPublicKey(uid int64) ([]PublicKey, error) { + keys := make([]PublicKey, 0, 5) + err := orm.Find(&keys, &PublicKey{OwnerId: uid}) + return keys, err +} + // rewriteAuthorizedKeys finds and deletes corresponding line in authorized_keys file. func rewriteAuthorizedKeys(key *PublicKey, p, tmpP string) error { sshOpLocker.Lock() @@ -137,28 +159,38 @@ func rewriteAuthorizedKeys(key *PublicKey, p, tmpP string) error { defer fw.Close() isFound := false - keyword := []byte(fmt.Sprintf("key-%d", key.Id)) - content := []byte(key.Content) - - snr := bufio.NewScanner(fr) - for snr.Scan() { - line := append(bytes.TrimSpace(snr.Bytes()), '\n') - if len(line) == 0 { - continue + keyword := fmt.Sprintf("key-%d", key.Id) + buf := bufio.NewReader(fr) + for { + line, errRead := buf.ReadString('\n') + line = strings.TrimSpace(line) + + if errRead != nil { + if errRead != io.EOF { + return errRead + } + + // Reached end of file, if nothing to read then break, + // otherwise handle the last line. + if len(line) == 0 { + break + } } // Found the line and copy rest of file. - if !isFound && bytes.Contains(line, keyword) && bytes.Contains(line, content) { + if !isFound && strings.Contains(line, keyword) && strings.Contains(line, key.Content) { isFound = true continue } - // Still finding the line, copy the line that currently read. - if _, err = fw.Write(line); err != nil { + if _, err = fw.WriteString(line + "\n"); err != nil { return err } - } + if errRead == io.EOF { + break + } + } return nil } @@ -175,37 +207,14 @@ func DeletePublicKey(key *PublicKey) error { return err } - p := filepath.Join(sshPath, "authorized_keys") - tmpP := filepath.Join(sshPath, "authorized_keys.tmp") - log.Trace("publickey.DeletePublicKey(authorized_keys): %s", p) + fpath := filepath.Join(sshPath, "authorized_keys") + tmpPath := filepath.Join(sshPath, "authorized_keys.tmp") + log.Trace("publickey.DeletePublicKey(authorized_keys): %s", fpath) - if err = rewriteAuthorizedKeys(key, p, tmpP); err != nil { + if err = rewriteAuthorizedKeys(key, fpath, tmpPath); err != nil { return err - } else if err = os.Remove(p); err != nil { + } else if err = os.Remove(fpath); err != nil { return err } - return os.Rename(tmpP, p) -} - -// ListPublicKey returns a list of public keys that user has. -func ListPublicKey(userId int64) ([]PublicKey, error) { - keys := make([]PublicKey, 0) - err := orm.Find(&keys, &PublicKey{OwnerId: userId}) - return keys, err -} - -// SaveAuthorizedKeyFile writes SSH key content to SSH key file. -func SaveAuthorizedKeyFile(key *PublicKey) error { - sshOpLocker.Lock() - defer sshOpLocker.Unlock() - - p := filepath.Join(sshPath, "authorized_keys") - f, err := os.OpenFile(p, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600) - if err != nil { - return err - } - defer f.Close() - - _, err = f.WriteString(GenAuthorizedKey(key.Id, key.Content)) - return err + return os.Rename(tmpPath, fpath) } diff --git a/models/repo.go b/models/repo.go index d2b92be487..079e100a13 100644 --- a/models/repo.go +++ b/models/repo.go @@ -694,8 +694,8 @@ func GetRepositoryById(id int64) (*Repository, error) { } // GetRepositories returns the list of repositories of given user. -func GetRepositories(user *User, private bool) ([]Repository, error) { - repos := make([]Repository, 0, 10) +func GetRepositories(user *User, private bool) ([]*Repository, error) { + repos := make([]*Repository, 0, 10) sess := orm.Desc("updated") if !private { sess.Where("is_private=?", false) |