commit
1a247340db
61 changed files with 1013 additions and 517 deletions
13
.gitignore
vendored
13
.gitignore
vendored
|
@ -1,9 +1,3 @@
|
||||||
<<<<<<< HEAD
|
|
||||||
|
|
||||||
|
|
||||||
gogs
|
|
||||||
*.exe
|
|
||||||
*.exe~
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
*.db
|
*.db
|
||||||
*.log
|
*.log
|
||||||
|
@ -14,8 +8,6 @@ data/
|
||||||
*.iml
|
*.iml
|
||||||
public/img/avatar/
|
public/img/avatar/
|
||||||
|
|
||||||
=======
|
|
||||||
>>>>>>> b4db9f67548a41922f1b337daf9c9d2b975b55c4
|
|
||||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||||
*.o
|
*.o
|
||||||
*.a
|
*.a
|
||||||
|
@ -37,4 +29,7 @@ _cgo_export.*
|
||||||
|
|
||||||
_testmain.go
|
_testmain.go
|
||||||
|
|
||||||
*.exe
|
*.exe
|
||||||
|
*.exe~
|
||||||
|
gogs
|
||||||
|
__pycache__
|
||||||
|
|
|
@ -5,4 +5,6 @@ filesets:
|
||||||
- conf
|
- conf
|
||||||
- LICENSE
|
- LICENSE
|
||||||
- README.md
|
- README.md
|
||||||
- README_ZH.md
|
- README_ZH.md
|
||||||
|
- start.bat
|
||||||
|
- start.sh
|
||||||
|
|
|
@ -5,7 +5,9 @@ Gogs(Go Git Service) is a Self Hosted Git Service in the Go Programming Language
|
||||||
|
|
||||||
![Demo](http://gowalker.org/public/gogs_demo.gif)
|
![Demo](http://gowalker.org/public/gogs_demo.gif)
|
||||||
|
|
||||||
##### 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
|
#### Other language version
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ Gogs(Go Git Service) 是一个由 Go 语言编写的自助 Git 托管服务。
|
||||||
|
|
||||||
![Demo](http://gowalker.org/public/gogs_demo.gif)
|
![Demo](http://gowalker.org/public/gogs_demo.gif)
|
||||||
|
|
||||||
##### 当前版本:0.1.9 Alpha
|
##### 当前版本:0.2.0 Alpha
|
||||||
|
|
||||||
## 开发目的
|
## 开发目的
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ RUN_USER = git
|
||||||
RUN_MODE = dev
|
RUN_MODE = dev
|
||||||
|
|
||||||
[repository]
|
[repository]
|
||||||
ROOT = /Users/%(RUN_USER)s/git/gogs-repositories
|
ROOT =
|
||||||
LANG_IGNS = Google Go|C|C++|Python|Ruby|C Sharp
|
LANG_IGNS = Google Go|C|C++|Python|Ruby|C Sharp
|
||||||
LICENSES = Apache v2 License|GPL v2|MIT License|Affero GPL|Artistic License 2.0|BSD (3-Clause) License
|
LICENSES = Apache v2 License|GPL v2|MIT License|Affero GPL|Artistic License 2.0|BSD (3-Clause) License
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ HTTP_PORT = 3000
|
||||||
[database]
|
[database]
|
||||||
; Either "mysql", "postgres" or "sqlite3"(binary release only), it's your choice
|
; Either "mysql", "postgres" or "sqlite3"(binary release only), it's your choice
|
||||||
DB_TYPE = mysql
|
DB_TYPE = mysql
|
||||||
HOST =
|
HOST = 127.0.0.1:3306
|
||||||
NAME = gogs
|
NAME = gogs
|
||||||
USER = root
|
USER = root
|
||||||
PASSWD =
|
PASSWD =
|
||||||
|
|
2
conf/mysql.sql
Normal file
2
conf/mysql.sql
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
DROP DATABASE gogs;
|
||||||
|
CREATE DATABASE IF NOT EXISTS gogs CHARACTER SET utf8 COLLATE utf8_general_ci;
|
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.
|
// Test that go1.2 tag above is included in builds. main.go refers to this definition.
|
||||||
const go12tag = true
|
const go12tag = true
|
||||||
|
|
||||||
const APP_VER = "0.1.9.0328 Alpha"
|
const APP_VER = "0.2.0.0330 Alpha"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
base.AppVer = APP_VER
|
base.AppVer = APP_VER
|
||||||
|
|
|
@ -26,6 +26,8 @@ type Access struct {
|
||||||
|
|
||||||
// AddAccess adds new access record.
|
// AddAccess adds new access record.
|
||||||
func AddAccess(access *Access) error {
|
func AddAccess(access *Access) error {
|
||||||
|
access.UserName = strings.ToLower(access.UserName)
|
||||||
|
access.RepoName = strings.ToLower(access.RepoName)
|
||||||
_, err := orm.Insert(access)
|
_, err := orm.Insert(access)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ type Action struct {
|
||||||
OpType int // Operations: CREATE DELETE STAR ...
|
OpType int // Operations: CREATE DELETE STAR ...
|
||||||
ActUserId int64 // Action user id.
|
ActUserId int64 // Action user id.
|
||||||
ActUserName string // Action user name.
|
ActUserName string // Action user name.
|
||||||
|
ActEmail string
|
||||||
RepoId int64
|
RepoId int64
|
||||||
RepoName string
|
RepoName string
|
||||||
RefName string
|
RefName string
|
||||||
|
@ -46,6 +47,10 @@ func (a Action) GetActUserName() string {
|
||||||
return a.ActUserName
|
return a.ActUserName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a Action) GetActEmail() string {
|
||||||
|
return a.ActEmail
|
||||||
|
}
|
||||||
|
|
||||||
func (a Action) GetRepoName() string {
|
func (a Action) GetRepoName() string {
|
||||||
return a.RepoName
|
return a.RepoName
|
||||||
}
|
}
|
||||||
|
@ -59,7 +64,7 @@ func (a Action) GetContent() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CommitRepoAction adds new action for committing repository.
|
// CommitRepoAction adds new action for committing repository.
|
||||||
func CommitRepoAction(userId int64, userName string,
|
func CommitRepoAction(userId int64, userName, actEmail string,
|
||||||
repoId int64, repoName string, refName string, commit *base.PushCommits) error {
|
repoId int64, repoName string, refName string, commit *base.PushCommits) error {
|
||||||
log.Trace("action.CommitRepoAction(start): %d/%s", userId, repoName)
|
log.Trace("action.CommitRepoAction(start): %d/%s", userId, repoName)
|
||||||
|
|
||||||
|
@ -69,8 +74,8 @@ func CommitRepoAction(userId int64, userName string,
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = NotifyWatchers(&Action{ActUserId: userId, ActUserName: userName, OpType: OP_COMMIT_REPO,
|
if err = NotifyWatchers(&Action{ActUserId: userId, ActUserName: userName, ActEmail: actEmail,
|
||||||
Content: string(bs), RepoId: repoId, RepoName: repoName, RefName: refName}); err != nil {
|
OpType: OP_COMMIT_REPO, Content: string(bs), RepoId: repoId, RepoName: repoName, RefName: refName}); err != nil {
|
||||||
log.Error("action.CommitRepoAction(notify watchers): %d/%s", userId, repoName)
|
log.Error("action.CommitRepoAction(notify watchers): %d/%s", userId, repoName)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -93,8 +98,8 @@ func CommitRepoAction(userId int64, userName string,
|
||||||
|
|
||||||
// NewRepoAction adds new action for creating repository.
|
// NewRepoAction adds new action for creating repository.
|
||||||
func NewRepoAction(user *User, repo *Repository) (err error) {
|
func NewRepoAction(user *User, repo *Repository) (err error) {
|
||||||
if err = NotifyWatchers(&Action{ActUserId: user.Id, ActUserName: user.Name, OpType: OP_CREATE_REPO,
|
if err = NotifyWatchers(&Action{ActUserId: user.Id, ActUserName: user.Name, ActEmail: user.Email,
|
||||||
RepoId: repo.Id, RepoName: repo.Name}); err != nil {
|
OpType: OP_CREATE_REPO, RepoId: repo.Id, RepoName: repo.Name}); err != nil {
|
||||||
log.Error("action.NewRepoAction(notify watchers): %d/%s", user.Id, repo.Name)
|
log.Error("action.NewRepoAction(notify watchers): %d/%s", user.Id, repo.Name)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,9 +70,12 @@ func GetTargetFile(userName, repoName, branchName, commitId, rpath string) (*Rep
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
commit, err := repo.GetCommit(branchName, commitId)
|
commit, err := repo.GetCommitOfBranch(branchName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
commit, err = repo.GetCommit(commitId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parts := strings.Split(path.Clean(rpath), "/")
|
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.
|
// 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))
|
repo, err := git.OpenRepository(RepoPath(userName, repoName))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
commit, err := repo.GetCommit(branchName, commitId)
|
commit, err := repo.GetCommit(commitId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -216,13 +228,13 @@ func GetReposFiles(userName, repoName, branchName, commitId, rpath string) ([]*R
|
||||||
return append(repodirs, repofiles...), nil
|
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))
|
repo, err := git.OpenRepository(RepoPath(userName, repoName))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return repo.GetCommit(branchname, commitid)
|
return repo.GetCommit(commitId)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCommitsByBranch returns all commits of given branch of repository.
|
// GetCommitsByBranch returns all commits of given branch of repository.
|
||||||
|
@ -397,7 +409,7 @@ func GetDiff(repoPath, commitid string) (*Diff, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
commit, err := repo.GetCommit("", commitid)
|
commit, err := repo.GetCommit(commitid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,23 +18,24 @@ var (
|
||||||
|
|
||||||
// Issue represents an issue or pull request of repository.
|
// Issue represents an issue or pull request of repository.
|
||||||
type Issue struct {
|
type Issue struct {
|
||||||
Id int64
|
Id int64
|
||||||
Index int64 // Index in one repository.
|
Index int64 // Index in one repository.
|
||||||
Name string
|
Name string
|
||||||
RepoId int64 `xorm:"index"`
|
RepoId int64 `xorm:"index"`
|
||||||
Repo *Repository `xorm:"-"`
|
Repo *Repository `xorm:"-"`
|
||||||
PosterId int64
|
PosterId int64
|
||||||
Poster *User `xorm:"-"`
|
Poster *User `xorm:"-"`
|
||||||
MilestoneId int64
|
MilestoneId int64
|
||||||
AssigneeId int64
|
AssigneeId int64
|
||||||
IsPull bool // Indicates whether is a pull request or not.
|
IsPull bool // Indicates whether is a pull request or not.
|
||||||
IsClosed bool
|
IsClosed bool
|
||||||
Labels string `xorm:"TEXT"`
|
Labels string `xorm:"TEXT"`
|
||||||
Mentions string `xorm:"TEXT"`
|
Mentions string `xorm:"TEXT"`
|
||||||
Content string `xorm:"TEXT"`
|
Content string `xorm:"TEXT"`
|
||||||
NumComments int
|
RenderedContent string `xorm:"-"`
|
||||||
Created time.Time `xorm:"created"`
|
NumComments int
|
||||||
Updated time.Time `xorm:"updated"`
|
Created time.Time `xorm:"created"`
|
||||||
|
Updated time.Time `xorm:"updated"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateIssue creates new issue for repository.
|
// CreateIssue creates new issue for repository.
|
||||||
|
@ -169,9 +170,17 @@ type Milestone struct {
|
||||||
Created time.Time `xorm:"created"`
|
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.
|
// Comment represents a comment in commit and issue page.
|
||||||
type Comment struct {
|
type Comment struct {
|
||||||
Id int64
|
Id int64
|
||||||
|
Type int
|
||||||
PosterId int64
|
PosterId int64
|
||||||
Poster *User `xorm:"-"`
|
Poster *User `xorm:"-"`
|
||||||
IssueId int64
|
IssueId int64
|
||||||
|
@ -182,21 +191,37 @@ type Comment struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateComment creates comment of issue or commit.
|
// 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()
|
sess := orm.NewSession()
|
||||||
defer sess.Close()
|
defer sess.Close()
|
||||||
sess.Begin()
|
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 {
|
CommitId: commitId, Line: line, Content: content}); err != nil {
|
||||||
sess.Rollback()
|
sess.Rollback()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
rawSql := "UPDATE `issue` SET num_comments = num_comments + 1 WHERE id = ?"
|
// Check comment type.
|
||||||
if _, err := sess.Exec(rawSql, issueId); err != nil {
|
switch cmtType {
|
||||||
sess.Rollback()
|
case IT_PLAIN:
|
||||||
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
|
||||||
|
}
|
||||||
|
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()
|
return sess.Commit()
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,20 +12,27 @@ import (
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
_ "github.com/lib/pq"
|
_ "github.com/lib/pq"
|
||||||
"github.com/lunny/xorm"
|
"github.com/lunny/xorm"
|
||||||
|
// _ "github.com/mattn/go-sqlite3"
|
||||||
|
|
||||||
"github.com/gogits/gogs/modules/base"
|
"github.com/gogits/gogs/modules/base"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
orm *xorm.Engine
|
orm *xorm.Engine
|
||||||
|
HasEngine bool
|
||||||
|
|
||||||
DbCfg struct {
|
DbCfg struct {
|
||||||
Type, Host, Name, User, Pwd, Path, SslMode string
|
Type, Host, Name, User, Pwd, Path, SslMode string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UseSQLite3 bool
|
||||||
)
|
)
|
||||||
|
|
||||||
func LoadModelsConfig() {
|
func LoadModelsConfig() {
|
||||||
DbCfg.Type = base.Cfg.MustValue("database", "DB_TYPE")
|
DbCfg.Type = base.Cfg.MustValue("database", "DB_TYPE")
|
||||||
|
if DbCfg.Type == "sqlite3" {
|
||||||
|
UseSQLite3 = true
|
||||||
|
}
|
||||||
DbCfg.Host = base.Cfg.MustValue("database", "HOST")
|
DbCfg.Host = base.Cfg.MustValue("database", "HOST")
|
||||||
DbCfg.Name = base.Cfg.MustValue("database", "NAME")
|
DbCfg.Name = base.Cfg.MustValue("database", "NAME")
|
||||||
DbCfg.User = base.Cfg.MustValue("database", "USER")
|
DbCfg.User = base.Cfg.MustValue("database", "USER")
|
||||||
|
@ -34,11 +41,32 @@ func LoadModelsConfig() {
|
||||||
DbCfg.Path = base.Cfg.MustValue("database", "PATH", "data/gogs.db")
|
DbCfg.Path = base.Cfg.MustValue("database", "PATH", "data/gogs.db")
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetEngine() {
|
func NewTestEngine(x *xorm.Engine) (err error) {
|
||||||
var err error
|
|
||||||
switch DbCfg.Type {
|
switch DbCfg.Type {
|
||||||
case "mysql":
|
case "mysql":
|
||||||
orm, err = xorm.NewEngine("mysql", fmt.Sprintf("%s:%s@%s/%s?charset=utf8",
|
x, err = xorm.NewEngine("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8",
|
||||||
|
DbCfg.User, DbCfg.Pwd, DbCfg.Host, DbCfg.Name))
|
||||||
|
case "postgres":
|
||||||
|
x, err = xorm.NewEngine("postgres", fmt.Sprintf("user=%s password=%s dbname=%s sslmode=%s",
|
||||||
|
DbCfg.User, DbCfg.Pwd, DbCfg.Name, DbCfg.SslMode))
|
||||||
|
// case "sqlite3":
|
||||||
|
// os.MkdirAll(path.Dir(DbCfg.Path), os.ModePerm)
|
||||||
|
// x, err = xorm.NewEngine("sqlite3", DbCfg.Path)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("Unknown database type: %s\n", DbCfg.Type)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("models.init(fail to conntect database): %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return x.Sync(new(User), new(PublicKey), new(Repository), new(Watch),
|
||||||
|
new(Action), new(Access), new(Issue), new(Comment))
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetEngine() (err error) {
|
||||||
|
switch DbCfg.Type {
|
||||||
|
case "mysql":
|
||||||
|
orm, err = xorm.NewEngine("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8",
|
||||||
DbCfg.User, DbCfg.Pwd, DbCfg.Host, DbCfg.Name))
|
DbCfg.User, DbCfg.Pwd, DbCfg.Host, DbCfg.Name))
|
||||||
case "postgres":
|
case "postgres":
|
||||||
orm, err = xorm.NewEngine("postgres", fmt.Sprintf("user=%s password=%s dbname=%s sslmode=%s",
|
orm, err = xorm.NewEngine("postgres", fmt.Sprintf("user=%s password=%s dbname=%s sslmode=%s",
|
||||||
|
@ -47,12 +75,10 @@ func SetEngine() {
|
||||||
os.MkdirAll(path.Dir(DbCfg.Path), os.ModePerm)
|
os.MkdirAll(path.Dir(DbCfg.Path), os.ModePerm)
|
||||||
orm, err = xorm.NewEngine("sqlite3", DbCfg.Path)
|
orm, err = xorm.NewEngine("sqlite3", DbCfg.Path)
|
||||||
default:
|
default:
|
||||||
fmt.Printf("Unknown database type: %s\n", DbCfg.Type)
|
return fmt.Errorf("Unknown database type: %s\n", DbCfg.Type)
|
||||||
os.Exit(2)
|
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("models.init(fail to conntect database): %v\n", err)
|
return fmt.Errorf("models.init(fail to conntect database): %v\n", err)
|
||||||
os.Exit(2)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WARNNING: for serv command, MUST remove the output to os.stdout,
|
// WARNNING: for serv command, MUST remove the output to os.stdout,
|
||||||
|
@ -62,20 +88,21 @@ func SetEngine() {
|
||||||
//orm.ShowErr = true
|
//orm.ShowErr = true
|
||||||
f, err := os.Create("xorm.log")
|
f, err := os.Create("xorm.log")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("models.init(fail to create xorm.log): %v\n", err)
|
return fmt.Errorf("models.init(fail to create xorm.log): %v\n", err)
|
||||||
os.Exit(2)
|
|
||||||
}
|
}
|
||||||
orm.Logger = f
|
orm.Logger = f
|
||||||
orm.ShowSQL = true
|
orm.ShowSQL = true
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEngine() {
|
func NewEngine() (err error) {
|
||||||
SetEngine()
|
if err = SetEngine(); err != nil {
|
||||||
if err := orm.Sync(new(User), new(PublicKey), new(Repository), new(Watch),
|
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 {
|
new(Action), new(Access), new(Issue), new(Comment)); err != nil {
|
||||||
fmt.Printf("sync database struct error: %v\n", err)
|
return fmt.Errorf("sync database struct error: %v\n", err)
|
||||||
os.Exit(2)
|
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Statistic struct {
|
type Statistic struct {
|
||||||
|
|
|
@ -10,8 +10,8 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
@ -59,15 +59,6 @@ func NewRepoContext() {
|
||||||
os.Exit(2)
|
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.
|
// Repository represents a git repository.
|
||||||
|
@ -105,15 +96,20 @@ func IsRepositoryExist(user *User, repoName string) (bool, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// Define as all lower case!!
|
illegalEquals = []string{"raw", "install", "api", "avatar", "user", "help", "stars", "issues", "pulls", "commits", "repo", "template", "admin"}
|
||||||
illegalPatterns = []string{"[.][Gg][Ii][Tt]", "raw", "user", "help", "stars", "issues", "pulls", "commits", "repo", "template", "admin"}
|
illegalSuffixs = []string{".git"}
|
||||||
)
|
)
|
||||||
|
|
||||||
// IsLegalName returns false if name contains illegal characters.
|
// IsLegalName returns false if name contains illegal characters.
|
||||||
func IsLegalName(repoName string) bool {
|
func IsLegalName(repoName string) bool {
|
||||||
for _, pattern := range illegalPatterns {
|
repoName = strings.ToLower(repoName)
|
||||||
has, _ := regexp.MatchString(pattern, repoName)
|
for _, char := range illegalEquals {
|
||||||
if has {
|
if repoName == char {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, char := range illegalSuffixs {
|
||||||
|
if strings.HasSuffix(repoName, char) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,8 +157,8 @@ func CreateRepository(user *User, repoName, desc, repoLang, license string, priv
|
||||||
}
|
}
|
||||||
|
|
||||||
access := Access{
|
access := Access{
|
||||||
UserName: user.Name,
|
UserName: user.LowerName,
|
||||||
RepoName: repo.Name,
|
RepoName: strings.ToLower(path.Join(user.Name, repo.Name)),
|
||||||
Mode: AU_WRITABLE,
|
Mode: AU_WRITABLE,
|
||||||
}
|
}
|
||||||
if _, err = session.Insert(&access); err != nil {
|
if _, err = session.Insert(&access); err != nil {
|
||||||
|
@ -198,12 +194,19 @@ func CreateRepository(user *User, repoName, desc, repoLang, license string, priv
|
||||||
|
|
||||||
c := exec.Command("git", "update-server-info")
|
c := exec.Command("git", "update-server-info")
|
||||||
c.Dir = repoPath
|
c.Dir = repoPath
|
||||||
err = c.Run()
|
if err = c.Run(); err != nil {
|
||||||
if err != nil {
|
|
||||||
log.Error("repo.CreateRepository(exec update-server-info): %v", err)
|
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.
|
// extractGitBareZip extracts git-bare.zip to repository path.
|
||||||
|
@ -362,7 +365,7 @@ func GetRepos(num, offset int) ([]UserRepo, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func RepoPath(userName, repoName string) string {
|
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 {
|
func UpdateRepository(repo *Repository) error {
|
||||||
|
@ -395,7 +398,7 @@ func DeleteRepository(userId, repoId int64, userName string) (err error) {
|
||||||
session.Rollback()
|
session.Rollback()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err := session.Delete(&Access{UserName: userName, RepoName: repo.Name}); err != nil {
|
if _, err := session.Delete(&Access{RepoName: strings.ToLower(path.Join(userName, repo.Name))}); err != nil {
|
||||||
session.Rollback()
|
session.Rollback()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -510,7 +513,6 @@ func NotifyWatchers(act *Action) error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
act.Id = 0
|
|
||||||
act.UserId = watches[i].UserId
|
act.UserId = watches[i].UserId
|
||||||
if _, err = orm.InsertOne(act); err != nil {
|
if _, err = orm.InsertOne(act); err != nil {
|
||||||
return errors.New("repo.NotifyWatchers(create action): " + err.Error())
|
return errors.New("repo.NotifyWatchers(create action): " + err.Error())
|
||||||
|
|
|
@ -39,6 +39,7 @@ var (
|
||||||
ErrUserNotExist = errors.New("User does not exist")
|
ErrUserNotExist = errors.New("User does not exist")
|
||||||
ErrEmailAlreadyUsed = errors.New("E-mail already used")
|
ErrEmailAlreadyUsed = errors.New("E-mail already used")
|
||||||
ErrUserNameIllegal = errors.New("User name contains illegal characters")
|
ErrUserNameIllegal = errors.New("User name contains illegal characters")
|
||||||
|
ErrKeyNotExist = errors.New("Public key does not exist")
|
||||||
)
|
)
|
||||||
|
|
||||||
// User represents the object of individual and member of organization.
|
// User represents the object of individual and member of organization.
|
||||||
|
@ -67,7 +68,7 @@ type User struct {
|
||||||
|
|
||||||
// HomeLink returns the user home page link.
|
// HomeLink returns the user home page link.
|
||||||
func (user *User) HomeLink() string {
|
func (user *User) HomeLink() string {
|
||||||
return "/user/" + user.LowerName
|
return "/user/" + user.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
// AvatarLink returns the user gravatar link.
|
// AvatarLink returns the user gravatar link.
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/codegangsta/martini"
|
"github.com/go-martini/martini"
|
||||||
|
|
||||||
"github.com/gogits/binding"
|
"github.com/gogits/binding"
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/codegangsta/martini"
|
"github.com/go-martini/martini"
|
||||||
|
|
||||||
"github.com/gogits/binding"
|
"github.com/gogits/binding"
|
||||||
|
|
||||||
|
@ -161,3 +161,54 @@ func AssignForm(form interface{}, data base.TmplData) {
|
||||||
data[fieldName] = val.Field(i).Interface()
|
data[fieldName] = val.Field(i).Interface()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type InstallForm struct {
|
||||||
|
Database string `form:"database" binding:"Required"`
|
||||||
|
Host string `form:"host"`
|
||||||
|
User string `form:"user"`
|
||||||
|
Passwd string `form:"passwd"`
|
||||||
|
DatabaseName string `form:"database_name"`
|
||||||
|
SslMode string `form:"ssl_mode"`
|
||||||
|
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)"`
|
||||||
|
AdminEmail string `form:"admin_email" binding:"Required;Email;MaxSize(50)"`
|
||||||
|
SmtpHost string `form:"smtp_host"`
|
||||||
|
SmtpEmail string `form:"mailer_user"`
|
||||||
|
SmtpPasswd string `form:"mailer_pwd"`
|
||||||
|
RegisterConfirm string `form:"register_confirm"`
|
||||||
|
MailNotify string `form:"mail_notify"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *InstallForm) Name(field string) string {
|
||||||
|
names := map[string]string{
|
||||||
|
"Database": "Database name",
|
||||||
|
"AdminName": "Admin user name",
|
||||||
|
"AdminPasswd": "Admin password",
|
||||||
|
"AdminEmail": "Admin e-maill address",
|
||||||
|
}
|
||||||
|
return names[field]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *InstallForm) Validate(errors *binding.Errors, req *http.Request, context martini.Context) {
|
||||||
|
if req.Method == "GET" || errors.Count() == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData)
|
||||||
|
data["HasError"] = true
|
||||||
|
AssignForm(f, data)
|
||||||
|
|
||||||
|
if len(errors.Overall) > 0 {
|
||||||
|
for _, err := range errors.Overall {
|
||||||
|
log.Error("InstallForm.Validate: %v", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
validate(errors, data, f)
|
||||||
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/codegangsta/martini"
|
"github.com/go-martini/martini"
|
||||||
|
|
||||||
"github.com/gogits/binding"
|
"github.com/gogits/binding"
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/codegangsta/martini"
|
"github.com/go-martini/martini"
|
||||||
|
|
||||||
"github.com/gogits/binding"
|
"github.com/gogits/binding"
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/codegangsta/martini"
|
"github.com/go-martini/martini"
|
||||||
|
|
||||||
"github.com/gogits/binding"
|
"github.com/gogits/binding"
|
||||||
|
|
||||||
|
|
|
@ -8,11 +8,10 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/codegangsta/martini"
|
"github.com/go-martini/martini"
|
||||||
|
|
||||||
"github.com/gogits/session"
|
|
||||||
|
|
||||||
"github.com/gogits/binding"
|
"github.com/gogits/binding"
|
||||||
|
"github.com/gogits/session"
|
||||||
|
|
||||||
"github.com/gogits/gogs/models"
|
"github.com/gogits/gogs/models"
|
||||||
"github.com/gogits/gogs/modules/base"
|
"github.com/gogits/gogs/modules/base"
|
||||||
|
@ -21,6 +20,10 @@ import (
|
||||||
|
|
||||||
// SignedInId returns the id of signed in user.
|
// SignedInId returns the id of signed in user.
|
||||||
func SignedInId(session session.SessionStore) int64 {
|
func SignedInId(session session.SessionStore) int64 {
|
||||||
|
if !models.HasEngine {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
userId := session.Get("userId")
|
userId := session.Get("userId")
|
||||||
if userId == nil {
|
if userId == nil {
|
||||||
return 0
|
return 0
|
||||||
|
|
|
@ -212,9 +212,9 @@ func newMailService() {
|
||||||
if Cfg.MustBool("mailer", "ENABLED") {
|
if Cfg.MustBool("mailer", "ENABLED") {
|
||||||
MailService = &Mailer{
|
MailService = &Mailer{
|
||||||
Name: Cfg.MustValue("mailer", "NAME", AppName),
|
Name: Cfg.MustValue("mailer", "NAME", AppName),
|
||||||
Host: Cfg.MustValue("mailer", "HOST", "127.0.0.1:25"),
|
Host: Cfg.MustValue("mailer", "HOST"),
|
||||||
User: Cfg.MustValue("mailer", "USER", "example@example.com"),
|
User: Cfg.MustValue("mailer", "USER"),
|
||||||
Passwd: Cfg.MustValue("mailer", "PASSWD", "******"),
|
Passwd: Cfg.MustValue("mailer", "PASSWD"),
|
||||||
}
|
}
|
||||||
log.Info("Mail Service Enabled")
|
log.Info("Mail Service Enabled")
|
||||||
}
|
}
|
||||||
|
@ -253,7 +253,7 @@ func NewConfigContext() {
|
||||||
cfgPath := filepath.Join(workDir, "conf/app.ini")
|
cfgPath := filepath.Join(workDir, "conf/app.ini")
|
||||||
Cfg, err = goconfig.LoadConfigFile(cfgPath)
|
Cfg, err = goconfig.LoadConfigFile(cfgPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Cannot load config file '%s'\n", cfgPath)
|
fmt.Printf("Cannot load config file(%s): %v\n", cfgPath, err)
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
Cfg.BlockMode = false
|
Cfg.BlockMode = false
|
||||||
|
@ -261,7 +261,7 @@ func NewConfigContext() {
|
||||||
cfgPath = filepath.Join(workDir, "custom/conf/app.ini")
|
cfgPath = filepath.Join(workDir, "custom/conf/app.ini")
|
||||||
if com.IsFile(cfgPath) {
|
if com.IsFile(cfgPath) {
|
||||||
if err = Cfg.AppendFiles(cfgPath); err != nil {
|
if err = Cfg.AppendFiles(cfgPath); err != nil {
|
||||||
fmt.Printf("Cannot load config file '%s'\n", cfgPath)
|
fmt.Printf("Cannot load config file(%s): %v\n", cfgPath, err)
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -272,18 +272,19 @@ func NewConfigContext() {
|
||||||
Domain = Cfg.MustValue("server", "DOMAIN")
|
Domain = Cfg.MustValue("server", "DOMAIN")
|
||||||
SecretKey = Cfg.MustValue("security", "SECRET_KEY")
|
SecretKey = Cfg.MustValue("security", "SECRET_KEY")
|
||||||
|
|
||||||
|
InstallLock = Cfg.MustBool("security", "INSTALL_LOCK", false)
|
||||||
|
|
||||||
RunUser = Cfg.MustValue("", "RUN_USER")
|
RunUser = Cfg.MustValue("", "RUN_USER")
|
||||||
curUser := os.Getenv("USERNAME")
|
curUser := os.Getenv("USERNAME")
|
||||||
if len(curUser) == 0 {
|
if len(curUser) == 0 {
|
||||||
curUser = os.Getenv("USER")
|
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)
|
fmt.Printf("Expect user(%s) but current user is: %s\n", RunUser, curUser)
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
InstallLock = Cfg.MustBool("security", "INSTALL_LOCK", false)
|
|
||||||
|
|
||||||
LogInRememberDays = Cfg.MustInt("security", "LOGIN_REMEMBER_DAYS")
|
LogInRememberDays = Cfg.MustInt("security", "LOGIN_REMEMBER_DAYS")
|
||||||
CookieUserName = Cfg.MustValue("security", "COOKIE_USERNAME")
|
CookieUserName = Cfg.MustValue("security", "COOKIE_USERNAME")
|
||||||
CookieRememberName = Cfg.MustValue("security", "COOKIE_REMEMBER_NAME")
|
CookieRememberName = Cfg.MustValue("security", "COOKIE_REMEMBER_NAME")
|
||||||
|
@ -291,9 +292,14 @@ func NewConfigContext() {
|
||||||
PictureService = Cfg.MustValue("picture", "SERVICE")
|
PictureService = Cfg.MustValue("picture", "SERVICE")
|
||||||
|
|
||||||
// Determine and create root git reposiroty path.
|
// Determine and create root git reposiroty path.
|
||||||
RepoRootPath = Cfg.MustValue("repository", "ROOT")
|
homeDir, err := com.HomeDir()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Fail to get home directory): %v\n", err)
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
RepoRootPath = Cfg.MustValue("repository", "ROOT", filepath.Join(homeDir, "git/gogs-repositories"))
|
||||||
if err = os.MkdirAll(RepoRootPath, os.ModePerm); err != nil {
|
if err = os.MkdirAll(RepoRootPath, os.ModePerm); err != nil {
|
||||||
fmt.Printf("models.init(fail to create RepoRootPath(%s)): %v\n", RepoRootPath, err)
|
fmt.Printf("Fail to create RepoRootPath(%s): %v\n", RepoRootPath, err)
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,13 @@ func List(l *list.List) chan interface{} {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ShortSha(sha1 string) string {
|
||||||
|
if len(sha1) == 40 {
|
||||||
|
return sha1[:10]
|
||||||
|
}
|
||||||
|
return sha1
|
||||||
|
}
|
||||||
|
|
||||||
var mailDomains = map[string]string{
|
var mailDomains = map[string]string{
|
||||||
"gmail.com": "gmail.com",
|
"gmail.com": "gmail.com",
|
||||||
}
|
}
|
||||||
|
@ -72,4 +79,5 @@ var TemplateFuncs template.FuncMap = map[string]interface{}{
|
||||||
},
|
},
|
||||||
"DiffTypeToStr": DiffTypeToStr,
|
"DiffTypeToStr": DiffTypeToStr,
|
||||||
"DiffLineTypeToStr": DiffLineTypeToStr,
|
"DiffLineTypeToStr": DiffLineTypeToStr,
|
||||||
|
"ShortSha": ShortSha,
|
||||||
}
|
}
|
||||||
|
|
|
@ -478,6 +478,7 @@ func (a argInt) Get(i int, args ...int) (r int) {
|
||||||
type Actioner interface {
|
type Actioner interface {
|
||||||
GetOpType() int
|
GetOpType() int
|
||||||
GetActUserName() string
|
GetActUserName() string
|
||||||
|
GetActEmail() string
|
||||||
GetRepoName() string
|
GetRepoName() string
|
||||||
GetBranch() string
|
GetBranch() string
|
||||||
GetContent() string
|
GetContent() string
|
||||||
|
@ -506,15 +507,23 @@ const (
|
||||||
<div><img src="%s?s=16" alt="user-avatar"/> %s</div>`
|
<div><img src="%s?s=16" alt="user-avatar"/> %s</div>`
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type PushCommit struct {
|
||||||
|
Sha1 string
|
||||||
|
Message string
|
||||||
|
AuthorEmail string
|
||||||
|
AuthorName string
|
||||||
|
}
|
||||||
|
|
||||||
type PushCommits struct {
|
type PushCommits struct {
|
||||||
Len int
|
Len int
|
||||||
Commits [][]string
|
Commits []*PushCommit
|
||||||
}
|
}
|
||||||
|
|
||||||
// ActionDesc accepts int that represents action operation type
|
// ActionDesc accepts int that represents action operation type
|
||||||
// and returns the description.
|
// and returns the description.
|
||||||
func ActionDesc(act Actioner, avatarLink string) string {
|
func ActionDesc(act Actioner) string {
|
||||||
actUserName := act.GetActUserName()
|
actUserName := act.GetActUserName()
|
||||||
|
email := act.GetActEmail()
|
||||||
repoName := act.GetRepoName()
|
repoName := act.GetRepoName()
|
||||||
repoLink := actUserName + "/" + repoName
|
repoLink := actUserName + "/" + repoName
|
||||||
branch := act.GetBranch()
|
branch := act.GetBranch()
|
||||||
|
@ -529,7 +538,7 @@ func ActionDesc(act Actioner, avatarLink string) string {
|
||||||
}
|
}
|
||||||
buf := bytes.NewBuffer([]byte("\n"))
|
buf := bytes.NewBuffer([]byte("\n"))
|
||||||
for _, commit := range push.Commits {
|
for _, commit := range push.Commits {
|
||||||
buf.WriteString(fmt.Sprintf(TPL_COMMIT_REPO_LI, avatarLink, repoLink, commit[0], commit[0][:7], commit[1]) + "\n")
|
buf.WriteString(fmt.Sprintf(TPL_COMMIT_REPO_LI, AvatarLink(commit.AuthorEmail), repoLink, commit.Sha1, commit.Sha1[:7], commit.Message) + "\n")
|
||||||
}
|
}
|
||||||
if push.Len > 3 {
|
if push.Len > 3 {
|
||||||
buf.WriteString(fmt.Sprintf(`<div><a href="/%s/%s/commits/%s">%d other commits >></a></div>`, actUserName, repoName, branch, push.Len))
|
buf.WriteString(fmt.Sprintf(`<div><a href="/%s/%s/commits/%s">%d other commits >></a></div>`, actUserName, repoName, branch, push.Len))
|
||||||
|
@ -539,7 +548,7 @@ func ActionDesc(act Actioner, avatarLink string) string {
|
||||||
case 6: // Create issue.
|
case 6: // Create issue.
|
||||||
infos := strings.SplitN(content, "|", 2)
|
infos := strings.SplitN(content, "|", 2)
|
||||||
return fmt.Sprintf(TPL_CREATE_Issue, actUserName, actUserName, repoLink, infos[0], repoLink, infos[0],
|
return fmt.Sprintf(TPL_CREATE_Issue, actUserName, actUserName, repoLink, infos[0], repoLink, infos[0],
|
||||||
avatarLink, infos[1])
|
AvatarLink(email), infos[1])
|
||||||
default:
|
default:
|
||||||
return "invalid type"
|
return "invalid type"
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,13 +15,14 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
logger = logs.NewLogger(10000)
|
NewLogger(10000, "console", `{"level": 0}`)
|
||||||
logger.SetLogger("console", `{"level": 0}`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLogger(bufLen int64, mode, config string) {
|
func NewLogger(bufLen int64, mode, config string) {
|
||||||
Mode, Config = mode, config
|
Mode, Config = mode, config
|
||||||
logger = logs.NewLogger(bufLen)
|
logger = logs.NewLogger(bufLen)
|
||||||
|
logger.EnableFuncCallDepth(true)
|
||||||
|
logger.SetLogFuncCallDepth(4)
|
||||||
logger.SetLogger(mode, config)
|
logger.SetLogger(mode, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ package middleware
|
||||||
import (
|
import (
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/codegangsta/martini"
|
"github.com/go-martini/martini"
|
||||||
|
|
||||||
"github.com/gogits/gogs/modules/base"
|
"github.com/gogits/gogs/modules/base"
|
||||||
)
|
)
|
||||||
|
@ -21,6 +21,11 @@ type ToggleOptions struct {
|
||||||
|
|
||||||
func Toggle(options *ToggleOptions) martini.Handler {
|
func Toggle(options *ToggleOptions) martini.Handler {
|
||||||
return func(ctx *Context) {
|
return func(ctx *Context) {
|
||||||
|
if !base.InstallLock {
|
||||||
|
ctx.Redirect("/install")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if options.SignOutRequire && ctx.IsSigned && ctx.Req.RequestURI != "/" {
|
if options.SignOutRequire && ctx.IsSigned && ctx.Req.RequestURI != "/" {
|
||||||
ctx.Redirect("/")
|
ctx.Redirect("/")
|
||||||
return
|
return
|
||||||
|
|
|
@ -15,9 +15,10 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/codegangsta/martini"
|
"github.com/go-martini/martini"
|
||||||
|
|
||||||
"github.com/gogits/cache"
|
"github.com/gogits/cache"
|
||||||
|
"github.com/gogits/git"
|
||||||
"github.com/gogits/session"
|
"github.com/gogits/session"
|
||||||
|
|
||||||
"github.com/gogits/gogs/models"
|
"github.com/gogits/gogs/models"
|
||||||
|
@ -41,11 +42,18 @@ type Context struct {
|
||||||
csrfToken string
|
csrfToken string
|
||||||
|
|
||||||
Repo struct {
|
Repo struct {
|
||||||
IsValid bool
|
|
||||||
IsOwner bool
|
IsOwner bool
|
||||||
IsWatching bool
|
IsWatching bool
|
||||||
|
IsBranch bool
|
||||||
|
IsTag bool
|
||||||
|
IsCommit bool
|
||||||
Repository *models.Repository
|
Repository *models.Repository
|
||||||
Owner *models.User
|
Owner *models.User
|
||||||
|
Commit *git.Commit
|
||||||
|
GitRepo *git.Repository
|
||||||
|
BranchName string
|
||||||
|
CommitId string
|
||||||
|
RepoLink string
|
||||||
CloneLink struct {
|
CloneLink struct {
|
||||||
SSH string
|
SSH string
|
||||||
HTTPS 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))
|
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 {
|
func (ctx *Context) GetCookie(name string) string {
|
||||||
cookie, err := ctx.Req.Cookie(name)
|
cookie, err := ctx.Req.Cookie(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -257,7 +269,7 @@ func InitContext() martini.Handler {
|
||||||
if user != nil {
|
if user != nil {
|
||||||
ctx.Data["SignedUser"] = user
|
ctx.Data["SignedUser"] = user
|
||||||
ctx.Data["SignedUserId"] = user.Id
|
ctx.Data["SignedUserId"] = user.Id
|
||||||
ctx.Data["SignedUserName"] = user.LowerName
|
ctx.Data["SignedUserName"] = user.Name
|
||||||
ctx.Data["IsAdmin"] = ctx.User.IsAdmin
|
ctx.Data["IsAdmin"] = ctx.User.IsAdmin
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/codegangsta/martini"
|
"github.com/go-martini/martini"
|
||||||
)
|
)
|
||||||
|
|
||||||
var isWindows bool
|
var isWindows bool
|
||||||
|
|
|
@ -17,7 +17,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/codegangsta/martini"
|
"github.com/go-martini/martini"
|
||||||
|
|
||||||
"github.com/gogits/gogs/modules/base"
|
"github.com/gogits/gogs/modules/base"
|
||||||
)
|
)
|
||||||
|
|
|
@ -9,24 +9,40 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/codegangsta/martini"
|
"github.com/go-martini/martini"
|
||||||
|
|
||||||
|
"github.com/gogits/git"
|
||||||
|
|
||||||
"github.com/gogits/gogs/models"
|
"github.com/gogits/gogs/models"
|
||||||
"github.com/gogits/gogs/modules/base"
|
"github.com/gogits/gogs/modules/base"
|
||||||
)
|
)
|
||||||
|
|
||||||
func RepoAssignment(redirect bool) martini.Handler {
|
func RepoAssignment(redirect bool, args ...bool) martini.Handler {
|
||||||
return func(ctx *Context, params martini.Params) {
|
return func(ctx *Context, params martini.Params) {
|
||||||
// assign false first
|
// valid brachname
|
||||||
ctx.Data["IsRepositoryValid"] = false
|
var validBranch bool
|
||||||
|
// display bare quick start if it is a bare repo
|
||||||
|
var displayBare bool
|
||||||
|
|
||||||
|
if len(args) >= 1 {
|
||||||
|
validBranch = args[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(args) >= 2 {
|
||||||
|
displayBare = args[1]
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
user *models.User
|
user *models.User
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
|
userName := params["username"]
|
||||||
|
repoName := params["reponame"]
|
||||||
|
branchName := params["branchname"]
|
||||||
|
|
||||||
// get repository owner
|
// 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 {
|
if !ctx.Repo.IsOwner {
|
||||||
user, err = models.GetUserByName(params["username"])
|
user, err = models.GetUserByName(params["username"])
|
||||||
|
@ -51,10 +67,8 @@ func RepoAssignment(redirect bool) martini.Handler {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Repo.Owner = user
|
|
||||||
|
|
||||||
// get repository
|
// get repository
|
||||||
repo, err := models.GetRepositoryByName(user.Id, params["reponame"])
|
repo, err := models.GetRepositoryByName(user.Id, repoName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == models.ErrRepoNotExist {
|
if err == models.ErrRepoNotExist {
|
||||||
ctx.Handle(404, "RepoAssignment", err)
|
ctx.Handle(404, "RepoAssignment", err)
|
||||||
|
@ -62,30 +76,87 @@ func RepoAssignment(redirect bool) martini.Handler {
|
||||||
ctx.Redirect("/")
|
ctx.Redirect("/")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.Handle(200, "RepoAssignment", err)
|
ctx.Handle(404, "RepoAssignment", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Repo.Repository = repo
|
||||||
|
|
||||||
|
ctx.Data["IsBareRepo"] = ctx.Repo.Repository.IsBare
|
||||||
|
|
||||||
|
gitRepo, err := git.OpenRepository(models.RepoPath(userName, repoName))
|
||||||
|
if err != nil {
|
||||||
|
ctx.Handle(404, "RepoAssignment Invalid repo "+models.RepoPath(userName, repoName), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Repo.GitRepo = gitRepo
|
||||||
|
|
||||||
|
ctx.Repo.Owner = user
|
||||||
|
ctx.Repo.RepoLink = "/" + user.Name + "/" + repo.Name
|
||||||
|
|
||||||
|
ctx.Data["Title"] = user.Name + "/" + repo.Name
|
||||||
|
ctx.Data["Repository"] = repo
|
||||||
|
ctx.Data["Owner"] = user
|
||||||
|
ctx.Data["RepoLink"] = ctx.Repo.RepoLink
|
||||||
|
ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner
|
||||||
|
ctx.Data["BranchName"] = ""
|
||||||
|
|
||||||
|
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.Data["CloneLink"] = ctx.Repo.CloneLink
|
||||||
|
|
||||||
|
// when repo is bare, not valid branch
|
||||||
|
if !ctx.Repo.Repository.IsBare && validBranch {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Data["IsBranch"] = ctx.Repo.IsBranch
|
||||||
|
ctx.Data["IsCommit"] = ctx.Repo.IsCommit
|
||||||
|
}
|
||||||
|
|
||||||
|
// repo is bare and display enable
|
||||||
|
if displayBare && ctx.Repo.Repository.IsBare {
|
||||||
|
ctx.HTML(200, "repo/single_bare")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Repo.IsValid = true
|
if ctx.IsSigned {
|
||||||
if ctx.User != nil {
|
|
||||||
ctx.Repo.IsWatching = models.IsWatching(ctx.User.Id, repo.Id)
|
ctx.Repo.IsWatching = models.IsWatching(ctx.User.Id, repo.Id)
|
||||||
}
|
}
|
||||||
ctx.Repo.Repository = repo
|
|
||||||
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)
|
|
||||||
|
|
||||||
if len(params["branchname"]) == 0 {
|
ctx.Data["BranchName"] = ctx.Repo.BranchName
|
||||||
params["branchname"] = "master"
|
ctx.Data["CommitId"] = ctx.Repo.CommitId
|
||||||
}
|
|
||||||
ctx.Data["Branchname"] = params["branchname"]
|
|
||||||
|
|
||||||
ctx.Data["IsRepositoryValid"] = true
|
|
||||||
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["IsRepositoryOwner"] = ctx.Repo.IsOwner
|
|
||||||
ctx.Data["IsRepositoryWatching"] = ctx.Repo.IsWatching
|
ctx.Data["IsRepositoryWatching"] = ctx.Repo.IsWatching
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1197,13 +1197,13 @@ html, body {
|
||||||
line-height: 42px;
|
line-height: 42px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#issue .issue-closed{
|
#issue .issue-closed, #issue .issue-opened {
|
||||||
border-bottom: 3px solid #CCC;
|
border-bottom: 2px solid #CCC;
|
||||||
margin-bottom: 24px;
|
margin-bottom: 24px;
|
||||||
padding-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;
|
margin: 0 .8em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
103
public/js/app.js
103
public/js/app.js
|
@ -56,6 +56,43 @@ var Gogits = {
|
||||||
},
|
},
|
||||||
toggleShow: function () {
|
toggleShow: function () {
|
||||||
$(this).removeClass("hidden");
|
$(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));
|
}(jQuery));
|
||||||
|
@ -362,21 +399,24 @@ function initRepository() {
|
||||||
|
|
||||||
function initInstall() {
|
function initInstall() {
|
||||||
// database type change
|
// database type change
|
||||||
$('#install-database').on("change", function () {
|
(function () {
|
||||||
var val = $(this).val();
|
$('#install-database').on("change", function () {
|
||||||
if (val != "sqlite") {
|
var val = $(this).val();
|
||||||
$('.server-sql').show();
|
if (val != "sqlite") {
|
||||||
$('.sqlite-setting').addClass("hide");
|
$('.server-sql').show();
|
||||||
if (val == "pgsql") {
|
$('.sqlite-setting').addClass("hide");
|
||||||
$('.pgsql-setting').removeClass("hide");
|
if (val == "pgsql") {
|
||||||
|
$('.pgsql-setting').removeClass("hide");
|
||||||
|
} else {
|
||||||
|
$('.pgsql-setting').addClass("hide");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$('.pgsql-setting').addClass("hide");
|
$('.server-sql').hide();
|
||||||
|
$('.sqlite-setting').removeClass("hide");
|
||||||
}
|
}
|
||||||
} else {
|
});
|
||||||
$('.server-sql').hide();
|
}());
|
||||||
$('.sqlite-setting').removeClass("hide");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function initIssue() {
|
function initIssue() {
|
||||||
|
@ -386,11 +426,11 @@ function initIssue() {
|
||||||
var $openBtn = $('#issue-open-btn');
|
var $openBtn = $('#issue-open-btn');
|
||||||
$('#issue-reply-content').on("keyup", function () {
|
$('#issue-reply-content').on("keyup", function () {
|
||||||
if ($(this).val().length) {
|
if ($(this).val().length) {
|
||||||
$closeBtn.text($closeBtn.data("text"));
|
$closeBtn.val($closeBtn.data("text"));
|
||||||
$openBtn.text($openBtn.data("text"));
|
$openBtn.val($openBtn.data("text"));
|
||||||
} else {
|
} else {
|
||||||
$closeBtn.text($closeBtn.data("origin"));
|
$closeBtn.val($closeBtn.data("origin"));
|
||||||
$openBtn.text($openBtn.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-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 ($) {
|
(function ($) {
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/codegangsta/martini"
|
"github.com/go-martini/martini"
|
||||||
|
|
||||||
"github.com/gogits/gogs/models"
|
"github.com/gogits/gogs/models"
|
||||||
"github.com/gogits/gogs/modules/base"
|
"github.com/gogits/gogs/modules/base"
|
||||||
|
|
|
@ -7,7 +7,7 @@ package admin
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/codegangsta/martini"
|
"github.com/go-martini/martini"
|
||||||
|
|
||||||
"github.com/gogits/gogs/models"
|
"github.com/gogits/gogs/models"
|
||||||
"github.com/gogits/gogs/modules/auth"
|
"github.com/gogits/gogs/modules/auth"
|
||||||
|
|
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), "")),
|
||||||
|
})
|
||||||
|
}
|
|
@ -5,7 +5,7 @@
|
||||||
package dev
|
package dev
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/codegangsta/martini"
|
"github.com/go-martini/martini"
|
||||||
|
|
||||||
"github.com/gogits/gogs/models"
|
"github.com/gogits/gogs/models"
|
||||||
"github.com/gogits/gogs/modules/base"
|
"github.com/gogits/gogs/modules/base"
|
||||||
|
|
|
@ -6,27 +6,188 @@ package routers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/Unknwon/goconfig"
|
||||||
|
"github.com/go-martini/martini"
|
||||||
|
"github.com/lunny/xorm"
|
||||||
|
|
||||||
"github.com/gogits/gogs/models"
|
"github.com/gogits/gogs/models"
|
||||||
|
"github.com/gogits/gogs/modules/auth"
|
||||||
"github.com/gogits/gogs/modules/base"
|
"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/modules/middleware"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Install(ctx *middleware.Context) {
|
// 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 base.InstallLock {
|
||||||
|
if err := models.NewEngine(); err != nil {
|
||||||
|
log.Error("%v", err)
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
models.HasEngine = true
|
||||||
|
}
|
||||||
|
base.NewServices()
|
||||||
|
checkRunMode()
|
||||||
|
}
|
||||||
|
|
||||||
|
func Install(ctx *middleware.Context, form auth.InstallForm) {
|
||||||
if base.InstallLock {
|
if base.InstallLock {
|
||||||
ctx.Handle(404, "install.Install", errors.New("Installation is prohibited"))
|
ctx.Handle(404, "install.Install", errors.New("Installation is prohibited"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Data["Title"] = "Install"
|
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
|
ctx.Data["PageIsInstall"] = true
|
||||||
|
|
||||||
if ctx.Req.Method == "GET" {
|
if ctx.Req.Method == "GET" {
|
||||||
|
// 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)
|
||||||
ctx.HTML(200, "install")
|
ctx.HTML(200, "install")
|
||||||
return
|
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
|
||||||
|
|
||||||
|
// Set test engine.
|
||||||
|
var x *xorm.Engine
|
||||||
|
if err := models.NewTestEngine(x); err != nil {
|
||||||
|
if strings.Contains(err.Error(), `Unknown database type: sqlite3`) {
|
||||||
|
ctx.RenderWithErr("Your release version does not support SQLite3, please download the official binary version "+
|
||||||
|
"from https://github.com/gogits/gogs/wiki/Install-from-binary, NOT the gobuild version.", "install", &form)
|
||||||
|
} else {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check run user.
|
||||||
|
curUser := os.Getenv("USERNAME")
|
||||||
|
if len(curUser) == 0 {
|
||||||
|
curUser = os.Getenv("USER")
|
||||||
|
}
|
||||||
|
// Does not check run user when the install lock is off.
|
||||||
|
if form.RunUser != curUser {
|
||||||
|
ctx.RenderWithErr("Run user isn't the current user: "+form.RunUser+" -> "+curUser, "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(strings.TrimSpace(form.SmtpHost)) > 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("", "RUN_MODE", "prod")
|
||||||
|
|
||||||
|
base.Cfg.SetValue("security", "INSTALL_LOCK", "true")
|
||||||
|
|
||||||
|
os.MkdirAll("custom/conf", os.ModePerm)
|
||||||
|
if err := goconfig.SaveConfigFile(base.Cfg, "custom/conf/app.ini"); err != nil {
|
||||||
|
ctx.RenderWithErr("Fail to save configuration: "+err.Error(), "install", &form)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalInit()
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
log.Info("Admin account already exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("First-time run install finished!")
|
||||||
|
ctx.Redirect("/user/login")
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,27 +5,22 @@
|
||||||
package repo
|
package repo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/codegangsta/martini"
|
"github.com/go-martini/martini"
|
||||||
|
|
||||||
"github.com/gogits/gogs/models"
|
"github.com/gogits/gogs/models"
|
||||||
"github.com/gogits/gogs/modules/middleware"
|
"github.com/gogits/gogs/modules/middleware"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Branches(ctx *middleware.Context, params martini.Params) {
|
func Branches(ctx *middleware.Context, params martini.Params) {
|
||||||
if !ctx.Repo.IsValid {
|
brs, err := models.GetBranches(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
brs, err := models.GetBranches(params["username"], params["reponame"])
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Handle(200, "repo.Branches", err)
|
ctx.Handle(404, "repo.Branches", err)
|
||||||
return
|
return
|
||||||
} else if len(brs) == 0 {
|
} else if len(brs) == 0 {
|
||||||
ctx.Handle(404, "repo.Branches", nil)
|
ctx.Handle(404, "repo.Branches", nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Data["Username"] = params["username"]
|
|
||||||
ctx.Data["Reponame"] = params["reponame"]
|
|
||||||
ctx.Data["Branches"] = brs
|
ctx.Data["Branches"] = brs
|
||||||
ctx.Data["IsRepoToolbarBranches"] = true
|
ctx.Data["IsRepoToolbarBranches"] = true
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"container/list"
|
"container/list"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
"github.com/codegangsta/martini"
|
"github.com/go-martini/martini"
|
||||||
|
|
||||||
"github.com/gogits/gogs/models"
|
"github.com/gogits/gogs/models"
|
||||||
"github.com/gogits/gogs/modules/base"
|
"github.com/gogits/gogs/modules/base"
|
||||||
|
@ -50,16 +50,12 @@ func Commits(ctx *middleware.Context, params martini.Params) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Diff(ctx *middleware.Context, params martini.Params) {
|
func Diff(ctx *middleware.Context, params martini.Params) {
|
||||||
userName := params["username"]
|
userName := ctx.Repo.Owner.Name
|
||||||
repoName := params["reponame"]
|
repoName := ctx.Repo.Repository.Name
|
||||||
branchName := params["branchname"]
|
branchName := ctx.Repo.BranchName
|
||||||
commitId := params["commitid"]
|
commitId := ctx.Repo.CommitId
|
||||||
|
|
||||||
commit, err := models.GetCommit(userName, repoName, branchName, commitId)
|
commit := ctx.Repo.Commit
|
||||||
if err != nil {
|
|
||||||
ctx.Handle(404, "repo.Diff", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
diff, err := models.GetDiff(models.RepoPath(userName, repoName), commitId)
|
diff, err := models.GetDiff(models.RepoPath(userName, repoName), commitId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -85,11 +81,9 @@ func Diff(ctx *middleware.Context, params martini.Params) {
|
||||||
return isImage
|
return isImage
|
||||||
}
|
}
|
||||||
|
|
||||||
shortSha := params["commitid"][:10]
|
|
||||||
ctx.Data["IsImageFile"] = isImageFile
|
ctx.Data["IsImageFile"] = isImageFile
|
||||||
ctx.Data["Title"] = commit.Message() + " · " + shortSha
|
ctx.Data["Title"] = commit.Message() + " · " + base.ShortSha(commitId)
|
||||||
ctx.Data["Commit"] = commit
|
ctx.Data["Commit"] = commit
|
||||||
ctx.Data["ShortSha"] = shortSha
|
|
||||||
ctx.Data["Diff"] = diff
|
ctx.Data["Diff"] = diff
|
||||||
ctx.Data["IsRepoToolbarCommits"] = true
|
ctx.Data["IsRepoToolbarCommits"] = true
|
||||||
ctx.Data["SourcePath"] = "/" + path.Join(userName, repoName, "src", commitId)
|
ctx.Data["SourcePath"] = "/" + path.Join(userName, repoName, "src", commitId)
|
||||||
|
|
|
@ -7,8 +7,9 @@ package repo
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/codegangsta/martini"
|
"github.com/go-martini/martini"
|
||||||
|
|
||||||
"github.com/gogits/gogs/models"
|
"github.com/gogits/gogs/models"
|
||||||
"github.com/gogits/gogs/modules/auth"
|
"github.com/gogits/gogs/modules/auth"
|
||||||
|
@ -19,10 +20,6 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func Issues(ctx *middleware.Context) {
|
func Issues(ctx *middleware.Context) {
|
||||||
if !ctx.Repo.IsValid {
|
|
||||||
ctx.Handle(404, "issue.Issues(invalid repo):", nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Data["Title"] = "Issues"
|
ctx.Data["Title"] = "Issues"
|
||||||
ctx.Data["IsRepoToolbarIssues"] = true
|
ctx.Data["IsRepoToolbarIssues"] = true
|
||||||
ctx.Data["IsRepoToolbarIssuesList"] = 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) {
|
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["Title"] = "Create issue"
|
||||||
ctx.Data["IsRepoToolbarIssues"] = true
|
ctx.Data["IsRepoToolbarIssues"] = true
|
||||||
ctx.Data["IsRepoToolbarIssuesList"] = false
|
ctx.Data["IsRepoToolbarIssuesList"] = false
|
||||||
|
@ -105,7 +98,7 @@ func CreateIssue(ctx *middleware.Context, params martini.Params, form auth.Creat
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify watchers.
|
// Notify watchers.
|
||||||
if err = models.NotifyWatchers(&models.Action{ActUserId: ctx.User.Id, ActUserName: ctx.User.Name,
|
if err = models.NotifyWatchers(&models.Action{ActUserId: ctx.User.Id, ActUserName: ctx.User.Name, ActEmail: ctx.User.Email,
|
||||||
OpType: models.OP_CREATE_ISSUE, Content: fmt.Sprintf("%d|%s", issue.Index, issue.Name),
|
OpType: models.OP_CREATE_ISSUE, Content: fmt.Sprintf("%d|%s", issue.Index, issue.Name),
|
||||||
RepoId: ctx.Repo.Repository.Id, RepoName: ctx.Repo.Repository.Name, RefName: ""}); err != nil {
|
RepoId: ctx.Repo.Repository.Id, RepoName: ctx.Repo.Repository.Name, RefName: ""}); err != nil {
|
||||||
ctx.Handle(200, "issue.CreateIssue", err)
|
ctx.Handle(200, "issue.CreateIssue", err)
|
||||||
|
@ -125,10 +118,6 @@ func CreateIssue(ctx *middleware.Context, params martini.Params, form auth.Creat
|
||||||
}
|
}
|
||||||
|
|
||||||
func ViewIssue(ctx *middleware.Context, params martini.Params) {
|
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()
|
index, err := base.StrTo(params["index"]).Int()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Handle(404, "issue.ViewIssue", err)
|
ctx.Handle(404, "issue.ViewIssue", err)
|
||||||
|
@ -152,7 +141,7 @@ func ViewIssue(ctx *middleware.Context, params martini.Params) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
issue.Poster = u
|
issue.Poster = u
|
||||||
issue.Content = string(base.RenderMarkdown([]byte(issue.Content), ""))
|
issue.RenderedContent = string(base.RenderMarkdown([]byte(issue.Content), ""))
|
||||||
|
|
||||||
// Get comments.
|
// Get comments.
|
||||||
comments, err := models.GetIssueComments(issue.Id)
|
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["Title"] = issue.Name
|
||||||
ctx.Data["Issue"] = issue
|
ctx.Data["Issue"] = issue
|
||||||
ctx.Data["Comments"] = comments
|
ctx.Data["Comments"] = comments
|
||||||
|
ctx.Data["IsIssueOwner"] = ctx.Repo.IsOwner || (ctx.IsSigned && issue.PosterId == ctx.User.Id)
|
||||||
ctx.Data["IsRepoToolbarIssues"] = true
|
ctx.Data["IsRepoToolbarIssues"] = true
|
||||||
ctx.Data["IsRepoToolbarIssuesList"] = false
|
ctx.Data["IsRepoToolbarIssuesList"] = false
|
||||||
ctx.HTML(200, "issue/view")
|
ctx.HTML(200, "issue/view")
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateIssue(ctx *middleware.Context, params martini.Params, form auth.CreateIssueForm) {
|
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()
|
index, err := base.StrTo(params["index"]).Int()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Handle(404, "issue.UpdateIssue", err)
|
ctx.Handle(404, "issue.UpdateIssue", err)
|
||||||
|
@ -216,22 +202,21 @@ func UpdateIssue(ctx *middleware.Context, params martini.Params, form auth.Creat
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Data["Title"] = issue.Name
|
ctx.JSON(200, map[string]interface{}{
|
||||||
ctx.Data["Issue"] = issue
|
"ok": true,
|
||||||
|
"title": issue.Name,
|
||||||
|
"content": string(base.RenderMarkdown([]byte(issue.Content), "")),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func Comment(ctx *middleware.Context, params martini.Params) {
|
func Comment(ctx *middleware.Context, params martini.Params) {
|
||||||
if !ctx.Repo.IsValid {
|
index, err := base.StrTo(ctx.Query("issueIndex")).Int64()
|
||||||
ctx.Handle(404, "issue.Comment(invalid repo):", nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
index, err := base.StrTo(ctx.Query("issueIndex")).Int()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Handle(404, "issue.Comment", err)
|
ctx.Handle(404, "issue.Comment(get index)", err)
|
||||||
return
|
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 != nil {
|
||||||
if err == models.ErrIssueNotExist {
|
if err == models.ErrIssueNotExist {
|
||||||
ctx.Handle(404, "issue.Comment", err)
|
ctx.Handle(404, "issue.Comment", err)
|
||||||
|
@ -241,22 +226,46 @@ func Comment(ctx *middleware.Context, params martini.Params) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
content := ctx.Query("content")
|
// Check if issue owner changes the status of issue.
|
||||||
if len(content) == 0 {
|
var newStatus string
|
||||||
ctx.Handle(404, "issue.Comment", err)
|
if ctx.Repo.IsOwner || issue.PosterId == ctx.User.Id {
|
||||||
return
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch params["action"] {
|
content := ctx.Query("content")
|
||||||
case "new":
|
if len(content) > 0 {
|
||||||
if err = models.CreateComment(ctx.User.Id, issue.Id, 0, 0, content); err != nil {
|
switch params["action"] {
|
||||||
ctx.Handle(500, "issue.Comment(create comment)", err)
|
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
|
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))
|
ctx.Redirect(fmt.Sprintf("/%s/%s/issues/%d", ctx.User.Name, ctx.Repo.Repository.Name, index))
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
package repo
|
package repo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/codegangsta/martini"
|
"github.com/go-martini/martini"
|
||||||
|
|
||||||
"github.com/gogits/gogs/modules/middleware"
|
"github.com/gogits/gogs/modules/middleware"
|
||||||
)
|
)
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/codegangsta/martini"
|
"github.com/go-martini/martini"
|
||||||
|
|
||||||
"github.com/gogits/webdav"
|
"github.com/gogits/webdav"
|
||||||
|
|
||||||
|
@ -53,20 +53,20 @@ func Create(ctx *middleware.Context, form auth.CreateRepoForm) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Single(ctx *middleware.Context, params martini.Params) {
|
func Single(ctx *middleware.Context, params martini.Params) {
|
||||||
if !ctx.Repo.IsValid {
|
branchName := ctx.Repo.BranchName
|
||||||
return
|
commitId := ctx.Repo.CommitId
|
||||||
}
|
userName := ctx.Repo.Owner.Name
|
||||||
|
repoName := ctx.Repo.Repository.Name
|
||||||
|
|
||||||
branchName := params["branchname"]
|
repoLink := ctx.Repo.RepoLink
|
||||||
userName := params["username"]
|
branchLink := ctx.Repo.RepoLink + "/src/" + branchName
|
||||||
repoName := params["reponame"]
|
rawLink := ctx.Repo.RepoLink + "/raw/" + branchName
|
||||||
|
|
||||||
// Get tree path
|
// Get tree path
|
||||||
treename := params["_1"]
|
treename := params["_1"]
|
||||||
|
|
||||||
if len(treename) > 0 && treename[len(treename)-1] == '/' {
|
if len(treename) > 0 && treename[len(treename)-1] == '/' {
|
||||||
ctx.Redirect("/" + ctx.Repo.Owner.LowerName + "/" +
|
ctx.Redirect(repoLink + "/src/" + branchName + "/" + treename[:len(treename)-1])
|
||||||
ctx.Repo.Repository.Name + "/src/" + branchName + "/" + treename[:len(treename)-1])
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,30 +77,21 @@ func Single(ctx *middleware.Context, params martini.Params) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Handle(404, "repo.Single(GetBranches)", err)
|
ctx.Handle(404, "repo.Single(GetBranches)", err)
|
||||||
return
|
return
|
||||||
} else if ctx.Repo.Repository.IsBare {
|
|
||||||
ctx.Data["IsBareRepo"] = true
|
|
||||||
ctx.HTML(200, "repo/single")
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Data["Branches"] = brs
|
ctx.Data["Branches"] = brs
|
||||||
|
|
||||||
var commitId string
|
isViewBranch := ctx.Repo.IsBranch
|
||||||
isViewBranch := models.IsBranchExist(userName, repoName, branchName)
|
|
||||||
if !isViewBranch {
|
|
||||||
commitId = branchName
|
|
||||||
}
|
|
||||||
ctx.Data["IsViewBranch"] = isViewBranch
|
ctx.Data["IsViewBranch"] = isViewBranch
|
||||||
|
|
||||||
repoFile, err := models.GetTargetFile(userName, repoName,
|
repoFile, err := models.GetTargetFile(userName, repoName,
|
||||||
branchName, commitId, treename)
|
branchName, commitId, treename)
|
||||||
|
|
||||||
if err != nil && err != models.ErrRepoFileNotExist {
|
if err != nil && err != models.ErrRepoFileNotExist {
|
||||||
ctx.Handle(404, "repo.Single(GetTargetFile)", err)
|
ctx.Handle(404, "repo.Single(GetTargetFile)", err)
|
||||||
return
|
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 {
|
if len(treename) != 0 && repoFile == nil {
|
||||||
ctx.Handle(404, "repo.Single", nil)
|
ctx.Handle(404, "repo.Single", nil)
|
||||||
return
|
return
|
||||||
|
@ -142,8 +133,7 @@ func Single(ctx *middleware.Context, params martini.Params) {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Directory and file list.
|
// Directory and file list.
|
||||||
files, err := models.GetReposFiles(userName, repoName,
|
files, err := models.GetReposFiles(userName, repoName, ctx.Repo.CommitId, treename)
|
||||||
branchName, commitId, treename)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Handle(404, "repo.Single(GetReposFiles)", err)
|
ctx.Handle(404, "repo.Single(GetReposFiles)", err)
|
||||||
return
|
return
|
||||||
|
@ -200,18 +190,7 @@ func Single(ctx *middleware.Context, params martini.Params) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get latest commit according username and repo name.
|
ctx.Data["LastCommit"] = ctx.Repo.Commit
|
||||||
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["Paths"] = Paths
|
ctx.Data["Paths"] = Paths
|
||||||
ctx.Data["Treenames"] = treenames
|
ctx.Data["Treenames"] = treenames
|
||||||
ctx.Data["BranchLink"] = branchLink
|
ctx.Data["BranchLink"] = branchLink
|
||||||
|
@ -219,11 +198,6 @@ func Single(ctx *middleware.Context, params martini.Params) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func SingleDownload(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
|
// Get tree path
|
||||||
treename := params["_1"]
|
treename := params["_1"]
|
||||||
|
|
||||||
|
@ -263,10 +237,6 @@ func SingleDownload(ctx *middleware.Context, params martini.Params) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Http(ctx *middleware.Context, params martini.Params) {
|
func Http(ctx *middleware.Context, params martini.Params) {
|
||||||
/*if !ctx.Repo.IsValid {
|
|
||||||
return
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// TODO: access check
|
// TODO: access check
|
||||||
|
|
||||||
username := params["username"]
|
username := params["username"]
|
||||||
|
@ -276,11 +246,9 @@ func Http(ctx *middleware.Context, params martini.Params) {
|
||||||
}
|
}
|
||||||
|
|
||||||
prefix := path.Join("/", username, params["reponame"])
|
prefix := path.Join("/", username, params["reponame"])
|
||||||
server := &webdav.Server{
|
server := webdav.NewServer(
|
||||||
Fs: webdav.Dir(models.RepoPath(username, reponame)),
|
models.RepoPath(username, reponame),
|
||||||
TrimPrefix: prefix,
|
prefix, true)
|
||||||
Listings: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
server.ServeHTTP(ctx.ResponseWriter, ctx.Req)
|
server.ServeHTTP(ctx.ResponseWriter, ctx.Req)
|
||||||
}
|
}
|
||||||
|
@ -293,12 +261,6 @@ func Setting(ctx *middleware.Context, params martini.Params) {
|
||||||
|
|
||||||
ctx.Data["IsRepoToolbarSetting"] = true
|
ctx.Data["IsRepoToolbarSetting"] = true
|
||||||
|
|
||||||
if ctx.Repo.Repository.IsBare {
|
|
||||||
ctx.Data["IsBareRepo"] = true
|
|
||||||
ctx.HTML(200, "repo/setting")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var title string
|
var title string
|
||||||
if t, ok := ctx.Data["Title"].(string); ok {
|
if t, ok := ctx.Data["Title"].(string); ok {
|
||||||
title = t
|
title = t
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/codegangsta/martini"
|
"github.com/go-martini/martini"
|
||||||
|
|
||||||
"github.com/gogits/gogs/models"
|
"github.com/gogits/gogs/models"
|
||||||
"github.com/gogits/gogs/modules/auth"
|
"github.com/gogits/gogs/modules/auth"
|
||||||
|
@ -120,7 +120,7 @@ func SignIn(ctx *middleware.Context, form auth.LogInForm) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if hasErr, ok := ctx.Data["HasError"]; ok && hasErr.(bool) {
|
if ctx.HasError() {
|
||||||
ctx.HTML(200, "user/signin")
|
ctx.HTML(200, "user/signin")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -279,7 +279,7 @@ func Feeds(ctx *middleware.Context, form auth.FeedsForm) {
|
||||||
feeds := make([]string, len(actions))
|
feeds := make([]string, len(actions))
|
||||||
for i := range actions {
|
for i := range actions {
|
||||||
feeds[i] = fmt.Sprintf(TPL_FEED, base.ActionIcon(actions[i].OpType),
|
feeds[i] = fmt.Sprintf(TPL_FEED, base.ActionIcon(actions[i].OpType),
|
||||||
base.TimeSince(actions[i].Created), base.ActionDesc(actions[i], ctx.User.AvatarLink()))
|
base.TimeSince(actions[i].Created), base.ActionDesc(actions[i]))
|
||||||
}
|
}
|
||||||
ctx.JSON(200, &feeds)
|
ctx.JSON(200, &feeds)
|
||||||
}
|
}
|
||||||
|
@ -308,17 +308,19 @@ func Issues(ctx *middleware.Context) {
|
||||||
|
|
||||||
showRepos := make([]models.Repository, 0, len(repos))
|
showRepos := make([]models.Repository, 0, len(repos))
|
||||||
|
|
||||||
var closedIssueCount, createdByCount int
|
isShowClosed := ctx.Query("state") == "closed"
|
||||||
|
var closedIssueCount, createdByCount, allIssueCount int
|
||||||
|
|
||||||
// Get all issues.
|
// Get all issues.
|
||||||
allIssues := make([]models.Issue, 0, 5*len(repos))
|
allIssues := make([]models.Issue, 0, 5*len(repos))
|
||||||
for i, repo := range 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 {
|
if err != nil {
|
||||||
ctx.Handle(200, "user.Issues(get issues)", err)
|
ctx.Handle(200, "user.Issues(get issues)", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
allIssueCount += repo.NumIssues
|
||||||
closedIssueCount += repo.NumClosedIssues
|
closedIssueCount += repo.NumClosedIssues
|
||||||
|
|
||||||
// Set repository information to issues.
|
// Set repository information to issues.
|
||||||
|
@ -330,12 +332,10 @@ func Issues(ctx *middleware.Context) {
|
||||||
repos[i].NumOpenIssues = repo.NumIssues - repo.NumClosedIssues
|
repos[i].NumOpenIssues = repo.NumIssues - repo.NumClosedIssues
|
||||||
if repos[i].NumOpenIssues > 0 {
|
if repos[i].NumOpenIssues > 0 {
|
||||||
showRepos = append(showRepos, repos[i])
|
showRepos = append(showRepos, repos[i])
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
showIssues := make([]models.Issue, 0, len(allIssues))
|
showIssues := make([]models.Issue, 0, len(allIssues))
|
||||||
isShowClosed := ctx.Query("state") == "closed"
|
|
||||||
ctx.Data["IsShowClosed"] = isShowClosed
|
ctx.Data["IsShowClosed"] = isShowClosed
|
||||||
|
|
||||||
// Get posters and filter issues.
|
// Get posters and filter issues.
|
||||||
|
@ -361,9 +361,9 @@ func Issues(ctx *middleware.Context) {
|
||||||
|
|
||||||
ctx.Data["Repos"] = showRepos
|
ctx.Data["Repos"] = showRepos
|
||||||
ctx.Data["Issues"] = showIssues
|
ctx.Data["Issues"] = showIssues
|
||||||
ctx.Data["AllIssueCount"] = len(allIssues)
|
ctx.Data["AllIssueCount"] = allIssueCount
|
||||||
ctx.Data["ClosedIssueCount"] = closedIssueCount
|
ctx.Data["ClosedIssueCount"] = closedIssueCount
|
||||||
ctx.Data["OpenIssueCount"] = len(allIssues) - closedIssueCount
|
ctx.Data["OpenIssueCount"] = allIssueCount - closedIssueCount
|
||||||
ctx.Data["CreatedByCount"] = createdByCount
|
ctx.Data["CreatedByCount"] = createdByCount
|
||||||
ctx.HTML(200, "issue/user")
|
ctx.HTML(200, "issue/user")
|
||||||
}
|
}
|
||||||
|
|
65
serve.go
65
serve.go
|
@ -74,29 +74,33 @@ func In(b string, sl map[string]int) bool {
|
||||||
func runServ(k *cli.Context) {
|
func runServ(k *cli.Context) {
|
||||||
execDir, _ := base.ExecDir()
|
execDir, _ := base.ExecDir()
|
||||||
newLogger(execDir)
|
newLogger(execDir)
|
||||||
log.Trace("new serv request " + log.Mode + ":" + log.Config)
|
|
||||||
|
|
||||||
base.NewConfigContext()
|
base.NewConfigContext()
|
||||||
models.LoadModelsConfig()
|
models.LoadModelsConfig()
|
||||||
|
|
||||||
|
if models.UseSQLite3 {
|
||||||
|
os.Chdir(execDir)
|
||||||
|
}
|
||||||
|
|
||||||
models.SetEngine()
|
models.SetEngine()
|
||||||
|
|
||||||
keys := strings.Split(os.Args[2], "-")
|
keys := strings.Split(os.Args[2], "-")
|
||||||
if len(keys) != 2 {
|
if len(keys) != 2 {
|
||||||
fmt.Println("auth file format error")
|
println("auth file format error")
|
||||||
log.Error("auth file format error")
|
log.Error("auth file format error")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
keyId, err := strconv.ParseInt(keys[1], 10, 64)
|
keyId, err := strconv.ParseInt(keys[1], 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("auth file format error")
|
println("auth file format error")
|
||||||
log.Error("auth file format error")
|
log.Error("auth file format error", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
user, err := models.GetUserByKeyId(keyId)
|
user, err := models.GetUserByKeyId(keyId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("You have no right to access")
|
println("You have no right to access")
|
||||||
log.Error("You have no right to access")
|
log.Error("SSH visit error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,13 +111,14 @@ func runServ(k *cli.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
verb, args := parseCmd(cmd)
|
verb, args := parseCmd(cmd)
|
||||||
rRepo := strings.Trim(args, "'")
|
repoPath := strings.Trim(args, "'")
|
||||||
rr := strings.SplitN(rRepo, "/", 2)
|
rr := strings.SplitN(repoPath, "/", 2)
|
||||||
if len(rr) != 2 {
|
if len(rr) != 2 {
|
||||||
println("Unavilable repository", args)
|
println("Unavilable repository", args)
|
||||||
log.Error("Unavilable repository %v", args)
|
log.Error("Unavilable repository %v", args)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
repoUserName := rr[0]
|
||||||
repoName := rr[1]
|
repoName := rr[1]
|
||||||
if strings.HasSuffix(repoName, ".git") {
|
if strings.HasSuffix(repoName, ".git") {
|
||||||
repoName = repoName[:len(repoName)-4]
|
repoName = repoName[:len(repoName)-4]
|
||||||
|
@ -122,46 +127,46 @@ func runServ(k *cli.Context) {
|
||||||
isWrite := In(verb, COMMANDS_WRITE)
|
isWrite := In(verb, COMMANDS_WRITE)
|
||||||
isRead := In(verb, COMMANDS_READONLY)
|
isRead := In(verb, COMMANDS_READONLY)
|
||||||
|
|
||||||
/*//repo, err := models.GetRepositoryByName(user.Id, repoName)
|
repoUser, err := models.GetUserByName(repoUserName)
|
||||||
//var isExist bool = true
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == models.ErrRepoNotExist {
|
fmt.Println("You have no right to access")
|
||||||
//isExist = false
|
log.Error("Get user failed", err)
|
||||||
if isRead {
|
return
|
||||||
println("Repository", user.Name+"/"+repoName, "is not exist")
|
}
|
||||||
log.Error("Repository " + user.Name + "/" + repoName + " is not exist")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println("Get repository error:", err)
|
|
||||||
log.Error("Get repository error: " + err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// access check
|
// access check
|
||||||
switch {
|
switch {
|
||||||
case isWrite:
|
case isWrite:
|
||||||
has, err := models.HasAccess(user.Name, repoName, models.AU_WRITABLE)
|
has, err := models.HasAccess(user.LowerName, path.Join(repoUserName, repoName), models.AU_WRITABLE)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
println("Inernel error:", err)
|
println("Inernel error:", err)
|
||||||
log.Error(err.Error())
|
log.Error(err.Error())
|
||||||
return
|
return
|
||||||
}
|
} else if !has {
|
||||||
if !has {
|
|
||||||
println("You have no right to write this repository")
|
println("You have no right to write this repository")
|
||||||
log.Error("You have no right to access this repository")
|
log.Error("User %s has no right to write repository %s", user.Name, repoPath)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case isRead:
|
case isRead:
|
||||||
has, err := models.HasAccess(user.Name, repoName, models.AU_READABLE)
|
repo, err := models.GetRepositoryByName(repoUser.Id, repoName)
|
||||||
|
if err != nil {
|
||||||
|
println("Get repository error:", err)
|
||||||
|
log.Error("Get repository error: " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !repo.IsPrivate {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
has, err := models.HasAccess(user.Name, repoPath, models.AU_READABLE)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
println("Inernel error")
|
println("Inernel error")
|
||||||
log.Error(err.Error())
|
log.Error(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !has {
|
if !has {
|
||||||
has, err = models.HasAccess(user.Name, repoName, models.AU_WRITABLE)
|
has, err = models.HasAccess(user.Name, repoPath, models.AU_WRITABLE)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
println("Inernel error")
|
println("Inernel error")
|
||||||
log.Error(err.Error())
|
log.Error(err.Error())
|
||||||
|
@ -184,7 +189,7 @@ func runServ(k *cli.Context) {
|
||||||
os.Setenv("userId", strconv.Itoa(int(user.Id)))
|
os.Setenv("userId", strconv.Itoa(int(user.Id)))
|
||||||
os.Setenv("repoName", repoName)
|
os.Setenv("repoName", repoName)
|
||||||
|
|
||||||
gitcmd := exec.Command(verb, rRepo)
|
gitcmd := exec.Command(verb, repoPath)
|
||||||
gitcmd.Dir = base.RepoRootPath
|
gitcmd.Dir = base.RepoRootPath
|
||||||
gitcmd.Stdout = os.Stdout
|
gitcmd.Stdout = os.Stdout
|
||||||
gitcmd.Stdin = os.Stdin
|
gitcmd.Stdin = os.Stdin
|
||||||
|
|
2
start.bat
Normal file
2
start.bat
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
@echo off
|
||||||
|
gogs.exe web
|
6
start.sh
Executable file
6
start.sh
Executable file
|
@ -0,0 +1,6 @@
|
||||||
|
#!/bin/bash -
|
||||||
|
#
|
||||||
|
# start gogs web
|
||||||
|
#
|
||||||
|
cd "$(dirname $0)"
|
||||||
|
./gogs web
|
|
@ -3,9 +3,8 @@
|
||||||
<form action="/install" method="post" class="form-horizontal card" id="install-card">
|
<form action="/install" method="post" class="form-horizontal card" id="install-card">
|
||||||
{{.CsrfTokenHtml}}
|
{{.CsrfTokenHtml}}
|
||||||
<h3>Install Steps For First-time Run</h3>
|
<h3>Install Steps For First-time Run</h3>
|
||||||
|
|
||||||
<div class="alert alert-danger form-error{{if .HasError}}{{else}} hidden{{end}}">{{.ErrorMsg}}</div>
|
<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">
|
<div class="form-group">
|
||||||
<label class="col-md-3 control-label">Database Type: </label>
|
<label class="col-md-3 control-label">Database Type: </label>
|
||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
|
@ -16,26 +15,28 @@
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="server-sql">
|
<div class="server-sql">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-md-3 control-label">Host: </label>
|
<label class="col-md-3 control-label">Host: </label>
|
||||||
|
|
||||||
<div class="col-md-8">
|
<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}}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-md-3 control-label">User: </label>
|
<label class="col-md-3 control-label">User: </label>
|
||||||
|
|
||||||
<div class="col-md-8">
|
<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" value="{{.user}}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-md-3 control-label">Password: </label>
|
<label class="col-md-3 control-label">Password: </label>
|
||||||
|
|
||||||
<div class="col-md-8">
|
<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" value="{{.passwd}}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -43,7 +44,7 @@
|
||||||
<label class="col-md-3 control-label">Database Name: </label>
|
<label class="col-md-3 control-label">Database Name: </label>
|
||||||
|
|
||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<input name="database" 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}}">
|
||||||
<p class="help-block">Recommend use INNODB engine with utf8_general_ci charset.</p>
|
<p class="help-block">Recommend use INNODB engine with utf8_general_ci charset.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -59,12 +60,13 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="sqlite-setting hide">
|
<div class="sqlite-setting hide">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-md-3 control-label">Path: </label>
|
<label class="col-md-3 control-label">Path: </label>
|
||||||
|
|
||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<input name="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>
|
<p class="help-block">The file path of SQLite3 database.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -73,12 +75,11 @@
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
<p class="help-block text-center">General Settings of Gogs</p>
|
<p class="help-block text-center">General Settings of Gogs</p>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-md-3 control-label">Repository Path: </label>
|
<label class="col-md-3 control-label">Repository Path: </label>
|
||||||
|
|
||||||
<div class="col-md-8">
|
<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>
|
<p class="help-block">The git copy of each repository is saved in this directory.</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -88,16 +89,25 @@
|
||||||
<label class="col-md-3 control-label">Run User: </label>
|
<label class="col-md-3 control-label">Run User: </label>
|
||||||
|
|
||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<input name="system-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>
|
<p class="help-block">The user has access to visit and run Gogs.</p>
|
||||||
</div>
|
</div>
|
||||||
</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">
|
<div class="form-group">
|
||||||
<label class="col-md-3 control-label">App URL: </label>
|
<label class="col-md-3 control-label">App URL: </label>
|
||||||
|
|
||||||
<div class="col-md-8">
|
<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>
|
<p class="help-block">This affects HTTP/HTTPS clone URL and somewhere in e-mail.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -105,35 +115,30 @@
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
<p class="help-block text-center">Admin Account Settings</p>
|
<p class="help-block text-center">Admin Account Settings</p>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-md-3 control-label">Username: </label>
|
<label class="col-md-3 control-label">Username: </label>
|
||||||
|
|
||||||
<div class="col-md-8">
|
<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>
|
</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>
|
<label class="col-md-3 control-label">Password: </label>
|
||||||
|
|
||||||
<div class="col-md-8">
|
<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>
|
</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>
|
<label class="col-md-3 control-label">E-mail: </label>
|
||||||
|
|
||||||
<div class="col-md-8">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
<div class="form-group text-center">
|
<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-danger btn-lg">Install Gogs</button>
|
||||||
<button class="btn btn-default btn-sm" type="button" data-toggle="modal" data-target="#advance-options-modal">
|
<button class="btn btn-default btn-sm" type="button" data-toggle="modal" data-target="#advance-options-modal">
|
||||||
Advanced Options
|
Advanced Options
|
||||||
|
@ -151,21 +156,21 @@
|
||||||
<label class="col-md-3 control-label">SMTP Host: </label>
|
<label class="col-md-3 control-label">SMTP Host: </label>
|
||||||
|
|
||||||
<div class="col-md-8">
|
<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>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-md-3 control-label">Email: </label>
|
<label class="col-md-3 control-label">Email: </label>
|
||||||
|
|
||||||
<div class="col-md-8">
|
<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>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-md-3 control-label">Password: </label>
|
<label class="col-md-3 control-label">Password: </label>
|
||||||
|
|
||||||
<div class="col-md-8">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
<hr/>
|
<hr/>
|
||||||
|
@ -175,7 +180,7 @@
|
||||||
<div class="col-md-offset-3 col-md-7">
|
<div class="col-md-offset-3 col-md-7">
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label>
|
<label>
|
||||||
<input name="register_confirm" type="checkbox">
|
<input name="register_confirm" type="checkbox" {{if .register_confirm}}checked{{end}}>
|
||||||
<strong>Enable Register Confirmation</strong>
|
<strong>Enable Register Confirmation</strong>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
@ -186,7 +191,7 @@
|
||||||
<div class="col-md-offset-3 col-md-7">
|
<div class="col-md-offset-3 col-md-7">
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label>
|
<label>
|
||||||
<input name="mail_notify" type="checkbox">
|
<input name="mail_notify" type="checkbox" {{if .mail_notify}}checked{{end}}>
|
||||||
<strong>Enable Mail Notification</strong>
|
<strong>Enable Mail Notification</strong>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
{{template "repo/toolbar" .}}
|
{{template "repo/toolbar" .}}
|
||||||
<div id="body" class="container">
|
<div id="body" class="container">
|
||||||
<div id="issue">
|
<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}}
|
{{.CsrfTokenHtml}}
|
||||||
<div class="col-md-1">
|
<div class="col-md-1">
|
||||||
<img class="avatar" src="{{.SignedUser.AvatarLink}}" alt=""/>
|
<img class="avatar" src="{{.SignedUser.AvatarLink}}" alt=""/>
|
||||||
|
@ -15,19 +15,19 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group panel-body">
|
<div class="form-group panel-body">
|
||||||
<div class="md-help pull-right"><!-- todo help link -->
|
<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>
|
</div>
|
||||||
<ul class="nav nav-tabs" data-init="tabs">
|
<ul class="nav nav-tabs" data-init="tabs">
|
||||||
<li class="active"><a href="#issue-textarea" data-toggle="tab">Write</a></li>
|
<li class="active issue-write"><a href="#issue-textarea" data-toggle="tab">Write</a></li>
|
||||||
<li><a href="#issue-preview" data-toggle="tab">Preview</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>
|
</ul>
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<div class="tab-pane" id="issue-textarea">
|
<div class="tab-pane" id="issue-textarea">
|
||||||
<div class="form-group">
|
<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>
|
</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>
|
</div>
|
||||||
<div class="text-right panel-body">
|
<div class="text-right panel-body">
|
||||||
|
@ -40,4 +40,4 @@
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{template "base/footer" .}}
|
{{template "base/footer" .}}
|
||||||
|
|
|
@ -6,24 +6,24 @@
|
||||||
<div id="issue">
|
<div id="issue">
|
||||||
<div class="col-md-3 filter-list">
|
<div class="col-md-3 filter-list">
|
||||||
<ul class="list-unstyled">
|
<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="#">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> -->
|
<!-- <li><a href="#">Mentioned</a></li> -->
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-9">
|
<div class="col-md-9">
|
||||||
<div class="filter-option">
|
<div class="filter-option">
|
||||||
<div class="btn-group">
|
<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-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="/{{.RepositoryLink}}/issues?state=closed&type={{.ViewType}}">{{.ClosedCount}} Closed</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>
|
</div>
|
||||||
<div class="issues list-group">
|
<div class="issues list-group">
|
||||||
{{range .Issues}}
|
{{range .Issues}}
|
||||||
<div class="list-group-item issue-item" id="issue-{{.Id}}">
|
<div class="list-group-item issue-item" id="issue-{{.Id}}">
|
||||||
<span class="number pull-right">#{{.Index}}</span>
|
<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">
|
<p class="info">
|
||||||
<span class="author"><img class="avatar" src="{{.Poster.AvatarLink}}" alt="" width="20"/>
|
<span class="author"><img class="avatar" src="{{.Poster.AvatarLink}}" alt="" width="20"/>
|
||||||
<a href="/user/{{.Poster.Name}}">{{.Poster.Name}}</a></span>
|
<a href="/user/{{.Poster.Name}}">{{.Poster.Name}}</a></span>
|
||||||
|
@ -37,4 +37,4 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{template "base/footer" .}}
|
{{template "base/footer" .}}
|
||||||
|
|
|
@ -4,16 +4,17 @@
|
||||||
{{template "repo/toolbar" .}}
|
{{template "repo/toolbar" .}}
|
||||||
<div id="body" class="container">
|
<div id="body" class="container">
|
||||||
<div id="issue">
|
<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="issue-head clearfix">
|
||||||
<div class="number pull-right">#{{.Issue.Index}}</div>
|
<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>
|
<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>
|
<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">
|
<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-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="{{.RepoLink}}/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>
|
<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
|
<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
|
<span class="time">{{TimeSince .Issue.Created}}</span> · {{.Issue.NumComments}} comments
|
||||||
|
@ -23,78 +24,77 @@
|
||||||
<div class="panel panel-default issue-content">
|
<div class="panel panel-default issue-content">
|
||||||
<div class="panel-body markdown">
|
<div class="panel-body markdown">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
{{str2html .Issue.Content}}
|
{{str2html .Issue.RenderedContent}}
|
||||||
</div>
|
</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>
|
||||||
</div>
|
</div>
|
||||||
{{range .Comments}}
|
{{range .Comments}}
|
||||||
<div class="issue-child" id="issue-comment-{issue.comment.id}">
|
{{if eq .Type 0}}
|
||||||
<a class="user pull-left" href="/user/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt=""/></a>
|
<div class="issue-child" id="issue-comment-{{.Id}}">
|
||||||
<div class="issue-content panel panel-default">
|
<a class="user pull-left" href="/user/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt=""/></a>
|
||||||
<div class="panel-heading">
|
<div class="issue-content panel panel-default">
|
||||||
<a href="/user/{{.Poster.Name}}" class="user">{{.Poster.Name}}</a> commented <span class="time">{{TimeSince .Created}}</span>
|
<div class="panel-heading">
|
||||||
<a class="issue-comment-del pull-right issue-action" href="#" title="Edit Comment"><i class="fa fa-times-circle"></i></a>
|
<a href="/user/{{.Poster.Name}}" class="user">{{.Poster.Name}}</a> commented <span class="time">{{TimeSince .Created}}</span>
|
||||||
<a class="issue-comment-edit pull-right issue-action" href="#" title="Remove Comment" data-url="{remove-link}"><i class="fa fa-edit"></i></a>
|
<!-- <a class="issue-comment-del pull-right issue-action" href="#" title="Edit Comment"><i class="fa fa-times-circle"></i></a>
|
||||||
<span class="role label label-default pull-right">Owner</span>
|
<a class="issue-comment-edit pull-right issue-action" href="#" title="Remove Comment" data-url="{remove-link}"><i class="fa fa-edit"></i></a> -->
|
||||||
</div>
|
<span class="role label label-default pull-right">Owner</span>
|
||||||
<div class="panel-body markdown">
|
</div>
|
||||||
{{str2html .Content}}
|
<div class="panel-body markdown">
|
||||||
</div>
|
{{str2html .Content}}
|
||||||
</div>
|
</div>
|
||||||
</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}}
|
{{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"/>
|
<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>
|
<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}}
|
{{.CsrfTokenHtml}}
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="md-help pull-right"><!-- todo help link -->
|
<div class="md-help pull-right">Content with <a href="https://help.github.com/articles/markdown-basics">Markdown</a>
|
||||||
Content with <a href="#">Markdown</a>
|
|
||||||
</div>
|
</div>
|
||||||
<ul class="nav nav-tabs" data-init="tabs">
|
<ul class="nav nav-tabs" data-init="tabs">
|
||||||
<li class="active"><a href="#issue-textarea" data-toggle="tab">Write</a></li>
|
<li class="active issue-write"><a href="#issue-textarea" data-toggle="tab">Write</a></li>
|
||||||
<li><a href="#issue-preview" data-toggle="tab">Preview</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>
|
</ul>
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<div class="tab-pane" id="issue-textarea">
|
<div class="tab-pane" id="issue-textarea">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="hidden" value="{{.Issue.Index}}" name="issueIndex"/>
|
<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>
|
</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>
|
</div>
|
||||||
<div class="text-right">
|
<div class="text-right">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="hidden" value="id" name="repo-id"/>
|
{{if .Issue.IsClosed}}
|
||||||
<button class="btn-default btn issue-open" id="issue-open-btn" data-origin="Re-Open" data-text="Re-Open & Comment">Open</button>
|
<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}}
|
||||||
<button class="btn-default btn issue-close" id="issue-close-btn" data-origin="Close" data-text="Close & Comment">Close</button>
|
<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>
|
<button class="btn-success btn" id="issue-reply-btn">Comment</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</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><!--
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
label assignment milestone dashboard
|
label assignment milestone dashboard
|
||||||
|
@ -102,4 +102,4 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{template "base/footer" .}}
|
{{template "base/footer" .}}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
{{template "base/head" .}}
|
{{template "base/head" .}}
|
||||||
{{template "base/navbar" .}}
|
{{template "base/navbar" .}}
|
||||||
{{template "repo/nav" .}}
|
{{template "repo/nav" .}}
|
||||||
{{template "repo/toolbar" .}}
|
|
||||||
<div id="body" class="container" data-page="repo">
|
<div id="body" class="container" data-page="repo">
|
||||||
<div id="source">
|
<div id="source">
|
||||||
<div class="panel panel-info diff-box diff-head-box">
|
<div class="panel panel-info diff-box diff-head-box">
|
||||||
|
@ -11,7 +10,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<span class="pull-right">
|
<span class="pull-right">
|
||||||
commit <span class="label label-default sha">{{.ShortSha}}</span>
|
commit <span class="label label-default sha">{{ShortSha .CommitId}}</span>
|
||||||
</span>
|
</span>
|
||||||
<p class="author">
|
<p class="author">
|
||||||
<img class="avatar" src="{{AvatarLink .Commit.Author.Email}}" alt=""/>
|
<img class="avatar" src="{{AvatarLink .Commit.Author.Email}}" alt=""/>
|
||||||
|
|
|
@ -7,12 +7,6 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-5 actions text-right clone-group-btn">
|
<div class="col-md-5 actions text-right clone-group-btn">
|
||||||
{{if not .IsBareRepo}}
|
{{if not .IsBareRepo}}
|
||||||
<!--<div class="btn-group" id="repo-clone">
|
|
||||||
<button type="button" class="btn btn-default"><i class="fa fa-download fa-lg fa-m"></i></button>
|
|
||||||
<button type="button" class="btn btn-default dropdown-toggle" data-container="body" data-toggle="popover" data-placement="bottom" data-content="<label>SSH:</label><div class='input-group'><input type='text' class='form-control' value='{{.CloneLink.SSH}}'></div>" data-html="1">
|
|
||||||
<span class="caret"></span>
|
|
||||||
</button>
|
|
||||||
</div>-->
|
|
||||||
<div class="btn-group" id="repo-clone">
|
<div class="btn-group" id="repo-clone">
|
||||||
<button type="button" class="btn btn-default"><i class="fa fa-download fa-lg fa-m"></i></button>
|
<button type="button" class="btn btn-default"><i class="fa fa-download fa-lg fa-m"></i></button>
|
||||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
|
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
|
||||||
|
@ -30,10 +24,10 @@
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="help-block text-center">Need help cloning? Visit <a href="#">Help</a>!</p>
|
<p class="help-block text-center">Need help cloning? Visit <a href="#">Help</a>!</p>
|
||||||
<hr/>
|
<!-- <hr/>
|
||||||
<div class="clone-zip text-center">
|
<div class="clone-zip text-center">
|
||||||
<a class="btn btn-success btn-lg" href="#"><i class="fa fa-suitcase"></i>Download ZIP</a>
|
<a class="btn btn-success btn-lg" href="#"><i class="fa fa-suitcase"></i>Download ZIP</a>
|
||||||
</div>
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="btn-group {{if .IsRepositoryWatching}}watching{{else}}no-watching{{end}}" id="repo-watching" data-watch="/{{.Owner.Name}}/{{.Repository.Name}}/action/watch" data-unwatch="/{{.Owner.Name}}/{{.Repository.Name}}/action/unwatch">
|
<div class="btn-group {{if .IsRepositoryWatching}}watching{{else}}no-watching{{end}}" id="repo-watching" data-watch="/{{.Owner.Name}}/{{.Repository.Name}}/action/watch" data-unwatch="/{{.Owner.Name}}/{{.Repository.Name}}/action/unwatch">
|
||||||
|
@ -61,9 +55,9 @@
|
||||||
<button type="button" class="btn btn-default" data-toggle="tooltip" data-placement="top" title="Star"><i class="fa fa-star"></i> {{.Repository.NumStars}}</button>
|
<button type="button" class="btn btn-default" data-toggle="tooltip" data-placement="top" title="Star"><i class="fa fa-star"></i> {{.Repository.NumStars}}</button>
|
||||||
</div> -->
|
</div> -->
|
||||||
{{end}}
|
{{end}}
|
||||||
<div class="btn-group">
|
<!-- <div class="btn-group">
|
||||||
<a type="button" {{if not .IsRepositoryOwner}}href="/{{.Username}}/{{.Reponame}}/fork"{{end}} class="btn btn-default" data-toggle="tooltip" data-placement="top" title="Fork"><i class="fa fa-code-fork fa-lg"></i> {{.Repository.NumForks}}</a>
|
<a type="button" {{if not .IsRepositoryOwner}}href="/{{.Username}}/{{.Reponame}}/fork"{{end}} class="btn btn-default" data-toggle="tooltip" data-placement="top" title="Fork"><i class="fa fa-code-fork fa-lg"></i> {{.Repository.NumForks}}</a>
|
||||||
</div>
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,18 +4,15 @@
|
||||||
{{template "repo/toolbar" .}}
|
{{template "repo/toolbar" .}}
|
||||||
<div id="body" class="container">
|
<div id="body" class="container">
|
||||||
<div id="source">
|
<div id="source">
|
||||||
{{if .IsBareRepo}}
|
|
||||||
{{template "repo/single_bare" .}}
|
|
||||||
{{else}}
|
|
||||||
<div class="source-toolbar">
|
<div class="source-toolbar">
|
||||||
{{ $n := len .Treenames}}
|
{{ $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}}
|
{{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">
|
<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 .IsBranch}}{{.BranchName}}{{else}}{{ShortSha .CommitId}}{{end}}
|
||||||
<b class="caret"></b></a>
|
<b class="caret"></b></a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
{{range .Branches}}
|
{{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}}
|
{{end}}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -38,7 +35,6 @@
|
||||||
{{else}}
|
{{else}}
|
||||||
{{template "repo/single_list" .}}
|
{{template "repo/single_list" .}}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{template "base/footer" .}}
|
{{template "base/footer" .}}
|
||||||
|
|
|
@ -1,31 +1,40 @@
|
||||||
<div class="panel panel-default guide-box clone-group-btn">
|
{{template "base/head" .}}
|
||||||
<div class="panel-heading guide-head">
|
{{template "base/navbar" .}}
|
||||||
<h4>Quick Guide</h4>
|
{{template "repo/nav" .}}
|
||||||
</div>
|
{{template "repo/toolbar" .}}
|
||||||
<div class="panel-body guide-content text-center">
|
<div id="body" class="container">
|
||||||
<h3>Clone this repository</h3>
|
<div id="source">
|
||||||
<div class="input-group col-md-8 col-md-offset-2 guide-buttons">
|
<div class="panel panel-default guide-box clone-group-btn">
|
||||||
<span class="input-group-btn">
|
<div class="panel-heading guide-head">
|
||||||
<button class="btn btn-default" data-link="{{.CloneLink.SSH}}" type="button">SSH</button>
|
<h4>Quick Guide</h4>
|
||||||
<button class="btn btn-default" data-link="{{.CloneLink.HTTPS}}" type="button">HTTPS</button>
|
</div>
|
||||||
</span>
|
<div class="panel-body guide-content text-center">
|
||||||
<input type="text" class="form-control clone-group-url" id="guide-clone-url" value="" readonly/>
|
<h3>Clone this repository</h3>
|
||||||
<span class="input-group-btn">
|
<div class="input-group col-md-8 col-md-offset-2 guide-buttons">
|
||||||
<button class="btn btn-default" type="button"><i class="fa fa-copy" data-toggle="tooltip" title="copy to clipboard" data-placement="top"></i></button>
|
<span class="input-group-btn">
|
||||||
</span>
|
<button class="btn btn-default" data-link="{{.CloneLink.SSH}}" type="button">SSH</button>
|
||||||
</div>
|
<button class="btn btn-default" data-link="{{.CloneLink.HTTPS}}" type="button">HTTPS</button>
|
||||||
<p>We recommend every repository include a <strong>README</strong>, <strong>LICENSE</strong>, and <strong>.gitignore</strong>.</p>
|
</span>
|
||||||
<hr/>
|
<input type="text" class="form-control clone-group-url" id="guide-clone-url" value="" readonly/>
|
||||||
<h3>Create a new repository on the command line</h3>
|
<span class="input-group-btn">
|
||||||
<pre class="text-left"><code>touch README.md
|
<button class="btn btn-default" type="button"><i class="fa fa-copy" data-toggle="tooltip" title="copy to clipboard" data-placement="top"></i></button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<p>We recommend every repository include a <strong>README</strong>, <strong>LICENSE</strong>, and <strong>.gitignore</strong>.</p>
|
||||||
|
<hr/>
|
||||||
|
<h3>Create a new repository on the command line</h3>
|
||||||
|
<pre class="text-left"><code>touch README.md
|
||||||
git init
|
git init
|
||||||
git add README.md
|
git add README.md
|
||||||
git commit -m "first commit"
|
git commit -m "first commit"
|
||||||
git remote add origin <span class="clone-url"></span>
|
git remote add origin <span class="clone-url"></span>
|
||||||
git push -u origin master</code></pre>
|
git push -u origin master</code></pre>
|
||||||
<hr/>
|
<hr/>
|
||||||
<h3>Push an existing repository from the command line</h3>
|
<h3>Push an existing repository from the command line</h3>
|
||||||
<pre class="text-left"><code>git remote add origin <span class="clone-url"></span>
|
<pre class="text-left"><code>git remote add origin <span class="clone-url"></span>
|
||||||
git push -u origin master</code></pre>
|
git push -u origin master</code></pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{template "base/footer" .}}
|
||||||
|
|
|
@ -3,24 +3,24 @@
|
||||||
<nav class="navbar navbar-toolbar navbar-default" role="navigation">
|
<nav class="navbar navbar-toolbar navbar-default" role="navigation">
|
||||||
<div class="collapse navbar-collapse">
|
<div class="collapse navbar-collapse">
|
||||||
<ul class="nav navbar-nav">
|
<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 .BranchName}}{{if ne .BranchName `master`}}/src/{{.BranchName}}{{end}}{{end}}">Source</a></li>
|
||||||
{{if not .IsBareRepo}}
|
{{if not .IsBareRepo}}
|
||||||
<li class="{{if .IsRepoToolbarCommits}}active{{end}}"><a href="/{{.RepositoryLink}}/commits/{{.Branchname}}">Commits</a></li>
|
<li class="{{if .IsRepoToolbarCommits}}active{{end}}"><a href="{{.RepoLink}}/commits/{{if .BranchName}}{{.BranchName}}{{else}}master{{end}}">Commits</a></li>
|
||||||
<!-- <li class="{{if .IsRepoToolbarBranches}}active{{end}}"><a href="/{{.RepositoryLink}}/branches">Branches</a></li> -->
|
<!-- <li class="{{if .IsRepoToolbarBranches}}active{{end}}"><a href="{{.RepoLink}}/branches">Branches</a></li> -->
|
||||||
<!-- <li class="{{if .IsRepoToolbarPulls}}active{{end}}"><a href="/{{.RepositoryLink}}/pulls">Pull Requests</a></li> -->
|
<!-- <li class="{{if .IsRepoToolbarPulls}}active{{end}}"><a href="{{.RepoLink}}/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 .IsRepoToolbarIssues}}active{{end}}"><a href="{{.RepoLink}}/issues">Issues <!--<span class="badge">42</span>--></a></li>
|
||||||
{{if .IsRepoToolbarIssues}}
|
{{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>
|
<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>
|
<button class="btn btn-primary btn-sm">Issues List</button>
|
||||||
</a>{{end}}</li>
|
</a>{{end}}</li>
|
||||||
{{end}}
|
{{end}}
|
||||||
<!-- <li class="dropdown">
|
<!-- <li class="dropdown">
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">More <b class="caret"></b></a>
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown">More <b class="caret"></b></a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li><a href="/{{.RepositoryLink}}/release">Release</a></li>
|
<li><a href="{{.RepoLink}}/release">Release</a></li>
|
||||||
<li><a href="//{{.RepositoryLink}}/wiki">Wiki</a></li>
|
<li><a href="{{.RepoLink}}/wiki">Wiki</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li> -->{{end}}
|
</li> -->{{end}}
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -34,7 +34,7 @@
|
||||||
<li><a href="#">Network</a></li>
|
<li><a href="#">Network</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li> -->{{end}}{{if .IsRepositoryOwner}}
|
</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}}
|
</li>{{end}}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -32,11 +32,10 @@
|
||||||
{{if eq .TabName "activity"}}
|
{{if eq .TabName "activity"}}
|
||||||
<div class="tab-pane active">
|
<div class="tab-pane active">
|
||||||
<ul class="list-unstyled activity-list">
|
<ul class="list-unstyled activity-list">
|
||||||
{{$avatarLink := .Owner.AvatarLink}}
|
|
||||||
{{range .Feeds}}
|
{{range .Feeds}}
|
||||||
<li>
|
<li>
|
||||||
<i class="icon fa fa-{{ActionIcon .OpType}}"></i>
|
<i class="icon fa fa-{{ActionIcon .OpType}}"></i>
|
||||||
<div class="info"><span class="meta">{{TimeSince .Created}}</span><br>{{ActionDesc . $avatarLink | str2html}}</div>
|
<div class="info"><span class="meta">{{TimeSince .Created}}</span><br>{{ActionDesc . | str2html}}</div>
|
||||||
<span class="clearfix"></span>
|
<span class="clearfix"></span>
|
||||||
</li>
|
</li>
|
||||||
{{else}}
|
{{else}}
|
||||||
|
@ -52,7 +51,7 @@
|
||||||
<li>
|
<li>
|
||||||
<div class="meta pull-right"><!-- <i class="fa fa-star"></i> {{.NumStars}} --> <i class="fa fa-code-fork"></i> {{.NumForks}}</div>
|
<div class="meta pull-right"><!-- <i class="fa fa-star"></i> {{.NumStars}} --> <i class="fa fa-code-fork"></i> {{.NumForks}}</div>
|
||||||
<h4>
|
<h4>
|
||||||
<a href="/{{$owner.Name}}/{{.LowerName}}">{{.LowerName}}</a>
|
<a href="/{{$owner.Name}}/{{.Name}}">{{.Name}}</a>
|
||||||
</h4>
|
</h4>
|
||||||
<p class="desc">{{.Description}}</p>
|
<p class="desc">{{.Description}}</p>
|
||||||
<div class="info">Last updated {{.Updated|TimeSince}}</div>
|
<div class="info">Last updated {{.Updated|TimeSince}}</div>
|
||||||
|
@ -64,4 +63,4 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{template "base/footer" .}}
|
{{template "base/footer" .}}
|
||||||
|
|
|
@ -44,7 +44,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group text-center" id="social-login">
|
<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>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
9
tests/.travel.yml
Normal file
9
tests/.travel.yml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
command: go test -v {}
|
||||||
|
include: ^.+_test\.go$
|
||||||
|
path: ./
|
||||||
|
depth: 1
|
||||||
|
verbose: true
|
||||||
|
timeout: 1m
|
||||||
|
reload: false
|
||||||
|
html: test.html
|
||||||
|
notify: []
|
11
tests/README.md
Normal file
11
tests/README.md
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
## gogs test
|
||||||
|
|
||||||
|
this is for developers
|
||||||
|
|
||||||
|
## prepare environment
|
||||||
|
go get -u github.com/shxsun/travelexec
|
||||||
|
# start gogs server
|
||||||
|
gogs web
|
||||||
|
|
||||||
|
## start test
|
||||||
|
travelexec
|
17
tests/default_test.go
Normal file
17
tests/default_test.go
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMain(t *testing.T) {
|
||||||
|
r, err := http.Get("http://localhost:3000/")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer r.Body.Close()
|
||||||
|
if r.StatusCode != http.StatusOK {
|
||||||
|
t.Error(r.StatusCode)
|
||||||
|
}
|
||||||
|
}
|
20
update.go
20
update.go
|
@ -32,6 +32,12 @@ gogs serv provide access auth for repositories`,
|
||||||
func runUpdate(c *cli.Context) {
|
func runUpdate(c *cli.Context) {
|
||||||
base.NewConfigContext()
|
base.NewConfigContext()
|
||||||
models.LoadModelsConfig()
|
models.LoadModelsConfig()
|
||||||
|
|
||||||
|
if models.UseSQLite3 {
|
||||||
|
execDir, _ := base.ExecDir()
|
||||||
|
os.Chdir(execDir)
|
||||||
|
}
|
||||||
|
|
||||||
models.SetEngine()
|
models.SetEngine()
|
||||||
|
|
||||||
w, _ := os.Create("update.log")
|
w, _ := os.Create("update.log")
|
||||||
|
@ -130,18 +136,26 @@ func runUpdate(c *cli.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
commits := make([][]string, 0)
|
commits := make([]*base.PushCommit, 0)
|
||||||
var maxCommits = 3
|
var maxCommits = 3
|
||||||
|
var actEmail string
|
||||||
for e := l.Front(); e != nil; e = e.Next() {
|
for e := l.Front(); e != nil; e = e.Next() {
|
||||||
commit := e.Value.(*git.Commit)
|
commit := e.Value.(*git.Commit)
|
||||||
commits = append(commits, []string{commit.Id().String(), commit.Message()})
|
if actEmail == "" {
|
||||||
|
actEmail = commit.Committer.Email
|
||||||
|
}
|
||||||
|
commits = append(commits,
|
||||||
|
&base.PushCommit{commit.Id().String(),
|
||||||
|
commit.Message(),
|
||||||
|
commit.Author.Email,
|
||||||
|
commit.Author.Name})
|
||||||
if len(commits) >= maxCommits {
|
if len(commits) >= maxCommits {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//commits = append(commits, []string{lastCommit.Id().String(), lastCommit.Message()})
|
//commits = append(commits, []string{lastCommit.Id().String(), lastCommit.Message()})
|
||||||
if err = models.CommitRepoAction(int64(sUserId), userName,
|
if err = models.CommitRepoAction(int64(sUserId), userName, actEmail,
|
||||||
repos.Id, repoName, git.BranchName(refName), &base.PushCommits{l.Len(), commits}); err != nil {
|
repos.Id, repoName, git.BranchName(refName), &base.PushCommits{l.Len(), commits}); err != nil {
|
||||||
log.Error("runUpdate.models.CommitRepoAction: %v", err)
|
log.Error("runUpdate.models.CommitRepoAction: %v", err)
|
||||||
}
|
}
|
||||||
|
|
57
web.go
57
web.go
|
@ -8,22 +8,20 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/codegangsta/cli"
|
"github.com/codegangsta/cli"
|
||||||
"github.com/codegangsta/martini"
|
"github.com/go-martini/martini"
|
||||||
|
|
||||||
"github.com/gogits/binding"
|
"github.com/gogits/binding"
|
||||||
|
|
||||||
"github.com/gogits/gogs/models"
|
|
||||||
"github.com/gogits/gogs/modules/auth"
|
"github.com/gogits/gogs/modules/auth"
|
||||||
"github.com/gogits/gogs/modules/avatar"
|
"github.com/gogits/gogs/modules/avatar"
|
||||||
"github.com/gogits/gogs/modules/base"
|
"github.com/gogits/gogs/modules/base"
|
||||||
"github.com/gogits/gogs/modules/log"
|
"github.com/gogits/gogs/modules/log"
|
||||||
"github.com/gogits/gogs/modules/mailer"
|
|
||||||
"github.com/gogits/gogs/modules/middleware"
|
"github.com/gogits/gogs/modules/middleware"
|
||||||
"github.com/gogits/gogs/routers"
|
"github.com/gogits/gogs/routers"
|
||||||
"github.com/gogits/gogs/routers/admin"
|
"github.com/gogits/gogs/routers/admin"
|
||||||
|
"github.com/gogits/gogs/routers/api/v1"
|
||||||
"github.com/gogits/gogs/routers/dev"
|
"github.com/gogits/gogs/routers/dev"
|
||||||
"github.com/gogits/gogs/routers/repo"
|
"github.com/gogits/gogs/routers/repo"
|
||||||
"github.com/gogits/gogs/routers/user"
|
"github.com/gogits/gogs/routers/user"
|
||||||
|
@ -39,27 +37,6 @@ and it takes care of all the other things for you`,
|
||||||
Flags: []cli.Flag{},
|
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 {
|
func newMartini() *martini.ClassicMartini {
|
||||||
r := martini.NewRouter()
|
r := martini.NewRouter()
|
||||||
m := martini.New()
|
m := martini.New()
|
||||||
|
@ -72,9 +49,8 @@ func newMartini() *martini.ClassicMartini {
|
||||||
}
|
}
|
||||||
|
|
||||||
func runWeb(*cli.Context) {
|
func runWeb(*cli.Context) {
|
||||||
globalInit()
|
fmt.Println("Server is running...")
|
||||||
base.NewServices()
|
routers.GlobalInit()
|
||||||
checkRunMode()
|
|
||||||
log.Info("%s %s", base.AppName, base.AppVer)
|
log.Info("%s %s", base.AppName, base.AppVer)
|
||||||
|
|
||||||
m := newMartini()
|
m := newMartini()
|
||||||
|
@ -90,12 +66,16 @@ func runWeb(*cli.Context) {
|
||||||
|
|
||||||
// Routers.
|
// Routers.
|
||||||
m.Get("/", ignSignIn, routers.Home)
|
m.Get("/", ignSignIn, routers.Home)
|
||||||
m.Get("/install", routers.Install)
|
m.Any("/install", binding.BindIgnErr(auth.InstallForm{}), routers.Install)
|
||||||
m.Get("/issues", reqSignIn, user.Issues)
|
m.Get("/issues", reqSignIn, user.Issues)
|
||||||
m.Get("/pulls", reqSignIn, user.Pulls)
|
m.Get("/pulls", reqSignIn, user.Pulls)
|
||||||
m.Get("/stars", reqSignIn, user.Stars)
|
m.Get("/stars", reqSignIn, user.Stars)
|
||||||
m.Get("/help", routers.Help)
|
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")
|
avt := avatar.CacheServer("public/img/avatar/", "public/img/avatar_default.jpg")
|
||||||
m.Get("/avatar/:hash", avt.ServeHTTP)
|
m.Get("/avatar/:hash", avt.ServeHTTP)
|
||||||
|
|
||||||
|
@ -150,26 +130,26 @@ func runWeb(*cli.Context) {
|
||||||
r.Post("/issues/:index", binding.BindIgnErr(auth.CreateIssueForm{}), repo.UpdateIssue)
|
r.Post("/issues/:index", binding.BindIgnErr(auth.CreateIssueForm{}), repo.UpdateIssue)
|
||||||
r.Post("/comment/:action", repo.Comment)
|
r.Post("/comment/:action", repo.Comment)
|
||||||
}, reqSignIn, middleware.RepoAssignment(true))
|
}, reqSignIn, middleware.RepoAssignment(true))
|
||||||
|
|
||||||
m.Group("/:username/:reponame", func(r martini.Router) {
|
m.Group("/:username/:reponame", func(r martini.Router) {
|
||||||
r.Get("/commits/:branchname", repo.Commits)
|
|
||||||
r.Get("/issues", repo.Issues)
|
r.Get("/issues", repo.Issues)
|
||||||
r.Get("/issues/:index", repo.ViewIssue)
|
r.Get("/issues/:index", repo.ViewIssue)
|
||||||
r.Get("/pulls", repo.Pulls)
|
r.Get("/pulls", repo.Pulls)
|
||||||
r.Get("/branches", repo.Branches)
|
r.Get("/branches", repo.Branches)
|
||||||
|
}, ignSignIn, middleware.RepoAssignment(true))
|
||||||
|
|
||||||
|
m.Group("/:username/:reponame", func(r martini.Router) {
|
||||||
r.Get("/src/:branchname", repo.Single)
|
r.Get("/src/:branchname", repo.Single)
|
||||||
r.Get("/src/:branchname/**", repo.Single)
|
r.Get("/src/:branchname/**", repo.Single)
|
||||||
r.Get("/raw/:branchname/**", repo.SingleDownload)
|
r.Get("/raw/:branchname/**", repo.SingleDownload)
|
||||||
r.Get("/commits/:branchname", repo.Commits)
|
r.Get("/commits/:branchname", repo.Commits)
|
||||||
r.Get("/commits/:branchname", repo.Commits)
|
r.Get("/commit/:branchname", repo.Diff)
|
||||||
}, ignSignIn, middleware.RepoAssignment(true))
|
r.Get("/commit/:branchname/**", repo.Diff)
|
||||||
|
}, ignSignIn, middleware.RepoAssignment(true, 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.Group("/:username", func(r martini.Router) {
|
m.Group("/:username", func(r martini.Router) {
|
||||||
r.Get("/:reponame", middleware.RepoAssignment(true), repo.Single)
|
|
||||||
r.Get("/:reponame", middleware.RepoAssignment(true), repo.Single)
|
|
||||||
r.Any("/:reponame/**", repo.Http)
|
r.Any("/:reponame/**", repo.Http)
|
||||||
|
r.Get("/:reponame", middleware.RepoAssignment(true, true, true), repo.Single)
|
||||||
}, ignSignIn)
|
}, ignSignIn)
|
||||||
|
|
||||||
// Not found handler.
|
// Not found handler.
|
||||||
|
@ -180,6 +160,7 @@ func runWeb(*cli.Context) {
|
||||||
base.Cfg.MustValue("server", "HTTP_PORT", "3000"))
|
base.Cfg.MustValue("server", "HTTP_PORT", "3000"))
|
||||||
log.Info("Listen: %s", listenAddr)
|
log.Info("Listen: %s", listenAddr)
|
||||||
if err := http.ListenAndServe(listenAddr, m); err != nil {
|
if err := http.ListenAndServe(listenAddr, m); err != nil {
|
||||||
log.Critical(err.Error())
|
fmt.Println(err.Error())
|
||||||
|
//log.Critical(err.Error()) // not working now
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue