Compare commits

..

86 Commits

Author SHA1 Message Date
Unknwon
c9e0b3b987 prepare for 0.5.9 2014-12-13 20:32:30 -05:00
Unknwon
28766479a7 update gopmfile 2014-12-13 20:26:04 -05:00
Unknwon
9ac940d31d update locales 2014-12-13 20:06:50 -05:00
Unknwon
b553ea45ee modes/repo: incorrect SSH clone URL for #742 2014-12-13 16:46:00 -05:00
Unknwon
ac4a10456e api: able to create repo and fix #726
- POST /user/repos
- POST /org/:org/repos
2014-12-12 20:30:32 -05:00
Unknwon
2f3a7e53cb fix #735 2014-12-12 01:29:36 -05:00
Unknwon
42c7bb7529 mirror code clean 2014-12-11 18:55:09 -05:00
无闻
35140f1cc7 Merge pull request #731 from cryptix/dev
increase minimum version for HTTPS to TLS 1.0 (POODLE, fixes #730)
2014-12-11 18:32:49 -05:00
Henry
4f4392b83e increase minimum version vor HTTPS to TLS 1.0 (POODLE, fixes #730) 2014-12-11 11:14:41 +01:00
codeskyblue
db6c0ebf76 fix git clone error when repo has upper case name 2014-12-11 15:57:32 +08:00
Unknwon
cf7ebfbdc8 mirror fix on release JS 2014-12-10 16:41:49 -05:00
Unknwon
bc8721fb6c Finish new UI for release page 2014-12-10 16:37:54 -05:00
Unknwon
01ba771783 fix #703 2014-12-10 07:00:11 -05:00
Unknwon
9ee80e3e54 fix compile error 2014-12-10 05:10:26 -05:00
无闻
b2c6a6920f Merge pull request #727 from Mageti/master
Correction for #723
2014-12-10 05:03:50 -05:00
Mageti
e321469884 remove unused code in BasicAuthDecode 2014-12-10 11:01:17 +01:00
Mageti
b7ebbb4064 Correction for #723
Correction for #723
Bug was : decode failed if the password contains ```:```
2014-12-10 10:51:51 +01:00
Unknwon
9a1fe801e5 fix #711 2014-12-09 02:18:25 -05:00
Unknwon
6f71632e3e new language 2014-12-07 19:27:49 -05:00
无闻
2844674587 Merge pull request #720 from Alukardd/dev
Allow send mail without authentication if SMTP server allow this
2014-12-07 16:05:55 -05:00
fuxiaohei
0daef29053 add label-create ui elements 2014-12-07 21:29:37 +08:00
Alukardd
21081836ba Allow send mail without authentication if SMTP server allow this 2014-12-07 16:07:48 +03:00
无闻
a2f6e1803b Merge pull request #718 from jbcrail/fix-comment-spelling
Fix spelling errors in comments.
2014-12-06 21:01:00 -05:00
Joseph Crail
39c068400e Fix spelling errors in comments. 2014-12-06 20:22:48 -05:00
Unknwon
47e7175b80 upload locales 2014-12-05 18:27:59 -05:00
Unknwon
0b785ad967 work on #672 2014-12-05 18:08:09 -05:00
Unknwon
069486d169 fix #165 2014-12-05 17:54:57 -05:00
无闻
298ebc58c1 Merge pull request #716 from ErebusBat/master
Fix Gravatar images in web view (like commit listing)
2014-12-05 16:20:34 -05:00
无闻
3fd41d138c Merge pull request #712 from Dennis-Smurf/enhancement-issuelink-in-commit
Added issue link rendering in commit messages
2014-12-05 16:15:43 -05:00
Andrew Burns
35b02997f8 Fix Gravatar images in web view (like commit listing)
Related to #700

In the original bug report it was referencing only the sytem avatar images for setup users (like in the header); however the problem also persists with things like commit history.

This commit fixes the `tool.AvatarLink` function so that it also uses the already existing `avatar.HashEmail` function.

I also refactored the `tool.AvatarLink` method some to make the control flow more apparent and adhere better to DRY (there were multiple calls to the `EncodeMd5` function that the `HashEmail` function call replaced, now there is only one.)
2014-12-05 11:02:59 -07:00
Andrew Burns
adc1ac689e HashEmail function should also remove spaces
According to the [Gravatar API](https://en.gravatar.com/site/implement/hash/) whitespace should also be removed from the email, it was not doing this previously.
2014-12-05 10:58:49 -07:00
dennis-smurf
528c075ad6 Added issue link rendering in commit messages 2014-12-05 11:02:52 +01:00
Unknwon
e577f2fff3 fix #706 and other mirror improve 2014-12-04 23:07:51 -05:00
无闻
daf96dfae1 Merge pull request #709 from TonyTsangHK/dev
Display multi-line commit message on commit diff page.
2014-12-04 22:36:54 -05:00
Tony Tsang
d4a1d9f82a Display multi-line commit message on commit diff page. 2014-12-05 10:53:37 +08:00
无闻
f7f4ea1dcf Merge pull request #708 from ErebusBat/master
Use the avatar.HashEmail function instead of hashing email directly.
2014-12-04 18:33:10 -05:00
fuxiaohei
0af3a5b603 add issue list filter ui 2014-12-04 23:22:16 +08:00
Andrew Burns
00cf3e4dab Use the avatar.HashEmail function instead of hashing email directly. Fixes #700 2014-12-03 16:19:35 -07:00
无闻
cb6be94358 Merge pull request #696 from deiwin/update/user-api-to-include-full-name
add full name to found users' list on the UI
2014-12-02 10:27:24 -05:00
Deiwin Sarjas
54ef1cee1d add full name to found users' list 2014-12-02 16:55:52 +02:00
无闻
b9999427a8 Merge pull request #694 from deiwin/update/user-api-to-include-full-name
update user api search results to include the full name
2014-12-02 07:50:05 -05:00
无闻
ddeb076890 Merge pull request #695 from CBiX/dev
fixed code view line height for firefox
2014-12-02 07:47:13 -05:00
Florian Hülsmann
d06d58e461 fixed code view line height for firefox 2014-12-02 11:31:57 +01:00
Deiwin Sarjas
48bb0fadc2 update user api search results to include the full name
Is fully backwards compatible
Fixes #677
2014-12-02 11:44:03 +02:00
无闻
cd627ba16e Merge pull request #690 from Dennis-Smurf/feature-sha1-markdown-pattern
Addded sha1 pattern in markdown for current repository
2014-12-01 11:35:18 -05:00
dennis-smurf
d0a80e432d Addded sha1 pattern in markdown for current repository 2014-12-01 09:30:35 +01:00
Unknwon
9558999698 mirror fix 2014-11-30 18:35:05 -05:00
Unknwon
5338808600 fix #676 2014-11-30 18:29:16 -05:00
Unknwon
82da024a4d fix #687 2014-11-30 10:55:26 -05:00
Unknwon
5c866fc737 Merge branch 'dev' of github.com:gogits/gogs into dev 2014-11-30 02:26:33 -05:00
Unknwon
d75013a0e8 fix #580 2014-11-30 02:26:29 -05:00
无闻
1591a37ad5 Merge pull request #686 from willglynn/cert_stub_exit_code
Cert command stub should return a non-zero exit code
2014-11-30 01:38:35 -05:00
Will Glynn
3e528f34af Cert command stub should return a non-zero exit code 2014-11-29 21:52:59 -06:00
Unknwon
b6437b5a4c safe check 2014-11-28 21:54:49 -05:00
Unknwon
db4951bc61 mirror fix on oauth2 2014-11-28 21:38:35 -05:00
Unknwon
d6132aaa88 fix oauth2 2014-11-28 21:20:13 -05:00
无闻
9adc8e9d3f Merge pull request #683 from jcracknell/admin-repos-cols
Fix swapped issue/star columns in /admin/repos
2014-11-28 15:28:08 -05:00
无闻
be54b4bf26 Merge pull request #682 from jcracknell/user-links
Fix user links
2014-11-28 15:22:56 -05:00
James Cracknell
64d90a761b Fix swapped issue/star columns in /admin/repos 2014-11-28 12:40:02 -07:00
James Cracknell
4d123d0a93 Fix user links 2014-11-28 11:53:00 -07:00
Unknwon
5dd8308686 Merge branch 'dev' of github.com:gogits/gogs into dev 2014-11-27 21:36:20 -05:00
Unknwon
9c2120eb34 fix #675 2014-11-27 21:36:12 -05:00
无闻
4f8d888e66 Merge pull request #674 from jcracknell/pfx-export
Added comments documenting how to export SSL keys from .pfx
2014-11-27 16:56:55 -05:00
James Cracknell
ca09a0b516 Added comments documenting how to export SSL keys from .pfx 2014-11-27 14:42:06 -07:00
Unknwon
a43164877c fix #664 2014-11-25 23:05:43 -05:00
Unknwon
515641d033 fix #659 2014-11-25 22:48:04 -05:00
Unknwon
54d25c13d7 Fix #543 2014-11-24 18:47:59 -05:00
fuxiaohei
23d53561d1 update milestone page design 2014-11-24 23:13:42 +08:00
Unknwon
0cce61de3a Merge branch 'dev' of github.com:gogits/gogs into dev 2014-11-24 09:54:22 -05:00
Unknwon
5b96e3fcc7 fix #660 2014-11-24 09:54:08 -05:00
fuxiaohei
79dae254cf add milestone page design 2014-11-24 22:33:04 +08:00
无闻
5b32cdd960 Merge pull request #657 from chai2010/dev
Fix #656
2014-11-23 22:15:25 -05:00
chai2010
f9ad8d6903 Fix #656 2014-11-24 10:58:39 +08:00
Unknwon
1b66600bd0 Fix #652 2014-11-23 02:33:47 -05:00
Unknwon
dc53270da9 Fix 653 2014-11-22 10:22:53 -05:00
Unknwon
8ea7ba3afa fix #644 2014-11-21 13:10:00 -05:00
Unknwon
ef275ebf62 more on change avatar 2014-11-21 12:51:36 -05:00
Unknwon
22ab4fa1b0 fix #139 2014-11-21 11:08:24 -05:00
Unknwon
55dfe2c978 custom avatar upload 2014-11-21 10:58:08 -05:00
Unknwon
3c3f7c2a56 Fix #643 2014-11-20 18:03:42 -05:00
Unknwon
0c92da7e9c fix invalid user links in admin panels 2014-11-19 21:19:37 -05:00
无闻
8fac41768c Merge pull request #639 from pkgr/pkgr
Make postinstall work for CentOS/RHEL packages as well.
2014-11-19 17:27:53 -05:00
Cyril Rohr
c418b83678 Make postinstall work for CentOS/RHEL packages as well. 2014-11-19 21:43:12 +00:00
无闻
b53f6357fc Merge pull request #638 from pkgr/pkgr
Fix packages generated on packager.io
2014-11-19 15:51:00 -05:00
Cyril Rohr
11ca3dedfb Fix .pkgr.yml 2014-11-19 19:18:44 +00:00
Cyril Rohr
f77680520f Link custom app.ini to /etc/gogs/ 2014-11-19 19:18:44 +00:00
104 changed files with 3006 additions and 953 deletions

View File

@@ -8,19 +8,20 @@ github.com/Unknwon/cae = commit:2e70a1351b
github.com/Unknwon/com = commit:2cbcbc6916
github.com/Unknwon/goconfig = commit:0f8d8dc1c0
github.com/Unknwon/i18n = commit:aec5f77857
github.com/Unknwon/macaron = commit:5c8d1b7642
github.com/Unknwon/macaron = commit:3d307c1232
github.com/codegangsta/cli = commit:7381bc4e62
github.com/go-sql-driver/mysql = commit:8111ee3ec3
github.com/go-xorm/core = commit:3e0fa232ab
github.com/go-xorm/xorm = commit:58d33844ce
github.com/gogits/go-gogs-client = commit:3b1d86c3a8
github.com/gogits/go-gogs-client = commit:92e76d616a
github.com/gogits/oauth2 = commit:99cbec870a
github.com/lib/pq = commit:b021d0ef20
github.com/macaron-contrib/binding = commit:0e23661e7d
github.com/macaron-contrib/cache = commit:0bb9e6c9ef
github.com/macaron-contrib/captcha = commit:3567dc48b8
github.com/macaron-contrib/csrf = commit:422b79675c
github.com/macaron-contrib/i18n = commit:2246f45894
github.com/macaron-contrib/i18n = commit:184bb832f2
github.com/macaron-contrib/oauth2 = commit:8f394c3629
github.com/macaron-contrib/session = commit:f00d48fd4f
github.com/macaron-contrib/toolbox = commit:57127bcc89
github.com/mattn/go-sqlite3 = commit:a80c27ba33

View File

@@ -2,10 +2,7 @@ targets:
ubuntu-14.04:
ubuntu-12.04:
debian-7:
centos6:
build_dependencies:
- mercurial
- bzr
centos-6:
dependencies:
- git
before:

View File

@@ -26,6 +26,7 @@ The goal of this project is to make the easiest, fastest and most painless way t
- 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!
- 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)!
## Features
@@ -47,7 +48,7 @@ The goal of this project is to make the easiest, fastest and most painless way t
- Drone CI integration
- Supports MySQL, PostgreSQL and SQLite3
- Social account login(GitHub, Google, QQ, Weibo)
- Multi-language support(English, Simplified Chinese, Traditional Chinese, Germany, French, Dutch, and [more](https://crowdin.com/project/gogs))
- Multi-language support([7 languages](https://crowdin.com/project/gogs))
## System Requirements
@@ -71,14 +72,15 @@ There are 5 ways to install Gogs:
- Router and middleware mechanism of [Macaron](https://github.com/Unknwon/macaron).
- Mail Service, modules design is inspired by [WeTalk](https://github.com/beego/wetalk).
- System Monitor Status is inspired by [GoBlog](https://github.com/fuxiaohei/goblog).
- Usage and modification from [beego](http://beego.me) modules.
- Thanks [lavachen](http://www.lavachen.cn/) and [Rocker](http://weibo.com/rocker1989) for designing Logo.
- Thanks [gobuild.io](http://gobuild.io) for providing binary compile and download service.
- Thanks [Crowdin](https://crowdin.com/project/gogs) for providing open source translation plan.
## Contributors
The [core team](http://gogs.io/team) of this project. See [contributors page](https://github.com/gogits/gogs/graphs/contributors) for full list of contributors.
- The [core team](http://gogs.io/team) of this project.
- See [contributors page](https://github.com/gogits/gogs/graphs/contributors) for full list of contributors.
- See [TRANSLATORS](conf/locale/TRANSLATORS) for full list of translators.
## License

View File

@@ -17,6 +17,7 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
- 您可以到 [Trello Board](https://trello.com/b/uxAoeLUl/gogs-go-git-service) 跟随开发团队的脚步。
- 想要先睹为快?通过 [在线体验](https://try.gogs.io/Unknown/gogs) 或查看 **安装部署 -> 二进制安装** 小节。
- 使用过程中遇到问题?尝试从 [故障排查](http://gogs.io/docs/intro/troubleshooting.md) 页面获取帮助。
- 希望帮助多国语言界面的翻译吗?请立即访问 [Crowdin](https://crowdin.com/project/gogs)
## 功能特性
@@ -38,7 +39,7 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
- Drone CI 持续部署集成
- 支持 MySQL、PostgreSQL 以及 SQLite3 数据库
- 社交帐号登录GitHub、Google、QQ、微博
- 多语言支持(英文、简体中文、繁体中文、德语、法语、荷兰语以及 [更多]([more](https://crowdin.com/project/gogs))
- 多语言支持([7 种语言]([more](https://crowdin.com/project/gogs))
## 系统要求
@@ -59,8 +60,7 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
## 特别鸣谢
- [Macaron](https://github.com/Unknwon/macaron) 的路由与中间件机制。
- [beego](http://beego.me) 模块的使用与修改。
- 基于 [Macaron](https://github.com/Unknwon/macaron) 的路由与中间件机制。
- 基于 [WeTalk](https://github.com/beego/wetalk) 修改的邮件服务和模块设计。
- 基于 [GoBlog](https://github.com/fuxiaohei/goblog) 修改的系统监视状态。
- 感谢 [gobuild.io](http://gobuild.io) 提供二进制编译与下载服务。
@@ -69,7 +69,9 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
## 贡献成员
本项目的 [开发团队](http://gogs.io/team)。您可以通过查看 [贡献者页面](https://github.com/gogits/gogs/graphs/contributors) 获取完整的贡献者列表。
- 本项目的 [开发团队](http://gogs.io/team)。
- 您可以通过查看 [贡献者页面](https://github.com/gogits/gogs/graphs/contributors) 获取完整的贡献者列表。
- 您可以通过查看 [TRANSLATORS](conf/locale/TRANSLATORS) 文件获取完整的翻译人员列表。
## 授权许可

View File

@@ -8,6 +8,7 @@ package cmd
import (
"fmt"
"os"
"time"
"github.com/codegangsta/cli"
@@ -31,4 +32,5 @@ Outputs to 'cert.pem' and 'key.pem' and will overwrite existing files.`,
func runCert(ctx *cli.Context) {
fmt.Println("Command cert not available, please use build tags 'cert' to rebuild.")
os.Exit(1)
}

View File

@@ -58,7 +58,7 @@ func runDump(ctx *cli.Context) {
workDir, _ := setting.WorkDir()
z.AddFile("gogs-repo.zip", path.Join(workDir, "gogs-repo.zip"))
z.AddFile("gogs-db.sql", path.Join(workDir, "gogs-db.sql"))
z.AddFile("custom/conf/app.ini", path.Join(workDir, "custom/conf/app.ini"))
z.AddDir("custom", path.Join(workDir, "custom"))
z.AddDir("log", path.Join(workDir, "log"))
// FIXME: SSH key file.
if err = z.Close(); err != nil {

View File

@@ -14,6 +14,7 @@ import (
"runtime"
"strings"
"github.com/Unknwon/com"
"github.com/codegangsta/cli"
"github.com/gogits/gogs/models"
@@ -164,10 +165,12 @@ func runFixLocation(ctx *cli.Context) {
// Fix in authorized_keys file.
sshPath := path.Join(models.SshPath, "authorized_keys")
fmt.Printf("Fixing pathes in file: %s\n", sshPath)
if err := rewriteAuthorizedKeys(sshPath, oldPath, execPath); err != nil {
fmt.Println(err)
os.Exit(1)
if com.IsFile(sshPath) {
fmt.Printf("Fixing pathes in file: %s\n", sshPath)
if err := rewriteAuthorizedKeys(sshPath, oldPath, execPath); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
// Fix position in gogs-repositories.

View File

@@ -164,7 +164,7 @@ func runServ(k *cli.Context) {
log.GitLogger.Fatal(2, "User %s has no right to read repository %s", user.Name, repoPath)
}
default:
println("Unknown command")
println("Unknown command: " + cmd)
return
}

View File

@@ -5,6 +5,7 @@
package cmd
import (
"crypto/tls"
"fmt"
"html/template"
"io/ioutil"
@@ -21,9 +22,12 @@ import (
"github.com/macaron-contrib/captcha"
"github.com/macaron-contrib/csrf"
"github.com/macaron-contrib/i18n"
"github.com/macaron-contrib/oauth2"
"github.com/macaron-contrib/session"
"github.com/macaron-contrib/toolbox"
api "github.com/gogits/go-gogs-client"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/auth"
"github.com/gogits/gogs/modules/auth/apiv1"
@@ -64,7 +68,7 @@ func checkVersion() {
// Check dependency version.
macaronVer := git.MustParseVersion(strings.Join(strings.Split(macaron.Version(), ".")[:3], "."))
if macaronVer.LessThan(git.MustParseVersion("0.4.2")) {
if macaronVer.LessThan(git.MustParseVersion("0.4.7")) {
log.Fatal(4, "Package macaron version is too old, did you forget to update?(github.com/Unknwon/macaron)")
}
i18nVer := git.MustParseVersion(i18n.Version())
@@ -94,6 +98,13 @@ func newMacaron() *macaron.Macaron {
SkipLogging: !setting.DisableRouterLog,
},
))
m.Use(macaron.Static(
setting.AvatarUploadPath,
macaron.StaticOptions{
Prefix: "avatars",
SkipLogging: !setting.DisableRouterLog,
},
))
m.Use(macaron.Renderer(macaron.RenderOptions{
Directory: path.Join(setting.StaticRootPath, "templates"),
Funcs: []template.FuncMap{base.TemplateFuncs},
@@ -133,6 +144,13 @@ func newMacaron() *macaron.Macaron {
},
},
}))
// OAuth 2.
if setting.OauthService != nil {
for _, info := range setting.OauthService.OauthInfos {
m.Use(oauth2.NewOAuth2Provider(info.Options, info.AuthUrl, info.TokenUrl))
}
}
m.Use(middleware.Contexter())
return m
}
@@ -154,6 +172,7 @@ func runWeb(*cli.Context) {
// Routers.
m.Get("/", ignSignIn, routers.Home)
m.Get("/explore", ignSignIn, routers.Explore)
// FIXME: when i'm binding form here???
m.Get("/install", bindIgnErr(auth.InstallForm{}), routers.Install)
m.Post("/install", bindIgnErr(auth.InstallForm{}), routers.InstallPost)
m.Group("", func() {
@@ -183,14 +202,15 @@ func runWeb(*cli.Context) {
})
// Repositories.
m.Get("/user/repos", middleware.ApiReqToken(), v1.ListMyRepos)
m.Combo("/user/repos", middleware.ApiReqToken()).Get(v1.ListMyRepos).Post(bind(api.CreateRepoOption{}), v1.CreateRepo)
m.Post("/org/:org/repos", middleware.ApiReqToken(), bind(api.CreateRepoOption{}), v1.CreateOrgRepo)
m.Group("/repos", func() {
m.Get("/search", v1.SearchRepos)
m.Post("/migrate", bindIgnErr(auth.MigrateRepoForm{}), v1.Migrate)
m.Post("/migrate", bindIgnErr(auth.MigrateRepoForm{}), v1.MigrateRepo)
m.Group("/:username/:reponame", func() {
m.Combo("/hooks").Get(v1.ListRepoHooks).Post(bind(v1.CreateRepoHookForm{}), v1.CreateRepoHook)
m.Patch("/hooks/:id:int", bind(v1.EditRepoHookForm{}), v1.EditRepoHook)
m.Combo("/hooks").Get(v1.ListRepoHooks).Post(bind(api.CreateHookOption{}), v1.CreateRepoHook)
m.Patch("/hooks/:id:int", bind(api.EditHookOption{}), v1.EditRepoHook)
m.Get("/raw/*", middleware.RepoRef(), v1.GetRepoRawFile)
}, middleware.ApiRepoAssignment(), middleware.ApiReqToken())
})
@@ -205,7 +225,7 @@ func runWeb(*cli.Context) {
m.Group("/user", func() {
m.Get("/login", user.SignIn)
m.Post("/login", bindIgnErr(auth.SignInForm{}), user.SignInPost)
m.Get("/login/:name", user.SocialSignIn)
m.Get("/info/:name", user.SocialSignIn)
m.Get("/sign_up", user.SignUp)
m.Post("/sign_up", bindIgnErr(auth.RegisterForm{}), user.SignUpPost)
m.Get("/reset_password", user.ResetPasswd)
@@ -214,6 +234,7 @@ func runWeb(*cli.Context) {
m.Group("/user/settings", func() {
m.Get("", user.Settings)
m.Post("", bindIgnErr(auth.UpdateProfileForm{}), user.SettingsPost)
m.Post("/avatar", binding.MultipartForm(auth.UploadAvatarForm{}), user.SettingsAvatar)
m.Get("/password", user.SettingsPassword)
m.Post("/password", bindIgnErr(auth.ChangePasswordForm{}), user.SettingsPasswordPost)
m.Get("/ssh", user.SettingsSSHKeys)
@@ -380,14 +401,17 @@ func runWeb(*cli.Context) {
})
m.Post("/comment/:action", repo.Comment)
m.Get("/releases/new", repo.NewRelease)
m.Post("/releases/new", bindIgnErr(auth.NewReleaseForm{}), repo.NewReleasePost)
m.Get("/releases/edit/:tagname", repo.EditRelease)
m.Post("/releases/edit/:tagname", bindIgnErr(auth.EditReleaseForm{}), repo.EditReleasePost)
m.Group("/releases", func() {
m.Get("/new", repo.NewRelease)
m.Post("/new", bindIgnErr(auth.NewReleaseForm{}), repo.NewReleasePost)
m.Get("/edit/:tagname", repo.EditRelease)
m.Post("/edit/:tagname", bindIgnErr(auth.EditReleaseForm{}), repo.EditReleasePost)
}, middleware.RepoRef())
}, reqSignIn, middleware.RepoAssignment(true))
m.Group("/:username/:reponame", func() {
m.Get("/releases", repo.Releases)
m.Get("/releases", middleware.RepoRef(), repo.Releases)
m.Get("/issues", repo.Issues)
m.Get("/issues/:index", repo.ViewIssue)
m.Get("/issues/milestones", repo.Milestones)
@@ -397,6 +421,7 @@ func runWeb(*cli.Context) {
m.Get("/issues2/", repo.Issues2)
m.Get("/pulls2/", repo.PullRequest2)
m.Get("/labels2/", repo.Labels2)
m.Get("/milestone2/", repo.Milestones2)
m.Group("", func() {
m.Get("/src/*", repo.Home)
@@ -432,7 +457,8 @@ func runWeb(*cli.Context) {
case setting.HTTP:
err = http.ListenAndServe(listenAddr, m)
case setting.HTTPS:
err = http.ListenAndServeTLS(listenAddr, setting.CertFile, setting.KeyFile, m)
server := &http.Server{Addr: listenAddr, TLSConfig: &tls.Config{MinVersion: tls.VersionTLS10}, Handler: m}
err = server.ListenAndServeTLS(setting.CertFile, setting.KeyFile)
case setting.FCGI:
err = fcgi.Serve(nil, m)
default:

View File

@@ -22,6 +22,11 @@ DISABLE_ROUTER_LOG = false
; Generate steps:
; $ cd path/to/gogs/custom/https
; $ ./gogs cert -ca=true -duration=8760h0m0s -host=myhost.example.com
;
; Or from a .pfx file exported from the Windows certificate store (do
; not forget to export the private key):
; $ openssl pkcs12 -in cert.pfx -out cert.pem -nokeys
; $ openssl pkcs12 -in cert.pfx -out key.pem -nocerts -nodes
CERT_FILE = custom/https/cert.pem
KEY_FILE = custom/https/key.pem
; Upper level of template and static file path
@@ -29,6 +34,8 @@ KEY_FILE = custom/https/key.pem
STATIC_ROOT_PATH =
; Application level GZIP support
ENABLE_GZIP = false
; Landing page for non-logged users, can be "home" or "explore"
LANDING_PAGE = home
[database]
; Either "mysql", "postgres" or "sqlite3", it's your choice
@@ -70,6 +77,7 @@ ENABLE_CACHE_AVATAR = false
ENABLE_NOTIFY_MAIL = false
; More detail: https://github.com/gogits/gogs/issues/165
ENABLE_REVERSE_PROXY_AUTHENTICATION = false
ENABLE_REVERSE_PROXY_AUTO_REGISTERATION = false
[webhook]
; Cron task interval in minutes
@@ -118,13 +126,10 @@ TOKEN_URL = https://accounts.google.com/o/oauth2/token
ENABLED = false
CLIENT_ID =
CLIENT_SECRET =
SCOPES = all
SCOPES = get_user_info
; QQ 互联
; AUTH_URL = https://graph.qq.com/oauth2.0/authorize
; TOKEN_URL = https://graph.qq.com/oauth2.0/token
; Tencent weibo
AUTH_URL = https://open.t.qq.com/cgi-bin/oauth2/authorize
TOKEN_URL = https://open.t.qq.com/cgi-bin/oauth2/access_token
AUTH_URL = https://graph.qq.com/oauth2.0/authorize
TOKEN_URL = https://graph.qq.com/oauth2.0/token
[oauth.weibo]
ENABLED = false
@@ -167,6 +172,7 @@ SESSION_LIFE_TIME = 86400
[picture]
; The place to picture data, either "server" or "qiniu", default is "server"
SERVICE = server
AVATAR_UPLOAD_PATH = data/avatars
; Chinese users can choose "duoshuo"
GRAVATAR_SOURCE = gravatar
DISABLE_GRAVATAR = false
@@ -252,7 +258,13 @@ CONN =
[git]
MAX_GITDIFF_LINES = 10000
; Arguments for command 'git fsck', e.g.: "--unreachable --tags"
; see more on http://git-scm.com/docs/git-fsck/1.7.5
FSCK_ARGS =
; Arguments for command 'git gc', e.g.: "--aggressive --auto"
; see more on http://git-scm.com/docs/git-gc/1.7.5
GC_ARGS =
[i18n]
LANGS = en-US,zh-CN,zh-HK,de-DE,fr-CA,nl-NL
NAMES = English,简体中文,繁體中文,Deutsch,Français,Nederlands
LANGS = en-US,zh-CN,zh-HK,de-DE,fr-CA,nl-NL,lv-LV
NAMES = English,简体中文,繁體中文,Deutsch,Français,Nederlands,Latviešu

6
conf/locale/TRANSLATORS Normal file
View File

@@ -0,0 +1,6 @@
# This file lists all PUBLIC individuals having contributed content to the translation.
# Order of name is meaningless.
Thomas Fanninger <gogs.thomas@fanninger.at>
Łukasz Jan Niemier <lukasz@niemier.pl>
Lafriks <lafriks@gmail.com>

View File

@@ -164,7 +164,7 @@ unable_verify_ssh_key=Gogs kann deinen SSH-Schlüssel nicht verifizieren, nimmt
auth_failed=Authentifizierung fehlgeschlagen: %v
still_own_repo=Dein Konto besitzt noch Repositorys. Diese müssen zuerst gelöscht oder übertragen werden.
still_has_org=Ihr Konto noch Mitgliedschaft in der Organisation, Sie nach links oder löschen Sie sie zuerst.
still_has_org=Du bist noch Mitglied einer Organisation, bitte lösche zunächst diese Mitgliedschaft.
org_still_own_repo=Diese Organisation besitzt noch Repositorys. Diese müssen zuerst gelöscht oder übertragen werden.
still_own_user=Diese Authentifizierung wird noch von einigen Benutzern genutzt. Entferne diese zuvor und lösche erneut.
@@ -173,6 +173,7 @@ target_branch_not_exist=Ziel-Branch existiert nicht
[user]
change_avatar=Ändere dein Profilbild auf gravatar.com
change_custom_avatar=Ändere deinen Avatar in den Einstellungen
join_on=Registriert
repositories=Repositorys
activity=Öffentliche Aktivität
@@ -202,6 +203,14 @@ change_username_desc=Benutzername wurde geändert, möchtest du fortfahren? Dies
continue=Weiter
cancel=Abbrechen
enable_custom_avatar=Aktiviere benuztzerdefinierten Avatar
enable_custom_avatar_helper=Aktiviere dies, um deinen Avatar nicht von Gravatar zu laden
choose_new_avatar=Neuen Avatar auswählen
update_avatar=Avatar-Einstellung aktualisieren
uploaded_avatar_not_a_image=Die hochgeladene Datei ist kein Bild.
no_custom_avatar_available=Kein benutzerdefinierter Avatar verfügbar, Aktivierung ist nicht möglich.
update_avatar_success=Deine Avatar-Einstellung wurde aktualisiert.
change_password=Passwort ändern
old_password=Aktuelles Passwort
new_password=Neues Passwort
@@ -368,6 +377,30 @@ diff.stats_desc=<strong> %d geänderte Dateien</strong> mit <strong>%d neuen Zei
diff.bin=BIN
diff.view_file=Datei anzeigen
release.releases=Releases
release.new_release=Neues Release
release.draft=Entwurf
release.prerelease=Pre-Release
release.stable=Endversion
release.edit=bearbeiten
release.ahead=<strong>%d</strong> Commits zu %s seit diesem Release
release.source_code=Quelltext
release.tag_name=Tag-Name
release.target=Ziel
release.tag_helper=Wähle ein neues Tag oder erstelle ein Tag beim Veröffentlichen.
release.release_title=Release-Titel
release.content_with_md=Inhalt mit <a href="%s">Markdown</a>
release.write=Schreiben
release.preview=Vorschau
release.content_placeholder=Schreibe hier etwas
release.loading=Laden…
release.prerelease_desc=Dies ist eine Pre-Release-Version
release.prerelease_helper=Wir möchten darauf hinweisen, dass dieses Release nicht für den produktiven Einsatz gedacht ist.
release.publish=Release veröffentlichen
release.save_draft=Entwurf speichern
release.edit_release=Release bearbeiten
release.tag_name_already_exist=Ein Release mit diesem Tag existiert bereits.
[org]
org_name_holder=Name der Organisation
org_name_helper=Gute Namen von Organisationen sind kurz und einprägsam.
@@ -462,11 +495,13 @@ dashboard.operation_name=Name der Operation
dashboard.operation_switch=Switch
dashboard.operation_run=Ausführen
dashboard.clean_unbind_oauth=ungebundene OAuths bereinigen
dashboard.clean_unbind_oauth_success=Alle aufheben OAuthes erfolgreich gelöscht wurden.
dashboard.clean_unbind_oauth_success=Alle ungebundenen OAuth-Tokens wurden gelöscht.
dashboard.delete_inactivate_accounts=inaktive Konten löschen
dashboard.delete_inactivate_accounts_success=Alle inaktive Konten erfolgreich gelöscht wurden.
dashboard.delete_repo_archives=Alle Repositories Archive löschen
dashboard.delete_repo_archives_success=Alle Repositories Archive wurden erfolgreich gelöscht.
dashboard.delete_inactivate_accounts_success=Alle inaktiven Konten wurden erfolgreich gelöscht.
dashboard.delete_repo_archives=Alle Repository-Archive löschen
dashboard.delete_repo_archives_success=Alle Repositoriy-Archive wurden gelöscht.
dashboard.git_gc_repos=Führe Garbage Collection auf Repositories aus
dashboard.git_gc_repos_success=Garbage Collection wurde auf allen Repositories erfolgreich ausgeführt.
dashboard.server_uptime=Server-Uptime
dashboard.current_goroutine=Aktuelle Goroutines
dashboard.current_memory_usage=Aktuelle Speichernutzung
@@ -512,11 +547,11 @@ users.update_profile_success=Kontoprofil aktualisiert
users.edit_account=Konto bearbeiten
users.is_activated=Dieses Konto ist aktiviert
users.is_admin=Dieses Konto hat Administratorrechte
users.allow_git_hook=Dieses Konto verfügt über Berechtigungen zum Erstellen von Git hooks
users.allow_git_hook=Dieses Konto ist berechtigt, Git-Hooks zu erstellen
users.update_profile=Kontoprofil aktualisieren
users.delete_account=Dieses Konto löschen
users.still_own_repo=Dieses Konto besitzt noch Repositorys. Diese müssen zuerst gelöscht oder übertragen werden.
users.still_has_org=Dieses Konto noch Mitgliedschaft in der Organisation, Sie nach links oder löschen Sie sie zuerst.
users.still_has_org=Dieses Konto ist noch Mitglied einer Organisation, bitte entferne diese Mitgliedschaft zuerst.
orgs.org_manage_panel=Organisationenverwaltung
orgs.name=Name

View File

@@ -173,6 +173,7 @@ target_branch_not_exist = Target branch does not exist
[user]
change_avatar = Change your avatar at gravatar.com
change_custom_avatar = Change your avatar in settings
join_on = Joined on
repositories = Repositories
activity = Public Activity
@@ -202,6 +203,14 @@ change_username_desc = Username has been changed, do you want to continue? This
continue = Continue
cancel = Cancel
enable_custom_avatar = Enable Custom Avatar
enable_custom_avatar_helper = Enable this to disable fetch from Gravatar
choose_new_avatar = Choose new avatar
update_avatar = Update Avatar Setting
uploaded_avatar_not_a_image = Uploaded file is not a image.
no_custom_avatar_available = No custom avatar available, cannot enable it.
update_avatar_success = Your avatar setting has been updated successfully.
change_password = Change Password
old_password = Current Password
new_password = New Password
@@ -368,6 +377,30 @@ diff.stats_desc = <strong> %d changed files</strong> with <strong>%d additions</
diff.bin = BIN
diff.view_file = View File
release.releases = Releases
release.new_release = New Release
release.draft = Draft
release.prerelease = Pre-Release
release.stable = Stable
release.edit = edit
release.ahead = <strong>%d</strong> commits to %s since this release
release.source_code = Source Code
release.tag_name = Tag name
release.target = Target
release.tag_helper = Choose an existing tag, or create a new tag on publish.
release.release_title = Release title
release.content_with_md = Content with <a href="%s">Markdown</a>
release.write = Write
release.preview = Preview
release.content_placeholder = Write some content
release.loading = Loading...
release.prerelease_desc = This is a pre-release
release.prerelease_helper = Well point out that this release is identified as non-production ready.
release.publish = Publish Release
release.save_draft = Save Draft
release.edit_release = Edit Release
release.tag_name_already_exist = Release with this tag name has already existed.
[org]
org_name_holder = Organization Name
org_name_helper = Great organization names are short and memorable.
@@ -467,6 +500,8 @@ dashboard.delete_inactivate_accounts = Delete all inactive accounts
dashboard.delete_inactivate_accounts_success = All inactivate accounts have been deleted successfully.
dashboard.delete_repo_archives = Delete all repositories archives
dashboard.delete_repo_archives_success = All repositories archives have been deleted successfully.
dashboard.git_gc_repos = Do garbage collection on repositories
dashboard.git_gc_repos_success = All repositories have done garbage collection successfully.
dashboard.server_uptime = Server Uptime
dashboard.current_goroutine = Current Goroutines
dashboard.current_memory_usage = Current Memory Usage

View File

@@ -173,6 +173,7 @@ target_branch_not_exist=Branche cible n'existe pas
[user]
change_avatar=Changez d'avatar via gravatar.com
change_custom_avatar=Changer de vignette dans les réglages
join_on=Adhéré le
repositories=Référentiels
activity=Activités publiques
@@ -202,6 +203,14 @@ change_username_desc=Nom d'utilisateur modifié. Cela affecte tous les liens rel
continue=Continuer
cancel=Annuler
enable_custom_avatar=Permettre vignette personnalisée
enable_custom_avatar_helper=Cette option désactive l'affichage via Gravatar
choose_new_avatar=Choisir nouvelle vignette
update_avatar=Réglage de mise à jour de vignette
uploaded_avatar_not_a_image=Le fichier téléchargé n'est pas une image.
no_custom_avatar_available=Aucun avatar personnalisé disponible, activation impossible.
update_avatar_success=La mise à jour de votre vignette a réussi.
change_password=Modifier le Mot de Passe
old_password=Mot de Passe actuel
new_password=Nouveau Mot de Passe
@@ -368,6 +377,30 @@ diff.stats_desc=<strong> %d fichiers modifiés</strong> avec <strong>%d ajouts</
diff.bin=BIN
diff.view_file=Voir le fichier
release.releases=Releases
release.new_release=New Release
release.draft=Draft
release.prerelease=Pre-Release
release.stable=Stable
release.edit=edit
release.ahead=<strong>%d</strong> commits to %s since this release
release.source_code=Source Code
release.tag_name=Tag name
release.target=Target
release.tag_helper=Choose an existing tag, or create a new tag on publish.
release.release_title=Release title
release.content_with_md=Content with <a href="%s">Markdown</a>
release.write=Write
release.preview=Preview
release.content_placeholder=Write some content
release.loading=Loading...
release.prerelease_desc=This is a pre-release
release.prerelease_helper=Well point out that this release is identified as non-production ready.
release.publish=Publish Release
release.save_draft=Save Draft
release.edit_release=Edit Release
release.tag_name_already_exist=Release with this tag name has already existed.
[org]
org_name_holder=Nom d'organisation
org_name_helper=Idéalement, un nom d'organisation devrait être court et mémorable.
@@ -467,6 +500,8 @@ dashboard.delete_inactivate_accounts=Supprimer tous les comptes inactifs
dashboard.delete_inactivate_accounts_success=Inactivent tous les comptes ont été supprimés avec succès.
dashboard.delete_repo_archives=Supprimer toutes les archives de référentiels
dashboard.delete_repo_archives_success=Toutes les archives de référentiels ont été supprimés avec succès.
dashboard.git_gc_repos=Collecter les déchets des référentiels
dashboard.git_gc_repos_success=Tous les référentiels ont effectué la collecte avec succès.
dashboard.server_uptime=Durée de Marche Serveur
dashboard.current_goroutine=Goroutines actuelles
dashboard.current_memory_usage=Utilisation Mémoire actuelle

718
conf/locale/locale_lv-LV.ini Executable file
View File

@@ -0,0 +1,718 @@
app_desc=Viegli uzstādāms Git serviss, kas rakstīts valodā Go
home=Sākums
dashboard=Infopanelis
explore=Izpētīt
help=Palīdzība
sign_in=Pierakstīties
social_sign_in=Sociālā pieteikšanās: 2. solis <small>piesaistīt kontu</small>
sign_out=Izrakstīties
sign_up=Pieteikties
register=Reģistrēties
website=Mājas lapa
version=Versija
page=Lapa
template=Sagatave
language=Valoda
username=Lietotājvārds
email=E-pasts
password=Parole
re_type=Parole atkārtoti
captcha=Pārbaudes kods
repository=Repozitorijs
organization=Organizācija
mirror=Spogulis
new_repo=Jauns repozitorijs
new_migrate=Jauna migrācija
new_fork=Jauns atdalītais repozitorijs
new_org=Jauna organizācija
manage_org=Pārvaldīt organizācijas
admin_panel=Admin panelis
account_settings=Konta iestatījumi
settings=Iestatījumi
news_feed=Jaunumu plūsma
pull_requests=Izmaiņu pieprasījumi
issues=Problēmas
cancel=Atcelt
[install]
install=Instalācija
title=Instalācijas soļi pirmo reizi palaižot
requite_db_desc=Gogs ir nepieciešama MySQL, PostgreSQL vai SQLite3 datu bāze.
db_type=Datu bāzes veids
host=Resursdators
user=Lietotājs
password=Parole
db_name=Datu bāzes nosaukums
db_helper=Nepieciešams izmantot MySQL INNODB dzini ar rakstzīmju kopu utf8_general_ci.
ssl_mode=SSL režīms
path=Ceļš
sqlite_helper=SQLite 3 datu bāzes faila atrašanās vieta.
general_title=Gogs vispārīgie iestatījumi
repo_path=Repozitoriju glabāšanas vieta
repo_path_helper=Visi Git attālinātie repozitoriji tiks glabāti šajā direktorijā.
run_user=Izpildes lietotājs
run_user_helper=Lietotājam ir jābūt rakstīšanas tiesībām repozitorija saknes direktorijai un Gogs jābūt palaistam zem šī lietotāja.
domain=Domēns
domain_helper=Tas ietekmē SSH klonēšanas URL.
app_url=Lietotnes URL
app_url_helper=Tas ietekmē HTTP/HTTPS klonēšanas URL un e-pasta saturā izsūtītās saites.
email_title=E-pasta pakalpojuma iestatījumi (neobligāti)
smtp_host=SMTP resursdators
mailer_user=Sūtītāja e-pasta adrese
mailer_password=Sūtītāja parole
notify_title=Paziņojumu iestatījumi (neobligāti)
register_confirm=Iespējot reģistrēšanās apstiprināšanu
mail_notify=Iespējot e-pasta paziņojumus
admin_title=Admin konta iestatījumi
admin_name=Lietotājvārds
admin_password=Parole
confirm_password=Apstipriniet paroli
admin_email=E-pasts
install_gogs=Instalēt Gogs
test_git_failed=Kļūda pārbaudot 'git' komandu: %v
sqlite3_not_available=Jūsu versija neatbalsta SQLite3, lūdzu lejupielādējiet oficiālo bināro versiju no %s, NEVIS gobuild versiju.
invalid_db_setting=Datu bāzes iestatījums nav pareizs: %v
invalid_repo_path=Repozitorija atrašanās vieta ir nekorekta: %v
run_user_not_match=Izpildes lietotājs nav pašreizējais lietotājs: %s -> %s
save_config_failed=Neizdevās saglabāt konfigurāciju: %v
invalid_admin_setting=Nekorekts admin konta iestatījums: %v
install_success=Laipni lūdzam! Mēs priecājamies, ka Jūs izvēlaties Gogs, patīkamu lietošanu!
[home]
uname_holder=Lietotājvārds vai e-pasts
password_holder=Parole
switch_dashboard_context=Mainīt infopaneļa kontekstu
my_repos=Mani repozitoriji
collaborative_repos=Sadarbības repozitoriji
my_orgs=Manas organizācijas
my_mirrors=Mani spoguļi
[explore]
repos=Repozitoriji
[auth]
create_new_account=Izveidot jaunu kontu
register_hepler_msg=Jau ir konts? Pieraksties tagad!
social_register_hepler_msg=Jau ir konts? Sasaisti tagad!
disable_register_prompt=Atvainojiet, reģistrācija ir atspējota. Lūdzu, sazinieties ar vietnes administratoru.
disable_register_mail=Atvainojiet, reģistrācijas e-pasta apstiprināšana ir atspējota.
remember_me=Atcerēties mani
forgot_password=Aizmirsu paroli
forget_password=Aizmirsi paroli?
sign_up_now=Nepieciešams konts? Reģistrējies tagad.
confirmation_mail_sent_prompt=Jauns apstiprināšanas e-pasts ir nosūtīts uz <b>%s</b>, lūdzu, pārbaudies savu e-pasta kontu tuvāko %d stundu laikā, lai pabeigtu reģistrācijas procesu.
sign_in_email=Atvērt savu e-pasta kontu
active_your_account=Aktivizēt savu kontu
resent_limit_prompt=Atvainojiet, Jūs sūtījāt aktivizācijas e-pastu pārāk bieži. Lūdzu, gaidiet 3 minūtes.
has_unconfirmed_mail=Sveiki %s, Jums ir neapstiprināta e-pasta adrese (<b>%s</b>). Ja neesat saņēmis apstiprināšanas e-pastu vai Jums ir nepieciešams nosūtīt jaunu, lūdzu, nospiediet pogu, kas atrodas zemāk.
resend_mail=Nospiediet šeit, lai vēlreiz nosūtītu aktivizācijas e-pastu
email_not_associate=Šī e-pasta adrese nav saistīta ar Jūsu kontu.
send_reset_mail=Spiediet šeit, lai nosūtītu paroles maiņas vēstuli uz Jūsu e-pastu
reset_password=Atjaunot savu paroli
invalid_code=Atvainojiet, Jūsu apstiprināšanas kodam ir beidzies derīguma termiņš vai arī tas ir nepareizs.
reset_password_helper=Nospiediet šeit, lai atjaunotu paroli
password_too_short=Paroles garums nedrīkst būt mazāks par 6.
[form]
UserName=Lietotājvārds
RepoName=Repozitorija nosaukums
Email=E-pasta adrese
Password=Parole
Retype=Parole atkārtoti
SSHTitle=SSH atslēgas nosaukums
HttpsUrl=HTTPS URL
PayloadUrl=Vērtuma URL
TeamName=Komandas nosaukums
AuthName=Autorizācijas nosaukums
AdminEmail=Admin e-pasta adrese
require_error=` nedrīkst būt tukšs.`
alpha_dash_error=` drīkst saturēt tikai latīņu alfabēta burtus, ciparus vai domuzīmes (-_).`
alpha_dash_dot_error=` drīkst saturēt tikai latīņu alfabēta burtus, ciparus, domuzīmes (-_) vai punktu.`
min_size_error=` jabūt vismaz %s simbolu garumā.`
max_size_error=` jabūt ne mazāk kā %s simbolu garumā.`
email_error=` nav derīga e-pasta adrese.`
url_error=` nav korekts URL.`
unknown_error=Nezināma kļūda:
captcha_incorrect=Pārbaudes kods nesakrīt ar attēlā redzamo.
password_not_match=Parole un atkārtoti ievadītā parole nav vienādas.
username_been_taken=Lietotājvārds ir jau aizņemts.
repo_name_been_taken=Repozitorija vārds ir jau aizņemts.
org_name_been_taken=Organizācijas nosaukums ir jau aizņemts.
team_name_been_taken=Komandas nosaukums ir jau aizņemts.
email_been_used=E-pasta adrese jau tiek izmantota.
ssh_key_been_used=Publiskās atslēgas nosaukums jau tiek izmantos.
illegal_username=Jūsu lietotājvārds satur neatļautas rakstzīmes.
illegal_repo_name=Krātuves nosaukums satur neatļautas rakstzīmes.
illegal_org_name=Organizācijas nosaukums satur neatļautas rakstzīmes.
illegal_team_name=Grupas nosaukums satur neatļautas rakstzīmes.
username_password_incorrect=Lietotājvārds vai parole nav pareiza.
enterred_invalid_repo_name=Lūdzu, pārliecinieties, vai ievadītā repozitorija nosaukums ir pareizs.
enterred_invalid_owner_name=Lūdzu, pārliecinieties, vai ievadītā īpašnieka vārds ir pareizs.
enterred_invalid_password=Lūdzu pārliecinieties, vai Jūsu ievadītā parole ir pareiza.
user_not_exist=Šāds lietotājs neeksistē.
last_org_owner=Nav iespējams noņemt vienīgo komandas īpašnieku. Pirms tam ir nepieciešams norādīt jauno īpašnieku.
invalid_ssh_key=Atvainojiet, nav iespējams pārbaudīt Jūsu SSH atslēgu: %s
unable_verify_ssh_key=Nav iespējams pārbaudīt jūsu SSH atslēgu, bet tiks pieņemts, ka tā ir derīga, lūdzu, pārliecinieties par to pats.
auth_failed=Autentifikācija neizdevās: %v
still_own_repo=Jūsu esat vismaz viena repozitorija īpašnieks, tos sākumā ir nepieciešams izdzēst vai nomainīt to īpašnieku.
still_has_org=Jūsu esat vismaz vienas organizācijas biedrs, sākumā nepieciešams pamest vai izdzēst šo organizāciju.
org_still_own_repo=Šī organizācija ir vismaz viena repozitorija īpašnieks, tos sākumā ir nepieciešams izdzēst vai nomainīt to īpašnieku.
still_own_user=Šo autentifikāciju joprojām izmanto vismaz viens lietotājs, nepieciešams šiem lietotājiem nomainīt autentifikācijas veidu vai tos izdzēst.
target_branch_not_exist=Mērķa atzars neeksistē
[user]
change_avatar=Mainīt savu profila attēlu vietnē gravatar.com
change_custom_avatar=Mainīt savu profila attēlu iestatījumos
join_on=Pievienojās
repositories=Repozitoriji
activity=Publiskā aktivitāte
followers=Sekotāji
starred=Atzīmēti ar zvaigznīti
following=Seko
[settings]
profile=Profils
password=Parole
ssh_keys=SSH atslēgas
social=Sociālie konti
applications=Lietotnes
orgs=Organizācijas
delete=Dzēst kontu
uid=Lietotāja ID
public_profile=Publiskais profils
profile_desc=Jūsu e-pasta adrese ir publiska un tiks izmantota, lai nosūtītju Jums paziņojumus, kas saistīti ar Jūsu kontu vai darbībām veiktām caur šo mājas lapu.
full_name=Pilns vārds
website=Mājas lapa
location=Atrašanās vieta
update_profile=Mainīt profilu
update_profile_success=Jūsu profila dati ir veiksmīgi saglabāti.
change_username=Lietotāja vārds mainīts
change_username_desc=Lietotājvārds tiks mainīts, vai vēlaties turpināt? Tas ietekmēs visas saites, kas attiecas uz Jūsu kontu.
continue=Turpināt
cancel=Atcelt
enable_custom_avatar=Iespējot maināmu profila attēlu
enable_custom_avatar_helper=Iespējojiet šo, lai atslēgtu profilu attēlu ņemšanu no gravatar.com
choose_new_avatar=Izvēlēties jaunu profila attēlu
update_avatar=Saglabāt profila bildi
uploaded_avatar_not_a_image=Augšupielādētais fails nav attēls.
no_custom_avatar_available=Nav iespējams mainīt profila bildi.
update_avatar_success=Jūsu profila bilde tika veiksmīgi saglabāta.
change_password=Mainīt paroli
old_password=Pašreizējā parole
new_password=Jauna parole
password_incorrect=Ievadīta nepareiza pašreizējā parole.
change_password_success=Parole tika veiksmīgi nomainīta. Tagad jūs varat pieraksītites, izmantojot jauno paroli.
manage_ssh_keys=Pārvaldīt SSH atslēgas
add_key=Pievienot atslēgu
ssh_desc=Šis ir saraksts ar Jūsu kontam piesaistītajām SSH atslēgām. Dzēsiet visas, kuras Jūs neatpazīstat.
ssh_helper=<strong>Vajadzīga palīdzība?</strong> Apskatieties pamācību kā <a href="%s">ģenerēt SSH atslēgas</a> vai kā novērst <a href="%s">biežāk sastopamās SSH problēmas</a>.
add_new_key=Pievienot SSH atslēgu
key_name=Atslēgas nosaukums
key_content=Saturs
add_key_success=Pievienota jauna SSH atslēga!
delete_key=Dzēst
add_on=Pievienota
last_used=Pēdējo reizi izmantota
no_activity=Nav nesenas aktivitātes
manage_social=Pārvaldīt piesaistītos sociālos kontus
social_desc=Šeit tiek attēloti visi sociālie konti, kas ir piesaistīti Jūsu kontam. Dzēsiet visus, kurus Jūs neatpazīstat.
unbind=Atsaistīt
unbind_success=Sociālais konts tika atsaistīts.
manage_access_token=Pārvaldīt personīgos piekļuves talonus
generate_new_token=Ģenerēt jaunu talonu
tokens_desc=Talons tika uzģēnerēts, tagad varat to izmantot, lai piekļūtu Gogs API.
new_token_desc=Pašlaik visiem taloniem ir pilna piekļuve Jūsu kontam.
token_name=Talona nosaukums
generate_token=Ģenerēt talonu
generate_token_succees=Jauns piekļuves talons tika veiksmīgi uzģenerēts! Pārliecinieties, ka esat to nokopējis, jo to Jums vairāk nebūs iespēja izdarīt!
delete_token=Dzēst
delete_token_success=Jūsu personīgās piekļuves talons tika veiksmīgi izdzēsts! Neazimistiet veikt nepieciešamos labojumus savās lietojumprogrammās, kas to izmantoja.
delete_account=Dzēst savu kontu
delete_prompt=Šī darbība pilnībā izdzēsīs Jūsu kontu, kā arī tā ir <strong>NEATGRIEZENISKA</strong>!
confirm_delete_account=Apstiprināt dzēšanu
delete_account_title=Konta dzēšana
delete_account_desc=Šis konts tiks neatgriezeniski dzēsts, vai vēlaties turpināt?
[repo]
owner=Īpašnieks
repo_name=Repozitorija nosaukums
repo_name_helper=Labi repzotoriju nosaukumi ir īsi, tādi kurus viegli atcerēties un <strong>unikāli</strong>.
visibility=Redzamība
visiblity_helper=Šis repozitorijs ir <span class="label label-red label-radius">Privāts</span>
fork_repo=Atdalīt repozitoriju
fork_from=Atdalīt no
fork_visiblity_helper=Atdalītam repozitorijam nav iespējams nomainīt tā redzamību
repo_desc=Apraksts
repo_lang=Valoda
repo_lang_helper=Izvēlieties .gitignore failu
license=Licence
license_helper=Izvēlieties licences failu
init_readme=Inicializēt šo repozitoriju ar README.md failu
create_repo=Izveidot repozitoriju
default_branch=Noklusējuma atzars
mirror_interval=Spoguļošanas intervāls (stundās)
goget_meta=Go-Get metadati
goget_meta_helper=Šis repozitorijs saturēs <span class="label label-blue label-radius">Go-Get</span> metadatus
need_auth=Nepieciešama autorizācija
migrate_type=Migrācijas veids
migrate_type_helper=Šis repozitorijs būs <span class="label label-blue label-radius">Spoguļots</span>
migrate_repo=Migrēt repozitoriju
copy_link=Kopēt
click_to_copy=Kopēt uz starpliktuvi
copied=Kopēšana notikusi veiksmīgi
clone_helper=Nepieciešama palīdzība kā veikt klonēšana? Apmeklējiet <a target="_blank" href="%s">Palīdzība</a> lapu!
unwatch=Nevērot
watch=Vērot
unstar=Noņemt zvaigznīti
star=Pievienot zvaigznīti
fork=Atdalīts
no_desc=Nav apraksta
quick_guide=Īsa pamācība
clone_this_repo=Klonēt šo repozitoriju
create_new_repo_command=Izveidot jaunu repozitoriju komandrindā
push_exist_repo=Nosūtīt izmaiņas no komandrindas eksistējošam repozitorijam
branch=Atzars
tree=Koks
branch_and_tags=Atzari un birkas
branches=Atzari
tags=Birkas
issues=Problēmas
commits=Revīzijas
releases=Laidieni
file_raw=Neapstrādāts
file_history=Vēsture
file_view_raw=Rādīt neapstrādātu
commits.commits=Revīzijas
commits.search=Meklēt revīzijas
commits.find=Meklēt
commits.author=Autors
commits.message=Ziņojums
commits.date=Datums
commits.older=Vecāki
commits.newer=Jaunāki
settings=Iestatījumi
settings.options=Opcijas
settings.collaboration=Sadarbība
settings.hooks=Tīmekļa āķi
settings.githooks=Git āķi
settings.deploy_keys=Izvietot atslēgas
settings.basic_settings=Pamatiestatījumi
settings.danger_zone=Bīstamā zona
settings.site=Oficiālā mājas lapa
settings.update_settings=Mainīt iestatījumus
settings.change_reponame=Mainīts repozitorija nosaukums
settings.change_reponame_desc=Repozitorija nosaukums tiks mainīts, vai vēlaties turpināt? Tas ietekmēs visas saites, kas saistītas ar šo repozitoriju.
settings.transfer=Mainīt īpašnieku
settings.transfer_desc=Mainīt šī repozitorija īpašnieku uz citu lietotāju vai organizāciju, kurai Jums ir administratora tiesībs.
settings.new_owner_has_same_repo=Jaunajam īpašniekam jau ir repozitorijs ar šādu nosaukumu.
settings.delete=Dzēst šo repozitoriju
settings.delete_desc=Dzēšot repozitoriju, tā datus vairs nebūs iespējams atgūt. Pirms dzēšanas pārliecinieites vai patiešām vēlaties to darīt.
settings.transfer_notices=<p>- Jūs zaudēsiet piekļuvi repozitorijam, ja jaunais īpašnieks ir individuāls lietotājs.</p><p>- Jūs saglabāsiet piekļuvi repzitorijam, ja jaunais īpašneiks ir organizācija un Jūs esat viens no tās īpašniekiem.</p>
settings.update_settings_success=Repozitorija opcijas ir veiksmīgi saglabātas.
settings.transfer_owner=Jaunais īpašnieks
settings.make_transfer=Mainīt
settings.transfer_succeed=Repozitorija īpašnieks ir veiksmīgi nomainīts.
settings.confirm_delete=Apstiprināt dzēšanu
settings.add_collaborator=Pievienot jaunu līdzstrādnieku
settings.add_collaborator_success=Jauns līdzstrādnieks ir pievienots.
settings.remove_collaborator_success=Līdzstrādnieks tika noņemts.
settings.user_is_org_member=Lietotājs ir organizācijas biedrs, kas nevar tikt pievienots kā līdzstrādnieks.
settings.add_webhook=Pievienot tīmekļa āķi
settings.hooks_desc=Tīmekļa āķi ļauj paziņot ārējiem servisiem par noteiktiem notikomiem, kas notiek Git servisā. Kad iestāsies kāds notikums, katram ārējā servisa URL tiks nosūtīts POST pieprasījums. Lai uzzinātu sīkāk skatieties <a target="_blank" href="%s">Tīmekļa āķu rokasgrāmatā</a>.
settings.githooks_desc=Git āķus apstrādā pats Git. Jūs varat labot atbalsīto āku failus sarakstā zemāk, lai veiktu pielāgotas darbības.
settings.githook_edit_desc=Ja āķis nav aktīvs, tiks attēlots piemērs kā to izmantot. Atstājot āķa saturu tukšu, tas tiks atspējots.
settings.githook_name=Āķa nosaukums
settings.githook_content=Āķa saturs
settings.update_githook=Labot āķi
settings.remove_hook_success=Tīmekļa āķis tika noņemts.
settings.add_webhook_desc=Uz norādīto URL tiks nosūtīts <code>POST</code> pieprasījums ar notikuma datiem. Jūs varat norādīt arī datu formātu, kādā datus vēlaties saņemt (JSON, <code>x-www-form-urlencoded</code> <em>utt.</em>). Detalizētāku informāciju ir iespējams uzzināt <a target="_blank" href="%s">Tīmekļa āķu rokasgrāmatā</a>.
settings.payload_url=Vērtuma URL
settings.content_type=Satura tips
settings.secret=Noslēpums
settings.event_desc=Kādu notikumu rezultātā tiktu izsaukts tīmekļā āķis?
settings.event_push_only=Tikai izmaiņu nosūtīšanas notikumiem.
settings.active=Aktīvs
settings.active_helper=Tiks nosūtīti notikuma dati, kad nostrādās šis āķis.
settings.add_hook_success=Jauns tīmekļa āķis tika veiksmīgi pievienots.
settings.update_webhook=Mainīt tīmekļa āķi
settings.update_hook_success=Tīmekļa āķist tika veiksmīgi saglabāts.
settings.delete_webhook=Dzēst tīmekļa āķi
settings.recent_deliveries=Pēdējās piegādes
settings.hook_type=Āķa veids
settings.add_slack_hook_desc=PIevienot <a href="%s">Slack</a> integrāciju Jūsu repozitorijā.
settings.slack_token=Talons
settings.slack_domain=Domēns
settings.slack_channel=Kanāls
diff.browse_source=Pārlūkot izejas kodu
diff.parent=vecāks
diff.commit=revīzija
diff.data_not_available=Salīdzināšanas dati nav pieejami.
diff.show_diff_stats=Rādīt salīdzināšanas statistiku
diff.stats_desc=<strong>%d mainītis faili</strong> ar <strong>%d papildinājumiem</strong> un <strong>%d dzēšanām</strong>
diff.bin=BIN
diff.view_file=Parādīt failu
release.releases=Releases
release.new_release=New Release
release.draft=Draft
release.prerelease=Pre-Release
release.stable=Stable
release.edit=edit
release.ahead=<strong>%d</strong> commits to %s since this release
release.source_code=Source Code
release.tag_name=Tag name
release.target=Target
release.tag_helper=Choose an existing tag, or create a new tag on publish.
release.release_title=Release title
release.content_with_md=Content with <a href="%s">Markdown</a>
release.write=Write
release.preview=Preview
release.content_placeholder=Write some content
release.loading=Loading...
release.prerelease_desc=This is a pre-release
release.prerelease_helper=Well point out that this release is identified as non-production ready.
release.publish=Publish Release
release.save_draft=Save Draft
release.edit_release=Edit Release
release.tag_name_already_exist=Release with this tag name has already existed.
[org]
org_name_holder=Organizācijas nosaukums
org_name_helper=Labi organizāciju nosaukumi ir īsi un tādi, kurus viegli atcerēties.
org_email_helper=Uz organizācijas e-pastu tiks sūtītas visas notifikācias un apstiprinājumi.
create_org=Izveidot organizāciju
repo_updated=Atjaunināts
people=Personas
invite_someone=Uzaicināt kādu
teams=Komandas
lower_members=dalībnieki
lower_repositories=repozitoriji
create_new_team=Izveidot jaunu komandu
org_desc=Apraksts
team_name=Komandas nosaukums
team_desc=Apraksts
team_name_helper=Šo nosaukumu varēs izmantot, lai pieminētu komandu sarunās.
team_desc_helper=Komandas apraksts
team_permission_desc=Kādām tiesībām šai komandai būtu jābūt?
settings=Iestatījumi
settings.options=Opcijas
settings.full_name=Pilns vārds, uzvārds
settings.website=Mājas lapa
settings.location=Atrašanās vieta
settings.update_settings=Mainīt iestatījumus
settings.change_orgname=Mainīts organizācijas nosaukums
settings.change_orgname_desc=Organizācijas nosaukums tiks mainīts, vai vēlaties turpinat? Tas ietekmēs saites, kas attiecas uz šo organizāciju.
settings.update_setting_success=Organizācijas iestatījumi tika veiksmīgi saglabāti.
settings.delete=Dzēst organizāciju
settings.delete_account=Dzēst šo organizāciju
settings.delete_prompt=Šī darbība pilnībā dzēsīs šo organizāciju, kā arī tā ir <strong>NEATGRIEZENISKA</strong>!
settings.confirm_delete_account=Apstiprināt dzēšanu
settings.delete_org_title=Organizācijas dzēšana
settings.delete_org_desc=Šī organizācija tiks pilnībā izdzēsta, vai vēlaties turpināt?
settings.hooks_desc=Pievienot tīmekļa āķus, kas nostrādās <strong>visiem repozitorijiem</strong> šajā organizācijā.
members.public=Publisks
members.public_helper=padarīt privātu
members.private=Privāts
members.private_helper=padarīt publisku
members.owner=Īpašnieks
members.member=Biedri
members.conceal=Noslēpt
members.remove=Noņemt
members.leave=Atstāt
members.invite_desc=Sāciet rakstīt lietotājvārdu, lai uzaicinātu jaunu biedru organizācijā %s:
members.invite_now=Uzaicināt tagad
teams.join=Pievienoties
teams.leave=Atstāt
teams.read_access=Lasīšanas piekļuve
teams.read_access_helper=Komanda varēs skatīties un klonēt šīs organizācijas repozitorijus.
teams.write_access=Rakstīšanas piekļuve
teams.write_access_helper=Komanda varēs skatīties un klonēt, kā arī nosūtīt izmaiņas šīs organizācijas repozitorijiem.
teams.admin_access=Administratora piekļuve
teams.admin_access_helper=Šī komanda varēs veikt push/pull komandas tās repozitorijiem, kā arī tiem pievienot citus līdzstrādniekus.
teams.no_desc=Komandai nav apraksta
teams.settings=Iestatījumi
teams.owners_permission_desc=Īpašniekiem ir pilna piekļuve <strong>visiem repozitorijiem</strong> un ir organizācijas <strong>administratora tiesības</strong>.
teams.members=Komandas biedri
teams.update_settings=Saglabāt iestatījumus
teams.delete_team=Dzēst komandu
teams.add_team_member=Pievienot komandas biedru
teams.delete_team_title=Komandas dzēšana
teams.delete_team_desc=Komanda tiks dzēsta, vai vēlaties turpināt? Komandas biedri var zaudēt piekļuvi dažiem vai pat visiem repozitorijiem.
teams.delete_team_success=Komanda tika veiksmīgi izdzēsta.
teams.read_permission_desc=Šai komandai ir <strong>lasīšanas</strong> tiesības: dalībnieki var skatīties un klonēt komandas repozitorijus.
teams.write_permission_desc=Šai komandai ir <strong>rakstīšanas</strong> tiesības: dalībnieki var lasīt un nosūtīt izmaiņas repozitorijiem.
teams.admin_permission_desc=Šai komandai ir <strong>administratora</strong> tiesības: dalībnieki var lasīt, rakstīt un pievienot citus dalībniekus komandas repozitorijiem.
teams.repositories=Komandas repozitoriji
teams.add_team_repository=Pievienot komandas repozitoriju
teams.remove_repo=Noņemt
teams.add_nonexistent_repo=Repozitorijs, kuram Jūs mēģinat pievienot neeksistē, sākumā izveidojiet to.
[admin]
dashboard=Infopanelis
users=Lietotāji
organizations=Organizācijas
repositories=Repozitoriji
authentication=Autentifikācijas
config=Konfigurācija
notices=Sistēmas paziņojumi
monitor=Uzraudzība
prev=Iepr.
next=Tālāk
dashboard.statistic=Statistika
dashboard.operations=Darbības
dashboard.system_status=Sistēmas uzraudzības statuss
dashboard.statistic_info=Gogs datu bāze satur <b>%d</b> lietotājus, <b>%d</b> organizācijas, <b>%d</b> publiskās atslēgas, <b>%d</b> repozitorijus, <b>%d</b> vērošanas, <b>%d</b> atzīmētas zvaigznītes, <b>%d</b> darbības, <b>%d</b> piekļuves, <b>%d</b> problēmas, <b>%d</b> komentārus, <b>%d</b> sociālos kontus, <b>%d</b> sekošanas, <b>%d</b> spoguļošanas, <b>%d</b> izlaides, <b>%d</b> login sources, <b>%d</b> tīmekļa āķus, <b>%d</b> starpposmus, <b>%d</b> etiķetes, <b>%d</b> āķu uzdevumus, <b>%d</b> komandas, <b>%d</b> labotus uzdevumus, <b>%d</b> pielikumus.
dashboard.operation_name=Darbības nosaukums
dashboard.operation_switch=Pārslēgt
dashboard.operation_run=Palaist
dashboard.clean_unbind_oauth=Notīrīt nesaistītās OAuth biļetes
dashboard.clean_unbind_oauth_success=Visas nesaistītās OAuth biļetes tika veiksmīgi izdzēstas.
dashboard.delete_inactivate_accounts=Dzēst visus neaktīvos kontus
dashboard.delete_inactivate_accounts_success=Visi neaktīvie kotni tika veiksmīgi izdzēsti.
dashboard.delete_repo_archives=Dzēst visu repozitoriju arhīvus
dashboard.delete_repo_archives_success=Visu repozitoriju arhīvi tika veiksmīgi izdzēsti.
dashboard.git_gc_repos=Veikt repozitoriju datu sakārtošānu (git gc)
dashboard.git_gc_repos_success=Datu sakārtošana visiem repozitorijiem veiksmīgi pabeigta.
dashboard.server_uptime=Servera darbības laiks
dashboard.current_goroutine=Izmantotās Gorutīnas
dashboard.current_memory_usage=Pašreiz izmantotā atmiņa
dashboard.total_memory_allocated=Kopējā piešķirtā atmiņa
dashboard.memory_obtained=Iegūtā atmiņa
dashboard.pointer_lookup_times=Rādītāju meklēšanas reizes
dashboard.memory_allocate_times=Atmiņas piešķiršanas reizes
dashboard.memory_free_times=Atmiņas atbrīvošanas reizes
dashboard.current_heap_usage=Pašreizējā kaudzes izmantošana
dashboard.heap_memory_obtained=Iegūtā kaudzes atmiņa
dashboard.heap_memory_idle=Neizmantotā kaudzes atmiņa
dashboard.heap_memory_in_use=Izmantotā kaudzes atmiņa
dashboard.heap_memory_released=Atbrīvotā kaudzes atmiņa
dashboard.heap_objects=Kaudzes atmiņas objekti
dashboard.bootstrap_stack_usage=Izmantotais sāknēšanas steka lielums
dashboard.stack_memory_obtained=Iegūtā steka atmiņa
dashboard.mspan_structures_usage=Izmantotās MSpan struktūras
dashboard.mspan_structures_obtained=Iegūtās MSpan struktūras
dashboard.mcache_structures_usage=Izmantotās MCache struktūras
dashboard.mcache_structures_obtained=Iegūtās MCache struktūras
dashboard.profiling_bucket_hash_table_obtained=Iegūtā profilēšanas kausa jaucējtabula
dashboard.gc_metadata_obtained=Iegūtie GC metadati
dashboard.other_system_allocation_obtained=Iegūtās citas sistēmas sadales
dashboard.next_gc_recycle=Nākošā GC atkritne
dashboard.last_gc_time=Laiks kopš pēdējās GC
dashboard.total_gc_time=Kopējais GC izpildes laiks
dashboard.total_gc_pause=Kopējais GC izpildes laiks
dashboard.last_gc_pause=Pedējās GC izpildes laiks
dashboard.gc_times=GC reizes
users.user_manage_panel=Lietotāju pārvaldības panelis
users.new_account=Izveidot jaunu kontu
users.name=Vārds
users.activated=Aktivizēts
users.admin=Administrators
users.repos=Repozitoriji
users.created=Izveidots
users.edit=Labot
users.auth_source=Autorizācijas avots
users.local=Iebūvētā
users.auth_login_name=Autorizāciju, pietiekšanās vārds
users.update_profile_success=Konta profils tika veiksmīgi saglabāts.
users.edit_account=Labot kontu
users.is_activated=Konts ir aktivizēts
users.is_admin=Šim kontam ir administratora piekļuves tiesības
users.allow_git_hook=Šim kontam ir tiesības pievienot/labot Git āķus
users.update_profile=Mainīt konta profilu
users.delete_account=Dzēst šo kontu
users.still_own_repo=Šis konts ir vismaz viena repozitorija īpašnieks, tos sākumā ir nepieciešams izdzēst vai nomainīt to īpašnieku.
users.still_has_org=Šis konts ir vismaz vienas organizācijas biedrs, sākumā nepieciešams pamest vai izdzēst šo organizāciju.
orgs.org_manage_panel=Organizāciju pārvaldības panelis
orgs.name=Nosaukums
orgs.teams=Komandas
orgs.members=Dalībnieki
repos.repo_manage_panel=Repozitoriju pārvaldības panelis
repos.owner=Īpašnieks
repos.name=Vārds
repos.private=Privāts
repos.watches=Vērošana
repos.stars=Atzīmētās zvaigznītes
repos.issues=Problēmas
auths.auth_manage_panel=Autorizāciju pārvaldības panelis
auths.new=Pievienot jaunu autorizācijas veidu
auths.name=Nosaukums
auths.type=Veids
auths.enabled=Iespējota
auths.updated=Atjaunināta
auths.auth_type=Autorizācijas veids
auths.auth_name=Autorizācijas nosaukums
auths.domain=Domēns
auths.host=Resursdators
auths.port=Ports
auths.base_dn=Pamata DN
auths.attributes=Meklēšanas atribūti
auths.filter=Meklēšanas filtrs
auths.ms_ad_sa=MS Ad SA
auths.smtp_auth=SMTP autorizācijas veids
auths.smtphost=SMTP resursdators
auths.smtpport=SMTP ports
auths.enable_tls=Iespējot TLS šifrēšanu
auths.enable_auto_register=Iespējot automātisko reģistrāciju
auths.tips=Padomi
auths.edit=Labot autorizācijas iestatījumus
auths.activated=Autentifikācija ir aktivizēta
auths.update_success=Autorizācijas iestatījumi tika veiksmīgi saglabāti.
auths.update=Mainīt autorizācijas iestatījumus
auths.delete=Dzēst šo autorizāciju
auths.delete_auth_title=Autorizācijas dzēšana
auths.delete_auth_desc=Šī autorizācija tiks dzēsta, vai vēlaties turpināt?
config.server_config=Servera konfigurācija
config.app_name=Lietotnes nosaukums
config.app_ver=Lietotnes versija
config.app_url=Lietotnes URL
config.domain=Domēns
config.offline_mode=Bezsaistes režīms
config.disable_router_log=Atspējot maršrutētāja žurnalizēšanu
config.run_user=Izpildes lietotājs
config.run_mode=Izpildes režīms
config.repo_root_path=Repozitoriju glabāšanas vieta
config.static_file_root_path=Statisko failu atrašanās vieta
config.log_file_root_path=Žurnalizēšanas failu glabāšanas vieta
config.script_type=Skripta veids
config.reverse_auth_user=Reversā lietotāja autentifikācija
config.db_config=Datu bāzes konfigurācija
config.db_type=Veids
config.db_host=Resursdators
config.db_name=Nosaukums
config.db_user=Lietotājs
config.db_ssl_mode=SSL režīms
config.db_ssl_mode_helper=(tikai PostgreSQL datu bāzei)
config.db_path=Ceļš
config.db_path_helper=(tikai Sqlite3 datu bāzei)
config.service_config=Pakalpojuma konfigurācija
config.register_email_confirm=E-pasta reģistrēšanas apstiprināšana
config.disable_register=Atspējot jaunu lietotāju reģistrāciju
config.require_sign_in_view=Nepieciešama autorizācija
config.mail_notify=Pasta paziņojumi
config.enable_cache_avatar=Glabāt profila attēlus kešatmiņā
config.active_code_lives=Aktīvā koda ilgums
config.reset_password_code_lives=Paroles atiestatīšanas koda ilgums
config.webhook_config=Tīkla āķu konfigurācija
config.task_interval=Uzdevuma intervāls
config.deliver_timeout=Piegādes noildze
config.mailer_config=Sūtītāja konfigurācija
config.mailer_enabled=Iespējots
config.mailer_name=Nosaukums
config.mailer_host=Resursdators
config.mailer_user=Lietotājs
config.oauth_config=OAuth konfigurācija
config.oauth_enabled=Iespējota
config.cache_config=Kešatmiņas konfigurācija
config.cache_adapter=Kešatmiņas adapteris
config.cache_interval=Kešatmiņas intervāls
config.cache_conn=Kešatmiņas pieslēguma parametri
config.session_config=Sesijas konfigurācja
config.session_provider=Sesijas nodrošinātājs
config.provider_config=Pakalpojumu sniedzēja konfigurācija
config.cookie_name=Sīkdatnes nosaukums
config.enable_set_cookie=Ļaut izmantot sīkdatnes
config.gc_interval_time=GC laika intervāls
config.session_life_time=Sesijas ilgums
config.https_only=Tikai HTTPS
config.cookie_life_time=Sīkdatņu glabāšanas ilgums
config.picture_config=Attēlu konfigurācija
config.picture_service=Lokāli attēli
config.disable_gravatar=Atspējot Gravatar
config.log_config=Žurnalizēšanas konfigurācija
config.log_mode=Žurnalizēšanas veids
monitor.cron=Cron uzdevumi
monitor.name=Nosaukums
monitor.schedule=Grafiks
monitor.next=Nākošās izpildes laiks
monitor.previous=Pēdējās izpildes laiks
monitor.execute_times=Izpilžu skaits
monitor.process=Darbojošies procesi
monitor.desc=Apraksts
monitor.start=Sākuma laiks
monitor.execute_time=Izpildes laiks
notices.system_notice_list=Sistēmas paziņojumi
notices.type=Veids
notices.type_1=Repozitorijs
notices.desc=Apraksts
notices.op=Op.
notices.delete_success=Sistēmas paziņojums tika veiksmīgi izdzēsts.
[action]
create_repo=izveidoja repozitoriju <a href="%s/%s">%s</a>
commit_repo=veica izmaiņu nosūtīšanu atzaram <a href="%s/%s/src/%s">%s</a> repozitorijā <a href="%s/%s">%s</a>
create_issue=reģistrēja problēmu <a href="%s/%s/issues/%s">%s#%s</a>
comment_issue=pievienoja komentāru problēmai <a href="%s/%s/issues/%s">%s#%s</a>
transfer_repo=mainīja repozitorija <code>%s</code> īpašnieku uz <a href="/%s%s">%s</a>
push_tag=pievienoja birku <a href="%s/%s/src/%s">%s</a> repozitorijam <a href="%s/%s">%s</a>
compare_2_commits=Veikt salīdzināšanu starp šīm 2 revīzijām
[tool]
ago=atpakaļ
from_now=no šī brīža
now=tagad
1s=1 sekundi %s
1m=1 minūti %s
1h=1 stundu %s
1d=1 dienu %s
1w=1 nedēļu %s
1mon=1 mēnesi %s
1y=1 gadu %s
seconds=%d sekundes %s
minutes=%d minūtes %s
hours=%d stundas %s
days=%d dienas %s
weeks=%d nedēļas %s
months=%d mēneši %s
years=%d gadi %s
raw_seconds=sekundes
raw_minutes=minūtes

View File

@@ -173,6 +173,7 @@ target_branch_not_exist=Doel branch bestaat niet
[user]
change_avatar=Verander uw avatar op Gravatar.com
change_custom_avatar=Change your avatar in settings
join_on=Aangemeld op
repositories=repositories
activity=Openbare activiteit
@@ -202,6 +203,14 @@ change_username_desc=Gebruikersnaam is gewijzigd. Wilt u doorgaan? Dit zal gevol
continue=Doorgaan
cancel=Annuleren
enable_custom_avatar=Enable Custom Avatar
enable_custom_avatar_helper=Enable this to disable fetch from Gravatar
choose_new_avatar=Choose new avatar
update_avatar=Update Avatar Setting
uploaded_avatar_not_a_image=Uploaded file is not a image.
no_custom_avatar_available=No custom avatar available, cannot enable it.
update_avatar_success=Your avatar setting has been updated successfully.
change_password=Verander wachtwoord
old_password=Huidige wachtwoord
new_password=Nieuw wachtwoord
@@ -368,6 +377,30 @@ diff.stats_desc=<strong>%d gewijzigde bestanden</strong> met <strong>toevoeginge
diff.bin=BIN
diff.view_file=Bestand weergeven
release.releases=Releases
release.new_release=New Release
release.draft=Draft
release.prerelease=Pre-Release
release.stable=Stable
release.edit=edit
release.ahead=<strong>%d</strong> commits to %s since this release
release.source_code=Source Code
release.tag_name=Tag name
release.target=Target
release.tag_helper=Choose an existing tag, or create a new tag on publish.
release.release_title=Release title
release.content_with_md=Content with <a href="%s">Markdown</a>
release.write=Write
release.preview=Preview
release.content_placeholder=Write some content
release.loading=Loading...
release.prerelease_desc=This is a pre-release
release.prerelease_helper=Well point out that this release is identified as non-production ready.
release.publish=Publish Release
release.save_draft=Save Draft
release.edit_release=Edit Release
release.tag_name_already_exist=Release with this tag name has already existed.
[org]
org_name_holder=Organisatienaam
org_name_helper=Een goede organisatienaam is kort en memorabel.
@@ -467,6 +500,8 @@ dashboard.delete_inactivate_accounts=Verwijder alle inactieve accounts
dashboard.delete_inactivate_accounts_success=Alle inactivering van rekeningen hebben verwijderd.
dashboard.delete_repo_archives=Verwijderen van alle repositories archieven
dashboard.delete_repo_archives_success=Alle repositories archieven hebben verwijderd.
dashboard.git_gc_repos=Do garbage collection on repositories
dashboard.git_gc_repos_success=All repositories have done garbage collection successfully.
dashboard.server_uptime=Uptime server
dashboard.current_goroutine=Huidige Goroutines
dashboard.current_memory_usage=Huidige geheugen gebruik

View File

@@ -173,6 +173,7 @@ target_branch_not_exist=目标分支不存在。
[user]
change_avatar=到 gravatar.com 上修改您的头像
change_custom_avatar=到个人设置中修改头像
join_on=加入于
repositories=仓库列表
activity=公开活动
@@ -202,6 +203,14 @@ change_username_desc=用户名被修改,您确定要继续操作吗?这将
continue=继续操作
cancel=取消操作
enable_custom_avatar=启动自定义头像
enable_custom_avatar_helper=激活该选项来禁止从 Gravatar 获取头像
choose_new_avatar=选择新的头像
update_avatar=更新头像设置
uploaded_avatar_not_a_image=上传的文件不是一张图片!
no_custom_avatar_available=未上传过自定义头像,无法激活该选项。
update_avatar_success=您的头像设置更新成功!
change_password=修改密码
old_password=当前密码
new_password=新的密码
@@ -368,6 +377,30 @@ diff.stats_desc=共有 <strong> %d 个文件被更改</strong>,包括 <strong>
diff.bin=二进制
diff.view_file=查看文件
release.releases=版本发布
release.new_release=发布新版
release.draft=草稿
release.prerelease=预发行
release.stable=稳定
release.edit=编辑
release.ahead=在该版本发布之后已有 <strong>%d</strong> 次代码提交到 %s 分支
release.source_code=源代码
release.tag_name=标签名称
release.target=目标分支
release.tag_helper=选择或创建一个已经存在的标签
release.release_title=发布标题
release.content_with_md=使用 <a href="%s">Markdown</a> 编辑内容
release.write=内容编辑
release.preview=效果预览
release.content_placeholder=请输入内容
release.loading=正在加载...
release.prerelease_desc=这是一个预发行版本
release.prerelease_helper=我们会告知用户不建议将本次发布投入生产环境使用。
release.publish=发布版本
release.save_draft=保存草稿
release.edit_release=编辑发布信息
release.tag_name_already_exist=已经存在使用相同标签进行发布的版本。
[org]
org_name_holder=组织名称
org_name_helper=伟大的组织都有一个简短而寓意深刻的名字。
@@ -467,6 +500,8 @@ dashboard.delete_inactivate_accounts=删除所有未激活帐户
dashboard.delete_inactivate_accounts_success=所有未激活帐号清除成功!
dashboard.delete_repo_archives=删除所有仓库存档
dashboard.delete_repo_archives_success=所有仓库存档清除成功!
dashboard.git_gc_repos=对仓库进行垃圾回收
dashboard.git_gc_repos_success=所有仓库垃圾回收成功!
dashboard.server_uptime=服务运行时间
dashboard.current_goroutine=当前 Goroutines 数量
dashboard.current_memory_usage=当前内存使用量

View File

@@ -173,6 +173,7 @@ target_branch_not_exist=目標分支不存在
[user]
change_avatar=到 gravatar.com 上修改您的頭像
change_custom_avatar=到個人設置中修改頭像
join_on=加入於
repositories=倉庫列表
activity=公開活動
@@ -202,6 +203,14 @@ change_username_desc=用戶名被修改,您確定要繼續操作嗎?這將
continue=繼續操作
cancel=取消操作
enable_custom_avatar=啟動自定義頭像
enable_custom_avatar_helper=激活該選項來禁止從 Gravatar 獲取頭像
choose_new_avatar=選擇新的頭像
update_avatar=更新頭像設置
uploaded_avatar_not_a_image=上傳的文件不是一張圖片!
no_custom_avatar_available=沒有任何自定義頭像,無法激活該選項。
update_avatar_success=您的頭像設置更新成功!
change_password=修改密碼
old_password=當前密碼
new_password=新的密碼
@@ -368,6 +377,30 @@ diff.stats_desc=共有 <strong> %d 個文件被更改</strong>,包括 <strong>
diff.bin=二進制
diff.view_file=查看文件
release.releases=Releases
release.new_release=New Release
release.draft=Draft
release.prerelease=Pre-Release
release.stable=Stable
release.edit=edit
release.ahead=<strong>%d</strong> commits to %s since this release
release.source_code=Source Code
release.tag_name=Tag name
release.target=Target
release.tag_helper=Choose an existing tag, or create a new tag on publish.
release.release_title=Release title
release.content_with_md=Content with <a href="%s">Markdown</a>
release.write=Write
release.preview=Preview
release.content_placeholder=Write some content
release.loading=Loading...
release.prerelease_desc=This is a pre-release
release.prerelease_helper=Well point out that this release is identified as non-production ready.
release.publish=Publish Release
release.save_draft=Save Draft
release.edit_release=Edit Release
release.tag_name_already_exist=Release with this tag name has already existed.
[org]
org_name_holder=組織名稱
org_name_helper=偉大的組織都有一個簡短而寓意深刻的名字。
@@ -467,6 +500,8 @@ dashboard.delete_inactivate_accounts=刪除所有未激活帳戶
dashboard.delete_inactivate_accounts_success=所有未激活帳號清除成功!
dashboard.delete_repo_archives=刪除所有倉庫存檔
dashboard.delete_repo_archives_success=所有倉庫存檔清除成功!
dashboard.git_gc_repos=對倉庫進行垃圾回收
dashboard.git_gc_repos_success=所有倉庫的垃圾回收已成功完成!
dashboard.server_uptime=服務執行時間
dashboard.current_goroutine=當前 Goroutines 數量
dashboard.current_memory_usage=當前內存使用量

View File

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

View File

@@ -58,6 +58,7 @@ type Action struct {
ActUserId int64 // Action user id.
ActUserName string // Action user name.
ActEmail string
ActAvatar string `xorm:"-"`
RepoId int64
RepoUserName string
RepoName string
@@ -348,7 +349,7 @@ func NewRepoAction(u *User, repo *Repository) (err error) {
return err
}
// TransferRepoAction adds new action for transfering repository.
// TransferRepoAction adds new action for transferring repository.
func TransferRepoAction(u, newUser *User, repo *Repository) (err error) {
action := &Action{
ActUserId: u.Id,

View File

@@ -6,6 +6,7 @@ package models
import (
"bufio"
"bytes"
"fmt"
"io"
"os"
@@ -15,8 +16,10 @@ import (
"github.com/Unknwon/com"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/git"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/mahonia"
"github.com/gogits/gogs/modules/process"
)
@@ -80,6 +83,8 @@ func ParsePatch(pid int64, maxlines int, cmd *exec.Cmd, reader io.Reader) (*Diff
leftLine, rightLine int
isTooLong bool
// FIXME: use first 30 lines to detect file encoding. Should use cache in the future.
buf bytes.Buffer
)
diff := &Diff{Files: make([]*DiffFile, 0)}
@@ -97,6 +102,11 @@ func ParsePatch(pid int64, maxlines int, cmd *exec.Cmd, reader io.Reader) (*Diff
i = i + 1
// FIXME: use first 30 lines to detect file encoding.
if i <= 30 {
buf.WriteString(line)
}
// Diff data too large, we only show the first about maxlines lines
if i == maxlines {
isTooLong = true
@@ -181,6 +191,21 @@ func ParsePatch(pid int64, maxlines int, cmd *exec.Cmd, reader io.Reader) (*Diff
}
}
// FIXME: use first 30 lines to detect file encoding.
charset, err := base.DetectEncoding(buf.Bytes())
if charset != "utf8" && err == nil {
decoder := mahonia.NewDecoder(charset)
if decoder != nil {
for _, f := range diff.Files {
for _, sec := range f.Sections {
for _, l := range sec.Lines {
l.Content = decoder.ConvertString(l.Content)
}
}
}
}
}
return diff, nil
}

View File

@@ -18,6 +18,7 @@ import (
"github.com/gogits/gogs/modules/auth/ldap"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/uuid"
)
type LoginType int
@@ -40,7 +41,7 @@ var LoginTypes = map[LoginType]string{
SMTP: "SMTP",
}
// Ensure structs implmented interface.
// Ensure structs implemented interface.
var (
_ core.Conversion = &LDAPConfig{}
_ core.Conversion = &SMTPConfig{}
@@ -225,33 +226,35 @@ func UserSignIn(uname, passwd string) (*User, error) {
}
}
// Query if name/passwd can login against the LDAP direcotry pool
// Query if name/passwd can login against the LDAP directory pool
// Create a local user if success
// Return the same LoginUserPlain semantic
// FIXME: https://github.com/gogits/gogs/issues/672
func LoginUserLdapSource(u *User, name, passwd string, sourceId int64, cfg *LDAPConfig, autoRegister bool) (*User, error) {
mail, logged := cfg.Ldapsource.SearchEntry(name, passwd)
if !logged {
// user not in LDAP, do nothing
// User not in LDAP, do nothing
return nil, ErrUserNotExist
}
if !autoRegister {
return u, nil
}
// fake a local user creation
// Fallback.
if len(mail) == 0 {
mail = uuid.NewV4().String() + "@localhost"
}
u = &User{
LowerName: strings.ToLower(name),
Name: strings.ToLower(name),
Name: name,
LoginType: LDAP,
LoginSource: sourceId,
LoginName: name,
IsActive: true,
Passwd: passwd,
Email: mail,
IsActive: true,
}
err := CreateUser(u)
return u, err
return u, CreateUser(u)
}
type loginAuth struct {
@@ -315,7 +318,7 @@ func SmtpAuth(host string, port int, a smtp.Auth, useTls bool) error {
return ErrUnsupportedLoginType
}
// Query if name/passwd can login against the LDAP direcotry pool
// Query if name/passwd can login against the LDAP directory pool
// Create a local user if success
// Return the same LoginUserPlain semantic
func LoginUserSMTPSource(u *User, name, passwd string, sourceId int64, cfg *SMTPConfig, autoRegister bool) (*User, error) {

View File

@@ -107,7 +107,7 @@ func SetEngine() (err error) {
return fmt.Errorf("models.init(fail to connect to database): %v", err)
}
// WARNNING: for serv command, MUST remove the output to os.stdout,
// WARNING: for serv command, MUST remove the output to os.stdout,
// so use log file to instead print to stdout.
logPath := path.Join(setting.LogRootPath, "xorm.log")
os.MkdirAll(path.Dir(logPath), os.ModePerm)

View File

@@ -79,7 +79,7 @@ func UpdateOauth2(oa *Oauth2) error {
return err
}
// GetOauthByUserId returns list of oauthes that are releated to given user.
// GetOauthByUserId returns list of oauthes that are related to given user.
func GetOauthByUserId(uid int64) ([]*Oauth2, error) {
socials := make([]*Oauth2, 0, 5)
err := x.Find(&socials, Oauth2{Uid: uid})

View File

@@ -25,8 +25,8 @@ var (
ErrLastOrgOwner = errors.New("The user to remove is the last member in owner team")
)
// IsOrgOwner returns true if given user is in the owner team.
func (org *User) IsOrgOwner(uid int64) bool {
// IsOwnedBy returns true if given user is in the owner team.
func (org *User) IsOwnedBy(uid int64) bool {
return IsOrganizationOwner(org.Id, uid)
}
@@ -77,6 +77,17 @@ func (org *User) RemoveMember(uid int64) error {
return RemoveOrgUser(org.Id, uid)
}
// IsOrgEmailUsed returns true if the e-mail has been used in organization account.
func IsOrgEmailUsed(email string) (bool, error) {
if len(email) == 0 {
return false, nil
}
return x.Get(&User{
Email: email,
Type: ORGANIZATION,
})
}
// CreateOrganization creates record of a new organization.
func CreateOrganization(org, owner *User) (*User, error) {
if !IsLegalName(org.Name) {
@@ -90,7 +101,7 @@ func CreateOrganization(org, owner *User) (*User, error) {
return nil, ErrUserAlreadyExist
}
isExist, err = IsEmailUsed(org.Email)
isExist, err = IsOrgEmailUsed(org.Email)
if err != nil {
return nil, err
} else if isExist {
@@ -159,6 +170,24 @@ func CreateOrganization(org, owner *User) (*User, error) {
return org, sess.Commit()
}
// GetOrgByName returns organization by given name.
func GetOrgByName(name string) (*User, error) {
if len(name) == 0 {
return nil, ErrOrgNotExist
}
u := &User{
LowerName: strings.ToLower(name),
Type: ORGANIZATION,
}
has, err := x.Get(u)
if err != nil {
return nil, err
} else if !has {
return nil, ErrOrgNotExist
}
return u, nil
}
// CountOrganizations returns number of organizations.
func CountOrganizations() int64 {
count, _ := x.Where("type=1").Count(new(User))
@@ -229,7 +258,7 @@ func IsOrganizationMember(orgId, uid int64) bool {
return has
}
// IsPublicMembership returns ture if given user public his/her membership.
// IsPublicMembership returns true if given user public his/her membership.
func IsPublicMembership(orgId, uid int64) bool {
has, _ := x.Where("uid=?", uid).And("org_id=?", orgId).And("is_public=?", true).Get(new(OrgUser))
return has
@@ -850,7 +879,7 @@ func GetTeamMembers(orgId, teamId int64) ([]*User, error) {
return us, err
}
// GetUserTeams returns all teams that user belongs to in given origanization.
// GetUserTeams returns all teams that user belongs to in given organization.
func GetUserTeams(orgId, uid int64) ([]*Team, error) {
tus := make([]*TeamUser, 0, 5)
if err := x.Where("uid=?", uid).And("org_id=?", orgId).Find(&tus); err != nil {

View File

@@ -89,6 +89,11 @@ type PublicKey struct {
HasUsed bool `xorm:"-"`
}
// OmitEmail returns content of public key but without e-mail address.
func (k *PublicKey) OmitEmail() string {
return strings.Join(strings.Split(k.Content, " ")[:2], " ")
}
// GetAuthorizedString generates and returns formatted public key string for authorized_keys file.
func (key *PublicKey) GetAuthorizedString() string {
return fmt.Sprintf(_TPL_PUBLICK_KEY, appPath, key.Id, key.Content)

View File

@@ -241,9 +241,30 @@ func IsRepositoryExist(u *User, repoName string) (bool, error) {
return com.IsDir(RepoPath(u.Name, repoName)), nil
}
// CloneLink represents different types of clone URLs of repository.
type CloneLink struct {
SSH string
HTTPS string
Git string
}
// CloneLink returns clone URLs of repository.
func (repo *Repository) CloneLink() (cl CloneLink, err error) {
if err = repo.GetOwner(); err != nil {
return cl, err
}
if setting.SshPort != 22 {
cl.SSH = fmt.Sprintf("ssh://%s@%s:%d/%s/%s.git", setting.RunUser, setting.Domain, setting.SshPort, repo.Owner.LowerName, repo.LowerName)
} else {
cl.SSH = fmt.Sprintf("%s@%s:%s/%s.git", setting.RunUser, setting.Domain, repo.Owner.LowerName, repo.LowerName)
}
cl.HTTPS = fmt.Sprintf("%s%s/%s.git", setting.AppUrl, repo.Owner.LowerName, repo.LowerName)
return cl, nil
}
var (
illegalEquals = []string{"debug", "raw", "install", "api", "avatar", "user", "org", "help", "stars", "issues", "pulls", "commits", "repo", "template", "admin", "new"}
illegalSuffixs = []string{".git"}
illegalSuffixs = []string{".git", ".keys"}
)
// IsLegalName returns false if name contains illegal characters.
@@ -308,28 +329,6 @@ func MirrorRepository(repoId int64, userName, repoName, repoPath, url string) er
return nil
}
// MirrorUpdate checks and updates mirror repositories.
func MirrorUpdate() {
if err := x.Iterate(new(Mirror), func(idx int, bean interface{}) error {
m := bean.(*Mirror)
if m.NextUpdate.After(time.Now()) {
return nil
}
repoPath := filepath.Join(setting.RepoRootPath, m.RepoName+".git")
if _, stderr, err := process.ExecDir(10*time.Minute,
repoPath, fmt.Sprintf("MirrorUpdate: %s", repoPath),
"git", "remote", "update"); err != nil {
return errors.New("git remote update: " + stderr)
}
m.NextUpdate = time.Now().Add(time.Duration(m.Interval) * time.Hour)
return UpdateMirror(m)
}); err != nil {
log.Error(4, "repo.MirrorUpdate: %v", err)
}
}
// MigrateRepository migrates a existing repository from other project hosting.
func MigrateRepository(u *User, name, desc string, private, mirror bool, url string) (*Repository, error) {
repo, err := CreateRepository(u, name, desc, "", "", private, mirror, false)
@@ -833,6 +832,7 @@ func TransferOwnership(u *User, newOwner string, repo *Repository) error {
// ChangeRepositoryName changes all corresponding setting from old repository name to new one.
func ChangeRepositoryName(userName, oldRepoName, newRepoName string) (err error) {
newRepoName = strings.ToLower(newRepoName)
if !IsLegalName(newRepoName) {
return ErrRepoNameIllegal
}
@@ -878,7 +878,7 @@ func UpdateRepository(repo *Repository) error {
return err
}
// DeleteRepository deletes a repository for a user or orgnaztion.
// DeleteRepository deletes a repository for a user or organization.
func DeleteRepository(uid, repoId int64, userName string) error {
repo := &Repository{Id: repoId, OwnerId: uid}
has, err := x.Get(repo)
@@ -1140,18 +1140,8 @@ type SearchOption struct {
Private bool
}
// FilterSQLInject tries to prevent SQL injection.
func FilterSQLInject(key string) string {
key = strings.TrimSpace(key)
key = strings.Split(key, " ")[0]
key = strings.Replace(key, ",", "", -1)
return key
}
// SearchRepositoryByName returns given number of repositories whose name contains keyword.
func SearchRepositoryByName(opt SearchOption) (repos []*Repository, err error) {
// Prevent SQL inject.
opt.Keyword = FilterSQLInject(opt.Keyword)
if len(opt.Keyword) == 0 {
return repos, nil
}
@@ -1183,6 +1173,87 @@ func DeleteRepositoryArchives() error {
})
}
var (
// Prevent duplicate tasks.
isMirrorUpdating = false
isGitFscking = false
)
// MirrorUpdate checks and updates mirror repositories.
func MirrorUpdate() {
if isMirrorUpdating {
return
}
isMirrorUpdating = true
defer func() { isMirrorUpdating = false }()
if err := x.Iterate(new(Mirror), func(idx int, bean interface{}) error {
m := bean.(*Mirror)
if m.NextUpdate.After(time.Now()) {
return nil
}
repoPath := filepath.Join(setting.RepoRootPath, m.RepoName+".git")
if _, stderr, err := process.ExecDir(10*time.Minute,
repoPath, fmt.Sprintf("MirrorUpdate: %s", repoPath),
"git", "remote", "update"); err != nil {
return errors.New("git remote update: " + stderr)
}
m.NextUpdate = time.Now().Add(time.Duration(m.Interval) * time.Hour)
return UpdateMirror(m)
}); err != nil {
log.Error(4, "repo.MirrorUpdate: %v", err)
}
}
// GitFsck calls 'git fsck' to check repository health.
func GitFsck() {
if isGitFscking {
return
}
isGitFscking = true
defer func() { isGitFscking = false }()
args := append([]string{"fsck"}, setting.GitFsckArgs...)
if err := x.Where("id > 0").Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
if err := repo.GetOwner(); err != nil {
return err
}
repoPath := RepoPath(repo.Owner.Name, repo.Name)
_, _, err := process.ExecDir(-1, repoPath, "Repository health check", "git", args...)
if err != nil {
desc := fmt.Sprintf("Fail to health check repository(%s)", repoPath)
log.Warn(desc)
if err = CreateRepositoryNotice(desc); err != nil {
log.Error(4, "Fail to add notice: %v", err)
}
}
return nil
}); err != nil {
log.Error(4, "repo.Fsck: %v", err)
}
}
func GitGcRepos() error {
args := append([]string{"gc"}, setting.GitGcArgs...)
return x.Where("id > 0").Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
if err := repo.GetOwner(); err != nil {
return err
}
_, stderr, err := process.ExecDir(-1, RepoPath(repo.Owner.Name, repo.Name), "Repository garbage collection", "git", args...)
if err != nil {
return fmt.Errorf("%v: %v", err, stderr)
}
return nil
})
}
// __ __ __ .__
// / \ / \_____ _/ |_ ____ | |__
// \ \/\/ /\__ \\ __\/ ___\| | \
@@ -1190,7 +1261,7 @@ func DeleteRepositoryArchives() error {
// \__/\ / (____ /__| \___ >___| /
// \/ \/ \/ \/
// Watch is connection request for receiving repository notifycation.
// Watch is connection request for receiving repository notification.
type Watch struct {
Id int64
UserId int64 `xorm:"UNIQUE(watch)"`

View File

@@ -5,18 +5,23 @@
package models
import (
"bytes"
"container/list"
"crypto/sha256"
"encoding/hex"
"errors"
"fmt"
"image"
"image/jpeg"
"os"
"path/filepath"
"strings"
"time"
"github.com/Unknwon/com"
"github.com/nfnt/resize"
"github.com/gogits/gogs/modules/avatar"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/git"
"github.com/gogits/gogs/modules/log"
@@ -45,33 +50,40 @@ var (
// User represents the object of individual and member of organization.
type User struct {
Id int64
LowerName string `xorm:"UNIQUE NOT NULL"`
Name string `xorm:"UNIQUE NOT NULL"`
FullName string
Email string `xorm:"UNIQUE NOT NULL"`
Passwd string `xorm:"NOT NULL"`
LoginType LoginType
LoginSource int64 `xorm:"NOT NULL DEFAULT 0"`
LoginName string
Type UserType
Orgs []*User `xorm:"-"`
Repos []*Repository `xorm:"-"`
Id int64
LowerName string `xorm:"UNIQUE NOT NULL"`
Name string `xorm:"UNIQUE NOT NULL"`
FullName string
Email string `xorm:"UNIQUE(s) NOT NULL"`
Passwd string `xorm:"NOT NULL"`
LoginType LoginType
LoginSource int64 `xorm:"NOT NULL DEFAULT 0"`
LoginName string
Type UserType `xorm:"UNIQUE(s)"`
Orgs []*User `xorm:"-"`
Repos []*Repository `xorm:"-"`
Location string
Website string
Rands string `xorm:"VARCHAR(10)"`
Salt string `xorm:"VARCHAR(10)"`
Created time.Time `xorm:"CREATED"`
Updated time.Time `xorm:"UPDATED"`
// Permissions.
IsActive bool
IsAdmin bool
AllowGitHook bool
// Avatar.
Avatar string `xorm:"VARCHAR(2048) NOT NULL"`
AvatarEmail string `xorm:"NOT NULL"`
UseCustomAvatar bool
// Counters.
NumFollowers int
NumFollowings int
NumStars int
NumRepos int
Avatar string `xorm:"VARCHAR(2048) NOT NULL"`
AvatarEmail string `xorm:"NOT NULL"`
Location string
Website string
IsActive bool
IsAdmin bool
AllowGitHook bool
Rands string `xorm:"VARCHAR(10)"`
Salt string `xorm:"VARCHAR(10)"`
Created time.Time `xorm:"CREATED"`
Updated time.Time `xorm:"UPDATED"`
// For organization.
Description string
@@ -96,9 +108,12 @@ func (u *User) HomeLink() string {
// AvatarLink returns user gravatar link.
func (u *User) AvatarLink() string {
if setting.DisableGravatar {
switch {
case u.UseCustomAvatar:
return setting.AppSubUrl + "/avatars/" + com.ToStr(u.Id)
case setting.DisableGravatar:
return setting.AppSubUrl + "/img/avatar_default.jpg"
} else if setting.Service.EnableCacheAvatar {
case setting.Service.EnableCacheAvatar:
return setting.AppSubUrl + "/avatar/" + u.Avatar
}
return setting.GravatarSource + u.Avatar
@@ -126,6 +141,48 @@ func (u *User) ValidtePassword(passwd string) bool {
return u.Passwd == newUser.Passwd
}
// CustomAvatarPath returns user custom avatar file path.
func (u *User) CustomAvatarPath() string {
return filepath.Join(setting.AvatarUploadPath, com.ToStr(u.Id))
}
// UploadAvatar saves custom avatar for user.
// FIXME: split uploads to different subdirs in case we have massive users.
func (u *User) UploadAvatar(data []byte) error {
u.UseCustomAvatar = true
img, _, err := image.Decode(bytes.NewReader(data))
if err != nil {
return err
}
m := resize.Resize(200, 200, img, resize.NearestNeighbor)
sess := x.NewSession()
defer sess.Close()
if err = sess.Begin(); err != nil {
return err
}
if _, err = sess.Id(u.Id).AllCols().Update(u); err != nil {
sess.Rollback()
return err
}
os.MkdirAll(setting.AvatarUploadPath, os.ModePerm)
fw, err := os.Create(u.CustomAvatarPath())
if err != nil {
sess.Rollback()
return err
}
defer fw.Close()
if err = jpeg.Encode(fw, m, nil); err != nil {
sess.Rollback()
return err
}
return sess.Commit()
}
// IsOrganization returns true if user is actually a organization.
func (u *User) IsOrganization() bool {
return u.Type == ORGANIZATION
@@ -220,8 +277,8 @@ func CreateUser(u *User) error {
}
u.LowerName = strings.ToLower(u.Name)
u.Avatar = base.EncodeMd5(u.Email)
u.AvatarEmail = u.Email
u.Avatar = avatar.HashEmail(u.AvatarEmail)
u.Rands = GetUserSalt()
u.Salt = GetUserSalt()
u.EncodePasswd()
@@ -361,6 +418,13 @@ func ChangeUserName(u *User, newUserName string) (err error) {
// UpdateUser updates user's information.
func UpdateUser(u *User) error {
has, err := x.Where("id != ?", u.Id).And("email = ?", u.Email).Get(new(User))
if err != nil {
return err
} else if has {
return ErrEmailAlreadyUsed
}
u.LowerName = strings.ToLower(u.Name)
if len(u.Location) > 255 {
@@ -373,7 +437,12 @@ func UpdateUser(u *User) error {
u.Description = u.Description[:255]
}
_, err := x.Id(u.Id).AllCols().Update(u)
if u.AvatarEmail == "" {
u.AvatarEmail = u.Email
}
u.Avatar = avatar.HashEmail(u.AvatarEmail)
_, err = x.Id(u.Id).AllCols().Update(u)
return err
}
@@ -515,43 +584,40 @@ func GetUserIdsByNames(names []string) []int64 {
return ids
}
// UserCommit represtns a commit with validation of user.
// UserCommit represents a commit with validation of user.
type UserCommit struct {
UserName string
User *User
*git.Commit
}
// ValidateCommitWithEmail chceck if author's e-mail of commit is corresponsind to a user.
func ValidateCommitWithEmail(c *git.Commit) (uname string) {
func ValidateCommitWithEmail(c *git.Commit) *User {
u, err := GetUserByEmail(c.Author.Email)
if err == nil {
uname = u.Name
if err != nil {
return nil
}
return uname
return u
}
// ValidateCommitsWithEmails checks if authors' e-mails of commits are corresponding to users.
func ValidateCommitsWithEmails(oldCommits *list.List) *list.List {
emails := map[string]string{}
emails := map[string]*User{}
newCommits := list.New()
e := oldCommits.Front()
for e != nil {
c := e.Value.(*git.Commit)
uname := ""
var u *User
if v, ok := emails[c.Author.Email]; !ok {
u, err := GetUserByEmail(c.Author.Email)
if err == nil {
uname = u.Name
}
emails[c.Author.Email] = uname
u, _ = GetUserByEmail(c.Author.Email)
emails[c.Author.Email] = u
} else {
uname = v
u = v
}
newCommits.PushBack(UserCommit{
UserName: uname,
Commit: c,
User: u,
Commit: c,
})
e = e.Next()
}
@@ -575,7 +641,6 @@ func GetUserByEmail(email string) (*User, error) {
// SearchUserByName returns given number of users whose name contains keyword.
func SearchUserByName(opt SearchOption) (us []*User, err error) {
opt.Keyword = FilterSQLInject(opt.Keyword)
if len(opt.Keyword) == 0 {
return us, nil
}
@@ -586,7 +651,7 @@ func SearchUserByName(opt SearchOption) (us []*User, err error) {
return us, err
}
// Follow is connection request for receiving user notifycation.
// Follow is connection request for receiving user notification.
type Follow struct {
Id int64
UserId int64 `xorm:"unique(follow)"`

View File

@@ -99,7 +99,7 @@ func (w *Webhook) UpdateEvent() error {
return err
}
// HasPushEvent returns true if hook enbaled push event.
// HasPushEvent returns true if hook enabled push event.
func (w *Webhook) HasPushEvent() bool {
if w.PushOnly {
return true

View File

@@ -14,7 +14,7 @@ import (
)
type MarkdownForm struct {
Text string `form:"text" binding:"Required"`
Text string `form:"text"`
Mode string `form:"mode"`
Context string `form:"context"`
}

View File

@@ -17,6 +17,7 @@ import (
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting"
"github.com/gogits/gogs/modules/uuid"
)
// SignedInId returns the id of signed in user.
@@ -60,6 +61,7 @@ func SignedInId(req *http.Request, sess session.Store) int64 {
}
// SignedInUser returns the user object of signed user.
// It returns a bool value to indicate whether user uses basic auth or not.
func SignedInUser(req *http.Request, sess session.Store) (*models.User, bool) {
if !models.HasEngine {
return nil, false
@@ -75,8 +77,25 @@ func SignedInUser(req *http.Request, sess session.Store) (*models.User, bool) {
if err != nil {
if err != models.ErrUserNotExist {
log.Error(4, "GetUserByName: %v", err)
return nil, false
}
// Check if enabled auto-registration.
if setting.Service.EnableReverseProxyAutoRegister {
u := &models.User{
Name: webAuthUser,
Email: uuid.NewV4().String() + "@localhost",
Passwd: webAuthUser,
IsActive: true,
}
if err = models.CreateUser(u); err != nil {
// FIXME: should I create a system notice?
log.Error(4, "CreateUser: %v", err)
return nil, false
} else {
return u, false
}
}
return nil, false
}
return u, false
}

View File

@@ -20,7 +20,7 @@ type Ldapsource struct {
Port int // port number
UseSSL bool // Use SSL
BaseDN string // Base DN
Attributes string // Attribut to search
Attributes string // Attribute to search
Filter string // Query filter to validate entry
MsAdSAFormat string // in the case of MS AD Simple Authen, the format to use (see: http://msdn.microsoft.com/en-us/library/cc223499.aspx)
Enabled bool // if this source is disabled
@@ -37,7 +37,7 @@ func AddSource(name string, host string, port int, usessl bool, basedn string, a
Authensource = append(Authensource, ldaphost)
}
//LoginUser : try to login an user to LDAP sources, return requested (attribut,true) if ok, ("",false) other wise
//LoginUser : try to login an user to LDAP sources, return requested (attribute,true) if ok, ("",false) other wise
//First match wins
//Returns first attribute if exists
func LoginUser(name, passwd string) (a string, r bool) {

View File

@@ -21,9 +21,9 @@ type CreateRepoForm struct {
RepoName string `form:"repo_name" binding:"Required;AlphaDashDot;MaxSize(100)"`
Private bool `form:"private"`
Description string `form:"desc" binding:"MaxSize(255)"`
AutoInit bool `form:"auto_init"`
Gitignore string `form:"gitignore"`
License string `form:"license"`
InitReadme bool `form:"init_readme"`
}
func (f *CreateRepoForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
@@ -164,7 +164,6 @@ func (f *NewReleaseForm) Validate(ctx *macaron.Context, errs binding.Errors) bin
}
type EditReleaseForm struct {
Target string `form:"tag_target" binding:"Required"`
Title string `form:"title" binding:"Required"`
Content string `form:"content" binding:"Required"`
Draft string `form:"draft"`

View File

@@ -5,6 +5,8 @@
package auth
import (
"mime/multipart"
"github.com/Unknwon/macaron"
"github.com/macaron-contrib/binding"
)
@@ -86,6 +88,15 @@ func (f *UpdateProfileForm) Validate(ctx *macaron.Context, errs binding.Errors)
return validate(errs, ctx.Data, f, ctx.Locale)
}
type UploadAvatarForm struct {
Enable bool `form:"enable"`
Avatar *multipart.FileHeader `form:"avatar"`
}
func (f *UploadAvatarForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
type ChangePasswordForm struct {
OldPassword string `form:"old_password" binding:"Required;MinSize(6);MaxSize(255)"`
Password string `form:"password" binding:"Required;MinSize(6);MaxSize(255)"`

View File

@@ -46,10 +46,14 @@ func init() {
}
// hash email to md5 string
// keep this func in order to make this package indenpent
// keep this func in order to make this package independent
func HashEmail(email string) string {
// https://en.gravatar.com/site/implement/hash/
email = strings.TrimSpace(email)
email = strings.ToLower(email)
h := md5.New()
h.Write([]byte(strings.ToLower(email)))
h.Write([]byte(email))
return hex.EncodeToString(h.Sum(nil))
}
@@ -121,7 +125,7 @@ func (this *Avatar) Encode(wr io.Writer, size int) (err error) {
if img, err = decodeImageFile(imgPath); err != nil {
return
}
m := resize.Resize(uint(size), 0, img, resize.Lanczos3)
m := resize.Resize(uint(size), 0, img, resize.NearestNeighbor)
return jpeg.Encode(wr, m, nil)
}

View File

@@ -100,10 +100,11 @@ func (options *CustomRender) Image(out *bytes.Buffer, link []byte, title []byte,
}
var (
MentionPattern = regexp.MustCompile(`@[0-9a-zA-Z_]{1,}`)
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-]*)?`)
issueIndexPattern = regexp.MustCompile(`#[0-9]+`)
MentionPattern = regexp.MustCompile(`@[0-9a-zA-Z_]{1,}`)
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-]*)?`)
issueIndexPattern = regexp.MustCompile(`#[0-9]+`)
sha1CurrentPattern = regexp.MustCompile(`\b[0-9a-f]{40}\b`)
)
func RenderSpecialLink(rawBytes []byte, urlPrefix string) []byte {
@@ -153,7 +154,22 @@ func RenderSpecialLink(rawBytes []byte, urlPrefix string) []byte {
rawBytes = bytes.Replace(rawBytes, m, []byte(fmt.Sprintf(
` <a href="%s">#%s</a>`, m, ShortSha(string(m[i+7:j])))), -1)
}
ms = issueIndexPattern.FindAll(rawBytes, -1)
rawBytes = RenderIssueIndexPattern(rawBytes, urlPrefix)
rawBytes = RenderSha1CurrentPattern(rawBytes, urlPrefix)
return rawBytes
}
func RenderSha1CurrentPattern(rawBytes []byte, urlPrefix string) []byte {
ms := sha1CurrentPattern.FindAll(rawBytes, -1)
for _, m := range ms {
rawBytes = bytes.Replace(rawBytes, m, []byte(fmt.Sprintf(
`<a href="%s/commit/%s"><code>%s</code></a>`, urlPrefix, m, ShortSha(string(m)))), -1)
}
return rawBytes
}
func RenderIssueIndexPattern(rawBytes []byte, urlPrefix string) []byte {
ms := issueIndexPattern.FindAll(rawBytes, -1)
for _, m := range ms {
rawBytes = bytes.Replace(rawBytes, m, []byte(fmt.Sprintf(
`<a href="%s/issues/%s">%s</a>`, urlPrefix, m[1:], m)), -1)

View File

@@ -47,18 +47,23 @@ func ShortSha(sha1 string) string {
return sha1
}
func ToUtf8WithErr(content []byte) (error, string) {
func DetectEncoding(content []byte) (string, error) {
detector := chardet.NewTextDetector()
result, err := detector.DetectBest(content)
return result.Charset, err
}
func ToUtf8WithErr(content []byte) (error, string) {
charset, err := DetectEncoding(content)
if err != nil {
return err, ""
}
if result.Charset == "utf8" {
if charset == "utf8" {
return nil, string(content)
}
decoder := mahonia.NewDecoder(result.Charset)
decoder := mahonia.NewDecoder(charset)
if decoder != nil {
return nil, decoder.ConvertString(string(content))
}

View File

@@ -11,7 +11,6 @@ import (
"crypto/sha1"
"encoding/base64"
"encoding/hex"
"errors"
"fmt"
"hash"
"html/template"
@@ -23,6 +22,7 @@ import (
"github.com/Unknwon/com"
"github.com/Unknwon/i18n"
"github.com/gogits/gogs/modules/avatar"
"github.com/gogits/gogs/modules/setting"
)
@@ -40,20 +40,14 @@ func EncodeSha1(str string) string {
return hex.EncodeToString(h.Sum(nil))
}
func BasicAuthDecode(encoded string) (user string, name string, err error) {
var s []byte
s, err = base64.StdEncoding.DecodeString(encoded)
func BasicAuthDecode(encoded string) (string, string, error) {
s, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return user, name, err
return "", "", err
}
a := strings.Split(string(s), ":")
if len(a) == 2 {
user, name = a[0], a[1]
} else {
err = errors.New("decode failed")
}
return user, name, err
auth := strings.SplitN(string(s), ":", 2)
return auth[0], auth[1], nil
}
func BasicAuthEncode(username, password string) string {
@@ -177,10 +171,13 @@ func CreateTimeLimitCode(data string, minutes int, startInf interface{}) string
func AvatarLink(email string) string {
if setting.DisableGravatar {
return setting.AppSubUrl + "/img/avatar_default.jpg"
} else if setting.Service.EnableCacheAvatar {
return setting.AppSubUrl + "/avatar/" + EncodeMd5(email)
}
return setting.GravatarSource + EncodeMd5(email)
gravatarHash := avatar.HashEmail(email)
if setting.Service.EnableCacheAvatar {
return setting.AppSubUrl + "/avatar/" + gravatarHash
}
return setting.GravatarSource + gravatarHash
}
// Seconds-based time units

View File

@@ -16,6 +16,7 @@ var c = New()
func NewCronContext() {
c.AddFunc("Update mirrors", "@every 1h", models.MirrorUpdate)
c.AddFunc("Deliver hooks", fmt.Sprintf("@every %dm", setting.WebhookTaskInterval), models.DeliverHooks)
c.AddFunc("Repository health check", "@every 1h", models.GitFsck)
c.Start()
}

View File

@@ -6,7 +6,7 @@ import (
"github.com/gogits/gogs/modules/asn1-ber"
)
// debbuging type
// debugging type
// - has a Printf method to write the debug output
type debugging bool

View File

@@ -162,7 +162,7 @@ func newLogger(buffer int64) *Logger {
return l
}
// SetLogger sets new logger instanse with given logger adapter and config.
// SetLogger sets new logger instance with given logger adapter and config.
func (l *Logger) SetLogger(adapter string, config string) error {
l.lock.Lock()
defer l.lock.Unlock()

View File

@@ -32,7 +32,7 @@ const (
)
// A Decoder is a function that decodes a character set, one character at a time.
// It works much like utf8.DecodeRune, but has an aditional status return value.
// It works much like utf8.DecodeRune, but has an additional status return value.
type Decoder func(p []byte) (c rune, size int, status Status)
// An Encoder is a function that encodes a character set, one character at a time.

View File

@@ -127,7 +127,10 @@ func Send(msg *Message) (int, error) {
return 0, fmt.Errorf("empty email body")
}
auth := smtp.PlainAuth("", setting.MailService.User, setting.MailService.Passwd, host[0])
var auth smtp.Auth
if len(setting.MailService.Passwd) > 0 {
auth = smtp.PlainAuth("", setting.MailService.User, setting.MailService.Passwd, host[0])
}
if msg.Massive {
// send mail to multiple emails one by one

View File

@@ -29,6 +29,12 @@ func Toggle(options *ToggleOptions) macaron.Handler {
return
}
// Checking non-logged users landing page.
if !ctx.IsSigned && ctx.Req.RequestURI == "/" && setting.LandingPageUrl != setting.LANDING_PAGE_HOME {
ctx.Redirect(string(setting.LandingPageUrl))
return
}
// Redirect to dashboard if user tries to visit any non-login page.
if options.SignOutRequire && ctx.IsSigned && ctx.Req.RequestURI != "/" {
ctx.Redirect(setting.AppSubUrl + "/")

View File

@@ -39,29 +39,25 @@ type Context struct {
IsBasicAuth bool
Repo struct {
IsOwner bool
IsTrueOwner bool
IsWatching bool
IsBranch bool
IsTag bool
IsCommit bool
IsAdmin bool // Current user is admin level.
HasAccess bool
Repository *models.Repository
Owner *models.User
Commit *git.Commit
Tag *git.Tag
GitRepo *git.Repository
BranchName string
TagName string
TreeName string
CommitId string
RepoLink string
CloneLink struct {
SSH string
HTTPS string
Git string
}
IsOwner bool
IsTrueOwner bool
IsWatching bool
IsBranch bool
IsTag bool
IsCommit bool
IsAdmin bool // Current user is admin level.
HasAccess bool
Repository *models.Repository
Owner *models.User
Commit *git.Commit
Tag *git.Tag
GitRepo *git.Repository
BranchName string
TagName string
TreeName string
CommitId string
RepoLink string
CloneLink models.CloneLink
CommitsCount int
Mirror *models.Mirror
}

View File

@@ -48,7 +48,7 @@ func OrgAssignment(redirect bool, args ...bool) macaron.Handler {
ctx.Data["Org"] = org
if ctx.IsSigned {
ctx.Org.IsOwner = org.IsOrgOwner(ctx.User.Id)
ctx.Org.IsOwner = org.IsOwnedBy(ctx.User.Id)
if ctx.Org.IsOwner {
ctx.Org.IsMember = true
ctx.Org.IsAdminTeam = true

View File

@@ -55,7 +55,7 @@ func ApiRepoAssignment() macaron.Handler {
ctx.Repo.Owner = u
// Organization owner team members are true owners as well.
if ctx.IsSigned && ctx.Repo.Owner.IsOrganization() && ctx.Repo.Owner.IsOrgOwner(ctx.User.Id) {
if ctx.IsSigned && ctx.Repo.Owner.IsOrganization() && ctx.Repo.Owner.IsOwnedBy(ctx.User.Id) {
ctx.Repo.IsTrueOwner = true
}
@@ -280,7 +280,7 @@ func RepoAssignment(redirect bool, args ...bool) macaron.Handler {
ctx.Repo.Owner = u
// Organization owner team members are true owners as well.
if ctx.IsSigned && ctx.Repo.Owner.IsOrganization() && ctx.Repo.Owner.IsOrgOwner(ctx.User.Id) {
if ctx.IsSigned && ctx.Repo.Owner.IsOrganization() && ctx.Repo.Owner.IsOwnedBy(ctx.User.Id) {
ctx.Repo.IsTrueOwner = true
}
@@ -386,12 +386,11 @@ func RepoAssignment(redirect bool, args ...bool) macaron.Handler {
ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner
ctx.Data["IsRepositoryTrueOwner"] = ctx.Repo.IsTrueOwner
if setting.SshPort != 22 {
ctx.Repo.CloneLink.SSH = fmt.Sprintf("ssh://%s@%s:%d/%s/%s.git", setting.RunUser, setting.Domain, setting.SshPort, u.LowerName, repo.LowerName)
} else {
ctx.Repo.CloneLink.SSH = fmt.Sprintf("%s@%s:%s/%s.git", setting.RunUser, setting.Domain, u.LowerName, repo.LowerName)
ctx.Repo.CloneLink, err = repo.CloneLink()
if err != nil {
ctx.Handle(500, "CloneLink", err)
return
}
ctx.Repo.CloneLink.HTTPS = fmt.Sprintf("%s%s/%s.git", setting.AppUrl, u.LowerName, repo.LowerName)
ctx.Data["CloneLink"] = ctx.Repo.CloneLink
if ctx.Repo.Repository.IsGoget {
@@ -402,6 +401,8 @@ func RepoAssignment(redirect bool, args ...bool) macaron.Handler {
// repo is bare and display enable
if ctx.Repo.Repository.IsBare {
log.Debug("Bare repository: %s", ctx.Repo.RepoLink)
// NOTE: to prevent templating error
ctx.Data["BranchName"] = ""
if displayBare {
ctx.HTML(200, "repo/bare")
}
@@ -451,7 +452,7 @@ func RequireTrueOwner() macaron.Handler {
}
}
// GitHookService checks if repsitory Git hooks service has been enabled.
// GitHookService checks if repository Git hooks service has been enabled.
func GitHookService() macaron.Handler {
return func(ctx *Context) {
if !ctx.User.AllowGitHook && !ctx.User.IsAdmin {

View File

@@ -17,10 +17,11 @@ import (
"github.com/Unknwon/com"
"github.com/Unknwon/goconfig"
"github.com/macaron-contrib/oauth2"
"github.com/macaron-contrib/session"
"github.com/gogits/gogs/modules/log"
// "github.com/gogits/gogs-ng/modules/ssh"
// "github.com/gogits/gogs/modules/ssh"
)
type Scheme string
@@ -31,6 +32,13 @@ const (
FCGI Scheme = "fcgi"
)
type LandingPage string
const (
LANDING_PAGE_HOME LandingPage = "/"
LANDING_PAGE_EXPLORE LandingPage = "/explore"
)
var (
// App settings.
AppVer string
@@ -48,6 +56,7 @@ var (
CertFile, KeyFile string
StaticRootPath string
EnableGzip bool
LandingPageUrl LandingPage
// Security settings.
InstallLock bool
@@ -66,9 +75,10 @@ var (
ScriptType string
// Picture settings.
PictureService string
GravatarSource string
DisableGravatar bool
PictureService string
AvatarUploadPath string
GravatarSource string
DisableGravatar bool
// Log settings.
LogRootPath string
@@ -99,6 +109,8 @@ var (
// Git settings.
MaxGitDiffLines int
GitFsckArgs []string
GitGcArgs []string
// I18n settings.
Langs, Names []string
@@ -196,6 +208,13 @@ func NewConfigContext() {
LogRootPath = Cfg.MustValue("log", "ROOT_PATH", path.Join(workDir, "log"))
EnableGzip = Cfg.MustBool("server", "ENABLE_GZIP")
switch Cfg.MustValue("server", "LANDING_PAGE", "home") {
case "explore":
LandingPageUrl = LANDING_PAGE_EXPLORE
default:
LandingPageUrl = LANDING_PAGE_HOME
}
InstallLock = Cfg.MustBool("security", "INSTALL_LOCK")
SecretKey = Cfg.MustValue("security", "SECRET_KEY")
LogInRememberDays = Cfg.MustInt("security", "LOGIN_REMEMBER_DAYS")
@@ -241,7 +260,7 @@ func NewConfigContext() {
log.Fatal(4, "Expect user(%s) but current user is: %s", RunUser, curUser)
}
// Determine and create root git reposiroty path.
// Determine and create root git repository path.
homeDir, err := com.HomeDir()
if err != nil {
log.Fatal(4, "Fail to get home directory: %v", err)
@@ -259,6 +278,9 @@ func NewConfigContext() {
ScriptType = Cfg.MustValue("repository", "SCRIPT_TYPE", "bash")
PictureService = Cfg.MustValueRange("picture", "SERVICE", "server", []string{"server"})
AvatarUploadPath = Cfg.MustValue("picture", "AVATAR_UPLOAD_PATH", "data/avatars")
os.MkdirAll(AvatarUploadPath, os.ModePerm)
switch Cfg.MustValue("picture", "GRAVATAR_SOURCE", "gravatar") {
case "duoshuo":
GravatarSource = "http://gravatar.duoshuo.com/avatar/"
@@ -268,6 +290,8 @@ func NewConfigContext() {
DisableGravatar = Cfg.MustBool("picture", "DISABLE_GRAVATAR")
MaxGitDiffLines = Cfg.MustInt("git", "MAX_GITDIFF_LINES", 10000)
GitFsckArgs = Cfg.MustValueArray("git", "FSCK_ARGS", " ")
GitGcArgs = Cfg.MustValueArray("git", "GC_ARGS", " ")
Langs = Cfg.MustValueArray("i18n", "LANGS", ",")
Names = Cfg.MustValueArray("i18n", "NAMES", ",")
@@ -276,15 +300,15 @@ func NewConfigContext() {
}
var Service struct {
RegisterEmailConfirm bool
DisableRegistration bool
RequireSignInView bool
EnableCacheAvatar bool
EnableNotifyMail bool
EnableReverseProxyAuth bool
LdapAuth bool
ActiveCodeLives int
ResetPwdCodeLives int
RegisterEmailConfirm bool
DisableRegistration bool
RequireSignInView bool
EnableCacheAvatar bool
EnableNotifyMail bool
EnableReverseProxyAuth bool
EnableReverseProxyAutoRegister bool
ActiveCodeLives int
ResetPwdCodeLives int
}
func newService() {
@@ -294,6 +318,7 @@ func newService() {
Service.RequireSignInView = Cfg.MustBool("service", "REQUIRE_SIGNIN_VIEW")
Service.EnableCacheAvatar = Cfg.MustBool("service", "ENABLE_CACHE_AVATAR")
Service.EnableReverseProxyAuth = Cfg.MustBool("service", "ENABLE_REVERSE_PROXY_AUTHENTICATION")
Service.EnableReverseProxyAutoRegister = Cfg.MustBool("service", "ENABLE_REVERSE_PROXY_AUTO_REGISTERATION")
}
var logLevels = map[string]string{
@@ -415,9 +440,8 @@ type Mailer struct {
}
type OauthInfo struct {
ClientId, ClientSecret string
Scopes string
AuthUrl, TokenUrl string
oauth2.Options
AuthUrl, TokenUrl string
}
// Oauther represents oauth service.
@@ -484,5 +508,5 @@ func NewServices() {
newRegisterMailService()
newNotifyMailService()
newWebhookService()
// ssh.Listen("2022")
// ssh.Listen("2222")
}

View File

@@ -7,12 +7,12 @@ package social
import (
"encoding/json"
"io/ioutil"
"net/http"
"net/url"
"strconv"
"strings"
oauth "github.com/gogits/oauth2"
"github.com/macaron-contrib/oauth2"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/log"
@@ -27,16 +27,11 @@ type BasicUserInfo struct {
type SocialConnector interface {
Type() int
SetRedirectUrl(string)
UserInfo(*oauth.Token, *url.URL) (*BasicUserInfo, error)
AuthCodeURL(string) string
Exchange(string) (*oauth.Token, error)
UserInfo(*oauth2.Token, *url.URL) (*BasicUserInfo, error)
}
var (
SocialBaseUrl = "/user/login"
SocialMap = make(map[string]SocialConnector)
SocialMap = make(map[string]SocialConnector)
)
func NewOauthService() {
@@ -44,27 +39,34 @@ func NewOauthService() {
return
}
oauth2.AppSubUrl = setting.AppSubUrl
setting.OauthService = &setting.Oauther{}
setting.OauthService.OauthInfos = make(map[string]*setting.OauthInfo)
socialConfigs := make(map[string]*oauth.Config)
socialConfigs := make(map[string]*oauth2.Options)
allOauthes := []string{"github", "google", "qq", "twitter", "weibo"}
// Load all OAuth config data.
for _, name := range allOauthes {
setting.OauthService.OauthInfos[name] = &setting.OauthInfo{
ClientId: setting.Cfg.MustValue("oauth."+name, "CLIENT_ID"),
ClientSecret: setting.Cfg.MustValue("oauth."+name, "CLIENT_SECRET"),
Scopes: setting.Cfg.MustValue("oauth."+name, "SCOPES"),
AuthUrl: setting.Cfg.MustValue("oauth."+name, "AUTH_URL"),
TokenUrl: setting.Cfg.MustValue("oauth."+name, "TOKEN_URL"),
if !setting.Cfg.MustBool("oauth."+name, "ENABLED") {
continue
}
socialConfigs[name] = &oauth.Config{
ClientId: setting.OauthService.OauthInfos[name].ClientId,
setting.OauthService.OauthInfos[name] = &setting.OauthInfo{
Options: oauth2.Options{
ClientID: setting.Cfg.MustValue("oauth."+name, "CLIENT_ID"),
ClientSecret: setting.Cfg.MustValue("oauth."+name, "CLIENT_SECRET"),
Scopes: setting.Cfg.MustValueArray("oauth."+name, "SCOPES", " "),
PathLogin: "/user/login/oauth2/" + name,
PathCallback: setting.AppSubUrl + "/user/login/" + name,
RedirectURL: setting.AppUrl + "user/login/" + name,
},
AuthUrl: setting.Cfg.MustValue("oauth."+name, "AUTH_URL"),
TokenUrl: setting.Cfg.MustValue("oauth."+name, "TOKEN_URL"),
}
socialConfigs[name] = &oauth2.Options{
ClientID: setting.OauthService.OauthInfos[name].ClientID,
ClientSecret: setting.OauthService.OauthInfos[name].ClientSecret,
RedirectURL: strings.TrimSuffix(setting.AppUrl, "/") + SocialBaseUrl + name,
Scope: setting.OauthService.OauthInfos[name].Scopes,
AuthURL: setting.OauthService.OauthInfos[name].AuthUrl,
TokenURL: setting.OauthService.OauthInfos[name].TokenUrl,
Scopes: setting.OauthService.OauthInfos[name].Scopes,
}
}
enabledOauths := make([]string, 0, 10)
@@ -91,11 +93,11 @@ func NewOauthService() {
}
// Twitter.
if setting.Cfg.MustBool("oauth.twitter", "ENABLED") {
setting.OauthService.Twitter = true
newTwitterOauth(socialConfigs["twitter"])
enabledOauths = append(enabledOauths, "Twitter")
}
// if setting.Cfg.MustBool("oauth.twitter", "ENABLED") {
// setting.OauthService.Twitter = true
// newTwitterOauth(socialConfigs["twitter"])
// enabledOauths = append(enabledOauths, "Twitter")
// }
// Weibo.
if setting.Cfg.MustBool("oauth.weibo", "ENABLED") {
@@ -115,38 +117,25 @@ func NewOauthService() {
// \/ \/ \/
type SocialGithub struct {
Token *oauth.Token
*oauth.Transport
opts *oauth2.Options
}
func newGitHubOauth(opts *oauth2.Options) {
SocialMap["github"] = &SocialGithub{opts}
}
func (s *SocialGithub) Type() int {
return int(models.GITHUB)
}
func newGitHubOauth(config *oauth.Config) {
SocialMap["github"] = &SocialGithub{
Transport: &oauth.Transport{
Config: config,
Transport: http.DefaultTransport,
},
}
}
func (s *SocialGithub) SetRedirectUrl(url string) {
s.Transport.Config.RedirectURL = url
}
func (s *SocialGithub) UserInfo(token *oauth.Token, _ *url.URL) (*BasicUserInfo, error) {
transport := &oauth.Transport{
Token: token,
}
func (s *SocialGithub) UserInfo(token *oauth2.Token, _ *url.URL) (*BasicUserInfo, error) {
transport := s.opts.NewTransportFromToken(token)
var data struct {
Id int `json:"id"`
Name string `json:"login"`
Email string `json:"email"`
}
var err error
r, err := transport.Client().Get(s.Transport.Scope)
r, err := transport.Client().Get("https://api.github.com/user")
if err != nil {
return nil, err
}
@@ -169,38 +158,25 @@ func (s *SocialGithub) UserInfo(token *oauth.Token, _ *url.URL) (*BasicUserInfo,
// \/ /_____/ \/
type SocialGoogle struct {
Token *oauth.Token
*oauth.Transport
opts *oauth2.Options
}
func (s *SocialGoogle) Type() int {
return int(models.GOOGLE)
}
func newGoogleOauth(config *oauth.Config) {
SocialMap["google"] = &SocialGoogle{
Transport: &oauth.Transport{
Config: config,
Transport: http.DefaultTransport,
},
}
func newGoogleOauth(opts *oauth2.Options) {
SocialMap["google"] = &SocialGoogle{opts}
}
func (s *SocialGoogle) SetRedirectUrl(url string) {
s.Transport.Config.RedirectURL = url
}
func (s *SocialGoogle) UserInfo(token *oauth.Token, _ *url.URL) (*BasicUserInfo, error) {
transport := &oauth.Transport{Token: token}
func (s *SocialGoogle) UserInfo(token *oauth2.Token, _ *url.URL) (*BasicUserInfo, error) {
transport := s.opts.NewTransportFromToken(token)
var data struct {
Id string `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
var err error
reqUrl := "https://www.googleapis.com/oauth2/v1/userinfo"
r, err := transport.Client().Get(reqUrl)
r, err := transport.Client().Get("https://www.googleapis.com/userinfo/v2/me")
if err != nil {
return nil, err
}
@@ -223,62 +199,35 @@ func (s *SocialGoogle) UserInfo(token *oauth.Token, _ *url.URL) (*BasicUserInfo,
// \__> \__>
type SocialTencent struct {
Token *oauth.Token
*oauth.Transport
reqUrl string
opts *oauth2.Options
}
func newTencentOauth(opts *oauth2.Options) {
SocialMap["qq"] = &SocialTencent{opts}
}
func (s *SocialTencent) Type() int {
return int(models.QQ)
}
func newTencentOauth(config *oauth.Config) {
SocialMap["qq"] = &SocialTencent{
reqUrl: "https://open.t.qq.com/api/user/info",
Transport: &oauth.Transport{
Config: config,
Transport: http.DefaultTransport,
},
}
}
func (s *SocialTencent) SetRedirectUrl(url string) {
s.Transport.Config.RedirectURL = url
}
func (s *SocialTencent) UserInfo(token *oauth.Token, URL *url.URL) (*BasicUserInfo, error) {
var data struct {
Data struct {
Id string `json:"openid"`
Name string `json:"name"`
Email string `json:"email"`
} `json:"data"`
}
var err error
// https://open.t.qq.com/api/user/info?
//oauth_consumer_key=APP_KEY&
//access_token=ACCESSTOKEN&openid=openid
//clientip=CLIENTIP&oauth_version=2.a
//scope=all
var urls = url.Values{
"oauth_consumer_key": {s.Transport.Config.ClientId},
"access_token": {token.AccessToken},
"openid": URL.Query()["openid"],
"oauth_version": {"2.a"},
"scope": {"all"},
}
r, err := http.Get(s.reqUrl + "?" + urls.Encode())
func (s *SocialTencent) UserInfo(token *oauth2.Token, URL *url.URL) (*BasicUserInfo, error) {
r, err := http.Get("https://graph.z.qq.com/moc2/me?access_token=" + url.QueryEscape(token.AccessToken))
if err != nil {
return nil, err
}
defer r.Body.Close()
if err = json.NewDecoder(r.Body).Decode(&data); err != nil {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
return nil, err
}
vals, err := url.ParseQuery(string(body))
if err != nil {
return nil, err
}
return &BasicUserInfo{
Identity: data.Data.Id,
Name: data.Data.Name,
Email: data.Data.Email,
Identity: vals.Get("openid"),
}, nil
}
@@ -289,54 +238,54 @@ func (s *SocialTencent) UserInfo(token *oauth.Token, URL *url.URL) (*BasicUserIn
// |____| \/\_/ |__||__| |__| \___ >__|
// \/
type SocialTwitter struct {
Token *oauth.Token
*oauth.Transport
}
// type SocialTwitter struct {
// Token *oauth2.Token
// *oauth2.Transport
// }
func (s *SocialTwitter) Type() int {
return int(models.TWITTER)
}
// func (s *SocialTwitter) Type() int {
// return int(models.TWITTER)
// }
func newTwitterOauth(config *oauth.Config) {
SocialMap["twitter"] = &SocialTwitter{
Transport: &oauth.Transport{
Config: config,
Transport: http.DefaultTransport,
},
}
}
// func newTwitterOauth(config *oauth2.Config) {
// SocialMap["twitter"] = &SocialTwitter{
// Transport: &oauth.Transport{
// Config: config,
// Transport: http.DefaultTransport,
// },
// }
// }
func (s *SocialTwitter) SetRedirectUrl(url string) {
s.Transport.Config.RedirectURL = url
}
// func (s *SocialTwitter) SetRedirectUrl(url string) {
// s.Transport.Config.RedirectURL = url
// }
//https://github.com/mrjones/oauth
func (s *SocialTwitter) UserInfo(token *oauth.Token, _ *url.URL) (*BasicUserInfo, error) {
// transport := &oauth.Transport{Token: token}
// var data struct {
// Id string `json:"id"`
// Name string `json:"name"`
// Email string `json:"email"`
// }
// var err error
// //https://github.com/mrjones/oauth
// func (s *SocialTwitter) UserInfo(token *oauth2.Token, _ *url.URL) (*BasicUserInfo, error) {
// // transport := &oauth.Transport{Token: token}
// // var data struct {
// // Id string `json:"id"`
// // Name string `json:"name"`
// // Email string `json:"email"`
// // }
// // var err error
// reqUrl := "https://www.googleapis.com/oauth2/v1/userinfo"
// r, err := transport.Client().Get(reqUrl)
// if err != nil {
// return nil, err
// }
// defer r.Body.Close()
// if err = json.NewDecoder(r.Body).Decode(&data); err != nil {
// return nil, err
// }
// return &BasicUserInfo{
// Identity: data.Id,
// Name: data.Name,
// Email: data.Email,
// }, nil
return nil, nil
}
// // reqUrl := "https://www.googleapis.com/oauth2/v1/userinfo"
// // r, err := transport.Client().Get(reqUrl)
// // if err != nil {
// // return nil, err
// // }
// // defer r.Body.Close()
// // if err = json.NewDecoder(r.Body).Decode(&data); err != nil {
// // return nil, err
// // }
// // return &BasicUserInfo{
// // Identity: data.Id,
// // Name: data.Name,
// // Email: data.Email,
// // }, nil
// return nil, nil
// }
// __ __ ._____.
// / \ / \ ____ |__\_ |__ ____
@@ -346,37 +295,25 @@ func (s *SocialTwitter) UserInfo(token *oauth.Token, _ *url.URL) (*BasicUserInfo
// \/ \/ \/
type SocialWeibo struct {
Token *oauth.Token
*oauth.Transport
opts *oauth2.Options
}
func newWeiboOauth(opts *oauth2.Options) {
SocialMap["weibo"] = &SocialWeibo{opts}
}
func (s *SocialWeibo) Type() int {
return int(models.WEIBO)
}
func newWeiboOauth(config *oauth.Config) {
SocialMap["weibo"] = &SocialWeibo{
Transport: &oauth.Transport{
Config: config,
Transport: http.DefaultTransport,
},
}
}
func (s *SocialWeibo) SetRedirectUrl(url string) {
s.Transport.Config.RedirectURL = url
}
func (s *SocialWeibo) UserInfo(token *oauth.Token, _ *url.URL) (*BasicUserInfo, error) {
transport := &oauth.Transport{Token: token}
func (s *SocialWeibo) UserInfo(token *oauth2.Token, _ *url.URL) (*BasicUserInfo, error) {
transport := s.opts.NewTransportFromToken(token)
var data struct {
Name string `json:"name"`
}
var err error
var urls = url.Values{
"access_token": {token.AccessToken},
"uid": {token.Extra["id_token"]},
"uid": {token.Extra("uid")},
}
reqUrl := "https://api.weibo.com/2/users/show.json"
r, err := transport.Client().Get(reqUrl + "?" + urls.Encode())
@@ -384,11 +321,12 @@ func (s *SocialWeibo) UserInfo(token *oauth.Token, _ *url.URL) (*BasicUserInfo,
return nil, err
}
defer r.Body.Close()
if err = json.NewDecoder(r.Body).Decode(&data); err != nil {
return nil, err
}
return &BasicUserInfo{
Identity: token.Extra["id_token"],
Identity: token.Extra("uid"),
Name: data.Name,
}, nil
}

View File

@@ -13,9 +13,8 @@ import (
"os/exec"
"strings"
"code.google.com/p/go.crypto/ssh"
"github.com/Unknwon/com"
"golang.org/x/crypto/ssh"
"github.com/gogits/gogs/modules/log"
)
@@ -35,8 +34,11 @@ func handleServerConn(keyId string, chans <-chan ssh.NewChannel) {
go func(in <-chan *ssh.Request) {
defer channel.Close()
for req := range in {
ok, payload := false, strings.TrimLeft(string(req.Payload), "\x00")
ok, payload := false, strings.TrimLeft(string(req.Payload), "\x00&")
fmt.Println("Request:", req.Type, req.WantReply, payload)
if req.WantReply {
fmt.Println(req.Reply(true, nil))
}
switch req.Type {
case "env":
args := strings.Split(strings.Replace(payload, "\x00", "", -1), "\v")
@@ -54,7 +56,7 @@ func handleServerConn(keyId string, chans <-chan ssh.NewChannel) {
case "exec":
os.Setenv("SSH_ORIGINAL_COMMAND", strings.TrimLeft(payload, "'("))
log.Info("Payload: %v", strings.TrimLeft(payload, "'("))
cmd := exec.Command("/Users/jiahuachen/Applications/Go/src/github.com/gogits/gogs-ng/gogs-ng", "serv", "key-"+keyId)
cmd := exec.Command("/Users/jiahuachen/Applications/Go/src/github.com/gogits/gogs/gogs", "serv", "key-"+keyId)
cmd.Stdout = channel
cmd.Stdin = channel
cmd.Stderr = channel.Stderr()
@@ -65,7 +67,6 @@ func handleServerConn(keyId string, chans <-chan ssh.NewChannel) {
}
}
fmt.Println("Done:", ok)
req.Reply(ok, nil) // BUG: Git on Mac seems not know this reply and hang?
}
fmt.Println("Done!!!")
}(requests)
@@ -101,7 +102,7 @@ func Listen(port string) {
config := &ssh.ServerConfig{
PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
// keyCache[string(ssh.MarshalAuthorizedKey(key))] = 2
return &ssh.Permissions{Extensions: map[string]string{"key-id": "2"}}, nil
return &ssh.Permissions{Extensions: map[string]string{"key-id": "1"}}, nil
},
}

View File

@@ -2,18 +2,6 @@
set -e
# summary of how this script can be called:
# * <postinst> `configure' <most-recently-configured-version>
# * <old-postinst> `abort-upgrade' <new version>
# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
# <new-version>
# * <postinst> `abort-remove'
# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
# <failed-install-package> <version> `removing'
# <conflicting-package> <version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
APP_NAME="gogs"
CLI="${APP_NAME}"
APP_USER=$(${CLI} config:get APP_USER)
@@ -21,28 +9,27 @@ APP_GROUP=$(${CLI} config:get APP_GROUP)
APP_CONFIG="/etc/${APP_NAME}/conf/app.ini"
case "$1" in
abort-upgrade|abort-remove|abort-deconfigure)
exit 0
;;
configure)
configure|*)
mkdir -p $(dirname ${APP_CONFIG})
chown ${APP_USER}.${APP_GROUP} $(dirname ${APP_CONFIG})
[ -f ${APP_CONFIG} ] || ${CLI} run cp conf/app.ini ${APP_CONFIG}
${CLI} config:set USER=${APP_USER}
${CLI} config:set GOGS_CUSTOM="/etc/${APP_NAME}"
PORT=$(${CLI} config:get PORT || echo "6000")
sed -i "s|HTTP_PORT = 3000|HTTP_PORT = ${PORT}|" ${APP_CONFIG}
sed -i "s|RUN_USER = git|RUN_USER = ${APP_USER}|" ${APP_CONFIG}
sed -i "s|RUN_MODE = dev|RUN_MODE = prod|" ${APP_CONFIG}
# setup symlink towards custom conf
mkdir -p /opt/${APP_NAME}/custom/conf
chown -R ${APP_USER}.${APP_GROUP} /opt/${APP_NAME}/custom
ln -f -s ${APP_CONFIG} /opt/${APP_NAME}/custom/conf/app.ini
# scale
${CLI} scale web=1 || true
;;
abort-upgrade|abort-remove|abort-deconfigure)
exit 0
;;
*)
echo "postinst called with unknown argument \`$1'" >&2
exit 1
;;
esac

View File

@@ -303,6 +303,9 @@ var Gogits = {};
// api working
Gogits.getUsers = function (val, $target) {
var notEmpty = function (str) {
return str && str.length > 0;
}
$.ajax({
url: '/api/v1/users/search?q=' + val,
dataType: "json",
@@ -310,7 +313,11 @@ var Gogits = {};
if (json.ok && json.data.length) {
var html = '';
$.each(json.data, function (i, item) {
html += '<li><img src="' + item.avatar + '">' + item.username + '</li>';
html += '<li><img src="' + item.avatar + '">' + item.username;
if (notEmpty(item.full_name)) {
html += ' (' + item.full_name + ')';
}
html += '</li>';
});
$target.toggleShow();
$target.find('ul').html(html);

View File

@@ -340,6 +340,30 @@ img.avatar-100 {
padding: 5px 15px;
color: #777;
}
.markdown table {
width: 100%;
overflow: auto;
word-break: normal;
margin: 15px 0;
border-collapse: collapse;
border-spacing: 0;
display: block;
}
.markdown table th {
font-weight: 700;
}
.markdown table th,
.markdown table td {
border: 1px solid #DDD;
padding: 6px 13px !important;
}
.markdown table tr {
background-color: #FFF;
border-top: 1px solid #CCC;
}
.markdown table tr:nth-child(2n) {
background-color: #F8F8F8;
}
.markdown a {
color: #428BCA;
}
@@ -376,29 +400,6 @@ img.avatar-100 {
.markdown h4 {
font-size: 18px;
}
.markdown table {
border-collapse: collapse;
border-spacing: 0;
display: block;
overflow: auto;
width: 100%;
margin: 0 0 9px;
}
.markdown table th {
font-weight: 700;
}
.markdown table th,
.markdown table td {
border: 1px solid #DDD;
padding: 6px 13px;
}
.markdown table tr {
background-color: #FFF;
border-top: 1px solid #CCC;
}
.markdown table tr:nth-child(2n) {
background-color: #f8f8f8;
}
.markdown dl dt {
font-style: italic;
margin-top: 9px;
@@ -1071,7 +1072,8 @@ The register and sign-in page style
text-overflow: clip;
}
#repo-content {
padding: 18px 0;
padding-top: 18px;
padding-bottom: 18px;
}
.repo-wide-wrapper {
padding: 18px;
@@ -1352,31 +1354,54 @@ The register and sign-in page style
#repo-create-cancel {
margin-left: 4em;
}
#release-new-target-branch-list,
#repo-create-owner-list {
top: 30px;
left: 0;
width: auto;
max-width: 300px;
}
#release-new-target-branch-list .octicon,
#repo-create-owner-list .octicon {
margin-right: 12px;
opacity: 0;
}
#release-new-target-branch-list .avatar,
#repo-create-owner-list .avatar {
width: 20px;
height: 20px;
}
#release-new-target-branch-list li,
#repo-create-owner-list li {
white-space: nowrap;
}
#release-new-target-branch-list li.checked .octicon,
#repo-create-owner-list li.checked .octicon {
opacity: 1;
}
#release-new-target-branch-list li a,
#repo-create-owner-list li a {
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
overflow: hidden;
}
#release-new-target-branch-list {
margin-top: -1px;
min-width: 150px;
}
#release-new-title {
margin-top: 10px;
}
#release-new-content {
width: 100%;
}
#release-preview-btn .btn {
border-left: 0;
}
#release-preview.markdown {
margin-top: 5px;
background-color: transparent;
}
.file-name {
margin-left: 1em;
}
@@ -1416,7 +1441,7 @@ The register and sign-in page style
}
.code-view .lines-num span {
font-family: Monaco, Menlo, Consolas, "Courier New", monospace;
line-height: 1.6;
line-height: 20px;
padding: 0 10px;
cursor: pointer;
display: block;
@@ -1510,6 +1535,9 @@ The register and sign-in page style
.commit-list .message span {
max-width: 500px;
}
.commit-message {
white-space: pre-wrap;
}
.diff-head-box {
margin-top: 10px;
}
@@ -1618,6 +1646,87 @@ The register and sign-in page style
margin-left: 44px;
margin-top: -15px;
}
#release h4 {
font-size: 18px;
}
#release h4 small {
font-weight: 400;
line-height: 1;
color: #999;
}
#release #release-head {
margin-top: 0;
margin-bottom: 0;
padding-bottom: 20px;
border-bottom: 1px solid #DDD;
}
#release #release-head .btn {
margin-left: 10px;
}
#release .release-item > div {
padding-top: 20px;
padding-bottom: 20px;
}
#release .release-item .label-green:hover {
background-color: #65ad4e;
}
#release .release-item .release-meta {
position: relative;
float: left;
padding-right: 15px;
}
#release .release-item .tag,
#release .release-item .commit {
display: block;
margin-top: 12px;
line-height: 20px;
}
#release .release-item .release-detail {
margin-top: -1px;
border-left: 1px solid #DDD;
position: relative;
float: left;
padding-left: 15px;
}
#release .release-item .title {
line-height: 25px;
margin-top: 0;
}
#release .release-item p.info {
line-height: 20px;
color: #666;
margin-bottom: 15px;
}
#release .release-item p.info > * {
margin-right: 10px;
}
#release .release-item .author img {
margin-top: -3px;
}
#release .release-item div.desc {
margin-bottom: 25px;
}
#release .release-item div.desc.markdown {
background-color: transparent;
}
#release .release-item .download a {
margin-right: 10px;
}
#release .release-item .dot {
width: 9px;
height: 9px;
background-color: #ccc;
z-index: 999;
position: absolute;
display: block;
left: -6px;
top: 27px;
border-radius: 6px;
border: 1px solid #FFF;
}
#release #release-new-form {
padding-top: 15px;
}
#admin-wrapper,
#setting-wrapper {
padding-bottom: 100px;
@@ -2019,10 +2128,14 @@ textarea#issue-add-content {
#issue-list-nav li.right {
margin-left: 4px;
}
#issue-new > a {
#issue-new > a,
#label-new > a,
#milestone-new > a {
padding: 0 !important;
}
#issue-new > a button {
#issue-new > a button,
#label-new > a button,
#milestone-new > a button {
height: 29px;
}
#issue-list-menu {
@@ -2059,10 +2172,6 @@ textarea#issue-add-content {
font-size: 15px;
margin: 0 6px;
}
#issue-list .item .index-num,
#pull-list .item .index-num {
padding: .25em .6em;
}
#issue-list .comment,
#pull-list .comment {
color: #666;
@@ -2070,10 +2179,6 @@ textarea#issue-add-content {
top: 6px;
right: 0;
}
#issue-list .issue-label,
#pull-list .issue-label {
padding: .25em .6em;
}
#issue-list .issue-label a,
#pull-list .issue-label a {
color: #FFF;
@@ -2090,6 +2195,53 @@ textarea#issue-add-content {
#pull-list .desc a:hover {
color: #03a2ef;
}
#issue-list-filter .drop > a {
width: 90px;
padding: 0;
margin-left: 12px;
text-align: center;
}
#issue-list-filter .drop-down {
z-index: 999;
width: 236px;
left: -158px;
top: 22px;
padding: 0 12px;
}
#issue-list-filter .drop-down h4 {
line-height: 40px;
border-bottom: 1px solid #CCC;
margin-bottom: 0;
}
#issue-list-filter .drop-down li {
line-height: 30px;
border-bottom: 1px dashed #EEE;
padding-left: 9px;
}
#issue-list-filter .drop-down li:hover {
background-color: #fcffec;
}
#issue-list-filter .drop-down > ul > li > a {
display: block;
}
#issue-list-filter .labels .color {
margin-top: 8px;
display: inline-block;
width: 12px;
height: 12px;
background-color: red;
margin-right: 9px;
margin-left: 9px;
}
#issue-list-filter .labels .name {
vertical-align: top;
display: inline-block;
color: #444;
}
#issue-list-filter .milestones a {
color: #444;
font-weight: bold;
}
#issue-list-pager {
margin: 18px 0 24px 0;
font-size: 14px;
@@ -2127,6 +2279,86 @@ textarea#issue-add-content {
margin-bottom: 12px;
border-bottom: 1px dashed #AAA;
}
#label-add-form {
padding: 18px 0;
border-bottom: 1px solid #DDD;
}
#label-add-form .ipt {
font-size: 14px;
}
#label-add-form .ipt[name=name] {
width: 300px;
}
#label-add-form .btn {
height: 33px;
font-size: 14px;
margin-left: 12px;
}
#label-color-drop .ipt {
width: 100px;
}
#label-color-drop .drop-down {
width: 128px;
top: 22px;
left: 50px;
padding: 12px;
line-height: 16px;
}
#label-color-drop .drop-down a.color {
width: 16px;
height: 16px;
display: inline-block;
}
#label-color-drop label {
width: 24px;
height: 24px;
display: inline-block;
margin: 0 1em;
vertical-align: middle;
}
#milestone-list {
padding-top: 6px;
}
#milestone-list .title-text {
font-size: 16px;
}
#milestone-list .desc {
color: #999;
line-height: 30px;
}
#milestone-list .content {
width: 400px;
}
#milestone-list .item {
padding-bottom: 18px;
margin-bottom: 18px;
border-bottom: 1px dashed #AAA;
position: relative;
}
#milestone-list .action {
position: absolute;
top: 0;
right: 0;
}
#milestone-list .status-bar > .bar {
margin: -2px 8px 0 8px;
width: 360px;
background-color: #DDD;
height: 14px;
vertical-align: middle;
}
#milestone-list .status-bar .opening {
background-color: #65ad4e;
width: 40%;
height: 14px;
vertical-align: top;
}
#milestone-list .action-bar {
margin-top: 8px;
}
#milestone-list .action-bar a {
margin-left: 12px;
}
.org-header-alert .alert {
margin-top: 10px;
}
@@ -2414,5 +2646,5 @@ textarea#issue-add-content {
border-bottom: 2px solid #D26911;
}
#profile-body {
margin-left: 10px;
margin-left: 20px;
}

View File

@@ -379,6 +379,7 @@ dt {
}
.btn-large {
font-size: 14.4px;
padding: .4em .9em;
}
.btn-green {
background-color: #65ad4e;

View File

@@ -2,6 +2,7 @@
// @codekit-prepend "lib/lib.js"
// @codekit-prepend "utils/tabs.js"
// @codekit-prepend "utils/preview.js"
// @codekit-prepend "gogs/issue_label.js"
// @codekit-prepend "lib/jquery.tipsy.js"
var Gogs = {};
@@ -203,6 +204,9 @@ var Gogs = {};
// Search users by keyword.
Gogs.searchUsers = function (val, $target) {
var notEmpty = function (str) {
return str && str.length > 0;
}
$.ajax({
url: Gogs.AppSubUrl + '/api/v1/users/search?q=' + val,
dataType: "json",
@@ -210,7 +214,11 @@ var Gogs = {};
if (json.ok && json.data.length) {
var html = '';
$.each(json.data, function (i, item) {
html += '<li><a><img src="' + item.avatar_url + '">' + item.username + '</a></li>';
html += '<li><a><img src="' + item.avatar_url + '">' + item.username;
if (notEmpty(item.full_name)) {
html += ' (' + item.full_name + ')';
}
html += '</a></li>';
});
$target.html(html);
$target.toggleShow();
@@ -395,6 +403,16 @@ function initRepo() {
$clone_btn.tipsy({
fade: true
});
// Markdown preview.
$('.markdown-preview').click(function() {
var $this = $(this);
$this.toggleAjax(function (resp) {
$($this.data("preview")).html(resp);
}, function () {
$($this.data("preview")).html("no content");
})
});
}
// when user changes hook type, hide/show proper divs
@@ -415,6 +433,18 @@ function initHookTypeChange() {
});
}
function initRepoRelease() {
$('#release-new-target-branch-list li').click(function() {
if (!$(this).hasClass('checked')) {
$('#repo-branch-current').text($(this).text());
$('#tag-target').val($(this).text());
$(this).parent().find('.checked').removeClass('checked');
$(this).addClass('checked');
}
})
}
function initRepoSetting() {
// Options.
// Confirmation of changing repository name.
@@ -745,8 +775,12 @@ $(document).ready(function () {
initRepoCreate();
}
if ($('#repo-header').length) {
initTimeSwitch();
initRepo();
}
if ($('#release').length) {
initRepoRelease();
}
if ($('#repo-setting').length) {
initRepoSetting();
}
@@ -811,3 +845,7 @@ function homepage() {
$('#promo-form').attr('action', Gogs.AppSubUrl + '/user/sign_up');
});
}
String.prototype.endsWith = function (suffix) {
return this.indexOf(suffix, this.length - suffix.length) !== -1;
};

View File

@@ -0,0 +1,43 @@
// when dom ready, init issue label events
$(document).ready(function(){
var labelColors = ["#e11d21","#EB6420","#FBCA04","#009800",
"#006B75","#207DE5","#0052cc","#53E917",
"#F6C6C7","#FAD8C7","#FEF2C0","#BFE5BF",
"#BFDADC","#C7DEF8","#BFD4F2","#D4C5F9"];
var colorDropHtml = "";
labelColors.forEach(function(item){
colorDropHtml += '<a class="color" style="background-color:'+item+'" data-color-hex="'+item+'"></a>';
});
// render label color input
var color_input = $('#label-add-color');
var color_label = $('#label-color-drop label');
color_label.css("background-color",labelColors[0]);
color_input.val(labelColors[0]);
// render label color drop
$('#label-color-drop .drop-down')
.html(colorDropHtml)
.on("click","a",function(){
var color = $(this).data("color-hex");
color_label.css("background-color",color);
color_input.val(color);
});
// color drop visible
var form = $('#label-add-form');
$('#label-new-btn').on("click",function(){
if(form.hasClass("hidden")){
form.removeClass("hidden");
}
});
$('#label-cancel-btn').on("click",function(){
form.addClass("hidden");
})
});

File diff suppressed because one or more lines are too long

View File

@@ -243,7 +243,9 @@ textarea#issue-add-content {
}
}
// new issue button
#issue-new {
#issue-new,
#label-new,
#milestone-new{
> a {
padding: 0 !important;
button {
@@ -294,9 +296,6 @@ textarea#issue-add-content {
font-size: 15px;
margin: 0 6px;
}
.index-num {
padding: .25em .6em;
}
}
.comment {
color: #666;
@@ -305,7 +304,6 @@ textarea#issue-add-content {
right: 0;
}
.issue-label {
padding: .25em .6em;
a {
color: #FFF;
}
@@ -320,6 +318,60 @@ textarea#issue-add-content {
}
}
}
// issue list filter
#issue-list-filter{
.drop > a{
width: 90px;
padding: 0;
margin-left: 12px;
text-align: center;
}
.drop-down{
z-index: 999;
width: 236px;
left:-158px; // 260 - 90 - 12
top:22px;
padding: 0 12px;
h4{
line-height: 40px;
border-bottom: 1px solid #CCC;
margin-bottom: 0;
}
li{
line-height: 30px;
border-bottom: 1px dashed #EEE;
padding-left: 9px;
&:hover{
background-color: #fcffec;
}
}
> ul > li > a{
display: block;
}
}
.labels{
.color{
margin-top: 8px;
display: inline-block;
width: 12px;
height: 12px;
background-color: red;
margin-right: 9px;
margin-left: 9px;
}
.name{
vertical-align: top;
display: inline-block;
color: #444;
}
}
.milestones{
a{
color: #444;
font-weight: bold;
}
}
}
// issue list pager
#issue-list-pager {
margin: 18px 0 24px 0;
@@ -363,4 +415,91 @@ textarea#issue-add-content {
margin-bottom: 12px;
border-bottom: 1px dashed #AAA;
}
}
// label add form
#label-add-form{
padding: 18px 0;
border-bottom: 1px solid #DDD;
.ipt{
font-size: 14px;
}
.ipt[name=name]{
width: 300px;
}
.btn{
height: 33px;
font-size: 14px;
margin-left: 12px;
}
}
// label color drop
#label-color-drop{
.ipt{
width:100px;
}
.drop-down{
width:128px;
top:22px;
left:50px;
padding: 12px;
line-height: 16px;
a.color{
width: 16px;
height: 16px;
display: inline-block;
}
}
label{
width: 24px;
height: 24px;
display: inline-block;
margin: 0 1em;
vertical-align: middle;
}
}
// milestone items
#milestone-list{
padding-top: 6px;
.title-text{
font-size: 16px;
}
.desc {
color: #999;
line-height: 30px;
}
.content{
width: 400px;
}
.item {
padding-bottom: 18px;
margin-bottom: 18px;
border-bottom: 1px dashed #AAA;
position: relative;
}
.action{
position: absolute;
top: 0;
right: 0;
}
.status-bar {
> .bar {
margin: -2px 8px 0 8px;
width: 360px;
background-color: #DDD;
height: 14px;
vertical-align:middle;
}
.opening{
background-color: #65ad4e;
width: 40%;
height: 14px;
vertical-align: top;
}
}
.action-bar{
margin-top: 8px;
a{
margin-left: 12px;
}
}
}

View File

@@ -59,6 +59,30 @@
color: #777;
}
}
table {
display: block;
width: 100%;
overflow: auto;
word-break: normal;
margin: 15px 0;
border-collapse: collapse;
border-spacing: 0;
display: block;
th {
font-weight: 700;
}
th, td {
border: 1px solid #DDD;
padding: 6px 13px !important;
}
tr {
background-color: #FFF;
border-top: 1px solid #CCC;
&:nth-child(2n) {
background-color: #F8F8F8;
}
}
}
}
.markdown a {
color: #428BCA;
@@ -96,29 +120,6 @@
.markdown h4 {
font-size: 18px
}
.markdown table {
border-collapse: collapse;
border-spacing: 0;
display: block;
overflow: auto;
width: 100%;
margin: 0 0 9px;
}
.markdown table th {
font-weight: 700
}
.markdown table th,
.markdown table td {
border: 1px solid #DDD;
padding: 6px 13px;
}
.markdown table tr {
background-color: #FFF;
border-top: 1px solid #CCC;
}
.markdown table tr:nth-child(2n) {
background-color: #F8F8F8
}
.markdown dl dt {
font-style: italic;
margin-top: 9px;

View File

@@ -55,5 +55,5 @@
}
}
#profile-body {
margin-left: 10px;
margin-left: 20px;
}

View File

@@ -90,7 +90,8 @@
}
}
#repo-content {
padding: 18px 0;
padding-top: 18px;
padding-bottom: 18px;
}
.repo-wide-wrapper {
padding: 18px;
@@ -383,6 +384,7 @@
#repo-create-cancel {
margin-left: 4em;
}
#release-new-target-branch-list,
#repo-create-owner-list {
top: 30px;
left: 0;
@@ -410,6 +412,23 @@
}
}
}
#release-new-target-branch-list {
margin-top: -1px;
min-width: 150px;
}
#release-new-title {
margin-top: 10px;
}
#release-new-content {
width: 100%;
}
#release-preview-btn .btn {
border-left: 0;
}
#release-preview.markdown {
margin-top: 5px;
background-color: transparent;
}
.file-name {
margin-left: 1em;
}
@@ -447,7 +466,7 @@
width: 1%;
span {
font-family: Monaco,Menlo,Consolas,"Courier New",monospace;
line-height: 1.6;
line-height: 20px;
padding: 0 10px;
cursor: pointer;
display: block;
@@ -535,6 +554,11 @@
}
}
}
.commit-message {
white-space: pre-wrap;
}
.diff-head-box {
margin-top: 10px;
.panel-body {
@@ -661,3 +685,90 @@
margin-left: 44px;
margin-top: -15px;
}
#release {
h4 {
font-size: 18px;
small {
font-weight: 400;
line-height: 1;
color: #999;
}
}
#release-head {
margin-top: 0;
margin-bottom: 0;
padding-bottom: 20px;
border-bottom: 1px solid #DDD;
.btn {
margin-left: 10px;
}
}
.release-item {
&>div {
padding-top: 20px;
padding-bottom: 20px;
}
.label-green:hover {
background-color: @labelGreenColor;
}
.release-meta {
position: relative;
float: left;
padding-right: 15px;
}
.tag,
.commit {
display: block;
margin-top: 12px;
line-height: 20px;
}
.release-detail {
margin-top: -1px;
border-left: 1px solid #DDD;
position: relative;
float: left;
padding-left: 15px;
}
.title {
line-height: 25px;
margin-top: 0;
}
p.info {
line-height: 20px;
color: #666;
margin-bottom: 15px;
>* {
margin-right: 10px;
}
}
.author {
img {
margin-top: -3px;
}
}
div.desc {
margin-bottom: 25px;
&.markdown {
background-color: transparent;
}
}
.download a {
margin-right: 10px;
}
.dot {
width: 9px;
height: 9px;
background-color: #ccc;
z-index: 999;
position: absolute;
display: block;
left: -6px;
top: 27px;
border-radius: 6px;
border: 1px solid #FFF;
}
}
#release-new-form {
padding-top: 15px;
}
}

