ソースを参照

Some file refactoring

Unknwon 8 年 前
コミット
6b6f54b79b
8 ファイル変更573 行追加551 行削除
  1. 28 28
      conf/app.ini
  2. 175 0
      models/attachment.go
  3. 0 0
      models/comment.go
  4. 0 502
      models/issue.go
  5. 349 0
      models/milestone.go
  6. 0 0
      models/mirror.go
  7. 0 0
      modules/bindata/bindata.go
  8. 21 21
      modules/setting/setting.go

+ 28 - 28
conf/app.ini

@@ -52,34 +52,6 @@ FILE_MAX_SIZE = 3
 ; Maximum number of files per upload
 MAX_FILES = 5
 
-[ui]
-; Number of repositories that are showed in one explore page
-EXPLORE_PAGING_NUM = 20
-; Number of issues that are showed in one page
-ISSUE_PAGING_NUM = 10
-; Number of maximum commits showed in one activity feed
-FEED_MAX_COMMIT_NUM = 5
-; Value of "theme-color" meta tag, used by Android >= 5.0
-; An invalid color like "none" or "disable" will have the default style
-; More info: https://developers.google.com/web/updates/2014/11/Support-for-theme-color-in-Chrome-39-for-Android
-THEME_COLOR_META_TAG = `#ff5343`
-; Max size in bytes of files to be displayed (default is 8MB)
-MAX_DISPLAY_FILE_SIZE = 8388608
-
-[ui.admin]
-; Number of users that are showed in one page
-USER_PAGING_NUM = 50
-; Number of repos that are showed in one page
-REPO_PAGING_NUM = 50
-; Number of notices that are showed in one page
-NOTICE_PAGING_NUM = 25
-; Number of organization that are showed in one page
-ORG_PAGING_NUM = 50
-
-[ui.user]
-; Number of repos that are showed in one page
-REPO_PAGING_NUM = 15
-
 [markdown]
 ; Enable hard line break extension
 ENABLE_HARD_LINE_BREAK = false
@@ -392,6 +364,34 @@ DEFAULT_INTERVAL = 8
 ; Max number of items will response in a page
 MAX_RESPONSE_ITEMS = 50
 
+[ui]
+; Number of repositories that are showed in one explore page
+EXPLORE_PAGING_NUM = 20
+; Number of issues that are showed in one page
+ISSUE_PAGING_NUM = 10
+; Number of maximum commits showed in one activity feed
+FEED_MAX_COMMIT_NUM = 5
+; Value of "theme-color" meta tag, used by Android >= 5.0
+; An invalid color like "none" or "disable" will have the default style
+; More info: https://developers.google.com/web/updates/2014/11/Support-for-theme-color-in-Chrome-39-for-Android
+THEME_COLOR_META_TAG = `#ff5343`
+; Max size in bytes of files to be displayed (default is 8MB)
+MAX_DISPLAY_FILE_SIZE = 8388608
+
+[ui.admin]
+; Number of users that are showed in one page
+USER_PAGING_NUM = 50
+; Number of repos that are showed in one page
+REPO_PAGING_NUM = 50
+; Number of notices that are showed in one page
+NOTICE_PAGING_NUM = 25
+; Number of organization that are showed in one page
+ORG_PAGING_NUM = 50
+
+[ui.user]
+; Number of repos that are showed in one page
+REPO_PAGING_NUM = 15
+
 [i18n]
 LANGS = en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,ja-JP,es-ES,pt-BR,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR,gl-ES
 NAMES = English,简体中文,繁體中文(香港),繁體中文(台湾),Deutsch,Français,Nederlands,Latviešu,Русский,日本語,Español,Português do Brasil,Polski,български,Italiano,Suomalainen,Türkçe,čeština,Српски,Svenska,한국어,Galego

+ 175 - 0
models/attachment.go

