Merge branch 'dev' of github.com:gogits/gogs into access
This commit is contained in:
commit
c5c467a9cd
24 changed files with 120 additions and 95 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,6 +1,7 @@
|
||||||
.DS_Store
|
.DS_Store
|
||||||
*.db
|
*.db
|
||||||
*.log
|
*.log
|
||||||
|
log/
|
||||||
custom/
|
custom/
|
||||||
data/
|
data/
|
||||||
.vendor/
|
.vendor/
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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)))
|
||||||
|
|
||||||
## 系统要求
|
## 系统要求
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
2
gogs.go
2
gogs.go
|
@ -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())
|
||||||
|
|
|
@ -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 (
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
0.5.13.0208 Beta
|
0.5.13.0211 Beta
|
|
@ -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>
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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/>
|
||||||
|
|
Loading…
Reference in a new issue