View File

@@ -14,6 +14,7 @@
}
.btn-large {
font-size: 1.2*@baseFontSize;
padding: .4em .9em;
}
.btn-green {

View File

@@ -117,6 +117,7 @@ const (
CLEAN_UNBIND_OAUTH AdminOperation = iota + 1
CLEAN_INACTIVATE_USER
CLEAN_REPO_ARCHIVES
GIT_GC_REPOS
)
func Dashboard(ctx *middleware.Context) {
@@ -140,6 +141,9 @@ func Dashboard(ctx *middleware.Context) {
case CLEAN_REPO_ARCHIVES:
success = ctx.Tr("admin.dashboard.delete_repo_archives_success")
err = models.DeleteRepositoryArchives()
case GIT_GC_REPOS:
success = ctx.Tr("admin.dashboard.git_gc_repos_success")
err = models.GitGcRepos()
}
if err != nil {

View File

@@ -192,13 +192,19 @@ func EditUserPost(ctx *middleware.Context, form auth.AdminEditUserForm) {
u.IsActive = form.Active
u.IsAdmin = form.Admin
u.AllowGitHook = form.AllowGitHook
ctx.Data["User"] = u
if err := models.UpdateUser(u); err != nil {
ctx.Handle(500, "UpdateUser", err)
if err == models.ErrEmailAlreadyUsed {
ctx.Data["Err_Email"] = true
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), USER_EDIT, &form)
} else {
ctx.Handle(500, "UpdateUser", err)
}
return
}
log.Trace("Account profile updated by admin(%s): %s", ctx.User.Name, u.Name)
ctx.Data["User"] = u
ctx.Flash.Success(ctx.Tr("admin.users.update_profile_success"))
ctx.Redirect(setting.AppSubUrl + "/admin/users/" + ctx.Params(":userid"))
}

View File

@@ -20,6 +20,11 @@ func Markdown(ctx *middleware.Context, form apiv1.MarkdownForm) {
return
}
if len(form.Text) == 0 {
ctx.Write([]byte(""))
return
}
switch form.Mode {
case "gfm":
ctx.Write(base.RenderMarkdown([]byte(form.Text),

View File

@@ -21,6 +21,25 @@ import (
"github.com/gogits/gogs/modules/setting"
)
// ToApiRepository converts repository to API format.
func ToApiRepository(owner *models.User, repo *models.Repository, permission api.Permission) *api.Repository {
cl, err := repo.CloneLink()
if err != nil {
log.Error(4, "CloneLink: %v", err)
}
return &api.Repository{
Id: repo.Id,
Owner: *ToApiUser(owner),
FullName: owner.Name + "/" + repo.Name,
Private: repo.IsPrivate,
Fork: repo.IsFork,
HtmlUrl: setting.AppUrl + owner.Name + "/" + repo.Name,
CloneUrl: cl.HTTPS,
SshUrl: cl.SSH,
Permissions: permission,
}
}
func SearchRepos(ctx *middleware.Context) {
opt := models.SearchOption{
Keyword: path.Base(ctx.Query("q")),
@@ -44,7 +63,7 @@ func SearchRepos(ctx *middleware.Context) {
})
return
}
if u.IsOrganization() && u.IsOrgOwner(ctx.User.Id) {
if u.IsOrganization() && u.IsOwnedBy(ctx.User.Id) {
opt.Private = true
}
// FIXME: how about collaborators?
@@ -75,13 +94,66 @@ func SearchRepos(ctx *middleware.Context) {
}
}
ctx.Render.JSON(200, map[string]interface{}{
ctx.JSON(200, map[string]interface{}{
"ok": true,
"data": results,
})
}
func Migrate(ctx *middleware.Context, form auth.MigrateRepoForm) {
func createRepo(ctx *middleware.Context, owner *models.User, opt api.CreateRepoOption) {
repo, err := models.CreateRepository(owner, opt.Name, opt.Description,
opt.Gitignore, opt.License, opt.Private, false, opt.AutoInit)
if err != nil {
if err == models.ErrRepoAlreadyExist ||
err == models.ErrRepoNameIllegal {
ctx.JSON(422, &base.ApiJsonErr{err.Error(), base.DOC_URL})
} else {
log.Error(4, "CreateRepository: %v", err)
if repo != nil {
if err = models.DeleteRepository(ctx.User.Id, repo.Id, ctx.User.Name); err != nil {
log.Error(4, "DeleteRepository: %v", err)
}
}
ctx.Error(500)
}
return
}
ctx.JSON(200, ToApiRepository(owner, repo, api.Permission{true, true, true}))
}
// POST /user/repos
// https://developer.github.com/v3/repos/#create
func CreateRepo(ctx *middleware.Context, opt api.CreateRepoOption) {
// Shouldn't reach this condition, but just in case.
if ctx.User.IsOrganization() {
ctx.JSON(422, "not allowed creating repository for organization")
return
}
createRepo(ctx, ctx.User, opt)
}
// POST /orgs/:org/repos
// https://developer.github.com/v3/repos/#create
func CreateOrgRepo(ctx *middleware.Context, opt api.CreateRepoOption) {
org, err := models.GetOrgByName(ctx.Params(":org"))
if err != nil {
if err == models.ErrUserNotExist {
ctx.Error(404)
} else {
ctx.Error(500)
}
return
}
if !org.IsOwnedBy(ctx.User.Id) {
ctx.Error(403)
return
}
createRepo(ctx, org, opt)
}
func MigrateRepo(ctx *middleware.Context, form auth.MigrateRepoForm) {
u, err := models.GetUserByName(ctx.Query("username"))
if err != nil {
ctx.JSON(500, map[string]interface{}{
@@ -103,17 +175,15 @@ func Migrate(ctx *middleware.Context, form auth.MigrateRepoForm) {
if form.Uid != u.Id {
org, err := models.GetUserById(form.Uid)
if err != nil {
ctx.JSON(500, map[string]interface{}{
"ok": false,
"error": err.Error(),
})
log.Error(4, "GetUserById: %v", err)
ctx.Error(500)
return
}
ctxUser = org
}
if ctx.HasError() {
ctx.JSON(500, map[string]interface{}{
ctx.JSON(422, map[string]interface{}{
"ok": false,
"error": ctx.GetErrMsg(),
})
@@ -122,7 +192,7 @@ func Migrate(ctx *middleware.Context, form auth.MigrateRepoForm) {
if ctxUser.IsOrganization() {
// Check ownership of organization.
if !ctxUser.IsOrgOwner(u.Id) {
if !ctxUser.IsOwnedBy(u.Id) {
ctx.JSON(403, map[string]interface{}{
"ok": false,
"error": "given user is not owner of organization",
@@ -173,29 +243,9 @@ func ListMyRepos(ctx *middleware.Context) {
return
}
sshUrlFmt := "%s@%s:%s/%s.git"
if setting.SshPort != 22 {
sshUrlFmt = "ssh://%s@%s:%d/%s/%s.git"
}
repos := make([]*api.Repository, numOwnRepos+len(collaRepos))
// FIXME: make only one loop
for i := range ownRepos {
repos[i] = &api.Repository{
Id: ownRepos[i].Id,
Owner: api.User{
Id: ctx.User.Id,
UserName: ctx.User.Name,
AvatarUrl: string(setting.Protocol) + ctx.User.AvatarLink(),
},
FullName: ctx.User.Name + "/" + ownRepos[i].Name,
Private: ownRepos[i].IsPrivate,
Fork: ownRepos[i].IsFork,
HtmlUrl: setting.AppUrl + ctx.User.Name + "/" + ownRepos[i].Name,
SshUrl: fmt.Sprintf(sshUrlFmt, setting.RunUser, setting.Domain, ctx.User.LowerName, ownRepos[i].LowerName),
Permissions: api.Permission{true, true, true},
}
repos[i].CloneUrl = repos[i].HtmlUrl + ".git"
repos[i] = ToApiRepository(ctx.User, ownRepos[i], api.Permission{true, true, true})
}
for i := range collaRepos {
if err = collaRepos[i].GetOwner(); err != nil {
@@ -203,24 +253,10 @@ func ListMyRepos(ctx *middleware.Context) {
return
}
j := i + numOwnRepos
repos[j] = &api.Repository{
Id: collaRepos[i].Id,
Owner: api.User{
Id: collaRepos[i].Owner.Id,
UserName: collaRepos[i].Owner.Name,
AvatarUrl: string(setting.Protocol) + collaRepos[i].Owner.AvatarLink(),
},
FullName: collaRepos[i].Owner.Name + "/" + collaRepos[i].Name,
Private: collaRepos[i].IsPrivate,
Fork: collaRepos[i].IsFork,
HtmlUrl: setting.AppUrl + collaRepos[i].Owner.Name + "/" + collaRepos[i].Name,
SshUrl: fmt.Sprintf(sshUrlFmt, setting.RunUser, setting.Domain, collaRepos[i].Owner.LowerName, collaRepos[i].LowerName),
Permissions: api.Permission{false, collaRepos[i].CanPush, true},
}
repos[j].CloneUrl = repos[j].HtmlUrl + ".git"
repos[j] = ToApiRepository(collaRepos[i].Owner, collaRepos[i].Repository, api.Permission{false, collaRepos[i].CanPush, true})
// FIXME: cache result to reduce DB query?
if collaRepos[i].Owner.IsOrganization() && collaRepos[i].Owner.IsOrgOwner(ctx.User.Id) {
if collaRepos[i].Owner.IsOrganization() && collaRepos[i].Owner.IsOwnedBy(ctx.User.Id) {
repos[j].Permissions.Admin = true
}
}

View File

@@ -48,15 +48,9 @@ func ListRepoHooks(ctx *middleware.Context) {
ctx.JSON(200, &apiHooks)
}
type CreateRepoHookForm struct {
Type string `json:"type" binding:"Required"`
Config map[string]string `json:"config" binding:"Required"`
Active bool `json:"active"`
}
// POST /repos/:username/:reponame/hooks
// https://developer.github.com/v3/repos/hooks/#create-a-hook
func CreateRepoHook(ctx *middleware.Context, form CreateRepoHookForm) {
func CreateRepoHook(ctx *middleware.Context, form api.CreateHookOption) {
if !models.IsValidHookTaskType(form.Type) {
ctx.JSON(422, &base.ApiJsonErr{"invalid hook type", base.DOC_URL})
return
@@ -124,14 +118,9 @@ func CreateRepoHook(ctx *middleware.Context, form CreateRepoHookForm) {
ctx.JSON(201, apiHook)
}
type EditRepoHookForm struct {
Config map[string]string `json:"config"`
Active *bool `json:"active"`
}
// PATCH /repos/:username/:reponame/hooks/:id
// https://developer.github.com/v3/repos/hooks/#edit-a-hook
func EditRepoHook(ctx *middleware.Context, form EditRepoHookForm) {
func EditRepoHook(ctx *middleware.Context, form api.EditHookOption) {
w, err := models.GetWebhookById(ctx.ParamsInt64(":id"))
if err != nil {
ctx.JSON(500, &base.ApiJsonErr{"GetWebhookById: " + err.Error(), base.DOC_URL})

View File

@@ -12,8 +12,18 @@ import (
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/middleware"
"github.com/gogits/gogs/modules/setting"
)
// ToApiUser converts user to API format.
func ToApiUser(u *models.User) *api.User {
return &api.User{
Id: u.Id,
UserName: u.Name,
AvatarUrl: string(setting.Protocol) + u.AvatarLink(),
}
}
func SearchUsers(ctx *middleware.Context) {
opt := models.SearchOption{
Keyword: ctx.Query("q"),
@@ -37,6 +47,7 @@ func SearchUsers(ctx *middleware.Context) {
results[i] = &api.User{
UserName: us[i].Name,
AvatarUrl: us[i].AvatarLink(),
FullName: us[i].FullName,
}
}

View File

@@ -88,6 +88,7 @@ func Install(ctx *middleware.Context, form auth.InstallForm) {
ctx.Data["Title"] = ctx.Tr("install.install")
ctx.Data["PageIsInstall"] = true
// FIXME: when i'm ckeching length here? should they all be 0 no matter when?
// Get and assign values to install form.
if len(form.DbHost) == 0 {
form.DbHost = models.DbCfg.Host
@@ -109,7 +110,15 @@ func Install(ctx *middleware.Context, form auth.InstallForm) {
form.RepoRootPath = setting.RepoRootPath
}
if len(form.RunUser) == 0 {
form.RunUser = setting.RunUser
// Note: it's not normall to use SSH in windows so current user can be first option(not git).
if setting.IsWindows && setting.RunUser == "git" {
form.RunUser = os.Getenv("USER")
if len(form.RunUser) == 0 {
form.RunUser = os.Getenv("USERNAME")
}
} else {
form.RunUser = setting.RunUser
}
}
if len(form.Domain) == 0 {
form.Domain = setting.Domain

View File

@@ -5,12 +5,14 @@
package repo
import (
"container/list"
"path"
"github.com/Unknwon/com"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/git"
"github.com/gogits/gogs/modules/middleware"
"github.com/gogits/gogs/modules/setting"
)
@@ -31,6 +33,16 @@ func RefCommits(ctx *middleware.Context) {
}
}
func RenderIssueLinks(oldCommits *list.List, repoLink string) *list.List {
newCommits := list.New()
for e := oldCommits.Front(); e != nil; e = e.Next() {
c := e.Value.(*git.Commit)
c.CommitMessage = string(base.RenderIssueIndexPattern([]byte(c.CommitMessage), repoLink))
newCommits.PushBack(c)
}
return newCommits
}
func Commits(ctx *middleware.Context) {
ctx.Data["IsRepoToolbarCommits"] = true
@@ -62,7 +74,7 @@ func Commits(ctx *middleware.Context) {
lastPage = 0
}
nextPage := page + 1
if nextPage*50 > commitsCount {
if page*50 > commitsCount {
nextPage = 0
}
@@ -72,6 +84,7 @@ func Commits(ctx *middleware.Context) {
ctx.Handle(500, "CommitsByRange", err)
return
}
commits = RenderIssueLinks(commits, ctx.Repo.RepoLink)
commits = models.ValidateCommitsWithEmails(commits)
ctx.Data["Commits"] = commits
@@ -110,6 +123,7 @@ func SearchCommits(ctx *middleware.Context) {
ctx.Handle(500, "SearchCommits", err)
return
}
commits = RenderIssueLinks(commits, ctx.Repo.RepoLink)
commits = models.ValidateCommitsWithEmails(commits)
ctx.Data["Keyword"] = keyword
@@ -171,6 +185,7 @@ func FileHistory(ctx *middleware.Context) {
ctx.Handle(500, "repo.FileHistory(CommitsByRange)", err)
return
}
commits = RenderIssueLinks(commits, ctx.Repo.RepoLink)
commits = models.ValidateCommitsWithEmails(commits)
ctx.Data["Commits"] = commits
@@ -191,7 +206,7 @@ func Diff(ctx *middleware.Context) {
commitId := ctx.Repo.CommitId
commit := ctx.Repo.Commit
commit.CommitMessage = string(base.RenderIssueIndexPattern([]byte(commit.CommitMessage), ctx.Repo.RepoLink))
diff, err := models.GetDiffCommit(models.RepoPath(userName, repoName),
commitId, setting.MaxGitDiffLines)
if err != nil {

View File

@@ -227,6 +227,7 @@ var routes = []route{
func HttpBackend(config *Config) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
for _, route := range routes {
r.URL.Path = strings.ToLower(r.URL.Path) // blue: In case some repo name has upper case name
if m := route.cr.FindStringSubmatch(r.URL.Path); m != nil {
if route.method != r.Method {
renderMethodNotAllowed(w, r)

View File

@@ -628,7 +628,7 @@ func UpdateAssignee(ctx *middleware.Context) {
}
aid := com.StrTo(ctx.Query("assigneeid")).MustInt64()
// Not check for invalid assignne id and give responsibility to owners.
// Not check for invalid assignee id and give responsibility to owners.
issue.AssigneeId = aid
if err = models.UpdateIssueUserPairByAssignee(aid, issue.Id); err != nil {
ctx.Handle(500, "UpdateIssueUserPairByAssignee: %v", err)
@@ -1133,3 +1133,7 @@ func PullRequest2(ctx *middleware.Context){
func Labels2(ctx *middleware.Context){
ctx.HTML(200,"repo/issue2/labels")
}
func Milestones2(ctx *middleware.Context){
ctx.HTML(200,"repo/milestone2/list")
}

View File

@@ -19,7 +19,7 @@ const (
)
func Releases(ctx *middleware.Context) {
ctx.Data["Title"] = "Releases"
ctx.Data["Title"] = ctx.Tr("repo.release.releases")
ctx.Data["IsRepoToolbarReleases"] = true
ctx.Data["IsRepoReleaseNew"] = false
@@ -35,35 +35,13 @@ func Releases(ctx *middleware.Context) {
return
}
// Get default branch.
refName := ctx.Repo.Repository.DefaultBranch
if !ctx.Repo.GitRepo.IsBranchExist(refName) {
brs, err := ctx.Repo.GitRepo.GetBranches()
if err != nil {
ctx.Handle(500, "GetBranches", err)
return
}
refName = brs[0]
}
commit, err := ctx.Repo.GitRepo.GetCommitOfBranch(refName)
if err != nil {
ctx.Handle(500, "GetCommitOfBranch", err)
return
}
commitsCount, err := commit.CommitsCount()
if err != nil {
ctx.Handle(500, "CommitsCount", err)
return
}
// Temproray cache commits count of used branches to speed up.
countCache := make(map[string]int)
tags := make([]*models.Release, len(rawTags))
for i, rawTag := range rawTags {
for _, rel := range rels {
if rel.IsDraft && !ctx.Repo.IsOwner {
for j, rel := range rels {
if rel == nil || (rel.IsDraft && !ctx.Repo.IsOwner) {
continue
}
if rel.TagName == rawTag {
@@ -72,6 +50,7 @@ func Releases(ctx *middleware.Context) {
ctx.Handle(500, "GetUserById", err)
return
}
// FIXME: duplicated code.
// Get corresponding target if it's not the current branch.
if ctx.Repo.BranchName != rel.Target {
// Get count if not exists.
@@ -89,11 +68,12 @@ func Releases(ctx *middleware.Context) {
}
rel.NumCommitsBehind = countCache[ctx.Repo.BranchName] - rel.NumCommits
} else {
rel.NumCommitsBehind = commitsCount - rel.NumCommits
rel.NumCommitsBehind = ctx.Repo.CommitsCount - rel.NumCommits
}
rel.Note = base.RenderMarkdownString(rel.Note, ctx.Repo.RepoLink)
tags[i] = rel
rels[j] = nil // Mark as used.
break
}
}
@@ -116,9 +96,44 @@ func Releases(ctx *middleware.Context) {
ctx.Handle(500, "CommitsCount", err)
return
}
tags[i].NumCommitsBehind = commitsCount - tags[i].NumCommits
tags[i].NumCommitsBehind = ctx.Repo.CommitsCount - tags[i].NumCommits
}
}
for _, rel := range rels {
if rel == nil {
continue
}
rel.Publisher, err = models.GetUserById(rel.PublisherId)
if err != nil {
ctx.Handle(500, "GetUserById", err)
return
}
// FIXME: duplicated code.
// Get corresponding target if it's not the current branch.
if ctx.Repo.BranchName != rel.Target {
// Get count if not exists.
if _, ok := countCache[rel.Target]; !ok {
commit, err := ctx.Repo.GitRepo.GetCommitOfBranch(ctx.Repo.BranchName)
if err != nil {
ctx.Handle(500, "GetCommitOfBranch", err)
return
}
countCache[ctx.Repo.BranchName], err = commit.CommitsCount()
if err != nil {
ctx.Handle(500, "CommitsCount2", err)
return
}
}
rel.NumCommitsBehind = countCache[ctx.Repo.BranchName] - rel.NumCommits
} else {
rel.NumCommitsBehind = ctx.Repo.CommitsCount - rel.NumCommits
}
rel.Note = base.RenderMarkdownString(rel.Note, ctx.Repo.RepoLink)
tags = append(tags, rel)
}
models.SortReleases(tags)
ctx.Data["Releases"] = tags
ctx.HTML(200, RELEASES)
@@ -130,7 +145,8 @@ func NewRelease(ctx *middleware.Context) {
return
}
ctx.Data["Title"] = "New Release"
ctx.Data["Title"] = ctx.Tr("repo.release.new_release")
ctx.Data["tag_target"] = ctx.Repo.Repository.DefaultBranch
ctx.Data["IsRepoToolbarReleases"] = true
ctx.Data["IsRepoReleaseNew"] = true
ctx.HTML(200, RELEASE_NEW)
@@ -142,7 +158,7 @@ func NewReleasePost(ctx *middleware.Context, form auth.NewReleaseForm) {
return
}
ctx.Data["Title"] = "New Release"
ctx.Data["Title"] = ctx.Tr("repo.release.new_release")
ctx.Data["IsRepoToolbarReleases"] = true
ctx.Data["IsRepoReleaseNew"] = true
@@ -183,9 +199,9 @@ func NewReleasePost(ctx *middleware.Context, form auth.NewReleaseForm) {
if err = models.CreateRelease(ctx.Repo.GitRepo, rel); err != nil {
if err == models.ErrReleaseAlreadyExist {
ctx.RenderWithErr("Release with this tag name has already existed", "release/new", &form)
ctx.RenderWithErr(ctx.Tr("repo.release.tag_name_already_exist"), RELEASE_NEW, &form)
} else {
ctx.Handle(500, "release.ReleasesNewPost(IsReleaseExist)", err)
ctx.Handle(500, "CreateRelease", err)
}
return
}
@@ -204,15 +220,15 @@ func EditRelease(ctx *middleware.Context) {
rel, err := models.GetRelease(ctx.Repo.Repository.Id, tagName)
if err != nil {
if err == models.ErrReleaseNotExist {
ctx.Handle(404, "release.ReleasesEdit(GetRelease)", err)
ctx.Handle(404, "GetRelease", err)
} else {
ctx.Handle(500, "release.ReleasesEdit(GetRelease)", err)
ctx.Handle(500, "GetRelease", err)
}
return
}
ctx.Data["Release"] = rel
ctx.Data["Title"] = "Edit Release"
ctx.Data["Title"] = ctx.Tr("repo.release.edit_release")
ctx.Data["IsRepoToolbarReleases"] = true
ctx.HTML(200, RELEASE_EDIT)
}
@@ -227,9 +243,9 @@ func EditReleasePost(ctx *middleware.Context, form auth.EditReleaseForm) {
rel, err := models.GetRelease(ctx.Repo.Repository.Id, tagName)
if err != nil {
if err == models.ErrReleaseNotExist {
ctx.Handle(404, "release.EditReleasePost(GetRelease)", err)
ctx.Handle(404, "GetRelease", err)
} else {
ctx.Handle(500, "release.EditReleasePost(GetRelease)", err)
ctx.Handle(500, "GetRelease", err)
}
return
}
@@ -240,7 +256,7 @@ func EditReleasePost(ctx *middleware.Context, form auth.EditReleaseForm) {
return
}
ctx.Data["Title"] = "Edit Release"
ctx.Data["Title"] = ctx.Tr("repo.release.edit_release")
ctx.Data["IsRepoToolbarReleases"] = true
rel.Title = form.Title
@@ -248,7 +264,7 @@ func EditReleasePost(ctx *middleware.Context, form auth.EditReleaseForm) {
rel.IsDraft = len(form.Draft) > 0
rel.IsPrerelease = form.Prerelease
if err = models.UpdateRelease(ctx.Repo.GitRepo, rel); err != nil {
ctx.Handle(500, "release.EditReleasePost(UpdateRelease)", err)
ctx.Handle(500, "UpdateRelease", err)
return
}
ctx.Redirect(ctx.Repo.RepoLink + "/releases")

View File

@@ -97,14 +97,14 @@ func CreatePost(ctx *middleware.Context, form auth.CreateRepoForm) {
if ctxUser.IsOrganization() {
// Check ownership of organization.
if !ctxUser.IsOrgOwner(ctx.User.Id) {
if !ctxUser.IsOwnedBy(ctx.User.Id) {
ctx.Error(403)
return
}
}
repo, err := models.CreateRepository(ctxUser, form.RepoName, form.Description,
form.Gitignore, form.License, form.Private, false, form.InitReadme)
form.Gitignore, form.License, form.Private, false, form.AutoInit)
if err == nil {
log.Trace("Repository created: %s/%s", ctxUser.Name, repo.Name)
ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + repo.Name)
@@ -174,7 +174,7 @@ func MigratePost(ctx *middleware.Context, form auth.MigrateRepoForm) {
if ctxUser.IsOrganization() {
// Check ownership of organization.
if !ctxUser.IsOrgOwner(ctx.User.Id) {
if !ctxUser.IsOwnedBy(ctx.User.Id) {
ctx.Error(403)
return
}
@@ -292,7 +292,7 @@ func ForkPost(ctx *middleware.Context, form auth.CreateRepoForm) {
if ctxUser.IsOrganization() {
// Check ownership of organization.
if !ctxUser.IsOrgOwner(ctx.User.Id) {
if !ctxUser.IsOwnedBy(ctx.User.Id) {
ctx.Error(403)
return
}

View File

@@ -72,6 +72,7 @@ func SettingsPost(ctx *middleware.Context, form auth.RepoSettingForm) {
}
log.Trace("Repository name changed: %s/%s -> %s", ctx.Repo.Owner.Name, ctx.Repo.Repository.Name, newRepoName)
ctx.Repo.Repository.Name = newRepoName
ctx.Repo.Repository.LowerName = strings.ToLower(newRepoName)
}
br := form.Branch
@@ -136,7 +137,7 @@ func SettingsPost(ctx *middleware.Context, form auth.RepoSettingForm) {
}
if ctx.Repo.Owner.IsOrganization() {
if !ctx.Repo.Owner.IsOrgOwner(ctx.User.Id) {
if !ctx.Repo.Owner.IsOwnedBy(ctx.User.Id) {
ctx.Error(404)
return
}

View File

@@ -152,6 +152,11 @@ func Home(ctx *middleware.Context) {
}
}
// Render issue index links.
for _, f := range files {
c := f[1].(*git.Commit)
c.CommitMessage = string(base.RenderIssueIndexPattern([]byte(c.CommitMessage), ctx.Repo.RepoLink))
}
ctx.Data["Files"] = files
var readmeFile *git.Blob
@@ -199,6 +204,7 @@ func Home(ctx *middleware.Context) {
}
lastCommit := ctx.Repo.Commit
lastCommit.CommitMessage = string(base.RenderIssueIndexPattern([]byte(lastCommit.CommitMessage), ctx.Repo.RepoLink))
if len(treePath) > 0 {
c, err := ctx.Repo.Commit.GetCommitOfRelPath(treePath)
if err != nil {

View File

@@ -5,7 +5,9 @@
package user
import (
"bytes"
"fmt"
"strings"
"github.com/Unknwon/com"
@@ -100,6 +102,13 @@ func Dashboard(ctx *middleware.Context) {
continue
}
}
// FIXME: cache results?
u, err := models.GetUserByName(act.ActUserName)
if err != nil {
ctx.Handle(500, "GetUserByName", err)
return
}
act.ActAvatar = u.AvatarLink()
feeds = append(feeds, act)
}
ctx.Data["Feeds"] = feeds
@@ -120,6 +129,20 @@ func Pulls(ctx *middleware.Context) {
ctx.HTML(200, PULLS)
}
func ShowSSHKeys(ctx *middleware.Context, uid int64) {
keys, err := models.ListPublicKeys(uid)
if err != nil {
ctx.Handle(500, "ListPublicKeys", err)
return
}
var buf bytes.Buffer
for i := range keys {
buf.WriteString(keys[i].OmitEmail())
}
ctx.RenderData(200, buf.Bytes())
}
func Profile(ctx *middleware.Context) {
ctx.Data["Title"] = "Profile"
ctx.Data["PageIsUserProfile"] = true
@@ -131,6 +154,12 @@ func Profile(ctx *middleware.Context) {
return
}
isShowKeys := false
if strings.HasSuffix(uname, ".keys") {
isShowKeys = true
uname = strings.TrimSuffix(uname, ".keys")
}
u, err := models.GetUserByName(uname)
if err != nil {
if err == models.ErrUserNotExist {
@@ -141,6 +170,12 @@ func Profile(ctx *middleware.Context) {
return
}
// Show SSH keys.
if isShowKeys {
ShowSSHKeys(ctx, u.Id)
return
}
if u.IsOrganization() {
ctx.Redirect(setting.AppSubUrl + "/org/" + u.Name)
return
@@ -156,11 +191,23 @@ func Profile(ctx *middleware.Context) {
ctx.Data["TabName"] = tab
switch tab {
case "activity":
ctx.Data["Feeds"], err = models.GetFeeds(u.Id, 0, true)
actions, err := models.GetFeeds(u.Id, 0, false)
if err != nil {
ctx.Handle(500, "GetFeeds", err)
return
}
feeds := make([]*models.Action, 0, len(actions))
for _, act := range actions {
// FIXME: cache results?
u, err := models.GetUserByName(act.ActUserName)
if err != nil {
ctx.Handle(500, "GetUserByName", err)
return
}
act.ActAvatar = u.AvatarLink()
feeds = append(feeds, act)
}
ctx.Data["Feeds"] = feeds
default:
ctx.Data["Repos"], err = models.GetRepositories(u.Id, ctx.IsSigned && ctx.User.Id == u.Id)
if err != nil {
@@ -185,32 +232,6 @@ func Email2User(ctx *middleware.Context) {
ctx.Redirect(setting.AppSubUrl + "/user/" + u.Name)
}
const (
TPL_FEED = `<i class="icon fa fa-%s"></i>
<div class="info"><span class="meta">%s</span><br>%s</div>`
)
// func Feeds(ctx *middleware.Context, form auth.FeedsForm) {
// actions, err := models.GetFeeds(form.UserId, form.Page*20, false)
// if err != nil {
// ctx.JSON(500, err)
// return
// }
// feeds := make([]string, 0, len(actions))
// for _, act := range actions {
// if act.IsPrivate {
// if has, _ := models.HasAccess(ctx.User.Name, act.RepoUserName+"/"+act.RepoName,
// models.READABLE); !has {
// continue
// }
// }
// feeds = append(feeds, fmt.Sprintf(TPL_FEED, base.ActionIcon(act.OpType),
// base.TimeSince(act.Created), base.ActionDesc(act)))
// }
// ctx.JSON(200, &feeds)
// }
func Issues(ctx *middleware.Context) {
ctx.Data["Title"] = "Your Issues"

View File

@@ -5,6 +5,7 @@
package user
import (
"io/ioutil"
"strings"
"github.com/Unknwon/com"
@@ -83,6 +84,48 @@ func SettingsPost(ctx *middleware.Context, form auth.UpdateProfileForm) {
ctx.Redirect(setting.AppSubUrl + "/user/settings")
}
// FIXME: limit size.
func SettingsAvatar(ctx *middleware.Context, form auth.UploadAvatarForm) {
defer ctx.Redirect(setting.AppSubUrl + "/user/settings")
ctx.User.UseCustomAvatar = form.Enable
if form.Avatar != nil {
fr, err := form.Avatar.Open()
if err != nil {
ctx.Flash.Error(err.Error())
return
}
data, err := ioutil.ReadAll(fr)
if err != nil {
ctx.Flash.Error(err.Error())
return
}
if _, ok := base.IsImageFile(data); !ok {
ctx.Flash.Error(ctx.Tr("settings.uploaded_avatar_not_a_image"))
return
}
if err = ctx.User.UploadAvatar(data); err != nil {
ctx.Flash.Error(err.Error())
return
}
} else {
// In case no avatar at all.
if form.Enable && !com.IsFile(ctx.User.CustomAvatarPath()) {
ctx.Flash.Error(ctx.Tr("settings.no_custom_avatar_available"))
return
}
}
if err := models.UpdateUser(ctx.User); err != nil {
ctx.Flash.Error(err.Error())
return
}
ctx.Flash.Success(ctx.Tr("settings.update_avatar_success"))
}
func SettingsPassword(ctx *middleware.Context) {
ctx.Data["Title"] = ctx.Tr("settings")
ctx.Data["PageIsUserSettings"] = true

View File

@@ -8,10 +8,11 @@ import (
"encoding/json"
"errors"
"fmt"
"net/url"
"strings"
// "strings"
"time"
"github.com/macaron-contrib/oauth2"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/middleware"
@@ -19,52 +20,39 @@ import (
"github.com/gogits/gogs/modules/social"
)
func extractPath(next string) string {
n, err := url.Parse(next)
if err != nil {
return setting.AppSubUrl + "/"
}
return n.Path
}
func SocialSignIn(ctx *middleware.Context) {
if setting.OauthService == nil {
ctx.Handle(404, "social.SocialSignIn(oauth service not enabled)", nil)
ctx.Handle(404, "OAuth2 service not enabled", nil)
return
}
next := setting.AppSubUrl + "/user/login"
info := ctx.Session.Get(oauth2.KEY_TOKEN)
if info == nil {
ctx.Redirect(next)
return
}
next := extractPath(ctx.Query("next"))
name := ctx.Params(":name")
connect, ok := social.SocialMap[name]
if !ok {
ctx.Handle(404, "social.SocialSignIn(social login not enabled)", errors.New(name))
return
}
appUrl := strings.TrimSuffix(setting.AppUrl, "/")
if name == "weibo" {
appUrl = strings.Replace(appUrl, "localhost", "127.0.0.1", 1)
}
code := ctx.Query("code")
if code == "" {
// redirect to social login page
connect.SetRedirectUrl(appUrl + ctx.Req.URL.Path)
ctx.Redirect(connect.AuthCodeURL(next))
ctx.Handle(404, "social login not enabled", errors.New(name))
return
}
// handle call back
tk, err := connect.Exchange(code)
if err != nil {
ctx.Handle(500, "social.SocialSignIn(Exchange)", err)
tk := new(oauth2.Token)
if err := json.Unmarshal(info.([]byte), tk); err != nil {
ctx.Handle(500, "Unmarshal token", err)
return
}
next = extractPath(ctx.Query("state"))
log.Trace("social.SocialSignIn(Got token)")
ui, err := connect.UserInfo(tk, ctx.Req.URL)
if err != nil {
ctx.Handle(500, fmt.Sprintf("social.SocialSignIn(get info from %s)", name), err)
ctx.Handle(500, fmt.Sprintf("UserInfo(%s)", name), err)
return
}
if len(ui.Identity) == 0 {
ctx.Handle(404, "no identity is presented", errors.New(name))
return
}
log.Info("social.SocialSignIn(social login): %s", ui)

View File

@@ -1 +1 @@
0.5.8.1118 Beta
0.5.9.1213 Beta

View File

@@ -44,6 +44,10 @@
<td>{{.i18n.Tr "admin.dashboard.delete_repo_archives"}}</td>
<td><i class="fa fa-caret-square-o-right"></i> <a href="{{AppSubUrl}}/admin?op=3">{{.i18n.Tr "admin.dashboard.operation_run"}}</a></td>
</tr>
<tr>
<td>{{.i18n.Tr "admin.dashboard.git_gc_repos"}}</td>
<td><i class="fa fa-caret-square-o-right"></i> <a href="{{AppSubUrl}}/admin?op=4">{{.i18n.Tr "admin.dashboard.operation_run"}}</a></td>
</tr>
</tbody>
</table>
</div>

View File

@@ -38,8 +38,8 @@
</table>
{{if or .LastPageNum .NextPageNum}}
<ul class="pagination">
{{if .LastPageNum}}<li><a class="btn btn-medium btn-gray btn-radius" href="{{AppSubUrl}}/admin/users?p={{.LastPageNum}}">&laquo; {{.i18n.Tr "admin.prev"}}</a></li>{{end}}
{{if .NextPageNum}}<li><a class="btn btn-medium btn-gray btn-radius" href="{{AppSubUrl}}/admin/users?p={{.NextPageNum}}">&raquo; {{.i18n.Tr "admin.next"}}</a></li>{{end}}
{{if .LastPageNum}}<li><a class="btn btn-medium btn-gray btn-radius" href="{{AppSubUrl}}/admin/notices?p={{.LastPageNum}}">&laquo; {{.i18n.Tr "admin.prev"}}</a></li>{{end}}
{{if .NextPageNum}}<li><a class="btn btn-medium btn-gray btn-radius" href="{{AppSubUrl}}/admin/notices?p={{.NextPageNum}}">&raquo; {{.i18n.Tr "admin.next"}}</a></li>{{end}}
</ul>
{{end}}
</div>

View File

@@ -31,12 +31,12 @@
{{range .Repos}}
<tr>
<td>{{.Id}}</td>
<td><a href="{{AppSubUrl}}/user/{{.Owner.Name}}">{{.Owner.Name}}</a></td>
<td><a href="{{AppSubUrl}}/{{.Owner.Name}}">{{.Owner.Name}}</a></td>
<td><a href="{{AppSubUrl}}/{{.Owner.Name}}/{{.Name}}">{{.Name}}</a></td>
<td><i class="fa fa{{if .IsPrivate}}-check{{end}}-square-o"></i></td>
<td>{{.NumWatches}}</td>
<td>{{.NumIssues}}</td>
<td>{{.NumStars}}</td>
<td>{{.NumIssues}}</td>
<td>{{DateFormat .Created "M d, Y"}}</td>
</tr>
{{end}}
@@ -57,4 +57,4 @@
</div>
</div>
</div>
{{template "ng/base/footer" .}}
{{template "ng/base/footer" .}}

View File

@@ -32,7 +32,7 @@
{{range .Users}}
<tr>
<td>{{.Id}}</td>
<td><a href="{{AppSubUrl}}/user/{{.Name}}">{{.Name}}</a></td>
<td><a href="{{AppSubUrl}}/{{.Name}}">{{.Name}}</a></td>
<td>{{.Email}}</td>
<td><i class="fa fa{{if .IsActive}}-check{{end}}-square-o"></i></td>
<td><i class="fa fa{{if .IsAdmin}}-check{{end}}-square-o"></i></td>

View File

@@ -34,6 +34,7 @@
<script src="{{AppSubUrl}}/ng/js/lib/jquery.magnific-popup.min.js"></script>
<script src="{{AppSubUrl}}/ng/js/utils/tabs.js"></script>
<script src="{{AppSubUrl}}/ng/js/utils/preview.js"></script>
<script src="{{AppSubUrl}}/ng/js/gogs/issue_label.js"></script>
<script src="{{AppSubUrl}}/ng/js/gogs.js"></script>
<title>{{if .Title}}{{.Title}} - {{end}}{{AppName}}</title>

View File

@@ -1,4 +1,4 @@
{{if .OauthService.GitHub}}<a class="btn github" href="{{AppSubUrl}}/user/login/github?next=/user/sign_up"><i class="fa fa-github"></i>GitHub</a>{{end}}
{{if .OauthService.Google}}<a class="btn google" href="{{AppSubUrl}}/user/login/google?next=/user/sign_up"><i class="fa fa-google"></i>Google +</a>{{end}}
{{if .OauthService.Weibo}}<a class="btn weibo" href="{{AppSubUrl}}/user/login/weibo?next=/user/sign_up"><i class="fa fa-weibo"></i>新浪微博</a>{{end}}
{{if .OauthService.Tencent}}<a class="btn qq" href="{{AppSubUrl}}/user/login/qq?next=/user/sign_up"><i class="fa fa-qq"></i>腾讯 QQ&nbsp;</a>{{end}}
{{if .OauthService.GitHub}}<a class="btn github" href="{{AppSubUrl}}/user/login/oauth2/github?next={{AppSubUrl}}/user/info/github"><i class="fa fa-github"></i>GitHub</a>{{end}}
{{if .OauthService.Google}}<a class="btn google" href="{{AppSubUrl}}/user/login/oauth2/google?next={{AppSubUrl}}/user/info/google"><i class="fa fa-google"></i>Google +</a>{{end}}
{{if .OauthService.Weibo}}<a class="btn weibo" href="{{AppSubUrl}}/user/login/oauth2/weibo?next={{AppSubUrl}}/user/info/weibo"><i class="fa fa-weibo"></i>新浪微博</a>{{end}}
{{if .OauthService.Tencent}}<a class="btn qq" href="{{AppSubUrl}}/user/login/oauth2/qq?next={{AppSubUrl}}/user/info/qq"><i class="fa fa-qq"></i>腾讯 QQ&nbsp;</a>{{end}}

View File

@@ -24,9 +24,15 @@
{{$r := List .Commits}}
{{range $r}}
<tr>
<td class="author"><img class="avatar-20" src="{{AvatarLink .Author.Email}}" alt=""/>&nbsp;&nbsp;&nbsp;{{if .UserName}}<a href="{{AppSubUrl}}/{{.UserName}}">{{.Author.Name}}</a>{{else}}{{.Author.Name}}{{end}}</td>
<td class="author">
{{if .User}}
<img class="avatar-20" src="{{.User.AvatarLink}}" alt=""/>&nbsp;&nbsp;&nbsp;<a href="{{AppSubUrl}}/{{.User.Name}}">{{.Author.Name}}</a>
{{else}}
<img class="avatar-20" src="{{AvatarLink .Author.Email}}" alt=""/>&nbsp;&nbsp;&nbsp;{{.Author.Name}}
{{end}}
</td>
<td class="sha"><a rel="nofollow" class="label label-green" href="{{AppSubUrl}}/{{$username}}/{{$reponame}}/commit/{{.Id}} ">{{SubStr .Id.String 0 10}} </a></td>
<td class="message"><span class="text-truncate">{{.Summary}}</span></td>
<td class="message"><span class="text-truncate">{{Str2html .Summary}}</span></td>
<td class="date">{{TimeSince .Author.When $.Lang}}</td>
</tr>
{{end}}

View File

@@ -69,7 +69,7 @@
</div>
<div class="field">
<label for="init-readme"></label>
<input class="ipt-chk" id="init-readme" name="init_readme" type="checkbox" {{if .init_readme}}checked{{end}} />
<input class="ipt-chk" id="init-readme" name="auto_init" type="checkbox" {{if .auto_init}}checked{{end}} />
<strong>{{.i18n.Tr "repo.init_readme"}}</strong>
</div>
<div class="field">

View File

@@ -17,7 +17,7 @@
<div class="panel panel-info panel-radius diff-head-box">
<div class="panel-header">
<a class="pull-right btn btn-blue btn-header btn-medium btn-radius" rel="nofollow" href="{{.SourcePath}}">{{.i18n.Tr "repo.diff.browse_source"}}</a>
<h4>{{.Commit.Message}}</h4>
<h4 class="commit-message">{{Str2html .Commit.Message}}</h4>
</div>
<div class="panel-body">
<span class="pull-right">
@@ -30,10 +30,11 @@
</ul>
</span>
<p class="author">
<img class="avatar-30" src="{{AvatarLink .Commit.Author.Email}}" />
{{if .Author}}
<a href="{{AppSubUrl}}/{{.Author}}"><strong>{{.Commit.Author.Name}}</strong></a>
<img class="avatar-30" src="{{.Author.AvatarLink}}" />
<a href="{{AppSubUrl}}/{{.Author.Name}}"><strong>{{.Commit.Author.Name}}</strong></a>
{{else}}
<img class="avatar-30" src="{{AvatarLink .Commit.Author.Email}}" />
<strong>{{.Commit.Author.Name}}</strong>
{{end}}
<span class="text-grey" id="authored-time">{{TimeSince .Commit.Author.When $.Lang}}</span>
@@ -111,7 +112,7 @@
</td>
<td class="lines-code">
<pre>{{ToUtf8 .Content}}</pre>
<pre>{{.Content}}</pre>
</td>
</tr>
{{end}}

View File

@@ -61,7 +61,7 @@
</li>
<li id="repo-find-jump" class="repo-jump right">
<a href="#">
<button class="btn btn-small btn btn-small btn-gray btn-left-radius"><i class="octicon octicon-list-unordered"></i></button>
<button class="btn btn-small btn-gray btn-left-radius"><i class="octicon octicon-list-unordered"></i></button>
</a>
</li> -->
</ul>

View File

@@ -85,7 +85,7 @@
</h5>
<p class="info">
<span class="author"><img class="avatar" src="{{.Poster.AvatarLink}}" alt="" width="20"/>
<a href="{{AppSubUrl}}/user/{{.Poster.Name}}">{{.Poster.Name}}</a></span>
<a href="{{AppSubUrl}}/{{.Poster.Name}}">{{.Poster.Name}}</a></span>
<span class="time">{{TimeSince .Created $.Lang}}</span>
<span class="comment"><i class="fa fa-comments"></i> {{.NumComments}}</span>
</p>

View File

@@ -8,7 +8,7 @@
<div class="issue-wrap col-md-10">
<div class="issue-head clearfix">
<div class="number pull-right">#{{.Issue.Index}}</div>
<a class="author pull-left" href="{{AppSubUrl}}/user/{{.Issue.Poster.Name}}"><img class="avatar" src="{{.Issue.Poster.AvatarLink}}" alt="" width="30"/></a>
<a class="author pull-left" href="{{AppSubUrl}}/{{.Issue.Poster.Name}}"><img class="avatar" src="{{.Issue.Poster.AvatarLink}}" alt="" width="30"/></a>
<h1 class="title pull-left">{{.Issue.Name}}</h1>
<input id="issue-edit-title" class="form-control input-lg pull-left hidden" type="text" value="{{.Issue.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"/>
@@ -17,7 +17,7 @@
<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="{{.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>
<a href="{{AppSubUrl}}/user/{{.Issue.Poster.Name}}" class="author"><strong>{{.Issue.Poster.Name}}</strong></a> opened this issue
<a href="{{AppSubUrl}}/{{.Issue.Poster.Name}}" class="author"><strong>{{.Issue.Poster.Name}}</strong></a> opened this issue
<span class="time">{{TimeSince .Issue.Created $.Lang}}</span> · {{.Issue.NumComments}} comments
</p>
</div>
@@ -63,10 +63,10 @@
{{/* 0 = COMMENT, 1 = REOPEN, 2 = CLOSE, 3 = ISSUE, 4 = COMMIT, 5 = PULL */}}
{{if eq .Type 0}}
<div class="issue-child" id="issue-comment-{{.Id}}">
<a class="user pull-left" href="{{AppSubUrl}}/user/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt=""/></a>
<a class="user pull-left" href="{{AppSubUrl}}/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt=""/></a>
<div class="issue-content panel panel-default">
<div class="panel-heading">
<a href="{{AppSubUrl}}/user/{{.Poster.Name}}" class="user">{{.Poster.Name}}</a> commented <span class="time">{{TimeSince .Created $.Lang}}</span>
<a href="{{AppSubUrl}}/{{.Poster.Name}}" class="user">{{.Poster.Name}}</a> commented <span class="time">{{TimeSince .Created $.Lang}}</span>
<!-- <a class="issue-comment-del pull-right issue-action" href="#" title="Edit Comment"><i class="fa fa-times-circle"></i></a>
<a class="issue-comment-edit pull-right issue-action" href="#" title="Remove Comment" data-url="{remove-link}"><i class="fa fa-edit"></i></a> -->
<span class="role label label-default pull-right">Owner</span>
@@ -93,25 +93,25 @@
</div>
{{else if eq .Type 1}}
<div class="issue-child issue-opened">
<a class="user pull-left" href="{{AppSubUrl}}/user/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt="" /></a>
<a class="user pull-left" href="{{AppSubUrl}}/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt="" /></a>
<div class="issue-content">
<a class="user pull-left" href="{{AppSubUrl}}/user/{{.Poster.Name}}">{{.Poster.Name}}</a> <span class="label label-success">Reopened</span> this issue <span class="time">{{TimeSince .Created $.Lang}}</span>
<a class="user pull-left" href="{{AppSubUrl}}/{{.Poster.Name}}">{{.Poster.Name}}</a> <span class="label label-success">Reopened</span> this issue <span class="time">{{TimeSince .Created $.Lang}}</span>
</div>
</div>
{{else if eq .Type 2}}
<div class="issue-child issue-closed">
<a class="user pull-left" href="{{AppSubUrl}}/user/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt=""/></a>
<a class="user pull-left" href="{{AppSubUrl}}/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt=""/></a>
<div class="issue-content">
<a class="user pull-left" href="{{AppSubUrl}}/user/{{.Poster.Name}}">{{.Poster.Name}}</a> <span class="label label-danger">Closed</span> this issue <span class="time">{{TimeSince .Created $.Lang}}</span>
<a class="user pull-left" href="{{AppSubUrl}}/{{.Poster.Name}}">{{.Poster.Name}}</a> <span class="label label-danger">Closed</span> this issue <span class="time">{{TimeSince .Created $.Lang}}</span>
</div>
</div>
{{else if eq .Type 4}}
<div class="issue-child issue-reference issue-reference-commit">
<a class="user pull-left" href="{{AppSubUrl}}/user/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt=""/></a>
<a class="user pull-left" href="{{AppSubUrl}}/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt=""/></a>
<div class="issue-content">
<a class="user pull-left" href="{{AppSubUrl}}/user/{{.Poster.Name}}">{{.Poster.Name}}</a> <span class="label label-primary">Referenced</span> this issue <span class="time">{{TimeSince .Created $.Lang}}</span>
<a class="user pull-left" href="{{AppSubUrl}}/{{.Poster.Name}}">{{.Poster.Name}}</a> <span class="label label-primary">Referenced</span> this issue <span class="time">{{TimeSince .Created $.Lang}}</span>
<p>
<a class="user pull-left" href="{{AppSubUrl}}/user/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt=""/></a>
<a class="user pull-left" href="{{AppSubUrl}}/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt=""/></a>
{{.ContentHtml}}
</p>
</div>
@@ -120,7 +120,7 @@
{{end}}
<hr class="issue-line"/>
{{if .SignedUser}}<div class="issue-child issue-reply">
<a class="user pull-left" href="{{AppSubUrl}}/user/{{.SignedUser.Name}}"><img class="avatar" src="{{.SignedUser.AvatarLink}}" alt=""/></a>
<a class="user pull-left" href="{{AppSubUrl}}/{{.SignedUser.Name}}"><img class="avatar" src="{{.SignedUser.AvatarLink}}" alt=""/></a>
<form class="panel panel-default issue-content" action="{{.RepoLink}}/comment/new" method="post" enctype="multipart/form-data">
{{.CsrfTokenHtml}}
<div class="panel-body">

View File

@@ -8,9 +8,21 @@
<li><a href="#">Pull Request</a></li>
<li class="current"><a href="#">Labels</a></li>
<li><a href="#">Milestones</a></li>
<li class="right" id="issue-new"><a href="#"><button id="issue-new-btn" class="btn btn-green text-bold">New Issue</button></a></li>
<li class="right"><a href="#">Filter</a></li>
<li class="right" id="label-new"><a href="#"><button id="label-new-btn" class="btn btn-green text-bold">New Label</button></a></li>
</ul>
<form id="label-add-form" action="#" class="form clear hidden">
<input type="text" class="ipt" name="name" placeholder="label name" id="label-add-name"/>
<div class="inline down drop" id="label-color-drop">
<label for="label-add-color"></label>
<input class="ipt" name="color" type="text" placeholder="color" id="label-add-color"/>
<div class="drop-down">
<a href="#" class="color" style="background: red"></a>
<a href="#" class="color" style="background: green"></a>
</div>
</div>
<button class="btn btn-gray right" type="button" id="label-cancel-btn">Cancel</button>
<button class="btn btn-green right" id="label-add-btn">Create</button>
</form>
<div id="issue-list-container">
<div id="issue-list-menu">
<div class="left"><span class="label label-black" id="labels-num">6</span><strong>Labels</strong></div>

View File

@@ -9,7 +9,7 @@
<li><a href="#">Labels</a></li>
<li><a href="#">Milestones</a></li>
<li class="right" id="issue-new"><a href="#"><button id="issue-new-btn" class="btn btn-green text-bold">New Issue</button></a></li>
<li class="right"><a href="#">Filter</a></li>
<!--<li class="right"><a href="#">Filter</a></li>-->
</ul>
<div id="issue-list-container">
<div id="issue-list-menu">
@@ -21,6 +21,36 @@
<i class="octicon octicon-issue-closed"></i> 12 Close
</a></span>
</div>
<ul id="issue-list-filter" class="right menu menu-line">
<li class="down drop label-filter">
<a href="#">Labels</a>
<div class="drop-down">
<h4>Labels</h4>
<ul class="labels list-no-style">
<li class="no-label"><strong>no label</strong></li>
<li><a href="#"><span class="color"></span><span class="name">bug</span></a></li>
<li><a href="#"><span class="color"></span><span class="name">feature</span></a></li>
<li><a href="#"><span class="color"></span><span class="name">roadmap</span></a></li>
</ul>
</div>
</li>
<li class="down drop milestone-filter">
<a href="#">Milestones</a>
<div class="drop-down">
<h4>Milestones</h4>
<ul class="milestones list-no-style">
<li class="no-label"><strong>no milestone</strong></li>
<li><a href="#">v1</a></li>
</ul>
</div>
</li>
<li class="down drop assignee-list">
<a href="#">Assignee</a>
<div class="drop-down">
aabbcc
</div>
</li>
</ul>
<div class="clear"></div>
</div>
<ul id="issue-list" class="list-no-style">

View File

@@ -0,0 +1,58 @@
{{template "ng/base/head" .}}
{{template "ng/base/header" .}}
<div id="repo-wrapper">
{{template "repo/header" .}}
<div class="issue-main container repo-wide-wrapper">
<ul id="issue-list-nav" class="menu menu-line">
<li><a href="#">Issue</a></li>
<li><a href="#">Pull Request</a></li>
<li><a href="#">Labels</a></li>
<li class="current"><a href="#">Milestones</a></li>
<li class="right" id="milestone-new"><a href="#"><button id="issue-new-btn" class="btn btn-green text-bold">New Milestone</button></a></li>
</ul>
<div id="issue-list-container">
<div id="issue-list-menu">
<div class="left">
<span class="mark open hover"><a href="#">
<i class="octicon octicon-milestone"></i> 88 Open
</a></span>
<span class="mark close"><a href="">
<i class="octicon octicon-issue-closed"></i> 12 Close
</a></span>
</div>
<div class="clear"></div>
</div>
<ul id="milestone-list" class="list-no-style">
<li class="item" id="milestone-id">
<!--<a class="comment" href="#">
<i class="octicon octicon-comment"></i> 7
</a>-->
<p class="title text-bold">
<i class="octicon octicon-milestone"></i>
<a href="#" class="title-text">Delete account text</a>
</p>
<p class="desc">
<i class="octicon octicon-clock"></i> Updated 3 days ago &nbsp;&nbsp;
<i class="octicon octicon-calendar"></i> Due to Dec 31,2014
</p>
<div class="content">
In this version of release, users are able to register and log in/out on Gogs, setting up SSH keys and do most of Git operations through SSH with public repositories. And Web UI only for view of Git data, no extra features are supported.
</div>
<div class="action">
<p class="status-bar">
<span class="closed">closed 12</span>
<span class="inline-block bar"><span class="inline-block opening"></span></span>
<span class="open">12 open</span>
</p>
<div class="action-bar text-right">
<a href="#">Edit</a>
<a href="#">Delete</a>
<a href="#" class="text-red">Close</a>
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
{{template "ng/base/footer" .}}

View File

@@ -1,70 +1,59 @@
{{template "base/head" .}}
{{template "base/navbar" .}}
{{template "repo/nav" .}}
{{template "repo/toolbar" .}}
<div id="body" class="container">
<div id="release">
<h4 id="release-head">Edit Release</h4>
{{template "base/alert" .}}
<form id="release-new-form" action="{{.RepoLink}}/releases/edit/{{.Release.TagName}}" method="post" class="form form-inline">
{{.CsrfTokenHtml}}
<div class="form-group">
<b>{{.Release.TagName}}</b>
<span class="target-at">@</span>
<div class="btn-group" id="release-new-target-select">
<button type="button" class="btn btn-default"><i class="fa fa-code-fork fa-lg fa-m"></i>
<span class="target-text">Target : </span>
<strong id="release-new-target-name"> {{.Release.Target}}</strong>
</button>
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
<span class="caret"></span>
</button>
<div class="dropdown-menu clone-group-btn" id="release-new-target-branch-list">
<ul class="list-group">
{{range .Branches}}
<li class="list-group-item">
<a href="#" rel="{{.}}"><i class="fa fa-code-fork"></i>{{.}}</a>
</li>
{{end}}
</ul>
{{template "ng/base/head" .}}
{{template "ng/base/header" .}}
<div id="repo-wrapper">
{{template "repo/header" .}}
<div id="repo-content" class="clear container">
<div id="repo-main" class="left grid-5-6">
{{template "ng/base/alert" .}}
<div id="release">
<h4 id="release-head">{{.i18n.Tr "repo.release.edit_release"}}</h4>
<form class="form" id="release-new-form" action="{{.RepoLink}}/releases/edit/{{.Release.TagName}}" method="post">
{{.CsrfTokenHtml}}
<div class="field">
<b>{{.Release.TagName}}</b>
<span class="target-at">@</span>
<strong>{{.Repository.DefaultBranch}}</strong>
</div>
<input id="tag-target" type="hidden" name="tag_target" value="{{.Release.Target}}"/>
</div>
<p class="help-block">Choose an existing tag, or create a new tag on publish</p>
</div>
<div class="form-group" style="display: block">
<input class="form-control input-lg" id="release-new-title" name="title" type="text" placeholder="release title" value="{{.Release.Title}}" />
</div>
<div class="form-group col-md-8" style="display: block" id="release-new-content-div">
<div class="md-help pull-right">
Content with <a href="https://help.github.com/articles/markdown-basics">Markdown</a>
</div>
<ul class="nav nav-tabs" data-init="tabs">
<li class="release-write active"><a href="#release-textarea" data-toggle="tab">Write</a></li>
<li class="release-preview"><a href="#release-preview" data-toggle="tab" data-ajax="/api/v1/markdown" data-ajax-name="release-preview" data-ajax-context="{{.RepoLink}}" data-ajax-method="post" data-preview="#release-preview">Preview</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="release-textarea">
<div class="form-group">
<textarea class="form-control" name="content" id="release-new-content" rows="10" placeholder="Write some content" data-ajax-rel="release-preview" data-ajax-val="val" data-ajax-field="text">{{.Release.Note}}</textarea>
<div class="field">
<input class="ipt ipt-large ipt-radius grid-4-5" id="release-new-title" name="title" placeholder="{{.i18n.Tr "repo.release.release_title"}}" value="{{.Release.Title}}" required>
</div>
<br>
<div class="field grid-4-5">
<div class="md-help pull-right">
{{.i18n.Tr "repo.release.content_with_md" "https://help.github.com/articles/markdown-basics" | Str2html}}
</div>
<div class="clear">
<ul class="tab-nav list-unstyled">
<li class="js-tab-nav js-tab-nav-show left" data-tab-target="#release-textarea">
<button class="btn btn-medium btn-gray btn-left-radius">{{.i18n.Tr "repo.release.write"}}</button>
</li>
<li class="js-tab-nav left markdown-preview" id="release-preview-btn" data-tab-target="#release-preview" data-ajax="/api/v1/markdown" data-ajax-name="release-preview" data-ajax-context="{{.RepoLink}}" data-ajax-method="post" data-preview="#release-preview">
<button class="btn btn-medium btn-gray btn-right-radius">{{.i18n.Tr "repo.release.preview"}}</button>
</li>
</ul>
</div>
<div id="release-textarea">
<div class="form-group">
<textarea class="ipt ipt-large ipt-radius" name="content" id="release-new-content" rows="10" placeholder="{{.i18n.Tr "repo.release.content_placeholder"}}" data-ajax-rel="release-preview" data-ajax-val="val" data-ajax-field="text" required>{{.Release.Note}}</textarea>
</div>
</div>
<div class="markdown hide" id="release-preview">{{.i18n.Tr "repo.release.loading"}}</div>
<br>
<hr>
<div class="text-right">
<input class="ipt-chk" name="prerelease" type="checkbox" {{if .Release.IsPrerelease}}checked{{end}}/>
<span><strong>{{.i18n.Tr "repo.release.prerelease_desc"}}</strong></span>
<p>{{.i18n.Tr "repo.release.prerelease_helper"}}</p>
<button class="btn btn-large btn-green btn-radius">Publish release</button>
{{if .Release.IsDraft}}
<input class="btn btn-large btn-gary btn-radius" type="submit" name="draft" value="{{.i18n.Tr "repo.release.save_draft"}}"/>
{{end}}
</div>
</div>
<div class="tab-pane release-preview-content" id="release-preview">loading...</div>
</div>
</form>
</div>
<div class="text-right form-group col-md-8" style="display: block">
<hr/>
<label for="release-new-pre-release">
<input id="release-new-pre-release" type="checkbox" name="prerelease" {{if .Release.IsPrerelease}}checked{{end}}/>
<strong>This is a pre-release</strong>
</label>
<p class="help-block">Well point out that this release is identified as non-production ready.</p>
</div>
<div class="text-right form-group col-md-8" style="display: block">
<button class="btn-success btn">Publish release</button>
<input class="btn btn-default" type="submit" name="draft" value="Save draft"/>
</div>
</form>
</div>
{{template "repo/sidebar" .}}
</div>
</div>
{{template "base/footer" .}}
{{template "ng/base/footer" .}}

View File

@@ -1,62 +1,71 @@
{{template "base/head" .}}
{{template "base/navbar" .}}
{{template "repo/nav" .}}
{{template "repo/toolbar" .}}
<div id="body" class="container">
<div id="release">
<h4 id="release-head">
<span class="release"><strong>Releases</strong></span><!-- /
<a class="tag" href="{{AppSubUrl}}/{tag_link}">Tags</a> -->
<!-- comment : if in tag page, show a.release and span.tag please -->
</h4>
<ul id="release-list" class="list-unstyled">
{{range .Releases}}
<li class="release-item clearfix" id="release-{{.Sha1}}">
{{if .PublisherId}}
<div class="col-md-2 text-right">
{{if .IsDraft}}
<span class="btn btn-primary status pre-release">Draft</span>
{{else if .IsPrerelease}}
<span class="btn btn-warning status pre-release">Pre-Release</span>
{{else}}
<span class="btn btn-success status stable">Stable</span>
{{template "ng/base/head" .}}
{{template "ng/base/header" .}}
<div id="repo-wrapper">
{{template "repo/header" .}}
<div id="repo-content" class="clear container">
<div id="repo-main" class="left grid-5-6">
<div id="release">
<h4 id="release-head">
<span class="release"><strong>{{.i18n.Tr "repo.release.releases"}}</strong></span><!-- /
<a class="tag" href="{{AppSubUrl}}/{tag_link}">Tags</a> -->
<!-- comment : if in tag page, show a.release and span.tag please -->
<a class="btn" href="{{$.RepoLink}}/releases/new">
<button class="btn btn-medium btn-blue btn-radius">
{{.i18n.Tr "repo.release.new_release"}}
</button>
</a>
</h4>
<ul id="release-list" class="list-unstyled">
{{range .Releases}}
<li class="release-item clearfix" id="release-{{.Sha1}}">
{{if .PublisherId}}
<div class="grid-1-6 text-right release-meta">
{{if .IsDraft}}
<span class="label label-blue label-radius">{{$.i18n.Tr "repo.release.draft"}}</span>
{{else if .IsPrerelease}}
<span class="label label-orange label-radius">{{$.i18n.Tr "repo.release.prerelease"}}</span>
{{else}}
<span class="label label-green label-radius">{{$.i18n.Tr "repo.release.stable"}}</span>
{{end}}
<a class="tag" href="{{$.RepoLink}}/src/{{.TagName}}" rel="nofollow"><i class="fa fa-tag"></i> {{.TagName}}</a>
<a class="commit" href="{{$.RepoLink}}/src/{{.Sha1}}" rel="nofollow"><i class="fa fa-code"></i> {{ShortSha .Sha1}}</a>
</div>
<div class="grid-9-12 release-detail left">
<h4 class="title"><a href="{{$.RepoLink}}/src/{{.TagName}}">{{.Title}}</a> <small>(<a href="{{$.RepoLink}}/releases/edit/{{.TagName}}" rel="nofollow">{{$.i18n.Tr "repo.release.edit"}}</a>)</small></h4>
<p class="info">
<span class="author"><img class="avatar-20" src="{{.Publisher.AvatarLink}}">&nbsp;&nbsp;
<a href="{{AppSubUrl}}/{{.Publisher.Name}}">{{.Publisher.Name}}</a></span>
{{if .Created}}<span class="time">{{TimeSince .Created $.Lang}}</span>{{end}}
<span class="ahead">{{$.i18n.Tr "repo.release.ahead" .NumCommitsBehind .Target | Str2html}}</span>
</p>
<div class="markdown desc">
{{str2html .Note}}
</div>
<p class="download">
<a class="btn btn-gray btn-large btn-radius" href="{{$.RepoLink}}/archive/{{.TagName}}.zip" rel="nofollow"><i class="fa fa-download"></i> {{$.i18n.Tr "repo.release.source_code"}} (ZIP)</a>
<a class="btn btn-gray btn-large btn-radius" href="{{$.RepoLink}}/archive/{{.TagName}}.tar.gz"><i class="fa fa-download"></i> {{$.i18n.Tr "repo.release.source_code"}} (TAR.GZ)</a>
</p>
<span class="dot">&nbsp;</span>
</div>
{{else}}
<div class="grid-1-6 text-right release-meta">
<a class="commit" href="{{$.RepoLink}}/src/{{.Sha1}}" rel="nofollow"><i class="fa fa-code"></i> {{ShortSha .Sha1}}</a>
</div>
<div class="grid-9-12 release-detail left">
<h5 class="title"><a href="{{$.RepoLink}}/src/{{.TagName}}" rel="nofollow">{{.TagName}}</a> <i class="fa fa-tag"></i></h5>
<p class="download">
<a class="download-link" href="{{$.RepoLink}}/archive/{{.TagName}}.zip" rel="nofollow"><i class="fa fa-download"></i> ZIP</a>
<a class="download-link" href="{{$.RepoLink}}/archive/{{.TagName}}.tar.gz"><i class="fa fa-download"></i> TAR.GZ</a>
</p>
<span class="dot">&nbsp;</span>
</div>
{{end}}
</li>
{{end}}
<a class="tag" href="{{$.RepoLink}}/src/{{.TagName}}" rel="nofollow"><i class="fa fa-tag"></i>{{.TagName}}</a>
<a class="commit" href="{{$.RepoLink}}/src/{{.Sha1}}" rel="nofollow"><i class="fa fa-code"></i>{{ShortSha .Sha1}}</a>
</div>
<div class="col-md-10">
<h4 class="title"><a href="{{$.RepoLink}}/src/{{.TagName}}">{{.Title}}</a> <small>(<a href="{{$.RepoLink}}/releases/edit/{{.TagName}}" rel="nofollow">edit</a>)</small></h4>
<p class="info">
<span class="author"><img class="avatar" src="{{.Publisher.AvatarLink}}" alt="" width="20">&nbsp;&nbsp;
<a href="{{AppSubUrl}}/user/{{.Publisher.Name}}">{{.Publisher.Name}}</a></span>
{{if .Created}}<span class="time">{{TimeSince .Created $.Lang}}</span>{{end}}
<span class="ahead"><strong>{{.NumCommitsBehind}}</strong> commits to {{.Target}} since this release</span>
</p>
<div class="markdown desc">
{{str2html .Note}}
</div>
<p class="download">
<a class="btn btn-default" href="{{$.RepoLink}}/archive/{{.TagName}}.zip" rel="nofollow"><i class="fa fa-download"></i>Source Code (ZIP)</a>
<a class="btn btn-default" href="{{$.RepoLink}}/archive/{{.TagName}}.tar.gz"><i class="fa fa-download"></i>Source Code (TAR.GZ)</a>
</p>
<span class="dot">&nbsp;</span>
</div>
{{else}}
<div class="col-md-2 text-right">
<a class="commit" href="{{$.RepoLink}}/src/{{.Sha1}}" rel="nofollow"><i class="fa fa-code"></i>{{ShortSha .Sha1}}</a>
</div>
<div class="col-md-10">
<h5 class="title"><a href="{{$.RepoLink}}/src/{{.TagName}}" rel="nofollow">{{.TagName}}</a><i class="fa fa-tag"></i></h5>
<p class="download">
<a class="download-link" href="{{$.RepoLink}}/archive/{{.TagName}}.zip" rel="nofollow"><i class="fa fa-download"></i>zip</a>
<a class="download-link" href="{{$.RepoLink}}/archive/{{.TagName}}.tar.gz"><i class="fa fa-download"></i>tar.gz</a>
</p>
<span class="dot">&nbsp;</span>
</div>
{{end}}
</li>
{{end}}
</ul>
</ul>
</div>
</div>
{{template "repo/sidebar" .}}
</div>
</div>
{{template "base/footer" .}}
{{template "ng/base/footer" .}}

View File

@@ -1,70 +1,68 @@
{{template "base/head" .}}
{{template "base/navbar" .}}
{{template "repo/nav" .}}
{{template "repo/toolbar" .}}
<div id="body" class="container">
<div id="release">
<h4 id="release-head">New Release</h4>
{{template "base/alert" .}}
<form id="release-new-form" action="{{.RepoLink}}/releases/new" method="post" class="form form-inline">
{{.CsrfTokenHtml}}
<div class="form-group">
<input id="tag-name" name="tag_name" type="text" class="form-control" placeholder="tag name" value="{{.tag_name}}" />
<span class="target-at">@</span>
<div class="btn-group" id="release-new-target-select">
<button type="button" class="btn btn-default"><i class="fa fa-code-fork fa-lg fa-m"></i>
<span class="target-text">Target : </span>
<strong id="release-new-target-name"> {{.Repository.DefaultBranch}}</strong>
</button>
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
<span class="caret"></span>
</button>
<div class="dropdown-menu clone-group-btn" id="release-new-target-branch-list">
<ul class="list-group">
{{range .Branches}}
<li class="list-group-item">
<a href="#" rel="{{.}}"><i class="fa fa-code-fork"></i>{{.}}</a>
</li>
{{end}}
</ul>
{{template "ng/base/head" .}}
{{template "ng/base/header" .}}
<div id="repo-wrapper">
{{template "repo/header" .}}
<div id="repo-content" class="clear container">
<div id="repo-main" class="left grid-5-6">
{{template "ng/base/alert" .}}
<div id="release">
<h4 id="release-head">{{.i18n.Tr "repo.release.new_release"}}</h4>
<form class="form" id="release-new-form" action="{{.RepoLink}}/releases/new" method="post">
{{.CsrfTokenHtml}}
<div class="field">
<input class="ipt ipt-large ipt-radius" name="tag_name" value="{{.tag_name}}" placeholder="{{.i18n.Tr "repo.release.tag_name"}}" required>
<span class="target-at">@</span>
<div class="inline-block drop">
<button class="btn btn-gray btn-medium btn-radius drop-bottom">
<i class="octicon octicon-git-branch"></i> {{.i18n.Tr "repo.release.target"}} :
<strong id="repo-branch-current">{{.Repository.DefaultBranch}}</strong>
</button>
<ul class="drop-down menu menu-vertical menu-radius switching-list" id="release-new-target-branch-list">
{{range .Branches}}
<li {{if eq . $.tag_target}}class="checked"{{end}}><a><i class="octicon octicon-check"></i>{{.}}</a></li>
{{end}}
</ul>
</div>
<input id="tag-target" type="hidden" name="tag_target" value="{{.tag_target}}"/>
</div>
<input id="tag-target" type="hidden" name="tag_target" value="{{.Repository.DefaultBranch}}"/>
</div>
<p class="help-block">Choose an existing tag, or create a new tag on publish</p>
</div>
<div class="form-group" style="display: block">
<input class="form-control input-lg" id="release-new-title" name="title" type="text" placeholder="release title" value="{{.title}}" />
</div>
<div class="form-group col-md-8" style="display: block" id="release-new-content-div">
<div class="md-help pull-right">
Content with <a href="https://help.github.com/articles/markdown-basics">Markdown</a>
</div>
<ul class="nav nav-tabs" data-init="tabs">
<li class="release-write active"><a href="#release-textarea" data-toggle="tab">Write</a></li>
<li class="release-preview"><a href="#release-preview" data-toggle="tab" data-ajax="/api/v1/markdown" data-ajax-name="release-preview" data-ajax-context="{{.RepoLink}}" data-ajax-method="post" data-preview="#release-preview">Preview</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="release-textarea">
<div class="form-group">
<textarea class="form-control" name="content" id="release-new-content" rows="10" placeholder="Write some content" data-ajax-rel="release-preview" data-ajax-val="val" data-ajax-field="text">{{.content}}</textarea>
<p class="help">{{.i18n.Tr "repo.release.tag_helper"}}</p>
<div class="field">
<input class="ipt ipt-large ipt-radius grid-4-5" id="release-new-title" name="title" placeholder="{{.i18n.Tr "repo.release.release_title"}}" value="{{.title}}" required>
</div>
<br>
<div class="field grid-4-5">
<div class="md-help pull-right">
{{.i18n.Tr "repo.release.content_with_md" "https://help.github.com/articles/markdown-basics" | Str2html}}
</div>
<div class="clear">
<ul class="tab-nav list-unstyled">
<li class="js-tab-nav js-tab-nav-show left" data-tab-target="#release-textarea">
<button class="btn btn-medium btn-gray btn-left-radius">{{.i18n.Tr "repo.release.write"}}</button>
</li>
<li class="js-tab-nav left markdown-preview" id="release-preview-btn" data-tab-target="#release-preview" data-ajax="/api/v1/markdown" data-ajax-name="release-preview" data-ajax-context="{{.RepoLink}}" data-ajax-method="post" data-preview="#release-preview">
<button class="btn btn-medium btn-gray btn-right-radius">{{.i18n.Tr "repo.release.preview"}}</button>
</li>
</ul>
</div>
<div id="release-textarea">
<div class="form-group">
<textarea class="ipt ipt-large ipt-radius" name="content" id="release-new-content" rows="10" placeholder="{{.i18n.Tr "repo.release.content_placeholder"}}" data-ajax-rel="release-preview" data-ajax-val="val" data-ajax-field="text" required>{{.content}}</textarea>
</div>
</div>
<div class="markdown hide" id="release-preview">{{.i18n.Tr "repo.release.loading"}}</div>
<hr>
<div class="text-right">
<input class="ipt-chk" name="prerelease" type="checkbox" {{if .prerelease}}checked{{end}}/>
<span><strong>{{.i18n.Tr "repo.release.prerelease_desc"}}</strong></span>
<p>{{.i18n.Tr "repo.release.prerelease_helper"}}</p>
<button class="btn btn-large btn-green btn-radius">{{.i18n.Tr "repo.release.publish"}}</button>
<input class="btn btn-large btn-gary btn-radius" type="submit" name="draft" value="{{.i18n.Tr "repo.release.save_draft"}}"/>
</div>
</div>
<div class="tab-pane release-preview-content" id="release-preview">loading...</div>
</div>
</form>
</div>
<div class="text-right form-group col-md-8" style="display: block">
<hr/>
<label for="release-new-pre-release">
<input id="release-new-pre-release" type="checkbox" name="prerelease" {{if .prerelease}}checked{{end}}/>
<strong>This is a pre-release</strong>
</label>
<p class="help-block">Well point out that this release is identified as non-production ready.</p>
</div>
<div class="text-right form-group col-md-8" style="display: block">
<button class="btn-success btn">Publish release</button>
<input class="btn btn-default" type="submit" name="draft" value="Save draft"/>
</div>
</form>
</div>
{{template "repo/sidebar" .}}
</div>
</div>
{{template "base/footer" .}}
{{template "ng/base/footer" .}}

View File

@@ -1,14 +1,20 @@
<table id="repo-files-table" class="table-border table-block table-radius">
<thead>
<tr>
<th colspan="4" class="clear">
<th colspan="5" class="clear">
<span class="author left">
{{if .LastCommitUser}}
<img class="avatar-24 radius" src="{{.LastCommitUser.AvatarLink}}" />
<a href="{{AppSubUrl}}/{{.LastCommitUser.Name}}"><strong>{{.LastCommit.Author.Name}}</strong></a>:
{{else}}
<img class="avatar-24 radius" src="{{AvatarLink .LastCommit.Author.Email}}" />
{{if .LastCommitUser}}<a href="{{AppSubUrl}}/{{.LastCommitUser}}">{{end}}<strong>{{.LastCommit.Author.Name}}</strong>:{{if .LastCommitUser}}</a>{{end}}
<strong>{{.LastCommit.Author.Name}}</strong>:
{{end}}
&nbsp;
</span>
<span class="last-commit"><a href="{{.RepoLink}}/commit/{{.LastCommit.Id}}" rel="nofollow">
<strong>{{ShortSha .LastCommit.Id.String}}</strong></a>
<span class="text-truncate">{{.LastCommit.Summary}}</span>
<span class="text-truncate">{{Str2html .LastCommit.Summary}}</span>
</span>
<span class="age right">{{TimeSince .LastCommit.Author.When $.Lang}}</span>
</th>
@@ -19,6 +25,7 @@
<tr class="has-parent">
<td class="icon"></td>
<td class="name"><a href="{{EscapePound .BranchLink}}{{.ParentPath}}">..</a></td>
<th class="sha">SHA1</th>
<td class="msg"></td>
<td class="age"></td>
</tr>
@@ -42,8 +49,11 @@
<a href="{{EscapePound $.BranchLink}}/{{$.TreePath}}{{$entry.Name}}" class="text-truncate">{{$entry.Name}}</a>
</td>
{{end}}
<td class="msg">
<a class="text-truncate" href="{{AppSubUrl}}/{{$.Username}}/{{$.Reponame}}/commit/{{$commit.Id}}" rel="nofollow">{{$commit.Summary}}</a>
<td class="sha">
<a rel="nofollow" class="label label-green" href="{{AppSubUrl}}/{{$.Username}}/{{$.Reponame}}/commit/{{$commit.Id}} ">{{SubStr $commit.Id.String 0 10}} </a>
</td>
<td class="message">
<span class="text-truncate">{{Str2html $commit.Summary}}</span>
</td>
<td class="age">{{TimeSince $commit.Committer.When $.Lang}}</td>
</tr>

View File

@@ -26,18 +26,16 @@
<button class="btn btn-green btn-large btn-radius">{{.i18n.Tr "sign_in"}}</button>&nbsp;&nbsp;&nbsp;&nbsp;
{{if not .IsSocialLogin}}<a href="{{AppSubUrl}}/user/forget_password">{{.i18n.Tr "auth.forget_password"}}</a>{{end}}
</div>
{{if not .IsSocialLogin}}
<div class="field">
<label></label>
<a href="{{AppSubUrl}}/user/sign_up">{{.i18n.Tr "auth.sign_up_now" | Str2html}}</a>
</div>
{{if .OauthEnabled}}
{{if and (not .IsSocialLogin) .OauthEnabled}}
<hr/>
<div id="sign-social" class="text-center social-buttons">
{{template "ng/base/social" .}}
</div>
{{end}}
{{end}}
</div>
</form>
</div>

Some files were not shown because too many files have changed in this diff Show More