@@ -0,0 +1,175 @@
+// Copyright 2017 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 models
+
+import (
+	"fmt"
+	"io"
+	"mime/multipart"
+	"os"
+	"path"
+	"time"
+
+	"github.com/go-xorm/xorm"
+	gouuid "github.com/satori/go.uuid"
+
+	"github.com/gogits/gogs/modules/setting"
+)
+
+// Attachment represent a attachment of issue/comment/release.
+type Attachment struct {
+	ID        int64  `xorm:"pk autoincr"`
+	UUID      string `xorm:"uuid UNIQUE"`
+	IssueID   int64  `xorm:"INDEX"`
+	CommentID int64
+	ReleaseID int64 `xorm:"INDEX"`
+	Name      string
+
+	Created     time.Time `xorm:"-"`
+	CreatedUnix int64
+}
+
+func (a *Attachment) BeforeInsert() {
+	a.CreatedUnix = time.Now().Unix()
+}
+
+func (a *Attachment) AfterSet(colName string, _ xorm.Cell) {
+	switch colName {
+	case "created_unix":
+		a.Created = time.Unix(a.CreatedUnix, 0).Local()
+	}
+}
+
+// AttachmentLocalPath returns where attachment is stored in local file system based on given UUID.
+func AttachmentLocalPath(uuid string) string {
+	return path.Join(setting.AttachmentPath, uuid[0:1], uuid[1:2], uuid)
+}
+
+// LocalPath returns where attachment is stored in local file system.
+func (attach *Attachment) LocalPath() string {
+	return AttachmentLocalPath(attach.UUID)
+}
+
+// NewAttachment creates a new attachment object.
+func NewAttachment(name string, buf []byte, file multipart.File) (_ *Attachment, err error) {
+	attach := &Attachment{
+		UUID: gouuid.NewV4().String(),
+		Name: name,
+	}
+
+	localPath := attach.LocalPath()
+	if err = os.MkdirAll(path.Dir(localPath), os.ModePerm); err != nil {
+		return nil, fmt.Errorf("MkdirAll: %v", err)
+	}
+
+	fw, err := os.Create(localPath)
+	if err != nil {
+		return nil, fmt.Errorf("Create: %v", err)
+	}
+	defer fw.Close()
+
+	if _, err = fw.Write(buf); err != nil {
+		return nil, fmt.Errorf("Write: %v", err)
+	} else if _, err = io.Copy(fw, file); err != nil {
+		return nil, fmt.Errorf("Copy: %v", err)
+	}
+
+	if _, err := x.Insert(attach); err != nil {
+		return nil, err
+	}
+
+	return attach, nil
+}
+
+func getAttachmentByUUID(e Engine, uuid string) (*Attachment, error) {
+	attach := &Attachment{UUID: uuid}
+	has, err := x.Get(attach)
+	if err != nil {
+		return nil, err
+	} else if !has {
+		return nil, ErrAttachmentNotExist{0, uuid}
+	}
+	return attach, nil
+}
+
+func getAttachmentsByUUIDs(e Engine, uuids []string) ([]*Attachment, error) {
+	if len(uuids) == 0 {
+		return []*Attachment{}, nil
+	}
+
+	// Silently drop invalid uuids.
+	attachments := make([]*Attachment, 0, len(uuids))
+	return attachments, e.In("uuid", uuids).Find(&attachments)
+}
+
+// GetAttachmentByUUID returns attachment by given UUID.
+func GetAttachmentByUUID(uuid string) (*Attachment, error) {
+	return getAttachmentByUUID(x, uuid)
+}
+
+func getAttachmentsByIssueID(e Engine, issueID int64) ([]*Attachment, error) {
+	attachments := make([]*Attachment, 0, 10)
+	return attachments, e.Where("issue_id = ? AND comment_id = 0", issueID).Find(&attachments)
+}
+
+// GetAttachmentsByIssueID returns all attachments of an issue.
+func GetAttachmentsByIssueID(issueID int64) ([]*Attachment, error) {
+	return getAttachmentsByIssueID(x, issueID)
+}
+
+func getAttachmentsByCommentID(e Engine, commentID int64) ([]*Attachment, error) {
+	attachments := make([]*Attachment, 0, 10)
+	return attachments, e.Where("comment_id=?", commentID).Find(&attachments)
+}
+
+// GetAttachmentsByCommentID returns all attachments if comment by given ID.
+func GetAttachmentsByCommentID(commentID int64) ([]*Attachment, error) {
+	return getAttachmentsByCommentID(x, commentID)
+}
+
+// DeleteAttachment deletes the given attachment and optionally the associated file.
+func DeleteAttachment(a *Attachment, remove bool) error {
+	_, err := DeleteAttachments([]*Attachment{a}, remove)
+	return err
+}
+
+// DeleteAttachments deletes the given attachments and optionally the associated files.
+func DeleteAttachments(attachments []*Attachment, remove bool) (int, error) {
+	for i, a := range attachments {
+		if remove {
+			if err := os.Remove(a.LocalPath()); err != nil {
+				return i, err
+			}
+		}
+
+		if _, err := x.Delete(a); err != nil {
+			return i, err
+		}
+	}
+
+	return len(attachments), nil
+}
+
+// DeleteAttachmentsByIssue deletes all attachments associated with the given issue.
+func DeleteAttachmentsByIssue(issueId int64, remove bool) (int, error) {
+	attachments, err := GetAttachmentsByIssueID(issueId)
+
+	if err != nil {
+		return 0, err
+	}
+
+	return DeleteAttachments(attachments, remove)
+}
+
+// DeleteAttachmentsByComment deletes all attachments associated with the given comment.
+func DeleteAttachmentsByComment(commentId int64, remove bool) (int, error) {
+	attachments, err := GetAttachmentsByCommentID(commentId)
+
+	if err != nil {
+		return 0, err
+	}
+
+	return DeleteAttachments(attachments, remove)
+}

+ 0 - 0
models/issue_comment.go → models/comment.go


+ 0 - 502
models/issue.go

@@ -7,17 +7,12 @@ package models
 import (
 	"errors"
 	"fmt"
-	"io"
-	"mime/multipart"
-	"os"
-	"path"
 	"strings"
 	"time"
 
 	"github.com/Unknwon/com"
 	"github.com/go-xorm/xorm"
 	api "github.com/gogits/go-gogs-client"
-	gouuid "github.com/satori/go.uuid"
 	log "gopkg.in/clog.v1"
 
 	"github.com/gogits/gogs/modules/base"
@@ -1332,500 +1327,3 @@ func updateIssueUsersByMentions(e Engine, issueID int64, uids []int64) error {
 	}
 	return nil
 }
