Merge branch 'dev' of github.com:gogits/gogs into access

release/v1.15
Unknwon 2015-02-11 19:25:59 -05:00
commit c5c467a9cd
24 changed files with 120 additions and 95 deletions

1
.gitignore vendored
View File

@ -1,6 +1,7 @@
.DS_Store .DS_Store
*.db *.db
*.log *.log
log/
custom/ custom/
data/ data/
.vendor/ .vendor/

View File

@ -3,6 +3,7 @@ path = github.com/gogits/gogs
[deps] [deps]
github.com/beego/memcache = commit:2aea774416 github.com/beego/memcache = commit:2aea774416
github.com/bradfitz/gomemcache =
github.com/Unknwon/cae = commit:2e70a1351b github.com/Unknwon/cae = commit:2e70a1351b
github.com/Unknwon/com = commit:d9bcf409c8 github.com/Unknwon/com = commit:d9bcf409c8
github.com/Unknwon/i18n = commit:1e88666229 github.com/Unknwon/i18n = commit:1e88666229
@ -27,6 +28,8 @@ github.com/microcosm-cc/bluemonday =
github.com/nfnt/resize = commit:8f44931448 github.com/nfnt/resize = commit:8f44931448
github.com/russross/blackfriday = commit:05b8cefd6a github.com/russross/blackfriday = commit:05b8cefd6a
github.com/shurcooL/go = commit:48293cbc7a github.com/shurcooL/go = commit:48293cbc7a
golang.org/x/net =
golang.org/x/text =
gopkg.in/ini.v1 = commit:28ad8c408b gopkg.in/ini.v1 = commit:28ad8c408b
gopkg.in/redis.v2 = commit:e617904962 gopkg.in/redis.v2 = commit:e617904962

View File

