mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 16:40:24 +08:00 
			
		
		
		
	Merge branch 'master' of github.com:gogits/gogs
This commit is contained in:
		@@ -5,7 +5,9 @@ Gogs(Go Git Service) is a Self Hosted Git Service in the Go Programming Language
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
##### Current version: 0.1.9 Alpha
 | 
			
		||||
##### Current version: 0.2.0 Alpha
 | 
			
		||||
 | 
			
		||||
#### Due to testing purpose, data of [try.gogits.org](http://try.gogits.org) has been reset in March 29, 2014 and will reset multiple times after. Please do NOT put your important data on the site.
 | 
			
		||||
 | 
			
		||||
#### Other language version
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@ Gogs(Go Git Service) 是一个由 Go 语言编写的自助 Git 托管服务。
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
##### 当前版本:0.1.9 Alpha
 | 
			
		||||
##### 当前版本:0.2.0 Alpha
 | 
			
		||||
 | 
			
		||||
## 开发目的
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								gogs.go
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								gogs.go
									
									
									
									
									
								
							@@ -19,7 +19,7 @@ import (
 | 
			
		||||
// Test that go1.2 tag above is included in builds. main.go refers to this definition.
 | 
			
		||||
const go12tag = true
 | 
			
		||||
 | 
			
		||||
const APP_VER = "0.1.9.0329 Alpha"
 | 
			
		||||
const APP_VER = "0.2.0.0329 Alpha"
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	base.AppVer = APP_VER
 | 
			
		||||
 
 | 
			
		||||
@@ -70,9 +70,12 @@ func GetTargetFile(userName, repoName, branchName, commitId, rpath string) (*Rep
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	commit, err := repo.GetCommit(branchName, commitId)
 | 
			
		||||
	commit, err := repo.GetCommitOfBranch(branchName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
		commit, err = repo.GetCommit(commitId)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	parts := strings.Split(path.Clean(rpath), "/")
 | 
			
		||||
@@ -110,13 +113,22 @@ func GetTargetFile(userName, repoName, branchName, commitId, rpath string) (*Rep
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetReposFiles returns a list of file object in given directory of repository.
 | 
			
		||||
func GetReposFiles(userName, repoName, branchName, commitId, rpath string) ([]*RepoFile, error) {
 | 
			
		||||
// func GetReposFilesOfBranch(userName, repoName, branchName, rpath string) ([]*RepoFile, error) {
 | 
			
		||||
// 	return getReposFiles(userName, repoName, commitId, rpath)
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// GetReposFiles returns a list of file object in given directory of repository.
 | 
			
		||||
func GetReposFiles(userName, repoName, commitId, rpath string) ([]*RepoFile, error) {
 | 
			
		||||
	return getReposFiles(userName, repoName, commitId, rpath)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getReposFiles(userName, repoName, commitId string, rpath string) ([]*RepoFile, error) {
 | 
			
		||||
	repo, err := git.OpenRepository(RepoPath(userName, repoName))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	commit, err := repo.GetCommit(branchName, commitId)
 | 
			
		||||
	commit, err := repo.GetCommit(commitId)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -216,13 +228,13 @@ func GetReposFiles(userName, repoName, branchName, commitId, rpath string) ([]*R
 | 
			
		||||
	return append(repodirs, repofiles...), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetCommit(userName, repoName, branchname, commitid string) (*git.Commit, error) {
 | 
			
		||||
func GetCommit(userName, repoName, commitId string) (*git.Commit, error) {
 | 
			
		||||
	repo, err := git.OpenRepository(RepoPath(userName, repoName))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return repo.GetCommit(branchname, commitid)
 | 
			
		||||
	return repo.GetCommit(commitId)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetCommitsByBranch returns all commits of given branch of repository.
 | 
			
		||||
@@ -397,7 +409,7 @@ func GetDiff(repoPath, commitid string) (*Diff, error) {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	commit, err := repo.GetCommit("", commitid)
 | 
			
		||||
	commit, err := repo.GetCommit(commitid)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -18,23 +18,24 @@ var (
 | 
			
		||||
 | 
			
		||||
// Issue represents an issue or pull request of repository.
 | 
			
		||||
type Issue struct {
 | 
			
		||||
	Id          int64
 | 
			
		||||
	Index       int64 // Index in one repository.
 | 
			
		||||
	Name        string
 | 
			
		||||
	RepoId      int64       `xorm:"index"`
 | 
			
		||||
	Repo        *Repository `xorm:"-"`
 | 
			
		||||
	PosterId    int64
 | 
			
		||||
	Poster      *User `xorm:"-"`
 | 
			
		||||
	MilestoneId int64
 | 
			
		||||
	AssigneeId  int64
 | 
			
		||||
	IsPull      bool // Indicates whether is a pull request or not.
 | 
			
		||||
	IsClosed    bool
 | 
			
		||||
	Labels      string `xorm:"TEXT"`
 | 
			
		||||
	Mentions    string `xorm:"TEXT"`
 | 
			
		||||
	Content     string `xorm:"TEXT"`
 | 
			
		||||
	NumComments int
 | 
			
		||||
	Created     time.Time `xorm:"created"`
 | 
			
		||||
	Updated     time.Time `xorm:"updated"`
 | 
			
		||||
	Id              int64
 | 
			
		||||
	Index           int64 // Index in one repository.
 | 
			
		||||
	Name            string
 | 
			
		||||
	RepoId          int64       `xorm:"index"`
 | 
			
		||||
	Repo            *Repository `xorm:"-"`
 | 
			
		||||
	PosterId        int64
 | 
			
		||||
	Poster          *User `xorm:"-"`
 | 
			
		||||
	MilestoneId     int64
 | 
			
		||||
	AssigneeId      int64
 | 
			
		||||
	IsPull          bool // Indicates whether is a pull request or not.
 | 
			
		||||
	IsClosed        bool
 | 
			
		||||
	Labels          string `xorm:"TEXT"`
 | 
			
		||||
	Mentions        string `xorm:"TEXT"`
 | 
			
		||||
	Content         string `xorm:"TEXT"`
 | 
			
		||||
	RenderedContent string `xorm:"-"`
 | 
			
		||||
	NumComments     int
 | 
			
		||||
	Created         time.Time `xorm:"created"`
 | 
			
		||||
	Updated         time.Time `xorm:"updated"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CreateIssue creates new issue for repository.
 | 
			
		||||
@@ -169,9 +170,17 @@ type Milestone struct {
 | 
			
		||||
	Created   time.Time `xorm:"created"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Issue types.
 | 
			
		||||
const (
 | 
			
		||||
	IT_PLAIN  = iota // Pure comment.
 | 
			
		||||
	IT_REOPEN        // Issue reopen status change prompt.
 | 
			
		||||
	IT_CLOSE         // Issue close status change prompt.
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Comment represents a comment in commit and issue page.
 | 
			
		||||
type Comment struct {
 | 
			
		||||
	Id       int64
 | 
			
		||||
	Type     int
 | 
			
		||||
	PosterId int64
 | 
			
		||||
	Poster   *User `xorm:"-"`
 | 
			
		||||
	IssueId  int64
 | 
			
		||||
@@ -182,21 +191,37 @@ type Comment struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CreateComment creates comment of issue or commit.
 | 
			
		||||
func CreateComment(userId, issueId, commitId, line int64, content string) error {
 | 
			
		||||
func CreateComment(userId, repoId, issueId, commitId, line int64, cmtType int, content string) error {
 | 
			
		||||
	sess := orm.NewSession()
 | 
			
		||||
	defer sess.Close()
 | 
			
		||||
	sess.Begin()
 | 
			
		||||
 | 
			
		||||
	if _, err := orm.Insert(&Comment{PosterId: userId, IssueId: issueId,
 | 
			
		||||
	if _, err := orm.Insert(&Comment{PosterId: userId, Type: cmtType, IssueId: issueId,
 | 
			
		||||
		CommitId: commitId, Line: line, Content: content}); err != nil {
 | 
			
		||||
		sess.Rollback()
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rawSql := "UPDATE `issue` SET num_comments = num_comments + 1 WHERE id = ?"
 | 
			
		||||
	if _, err := sess.Exec(rawSql, issueId); err != nil {
 | 
			
		||||
		sess.Rollback()
 | 
			
		||||
		return err
 | 
			
		||||
	// Check comment type.
 | 
			
		||||
	switch cmtType {
 | 
			
		||||
	case IT_PLAIN:
 | 
			
		||||
		rawSql := "UPDATE `issue` SET num_comments = num_comments + 1 WHERE id = ?"
 | 
			
		||||
		if _, err := sess.Exec(rawSql, issueId); err != nil {
 | 
			
		||||
			sess.Rollback()
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	case IT_REOPEN:
 | 
			
		||||
		rawSql := "UPDATE `repository` SET num_closed_issues = num_closed_issues - 1 WHERE id = ?"
 | 
			
		||||
		if _, err := sess.Exec(rawSql, repoId); err != nil {
 | 
			
		||||
			sess.Rollback()
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	case IT_CLOSE:
 | 
			
		||||
		rawSql := "UPDATE `repository` SET num_closed_issues = num_closed_issues + 1 WHERE id = ?"
 | 
			
		||||
		if _, err := sess.Exec(rawSql, repoId); err != nil {
 | 
			
		||||
			sess.Rollback()
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return sess.Commit()
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -34,8 +34,7 @@ func LoadModelsConfig() {
 | 
			
		||||
	DbCfg.Path = base.Cfg.MustValue("database", "PATH", "data/gogs.db")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SetEngine() {
 | 
			
		||||
	var err error
 | 
			
		||||
func SetEngine() (err error) {
 | 
			
		||||
	switch DbCfg.Type {
 | 
			
		||||
	case "mysql":
 | 
			
		||||
		orm, err = xorm.NewEngine("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8",
 | 
			
		||||
@@ -47,12 +46,10 @@ func SetEngine() {
 | 
			
		||||
		os.MkdirAll(path.Dir(DbCfg.Path), os.ModePerm)
 | 
			
		||||
		orm, err = xorm.NewEngine("sqlite3", DbCfg.Path)
 | 
			
		||||
	default:
 | 
			
		||||
		fmt.Printf("Unknown database type: %s\n", DbCfg.Type)
 | 
			
		||||
		os.Exit(2)
 | 
			
		||||
		return fmt.Errorf("Unknown database type: %s\n", DbCfg.Type)
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Printf("models.init(fail to conntect database): %v\n", err)
 | 
			
		||||
		os.Exit(2)
 | 
			
		||||
		return fmt.Errorf("models.init(fail to conntect database): %v\n", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// WARNNING: for serv command, MUST remove the output to os.stdout,
 | 
			
		||||
@@ -62,20 +59,21 @@ func SetEngine() {
 | 
			
		||||
	//orm.ShowErr = true
 | 
			
		||||
	f, err := os.Create("xorm.log")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Printf("models.init(fail to create xorm.log): %v\n", err)
 | 
			
		||||
		os.Exit(2)
 | 
			
		||||
		return fmt.Errorf("models.init(fail to create xorm.log): %v\n", err)
 | 
			
		||||
	}
 | 
			
		||||
	orm.Logger = f
 | 
			
		||||
	orm.ShowSQL = true
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewEngine() {
 | 
			
		||||
	SetEngine()
 | 
			
		||||
	if err := orm.Sync(new(User), new(PublicKey), new(Repository), new(Watch),
 | 
			
		||||
func NewEngine() (err error) {
 | 
			
		||||
	if err = SetEngine(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	} else if err = orm.Sync(new(User), new(PublicKey), new(Repository), new(Watch),
 | 
			
		||||
		new(Action), new(Access), new(Issue), new(Comment)); err != nil {
 | 
			
		||||
		fmt.Printf("sync database struct error: %v\n", err)
 | 
			
		||||
		os.Exit(2)
 | 
			
		||||
		return fmt.Errorf("sync database struct error: %v\n", err)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Statistic struct {
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,6 @@ import (
 | 
			
		||||
	"os/exec"
 | 
			
		||||
	"path"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
	"unicode/utf8"
 | 
			
		||||
@@ -60,15 +59,6 @@ func NewRepoContext() {
 | 
			
		||||
			os.Exit(2)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Initialize illegal patterns.
 | 
			
		||||
	for i := range illegalPatterns[1:] {
 | 
			
		||||
		pattern := ""
 | 
			
		||||
		for j := range illegalPatterns[i+1] {
 | 
			
		||||
			pattern += "[" + string(illegalPatterns[i+1][j]-32) + string(illegalPatterns[i+1][j]) + "]"
 | 
			
		||||
		}
 | 
			
		||||
		illegalPatterns[i+1] = pattern
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Repository represents a git repository.
 | 
			
		||||
@@ -106,15 +96,20 @@ func IsRepositoryExist(user *User, repoName string) (bool, error) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	// Define as all lower case!!
 | 
			
		||||
	illegalPatterns = []string{"[.][Gg][Ii][Tt]", "raw", "user", "help", "stars", "issues", "pulls", "commits", "repo", "template", "admin"}
 | 
			
		||||
	illegalEquals  = []string{"raw", "install", "api", "avatar", "user", "help", "stars", "issues", "pulls", "commits", "repo", "template", "admin"}
 | 
			
		||||
	illegalSuffixs = []string{".git"}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// IsLegalName returns false if name contains illegal characters.
 | 
			
		||||
func IsLegalName(repoName string) bool {
 | 
			
		||||
	for _, pattern := range illegalPatterns {
 | 
			
		||||
		has, _ := regexp.MatchString(pattern, repoName)
 | 
			
		||||
		if has {
 | 
			
		||||
	repoName = strings.ToLower(repoName)
 | 
			
		||||
	for _, char := range illegalEquals {
 | 
			
		||||
		if repoName == char {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, char := range illegalSuffixs {
 | 
			
		||||
		if strings.HasSuffix(repoName, char) {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -199,12 +194,19 @@ func CreateRepository(user *User, repoName, desc, repoLang, license string, priv
 | 
			
		||||
 | 
			
		||||
	c := exec.Command("git", "update-server-info")
 | 
			
		||||
	c.Dir = repoPath
 | 
			
		||||
	err = c.Run()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
	if err = c.Run(); err != nil {
 | 
			
		||||
		log.Error("repo.CreateRepository(exec update-server-info): %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return repo, NewRepoAction(user, repo)
 | 
			
		||||
	if err = NewRepoAction(user, repo); err != nil {
 | 
			
		||||
		log.Error("repo.CreateRepository(NewRepoAction): %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = WatchRepo(user.Id, repo.Id, true); err != nil {
 | 
			
		||||
		log.Error("repo.CreateRepository(WatchRepo): %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return repo, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// extractGitBareZip extracts git-bare.zip to repository path.
 | 
			
		||||
@@ -363,7 +365,7 @@ func GetRepos(num, offset int) ([]UserRepo, error) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RepoPath(userName, repoName string) string {
 | 
			
		||||
	return filepath.Join(UserPath(userName), repoName+".git")
 | 
			
		||||
	return filepath.Join(UserPath(userName), strings.ToLower(repoName)+".git")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func UpdateRepository(repo *Repository) error {
 | 
			
		||||
 
 | 
			
		||||
@@ -172,6 +172,7 @@ type InstallForm struct {
 | 
			
		||||
	DatabasePath    string `form:"database_path"`
 | 
			
		||||
	RepoRootPath    string `form:"repo_path"`
 | 
			
		||||
	RunUser         string `form:"run_user"`
 | 
			
		||||
	Domain          string `form:"domain"`
 | 
			
		||||
	AppUrl          string `form:"app_url"`
 | 
			
		||||
	AdminName       string `form:"admin_name" binding:"Required"`
 | 
			
		||||
	AdminPasswd     string `form:"admin_pwd" binding:"Required;MinSize(6);MaxSize(30)"`
 | 
			
		||||
 
 | 
			
		||||
@@ -272,18 +272,19 @@ func NewConfigContext() {
 | 
			
		||||
	Domain = Cfg.MustValue("server", "DOMAIN")
 | 
			
		||||
	SecretKey = Cfg.MustValue("security", "SECRET_KEY")
 | 
			
		||||
 | 
			
		||||
	InstallLock = Cfg.MustBool("security", "INSTALL_LOCK", false)
 | 
			
		||||
 | 
			
		||||
	RunUser = Cfg.MustValue("", "RUN_USER")
 | 
			
		||||
	curUser := os.Getenv("USERNAME")
 | 
			
		||||
	if len(curUser) == 0 {
 | 
			
		||||
		curUser = os.Getenv("USER")
 | 
			
		||||
	}
 | 
			
		||||
	if RunUser != curUser {
 | 
			
		||||
	// Does not check run user when the install lock is off.
 | 
			
		||||
	if InstallLock && RunUser != curUser {
 | 
			
		||||
		fmt.Printf("Expect user(%s) but current user is: %s\n", RunUser, curUser)
 | 
			
		||||
		os.Exit(2)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	InstallLock = Cfg.MustBool("security", "INSTALL_LOCK", false)
 | 
			
		||||
 | 
			
		||||
	LogInRememberDays = Cfg.MustInt("security", "LOGIN_REMEMBER_DAYS")
 | 
			
		||||
	CookieUserName = Cfg.MustValue("security", "COOKIE_USERNAME")
 | 
			
		||||
	CookieRememberName = Cfg.MustValue("security", "COOKIE_REMEMBER_NAME")
 | 
			
		||||
 
 | 
			
		||||
@@ -33,6 +33,13 @@ func List(l *list.List) chan interface{} {
 | 
			
		||||
	return c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ShortSha(sha1 string) string {
 | 
			
		||||
	if len(sha1) == 40 {
 | 
			
		||||
		return sha1[:10]
 | 
			
		||||
	}
 | 
			
		||||
	return sha1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var mailDomains = map[string]string{
 | 
			
		||||
	"gmail.com": "gmail.com",
 | 
			
		||||
}
 | 
			
		||||
@@ -72,4 +79,5 @@ var TemplateFuncs template.FuncMap = map[string]interface{}{
 | 
			
		||||
	},
 | 
			
		||||
	"DiffTypeToStr":     DiffTypeToStr,
 | 
			
		||||
	"DiffLineTypeToStr": DiffLineTypeToStr,
 | 
			
		||||
	"ShortSha":          ShortSha,
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -15,13 +15,14 @@ var (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	logger = logs.NewLogger(10000)
 | 
			
		||||
	logger.SetLogger("console", `{"level": 0}`)
 | 
			
		||||
	NewLogger(10000, "console", `{"level": 0}`)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewLogger(bufLen int64, mode, config string) {
 | 
			
		||||
	Mode, Config = mode, config
 | 
			
		||||
	logger = logs.NewLogger(bufLen)
 | 
			
		||||
	logger.EnableFuncCallDepth(true)
 | 
			
		||||
	logger.SetLogFuncCallDepth(4)
 | 
			
		||||
	logger.SetLogger(mode, config)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,7 @@ import (
 | 
			
		||||
	"github.com/codegangsta/martini"
 | 
			
		||||
 | 
			
		||||
	"github.com/gogits/cache"
 | 
			
		||||
	"github.com/gogits/git"
 | 
			
		||||
	"github.com/gogits/session"
 | 
			
		||||
 | 
			
		||||
	"github.com/gogits/gogs/models"
 | 
			
		||||
@@ -41,11 +42,18 @@ type Context struct {
 | 
			
		||||
	csrfToken string
 | 
			
		||||
 | 
			
		||||
	Repo struct {
 | 
			
		||||
		IsValid    bool
 | 
			
		||||
		IsOwner    bool
 | 
			
		||||
		IsWatching bool
 | 
			
		||||
		IsBranch   bool
 | 
			
		||||
		IsTag      bool
 | 
			
		||||
		IsCommit   bool
 | 
			
		||||
		Repository *models.Repository
 | 
			
		||||
		Owner      *models.User
 | 
			
		||||
		Commit     *git.Commit
 | 
			
		||||
		GitRepo    *git.Repository
 | 
			
		||||
		BranchName string
 | 
			
		||||
		CommitId   string
 | 
			
		||||
		RepoLink   string
 | 
			
		||||
		CloneLink  struct {
 | 
			
		||||
			SSH   string
 | 
			
		||||
			HTTPS string
 | 
			
		||||
@@ -98,6 +106,10 @@ func (ctx *Context) Handle(status int, title string, err error) {
 | 
			
		||||
	ctx.HTML(status, fmt.Sprintf("status/%d", status))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ctx *Context) Debug(msg string, args ...interface{}) {
 | 
			
		||||
	log.Debug(msg, args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ctx *Context) GetCookie(name string) string {
 | 
			
		||||
	cookie, err := ctx.Req.Cookie(name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,8 @@ import (
 | 
			
		||||
 | 
			
		||||
	"github.com/codegangsta/martini"
 | 
			
		||||
 | 
			
		||||
	"github.com/gogits/git"
 | 
			
		||||
 | 
			
		||||
	"github.com/gogits/gogs/models"
 | 
			
		||||
	"github.com/gogits/gogs/modules/base"
 | 
			
		||||
)
 | 
			
		||||
@@ -25,8 +27,12 @@ func RepoAssignment(redirect bool) martini.Handler {
 | 
			
		||||
			err  error
 | 
			
		||||
		)
 | 
			
		||||
 | 
			
		||||
		userName := params["username"]
 | 
			
		||||
		repoName := params["reponame"]
 | 
			
		||||
		branchName := params["branchname"]
 | 
			
		||||
 | 
			
		||||
		// get repository owner
 | 
			
		||||
		ctx.Repo.IsOwner = ctx.IsSigned && ctx.User.LowerName == strings.ToLower(params["username"])
 | 
			
		||||
		ctx.Repo.IsOwner = ctx.IsSigned && ctx.User.LowerName == strings.ToLower(userName)
 | 
			
		||||
 | 
			
		||||
		if !ctx.Repo.IsOwner {
 | 
			
		||||
			user, err = models.GetUserByName(params["username"])
 | 
			
		||||
@@ -51,10 +57,8 @@ func RepoAssignment(redirect bool) martini.Handler {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ctx.Repo.Owner = user
 | 
			
		||||
 | 
			
		||||
		// get repository
 | 
			
		||||
		repo, err := models.GetRepositoryByName(user.Id, params["reponame"])
 | 
			
		||||
		repo, err := models.GetRepositoryByName(user.Id, repoName)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if err == models.ErrRepoNotExist {
 | 
			
		||||
				ctx.Handle(404, "RepoAssignment", err)
 | 
			
		||||
@@ -62,29 +66,69 @@ func RepoAssignment(redirect bool) martini.Handler {
 | 
			
		||||
				ctx.Redirect("/")
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			ctx.Handle(200, "RepoAssignment", err)
 | 
			
		||||
			ctx.Handle(404, "RepoAssignment", err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		ctx.Repo.Repository = repo
 | 
			
		||||
 | 
			
		||||
		ctx.Repo.IsValid = true
 | 
			
		||||
		if ctx.User != nil {
 | 
			
		||||
		gitRepo, err := git.OpenRepository(models.RepoPath(userName, repoName))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			ctx.Handle(404, "RepoAssignment Invalid repo", err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		ctx.Repo.GitRepo = gitRepo
 | 
			
		||||
 | 
			
		||||
	detect:
 | 
			
		||||
		if len(branchName) > 0 {
 | 
			
		||||
			// TODO check tag
 | 
			
		||||
			if models.IsBranchExist(user.Name, repoName, branchName) {
 | 
			
		||||
				ctx.Repo.IsBranch = true
 | 
			
		||||
				ctx.Repo.BranchName = branchName
 | 
			
		||||
 | 
			
		||||
				ctx.Repo.Commit, err = gitRepo.GetCommitOfBranch(branchName)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					ctx.Handle(404, "RepoAssignment invalid branch", nil)
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				ctx.Repo.CommitId = ctx.Repo.Commit.Oid.String()
 | 
			
		||||
 | 
			
		||||
			} else if len(branchName) == 40 {
 | 
			
		||||
				ctx.Repo.IsCommit = true
 | 
			
		||||
				ctx.Repo.CommitId = branchName
 | 
			
		||||
				ctx.Repo.BranchName = branchName
 | 
			
		||||
 | 
			
		||||
				ctx.Repo.Commit, err = gitRepo.GetCommit(branchName)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					ctx.Handle(404, "RepoAssignment invalid commit", nil)
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				ctx.Handle(404, "RepoAssignment invalid repo", nil)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		} else {
 | 
			
		||||
			branchName = "master"
 | 
			
		||||
			goto detect
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if ctx.IsSigned {
 | 
			
		||||
			ctx.Repo.IsWatching = models.IsWatching(ctx.User.Id, repo.Id)
 | 
			
		||||
		}
 | 
			
		||||
		ctx.Repo.Repository = repo
 | 
			
		||||
 | 
			
		||||
		ctx.Repo.Owner = user
 | 
			
		||||
		ctx.Repo.CloneLink.SSH = fmt.Sprintf("%s@%s:%s/%s.git", base.RunUser, base.Domain, user.LowerName, repo.LowerName)
 | 
			
		||||
		ctx.Repo.CloneLink.HTTPS = fmt.Sprintf("%s%s/%s.git", base.AppUrl, user.LowerName, repo.LowerName)
 | 
			
		||||
		ctx.Repo.RepoLink = "/" + user.Name + "/" + repo.Name
 | 
			
		||||
 | 
			
		||||
		if len(params["branchname"]) == 0 {
 | 
			
		||||
			params["branchname"] = "master"
 | 
			
		||||
		}
 | 
			
		||||
		ctx.Data["Branchname"] = params["branchname"]
 | 
			
		||||
 | 
			
		||||
		ctx.Data["IsRepositoryValid"] = true
 | 
			
		||||
		ctx.Data["BranchName"] = ctx.Repo.BranchName
 | 
			
		||||
		ctx.Data["CommitId"] = ctx.Repo.CommitId
 | 
			
		||||
		ctx.Data["Repository"] = repo
 | 
			
		||||
		ctx.Data["Owner"] = user
 | 
			
		||||
		ctx.Data["Title"] = user.Name + "/" + repo.Name
 | 
			
		||||
		ctx.Data["CloneLink"] = ctx.Repo.CloneLink
 | 
			
		||||
		ctx.Data["RepositoryLink"] = ctx.Data["Title"]
 | 
			
		||||
		ctx.Data["RepoLink"] = ctx.Repo.RepoLink
 | 
			
		||||
		ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner
 | 
			
		||||
		ctx.Data["IsRepositoryWatching"] = ctx.Repo.IsWatching
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -1197,13 +1197,13 @@ html, body {
 | 
			
		||||
    line-height: 42px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#issue .issue-closed{
 | 
			
		||||
    border-bottom: 3px solid #CCC;
 | 
			
		||||
#issue .issue-closed, #issue .issue-opened {
 | 
			
		||||
    border-bottom: 2px solid #CCC;
 | 
			
		||||
    margin-bottom: 24px;
 | 
			
		||||
    padding-bottom: 24px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#issue .issue-closed .btn-danger,#issue .issue-opened .btn-success{
 | 
			
		||||
#issue .issue-closed .label-danger,#issue .issue-opened .label-success{
 | 
			
		||||
    margin: 0 .8em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										103
									
								
								public/js/app.js
									
									
									
									
									
								
							
							
						
						
									
										103
									
								
								public/js/app.js
									
									
									
									
									
								
							@@ -56,6 +56,43 @@ var Gogits = {
 | 
			
		||||
        },
 | 
			
		||||
        toggleShow: function () {
 | 
			
		||||
            $(this).removeClass("hidden");
 | 
			
		||||
        },
 | 
			
		||||
        toggleAjax: function (successCallback) {
 | 
			
		||||
            var url = $(this).data("ajax");
 | 
			
		||||
            var method = $(this).data('ajax-method') || 'get';
 | 
			
		||||
            var ajaxName = $(this).data('ajax-name');
 | 
			
		||||
            var data = {};
 | 
			
		||||
            $('[data-ajax-rel=' + ajaxName + ']').each(function () {
 | 
			
		||||
                var field = $(this).data("ajax-field");
 | 
			
		||||
                var t = $(this).data("ajax-val");
 | 
			
		||||
                if (t == "val") {
 | 
			
		||||
                    data[field] = $(this).val();
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
                if (t == "txt") {
 | 
			
		||||
                    data[field] = $(this).text();
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
                if (t == "html") {
 | 
			
		||||
                    data[field] = $(this).html();
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
                if (t == "data") {
 | 
			
		||||
                    data[field] = $(this).data("ajax-data");
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
                return true;
 | 
			
		||||
            });
 | 
			
		||||
            $.ajax({
 | 
			
		||||
                url: url,
 | 
			
		||||
                method: method.toUpperCase(),
 | 
			
		||||
                data: data,
 | 
			
		||||
                success: function (d) {
 | 
			
		||||
                    if (successCallback) {
 | 
			
		||||
                        successCallback(d);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
    })
 | 
			
		||||
}(jQuery));
 | 
			
		||||
@@ -362,21 +399,24 @@ function initRepository() {
 | 
			
		||||
 | 
			
		||||
function initInstall() {
 | 
			
		||||
    // database type change
 | 
			
		||||
    $('#install-database').on("change", function () {
 | 
			
		||||
        var val = $(this).val();
 | 
			
		||||
        if (val != "sqlite") {
 | 
			
		||||
            $('.server-sql').show();
 | 
			
		||||
            $('.sqlite-setting').addClass("hide");
 | 
			
		||||
            if (val == "pgsql") {
 | 
			
		||||
                $('.pgsql-setting').removeClass("hide");
 | 
			
		||||
    (function () {
 | 
			
		||||
        $('#install-database').on("change", function () {
 | 
			
		||||
            var val = $(this).val();
 | 
			
		||||
            if (val != "sqlite") {
 | 
			
		||||
                $('.server-sql').show();
 | 
			
		||||
                $('.sqlite-setting').addClass("hide");
 | 
			
		||||
                if (val == "pgsql") {
 | 
			
		||||
                    $('.pgsql-setting').removeClass("hide");
 | 
			
		||||
                } else {
 | 
			
		||||
                    $('.pgsql-setting').addClass("hide");
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                $('.pgsql-setting').addClass("hide");
 | 
			
		||||
                $('.server-sql').hide();
 | 
			
		||||
                $('.sqlite-setting').removeClass("hide");
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            $('.server-sql').hide();
 | 
			
		||||
            $('.sqlite-setting').removeClass("hide");
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
        });
 | 
			
		||||
    }());
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function initIssue() {
 | 
			
		||||
@@ -386,11 +426,11 @@ function initIssue() {
 | 
			
		||||
        var $openBtn = $('#issue-open-btn');
 | 
			
		||||
        $('#issue-reply-content').on("keyup", function () {
 | 
			
		||||
            if ($(this).val().length) {
 | 
			
		||||
                $closeBtn.text($closeBtn.data("text"));
 | 
			
		||||
                $openBtn.text($openBtn.data("text"));
 | 
			
		||||
                $closeBtn.val($closeBtn.data("text"));
 | 
			
		||||
                $openBtn.val($openBtn.data("text"));
 | 
			
		||||
            } else {
 | 
			
		||||
                $closeBtn.text($closeBtn.data("origin"));
 | 
			
		||||
                $openBtn.text($openBtn.data("origin"));
 | 
			
		||||
                $closeBtn.val($closeBtn.data("origin"));
 | 
			
		||||
                $openBtn.val($openBtn.data("origin"));
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }());
 | 
			
		||||
@@ -406,6 +446,35 @@ function initIssue() {
 | 
			
		||||
            $('#issue-edit-title,#issue-edit-content,.issue-edit-cancel,.issue-edit-save').toggleHide();
 | 
			
		||||
        })
 | 
			
		||||
    }());
 | 
			
		||||
 | 
			
		||||
    // issue ajax update
 | 
			
		||||
    (function () {
 | 
			
		||||
        $('.issue-edit-save').on("click", function () {
 | 
			
		||||
            $(this).toggleAjax(function (json) {
 | 
			
		||||
                if (json.ok) {
 | 
			
		||||
                    $('.issue-head h1.title').text(json.title);
 | 
			
		||||
                    $('.issue-main > .issue-content .content').html(json.content);
 | 
			
		||||
                    $('.issue-edit-cancel').trigger("click");
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }());
 | 
			
		||||
 | 
			
		||||
    // issue ajax preview
 | 
			
		||||
    (function () {
 | 
			
		||||
        $('[data-ajax-name=issue-preview]').on("click", function () {
 | 
			
		||||
            var $this = $(this);
 | 
			
		||||
            $this.toggleAjax(function (json) {
 | 
			
		||||
                if (json.ok) {
 | 
			
		||||
                    $($this.data("preview")).html(json.content);
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
        });
 | 
			
		||||
        $('.issue-write a[data-toggle]').on("click", function () {
 | 
			
		||||
            $('.issue-preview-content').html("loading...");
 | 
			
		||||
        });
 | 
			
		||||
    }())
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
(function ($) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										18
									
								
								routers/api/v1/miscellaneous.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								routers/api/v1/miscellaneous.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
// 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 v1
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/gogits/gogs/modules/base"
 | 
			
		||||
	"github.com/gogits/gogs/modules/middleware"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Markdown(ctx *middleware.Context) {
 | 
			
		||||
	content := ctx.Query("content")
 | 
			
		||||
	ctx.Render.JSON(200, map[string]interface{}{
 | 
			
		||||
		"ok":      true,
 | 
			
		||||
		"content": string(base.RenderMarkdown([]byte(content), "")),
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
@@ -6,13 +6,46 @@ package routers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/Unknwon/goconfig"
 | 
			
		||||
	"github.com/codegangsta/martini"
 | 
			
		||||
 | 
			
		||||
	"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"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Check run mode(Default of martini is Dev).
 | 
			
		||||
func checkRunMode() {
 | 
			
		||||
	switch base.Cfg.MustValue("", "RUN_MODE") {
 | 
			
		||||
	case "prod":
 | 
			
		||||
		martini.Env = martini.Prod
 | 
			
		||||
	case "test":
 | 
			
		||||
		martini.Env = martini.Test
 | 
			
		||||
	}
 | 
			
		||||
	log.Info("Run Mode: %s", strings.Title(martini.Env))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GlobalInit is for global configuration reload-able.
 | 
			
		||||
func GlobalInit() {
 | 
			
		||||
	base.NewConfigContext()
 | 
			
		||||
	mailer.NewMailerContext()
 | 
			
		||||
	models.LoadModelsConfig()
 | 
			
		||||
	models.LoadRepoConfig()
 | 
			
		||||
	models.NewRepoContext()
 | 
			
		||||
	if err := models.NewEngine(); err != nil && base.InstallLock {
 | 
			
		||||
		log.Error("%v", err)
 | 
			
		||||
		os.Exit(2)
 | 
			
		||||
	}
 | 
			
		||||
	base.NewServices()
 | 
			
		||||
	checkRunMode()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Install(ctx *middleware.Context, form auth.InstallForm) {
 | 
			
		||||
	if base.InstallLock {
 | 
			
		||||
		ctx.Handle(404, "install.Install", errors.New("Installation is prohibited"))
 | 
			
		||||
@@ -20,14 +53,114 @@ func Install(ctx *middleware.Context, form auth.InstallForm) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx.Data["Title"] = "Install"
 | 
			
		||||
	ctx.Data["DbCfg"] = models.DbCfg
 | 
			
		||||
	ctx.Data["RepoRootPath"] = base.RepoRootPath
 | 
			
		||||
	ctx.Data["RunUser"] = base.RunUser
 | 
			
		||||
	ctx.Data["AppUrl"] = base.AppUrl
 | 
			
		||||
	ctx.Data["PageIsInstall"] = true
 | 
			
		||||
 | 
			
		||||
	// Get and assign value to install form.
 | 
			
		||||
	if len(form.Host) == 0 {
 | 
			
		||||
		form.Host = models.DbCfg.Host
 | 
			
		||||
	}
 | 
			
		||||
	if len(form.User) == 0 {
 | 
			
		||||
		form.User = models.DbCfg.User
 | 
			
		||||
	}
 | 
			
		||||
	if len(form.Passwd) == 0 {
 | 
			
		||||
		form.Passwd = models.DbCfg.Pwd
 | 
			
		||||
	}
 | 
			
		||||
	if len(form.DatabaseName) == 0 {
 | 
			
		||||
		form.DatabaseName = models.DbCfg.Name
 | 
			
		||||
	}
 | 
			
		||||
	if len(form.DatabasePath) == 0 {
 | 
			
		||||
		form.DatabasePath = models.DbCfg.Path
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(form.RepoRootPath) == 0 {
 | 
			
		||||
		form.RepoRootPath = base.RepoRootPath
 | 
			
		||||
	}
 | 
			
		||||
	if len(form.RunUser) == 0 {
 | 
			
		||||
		form.RunUser = base.RunUser
 | 
			
		||||
	}
 | 
			
		||||
	if len(form.Domain) == 0 {
 | 
			
		||||
		form.Domain = base.Domain
 | 
			
		||||
	}
 | 
			
		||||
	if len(form.AppUrl) == 0 {
 | 
			
		||||
		form.AppUrl = base.AppUrl
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	auth.AssignForm(form, ctx.Data)
 | 
			
		||||
 | 
			
		||||
	if ctx.Req.Method == "GET" {
 | 
			
		||||
		ctx.HTML(200, "install")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ctx.HasError() {
 | 
			
		||||
		ctx.HTML(200, "install")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Pass basic check, now test configuration.
 | 
			
		||||
	// Test database setting.
 | 
			
		||||
	dbTypes := map[string]string{"mysql": "mysql", "pgsql": "postgres", "sqlite": "sqlite3"}
 | 
			
		||||
	models.DbCfg.Type = dbTypes[form.Database]
 | 
			
		||||
	models.DbCfg.Host = form.Host
 | 
			
		||||
	models.DbCfg.User = form.User
 | 
			
		||||
	models.DbCfg.Pwd = form.Passwd
 | 
			
		||||
	models.DbCfg.Name = form.DatabaseName
 | 
			
		||||
	models.DbCfg.SslMode = form.SslMode
 | 
			
		||||
	models.DbCfg.Path = form.DatabasePath
 | 
			
		||||
 | 
			
		||||
	if err := models.NewEngine(); err != nil {
 | 
			
		||||
		ctx.RenderWithErr("Database setting is not correct: "+err.Error(), "install", &form)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Test repository root path.
 | 
			
		||||
	if err := os.MkdirAll(form.RepoRootPath, os.ModePerm); err != nil {
 | 
			
		||||
		ctx.RenderWithErr("Repository root path is invalid: "+err.Error(), "install", &form)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Create admin account.
 | 
			
		||||
	if _, err := models.RegisterUser(&models.User{Name: form.AdminName, Email: form.AdminEmail, Passwd: form.AdminPasswd,
 | 
			
		||||
		IsAdmin: true, IsActive: true}); err != nil {
 | 
			
		||||
		if err != models.ErrUserAlreadyExist {
 | 
			
		||||
			ctx.RenderWithErr("Admin account setting is invalid: "+err.Error(), "install", &form)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Save settings.
 | 
			
		||||
	base.Cfg.SetValue("database", "DB_TYPE", models.DbCfg.Type)
 | 
			
		||||
	base.Cfg.SetValue("database", "HOST", models.DbCfg.Host)
 | 
			
		||||
	base.Cfg.SetValue("database", "NAME", models.DbCfg.Name)
 | 
			
		||||
	base.Cfg.SetValue("database", "USER", models.DbCfg.User)
 | 
			
		||||
	base.Cfg.SetValue("database", "PASSWD", models.DbCfg.Pwd)
 | 
			
		||||
	base.Cfg.SetValue("database", "SSL_MODE", models.DbCfg.SslMode)
 | 
			
		||||
	base.Cfg.SetValue("database", "PATH", models.DbCfg.Path)
 | 
			
		||||
 | 
			
		||||
	base.Cfg.SetValue("repository", "ROOT", form.RepoRootPath)
 | 
			
		||||
	base.Cfg.SetValue("", "RUN_USER", form.RunUser)
 | 
			
		||||
	base.Cfg.SetValue("server", "DOMAIN", form.Domain)
 | 
			
		||||
	base.Cfg.SetValue("server", "ROOT_URL", form.AppUrl)
 | 
			
		||||
 | 
			
		||||
	if len(form.Host) > 0 {
 | 
			
		||||
		base.Cfg.SetValue("mailer", "ENABLED", "true")
 | 
			
		||||
		base.Cfg.SetValue("mailer", "HOST", form.SmtpHost)
 | 
			
		||||
		base.Cfg.SetValue("mailer", "USER", form.SmtpEmail)
 | 
			
		||||
		base.Cfg.SetValue("mailer", "PASSWD", form.SmtpPasswd)
 | 
			
		||||
 | 
			
		||||
		base.Cfg.SetValue("service", "REGISTER_EMAIL_CONFIRM", base.ToStr(form.RegisterConfirm == "on"))
 | 
			
		||||
		base.Cfg.SetValue("service", "ENABLE_NOTIFY_MAIL", base.ToStr(form.MailNotify == "on"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	base.Cfg.SetValue("security", "INSTALL_LOCK", "true")
 | 
			
		||||
 | 
			
		||||
	if err := goconfig.SaveConfigFile(base.Cfg, "custom/conf/app.ini"); err != nil {
 | 
			
		||||
		ctx.RenderWithErr("Fail to save configuration: "+err.Error(), "install", &form)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	GlobalInit()
 | 
			
		||||
 | 
			
		||||
	log.Info("First-time run install finished!")
 | 
			
		||||
	ctx.Redirect("/user/login")
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -11,21 +11,15 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Branches(ctx *middleware.Context, params martini.Params) {
 | 
			
		||||
	if !ctx.Repo.IsValid {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	brs, err := models.GetBranches(params["username"], params["reponame"])
 | 
			
		||||
	brs, err := models.GetBranches(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		ctx.Handle(200, "repo.Branches", err)
 | 
			
		||||
		ctx.Handle(404, "repo.Branches", err)
 | 
			
		||||
		return
 | 
			
		||||
	} else if len(brs) == 0 {
 | 
			
		||||
		ctx.Handle(404, "repo.Branches", nil)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx.Data["Username"] = params["username"]
 | 
			
		||||
	ctx.Data["Reponame"] = params["reponame"]
 | 
			
		||||
	ctx.Data["Branches"] = brs
 | 
			
		||||
	ctx.Data["IsRepoToolbarBranches"] = true
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -50,16 +50,12 @@ func Commits(ctx *middleware.Context, params martini.Params) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Diff(ctx *middleware.Context, params martini.Params) {
 | 
			
		||||
	userName := params["username"]
 | 
			
		||||
	repoName := params["reponame"]
 | 
			
		||||
	branchName := params["branchname"]
 | 
			
		||||
	commitId := params["commitid"]
 | 
			
		||||
	userName := ctx.Repo.Owner.Name
 | 
			
		||||
	repoName := ctx.Repo.Repository.Name
 | 
			
		||||
	branchName := ctx.Repo.BranchName
 | 
			
		||||
	commitId := ctx.Repo.CommitId
 | 
			
		||||
 | 
			
		||||
	commit, err := models.GetCommit(userName, repoName, branchName, commitId)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		ctx.Handle(404, "repo.Diff", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	commit := ctx.Repo.Commit
 | 
			
		||||
 | 
			
		||||
	diff, err := models.GetDiff(models.RepoPath(userName, repoName), commitId)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@@ -85,11 +81,9 @@ func Diff(ctx *middleware.Context, params martini.Params) {
 | 
			
		||||
		return isImage
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	shortSha := params["commitid"][:10]
 | 
			
		||||
	ctx.Data["IsImageFile"] = isImageFile
 | 
			
		||||
	ctx.Data["Title"] = commit.Message() + " · " + shortSha
 | 
			
		||||
	ctx.Data["Title"] = commit.Message() + " · " + base.ShortSha(commitId)
 | 
			
		||||
	ctx.Data["Commit"] = commit
 | 
			
		||||
	ctx.Data["ShortSha"] = shortSha
 | 
			
		||||
	ctx.Data["Diff"] = diff
 | 
			
		||||
	ctx.Data["IsRepoToolbarCommits"] = true
 | 
			
		||||
	ctx.Data["SourcePath"] = "/" + path.Join(userName, repoName, "src", commitId)
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@ package repo
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/codegangsta/martini"
 | 
			
		||||
 | 
			
		||||
@@ -19,10 +20,6 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Issues(ctx *middleware.Context) {
 | 
			
		||||
	if !ctx.Repo.IsValid {
 | 
			
		||||
		ctx.Handle(404, "issue.Issues(invalid repo):", nil)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx.Data["Title"] = "Issues"
 | 
			
		||||
	ctx.Data["IsRepoToolbarIssues"] = true
 | 
			
		||||
	ctx.Data["IsRepoToolbarIssuesList"] = true
 | 
			
		||||
@@ -79,10 +76,6 @@ func Issues(ctx *middleware.Context) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func CreateIssue(ctx *middleware.Context, params martini.Params, form auth.CreateIssueForm) {
 | 
			
		||||
	if !ctx.Repo.IsValid {
 | 
			
		||||
		ctx.Handle(404, "issue.CreateIssue(invalid repo):", nil)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx.Data["Title"] = "Create issue"
 | 
			
		||||
	ctx.Data["IsRepoToolbarIssues"] = true
 | 
			
		||||
	ctx.Data["IsRepoToolbarIssuesList"] = false
 | 
			
		||||
@@ -125,10 +118,6 @@ func CreateIssue(ctx *middleware.Context, params martini.Params, form auth.Creat
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ViewIssue(ctx *middleware.Context, params martini.Params) {
 | 
			
		||||
	if !ctx.Repo.IsValid {
 | 
			
		||||
		ctx.Handle(404, "issue.ViewIssue(invalid repo):", nil)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	index, err := base.StrTo(params["index"]).Int()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		ctx.Handle(404, "issue.ViewIssue", err)
 | 
			
		||||
@@ -152,7 +141,7 @@ func ViewIssue(ctx *middleware.Context, params martini.Params) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	issue.Poster = u
 | 
			
		||||
	issue.Content = string(base.RenderMarkdown([]byte(issue.Content), ""))
 | 
			
		||||
	issue.RenderedContent = string(base.RenderMarkdown([]byte(issue.Content), ""))
 | 
			
		||||
 | 
			
		||||
	// Get comments.
 | 
			
		||||
	comments, err := models.GetIssueComments(issue.Id)
 | 
			
		||||
@@ -175,16 +164,13 @@ func ViewIssue(ctx *middleware.Context, params martini.Params) {
 | 
			
		||||
	ctx.Data["Title"] = issue.Name
 | 
			
		||||
	ctx.Data["Issue"] = issue
 | 
			
		||||
	ctx.Data["Comments"] = comments
 | 
			
		||||
	ctx.Data["IsIssueOwner"] = ctx.Repo.IsOwner || issue.PosterId == ctx.User.Id
 | 
			
		||||
	ctx.Data["IsRepoToolbarIssues"] = true
 | 
			
		||||
	ctx.Data["IsRepoToolbarIssuesList"] = false
 | 
			
		||||
	ctx.HTML(200, "issue/view")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func UpdateIssue(ctx *middleware.Context, params martini.Params, form auth.CreateIssueForm) {
 | 
			
		||||
	if !ctx.Repo.IsValid {
 | 
			
		||||
		ctx.Handle(404, "issue.UpdateIssue(invalid repo):", nil)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	index, err := base.StrTo(params["index"]).Int()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		ctx.Handle(404, "issue.UpdateIssue", err)
 | 
			
		||||
@@ -216,29 +202,21 @@ func UpdateIssue(ctx *middleware.Context, params martini.Params, form auth.Creat
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx.Data["Title"] = issue.Name
 | 
			
		||||
	ctx.Data["Issue"] = issue
 | 
			
		||||
	ctx.JSON(200, map[string]interface{}{
 | 
			
		||||
		"ok":      true,
 | 
			
		||||
		"title":   issue.Name,
 | 
			
		||||
		"content": string(base.RenderMarkdown([]byte(issue.Content), "")),
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Comment(ctx *middleware.Context, params martini.Params) {
 | 
			
		||||
	fmt.Println(ctx.Query("change_status"))
 | 
			
		||||
	if !ctx.Repo.IsValid {
 | 
			
		||||
		ctx.Handle(404, "issue.Comment(invalid repo):", nil)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	index, err := base.StrTo(ctx.Query("issueIndex")).Int()
 | 
			
		||||
	index, err := base.StrTo(ctx.Query("issueIndex")).Int64()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		ctx.Handle(404, "issue.Comment", err)
 | 
			
		||||
		ctx.Handle(404, "issue.Comment(get index)", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	content := ctx.Query("content")
 | 
			
		||||
	if len(content) == 0 {
 | 
			
		||||
		ctx.Redirect(fmt.Sprintf("/%s/%s/issues/%d", ctx.User.Name, ctx.Repo.Repository.Name, index))
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, int64(index))
 | 
			
		||||
	issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, index)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if err == models.ErrIssueNotExist {
 | 
			
		||||
			ctx.Handle(404, "issue.Comment", err)
 | 
			
		||||
@@ -248,16 +226,46 @@ func Comment(ctx *middleware.Context, params martini.Params) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch params["action"] {
 | 
			
		||||
	case "new":
 | 
			
		||||
		if err = models.CreateComment(ctx.User.Id, issue.Id, 0, 0, content); err != nil {
 | 
			
		||||
			ctx.Handle(500, "issue.Comment(create comment)", err)
 | 
			
		||||
	// 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 {
 | 
			
		||||
				ctx.Handle(200, "issue.Comment(update issue status)", err)
 | 
			
		||||
				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)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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
 | 
			
		||||
			}
 | 
			
		||||
			log.Trace("%s Comment created: %d", ctx.Req.RequestURI, issue.Id)
 | 
			
		||||
		default:
 | 
			
		||||
			ctx.Handle(404, "issue.Comment", err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		log.Trace("%s Comment created: %d", ctx.Req.RequestURI, issue.Id)
 | 
			
		||||
	default:
 | 
			
		||||
		ctx.Handle(404, "issue.Comment", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx.Redirect(fmt.Sprintf("/%s/%s/issues/%d", ctx.User.Name, ctx.Repo.Repository.Name, index))
 | 
			
		||||
 
 | 
			
		||||
@@ -53,20 +53,20 @@ func Create(ctx *middleware.Context, form auth.CreateRepoForm) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Single(ctx *middleware.Context, params martini.Params) {
 | 
			
		||||
	if !ctx.Repo.IsValid {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	branchName := ctx.Repo.BranchName
 | 
			
		||||
	commitId := ctx.Repo.CommitId
 | 
			
		||||
	userName := ctx.Repo.Owner.Name
 | 
			
		||||
	repoName := ctx.Repo.Repository.Name
 | 
			
		||||
 | 
			
		||||
	branchName := params["branchname"]
 | 
			
		||||
	userName := params["username"]
 | 
			
		||||
	repoName := params["reponame"]
 | 
			
		||||
	repoLink := ctx.Repo.RepoLink
 | 
			
		||||
	branchLink := ctx.Repo.RepoLink + "/src/" + branchName
 | 
			
		||||
	rawLink := ctx.Repo.RepoLink + "/raw/" + branchName
 | 
			
		||||
 | 
			
		||||
	// Get tree path
 | 
			
		||||
	treename := params["_1"]
 | 
			
		||||
 | 
			
		||||
	if len(treename) > 0 && treename[len(treename)-1] == '/' {
 | 
			
		||||
		ctx.Redirect("/" + ctx.Repo.Owner.LowerName + "/" +
 | 
			
		||||
			ctx.Repo.Repository.Name + "/src/" + branchName + "/" + treename[:len(treename)-1])
 | 
			
		||||
		ctx.Redirect(repoLink + "/src/" + branchName + "/" + treename[:len(treename)-1])
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -84,23 +84,17 @@ func Single(ctx *middleware.Context, params martini.Params) {
 | 
			
		||||
	}
 | 
			
		||||
	ctx.Data["Branches"] = brs
 | 
			
		||||
 | 
			
		||||
	var commitId string
 | 
			
		||||
	isViewBranch := models.IsBranchExist(userName, repoName, branchName)
 | 
			
		||||
	if !isViewBranch {
 | 
			
		||||
		commitId = branchName
 | 
			
		||||
	}
 | 
			
		||||
	isViewBranch := ctx.Repo.IsBranch
 | 
			
		||||
	ctx.Data["IsViewBranch"] = isViewBranch
 | 
			
		||||
 | 
			
		||||
	repoFile, err := models.GetTargetFile(userName, repoName,
 | 
			
		||||
		branchName, commitId, treename)
 | 
			
		||||
 | 
			
		||||
	if err != nil && err != models.ErrRepoFileNotExist {
 | 
			
		||||
		ctx.Handle(404, "repo.Single(GetTargetFile)", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	branchLink := "/" + ctx.Repo.Owner.LowerName + "/" + ctx.Repo.Repository.Name + "/src/" + branchName
 | 
			
		||||
	rawLink := "/" + ctx.Repo.Owner.LowerName + "/" + ctx.Repo.Repository.Name + "/raw/" + branchName
 | 
			
		||||
 | 
			
		||||
	if len(treename) != 0 && repoFile == nil {
 | 
			
		||||
		ctx.Handle(404, "repo.Single", nil)
 | 
			
		||||
		return
 | 
			
		||||
@@ -142,8 +136,7 @@ func Single(ctx *middleware.Context, params martini.Params) {
 | 
			
		||||
 | 
			
		||||
	} else {
 | 
			
		||||
		// Directory and file list.
 | 
			
		||||
		files, err := models.GetReposFiles(userName, repoName,
 | 
			
		||||
			branchName, commitId, treename)
 | 
			
		||||
		files, err := models.GetReposFiles(userName, repoName, ctx.Repo.CommitId, treename)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			ctx.Handle(404, "repo.Single(GetReposFiles)", err)
 | 
			
		||||
			return
 | 
			
		||||
@@ -200,18 +193,7 @@ func Single(ctx *middleware.Context, params martini.Params) {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Get latest commit according username and repo name.
 | 
			
		||||
	commit, err := models.GetCommit(userName, repoName,
 | 
			
		||||
		branchName, commitId)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Error("repo.Single(GetCommit): %v", err)
 | 
			
		||||
		ctx.Handle(404, "repo.Single(GetCommit)", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	ctx.Data["LastCommit"] = commit
 | 
			
		||||
 | 
			
		||||
	ctx.Data["CommitId"] = commitId
 | 
			
		||||
 | 
			
		||||
	ctx.Data["LastCommit"] = ctx.Repo.Commit
 | 
			
		||||
	ctx.Data["Paths"] = Paths
 | 
			
		||||
	ctx.Data["Treenames"] = treenames
 | 
			
		||||
	ctx.Data["BranchLink"] = branchLink
 | 
			
		||||
@@ -219,11 +201,6 @@ func Single(ctx *middleware.Context, params martini.Params) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SingleDownload(ctx *middleware.Context, params martini.Params) {
 | 
			
		||||
	if !ctx.Repo.IsValid {
 | 
			
		||||
		ctx.Handle(404, "repo.SingleDownload", nil)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Get tree path
 | 
			
		||||
	treename := params["_1"]
 | 
			
		||||
 | 
			
		||||
@@ -263,10 +240,6 @@ func SingleDownload(ctx *middleware.Context, params martini.Params) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Http(ctx *middleware.Context, params martini.Params) {
 | 
			
		||||
	/*if !ctx.Repo.IsValid {
 | 
			
		||||
		return
 | 
			
		||||
	}*/
 | 
			
		||||
 | 
			
		||||
	// TODO: access check
 | 
			
		||||
 | 
			
		||||
	username := params["username"]
 | 
			
		||||
 
 | 
			
		||||
@@ -120,7 +120,7 @@ func SignIn(ctx *middleware.Context, form auth.LogInForm) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if hasErr, ok := ctx.Data["HasError"]; ok && hasErr.(bool) {
 | 
			
		||||
	if ctx.HasError() {
 | 
			
		||||
		ctx.HTML(200, "user/signin")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
@@ -308,17 +308,19 @@ func Issues(ctx *middleware.Context) {
 | 
			
		||||
 | 
			
		||||
	showRepos := make([]models.Repository, 0, len(repos))
 | 
			
		||||
 | 
			
		||||
	var closedIssueCount, createdByCount int
 | 
			
		||||
	isShowClosed := ctx.Query("state") == "closed"
 | 
			
		||||
	var closedIssueCount, createdByCount, allIssueCount int
 | 
			
		||||
 | 
			
		||||
	// Get all issues.
 | 
			
		||||
	allIssues := make([]models.Issue, 0, 5*len(repos))
 | 
			
		||||
	for i, repo := range repos {
 | 
			
		||||
		issues, err := models.GetIssues(0, repo.Id, posterId, 0, page, false, false, "", "")
 | 
			
		||||
		issues, err := models.GetIssues(0, repo.Id, posterId, 0, page, isShowClosed, false, "", "")
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			ctx.Handle(200, "user.Issues(get issues)", err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		allIssueCount += repo.NumIssues
 | 
			
		||||
		closedIssueCount += repo.NumClosedIssues
 | 
			
		||||
 | 
			
		||||
		// Set repository information to issues.
 | 
			
		||||
@@ -330,12 +332,10 @@ func Issues(ctx *middleware.Context) {
 | 
			
		||||
		repos[i].NumOpenIssues = repo.NumIssues - repo.NumClosedIssues
 | 
			
		||||
		if repos[i].NumOpenIssues > 0 {
 | 
			
		||||
			showRepos = append(showRepos, repos[i])
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	showIssues := make([]models.Issue, 0, len(allIssues))
 | 
			
		||||
	isShowClosed := ctx.Query("state") == "closed"
 | 
			
		||||
	ctx.Data["IsShowClosed"] = isShowClosed
 | 
			
		||||
 | 
			
		||||
	// Get posters and filter issues.
 | 
			
		||||
@@ -361,9 +361,9 @@ func Issues(ctx *middleware.Context) {
 | 
			
		||||
 | 
			
		||||
	ctx.Data["Repos"] = showRepos
 | 
			
		||||
	ctx.Data["Issues"] = showIssues
 | 
			
		||||
	ctx.Data["AllIssueCount"] = len(allIssues)
 | 
			
		||||
	ctx.Data["AllIssueCount"] = allIssueCount
 | 
			
		||||
	ctx.Data["ClosedIssueCount"] = closedIssueCount
 | 
			
		||||
	ctx.Data["OpenIssueCount"] = len(allIssues) - closedIssueCount
 | 
			
		||||
	ctx.Data["OpenIssueCount"] = allIssueCount - closedIssueCount
 | 
			
		||||
	ctx.Data["CreatedByCount"] = createdByCount
 | 
			
		||||
	ctx.HTML(200, "issue/user")
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,9 +3,8 @@
 | 
			
		||||
    <form action="/install" method="post" class="form-horizontal card" id="install-card">
 | 
			
		||||
        {{.CsrfTokenHtml}}
 | 
			
		||||
        <h3>Install Steps For First-time Run</h3>
 | 
			
		||||
 | 
			
		||||
        <div class="alert alert-danger form-error{{if .HasError}}{{else}} hidden{{end}}">{{.ErrorMsg}}</div>
 | 
			
		||||
        <p class="help-block text-center">Gogs requires MySQL or PostgreSQL based on your choice</p>
 | 
			
		||||
        <p class="help-block text-center">Gogs requires MySQL or PostgreSQL, SQLite3 only available for official binary version</p>
 | 
			
		||||
        <div class="form-group">
 | 
			
		||||
            <label class="col-md-3 control-label">Database Type: </label>
 | 
			
		||||
            <div class="col-md-8">
 | 
			
		||||
@@ -16,26 +15,28 @@
 | 
			
		||||
                </select>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="server-sql">
 | 
			
		||||
            <div class="form-group">
 | 
			
		||||
                <label class="col-md-3 control-label">Host: </label>
 | 
			
		||||
 | 
			
		||||
                <div class="col-md-8">
 | 
			
		||||
                    <input name="host" class="form-control" placeholder="Type database server host, leave blank to keep default" value="{{.DbCfg.Host}}" required="required">
 | 
			
		||||
                    <input name="host" class="form-control" placeholder="Type database server host" value="{{.host}}" required="required">
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <div class="form-group">
 | 
			
		||||
                <label class="col-md-3 control-label">User: </label>
 | 
			
		||||
 | 
			
		||||
                <div class="col-md-8">
 | 
			
		||||
                    <input name="user" class="form-control" placeholder="Type database username" required="required" value="{{.DbCfg.User}}">
 | 
			
		||||
                    <input name="user" class="form-control" placeholder="Type database username" required="required" value="{{.user}}">
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <div class="form-group">
 | 
			
		||||
                <label class="col-md-3 control-label">Password: </label>
 | 
			
		||||
 | 
			
		||||
                <div class="col-md-8">
 | 
			
		||||
                    <input name="passwd" type="password" class="form-control" placeholder="Type database password" required="required" value="{{.DbCfg.Pwd}}">
 | 
			
		||||
                    <input name="passwd" type="password" class="form-control" placeholder="Type database password" required="required" value="{{.passwd}}">
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
@@ -43,7 +44,7 @@
 | 
			
		||||
                <label class="col-md-3 control-label">Database Name: </label>
 | 
			
		||||
 | 
			
		||||
                <div class="col-md-8">
 | 
			
		||||
                    <input name="database_name" type="text" class="form-control" placeholder="Type mysql database name" value="{{.DbCfg.Name}}" required="required">
 | 
			
		||||
                    <input name="database_name" type="text" class="form-control" placeholder="Type mysql database name" value="{{.database_name}}" required="required">
 | 
			
		||||
                    <p class="help-block">Recommend use INNODB engine with utf8_general_ci charset.</p>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
@@ -59,12 +60,13 @@
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="sqlite-setting hide">
 | 
			
		||||
            <div class="form-group">
 | 
			
		||||
                <label class="col-md-3 control-label">Path: </label>
 | 
			
		||||
 | 
			
		||||
                <div class="col-md-8">
 | 
			
		||||
                    <input name="database_path" class="form-control" placeholder="Type sqlite3 file path" value="{{.DbCfg.Path}}">
 | 
			
		||||
                    <input name="database_path" class="form-control" placeholder="Type sqlite3 file path" value="{{.database_path}}">
 | 
			
		||||
                    <p class="help-block">The file path of SQLite3 database.</p>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
@@ -73,12 +75,11 @@
 | 
			
		||||
        <hr/>
 | 
			
		||||
 | 
			
		||||
        <p class="help-block text-center">General Settings of Gogs</p>
 | 
			
		||||
 | 
			
		||||
        <div class="form-group">
 | 
			
		||||
            <label class="col-md-3 control-label">Repository Path: </label>
 | 
			
		||||
 | 
			
		||||
            <div class="col-md-8">
 | 
			
		||||
                <input name="repo_path" type="text" class="form-control" placeholder="Type your repository directory" value="{{.RepoRootPath}}" required="required">
 | 
			
		||||
                <input name="repo_path" type="text" class="form-control" placeholder="Type your repository directory" value="{{.repo_path}}" required="required">
 | 
			
		||||
 | 
			
		||||
                <p class="help-block">The git copy of each repository is saved in this directory.</p>
 | 
			
		||||
            </div>
 | 
			
		||||
@@ -88,16 +89,25 @@
 | 
			
		||||
            <label class="col-md-3 control-label">Run User: </label>
 | 
			
		||||
 | 
			
		||||
            <div class="col-md-8">
 | 
			
		||||
                <input name="run_user" type="text" class="form-control" placeholder="Type system user name" value="{{.RunUser}}" required="required">
 | 
			
		||||
                <input name="run_user" type="text" class="form-control" placeholder="Type system user name" value="{{.run_user}}" required="required">
 | 
			
		||||
                <p class="help-block">The user has access to visit and run Gogs.</p>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        
 | 
			
		||||
        <div class="form-group">
 | 
			
		||||
            <label class="col-md-3 control-label">Domain: </label>
 | 
			
		||||
 | 
			
		||||
            <div class="col-md-8">
 | 
			
		||||
                <input name="domain" type="text" class="form-control" placeholder="Type your domain name" value="{{.domain}}" required="required">
 | 
			
		||||
                <p class="help-block">This affects SSH clone URL.</p>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        
 | 
			
		||||
        <div class="form-group">
 | 
			
		||||
            <label class="col-md-3 control-label">App URL: </label>
 | 
			
		||||
 | 
			
		||||
            <div class="col-md-8">
 | 
			
		||||
                <input name="app_url" type="text" class="form-control" placeholder="Type app root URL " value="{{.AppUrl}}" required="required">
 | 
			
		||||
                <input name="app_url" type="text" class="form-control" placeholder="Type app root URL" value="{{.app_url}}" required="required">
 | 
			
		||||
                <p class="help-block">This affects HTTP/HTTPS clone URL and somewhere in e-mail.</p>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
@@ -105,35 +115,30 @@
 | 
			
		||||
        <hr/>
 | 
			
		||||
 | 
			
		||||
        <p class="help-block text-center">Admin Account Settings</p>
 | 
			
		||||
 | 
			
		||||
        <div class="form-group">
 | 
			
		||||
            <label class="col-md-3 control-label">Username: </label>
 | 
			
		||||
 | 
			
		||||
            <div class="col-md-8">
 | 
			
		||||
                <input name="admin_name" type="text" class="form-control" placeholder="Type admin user name" value="admin" required="required">
 | 
			
		||||
                <input name="admin_name" type="text" class="form-control" placeholder="Type admin user name" value="{{.admin_name}}" required="required">
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="form-group">
 | 
			
		||||
        <div class="form-group {{if .Err_AdminPasswd}}has-error has-feedback{{end}}">
 | 
			
		||||
            <label class="col-md-3 control-label">Password: </label>
 | 
			
		||||
 | 
			
		||||
            <div class="col-md-8">
 | 
			
		||||
                <input name="admin_pwd" type="password" class="form-control" placeholder="Type admin user password" required="required">
 | 
			
		||||
                <input name="admin_pwd" type="password" class="form-control" placeholder="Type admin user password" value="{{.admin_pwd}}" required="required">
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="form-group">
 | 
			
		||||
        <div class="form-group {{if .Err_AdminEmail}}has-error has-feedback{{end}}">
 | 
			
		||||
            <label class="col-md-3 control-label">E-mail: </label>
 | 
			
		||||
 | 
			
		||||
            <div class="col-md-8">
 | 
			
		||||
                <input name="admin_email" type="text" class="form-control" placeholder="Type admin user e-mail" required="required">
 | 
			
		||||
                <input name="admin_email" type="text" class="form-control" placeholder="Type admin user e-mail" value="{{.admin_email}}" required="required">
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <hr/>
 | 
			
		||||
 | 
			
		||||
        <div class="form-group text-center">
 | 
			
		||||
            <button class="btn btn-primary btn-lg">Test Configuration</button>
 | 
			
		||||
            <button class="btn btn-danger btn-lg">Install Gogs</button>
 | 
			
		||||
            <button class="btn btn-default btn-sm" type="button" data-toggle="modal" data-target="#advance-options-modal">
 | 
			
		||||
                Advanced Options
 | 
			
		||||
@@ -151,21 +156,21 @@
 | 
			
		||||
                            <label class="col-md-3 control-label">SMTP Host: </label>
 | 
			
		||||
 | 
			
		||||
                            <div class="col-md-8">
 | 
			
		||||
                                <input name="smtp_host" type="text" class="form-control" placeholder="Type SMTP host address">
 | 
			
		||||
                                <input name="smtp_host" type="text" class="form-control" placeholder="Type SMTP host address" value="{{.smtp_host}}">
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="form-group">
 | 
			
		||||
                            <label class="col-md-3 control-label">Email: </label>
 | 
			
		||||
 | 
			
		||||
                            <div class="col-md-8">
 | 
			
		||||
                                <input name="mailer_user" type="text" class="form-control" placeholder="Type SMTP user e-mail address">
 | 
			
		||||
                                <input name="mailer_user" type="text" class="form-control" placeholder="Type SMTP user e-mail address" value="{{.mailer_user}}">
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="form-group">
 | 
			
		||||
                            <label class="col-md-3 control-label">Password: </label>
 | 
			
		||||
 | 
			
		||||
                            <div class="col-md-8">
 | 
			
		||||
                                <input name="mailer_pwd" type="password" class="form-control" placeholder="Type SMTP user password">
 | 
			
		||||
                                <input name="mailer_pwd" type="password" class="form-control" placeholder="Type SMTP user password" value="{{.mailer_pwd}}">
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <hr/>
 | 
			
		||||
@@ -175,7 +180,7 @@
 | 
			
		||||
                            <div class="col-md-offset-3 col-md-7">
 | 
			
		||||
                                <div class="checkbox">
 | 
			
		||||
                                    <label>
 | 
			
		||||
                                        <input name="register_confirm" type="checkbox">
 | 
			
		||||
                                        <input name="register_confirm" type="checkbox" {{if .register_confirm}}checked{{end}}>
 | 
			
		||||
                                        <strong>Enable Register Confirmation</strong>
 | 
			
		||||
                                    </label>
 | 
			
		||||
                                </div>
 | 
			
		||||
@@ -186,7 +191,7 @@
 | 
			
		||||
                            <div class="col-md-offset-3 col-md-7">
 | 
			
		||||
                                <div class="checkbox">
 | 
			
		||||
                                    <label>
 | 
			
		||||
                                        <input name="mail_notify" type="checkbox">
 | 
			
		||||
                                        <input name="mail_notify" type="checkbox" {{if .mail_notify}}checked{{end}}>
 | 
			
		||||
                                        <strong>Enable Mail Notification</strong>
 | 
			
		||||
                                    </label>
 | 
			
		||||
                                </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
{{template "repo/toolbar" .}}
 | 
			
		||||
<div id="body" class="container">
 | 
			
		||||
    <div id="issue">
 | 
			
		||||
        <form class="form" action="/{{.RepositoryLink}}/issues/new" method="post" id="issue-create-form">
 | 
			
		||||
        <form class="form" action="{{.RepoLink}}/issues/new" method="post" id="issue-create-form">
 | 
			
		||||
            {{.CsrfTokenHtml}}
 | 
			
		||||
            <div class="col-md-1">
 | 
			
		||||
                <img class="avatar" src="{{.SignedUser.AvatarLink}}" alt=""/>
 | 
			
		||||
@@ -15,19 +15,19 @@
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="form-group panel-body">
 | 
			
		||||
                    <div class="md-help pull-right"><!-- todo help link -->
 | 
			
		||||
                        Content with <a href="#">Markdown</a>
 | 
			
		||||
                        Content with <a href="https://help.github.com/articles/markdown-basics">Markdown</a>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <ul class="nav nav-tabs" data-init="tabs">
 | 
			
		||||
                        <li class="active"><a href="#issue-textarea" data-toggle="tab">Write</a></li>
 | 
			
		||||
                        <li><a href="#issue-preview" data-toggle="tab">Preview</a></li>
 | 
			
		||||
                        <li class="active issue-write"><a href="#issue-textarea" data-toggle="tab">Write</a></li>
 | 
			
		||||
                        <li class="issue-preview"><a href="#issue-preview" data-toggle="tab" data-ajax="/api/v1/markdown?repo=repo_id&issue=new" data-ajax-name="issue-preview" data-ajax-method="post" data-preview="#issue-preview">Preview</a></li>
 | 
			
		||||
                    </ul>
 | 
			
		||||
                    <div class="tab-content">
 | 
			
		||||
                        <div class="tab-pane" id="issue-textarea">
 | 
			
		||||
                            <div class="form-group">
 | 
			
		||||
                                <textarea class="form-control" name="content" id="issue-content" rows="10" placeholder="Write some content">{{.content}}</textarea>
 | 
			
		||||
                                <textarea class="form-control" name="content" id="issue-content" rows="10" placeholder="Write some content" data-ajax-rel="issue-preview" data-ajax-val="val" data-ajax-field="content">{{.content}}</textarea>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="tab-pane" id="issue-preview">preview</div>
 | 
			
		||||
                        <div class="tab-pane issue-preview-content" id="issue-preview">loading...</div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="text-right panel-body">
 | 
			
		||||
 
 | 
			
		||||
@@ -6,24 +6,24 @@
 | 
			
		||||
    <div id="issue">
 | 
			
		||||
        <div class="col-md-3 filter-list">
 | 
			
		||||
            <ul class="list-unstyled">
 | 
			
		||||
                <li><a href="/{{.RepositoryLink}}/issues"{{if eq .ViewType "all"}} class="active"{{end}}>All Issues <strong class="pull-right">{{.IssueCount}}</strong></a></li>
 | 
			
		||||
                <li><a href="{{.RepoLink}}/issues"{{if eq .ViewType "all"}} class="active"{{end}}>All Issues <strong class="pull-right">{{.IssueCount}}</strong></a></li>
 | 
			
		||||
                <!-- <li><a href="#">Assigned to you</a></li> -->
 | 
			
		||||
                <li><a href="/{{.RepositoryLink}}/issues?type=created_by"{{if eq .ViewType "created_by"}} class="active"{{end}}>Created by you <strong class="pull-right">{{.IssueCreatedCount}}</strong></a></li>
 | 
			
		||||
                <li><a href="{{.RepoLink}}/issues?type=created_by"{{if eq .ViewType "created_by"}} class="active"{{end}}>Created by you <strong class="pull-right">{{.IssueCreatedCount}}</strong></a></li>
 | 
			
		||||
                <!-- <li><a href="#">Mentioned</a></li> -->
 | 
			
		||||
            </ul>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="col-md-9">
 | 
			
		||||
            <div class="filter-option">
 | 
			
		||||
                <div class="btn-group">
 | 
			
		||||
                    <a class="btn btn-default issue-open{{if not .IsShowClosed}} active{{end}}" href="/{{.RepositoryLink}}/issues?type={{.ViewType}}">{{.OpenCount}} Open</a>
 | 
			
		||||
                    <a class="btn btn-default issue-close{{if .IsShowClosed}} active{{end}}" href="/{{.RepositoryLink}}/issues?state=closed&type={{.ViewType}}">{{.ClosedCount}} Closed</a>
 | 
			
		||||
                    <a class="btn btn-default issue-open{{if not .IsShowClosed}} active{{end}}" href="{{.RepoLink}}/issues?type={{.ViewType}}">{{.OpenCount}} Open</a>
 | 
			
		||||
                    <a class="btn btn-default issue-close{{if .IsShowClosed}} active{{end}}" href="{{.RepoLink}}/issues?state=closed&type={{.ViewType}}">{{.ClosedCount}} Closed</a>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="issues list-group">
 | 
			
		||||
                {{range .Issues}}
 | 
			
		||||
                <div class="list-group-item issue-item" id="issue-{{.Id}}">
 | 
			
		||||
                    <span class="number pull-right">#{{.Index}}</span>
 | 
			
		||||
                    <h5 class="title"><a href="/{{$.RepositoryLink}}/issues/{{.Index}}">{{.Name}}</a></h5>
 | 
			
		||||
                    <h5 class="title"><a href="{{$.RepoLink}}/issues/{{.Index}}">{{.Name}}</a></h5>
 | 
			
		||||
                    <p class="info">
 | 
			
		||||
                        <span class="author"><img class="avatar" src="{{.Poster.AvatarLink}}" alt="" width="20"/>
 | 
			
		||||
                        <a href="/user/{{.Poster.Name}}">{{.Poster.Name}}</a></span>
 | 
			
		||||
 
 | 
			
		||||
@@ -4,16 +4,17 @@
 | 
			
		||||
{{template "repo/toolbar" .}}
 | 
			
		||||
<div id="body" class="container">
 | 
			
		||||
    <div id="issue">
 | 
			
		||||
        <div id="issue-{issue.id}" class="issue-whole issue-is-opening">
 | 
			
		||||
        <div id="issue-{{.Issue.Id}}" class="issue-whole issue-is-opening">
 | 
			
		||||
            <div class="issue-head clearfix">
 | 
			
		||||
                <div class="number pull-right">#{{.Issue.Index}}</div>
 | 
			
		||||
                <a class="author pull-left" href="/user/{{.Issue.Poster.Name}}"><img class="avatar" src="{{.Issue.Poster.AvatarLink}}" alt="" width="30"/></a>
 | 
			
		||||
                <h1 class="title pull-left">{{.Issue.Name}}</h1>
 | 
			
		||||
                <input id="issue-edit-title" class="form-control input-lg pull-left hidden" type="text" value="{issue.title}" data-ajax-rel="issue-save"/>
 | 
			
		||||
                <input id="issue-edit-title" class="form-control input-lg pull-left hidden" type="text" value="{{.Issue.Name}}" data-ajax-rel="issue-edit-save" data-ajax-val="val" data-ajax-field="title"/>
 | 
			
		||||
                <input type="hidden" value="{{.Issue.Id}}" data-ajax-rel="issue-edit-save" data-ajax-val="val" data-ajax-field="issue_id"/>
 | 
			
		||||
                <p class="info pull-left">
 | 
			
		||||
                    <!-- <a class="btn btn-default pull-right issue-edit" href="#" id="issue-edit-btn">Edit</a> -->
 | 
			
		||||
                    {{if .IsIssueOwner}}<a class="btn btn-default pull-right issue-edit" href="#" id="issue-edit-btn">Edit</a>
 | 
			
		||||
                    <a class="btn btn-danger pull-right issue-edit-cancel hidden" href="#">Cancel</a>
 | 
			
		||||
                    <a class="btn btn-primary pull-right issue-edit-save hidden" href="#" data-ajax="{issue.save.link}" data-ajax-name="issue-save">Save</a>
 | 
			
		||||
                    <a class="btn btn-primary pull-right issue-edit-save hidden" href="#" data-ajax="/{{.RepositoryLink}}/issues/{{.Issue.Index}}" data-ajax-name="issue-edit-save" data-ajax-method="post">Save</a>{{end}}
 | 
			
		||||
                    <span class="status label label-{{if .Issue.IsClosed}}danger{{else}}success{{end}}">{{if .Issue.IsClosed}}Closed{{else}}Open{{end}}</span>
 | 
			
		||||
                    <a href="/user/{{.Issue.Poster.Name}}" class="author"><strong>{{.Issue.Poster.Name}}</strong></a> opened this issue
 | 
			
		||||
                    <span class="time">{{TimeSince .Issue.Created}}</span> · {{.Issue.NumComments}} comments
 | 
			
		||||
@@ -23,78 +24,77 @@
 | 
			
		||||
               <div class="panel panel-default issue-content">
 | 
			
		||||
                   <div class="panel-body markdown">
 | 
			
		||||
                       <div class="content">
 | 
			
		||||
                           {{str2html .Issue.Content}}
 | 
			
		||||
                           {{str2html .Issue.RenderedContent}}
 | 
			
		||||
                       </div>
 | 
			
		||||
                       <textarea class="form-control hidden" name="content" id="issue-edit-content" rows="10" data-ajax-rel="issue-save">content</textarea>
 | 
			
		||||
                       <textarea class="form-control hidden" name="content" id="issue-edit-content" rows="10" data-ajax-rel="issue-edit-save" data-ajax-val="val" data-ajax-field="content">{{.Issue.Content}}</textarea>
 | 
			
		||||
                   </div>
 | 
			
		||||
               </div>
 | 
			
		||||
               {{range .Comments}}
 | 
			
		||||
               <div class="issue-child" id="issue-comment-{issue.comment.id}">
 | 
			
		||||
                   <a class="user pull-left" href="/user/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt=""/></a>
 | 
			
		||||
                   <div class="issue-content panel panel-default">
 | 
			
		||||
                       <div class="panel-heading">
 | 
			
		||||
                           <a href="/user/{{.Poster.Name}}" class="user">{{.Poster.Name}}</a> commented <span class="time">{{TimeSince .Created}}</span>
 | 
			
		||||
                           <!-- <a class="issue-comment-del pull-right issue-action" href="#" title="Edit Comment"><i class="fa fa-times-circle"></i></a>
 | 
			
		||||
                           <a class="issue-comment-edit pull-right issue-action" href="#" title="Remove Comment" data-url="{remove-link}"><i class="fa fa-edit"></i></a> -->
 | 
			
		||||
                           <span class="role label label-default pull-right">Owner</span>
 | 
			
		||||
                       </div>
 | 
			
		||||
                       <div class="panel-body markdown">
 | 
			
		||||
                          {{str2html .Content}}
 | 
			
		||||
                       </div>
 | 
			
		||||
                   </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                {{if eq .Type 0}}
 | 
			
		||||
                 <div class="issue-child" id="issue-comment-{{.Id}}">
 | 
			
		||||
                     <a class="user pull-left" href="/user/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt=""/></a>
 | 
			
		||||
                     <div class="issue-content panel panel-default">
 | 
			
		||||
                         <div class="panel-heading">
 | 
			
		||||
                             <a href="/user/{{.Poster.Name}}" class="user">{{.Poster.Name}}</a> commented <span class="time">{{TimeSince .Created}}</span>
 | 
			
		||||
                             <!-- <a class="issue-comment-del pull-right issue-action" href="#" title="Edit Comment"><i class="fa fa-times-circle"></i></a>
 | 
			
		||||
                             <a class="issue-comment-edit pull-right issue-action" href="#" title="Remove Comment" data-url="{remove-link}"><i class="fa fa-edit"></i></a> -->
 | 
			
		||||
                             <span class="role label label-default pull-right">Owner</span>
 | 
			
		||||
                         </div>
 | 
			
		||||
                         <div class="panel-body markdown">
 | 
			
		||||
                            {{str2html .Content}}
 | 
			
		||||
                         </div>
 | 
			
		||||
                     </div>
 | 
			
		||||
                  </div>
 | 
			
		||||
                  {{else if eq .Type 1}}
 | 
			
		||||
                  <div class="issue-child issue-opened">
 | 
			
		||||
                      <a class="user pull-left" href="/user/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt="" /></a>
 | 
			
		||||
                      <div class="issue-content">
 | 
			
		||||
                          <a class="user pull-left" href="/user/{{.Poster.Name}}">{{.Poster.Name}}</a> <span class="label label-success">Reopened</span> this issue <span class="time">{{TimeSince .Created}}</span>
 | 
			
		||||
                      </div>
 | 
			
		||||
                  </div>
 | 
			
		||||
                  {{else if eq .Type 2}}
 | 
			
		||||
                  <div class="issue-child issue-closed">
 | 
			
		||||
                    <a class="user pull-left" href="/user/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt=""/></a>
 | 
			
		||||
                    <div class="issue-content">
 | 
			
		||||
                        <a class="user pull-left" href="/user/{{.Poster.Name}}">{{.Poster.Name}}</a> <span class="label label-danger">Closed</span> this issue <span class="time">{{TimeSince .Created}}</span>
 | 
			
		||||
                    </div>
 | 
			
		||||
                  </div>
 | 
			
		||||
                  {{end}}
 | 
			
		||||
                {{end}}
 | 
			
		||||
                <!-- <div class="issue-child issue-closed">
 | 
			
		||||
                    <a class="user pull-left" href="{user.link}"><img class="avatar" src="{user.avatar}" alt=""/></a>
 | 
			
		||||
                    <div class="issue-content">
 | 
			
		||||
                        <a class="user pull-left" href="{user.link}">{user.name}</a>
 | 
			
		||||
                        <span class="btn btn-danger">Closed</span> this
 | 
			
		||||
                        <span class="time">{close.time}</span>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="issue-child issue-opened">
 | 
			
		||||
                    <a class="user pull-left" href="{user.link}"><img class="avatar" src="{user.avatar}" alt=""/></a>
 | 
			
		||||
                    <div class="issue-content">
 | 
			
		||||
                        <a class="user pull-left" href="{user.link}">{user.name}</a>
 | 
			
		||||
                        <span class="btn btn-success">Reopened</span> this
 | 
			
		||||
                        <span class="time">{close.time}</span>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div> -->
 | 
			
		||||
                <hr class="issue-line"/>
 | 
			
		||||
                <div class="issue-child issue-reply">
 | 
			
		||||
                {{if .SignedUser}}<div class="issue-child issue-reply">
 | 
			
		||||
                    <a class="user pull-left" href="/user/{{.SignedUser.Name}}"><img class="avatar" src="{{.SignedUser.AvatarLink}}" alt=""/></a>
 | 
			
		||||
                    <form class="panel panel-default issue-content" action="/{{.RepositoryLink}}/comment/new" method="post">
 | 
			
		||||
                    <form class="panel panel-default issue-content" action="{{.RepoLink}}/comment/new" method="post">
 | 
			
		||||
                        {{.CsrfTokenHtml}}
 | 
			
		||||
                        <div class="panel-body">
 | 
			
		||||
                            <div class="form-group">
 | 
			
		||||
                                <div class="md-help pull-right"><!-- todo help link -->
 | 
			
		||||
                                    Content with <a href="#">Markdown</a>
 | 
			
		||||
                                <div class="md-help pull-right">Content with <a href="https://help.github.com/articles/markdown-basics">Markdown</a>
 | 
			
		||||
                                </div>
 | 
			
		||||
                                <ul class="nav nav-tabs" data-init="tabs">
 | 
			
		||||
                                    <li class="active"><a href="#issue-textarea" data-toggle="tab">Write</a></li>
 | 
			
		||||
                                    <li><a href="#issue-preview" data-toggle="tab">Preview</a></li>
 | 
			
		||||
                                    <li class="active issue-write"><a href="#issue-textarea" data-toggle="tab">Write</a></li>
 | 
			
		||||
                                    <li class="issue-preview"><a href="#issue-preview" data-toggle="tab" data-ajax="/api/v1/markdown?repo=repo_id&issue=issue_id&comment=new" data-ajax-name="issue-preview" data-ajax-method="post" data-preview="#issue-preview">Preview</a></li>
 | 
			
		||||
                                </ul>
 | 
			
		||||
                                <div class="tab-content">
 | 
			
		||||
                                    <div class="tab-pane" id="issue-textarea">
 | 
			
		||||
                                        <div class="form-group">
 | 
			
		||||
                                            <input type="hidden" value="{{.Issue.Index}}" name="issueIndex"/>
 | 
			
		||||
                                            <textarea class="form-control" name="content" id="issue-reply-content" rows="10" placeholder="Write some content">{{.content}}</textarea>
 | 
			
		||||
                                            <textarea class="form-control" name="content" id="issue-reply-content" rows="10" placeholder="Write some content" data-ajax-rel="issue-preview" data-ajax-val="val" data-ajax-field="content">{{.content}}</textarea>
 | 
			
		||||
                                        </div>
 | 
			
		||||
                                    </div>
 | 
			
		||||
                                    <div class="tab-pane" id="issue-preview">preview</div>
 | 
			
		||||
                                    <div class="tab-pane issue-preview-content" id="issue-preview">Loading...</div>
 | 
			
		||||
                                </div>
 | 
			
		||||
                            </div>
 | 
			
		||||
                            <div class="text-right">
 | 
			
		||||
                                <div class="form-group">
 | 
			
		||||
                                    {{if .Issue.IsClosed}}
 | 
			
		||||
                                    <input type="submit" class="btn-default btn issue-open" id="issue-open-btn" data-origin="Re-Open" data-text="Re-Open & Comment" name="change_status" value="Reopen"/>{{else}}
 | 
			
		||||
                                    <input type="submit" class="btn-default btn issue-open" id="issue-open-btn" data-origin="Reopen" data-text="Reopen & Comment" name="change_status" value="Reopen"/>{{else}}
 | 
			
		||||
                                    <input type="submit" class="btn-default btn issue-close" id="issue-close-btn" data-origin="Close" data-text="Close & Comment" name="change_status" value="Close"/>{{end}}  
 | 
			
		||||
                                    <button class="btn-success btn" id="issue-reply-btn">Comment</button>
 | 
			
		||||
                                </div>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </form>
 | 
			
		||||
                </div>
 | 
			
		||||
                </div>{{else}}<div class="alert alert-warning"><a class="btn btn-success btn-lg" href="/user/sign_up">Sign up for free</a> to join this conversation. Already have an account? <a href="/user/login">Sign in to comment</a></div>{{end}}
 | 
			
		||||
            </div><!--
 | 
			
		||||
            <div class="col-md-3">
 | 
			
		||||
                label assignment milestone dashboard
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
{{template "base/head" .}}
 | 
			
		||||
{{template "base/navbar" .}}
 | 
			
		||||
{{template "repo/nav" .}}
 | 
			
		||||
{{template "repo/toolbar" .}}
 | 
			
		||||
<div id="body" class="container" data-page="repo">
 | 
			
		||||
    <div id="source">
 | 
			
		||||
        <div class="panel panel-info diff-box diff-head-box">
 | 
			
		||||
@@ -11,7 +10,7 @@
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="panel-body">
 | 
			
		||||
                <span class="pull-right">
 | 
			
		||||
                    commit <span class="label label-default sha">{{.ShortSha}}</span>
 | 
			
		||||
                    commit <span class="label label-default sha">{{ShortSha .CommitId}}</span>
 | 
			
		||||
                </span>
 | 
			
		||||
                <p class="author">
 | 
			
		||||
                    <img class="avatar" src="{{AvatarLink .Commit.Author.Email}}" alt=""/>
 | 
			
		||||
 
 | 
			
		||||
@@ -11,11 +11,11 @@
 | 
			
		||||
            {{ $n := len .Treenames}}
 | 
			
		||||
            {{if not .IsFile}}<button class="btn btn-default pull-right hidden"><i class="fa fa-plus-square"></i>Add File</button>{{end}}
 | 
			
		||||
            <div class="dropdown branch-switch">
 | 
			
		||||
                <a href="#" class="btn btn-success dropdown-toggle" data-toggle="dropdown"><i class="fa fa-chain"></i>{{if .CommitId}}{{SubStr .CommitId 0 10}}{{else}}{{.Branchname}}{{end}}  
 | 
			
		||||
                <a href="#" class="btn btn-success dropdown-toggle" data-toggle="dropdown"><i class="fa fa-chain"></i>{{if .CommitId}}{{ShortSha .CommitId}}{{else}}{{.BranchName}}{{end}}  
 | 
			
		||||
                    <b class="caret"></b></a>
 | 
			
		||||
                <ul class="dropdown-menu">
 | 
			
		||||
                    {{range .Branches}}
 | 
			
		||||
                    <li><a {{if eq . $.Branchname}}class="current" {{end}}href="/{{$.Username}}/{{$.Reponame}}/src/{{.}}">{{.}}</a></li>
 | 
			
		||||
                    <li><a {{if eq . $.BranchName}}class="current" {{end}}href="/{{$.Username}}/{{$.Reponame}}/src/{{.}}">{{.}}</a></li>
 | 
			
		||||
                    {{end}}
 | 
			
		||||
                </ul>
 | 
			
		||||
            </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -3,24 +3,24 @@
 | 
			
		||||
        <nav class="navbar navbar-toolbar navbar-default" role="navigation">
 | 
			
		||||
            <div class="collapse navbar-collapse">
 | 
			
		||||
                <ul class="nav navbar-nav">
 | 
			
		||||
                    <li class="{{if .IsRepoToolbarSource}}active{{end}}"><a href="/{{.RepositoryLink}}">Source</a></li>
 | 
			
		||||
                    <li class="{{if .IsRepoToolbarSource}}active{{end}}"><a href="{{.RepoLink}}{{if ne .BranchName `master`}}/src/{{.BranchName}}{{end}}">Source</a></li>
 | 
			
		||||
                    {{if not .IsBareRepo}}
 | 
			
		||||
                    <li class="{{if .IsRepoToolbarCommits}}active{{end}}"><a href="/{{.RepositoryLink}}/commits/{{.Branchname}}">Commits</a></li>
 | 
			
		||||
                    <!-- <li class="{{if .IsRepoToolbarBranches}}active{{end}}"><a href="/{{.RepositoryLink}}/branches">Branches</a></li> -->
 | 
			
		||||
                    <!-- <li class="{{if .IsRepoToolbarPulls}}active{{end}}"><a href="/{{.RepositoryLink}}/pulls">Pull Requests</a></li> -->
 | 
			
		||||
                    <li class="{{if .IsRepoToolbarIssues}}active{{end}}"><a href="/{{.RepositoryLink}}/issues">Issues <!--<span class="badge">42</span>--></a></li>
 | 
			
		||||
                    <li class="{{if .IsRepoToolbarCommits}}active{{end}}"><a href="{{.RepoLink}}/commits/{{.BranchName}}">Commits</a></li>
 | 
			
		||||
                    <!-- <li class="{{if .IsRepoToolbarBranches}}active{{end}}"><a href="{{.RepoLink}}/branches">Branches</a></li> -->
 | 
			
		||||
                    <!-- <li class="{{if .IsRepoToolbarPulls}}active{{end}}"><a href="{{.RepoLink}}/pulls">Pull Requests</a></li> -->
 | 
			
		||||
                    <li class="{{if .IsRepoToolbarIssues}}active{{end}}"><a href="{{.RepoLink}}/issues">Issues <!--<span class="badge">42</span>--></a></li>
 | 
			
		||||
                    {{if .IsRepoToolbarIssues}}
 | 
			
		||||
                    <li class="tmp">{{if .IsRepoToolbarIssuesList}}<a href="/{{.RepositoryLink}}/issues/new">
 | 
			
		||||
                    <li class="tmp">{{if .IsRepoToolbarIssuesList}}<a href="{{.RepoLink}}/issues/new">
 | 
			
		||||
                        <button class="btn btn-primary btn-sm">New Issue</button>
 | 
			
		||||
                    </a>{{else}}<a href="/{{.RepositoryLink}}/issues">
 | 
			
		||||
                    </a>{{else}}<a href="{{.RepoLink}}/issues">
 | 
			
		||||
                        <button class="btn btn-primary btn-sm">Issues List</button>
 | 
			
		||||
                    </a>{{end}}</li>
 | 
			
		||||
                    {{end}}
 | 
			
		||||
                    <!-- <li class="dropdown">
 | 
			
		||||
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown">More <b class="caret"></b></a>
 | 
			
		||||
                        <ul class="dropdown-menu">
 | 
			
		||||
                            <li><a href="/{{.RepositoryLink}}/release">Release</a></li>
 | 
			
		||||
                            <li><a href="//{{.RepositoryLink}}/wiki">Wiki</a></li>
 | 
			
		||||
                            <li><a href="{{.RepoLink}}/release">Release</a></li>
 | 
			
		||||
                            <li><a href="{{.RepoLink}}/wiki">Wiki</a></li>
 | 
			
		||||
                        </ul>
 | 
			
		||||
                    </li> -->{{end}}
 | 
			
		||||
                </ul>
 | 
			
		||||
@@ -34,7 +34,7 @@
 | 
			
		||||
                            <li><a href="#">Network</a></li>
 | 
			
		||||
                        </ul>
 | 
			
		||||
                    </li> -->{{end}}{{if .IsRepositoryOwner}}
 | 
			
		||||
                    <li class="{{if .IsRepoToolbarSetting}}active{{end}}"><a href="/{{.RepositoryLink}}/settings">Settings</a>
 | 
			
		||||
                    <li class="{{if .IsRepoToolbarSetting}}active{{end}}"><a href="{{.RepoLink}}/settings">Settings</a>
 | 
			
		||||
                    </li>{{end}}
 | 
			
		||||
                </ul>
 | 
			
		||||
            </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -44,7 +44,7 @@
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="form-group text-center" id="social-login">
 | 
			
		||||
            <a class="btn btn-danger btn-lg">Register new account</a>
 | 
			
		||||
            <a class="btn btn-danger btn-lg" href="/user/sign_up">Register new account</a>
 | 
			
		||||
        </div>
 | 
			
		||||
    </form>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										43
									
								
								web.go
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								web.go
									
									
									
									
									
								
							@@ -8,22 +8,20 @@ import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"html/template"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/codegangsta/cli"
 | 
			
		||||
	"github.com/codegangsta/martini"
 | 
			
		||||
 | 
			
		||||
	"github.com/gogits/binding"
 | 
			
		||||
 | 
			
		||||
	"github.com/gogits/gogs/models"
 | 
			
		||||
	"github.com/gogits/gogs/modules/auth"
 | 
			
		||||
	"github.com/gogits/gogs/modules/avatar"
 | 
			
		||||
	"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/routers"
 | 
			
		||||
	"github.com/gogits/gogs/routers/admin"
 | 
			
		||||
	"github.com/gogits/gogs/routers/api/v1"
 | 
			
		||||
	"github.com/gogits/gogs/routers/dev"
 | 
			
		||||
	"github.com/gogits/gogs/routers/repo"
 | 
			
		||||
	"github.com/gogits/gogs/routers/user"
 | 
			
		||||
@@ -39,27 +37,6 @@ and it takes care of all the other things for you`,
 | 
			
		||||
	Flags:  []cli.Flag{},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// globalInit is for global configuration reload-able.
 | 
			
		||||
func globalInit() {
 | 
			
		||||
	base.NewConfigContext()
 | 
			
		||||
	mailer.NewMailerContext()
 | 
			
		||||
	models.LoadModelsConfig()
 | 
			
		||||
	models.LoadRepoConfig()
 | 
			
		||||
	models.NewRepoContext()
 | 
			
		||||
	models.NewEngine()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Check run mode(Default of martini is Dev).
 | 
			
		||||
func checkRunMode() {
 | 
			
		||||
	switch base.Cfg.MustValue("", "RUN_MODE") {
 | 
			
		||||
	case "prod":
 | 
			
		||||
		martini.Env = martini.Prod
 | 
			
		||||
	case "test":
 | 
			
		||||
		martini.Env = martini.Test
 | 
			
		||||
	}
 | 
			
		||||
	log.Info("Run Mode: %s", strings.Title(martini.Env))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newMartini() *martini.ClassicMartini {
 | 
			
		||||
	r := martini.NewRouter()
 | 
			
		||||
	m := martini.New()
 | 
			
		||||
@@ -72,9 +49,8 @@ func newMartini() *martini.ClassicMartini {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func runWeb(*cli.Context) {
 | 
			
		||||
	globalInit()
 | 
			
		||||
	base.NewServices()
 | 
			
		||||
	checkRunMode()
 | 
			
		||||
	fmt.Println("Server is running...")
 | 
			
		||||
	routers.GlobalInit()
 | 
			
		||||
	log.Info("%s %s", base.AppName, base.AppVer)
 | 
			
		||||
 | 
			
		||||
	m := newMartini()
 | 
			
		||||
@@ -90,12 +66,16 @@ func runWeb(*cli.Context) {
 | 
			
		||||
 | 
			
		||||
	// Routers.
 | 
			
		||||
	m.Get("/", ignSignIn, routers.Home)
 | 
			
		||||
	m.Any("/install", routers.Install)
 | 
			
		||||
	m.Any("/install", binding.BindIgnErr(auth.InstallForm{}), routers.Install)
 | 
			
		||||
	m.Get("/issues", reqSignIn, user.Issues)
 | 
			
		||||
	m.Get("/pulls", reqSignIn, user.Pulls)
 | 
			
		||||
	m.Get("/stars", reqSignIn, user.Stars)
 | 
			
		||||
	m.Get("/help", routers.Help)
 | 
			
		||||
 | 
			
		||||
	m.Group("/api/v1", func(r martini.Router) {
 | 
			
		||||
		r.Post("/markdown", v1.Markdown)
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	avt := avatar.CacheServer("public/img/avatar/", "public/img/avatar_default.jpg")
 | 
			
		||||
	m.Get("/avatar/:hash", avt.ServeHTTP)
 | 
			
		||||
 | 
			
		||||
@@ -150,8 +130,8 @@ func runWeb(*cli.Context) {
 | 
			
		||||
		r.Post("/issues/:index", binding.BindIgnErr(auth.CreateIssueForm{}), repo.UpdateIssue)
 | 
			
		||||
		r.Post("/comment/:action", repo.Comment)
 | 
			
		||||
	}, reqSignIn, middleware.RepoAssignment(true))
 | 
			
		||||
 | 
			
		||||
	m.Group("/:username/:reponame", func(r martini.Router) {
 | 
			
		||||
		r.Get("/commits/:branchname", repo.Commits)
 | 
			
		||||
		r.Get("/issues", repo.Issues)
 | 
			
		||||
		r.Get("/issues/:index", repo.ViewIssue)
 | 
			
		||||
		r.Get("/pulls", repo.Pulls)
 | 
			
		||||
@@ -160,11 +140,10 @@ func runWeb(*cli.Context) {
 | 
			
		||||
		r.Get("/src/:branchname/**", repo.Single)
 | 
			
		||||
		r.Get("/raw/:branchname/**", repo.SingleDownload)
 | 
			
		||||
		r.Get("/commits/:branchname", repo.Commits)
 | 
			
		||||
		r.Get("/commits/:branchname", repo.Commits)
 | 
			
		||||
	}, ignSignIn, middleware.RepoAssignment(true))
 | 
			
		||||
 | 
			
		||||
	m.Get("/:username/:reponame/commit/:commitid/**", ignSignIn, middleware.RepoAssignment(true), repo.Diff)
 | 
			
		||||
	m.Get("/:username/:reponame/commit/:commitid", ignSignIn, middleware.RepoAssignment(true), repo.Diff)
 | 
			
		||||
	m.Get("/:username/:reponame/commit/:branchname/**", ignSignIn, middleware.RepoAssignment(true), repo.Diff)
 | 
			
		||||
	m.Get("/:username/:reponame/commit/:branchname", ignSignIn, middleware.RepoAssignment(true), repo.Diff)
 | 
			
		||||
 | 
			
		||||
	m.Group("/:username", func(r martini.Router) {
 | 
			
		||||
		r.Get("/:reponame", middleware.RepoAssignment(true), repo.Single)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user