-
-//    _____  .__.__                   __
-//   /     \ |__|  |   ____   _______/  |_  ____   ____   ____
-//  /  \ /  \|  |  | _/ __ \ /  ___/\   __\/  _ \ /    \_/ __ \
-// /    Y    \  |  |_\  ___/ \___ \  |  | (  <_> )   |  \  ___/
-// \____|__  /__|____/\___  >____  > |__|  \____/|___|  /\___  >
-//         \/             \/     \/                   \/     \/
-
-// Milestone represents a milestone of repository.
-type Milestone struct {
-	ID              int64 `xorm:"pk autoincr"`
-	RepoID          int64 `xorm:"INDEX"`
-	Name            string
-	Content         string `xorm:"TEXT"`
-	RenderedContent string `xorm:"-"`
-	IsClosed        bool
-	NumIssues       int
-	NumClosedIssues int
-	NumOpenIssues   int  `xorm:"-"`
-	Completeness    int  // Percentage(1-100).
-	IsOverDue       bool `xorm:"-"`
-
-	DeadlineString string    `xorm:"-"`
-	Deadline       time.Time `xorm:"-"`
-	DeadlineUnix   int64
-	ClosedDate     time.Time `xorm:"-"`
-	ClosedDateUnix int64
-}
-
-func (m *Milestone) BeforeInsert() {
-	m.DeadlineUnix = m.Deadline.Unix()
-}
-
-func (m *Milestone) BeforeUpdate() {
-	if m.NumIssues > 0 {
-		m.Completeness = m.NumClosedIssues * 100 / m.NumIssues
-	} else {
-		m.Completeness = 0
-	}
-
-	m.DeadlineUnix = m.Deadline.Unix()
-	m.ClosedDateUnix = m.ClosedDate.Unix()
-}
-
-func (m *Milestone) AfterSet(colName string, _ xorm.Cell) {
-	switch colName {
-	case "num_closed_issues":
-		m.NumOpenIssues = m.NumIssues - m.NumClosedIssues
-
-	case "deadline_unix":
-		m.Deadline = time.Unix(m.DeadlineUnix, 0).Local()
-		if m.Deadline.Year() == 9999 {
-			return
-		}
-
-		m.DeadlineString = m.Deadline.Format("2006-01-02")
-		if time.Now().Local().After(m.Deadline) {
-			m.IsOverDue = true
-		}
-
-	case "closed_date_unix":
-		m.ClosedDate = time.Unix(m.ClosedDateUnix, 0).Local()
-	}
-}
-
-// State returns string representation of milestone status.
-func (m *Milestone) State() api.StateType {
-	if m.IsClosed {
-		return api.STATE_CLOSED
-	}
-	return api.STATE_OPEN
-}
-
-func (m *Milestone) ChangeStatus(isClosed bool) error {
-	return ChangeMilestoneStatus(m, isClosed)
-}
-
-func (m *Milestone) APIFormat() *api.Milestone {
-	apiMilestone := &api.Milestone{
-		ID:           m.ID,
-		State:        m.State(),
-		Title:        m.Name,
-		Description:  m.Content,
-		OpenIssues:   m.NumOpenIssues,
-		ClosedIssues: m.NumClosedIssues,
-	}
-	if m.IsClosed {
-		apiMilestone.Closed = &m.ClosedDate
-	}
-	if m.Deadline.Year() < 9999 {
-		apiMilestone.Deadline = &m.Deadline
-	}
-	return apiMilestone
-}
-
-// NewMilestone creates new milestone of repository.
-func NewMilestone(m *Milestone) (err error) {
-	sess := x.NewSession()
-	defer sessionRelease(sess)
-	if err = sess.Begin(); err != nil {
-		return err
-	}
-
-	if _, err = sess.Insert(m); err != nil {
-		return err
-	}
-
-	if _, err = sess.Exec("UPDATE `repository` SET num_milestones = num_milestones + 1 WHERE id = ?", m.RepoID); err != nil {
-		return err
-	}
-	return sess.Commit()
-}
-
-func getMilestoneByRepoID(e Engine, repoID, id int64) (*Milestone, error) {
-	m := &Milestone{
-		ID:     id,
-		RepoID: repoID,
-	}
-	has, err := e.Get(m)
-	if err != nil {
-		return nil, err
-	} else if !has {
-		return nil, ErrMilestoneNotExist{id, repoID}
-	}
-	return m, nil
-}
-
-// GetWebhookByRepoID returns the milestone in a repository.
-func GetMilestoneByRepoID(repoID, id int64) (*Milestone, error) {
-	return getMilestoneByRepoID(x, repoID, id)
-}
-
-// GetMilestonesByRepoID returns all milestones of a repository.
-func GetMilestonesByRepoID(repoID int64) ([]*Milestone, error) {
-	miles := make([]*Milestone, 0, 10)
-	return miles, x.Where("repo_id = ?", repoID).Find(&miles)
-}
-
-// GetMilestones returns a list of milestones of given repository and status.
-func GetMilestones(repoID int64, page int, isClosed bool) ([]*Milestone, error) {
-	miles := make([]*Milestone, 0, setting.UI.IssuePagingNum)
-	sess := x.Where("repo_id = ? AND is_closed = ?", repoID, isClosed)
-	if page > 0 {
-		sess = sess.Limit(setting.UI.IssuePagingNum, (page-1)*setting.UI.IssuePagingNum)
-	}
-	return miles, sess.Find(&miles)
-}
-
-func updateMilestone(e Engine, m *Milestone) error {
-	_, err := e.Id(m.ID).AllCols().Update(m)
-	return err
-}
-
-// UpdateMilestone updates information of given milestone.
-func UpdateMilestone(m *Milestone) error {
-	return updateMilestone(x, m)
-}
-
-func countRepoMilestones(e Engine, repoID int64) int64 {
-	count, _ := e.Where("repo_id=?", repoID).Count(new(Milestone))
-	return count
-}
-
-// CountRepoMilestones returns number of milestones in given repository.
-func CountRepoMilestones(repoID int64) int64 {
-	return countRepoMilestones(x, repoID)
-}
-
-func countRepoClosedMilestones(e Engine, repoID int64) int64 {
-	closed, _ := e.Where("repo_id=? AND is_closed=?", repoID, true).Count(new(Milestone))
-	return closed
-}
-
-// CountRepoClosedMilestones returns number of closed milestones in given repository.
-func CountRepoClosedMilestones(repoID int64) int64 {
-	return countRepoClosedMilestones(x, repoID)
-}
-
-// MilestoneStats returns number of open and closed milestones of given repository.
-func MilestoneStats(repoID int64) (open int64, closed int64) {
-	open, _ = x.Where("repo_id=? AND is_closed=?", repoID, false).Count(new(Milestone))
-	return open, CountRepoClosedMilestones(repoID)
-}
-
-// ChangeMilestoneStatus changes the milestone open/closed status.
-// If milestone passes with changed values, those values will be
-// updated to database as well.
-func ChangeMilestoneStatus(m *Milestone, isClosed bool) (err error) {
-	repo, err := GetRepositoryByID(m.RepoID)
-	if err != nil {
-		return err
-	}
-
-	sess := x.NewSession()
-	defer sessionRelease(sess)
-	if err = sess.Begin(); err != nil {
-		return err
-	}
-
-	m.IsClosed = isClosed
-	if err = updateMilestone(sess, m); err != nil {
-		return err
-	}
-
-	repo.NumMilestones = int(countRepoMilestones(sess, repo.ID))
-	repo.NumClosedMilestones = int(countRepoClosedMilestones(sess, repo.ID))
-	if _, err = sess.Id(repo.ID).AllCols().Update(repo); err != nil {
-		return err
-	}
-	return sess.Commit()
-}
-
-func changeMilestoneIssueStats(e *xorm.Session, issue *Issue) error {
-	if issue.MilestoneID == 0 {
-		return nil
-	}
-
-	m, err := getMilestoneByRepoID(e, issue.RepoID, issue.MilestoneID)
-	if err != nil {
-		return err
-	}
-
-	if issue.IsClosed {
-		m.NumOpenIssues--
-		m.NumClosedIssues++
-	} else {
-		m.NumOpenIssues++
-		m.NumClosedIssues--
-	}
-
-	return updateMilestone(e, m)
-}
-
-// ChangeMilestoneIssueStats updates the open/closed issues counter and progress
-// for the milestone associated with the given issue.
-func ChangeMilestoneIssueStats(issue *Issue) (err error) {
-	sess := x.NewSession()
-	defer sessionRelease(sess)
-	if err = sess.Begin(); err != nil {
-		return err
-	}
-
-	if err = changeMilestoneIssueStats(sess, issue); err != nil {
-		return err
-	}
-
-	return sess.Commit()
-}
-
-func changeMilestoneAssign(e *xorm.Session, issue *Issue, oldMilestoneID int64) error {
-	if oldMilestoneID > 0 {
-		m, err := getMilestoneByRepoID(e, issue.RepoID, oldMilestoneID)
-		if err != nil {
-			return err
-		}
-
-		m.NumIssues--
-		if issue.IsClosed {
-			m.NumClosedIssues--
-		}
-
-		if err = updateMilestone(e, m); err != nil {
-			return err
-		} else if _, err = e.Exec("UPDATE `issue_user` SET milestone_id = 0 WHERE issue_id = ?", issue.ID); err != nil {
-			return err
-		}
-	}
-
-	if issue.MilestoneID > 0 {
-		m, err := getMilestoneByRepoID(e, issue.RepoID, issue.MilestoneID)
-		if err != nil {
-			return err
-		}
-
-		m.NumIssues++
-		if issue.IsClosed {
-			m.NumClosedIssues++
-		}
-
-		if err = updateMilestone(e, m); err != nil {
-			return err
-		} else if _, err = e.Exec("UPDATE `issue_user` SET milestone_id = ? WHERE issue_id = ?", m.ID, issue.ID); err != nil {
-			return err
-		}
-	}
-
-	return updateIssue(e, issue)
-}
-
-// ChangeMilestoneAssign changes assignment of milestone for issue.
-func ChangeMilestoneAssign(issue *Issue, oldMilestoneID int64) (err error) {
-	sess := x.NewSession()
-	defer sess.Close()
-	if err = sess.Begin(); err != nil {
-		return err
-	}
-
-	if err = changeMilestoneAssign(sess, issue, oldMilestoneID); err != nil {
-		return err
-	}
-	return sess.Commit()
-}
-
-// DeleteMilestoneOfRepoByID deletes a milestone from a repository.
-func DeleteMilestoneOfRepoByID(repoID, id int64) error {
-	m, err := GetMilestoneByRepoID(repoID, id)
-	if err != nil {
-		if IsErrMilestoneNotExist(err) {
-			return nil
-		}
-		return err
-	}
-
-	repo, err := GetRepositoryByID(m.RepoID)
-	if err != nil {
-		return err
-	}
-
-	sess := x.NewSession()
-	defer sessionRelease(sess)
-	if err = sess.Begin(); err != nil {
-		return err
-	}
-
-	if _, err = sess.Id(m.ID).Delete(new(Milestone)); err != nil {
-		return err
-	}
-
-	repo.NumMilestones = int(countRepoMilestones(sess, repo.ID))
-	repo.NumClosedMilestones = int(countRepoClosedMilestones(sess, repo.ID))
-	if _, err = sess.Id(repo.ID).AllCols().Update(repo); err != nil {
-		return err
-	}
-
-	if _, err = sess.Exec("UPDATE `issue` SET milestone_id = 0 WHERE milestone_id = ?", m.ID); err != nil {
-		return err
-	} else if _, err = sess.Exec("UPDATE `issue_user` SET milestone_id = 0 WHERE milestone_id = ?", m.ID); err != nil {
-		return err
-	}
-	return sess.Commit()
-}
-
-// Attachment represent a attachment of issue/comment/release.
-type Attachment struct {
-	ID        int64  `xorm:"pk autoincr"`
-	UUID      string `xorm:"uuid UNIQUE"`
-	IssueID   int64  `xorm:"INDEX"`
-	CommentID int64
-	ReleaseID int64 `xorm:"INDEX"`
-	Name      string
-
-	Created     time.Time `xorm:"-"`
-	CreatedUnix int64
-}
-
-func (a *Attachment) BeforeInsert() {
-	a.CreatedUnix = time.Now().Unix()
-}
-
-func (a *Attachment) AfterSet(colName string, _ xorm.Cell) {
-	switch colName {
-	case "created_unix":
-		a.Created = time.Unix(a.CreatedUnix, 0).Local()
-	}
-}
-
-// AttachmentLocalPath returns where attachment is stored in local file system based on given UUID.
-func AttachmentLocalPath(uuid string) string {
-	return path.Join(setting.AttachmentPath, uuid[0:1], uuid[1:2], uuid)
-}
-
-// LocalPath returns where attachment is stored in local file system.
-func (attach *Attachment) LocalPath() string {
-	return AttachmentLocalPath(attach.UUID)
-}
-
-// NewAttachment creates a new attachment object.
-func NewAttachment(name string, buf []byte, file multipart.File) (_ *Attachment, err error) {
-	attach := &Attachment{
-		UUID: gouuid.NewV4().String(),
-		Name: name,
-	}
-
-	localPath := attach.LocalPath()
-	if err = os.MkdirAll(path.Dir(localPath), os.ModePerm); err != nil {
-		return nil, fmt.Errorf("MkdirAll: %v", err)
-	}
-
-	fw, err := os.Create(localPath)
-	if err != nil {
-		return nil, fmt.Errorf("Create: %v", err)
-	}
-	defer fw.Close()
-
-	if _, err = fw.Write(buf); err != nil {
-		return nil, fmt.Errorf("Write: %v", err)
-	} else if _, err = io.Copy(fw, file); err != nil {
-		return nil, fmt.Errorf("Copy: %v", err)
-	}
-
-	if _, err := x.Insert(attach); err != nil {
-		return nil, err
-	}
-
-	return attach, nil
-}
-
-func getAttachmentByUUID(e Engine, uuid string) (*Attachment, error) {
-	attach := &Attachment{UUID: uuid}
-	has, err := x.Get(attach)
-	if err != nil {
-		return nil, err
-	} else if !has {
-		return nil, ErrAttachmentNotExist{0, uuid}
-	}
-	return attach, nil
-}
-
-func getAttachmentsByUUIDs(e Engine, uuids []string) ([]*Attachment, error) {
-	if len(uuids) == 0 {
-		return []*Attachment{}, nil
-	}
-
-	// Silently drop invalid uuids.
-	attachments := make([]*Attachment, 0, len(uuids))
-	return attachments, e.In("uuid", uuids).Find(&attachments)
-}
-
-// GetAttachmentByUUID returns attachment by given UUID.
-func GetAttachmentByUUID(uuid string) (*Attachment, error) {
-	return getAttachmentByUUID(x, uuid)
-}
-
-func getAttachmentsByIssueID(e Engine, issueID int64) ([]*Attachment, error) {
-	attachments := make([]*Attachment, 0, 10)
-	return attachments, e.Where("issue_id = ? AND comment_id = 0", issueID).Find(&attachments)
-}
-
-// GetAttachmentsByIssueID returns all attachments of an issue.
-func GetAttachmentsByIssueID(issueID int64) ([]*Attachment, error) {
-	return getAttachmentsByIssueID(x, issueID)
-}
-
-func getAttachmentsByCommentID(e Engine, commentID int64) ([]*Attachment, error) {
-	attachments := make([]*Attachment, 0, 10)
-	return attachments, e.Where("comment_id=?", commentID).Find(&attachments)
-}
-
-// GetAttachmentsByCommentID returns all attachments if comment by given ID.
-func GetAttachmentsByCommentID(commentID int64) ([]*Attachment, error) {
-	return getAttachmentsByCommentID(x, commentID)
-}
-
-// DeleteAttachment deletes the given attachment and optionally the associated file.
-func DeleteAttachment(a *Attachment, remove bool) error {
-	_, err := DeleteAttachments([]*Attachment{a}, remove)
-	return err
-}
-
-// DeleteAttachments deletes the given attachments and optionally the associated files.
-func DeleteAttachments(attachments []*Attachment, remove bool) (int, error) {
-	for i, a := range attachments {
-		if remove {
-			if err := os.Remove(a.LocalPath()); err != nil {
-				return i, err
-			}
-		}
-
-		if _, err := x.Delete(a); err != nil {
-			return i, err
-		}
-	}
-
-	return len(attachments), nil
-}
-
-// DeleteAttachmentsByIssue deletes all attachments associated with the given issue.
-func DeleteAttachmentsByIssue(issueId int64, remove bool) (int, error) {
-	attachments, err := GetAttachmentsByIssueID(issueId)
-
-	if err != nil {
-		return 0, err
-	}
-
-	return DeleteAttachments(attachments, remove)
-}
-
-// DeleteAttachmentsByComment deletes all attachments associated with the given comment.
-func DeleteAttachmentsByComment(commentId int64, remove bool) (int, error) {
-	attachments, err := GetAttachmentsByCommentID(commentId)
-
-	if err != nil {
-		return 0, err
-	}
-
-	return DeleteAttachments(attachments, remove)
-}