@ -28,7 +28,7 @@ The goal of this project is to make the easiest, fastest and most painless way t
- Please see [Documentation](http://gogs.io/docs/intro/) for project design, known issues, and change log. - Please see [Documentation](http://gogs.io/docs/intro/) for project design, known issues, and change log.
- See [Trello Board](https://trello.com/b/uxAoeLUl/gogs-go-git-service) to follow the develop team. - See [Trello Board](https://trello.com/b/uxAoeLUl/gogs-go-git-service) to follow the develop team.
- Try it before anything? Do it [online](https://try.gogs.io/Unknown/gogs) or go down to **Installation -> Install from binary** section! - Try it before anything? Do it [online](https://try.gogs.io/unknwon/gogs) or go down to **Installation -> Install from binary** section!
- Having troubles? Get help from [Troubleshooting](http://gogs.io/docs/intro/troubleshooting.md). - Having troubles? Get help from [Troubleshooting](http://gogs.io/docs/intro/troubleshooting.md).
- Want to help on localization? Check out [Crowdin](https://crowdin.com/project/gogs)! - Want to help on localization? Check out [Crowdin](https://crowdin.com/project/gogs)!
@ -52,7 +52,7 @@ The goal of this project is to make the easiest, fastest and most painless way t
- Drone CI integration - Drone CI integration
- Supports MySQL, PostgreSQL and SQLite3 - Supports MySQL, PostgreSQL and SQLite3
- Social account login(GitHub, Google, QQ, Weibo) - Social account login(GitHub, Google, QQ, Weibo)
- Multi-language support([9 languages](https://crowdin.com/project/gogs)) - Multi-language support([10 languages](https://crowdin.com/project/gogs))
## System Requirements ## System Requirements

View File

@ -1,4 +1,4 @@
Gogs - Go Git Service [![wercker status](https://app.wercker.com/status/ad0bdb0bc450ac6f09bc56b9640a50aa/s/ "wercker status")](https://app.wercker.com/project/bykey/ad0bdb0bc450ac6f09bc56b9640a50aa) [![Build Status](https://travis-ci.org/gogits/gogs.svg?branch=master)](https://travis-ci.org/gogits/gogs) Gogs - Go Git Service [![Build Status](https://travis-ci.org/gogits/gogs.svg?branch=master)](https://travis-ci.org/gogits/gogs)
===================== =====================
Gogs(Go Git Service) 是一个基于 Go 语言的自助 Git 服务。 Gogs(Go Git Service) 是一个基于 Go 语言的自助 Git 服务。
@ -15,7 +15,7 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
- 有关项目设计、已知问题和变更日志,请通过 [使用手册](http://gogs.io/docs/intro/) 查看。 - 有关项目设计、已知问题和变更日志,请通过 [使用手册](http://gogs.io/docs/intro/) 查看。
- 您可以到 [Trello Board](https://trello.com/b/uxAoeLUl/gogs-go-git-service) 跟随开发团队的脚步。 - 您可以到 [Trello Board](https://trello.com/b/uxAoeLUl/gogs-go-git-service) 跟随开发团队的脚步。
- 想要先睹为快?通过 [在线体验](https://try.gogs.io/Unknown/gogs) 或查看 **安装部署 -> 二进制安装** 小节。 - 想要先睹为快?通过 [在线体验](https://try.gogs.io/unknwon/gogs) 或查看 **安装部署 -> 二进制安装** 小节。
- 使用过程中遇到问题?尝试从 [故障排查](http://gogs.io/docs/intro/troubleshooting.md) 页面获取帮助。 - 使用过程中遇到问题?尝试从 [故障排查](http://gogs.io/docs/intro/troubleshooting.md) 页面获取帮助。
- 希望帮助多国语言界面的翻译吗?请立即访问 [Crowdin](https://crowdin.com/project/gogs) - 希望帮助多国语言界面的翻译吗?请立即访问 [Crowdin](https://crowdin.com/project/gogs)
@ -39,7 +39,7 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
- Drone CI 持续部署集成 - Drone CI 持续部署集成
- 支持 MySQL、PostgreSQL 以及 SQLite3 数据库 - 支持 MySQL、PostgreSQL 以及 SQLite3 数据库
- 社交帐号登录GitHub、Google、QQ、微博 - 社交帐号登录GitHub、Google、QQ、微博
- 多语言支持([9 种语言]([more](https://crowdin.com/project/gogs)) - 多语言支持([10 种语言]([more](https://crowdin.com/project/gogs))
## 系统要求 ## 系统要求

View File

@ -89,6 +89,8 @@ ENABLE_REVERSE_PROXY_AUTO_REGISTERATION = false
TASK_INTERVAL = 1 TASK_INTERVAL = 1
; Deliver timeout in seconds ; Deliver timeout in seconds
DELIVER_TIMEOUT = 5 DELIVER_TIMEOUT = 5
; Allow insecure certification
SKIP_TLS_VERIFY = false
[mailer] [mailer]
ENABLED = false ENABLED = false

View File

@ -647,6 +647,7 @@ config.reset_password_code_lives = Reset Password Code Lives
config.webhook_config = Webhook Configuration config.webhook_config = Webhook Configuration
config.task_interval = Task Interval config.task_interval = Task Interval
config.deliver_timeout = Deliver Timeout config.deliver_timeout = Deliver Timeout
config.skip_tls_verify = Skip TLS Verify
config.mailer_config = Mailer Configuration config.mailer_config = Mailer Configuration
config.mailer_enabled = Enabled config.mailer_enabled = Enabled
config.mailer_name = Name config.mailer_name = Name

View File

@ -516,8 +516,8 @@ dashboard.git_gc_repos=リポジトリでのガベージコレクションを実
dashboard.git_gc_repos_success=すべてのリポジトリは正常にガベージ コレクションを行いました。 dashboard.git_gc_repos_success=すべてのリポジトリは正常にガベージ コレクションを行いました。
dashboard.resync_all_sshkeys='.ssh/ autorized_key' ファイルを再生成します。警告Gogsキー以外は失われます dashboard.resync_all_sshkeys='.ssh/ autorized_key' ファイルを再生成します。警告Gogsキー以外は失われます
dashboard.resync_all_sshkeys_success=すべての公開鍵が正常に書き換えられました。 dashboard.resync_all_sshkeys_success=すべての公開鍵が正常に書き換えられました。
dashboard.resync_all_update_hooks=Rewrite all update hook of repositories (needed when custom config path is changed) dashboard.resync_all_update_hooks=リポジトリの update フックをすべて再更新する(カスタムの設定パスが変更されたときに必要)
dashboard.resync_all_update_hooks_success=All repositories' update hook have been rewritten successfully. dashboard.resync_all_update_hooks_success=リポジトリの update フックがすべて正常に再更新されました。
dashboard.server_uptime=サーバーの稼働時間 dashboard.server_uptime=サーバーの稼働時間
dashboard.current_goroutine=現在のGoroutine dashboard.current_goroutine=現在のGoroutine

View File

@ -17,7 +17,7 @@ import (
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
) )
const APP_VER = "0.5.13.0208 Beta" const APP_VER = "0.5.13.0211 Beta"
func init() { func init() {
runtime.GOMAXPROCS(runtime.NumCPU()) runtime.GOMAXPROCS(runtime.NumCPU())

View File

@ -24,7 +24,10 @@ import (
type Engine interface { type Engine interface {
Delete(interface{}) (int64, error) Delete(interface{}) (int64, error)
Exec(string, ...interface{}) (sql.Result, error) Exec(string, ...interface{}) (sql.Result, error)
Get(interface{}) (bool, error)
Insert(...interface{}) (int64, error) Insert(...interface{}) (int64, error)
Id(interface{}) *xorm.Session
Where(string, ...interface{}) *xorm.Session
} }
var ( var (

View File

@ -12,7 +12,6 @@ import (
"strings" "strings"
"github.com/Unknwon/com" "github.com/Unknwon/com"
"github.com/go-xorm/xorm"
"github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/base"
) )
@ -391,7 +390,7 @@ func RemoveOrgUser(orgId, uid int64) error {
return err return err
} }
for _, t := range ts { for _, t := range ts {
if err = removeTeamMemberWithSess(org.Id, t.Id, u.Id, sess); err != nil { if err = removeTeamMember(sess, org.Id, t.Id, u.Id); err != nil {
return err return err
} }
} }
@ -486,18 +485,18 @@ func (t *Team) RemoveMember(uid int64) error {
} }
// addAccessWithAuthorize inserts or updates access with given mode. // addAccessWithAuthorize inserts or updates access with given mode.
func addAccessWithAuthorize(sess *xorm.Session, access *Access, mode AccessType) error { func addAccessWithAuthorize(e Engine, access *Access, mode AccessType) error {
has, err := x.Get(access) has, err := e.Get(access)
if err != nil { if err != nil {
return fmt.Errorf("fail to get access: %v", err) return fmt.Errorf("fail to get access: %v", err)
} }
access.Mode = mode access.Mode = mode
if has { if has {
if _, err = sess.Id(access.Id).Update(access); err != nil { if _, err = e.Id(access.Id).Update(access); err != nil {
return fmt.Errorf("fail to update access: %v", err) return fmt.Errorf("fail to update access: %v", err)
} }
} else { } else {
if _, err = sess.Insert(access); err != nil { if _, err = e.Insert(access); err != nil {
return fmt.Errorf("fail to insert access: %v", err) return fmt.Errorf("fail to insert access: %v", err)
} }
} }
@ -536,7 +535,7 @@ func (t *Team) AddRepository(repo *Repository) (err error) {
mode := AuthorizeToAccessType(t.Authorize) mode := AuthorizeToAccessType(t.Authorize)
for _, u := range t.Members { for _, u := range t.Members {
auth, err := GetHighestAuthorize(t.OrgId, u.Id, repo.Id, t.Id) auth, err := getHighestAuthorize(sess, t.OrgId, u.Id, repo.Id, t.Id)
if err != nil { if err != nil {
sess.Rollback() sess.Rollback()
return err return err
@ -552,7 +551,7 @@ func (t *Team) AddRepository(repo *Repository) (err error) {
return err return err
} }
} }
if err = WatchRepo(u.Id, repo.Id, true); err != nil { if err = watchRepo(sess, u.Id, repo.Id, true); err != nil {
sess.Rollback() sess.Rollback()
return err return err
} }
@ -593,7 +592,7 @@ func (t *Team) RemoveRepository(repoId int64) error {
// Remove access to team members. // Remove access to team members.
for _, u := range t.Members { for _, u := range t.Members {
auth, err := GetHighestAuthorize(t.OrgId, u.Id, repo.Id, t.Id) auth, err := getHighestAuthorize(sess, t.OrgId, u.Id, repo.Id, t.Id)
if err != nil { if err != nil {
sess.Rollback() sess.Rollback()
return err return err
@ -607,7 +606,7 @@ func (t *Team) RemoveRepository(repoId int64) error {
if _, err = sess.Delete(access); err != nil { if _, err = sess.Delete(access); err != nil {
sess.Rollback() sess.Rollback()
return fmt.Errorf("fail to delete access: %v", err) return fmt.Errorf("fail to delete access: %v", err)
} else if err = WatchRepo(u.Id, repo.Id, false); err != nil { } else if err = watchRepo(sess, u.Id, repo.Id, false); err != nil {
sess.Rollback() sess.Rollback()
return err return err
} }
@ -678,10 +677,9 @@ func GetTeam(orgId int64, name string) (*Team, error) {
return t, nil return t, nil
} }
// GetTeamById returns team by given ID. func getTeamById(e Engine, teamId int64) (*Team, error) {
func GetTeamById(teamId int64) (*Team, error) {
t := new(Team) t := new(Team)
has, err := x.Id(teamId).Get(t) has, err := e.Id(teamId).Get(t)
if err != nil { if err != nil {
return nil, err return nil, err
} else if !has { } else if !has {
@ -690,9 +688,13 @@ func GetTeamById(teamId int64) (*Team, error) {
return t, nil return t, nil
} }
// GetHighestAuthorize returns highest repository authorize level for given user and team. // GetTeamById returns team by given ID.
func GetHighestAuthorize(orgId, uid, repoId, teamId int64) (AuthorizeType, error) { func GetTeamById(teamId int64) (*Team, error) {
ts, err := GetUserTeams(orgId, uid) return getTeamById(x, teamId)
}
func getHighestAuthorize(e Engine, orgId, uid, repoId, teamId int64) (AuthorizeType, error) {
ts, err := getUserTeams(e, orgId, uid)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -714,6 +716,11 @@ func GetHighestAuthorize(orgId, uid, repoId, teamId int64) (AuthorizeType, error
return auth, nil return auth, nil
} }
// GetHighestAuthorize returns highest repository authorize level for given user and team.
func GetHighestAuthorize(orgId, uid, repoId, teamId int64) (AuthorizeType, error) {
return getHighestAuthorize(x, orgId, uid, repoId, teamId)
}
// UpdateTeam updates information of team. // UpdateTeam updates information of team.
func UpdateTeam(t *Team, authChanged bool) (err error) { func UpdateTeam(t *Team, authChanged bool) (err error) {
if !IsLegalName(t.Name) { if !IsLegalName(t.Name) {
@ -866,10 +873,14 @@ type TeamUser struct {
TeamId int64 TeamId int64
} }
func isTeamMember(e Engine, orgId, teamId, uid int64) bool {
has, _ := e.Where("uid=?", uid).And("org_id=?", orgId).And("team_id=?", teamId).Get(new(TeamUser))
return has
}
// IsTeamMember returns true if given user is a member of team. // IsTeamMember returns true if given user is a member of team.
func IsTeamMember(orgId, teamId, uid int64) bool { func IsTeamMember(orgId, teamId, uid int64) bool {
has, _ := x.Where("uid=?", uid).And("org_id=?", orgId).And("team_id=?", teamId).Get(new(TeamUser)) return isTeamMember(x, orgId, teamId, uid)
return has
} }
// GetTeamMembers returns all members in given team of organization. // GetTeamMembers returns all members in given team of organization.
@ -879,17 +890,16 @@ func GetTeamMembers(orgId, teamId int64) ([]*User, error) {
return us, err return us, err
} }
// GetUserTeams returns all teams that user belongs to in given organization. func getUserTeams(e Engine, orgId, uid int64) ([]*Team, error) {
func GetUserTeams(orgId, uid int64) ([]*Team, error) {
tus := make([]*TeamUser, 0, 5) tus := make([]*TeamUser, 0, 5)
if err := x.Where("uid=?", uid).And("org_id=?", orgId).Find(&tus); err != nil { if err := e.Where("uid=?", uid).And("org_id=?", orgId).Find(&tus); err != nil {
return nil, err return nil, err
} }
ts := make([]*Team, len(tus)) ts := make([]*Team, len(tus))
for i, tu := range tus { for i, tu := range tus {
t := new(Team) t := new(Team)
has, err := x.Id(tu.TeamId).Get(t) has, err := e.Id(tu.TeamId).Get(t)
if err != nil { if err != nil {
return nil, err return nil, err
} else if !has { } else if !has {
@ -900,6 +910,11 @@ func GetUserTeams(orgId, uid int64) ([]*Team, error) {
return ts, nil return ts, nil
} }
// GetUserTeams returns all teams that user belongs to in given organization.
func GetUserTeams(orgId, uid int64) ([]*Team, error) {
return getUserTeams(x, orgId, uid)
}
// AddTeamMember adds new member to given team of given organization. // AddTeamMember adds new member to given team of given organization.
func AddTeamMember(orgId, teamId, uid int64) error { func AddTeamMember(orgId, teamId, uid int64) error {
if IsTeamMember(orgId, teamId, uid) { if IsTeamMember(orgId, teamId, uid) {
@ -956,7 +971,7 @@ func AddTeamMember(orgId, teamId, uid int64) error {
// Give access to team repositories. // Give access to team repositories.
mode := AuthorizeToAccessType(t.Authorize) mode := AuthorizeToAccessType(t.Authorize)
for _, repo := range t.Repos { for _, repo := range t.Repos {
auth, err := GetHighestAuthorize(t.OrgId, u.Id, repo.Id, teamId) auth, err := getHighestAuthorize(sess, t.OrgId, u.Id, repo.Id, teamId)
if err != nil { if err != nil {
sess.Rollback() sess.Rollback()
return err return err
@ -993,13 +1008,13 @@ func AddTeamMember(orgId, teamId, uid int64) error {
return sess.Commit() return sess.Commit()
} }
func removeTeamMemberWithSess(orgId, teamId, uid int64, sess *xorm.Session) error { func removeTeamMember(e Engine, orgId, teamId, uid int64) error {
if !IsTeamMember(orgId, teamId, uid) { if !isTeamMember(e, orgId, teamId, uid) {
return nil return nil
} }
// Get team and its repositories. // Get team and its repositories.
t, err := GetTeamById(teamId) t, err := getTeamById(e, teamId)
if err != nil { if err != nil {
return err return err
} }
@ -1033,19 +1048,16 @@ func removeTeamMemberWithSess(orgId, teamId, uid int64, sess *xorm.Session) erro
TeamId: teamId, TeamId: teamId,
} }
if _, err := sess.Delete(tu); err != nil { if _, err := e.Delete(tu); err != nil {
sess.Rollback()
return err return err
} else if _, err = sess.Id(t.Id).AllCols().Update(t); err != nil { } else if _, err = e.Id(t.Id).AllCols().Update(t); err != nil {
sess.Rollback()
return err return err
} }
// Delete access to team repositories. // Delete access to team repositories.
for _, repo := range t.Repos { for _, repo := range t.Repos {
auth, err := GetHighestAuthorize(t.OrgId, u.Id, repo.Id, teamId) auth, err := getHighestAuthorize(e, t.OrgId, u.Id, repo.Id, teamId)
if err != nil { if err != nil {
sess.Rollback()
return err return err
} }
@ -1055,17 +1067,14 @@ func removeTeamMemberWithSess(orgId, teamId, uid int64, sess *xorm.Session) erro
} }
// Delete access if this is the last team user belongs to. // Delete access if this is the last team user belongs to.
if auth == 0 { if auth == 0 {
if _, err = sess.Delete(access); err != nil { if _, err = e.Delete(access); err != nil {
sess.Rollback()
return fmt.Errorf("fail to delete access: %v", err) return fmt.Errorf("fail to delete access: %v", err)
} else if err = WatchRepo(u.Id, repo.Id, false); err != nil { } else if err = watchRepo(e, u.Id, repo.Id, false); err != nil {
sess.Rollback()
return err return err
} }
} else if auth < t.Authorize { } else if auth < t.Authorize {
// Downgrade authorize level. // Downgrade authorize level.
if err = addAccessWithAuthorize(sess, access, AuthorizeToAccessType(auth)); err != nil { if err = addAccessWithAuthorize(e, access, AuthorizeToAccessType(auth)); err != nil {
sess.Rollback()
return err return err
} }
} }
@ -1073,17 +1082,15 @@ func removeTeamMemberWithSess(orgId, teamId, uid int64, sess *xorm.Session) erro
// This must exist. // This must exist.
ou := new(OrgUser) ou := new(OrgUser)
_, err = sess.Where("uid=?", uid).And("org_id=?", org.Id).Get(ou) _, err = e.Where("uid=?", uid).And("org_id=?", org.Id).Get(ou)
if err != nil { if err != nil {
sess.Rollback()
return err return err
} }
ou.NumTeams-- ou.NumTeams--
if t.IsOwnerTeam() { if t.IsOwnerTeam() {
ou.IsOwner = false ou.IsOwner = false
} }
if _, err = sess.Id(ou.Id).AllCols().Update(ou); err != nil { if _, err = e.Id(ou.Id).AllCols().Update(ou); err != nil {
sess.Rollback()
return err return err
} }
return nil return nil
@ -1096,7 +1103,8 @@ func RemoveTeamMember(orgId, teamId, uid int64) error {
if err := sess.Begin(); err != nil { if err := sess.Begin(); err != nil {
return err return err
} }
if err := removeTeamMemberWithSess(orgId, teamId, uid, sess); err != nil { if err := removeTeamMember(sess, orgId, teamId, uid); err != nil {
sess.Rollback()
return err return err
} }
return sess.Commit() return sess.Commit()

View File

@ -357,13 +357,16 @@ func MigrateRepository(u *User, name, desc string, private, mirror bool, url str
os.RemoveAll(repoPath) os.RemoveAll(repoPath)
} }
// this command could for both migrate and mirror // FIXME: this command could for both migrate and mirror
_, stderr, err := process.ExecTimeout(10*time.Minute, _, stderr, err := process.ExecTimeout(10*time.Minute,
fmt.Sprintf("MigrateRepository: %s", repoPath), fmt.Sprintf("MigrateRepository: %s", repoPath),
"git", "clone", "--mirror", "--bare", url, repoPath) "git", "clone", "--mirror", "--bare", url, repoPath)
if err != nil { if err != nil {
return repo, errors.New("git clone: " + stderr) return repo, fmt.Errorf("git clone --mirror --bare: %v", stderr)
} else if err = createUpdateHook(repoPath); err != nil {
return repo, fmt.Errorf("create update hook: %v", err)
} }
return repo, UpdateRepository(repo) return repo, UpdateRepository(repo)
} }
@ -402,7 +405,7 @@ func initRepoCommit(tmpPath string, sig *git.Signature) (err error) {
return nil return nil
} }
func createHookUpdate(repoPath string) error { func createUpdateHook(repoPath string) error {
return ioutil.WriteFile(path.Join(repoPath, "hooks/update"), return ioutil.WriteFile(path.Join(repoPath, "hooks/update"),
[]byte(fmt.Sprintf(_TPL_UPDATE_HOOK, setting.ScriptType, "\""+appPath+"\"", setting.CustomConf)), 0777) []byte(fmt.Sprintf(_TPL_UPDATE_HOOK, setting.ScriptType, "\""+appPath+"\"", setting.CustomConf)), 0777)
} }
@ -416,8 +419,7 @@ func initRepository(f string, u *User, repo *Repository, initReadme bool, repoLa
return err return err
} }
// hook/post-update if err := createUpdateHook(repoPath); err != nil {
if err := createHookUpdate(repoPath); err != nil {
return err return err
} }
@ -1178,7 +1180,7 @@ func RewriteRepositoryUpdateHook() error {
if err := repo.GetOwner(); err != nil { if err := repo.GetOwner(); err != nil {
return err return err
} }
return createHookUpdate(RepoPath(repo.Owner.Name, repo.Name)) return createUpdateHook(RepoPath(repo.Owner.Name, repo.Name))
}) })
} }
@ -1297,7 +1299,7 @@ func IsWatching(uid, repoId int64) bool {
return has return has
} }
func watchRepoWithEngine(e Engine, uid, repoId int64, watch bool) (err error) { func watchRepo(e Engine, uid, repoId int64, watch bool) (err error) {
if watch { if watch {
if IsWatching(uid, repoId) { if IsWatching(uid, repoId) {
return nil return nil
@ -1320,7 +1322,7 @@ func watchRepoWithEngine(e Engine, uid, repoId int64, watch bool) (err error) {
// Watch or unwatch repository. // Watch or unwatch repository.
func WatchRepo(uid, repoId int64, watch bool) (err error) { func WatchRepo(uid, repoId int64, watch bool) (err error) {
return watchRepoWithEngine(x, uid, repoId, watch) return watchRepo(x, uid, repoId, watch)
} }
// GetWatchers returns all watchers of given repository. // GetWatchers returns all watchers of given repository.
@ -1508,14 +1510,14 @@ func ForkRepository(u *User, oldRepo *Repository, name, desc string) (*Repositor
log.Error(4, "GetMembers: %v", err) log.Error(4, "GetMembers: %v", err)
} else { } else {
for _, u := range t.Members { for _, u := range t.Members {
if err = watchRepoWithEngine(sess, u.Id, repo.Id, true); err != nil { if err = watchRepo(sess, u.Id, repo.Id, true); err != nil {
log.Error(4, "WatchRepo2: %v", err) log.Error(4, "WatchRepo2: %v", err)
} }
} }
} }
} }
} else { } else {
if err = watchRepoWithEngine(sess, u.Id, repo.Id, true); err != nil { if err = watchRepo(sess, u.Id, repo.Id, true); err != nil {
log.Error(4, "WatchRepo3: %v", err) log.Error(4, "WatchRepo3: %v", err)
} }
} }

View File

@ -5,6 +5,7 @@
package models package models
import ( import (
"crypto/tls"
"encoding/json" "encoding/json"
"errors" "errors"
"io/ioutil" "io/ioutil"
@ -307,13 +308,14 @@ func DeliverHooks() {
defer func() { isShooting = false }() defer func() { isShooting = false }()
tasks := make([]*HookTask, 0, 10) tasks := make([]*HookTask, 0, 10)
timeout := time.Duration(setting.WebhookDeliverTimeout) * time.Second timeout := time.Duration(setting.Webhook.DeliverTimeout) * time.Second
x.Where("is_delivered=?", false).Iterate(new(HookTask), x.Where("is_delivered=?", false).Iterate(new(HookTask),
func(idx int, bean interface{}) error { func(idx int, bean interface{}) error {
t := bean.(*HookTask) t := bean.(*HookTask)
req := httplib.Post(t.Url).SetTimeout(timeout, timeout). req := httplib.Post(t.Url).SetTimeout(timeout, timeout).
Header("X-Gogs-Delivery", t.Uuid). Header("X-Gogs-Delivery", t.Uuid).
Header("X-Gogs-Event", string(t.EventType)) Header("X-Gogs-Event", string(t.EventType)).
SetTLSClientConfig(&tls.Config{InsecureSkipVerify: setting.Webhook.SkipTLSVerify})
switch t.ContentType { switch t.ContentType {
case JSON: case JSON:
@ -329,7 +331,7 @@ func DeliverHooks() {
case GOGS: case GOGS:
{ {
if _, err := req.Response(); err != nil { if _, err := req.Response(); err != nil {
log.Error(4, "Delivery: %v", err) log.Error(5, "Delivery: %v", err)
} else { } else {
t.IsSucceed = true t.IsSucceed = true
} }
@ -337,15 +339,15 @@ func DeliverHooks() {
case SLACK: case SLACK:
{ {
if res, err := req.Response(); err != nil { if res, err := req.Response(); err != nil {
log.Error(4, "Delivery: %v", err) log.Error(5, "Delivery: %v", err)
} else { } else {
defer res.Body.Close() defer res.Body.Close()
contents, err := ioutil.ReadAll(res.Body) contents, err := ioutil.ReadAll(res.Body)
if err != nil { if err != nil {
log.Error(4, "%s", err) log.Error(5, "%s", err)
} else { } else {
if string(contents) != "ok" { if string(contents) != "ok" {
log.Error(4, "slack failed with: %s", string(contents)) log.Error(5, "slack failed with: %s", string(contents))
} else { } else {
t.IsSucceed = true t.IsSucceed = true
} }

View File

@ -106,7 +106,7 @@ func (options *CustomRender) Image(out *bytes.Buffer, link []byte, title []byte,
} }
var ( var (
MentionPattern = regexp.MustCompile(`((^|\s)@)[0-9a-zA-Z_]{1,}`) MentionPattern = regexp.MustCompile(`(\s|^)@[0-9a-zA-Z_]+`)
commitPattern = regexp.MustCompile(`(\s|^)https?.*commit/[0-9a-zA-Z]+(#+[0-9a-zA-Z-]*)?`) commitPattern = regexp.MustCompile(`(\s|^)https?.*commit/[0-9a-zA-Z]+(#+[0-9a-zA-Z-]*)?`)
issueFullPattern = regexp.MustCompile(`(\s|^)https?.*issues/[0-9]+(#+[0-9a-zA-Z-]*)?`) issueFullPattern = regexp.MustCompile(`(\s|^)https?.*issues/[0-9]+(#+[0-9a-zA-Z-]*)?`)
issueIndexPattern = regexp.MustCompile(`( |^)#[0-9]+`) issueIndexPattern = regexp.MustCompile(`( |^)#[0-9]+`)
@ -128,8 +128,9 @@ func RenderSpecialLink(rawBytes []byte, urlPrefix string) []byte {
if !inCodeBlock && !bytes.HasPrefix(line, tab) { if !inCodeBlock && !bytes.HasPrefix(line, tab) {
ms := MentionPattern.FindAll(line, -1) ms := MentionPattern.FindAll(line, -1)
for _, m := range ms { for _, m := range ms {
m = bytes.TrimSpace(m)
line = bytes.Replace(line, m, line = bytes.Replace(line, m,
[]byte(fmt.Sprintf(`<a href="%s/%s">%s</a>`, setting.AppSubUrl, m[2:], m)), -1) []byte(fmt.Sprintf(`<a href="%s/%s">%s</a>`, setting.AppSubUrl, m[1:], m)), -1)
} }
} }

View File

@ -15,7 +15,7 @@ var c = New()
func NewCronContext() { func NewCronContext() {
c.AddFunc("Update mirrors", "@every 1h", models.MirrorUpdate) c.AddFunc("Update mirrors", "@every 1h", models.MirrorUpdate)
c.AddFunc("Deliver hooks", fmt.Sprintf("@every %dm", setting.WebhookTaskInterval), models.DeliverHooks) c.AddFunc("Deliver hooks", fmt.Sprintf("@every %dm", setting.Webhook.TaskInterval), models.DeliverHooks)
if setting.Git.Fsck.Enable { if setting.Git.Fsck.Enable {
c.AddFunc("Repository health check", fmt.Sprintf("@every %dh", setting.Git.Fsck.Interval), models.GitFsck) c.AddFunc("Repository health check", fmt.Sprintf("@every %dh", setting.Git.Fsck.Interval), models.GitFsck)
} }

View File

@ -6,7 +6,6 @@ package middleware
import ( import (
"net/url" "net/url"
"strings"
"github.com/Unknwon/macaron" "github.com/Unknwon/macaron"
"github.com/macaron-contrib/csrf" "github.com/macaron-contrib/csrf"
@ -50,10 +49,6 @@ func Toggle(options *ToggleOptions) macaron.Handler {
if options.SignInRequire { if options.SignInRequire {
if !ctx.IsSigned { if !ctx.IsSigned {
// Ignore watch repository operation.
if strings.HasSuffix(ctx.Req.RequestURI, "watch") {
return
}
ctx.SetCookie("redirect_to", url.QueryEscape(setting.AppSubUrl+ctx.Req.RequestURI), 0, setting.AppSubUrl) ctx.SetCookie("redirect_to", url.QueryEscape(setting.AppSubUrl+ctx.Req.RequestURI), 0, setting.AppSubUrl)
ctx.Redirect(setting.AppSubUrl + "/user/login") ctx.Redirect(setting.AppSubUrl + "/user/login")
return return

View File

@ -68,8 +68,11 @@ var (
ReverseProxyAuthUser string ReverseProxyAuthUser string
// Webhook settings. // Webhook settings.
WebhookTaskInterval int Webhook struct {
WebhookDeliverTimeout int TaskInterval int
DeliverTimeout int
SkipTLSVerify bool
}
// Repository settings. // Repository settings.
RepoRootPath string RepoRootPath string
@ -508,8 +511,10 @@ func newNotifyMailService() {
} }
func newWebhookService() { func newWebhookService() {
WebhookTaskInterval = Cfg.Section("webhook").Key("TASK_INTERVAL").MustInt(1) sec := Cfg.Section("webhook")
WebhookDeliverTimeout = Cfg.Section("webhook").Key("DELIVER_TIMEOUT").MustInt(5) Webhook.TaskInterval = sec.Key("TASK_INTERVAL").MustInt(1)
Webhook.DeliverTimeout = sec.Key("DELIVER_TIMEOUT").MustInt(5)
Webhook.SkipTLSVerify = sec.Key("SKIP_TLS_VERIFY").MustBool()
} }
func NewServices() { func NewServices() {

View File

@ -1066,6 +1066,9 @@ The register and sign-in page style
#repo-header-download-drop .btn > i { #repo-header-download-drop .btn > i {
margin-right: 6px; margin-right: 6px;
} }
#repo-header-download-drop input {
cursor: default;
}
#repo-header-download-drop button, #repo-header-download-drop button,
#repo-header-download-drop input { #repo-header-download-drop input {
font-size: 11px; font-size: 11px;

View File

@ -81,6 +81,9 @@
.btn>i { .btn>i {
margin-right: 6px; margin-right: 6px;
} }
input {
cursor: default;
}
button, input { button, input {
font-size: 11px; font-size: 11px;
} }

View File

@ -188,11 +188,8 @@ func Config(ctx *middleware.Context) {
ctx.Data["ReverseProxyAuthUser"] = setting.ReverseProxyAuthUser ctx.Data["ReverseProxyAuthUser"] = setting.ReverseProxyAuthUser
ctx.Data["Service"] = setting.Service ctx.Data["Service"] = setting.Service
ctx.Data["DbCfg"] = models.DbCfg ctx.Data["DbCfg"] = models.DbCfg
ctx.Data["Webhook"] = setting.Webhook
ctx.Data["WebhookTaskInterval"] = setting.WebhookTaskInterval
ctx.Data["WebhookDeliverTimeout"] = setting.WebhookDeliverTimeout
ctx.Data["MailerEnabled"] = false ctx.Data["MailerEnabled"] = false
if setting.MailService != nil { if setting.MailService != nil {

View File

@ -138,11 +138,8 @@ func TeamsRepoAction(ctx *middleware.Context) {
} }
if err != nil { if err != nil {
log.Error(3, "Action(%s): %v", ctx.Params(":action"), err) log.Error(3, "Action(%s): '%s' %v", ctx.Params(":action"), ctx.Org.Team.Name, err)
ctx.JSON(200, map[string]interface{}{ ctx.Handle(500, "TeamsRepoAction", err)
"ok": false,
"err": err.Error(),
})
return return
} }
ctx.Redirect(ctx.Org.OrgLink + "/teams/" + ctx.Org.Team.LowerName + "/repositories") ctx.Redirect(ctx.Org.OrgLink + "/teams/" + ctx.Org.Team.LowerName + "/repositories")

View File

@ -1 +1 @@
0.5.13.0208 Beta 0.5.13.0211 Beta

View File

@ -102,9 +102,11 @@
<div class="panel-body"> <div class="panel-body">
<dl class="dl-horizontal admin-dl-horizontal"> <dl class="dl-horizontal admin-dl-horizontal">
<dt>{{.i18n.Tr "admin.config.task_interval"}}</dt> <dt>{{.i18n.Tr "admin.config.task_interval"}}</dt>
<dd>{{.WebhookTaskInterval}} {{.i18n.Tr "tool.raw_minutes"}}</dd> <dd>{{.Webhook.TaskInterval}} {{.i18n.Tr "tool.raw_minutes"}}</dd>
<dt>{{.i18n.Tr "admin.config.deliver_timeout"}}</dt> <dt>{{.i18n.Tr "admin.config.deliver_timeout"}}</dt>
<dd>{{.WebhookDeliverTimeout}} {{.i18n.Tr "tool.raw_seconds"}}</dd> <dd>{{.Webhook.DeliverTimeout}} {{.i18n.Tr "tool.raw_seconds"}}</dd>
<dt>{{.i18n.Tr "admin.config.skip_tls_verify"}}</dt>
<dd><i class="fa fa{{if .Webhook.SkipTLSVerify}}-check{{end}}-square-o"></i></dd>
</dl> </dl>
</div> </div>
</div> </div>

View File

@ -1,7 +1,7 @@
</div> </div>
<footer id="footer"> <footer id="footer">
<div class="container clear"> <div class="container clear">
<p class="left" id="footer-rights">© 2014 GoGits · {{.i18n.Tr "version"}}: {{AppVer}} · {{.i18n.Tr "page"}}: <strong>{{LoadTimes .PageStartTime}}</strong> · <p class="left" id="footer-rights">© 2015 GoGits · {{.i18n.Tr "version"}}: {{AppVer}} · {{.i18n.Tr "page"}}: <strong>{{LoadTimes .PageStartTime}}</strong> ·
{{.i18n.Tr "template"}}: <strong>{{call .TmplLoadTimes}}</strong></p> {{.i18n.Tr "template"}}: <strong>{{call .TmplLoadTimes}}</strong></p>
<div class="right" id="footer-links"> <div class="right" id="footer-links">

View File

@ -22,7 +22,7 @@
<button class="btn btn-blue left btn-left-radius" id="repo-clone-ssh" data-link="{{$.CloneLink.SSH}}">SSH</button> <button class="btn btn-blue left btn-left-radius" id="repo-clone-ssh" data-link="{{$.CloneLink.SSH}}">SSH</button>
{{end}} {{end}}
<button class="btn {{if $.DisableSSH}}btn-blue{{else}}btn-gray{{end}} left" id="repo-clone-https" data-link="{{$.CloneLink.HTTPS}}">HTTPS</button> <button class="btn {{if $.DisableSSH}}btn-blue{{else}}btn-gray{{end}} left" id="repo-clone-https" data-link="{{$.CloneLink.HTTPS}}">HTTPS</button>
<input id="repo-clone-url" class="ipt ipt-disabled left" value="{{if $.DisableSSH}}{{$.CloneLink.HTTPS}}{{else}}{{$.CloneLink.SSH}}{{end}}" readonly /> <input id="repo-clone-url" class="ipt ipt-disabled left" value="{{if $.DisableSSH}}{{$.CloneLink.HTTPS}}{{else}}{{$.CloneLink.SSH}}{{end}}" onclick="this.select();" readonly />
<button id="repo-clone-copy" class="btn btn-black left btn-right-radius" data-copy-val="val" data-copy-from="#repo-clone-url" original-title="{{$.i18n.Tr "repo.click_to_copy"}}" data-original-title="{{$.i18n.Tr "repo.click_to_copy"}}" data-after-title="{{$.i18n.Tr "repo.copied"}}">{{$.i18n.Tr "repo.copy_link"}}</button> <button id="repo-clone-copy" class="btn btn-black left btn-right-radius" data-copy-val="val" data-copy-from="#repo-clone-url" original-title="{{$.i18n.Tr "repo.click_to_copy"}}" data-original-title="{{$.i18n.Tr "repo.click_to_copy"}}" data-after-title="{{$.i18n.Tr "repo.copied"}}">{{$.i18n.Tr "repo.copy_link"}}</button>
<p class="text-center" id="repo-clone-help">{{$.i18n.Tr "repo.clone_helper" "http://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository" | Str2html}}</p> <p class="text-center" id="repo-clone-help">{{$.i18n.Tr "repo.clone_helper" "http://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository" | Str2html}}</p>
<hr/> <hr/>