+ 349 - 0
models/milestone.go

@@ -0,0 +1,349 @@
+// Copyright 2017 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 models
+
+import (
+	"time"
+
+	"github.com/go-xorm/xorm"
+
+	api "github.com/gogits/go-gogs-client"
+
+	"github.com/gogits/gogs/modules/setting"
+)
+
+// Milestone represents a milestone of repository.
+type Milestone struct {
+	ID              int64 `xorm:"pk autoincr"`
+	RepoID          int64 `xorm:"INDEX"`
+	Name            string
+	Content         string `xorm:"TEXT"`
+	RenderedContent string `xorm:"-"`
+	IsClosed        bool
+	NumIssues       int
+	NumClosedIssues int
+	NumOpenIssues   int  `xorm:"-"`
+	Completeness    int  // Percentage(1-100).
+	IsOverDue       bool `xorm:"-"`
+
+	DeadlineString string    `xorm:"-"`
+	Deadline       time.Time `xorm:"-"`
+	DeadlineUnix   int64
+	ClosedDate     time.Time `xorm:"-"`
+	ClosedDateUnix int64
+}
+
+func (m *Milestone) BeforeInsert() {
+	m.DeadlineUnix = m.Deadline.Unix()
+}
+
+func (m *Milestone) BeforeUpdate() {
+	if m.NumIssues > 0 {
+		m.Completeness = m.NumClosedIssues * 100 / m.NumIssues
+	} else {
+		m.Completeness = 0
+	}
+
+	m.DeadlineUnix = m.Deadline.Unix()
+	m.ClosedDateUnix = m.ClosedDate.Unix()
+}
+
+func (m *Milestone) AfterSet(colName string, _ xorm.Cell) {
+	switch colName {
+	case "num_closed_issues":
+		m.NumOpenIssues = m.NumIssues - m.NumClosedIssues
+
+	case "deadline_unix":
+		m.Deadline = time.Unix(m.DeadlineUnix, 0).Local()
+		if m.Deadline.Year() == 9999 {
+			return
+		}
+
+		m.DeadlineString = m.Deadline.Format("2006-01-02")
+		if time.Now().Local().After(m.Deadline) {
+			m.IsOverDue = true
+		}
+
+	case "closed_date_unix":
+		m.ClosedDate = time.Unix(m.ClosedDateUnix, 0).Local()
+	}
+}
+
+// State returns string representation of milestone status.
+func (m *Milestone) State() api.StateType {
+	if m.IsClosed {
+		return api.STATE_CLOSED
+	}
+	return api.STATE_OPEN
+}
+
+func (m *Milestone) ChangeStatus(isClosed bool) error {
+	return ChangeMilestoneStatus(m, isClosed)
+}
+
+func (m *Milestone) APIFormat() *api.Milestone {
+	apiMilestone := &api.Milestone{
+		ID:           m.ID,
+		State:        m.State(),
+		Title:        m.Name,
+		Description:  m.Content,
+		OpenIssues:   m.NumOpenIssues,
+		ClosedIssues: m.NumClosedIssues,
+	}
+	if m.IsClosed {
+		apiMilestone.Closed = &m.ClosedDate
+	}
+	if m.Deadline.Year() < 9999 {
+		apiMilestone.Deadline = &m.Deadline
+	}
+	return apiMilestone
+}
+
+// NewMilestone creates new milestone of repository.
+func NewMilestone(m *Milestone) (err error) {
+	sess := x.NewSession()
+	defer sessionRelease(sess)
+	if err = sess.Begin(); err != nil {
+		return err
+	}
+
+	if _, err = sess.Insert(m); err != nil {
+		return err
+	}
+
+	if _, err = sess.Exec("UPDATE `repository` SET num_milestones = num_milestones + 1 WHERE id = ?", m.RepoID); err != nil {
+		return err
+	}
+	return sess.Commit()
+}
+
+func getMilestoneByRepoID(e Engine, repoID, id int64) (*Milestone, error) {
+	m := &Milestone{
+		ID:     id,
+		RepoID: repoID,
+	}
+	has, err := e.Get(m)
+	if err != nil {
+		return nil, err
+	} else if !has {
+		return nil, ErrMilestoneNotExist{id, repoID}
+	}
+	return m, nil
+}
+
+// GetWebhookByRepoID returns the milestone in a repository.
+func GetMilestoneByRepoID(repoID, id int64) (*Milestone, error) {
+	return getMilestoneByRepoID(x, repoID, id)
+}
+
+// GetMilestonesByRepoID returns all milestones of a repository.
+func GetMilestonesByRepoID(repoID int64) ([]*Milestone, error) {
+	miles := make([]*Milestone, 0, 10)
+	return miles, x.Where("repo_id = ?", repoID).Find(&miles)
+}
+
+// GetMilestones returns a list of milestones of given repository and status.
+func GetMilestones(repoID int64, page int, isClosed bool) ([]*Milestone, error) {
+	miles := make([]*Milestone, 0, setting.UI.IssuePagingNum)
+	sess := x.Where("repo_id = ? AND is_closed = ?", repoID, isClosed)
+	if page > 0 {
+		sess = sess.Limit(setting.UI.IssuePagingNum, (page-1)*setting.UI.IssuePagingNum)
+	}
+	return miles, sess.Find(&miles)
+}
+
+func updateMilestone(e Engine, m *Milestone) error {
+	_, err := e.Id(m.ID).AllCols().Update(m)
+	return err
+}
+
+// UpdateMilestone updates information of given milestone.
+func UpdateMilestone(m *Milestone) error {
+	return updateMilestone(x, m)
+}
+
+func countRepoMilestones(e Engine, repoID int64) int64 {
+	count, _ := e.Where("repo_id=?", repoID).Count(new(Milestone))
+	return count
+}
+
+// CountRepoMilestones returns number of milestones in given repository.
+func CountRepoMilestones(repoID int64) int64 {
+	return countRepoMilestones(x, repoID)
+}
+
+func countRepoClosedMilestones(e Engine, repoID int64) int64 {
+	closed, _ := e.Where("repo_id=? AND is_closed=?", repoID, true).Count(new(Milestone))
+	return closed
+}
+
+// CountRepoClosedMilestones returns number of closed milestones in given repository.
+func CountRepoClosedMilestones(repoID int64) int64 {
+	return countRepoClosedMilestones(x, repoID)
+}
+
+// MilestoneStats returns number of open and closed milestones of given repository.
+func MilestoneStats(repoID int64) (open int64, closed int64) {
+	open, _ = x.Where("repo_id=? AND is_closed=?", repoID, false).Count(new(Milestone))
+	return open, CountRepoClosedMilestones(repoID)
+}
+
+// ChangeMilestoneStatus changes the milestone open/closed status.
+// If milestone passes with changed values, those values will be
+// updated to database as well.
+func ChangeMilestoneStatus(m *Milestone, isClosed bool) (err error) {
+	repo, err := GetRepositoryByID(m.RepoID)
+	if err != nil {
+		return err
+	}
+
+	sess := x.NewSession()
+	defer sessionRelease(sess)
+	if err = sess.Begin(); err != nil {
+		return err
+	}
+
+	m.IsClosed = isClosed
+	if err = updateMilestone(sess, m); err != nil {
+		return err
+	}
+
+	repo.NumMilestones = int(countRepoMilestones(sess, repo.ID))
+	repo.NumClosedMilestones = int(countRepoClosedMilestones(sess, repo.ID))
+	if _, err = sess.Id(repo.ID).AllCols().Update(repo); err != nil {
+		return err
+	}
+	return sess.Commit()
+}
+
+func changeMilestoneIssueStats(e *xorm.Session, issue *Issue) error {
+	if issue.MilestoneID == 0 {
+		return nil
+	}
+
+	m, err := getMilestoneByRepoID(e, issue.RepoID, issue.MilestoneID)
+	if err != nil {
+		return err
+	}
+
+	if issue.IsClosed {
+		m.NumOpenIssues--
+		m.NumClosedIssues++
+	} else {
+		m.NumOpenIssues++
+		m.NumClosedIssues--
+	}
+
+	return updateMilestone(e, m)
+}
+
+// ChangeMilestoneIssueStats updates the open/closed issues counter and progress
+// for the milestone associated with the given issue.
+func ChangeMilestoneIssueStats(issue *Issue) (err error) {
+	sess := x.NewSession()
+	defer sessionRelease(sess)
+	if err = sess.Begin(); err != nil {
+		return err
+	}
+
+	if err = changeMilestoneIssueStats(sess, issue); err != nil {
+		return err
+	}
+
+	return sess.Commit()
+}
+
+func changeMilestoneAssign(e *xorm.Session, issue *Issue, oldMilestoneID int64) error {
+	if oldMilestoneID > 0 {
+		m, err := getMilestoneByRepoID(e, issue.RepoID, oldMilestoneID)
+		if err != nil {
+			return err
+		}
+
+		m.NumIssues--
+		if issue.IsClosed {
+			m.NumClosedIssues--
+		}
+
+		if err = updateMilestone(e, m); err != nil {
+			return err
+		} else if _, err = e.Exec("UPDATE `issue_user` SET milestone_id = 0 WHERE issue_id = ?", issue.ID); err != nil {
+			return err
+		}
+	}
+
+	if issue.MilestoneID > 0 {
+		m, err := getMilestoneByRepoID(e, issue.RepoID, issue.MilestoneID)
+		if err != nil {
+			return err
+		}
+
+		m.NumIssues++
+		if issue.IsClosed {
+			m.NumClosedIssues++
+		}
+
+		if err = updateMilestone(e, m); err != nil {
+			return err
+		} else if _, err = e.Exec("UPDATE `issue_user` SET milestone_id = ? WHERE issue_id = ?", m.ID, issue.ID); err != nil {
+			return err
+		}
+	}
+
+	return updateIssue(e, issue)
+}
+
+// ChangeMilestoneAssign changes assignment of milestone for issue.
+func ChangeMilestoneAssign(issue *Issue, oldMilestoneID int64) (err error) {
+	sess := x.NewSession()
+	defer sess.Close()
+	if err = sess.Begin(); err != nil {
+		return err
+	}
+
+	if err = changeMilestoneAssign(sess, issue, oldMilestoneID); err != nil {
+		return err
+	}
+	return sess.Commit()
+}
+
+// DeleteMilestoneOfRepoByID deletes a milestone from a repository.
+func DeleteMilestoneOfRepoByID(repoID, id int64) error {
+	m, err := GetMilestoneByRepoID(repoID, id)
+	if err != nil {
+		if IsErrMilestoneNotExist(err) {
+			return nil
+		}
+		return err
+	}
+
+	repo, err := GetRepositoryByID(m.RepoID)
+	if err != nil {
+		return err
+	}
+
+	sess := x.NewSession()
+	defer sessionRelease(sess)
+	if err = sess.Begin(); err != nil {
+		return err
+	}
+
+	if _, err = sess.Id(m.ID).Delete(new(Milestone)); err != nil {
+		return err
+	}
+
+	repo.NumMilestones = int(countRepoMilestones(sess, repo.ID))
+	repo.NumClosedMilestones = int(countRepoClosedMilestones(sess, repo.ID))
+	if _, err = sess.Id(repo.ID).AllCols().Update(repo); err != nil {
+		return err
+	}
+
+	if _, err = sess.Exec("UPDATE `issue` SET milestone_id = 0 WHERE milestone_id = ?", m.ID); err != nil {
+		return err
+	} else if _, err = sess.Exec("UPDATE `issue_user` SET milestone_id = 0 WHERE milestone_id = ?", m.ID); err != nil {
+		return err
+	}
+	return sess.Commit()
+}

+ 0 - 0
models/repo_mirror.go → models/mirror.go


ファイルの差分が大きいため隠しています
+ 0 - 0
modules/bindata/bindata.go


+ 21 - 21
modules/setting/setting.go

@@ -144,25 +144,6 @@ var (
 	RepoRootPath string
 	ScriptType   string
 
-	// UI settings
-	UI struct {
-		ExplorePagingNum   int
-		IssuePagingNum     int
-		FeedMaxCommitNum   int
-		ThemeColorMetaTag  string
-		MaxDisplayFileSize int64
-
-		Admin struct {
-			UserPagingNum   int
-			RepoPagingNum   int
-			NoticePagingNum int
-			OrgPagingNum    int
-		} `ini:"ui.admin"`
-		User struct {
-			RepoPagingNum int
-		} `ini:"ui.user"`
-	}
-
 	// Markdown sttings
 	Markdown struct {
 		EnableHardLineBreak bool
@@ -253,6 +234,25 @@ var (
 		MaxResponseItems int
 	}
 
+	// UI settings
+	UI struct {
+		ExplorePagingNum   int
+		IssuePagingNum     int
+		FeedMaxCommitNum   int
+		ThemeColorMetaTag  string
+		MaxDisplayFileSize int64
+
+		Admin struct {
+			UserPagingNum   int
+			RepoPagingNum   int
+			NoticePagingNum int
+			OrgPagingNum    int
+		} `ini:"ui.admin"`
+		User struct {
+			RepoPagingNum int
+		} `ini:"ui.user"`
+	}
+
 	// I18n settings
 	Langs, Names []string
 	dateLangs    map[string]string
@@ -569,8 +569,6 @@ func NewContext() {
 
 	if err = Cfg.Section("http").MapTo(&HTTP); err != nil {
 		log.Fatal(4, "Fail to map HTTP settings: %v", err)
-	} else if err = Cfg.Section("ui").MapTo(&UI); err != nil {
-		log.Fatal(4, "Fail to map UI settings: %v", err)
 	} else if err = Cfg.Section("markdown").MapTo(&Markdown); err != nil {
 		log.Fatal(4, "Fail to map Markdown settings: %v", err)
 	} else if err = Cfg.Section("admin").MapTo(&Admin); err != nil {
@@ -583,6 +581,8 @@ func NewContext() {
 		log.Fatal(4, "Fail to map Mirror settings: %v", err)
 	} else if err = Cfg.Section("api").MapTo(&API); err != nil {
 		log.Fatal(4, "Fail to map API settings: %v", err)
+	} else if err = Cfg.Section("ui").MapTo(&UI); err != nil {
+		log.Fatal(4, "Fail to map UI settings: %v", err)
 	}
 
 	if Mirror.DefaultInterval <= 0 {

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません