mirror of
https://github.com/gogs/gogs.git
synced 2026-03-01 01:30:57 +01:00
Compare commits
150 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7cf0564587 | ||
|
|
1cb57b1a44 | ||
|
|
8f0f845b14 | ||
|
|
e9c599b48a | ||
|
|
e6cf83b8c0 | ||
|
|
deee2d5fa8 | ||
|
|
4aecaf7488 | ||
|
|
82f7a01ded | ||
|
|
49aeb87e44 | ||
|
|
104d914b39 | ||
|
|
8e815abeb0 | ||
|
|
8fa2056e14 | ||
|
|
e7f4d23412 | ||
|
|
466facc009 | ||
|
|
33894591a6 | ||
|
|
35c83f6026 | ||
|
|
fc6db829b2 | ||
|
|
69025f1510 | ||
|
|
d61962a18a | ||
|
|
588f3215c6 | ||
|
|
471b8a18ab | ||
|
|
c226e92284 | ||
|
|
80b23854bc | ||
|
|
86abd34eb8 | ||
|
|
7dbb98b2a3 | ||
|
|
25dd6f8fa0 | ||
|
|
37ab32b613 | ||
|
|
fd07de5751 | ||
|
|
27491031ba | ||
|
|
8238c28c31 | ||
|
|
08cd20bad9 | ||
|
|
96a95e9dfd | ||
|
|
f745b08163 | ||
|
|
d0e34c57cc | ||
|
|
2bfe2ddb6d | ||
|
|
b72e75e522 | ||
|
|
b668fc7aad | ||
|
|
48bb639371 | ||
|
|
0720d3988f | ||
|
|
7ba9d1171c | ||
|
|
6b70a0c0d9 | ||
|
|
98674b2a21 | ||
|
|
4aafeace23 | ||
|
|
34102f7889 | ||
|
|
da6fd93f0d | ||
|
|
406efbf3f5 | ||
|
|
6abbea4f3d | ||
|
|
5d5d774e03 | ||
|
|
5e763baa12 | ||
|
|
18c0697329 | ||
|
|
e3d73d9b24 | ||
|
|
6c84223f43 | ||
|
|
b447d18dca | ||
|
|
63a73b43b4 | ||
|
|
3db80f2c55 | ||
|
|
a6a2f59d1d | ||
|
|
d446be9f5f | ||
|
|
8d17ff8ce7 | ||
|
|
b0b11fd7b1 | ||
|
|
f44204e944 | ||
|
|
473e265727 | ||
|
|
3a6ba39a61 | ||
|
|
0d90a16d9f | ||
|
|
fab038b175 | ||
|
|
e3dece1371 | ||
|
|
d5de48df89 | ||
|
|
8896c82d34 | ||
|
|
1f61340fa3 | ||
|
|
f92bfabf86 | ||
|
|
cd8b43d984 | ||
|
|
556881964f | ||
|
|
ee68a826a5 | ||
|
|
e90f014e4a | ||
|
|
125fe92a19 | ||
|
|
10e4b5b6c6 | ||
|
|
7ccab9cd09 | ||
|
|
2369881808 | ||
|
|
04164eada3 | ||
|
|
e97a6ff911 | ||
|
|
7d109573cb | ||
|
|
74a8bb93d8 | ||
|
|
059338139c | ||
|
|
aa670ce660 | ||
|
|
81fcc0db0c | ||
|
|
c753fdceaf | ||
|
|
a6a99d49cf | ||
|
|
9dfa17faf2 | ||
|
|
3fcc39c26b | ||
|
|
1654e9ecab | ||
|
|
bbee7b7196 | ||
|
|
4f567edc6e | ||
|
|
fc4dff1b17 | ||
|
|
065f8d1f56 | ||
|
|
2f1369c614 | ||
|
|
8f1d2d9f24 | ||
|
|
3efe3f42e8 | ||
|
|
5293ae1221 | ||
|
|
d2f439a241 | ||
|
|
77ac1e6ff6 | ||
|
|
c0ad512398 | ||
|
|
563e8b4ea9 | ||
|
|
be19fe48d7 | ||
|
|
b508fb041f | ||
|
|
1628ef4ba5 | ||
|
|
0fa209d07b | ||
|
|
6e341e26b3 | ||
|
|
a307574fbc | ||
|
|
58e28e5d9d | ||
|
|
4e18bbf1cf | ||
|
|
e6fc58a744 | ||
|
|
aa68e86206 | ||
|
|
7759b9ee6e | ||
|
|
b6519f78c7 | ||
|
|
455fad0fbd | ||
|
|
ed89b39984 | ||
|
|
f9454cc32c | ||
|
|
d85366930c | ||
|
|
f625665d8d | ||
|
|
d047811c1a | ||
|
|
685ed1f807 | ||
|
|
8c1986181d | ||
|
|
cd6a2b78a7 | ||
|
|
0009a1d2b1 | ||
|
|
cdd8f7c53a | ||
|
|
ddf7014b9b | ||
|
|
2692d4aa49 | ||
|
|
25f5a8d798 | ||
|
|
3aaf292ba8 | ||
|
|
6b7d35eade | ||
|
|
6d0f3a07d4 | ||
|
|
b99c4baab2 | ||
|
|
7fda0cdb93 | ||
|
|
0b3722c359 | ||
|
|
31eb49c3ae | ||
|
|
8a6c86644e | ||
|
|
6c1ee384f1 | ||
|
|
0a4cda0dd4 | ||
|
|
2804784df9 | ||
|
|
876a856759 | ||
|
|
7e7160eefd | ||
|
|
c5c467a9cd | ||
|
|
c7a042ef36 | ||
|
|
e805fdb29c | ||
|
|
0d158e569b | ||
|
|
00653e52ee | ||
|
|
4e79adf6b5 | ||
|
|
03af37554e | ||
|
|
fd1df86c44 | ||
|
|
bef38d9d3f | ||
|
|
76f8904718 |
@@ -1,6 +1,6 @@
|
||||
[run]
|
||||
init_cmds = [
|
||||
["grep", "-rn", "FIXME", "."],
|
||||
#["grep", "-rn", "FIXME", "."],
|
||||
["./gogs", "web"]
|
||||
]
|
||||
watch_all = true
|
||||
@@ -14,6 +14,7 @@ watch_dirs = [
|
||||
watch_exts = [".go", ".ini"]
|
||||
build_delay = 1500
|
||||
cmds = [
|
||||
#["go-bindata", "-o=modules/bindata/bindata.go", "-ignore=\\.DS_Store|README", "-pkg=bindata", "conf/..."],
|
||||
["go", "install", "-tags", "sqlite cert"],# redis memcache
|
||||
["go", "build", "-tags", "sqlite cert"],
|
||||
["./gogs", "web"]
|
||||
|
||||
12
.editorconfig
Normal file
12
.editorconfig
Normal file
@@ -0,0 +1,12 @@
|
||||
# http://editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_style = tab
|
||||
|
||||
[*.yml]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
22
.gobuild.yml
22
.gobuild.yml
@@ -1,22 +0,0 @@
|
||||
filesets:
|
||||
includes:
|
||||
- conf
|
||||
- etc
|
||||
- public
|
||||
- scripts
|
||||
- templates
|
||||
- LICENSE
|
||||
- README.md
|
||||
- README_ZH.md
|
||||
excludes:
|
||||
- \.git
|
||||
depth: 5
|
||||
settings:
|
||||
build: |
|
||||
if test "$GOOS" = "windows" -a "$GOARCH" = "386"
|
||||
then
|
||||
go install -v
|
||||
else
|
||||
go get -v -tags "sqlite redis memcache cert" github.com/gogits/gogs
|
||||
go install -v -tags "sqlite redis memcache cert"
|
||||
fi
|
||||
38
.gopmfile
38
.gopmfile
@@ -5,33 +5,33 @@ path = github.com/gogits/gogs
|
||||
github.com/bradfitz/gomemcache = commit:72a68649ba
|
||||
github.com/Unknwon/cae = commit:2e70a1351b
|
||||
github.com/Unknwon/com = commit:188d690b1a
|
||||
github.com/Unknwon/i18n = commit:1e88666229
|
||||
github.com/Unknwon/macaron = commit:e089393c3f
|
||||
github.com/codegangsta/cli = commit:6086d7927e
|
||||
github.com/go-sql-driver/mysql = commit:27633f0519
|
||||
github.com/go-xorm/core = commit:16cb27928f
|
||||
github.com/go-xorm/xorm = commit:f2d3be988e
|
||||
github.com/Unknwon/i18n = commit:7457d88830
|
||||
github.com/Unknwon/macaron = commit:93de4f3fad
|
||||
github.com/codegangsta/cli = commit:2bcd11f863
|
||||
github.com/go-sql-driver/mysql = commit:a197e5d405
|
||||
github.com/go-xorm/core = commit:be6e7ac47d
|
||||
github.com/go-xorm/xorm = commit:1f0dd9bef2
|
||||
github.com/gogits/chardet = commit:2404f77725
|
||||
github.com/gogits/go-gogs-client = commit:92e76d616a
|
||||
github.com/lib/pq = commit:835d5eb08d
|
||||
github.com/macaron-contrib/binding = commit:dc739fabc3
|
||||
github.com/macaron-contrib/cache = commit:b68f6b448f
|
||||
github.com/macaron-contrib/captcha = commit:066c50c7eb
|
||||
github.com/lib/pq = commit:30ed2200d7
|
||||
github.com/macaron-contrib/binding = commit:548a793679
|
||||
github.com/macaron-contrib/cache = commit:928d5c35cd
|
||||
github.com/macaron-contrib/captcha = commit:fbb8b1ebb5
|
||||
github.com/macaron-contrib/csrf = commit:98ddf5a710
|
||||
github.com/macaron-contrib/i18n = commit:eeebd44f64
|
||||
github.com/macaron-contrib/i18n = commit:627d60fe6f
|
||||
github.com/macaron-contrib/oauth2 = commit:8f394c3629
|
||||
github.com/macaron-contrib/session = commit:8e8d938b27
|
||||
github.com/macaron-contrib/session = commit:31e841d95c
|
||||
github.com/macaron-contrib/toolbox = commit:acbfe36e16
|
||||
github.com/mattn/go-sqlite3 = commit:25d045f12a
|
||||
github.com/mattn/go-sqlite3 = commit:5253daf856
|
||||
github.com/microcosm-cc/bluemonday = commit:fcd0f5074e
|
||||
github.com/nfnt/resize = commit:8f44931448
|
||||
github.com/russross/blackfriday = commit:77efab57b2
|
||||
github.com/shurcooL/go = commit:329f57438c
|
||||
golang.org/x/net =
|
||||
golang.org/x/text =
|
||||
github.com/nfnt/resize = commit:53e9ca890b
|
||||
github.com/russross/blackfriday = commit:6928e11ecd
|
||||
github.com/shurcooL/go = commit:bc30a0bd33
|
||||
golang.org/x/net = commit:0b492c5a96
|
||||
golang.org/x/text = commit:c6bc7e82e2
|
||||
gopkg.in/ini.v1 = commit:4febc4104c
|
||||
gopkg.in/redis.v2 = commit:e617904962
|
||||
|
||||
[res]
|
||||
include = conf|etc|public|scripts|templates
|
||||
include = etc|public|scripts|templates
|
||||
|
||||
|
||||
@@ -12,4 +12,5 @@ script: go build -v
|
||||
|
||||
notifications:
|
||||
email:
|
||||
- u@gogs.io
|
||||
- u@gogs.io
|
||||
slack: gophercn:o5pSanyTeNhnfYc3QnG0X7Wx
|
||||
@@ -2,20 +2,20 @@
|
||||
|
||||
> This guidelines sheet is forked from [CONTRIBUTING.md](https://github.com/drone/drone/blob/master/CONTRIBUTING.md).
|
||||
|
||||
Gogs is not perfect and it has bugs, or incomplete features for rare cases. You're welcome to tell us or contribute some code. This document describes details about how can you contribute to Gogs project.
|
||||
Gogs is not perfect, and it has bugs or incomplete features in rare cases. You're welcome to tell us, or to contribute some code. This document describes details about how can you contribute to Gogs project.
|
||||
|
||||
## Contribution guidelines
|
||||
|
||||
Depends on the situation, you will:
|
||||
|
||||
- Find bug, create an issue
|
||||
- Need more functionality, make a feature request
|
||||
- Want to contribute code, open a pull request
|
||||
- Run into issue, need help
|
||||
- Find a bug and create an issue
|
||||
- Need more functionality and make a feature request
|
||||
- Want to contribute code and open a pull request
|
||||
- Run into issue and need help
|
||||
|
||||
### Bug Report
|
||||
|
||||
If you find or consider something is a bug, please create a issue on [GitHub](https://github.com/gogits/gogs/issues). To reduce unnecessary time wasting of interacting and waiting with team members, please include following information in the first place with a comfortable form for you:
|
||||
If you find something you consider a bug, please create a issue on [GitHub](https://github.com/gogits/gogs/issues). To avoid wasting time and reduce back-and-forth communication with team members, please include at least the following information in a form comfortable for you:
|
||||
|
||||
- Bug Description
|
||||
- Gogs Version
|
||||
@@ -28,7 +28,7 @@ Please take a moment to check that an issue on [GitHub](https://github.com/gogit
|
||||
|
||||
#### Bug Report Example
|
||||
|
||||
Gogs crashed when create repository with license, using v0.5.13.0207, SQLite3, Git 1.9.0, Ubuntu 12.04.
|
||||
Gogs crashed when creating a repository with a license, using v0.5.13.0207, SQLite3, Git 1.9.0, Ubuntu 12.04.
|
||||
|
||||
Error log:
|
||||
|
||||
@@ -38,11 +38,11 @@ Error log:
|
||||
|
||||
### Feature Request
|
||||
|
||||
There is no standard form of making a feature request, just try to describe the feature as clear as possible because team members may not have experience with the functionality you're talking about.
|
||||
There is no standard form of making a feature request. Just try to describe the feature as clearly as possible, because team members may not have experience with the functionality you're talking about.
|
||||
|
||||
### Pull Request
|
||||
|
||||
Pull requests are always welcome, but note that **ALL PULL REQUESTS MUST SEND TO `DEV` BRANCH**.
|
||||
Pull requests are always welcome, but note that **ALL PULL REQUESTS MUST APPLY TO THE `DEV` BRANCH**.
|
||||
|
||||
We are always thrilled to receive pull requests, and do our best to process them as fast as possible. Not sure if that typo is worth a pull request? Do it! We will appreciate it.
|
||||
|
||||
@@ -52,7 +52,7 @@ We're trying very hard to keep Gogs lean and focused. We don't want it to do eve
|
||||
|
||||
### Ask For Help
|
||||
|
||||
Before open any new issue, please check your problem on [Troubleshooting](http://gogs.io/docs/intro/troubleshooting.md) and [FAQs](http://gogs.io/docs/intro/faqs.html) pages.
|
||||
Before opening an issue, please make sure your problem isn't already addressed on the [Troubleshooting](http://gogs.io/docs/intro/troubleshooting.md) and [FAQs](http://gogs.io/docs/intro/faqs.html) pages.
|
||||
|
||||
## Things To Notice
|
||||
|
||||
|
||||
17
Dockerfile
Normal file
17
Dockerfile
Normal file
@@ -0,0 +1,17 @@
|
||||
FROM google/golang:latest
|
||||
|
||||
ENV TAGS="sqlite redis memcache cert" USER="git" HOME="/home/git"
|
||||
|
||||
COPY . /gopath/src/github.com/gogits/gogs/
|
||||
WORKDIR /gopath/src/github.com/gogits/gogs/
|
||||
|
||||
RUN go get -v -tags="$TAGS" github.com/gogits/gogs \
|
||||
&& go build -tags="$TAGS" \
|
||||
&& useradd -d $HOME -m $USER \
|
||||
&& chown -R $USER .
|
||||
|
||||
USER $USER
|
||||
|
||||
ENTRYPOINT [ "./gogs" ]
|
||||
|
||||
CMD [ "web" ]
|
||||
34
README.md
34
README.md
@@ -3,18 +3,18 @@ Gogs - Go Git Service [](https://gitter.im/gogits/gogs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
Gogs(Go Git Service) is a painless self-hosted Git Service written in Go.
|
||||
Gogs (Go Git Service) is a painless self-hosted Git service written in Go.
|
||||
|
||||

|
||||
|
||||
##### Current version: 0.5.13 Beta
|
||||
##### Current version: 0.6.0 Beta
|
||||
|
||||
### NOTICES
|
||||
|
||||
- Due to testing purpose, data of [try.gogs.io](https://try.gogs.io) has been reset in **Jan 28, 2015** and will reset multiple times after. Please do **NOT** put your important data on the site.
|
||||
- Demo site [try.gogs.io](https://try.gogs.io) is running under `dev` branch.
|
||||
- You **MUST** read [CONTRIBUTING.md](CONTRIBUTING.md) before you start filing a issue or making a Pull Request.
|
||||
- If you think there are vulnerabilities in the project, please talk private to **u@gogs.io**, thanks!
|
||||
- The demo site [try.gogs.io](https://try.gogs.io) is running under `develop` branch.
|
||||
- You **MUST** read [CONTRIBUTING.md](CONTRIBUTING.md) before you start filing an issue or making a Pull Request, and **MUST** discuss with us on [Gitter](https://gitter.im/gogits/gogs) for UI changes and feature Pull Reuqests, otherwise it's high possibilities that we are not going to merge it.
|
||||
- If you think there are vulnerabilities in the project, please talk privately to **u@gogs.io**. Thanks!
|
||||
|
||||
#### Other language version
|
||||
|
||||
@@ -22,15 +22,15 @@ Gogs(Go Git Service) is a painless self-hosted Git Service written in Go.
|
||||
|
||||
## Purpose
|
||||
|
||||
The goal of this project is to make the easiest, fastest and most painless way to set up a self-hosted Git service. With Go, this can be done in independent binary distribution across **ALL platforms** that Go supports, including Linux, Mac OS X, and Windows.
|
||||
The goal of this project is to make the easiest, fastest, and most painless way to set up a self-hosted Git service. With Go, this can be done via an independent binary distribution across **ALL platforms** that Go supports, including Linux, Mac OS X, and Windows.
|
||||
|
||||
## Overview
|
||||
|
||||
- Please see [Documentation](http://gogs.io/docs/intro/) for project design, known issues, and change log.
|
||||
- See [Trello Board](https://trello.com/b/uxAoeLUl/gogs-go-git-service) to follow the develop team.
|
||||
- Try it before anything? Do it [online](https://try.gogs.io/unknwon/gogs) or go down to **Installation -> Install from binary** section!
|
||||
- Having troubles? Get help from [Troubleshooting](http://gogs.io/docs/intro/troubleshooting.md).
|
||||
- Want to help on localization? Check out [Crowdin](https://crowdin.com/project/gogs)!
|
||||
- Please see the [Documentation](http://gogs.io/docs/intro/) for project design, known issues, and change log.
|
||||
- See the [Trello Board](https://trello.com/b/uxAoeLUl/gogs-go-git-service) to follow the develop team.
|
||||
- Want to try it before doing anything else? Do it [online](https://try.gogs.io/unknwon/gogs) or go down to the **Installation -> Install from binary** section!
|
||||
- Having trouble? Get help with [Troubleshooting](http://gogs.io/docs/intro/troubleshooting.md).
|
||||
- Want to help with localization? Check out the [guide](http://gogs.io/docs/features/i18n.html)!
|
||||
|
||||
## Features
|
||||
|
||||
@@ -46,22 +46,22 @@ The goal of this project is to make the easiest, fastest and most painless way t
|
||||
- Repository Git hooks
|
||||
- Add/remove repository collaborators
|
||||
- Gravatar and cache support
|
||||
- Mail service(register, issue)
|
||||
- Mail service (register, issue)
|
||||
- Administration panel
|
||||
- Slack webhook integration
|
||||
- Drone CI integration
|
||||
- Supports MySQL, PostgreSQL and SQLite3
|
||||
- Social account login(GitHub, Google, QQ, Weibo)
|
||||
- Multi-language support([10 languages](https://crowdin.com/project/gogs))
|
||||
- Social account login (GitHub, Google, QQ, Weibo)
|
||||
- Multi-language support ([11 languages](https://crowdin.com/project/gogs))
|
||||
|
||||
## System Requirements
|
||||
|
||||
- A cheap Raspberry Pi is powerful enough to match the minimal requirement.
|
||||
- 4 CPU Cores and 1GB RAM would be the baseline for teamwork.
|
||||
- A cheap Raspberry Pi is powerful enough for basic functionality.
|
||||
- At least 2 CPU cores and 1GB RAM would be the baseline for teamwork.
|
||||
|
||||
## Installation
|
||||
|
||||
Make sure you install [Prerequirements](http://gogs.io/docs/installation/) first.
|
||||
Make sure you install the [prerequisites](http://gogs.io/docs/installation/) first.
|
||||
|
||||
There are 5 ways to install Gogs:
|
||||
|
||||
|
||||
12
README_ZH.md
12
README_ZH.md
@@ -5,7 +5,7 @@ Gogs(Go Git Service) 是一个基于 Go 语言的自助 Git 服务。
|
||||
|
||||

|
||||
|
||||
##### 当前版本:0.5.13 Beta
|
||||
##### 当前版本:0.6.0 Beta
|
||||
|
||||
## 开发目的
|
||||
|
||||
@@ -13,11 +13,11 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
|
||||
|
||||
## 项目概览
|
||||
|
||||
- 有关项目设计、已知问题和变更日志,请通过 [使用手册](http://gogs.io/docs/intro/) 查看。
|
||||
- 有关项目设计、已知问题和变更日志,请通过 [使用手册](http://gogs.io/docs/intro/) 查看。
|
||||
- 您可以到 [Trello Board](https://trello.com/b/uxAoeLUl/gogs-go-git-service) 跟随开发团队的脚步。
|
||||
- 想要先睹为快?通过 [在线体验](https://try.gogs.io/unknwon/gogs) 或查看 **安装部署 -> 二进制安装** 小节。
|
||||
- 使用过程中遇到问题?尝试从 [故障排查](http://gogs.io/docs/intro/troubleshooting.md) 页面获取帮助。
|
||||
- 希望帮助多国语言界面的翻译吗?请立即访问 [Crowdin](https://crowdin.com/project/gogs)!
|
||||
- 希望帮助多国语言界面的翻译吗?请立即访问 [详情页面](http://gogs.io/docs/features/i18n.html)!
|
||||
|
||||
## 功能特性
|
||||
|
||||
@@ -39,12 +39,12 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
|
||||
- Drone CI 持续部署集成
|
||||
- 支持 MySQL、PostgreSQL 以及 SQLite3 数据库
|
||||
- 社交帐号登录(GitHub、Google、QQ、微博)
|
||||
- 多语言支持([10 种语言]([more](https://crowdin.com/project/gogs)))
|
||||
- 多语言支持([11 种语言]([more](https://crowdin.com/project/gogs)))
|
||||
|
||||
## 系统要求
|
||||
|
||||
- 最低的系统硬件要求为一个廉价的树莓派
|
||||
- 如果用于团队项目,建议使用 4 核 CPU 及 1GB 内存
|
||||
- 如果用于团队项目,建议使用 2 核 CPU 及 1GB 内存
|
||||
|
||||
## 安装部署
|
||||
|
||||
@@ -75,4 +75,4 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
|
||||
|
||||
## 授权许可
|
||||
|
||||
本项目采用 MIT 开源授权许可证,完整的授权说明已放置在 [LICENSE](https://github.com/gogits/gogs/blob/master/LICENSE) 文件中。
|
||||
本项目采用 MIT 开源授权许可证,完整的授权说明已放置在 [LICENSE](https://github.com/gogits/gogs/blob/master/LICENSE) 文件中。
|
||||
|
||||
145
cmd/serve.go
145
cmd/serve.go
@@ -8,7 +8,6 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -22,6 +21,10 @@ import (
|
||||
"github.com/gogits/gogs/modules/uuid"
|
||||
)
|
||||
|
||||
const (
|
||||
_ACCESS_DENIED_MESSAGE = "Repository does not exist or you do not have access"
|
||||
)
|
||||
|
||||
var CmdServ = cli.Command{
|
||||
Name: "serv",
|
||||
Usage: "This command should only be called by SSH shell",
|
||||
@@ -43,7 +46,7 @@ func setup(logPath string) {
|
||||
|
||||
models.LoadModelsConfig()
|
||||
|
||||
if models.UseSQLite3 {
|
||||
if setting.UseSQLite3 {
|
||||
workDir, _ := setting.WorkDir()
|
||||
os.Chdir(workDir)
|
||||
}
|
||||
@@ -56,67 +59,53 @@ func parseCmd(cmd string) (string, string) {
|
||||
if len(ss) != 2 {
|
||||
return "", ""
|
||||
}
|
||||
|
||||
verb, args := ss[0], ss[1]
|
||||
if verb == "git" {
|
||||
ss = strings.SplitN(args, " ", 2)
|
||||
args = ss[1]
|
||||
verb = fmt.Sprintf("%s %s", verb, ss[0])
|
||||
}
|
||||
return verb, strings.Replace(args, "'/", "'", 1)
|
||||
return ss[0], strings.Replace(ss[1], "'/", "'", 1)
|
||||
}
|
||||
|
||||
var (
|
||||
COMMANDS_READONLY = map[string]models.AccessType{
|
||||
"git-upload-pack": models.WRITABLE,
|
||||
"git upload-pack": models.WRITABLE,
|
||||
"git-upload-archive": models.WRITABLE,
|
||||
}
|
||||
|
||||
COMMANDS_WRITE = map[string]models.AccessType{
|
||||
"git-receive-pack": models.READABLE,
|
||||
"git receive-pack": models.READABLE,
|
||||
COMMANDS = map[string]models.AccessMode{
|
||||
"git-upload-pack": models.ACCESS_MODE_READ,
|
||||
"git-upload-archive": models.ACCESS_MODE_READ,
|
||||
"git-receive-pack": models.ACCESS_MODE_WRITE,
|
||||
}
|
||||
)
|
||||
|
||||
func In(b string, sl map[string]models.AccessType) bool {
|
||||
_, e := sl[b]
|
||||
return e
|
||||
}
|
||||
|
||||
func runServ(k *cli.Context) {
|
||||
if k.IsSet("config") {
|
||||
setting.CustomConf = k.String("config")
|
||||
func runServ(c *cli.Context) {
|
||||
if c.IsSet("config") {
|
||||
setting.CustomConf = c.String("config")
|
||||
}
|
||||
setup("serv.log")
|
||||
|
||||
if len(k.Args()) < 1 {
|
||||
log.GitLogger.Fatal(2, "Not enough arguments")
|
||||
fail := func(userMessage, logMessage string, args ...interface{}) {
|
||||
fmt.Fprintln(os.Stderr, "Gogs: ", userMessage)
|
||||
log.GitLogger.Fatal(2, logMessage, args...)
|
||||
}
|
||||
keys := strings.Split(k.Args()[0], "-")
|
||||
|
||||
if len(c.Args()) < 1 {
|
||||
fail("Not enough arguments", "Not enough arugments")
|
||||
}
|
||||
|
||||
keys := strings.Split(c.Args()[0], "-")
|
||||
if len(keys) != 2 {
|
||||
println("Gogs: auth file format error")
|
||||
log.GitLogger.Fatal(2, "Invalid auth file format: %s", os.Args[2])
|
||||
fail("key-id format error", "Invalid key id: %s", c.Args()[0])
|
||||
}
|
||||
|
||||
keyId, err := com.StrTo(keys[1]).Int64()
|
||||
if err != nil {
|
||||
println("Gogs: auth file format error")
|
||||
log.GitLogger.Fatal(2, "Invalid auth file format: %v", err)
|
||||
fail("key-id format error", "Invalid key id: %s", err)
|
||||
}
|
||||
|
||||
user, err := models.GetUserByKeyId(keyId)
|
||||
if err != nil {
|
||||
if err == models.ErrUserNotKeyOwner {
|
||||
println("Gogs: you are not the owner of SSH key")
|
||||
log.GitLogger.Fatal(2, "Invalid owner of SSH key: %d", keyId)
|
||||
}
|
||||
println("Gogs: internal error:", err.Error())
|
||||
log.GitLogger.Fatal(2, "Fail to get user by key ID(%d): %v", keyId, err)
|
||||
fail("internal error", "Fail to get user by key ID(%d): %v", keyId, err)
|
||||
}
|
||||
|
||||
cmd := os.Getenv("SSH_ORIGINAL_COMMAND")
|
||||
if cmd == "" {
|
||||
println("Hi", user.Name, "! You've successfully authenticated, but Gogs does not provide shell access.")
|
||||
if user.IsAdmin {
|
||||
println("If this is unexpected, please log in with password and setup Gogs under another user.")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -124,62 +113,47 @@ func runServ(k *cli.Context) {
|
||||
repoPath := strings.Trim(args, "'")
|
||||
rr := strings.SplitN(repoPath, "/", 2)
|
||||
if len(rr) != 2 {
|
||||
println("Gogs: unavailable repository", args)
|
||||
log.GitLogger.Fatal(2, "Unavailable repository: %v", args)
|
||||
fail("Invalid repository path", "Invalide repository path: %v", args)
|
||||
}
|
||||
repoUserName := rr[0]
|
||||
repoName := strings.TrimSuffix(rr[1], ".git")
|
||||
|
||||
isWrite := In(verb, COMMANDS_WRITE)
|
||||
isRead := In(verb, COMMANDS_READONLY)
|
||||
|
||||
repoUser, err := models.GetUserByName(repoUserName)
|
||||
if err != nil {
|
||||
if err == models.ErrUserNotExist {
|
||||
println("Gogs: given repository owner are not registered")
|
||||
log.GitLogger.Fatal(2, "Unregistered owner: %s", repoUserName)
|
||||
fail("Repository owner does not exist", "Unregistered owner: %s", repoUserName)
|
||||
}
|
||||
println("Gogs: internal error:", err.Error())
|
||||
log.GitLogger.Fatal(2, "Fail to get repository owner(%s): %v", repoUserName, err)
|
||||
fail("Internal error", "Fail to get repository owner(%s): %v", repoUserName, err)
|
||||
}
|
||||
|
||||
// Access check.
|
||||
switch {
|
||||
case isWrite:
|
||||
has, err := models.HasAccess(user.Name, path.Join(repoUserName, repoName), models.WRITABLE)
|
||||
if err != nil {
|
||||
println("Gogs: internal error:", err.Error())
|
||||
log.GitLogger.Fatal(2, "Fail to check write access:", err)
|
||||
} else if !has {
|
||||
println("You have no right to write this repository")
|
||||
log.GitLogger.Fatal(2, "User %s has no right to write repository %s", user.Name, repoPath)
|
||||
}
|
||||
case isRead:
|
||||
repo, err := models.GetRepositoryByName(repoUser.Id, repoName)
|
||||
if err != nil {
|
||||
if err == models.ErrRepoNotExist {
|
||||
println("Gogs: given repository does not exist")
|
||||
log.GitLogger.Fatal(2, "Repository does not exist: %s/%s", repoUser.Name, repoName)
|
||||
repo, err := models.GetRepositoryByName(repoUser.Id, repoName)
|
||||
if err != nil {
|
||||
if models.IsErrRepoNotExist(err) {
|
||||
if user.Id == repoUser.Id || repoUser.IsOwnedBy(user.Id) {
|
||||
fail("Repository does not exist", "Repository does not exist: %s/%s", repoUser.Name, repoName)
|
||||
} else {
|
||||
fail(_ACCESS_DENIED_MESSAGE, "Repository does not exist: %s/%s", repoUser.Name, repoName)
|
||||
}
|
||||
println("Gogs: internal error:", err.Error())
|
||||
log.GitLogger.Fatal(2, "Fail to get repository: %v", err)
|
||||
}
|
||||
fail("Internal error", "Fail to get repository: %v", err)
|
||||
}
|
||||
|
||||
if !repo.IsPrivate {
|
||||
break
|
||||
}
|
||||
requestedMode, has := COMMANDS[verb]
|
||||
if !has {
|
||||
fail("Unknown git command", "Unknown git command %s", verb)
|
||||
}
|
||||
|
||||
has, err := models.HasAccess(user.Name, path.Join(repoUserName, repoName), models.READABLE)
|
||||
if err != nil {
|
||||
println("Gogs: internal error:", err.Error())
|
||||
log.GitLogger.Fatal(2, "Fail to check read access:", err)
|
||||
} else if !has {
|
||||
println("You have no right to access this repository")
|
||||
log.GitLogger.Fatal(2, "User %s has no right to read repository %s", user.Name, repoPath)
|
||||
mode, err := models.AccessLevel(user, repo)
|
||||
if err != nil {
|
||||
fail("Internal error", "Fail to check access: %v", err)
|
||||
} else if mode < requestedMode {
|
||||
clientMessage := _ACCESS_DENIED_MESSAGE
|
||||
if mode >= models.ACCESS_MODE_READ {
|
||||
clientMessage = "You do not have sufficient authorization for this action"
|
||||
}
|
||||
default:
|
||||
println("Unknown command: " + cmd)
|
||||
return
|
||||
fail(clientMessage,
|
||||
"User %s does not have level %v access to repository %s",
|
||||
user.Name, requestedMode, repoPath)
|
||||
}
|
||||
|
||||
uuid := uuid.NewV4().String()
|
||||
@@ -197,11 +171,10 @@ func runServ(k *cli.Context) {
|
||||
gitcmd.Stdin = os.Stdin
|
||||
gitcmd.Stderr = os.Stderr
|
||||
if err = gitcmd.Run(); err != nil {
|
||||
println("Gogs: internal error:", err.Error())
|
||||
log.GitLogger.Fatal(2, "Fail to execute git command: %v", err)
|
||||
fail("Internal error", "Fail to execute git command: %v", err)
|
||||
}
|
||||
|
||||
if isWrite {
|
||||
if requestedMode == models.ACCESS_MODE_WRITE {
|
||||
tasks, err := models.GetUpdateTasksByUuid(uuid)
|
||||
if err != nil {
|
||||
log.GitLogger.Fatal(2, "GetUpdateTasksByUuid: %v", err)
|
||||
@@ -223,10 +196,10 @@ func runServ(k *cli.Context) {
|
||||
// Update key activity.
|
||||
key, err := models.GetPublicKeyById(keyId)
|
||||
if err != nil {
|
||||
log.GitLogger.Fatal(2, "GetPublicKeyById: %v", err)
|
||||
fail("Internal error", "GetPublicKeyById: %v", err)
|
||||
}
|
||||
key.Updated = time.Now()
|
||||
if err = models.UpdatePublicKey(key); err != nil {
|
||||
log.GitLogger.Fatal(2, "UpdatePublicKey: %v", err)
|
||||
fail("Internal error", "UpdatePublicKey: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
29
cmd/web.go
29
cmd/web.go
@@ -34,6 +34,7 @@ import (
|
||||
"github.com/gogits/gogs/modules/auth/apiv1"
|
||||
"github.com/gogits/gogs/modules/avatar"
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/bindata"
|
||||
"github.com/gogits/gogs/modules/git"
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/middleware"
|
||||
@@ -78,11 +79,11 @@ func checkVersion() {
|
||||
|
||||
// Check dependency version.
|
||||
checkers := []VerChecker{
|
||||
{"github.com/Unknwon/macaron", macaron.Version, "0.5.1"},
|
||||
{"github.com/macaron-contrib/binding", binding.Version, "0.0.4"},
|
||||
{"github.com/Unknwon/macaron", macaron.Version, "0.5.4"},
|
||||
{"github.com/macaron-contrib/binding", binding.Version, "0.0.6"},
|
||||
{"github.com/macaron-contrib/cache", cache.Version, "0.0.7"},
|
||||
{"github.com/macaron-contrib/csrf", csrf.Version, "0.0.3"},
|
||||
{"github.com/macaron-contrib/i18n", i18n.Version, "0.0.5"},
|
||||
{"github.com/macaron-contrib/i18n", i18n.Version, "0.0.7"},
|
||||
{"github.com/macaron-contrib/session", session.Version, "0.1.6"},
|
||||
{"gopkg.in/ini.v1", ini.Version, "1.2.0"},
|
||||
}
|
||||
@@ -123,9 +124,18 @@ func newMacaron() *macaron.Macaron {
|
||||
Funcs: []template.FuncMap{base.TemplateFuncs},
|
||||
IndentJSON: macaron.Env != macaron.PROD,
|
||||
}))
|
||||
|
||||
localeNames, err := bindata.AssetDir("conf/locale")
|
||||
if err != nil {
|
||||
log.Fatal(4, "Fail to list locale files: %v", err)
|
||||
}
|
||||
localFiles := make(map[string][]byte)
|
||||
for _, name := range localeNames {
|
||||
localFiles[name] = bindata.MustAsset("conf/locale/" + name)
|
||||
}
|
||||
m.Use(i18n.I18n(i18n.Options{
|
||||
SubURL: setting.AppSubUrl,
|
||||
Directory: path.Join(setting.ConfRootPath, "locale"),
|
||||
Files: localFiles,
|
||||
CustomDirectory: path.Join(setting.CustomPath, "conf/locale"),
|
||||
Langs: setting.Langs,
|
||||
Names: setting.Names,
|
||||
@@ -166,12 +176,11 @@ func newMacaron() *macaron.Macaron {
|
||||
}
|
||||
|
||||
func runWeb(ctx *cli.Context) {
|
||||
checkVersion()
|
||||
|
||||
if ctx.IsSet("config") {
|
||||
setting.CustomConf = ctx.String("config")
|
||||
}
|
||||
routers.GlobalInit()
|
||||
checkVersion()
|
||||
|
||||
m := newMacaron()
|
||||
|
||||
@@ -230,7 +239,7 @@ func runWeb(ctx *cli.Context) {
|
||||
})
|
||||
|
||||
m.Any("/*", func(ctx *middleware.Context) {
|
||||
ctx.JSON(404, &base.ApiJsonErr{"Not Found", base.DOC_URL})
|
||||
ctx.HandleAPI(404, "Page not found")
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -319,7 +328,7 @@ func runWeb(ctx *cli.Context) {
|
||||
m.Get("/template/*", dev.TemplatePreview)
|
||||
}
|
||||
|
||||
reqTrueOwner := middleware.RequireTrueOwner()
|
||||
reqAdmin := middleware.RequireAdmin()
|
||||
|
||||
// Organization.
|
||||
m.Group("/org", func() {
|
||||
@@ -394,7 +403,7 @@ func runWeb(ctx *cli.Context) {
|
||||
m.Post("/:name", repo.GitHooksEditPost)
|
||||
}, middleware.GitHookService())
|
||||
})
|
||||
}, reqSignIn, middleware.RepoAssignment(true), reqTrueOwner)
|
||||
}, reqSignIn, middleware.RepoAssignment(true), reqAdmin)
|
||||
|
||||
m.Group("/:username/:reponame", func() {
|
||||
m.Get("/action/:action", repo.Action)
|
||||
@@ -458,7 +467,7 @@ func runWeb(ctx *cli.Context) {
|
||||
// robots.txt
|
||||
m.Get("/robots.txt", func(ctx *middleware.Context) {
|
||||
if setting.HasRobotsTxt {
|
||||
ctx.ServeFile(path.Join(setting.CustomPath, "robots.txt"))
|
||||
ctx.ServeFileContent(path.Join(setting.CustomPath, "robots.txt"))
|
||||
} else {
|
||||
ctx.Error(404)
|
||||
}
|
||||
|
||||
7
conf/README
Normal file
7
conf/README
Normal file
@@ -0,0 +1,7 @@
|
||||
Execute following command in ROOT directory when anything is changed:
|
||||
|
||||
$ go-bindata -o=modules/bindata/bindata.go -ignore="\\.DS_Store|README" -pkg=bindata conf/...
|
||||
|
||||
Add -debug flag to make life easier in development(somehow isn't working):
|
||||
|
||||
$ go-bindata -debug -o=modules/bindata/bindata.go -ignore="\\.DS_Store|README" -pkg=bindata conf/...
|
||||
10
conf/app.ini
10
conf/app.ini
@@ -82,7 +82,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
|
||||
ENABLE_REVERSE_PROXY_AUTO_REGISTRATION = false
|
||||
|
||||
[webhook]
|
||||
; Cron task interval in minutes
|
||||
@@ -105,6 +105,10 @@ SUBJECT = %(APP_NAME)s
|
||||
HOST =
|
||||
; Do not verify the certificate of the server. Only use this for self-signed certificates
|
||||
SKIP_VERIFY =
|
||||
; Use client certificate
|
||||
USE_CERTIFICATE = false
|
||||
CERT_FILE = custom/mailer/cert.pem
|
||||
KEY_FILE = custom/mailer/key.pem
|
||||
; Mail from address, RFC 5322. This can be just an email address, or the "Name" <email@example.com> format
|
||||
FROM =
|
||||
; Mailer user name and password
|
||||
@@ -282,5 +286,5 @@ INTERVAL = 24
|
||||
ARGS =
|
||||
|
||||
[i18n]
|
||||
LANGS = en-US,zh-CN,zh-HK,de-DE,fr-CA,nl-NL,lv-LV,ru-RU,ja-JP,es-ES
|
||||
NAMES = English,简体中文,繁體中文,Deutsch,Français,Nederlands,Latviešu,Русский,日本语,Español
|
||||
LANGS = en-US,zh-CN,zh-HK,de-DE,fr-CA,nl-NL,lv-LV,ru-RU,ja-JP,es-ES,pt-BR
|
||||
NAMES = English,简体中文,繁體中文,Deutsch,Français,Nederlands,Latviešu,Русский,日本语,Español,Português
|
||||
|
||||
Binary file not shown.
@@ -7,4 +7,5 @@ Huimin Wang <wanghm2009@hotmail.co.jp>
|
||||
Thomas Fanninger <gogs.thomas@fanninger.at>
|
||||
Łukasz Jan Niemier <lukasz@niemier.pl>
|
||||
Lafriks <lafriks@gmail.com>
|
||||
Miguel de la Cruz <miguel@mcrx.me>
|
||||
Miguel de la Cruz <miguel@mcrx.me>
|
||||
Natan Albuquerque <natanalbuquerque5@gmail.com>
|
||||
@@ -1,4 +1,4 @@
|
||||
app_desc=Ein einfacher, selbst gehosteter Git-Service, geschrieben in Go
|
||||
app_desc=Ein schmerzloser, selbst gehosteter Git-Service, geschrieben in Go
|
||||
|
||||
home=Home
|
||||
dashboard=Übersicht
|
||||
@@ -60,7 +60,7 @@ run_user_helper=Der Benutzer muss die Zugriffsberechtigung für das Repository R
|
||||
domain=Domain
|
||||
domain_helper=Dies hat Auswirkung auf die SSH clone URLs.
|
||||
http_port=HTTP Port
|
||||
http_port_helper=Port number which application will listen on.
|
||||
http_port_helper=Auf dieser Port Nummer ist die Apllikation erreichbar.
|
||||
app_url=Anwendungs-URL
|
||||
app_url_helper=Dies hat Auswirkung auf die HTTP/HTTPS clone URLs und für die E-Mails.
|
||||
email_title=E-Mail-Service Einstellungen (optional)
|
||||
@@ -281,13 +281,13 @@ init_readme=Repository mit README.md initialisieren
|
||||
create_repo=Repository erstellen
|
||||
default_branch=Standard-Branch
|
||||
mirror_interval=Spiegel-Intervall (in Stunden)
|
||||
goget_meta=Go-Get Meta
|
||||
goget_meta_helper=Dieses Repository wird man mit <span class="label label-blue label-radius">go get</span> klonen können.
|
||||
|
||||
need_auth=Authorisierung benötigt
|
||||
migrate_type=Migrationstyp
|
||||
migrate_type_helper=Dieses Repository wird ein <span class="label label-blue label-radius">Spiegel</span>
|
||||
migrate_repo=Repository migrieren
|
||||
migrate.clone_address=Adresse kopieren
|
||||
migrate.invalid_local_path=Lokaler Pfad ist ungültig, er existiert nicht oder ist kein Ordner.
|
||||
|
||||
copy_link=Kopieren
|
||||
click_to_copy=In Zwischenablage kopieren
|
||||
@@ -514,10 +514,10 @@ 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.resync_all_sshkeys=Rewrite '.ssh/autorized_key' file (caution: non-Gogs keys will be lost)
|
||||
dashboard.resync_all_sshkeys_success=All public keys have been rewritten successfully.
|
||||
dashboard.resync_all_update_hooks=Rewrite all update hook of repositories (needed when custom config path is changed)
|
||||
dashboard.resync_all_update_hooks_success=All repositories' update hook have been rewritten successfully.
|
||||
dashboard.resync_all_sshkeys=Überschreibe '.ssh/autorized_key' Datei (Warnung: Keys, die nicht zu Gogs gehören werden verloren gehen)
|
||||
dashboard.resync_all_sshkeys_success=Alle öffentlichen Keys sind erfolgreich neu geschrieben worden.
|
||||
dashboard.resync_all_update_hooks=Überschreibe alle Hooks der Repositories (benötigt, wenn sich der Pfad in der Konfiguration ändert)
|
||||
dashboard.resync_all_update_hooks_success=Die Hooks aller Repositories sind erfolgreich neu geschrieben worden.
|
||||
|
||||
dashboard.server_uptime=Server-Uptime
|
||||
dashboard.current_goroutine=Aktuelle Goroutines
|
||||
@@ -595,7 +595,10 @@ auths.domain=Domain
|
||||
auths.host=Host
|
||||
auths.port=Port
|
||||
auths.base_dn=Base DN
|
||||
auths.attributes=Suchattribute
|
||||
auths.attribute_username=Benutzername Attribut
|
||||
auths.attribute_name=Vorname Attribut
|
||||
auths.attribute_surname=Nachname Attribut
|
||||
auths.attribute_mail=E-Mail Attribut
|
||||
auths.filter=Suchfilter
|
||||
auths.ms_ad_sa=Ms Ad SA
|
||||
auths.smtp_auth=SMTP-Authentifizierungstyp
|
||||
@@ -638,7 +641,7 @@ config.db_path_helper=(nur für "sqlite3")
|
||||
config.service_config=Service-Einstellungen
|
||||
config.register_email_confirm=E-Mail-Bestätigung bei Registrierung
|
||||
config.disable_register=Registrierung deaktivieren
|
||||
config.show_registration_button=Show Register Button
|
||||
config.show_registration_button=Zeige die Schaltfläche Registrieren
|
||||
config.require_sign_in_view=Ansehen erfordert Registrierung
|
||||
config.mail_notify=E-Mail-Benachrichtigung
|
||||
config.enable_cache_avatar=Avatar-Cache aktivieren
|
||||
@@ -647,7 +650,7 @@ config.reset_password_code_lives=Passwortcode Lebensdauer
|
||||
config.webhook_config=Webhook-Einstellungen
|
||||
config.task_interval=Task-Intervall
|
||||
config.deliver_timeout=Zeitlimit für Zustellung
|
||||
config.skip_tls_verify=Skip TLS Verify
|
||||
config.skip_tls_verify=TLS verifikation überspringen
|
||||
config.mailer_config=Mailer-Einstellungen
|
||||
config.mailer_enabled=Aktiviert
|
||||
config.mailer_name=Name
|
||||
@@ -693,12 +696,12 @@ notices.op=Op.
|
||||
notices.delete_success=System-Mitteilung erfolgreich gelöscht.
|
||||
|
||||
[action]
|
||||
create_repo=hat Repository <a href="%s/%s">%s</a> erstellt
|
||||
commit_repo=hat nach <a href="%s/%s/src/%s">%s</a> in <a href="%s/%s">%s</a> gepusht
|
||||
create_issue=`hat Issue <a href="%s/issues/%s">%[1]s#%[2]s</a> eröffnet`
|
||||
comment_issue=`hat Issue <a href="%s/issues/%s">%[1]s#%[2]s</a> kommentiert`
|
||||
transfer_repo=hat Repository <code>%s</code> transferiert an <a href="/%s%s">%s</a>
|
||||
push_tag=hat nach <a href="%s/%s/src/%s">%s</a> in <a href="%s/%s">%s</a> gepusht
|
||||
create_repo=hat Repository <a href="%s">%s</a> erstellt
|
||||
commit_repo=hat nach <a href="%s/src/%s">%[2]s</a> in <a href="%[1]s">%[3]s</a> gepusht
|
||||
create_issue=`hat Issue <a href="%s/issues/%s">%s#%[2]s</a> eröffnet`
|
||||
comment_issue=`hat Issue <a href="%s/issues/%s">%s#%[2]s</a> kommentiert`
|
||||
transfer_repo=hat Repository <code>%s</code> transferiert an <a href="%s">%s</a>
|
||||
push_tag=hat nach <a href="%s/src/%s">%[2]s</a> in <a href="%[1]s">%[3]s</a> gepusht
|
||||
compare_2_commits=Zeige Vergleich dieser 2 Commits
|
||||
|
||||
[tool]
|
||||
|
||||
@@ -107,13 +107,13 @@ remember_me = Remember Me
|
||||
forgot_password= Forgot Password
|
||||
forget_password = Forgot password?
|
||||
sign_up_now = Need an account? Sign up now.
|
||||
confirmation_mail_sent_prompt = A new confirmation e-mail has been sent to <b>%s</b>, please check your inbox within the next %d hours to complete your registration.
|
||||
confirmation_mail_sent_prompt = A new confirmation e-mail has been sent to <b>%s</b>, please check your inbox within the next %d hours to complete the registration process.
|
||||
sign_in_email = Sign in to your e-mail
|
||||
active_your_account = Activate Your Account
|
||||
resent_limit_prompt = Sorry, you are sending an activation e-mail too frequently. Please wait 3 minutes.
|
||||
resent_limit_prompt = Sorry, you already requested an activation email recently. Please wait 3 minutes then try again.
|
||||
has_unconfirmed_mail = Hi %s, you have an unconfirmed e-mail address (<b>%s</b>). If you haven't received a confirmation e-mail or need to resend a new one, please click on the button below.
|
||||
resend_mail = Click here to resend your activation e-mail
|
||||
email_not_associate = This e-mail address does not associate to any account.
|
||||
email_not_associate = This e-mail address is not associated with any account.
|
||||
send_reset_mail = Click here to (re)send your password reset e-mail
|
||||
reset_password = Reset Your Password
|
||||
invalid_code = Sorry, your confirmation code has expired or not valid.
|
||||
@@ -149,29 +149,29 @@ repo_name_been_taken = Repository name has been already taken.
|
||||
org_name_been_taken = Organization name has been already taken.
|
||||
team_name_been_taken = Team name has been already taken.
|
||||
email_been_used = E-mail address has been already used.
|
||||
ssh_key_been_used = Public key name has been used.
|
||||
ssh_key_been_used = Public key name or content has been used.
|
||||
illegal_username = Your username contains illegal characters.
|
||||
illegal_repo_name = Repository name contains illegal characters.
|
||||
illegal_org_name = Organization name contains illegal characters.
|
||||
illegal_team_name = Team name contains illegal characters.
|
||||
username_password_incorrect = Username or password is not correct.
|
||||
enterred_invalid_repo_name = Please make sure you entered repository name is correct.
|
||||
enterred_invalid_owner_name = Please make sure you entered owner name is correct.
|
||||
enterred_invalid_password = Please make sure you entered password is correct.
|
||||
enterred_invalid_repo_name = Please make sure that the repository name you entered is correct.
|
||||
enterred_invalid_owner_name = Please make sure that the owner name you entered is correct.
|
||||
enterred_invalid_password = Please make sure the that password you entered is correct.
|
||||
user_not_exist = Given user does not exist.
|
||||
last_org_owner = The user to remove is the last member in owner team. There must be another owner.
|
||||
last_org_owner = Removing the last user from a owner team isn't allowed, as there must always be at least one owner in any given organization.
|
||||
|
||||
invalid_ssh_key = Sorry, we're not able to verify your SSH key: %s
|
||||
unable_verify_ssh_key = Gogs cannot verify your SSH key, but we assume that is valid, please make sure yourself.
|
||||
unable_verify_ssh_key = Gogs cannot verify your SSH key, but we assume that it is valid, please double-check it.
|
||||
auth_failed = Authentication failed: %v
|
||||
|
||||
still_own_repo = Your account still have ownership of repository, you have to delete or transfer them first.
|
||||
still_has_org = Your account still have membership of organization, you have to left or delete them first.
|
||||
still_own_repo = Your account still has ownership over at least one repository, you have to delete or transfer them first.
|
||||
still_has_org = Your account still has membership in at least one organization, you have to leave or delete your memberships first.
|
||||
org_still_own_repo = This organization still have ownership of repository, you have to delete or transfer them first.
|
||||
|
||||
still_own_user = This authentication still has used by some users, you should move them and then delete again.
|
||||
still_own_user = This authentication still is in use by at least one user, please remove them from the authentication and try again.
|
||||
|
||||
target_branch_not_exist = Target branch does not exist
|
||||
target_branch_not_exist = Target branch does not exist.
|
||||
|
||||
[user]
|
||||
change_avatar = Change your avatar at gravatar.com
|
||||
@@ -201,7 +201,7 @@ location = Location
|
||||
update_profile = Update Profile
|
||||
update_profile_success = Your profile has been updated successfully.
|
||||
change_username = Username Changed
|
||||
change_username_desc = Username has been changed, do you want to continue? This will affect all links relate to your account.
|
||||
change_username_desc = You changed your username. This will affect the way how links relate to your account. Do you want to continue?
|
||||
continue = Continue
|
||||
cancel = Cancel
|
||||
|
||||
@@ -217,7 +217,7 @@ change_password = Change Password
|
||||
old_password = Current Password
|
||||
new_password = New Password
|
||||
password_incorrect = Current password is not correct.
|
||||
change_password_success = Password is changed successfully. You can now sign in via new password.
|
||||
change_password_success = Your password was successfully changed. You can now sign using this new password.
|
||||
|
||||
emails = E-mail Addresses
|
||||
manage_emails = Manage e-mail addresses
|
||||
@@ -227,12 +227,13 @@ primary_email = Set as primary
|
||||
delete_email = Delete
|
||||
add_new_email = Add new e-mail address
|
||||
add_email = Add e-mail
|
||||
add_email_confirmation_sent = A new confirmation e-mail has been sent to <b>%s</b>, please check your inbox within the next %d hours to complete the confirmation process.
|
||||
add_email_success = Your new E-mail address was successfully added.
|
||||
|
||||
manage_ssh_keys = Manage SSH Keys
|
||||
add_key = Add Key
|
||||
ssh_desc = This is a list of SSH keys associated with your account. Remove any keys that you do not recognize.
|
||||
ssh_helper = <strong>Need help?</strong> Check out our guide to <a href="%s">generating SSH keys</a> or troubleshoot <a href="%s">common SSH Problems</a>.
|
||||
ssh_desc = This is a list of SSH keys associated with your account. As these keys allow anyone using them to gain access to your repositories, it is highly important that you make sure you recognize them.
|
||||
ssh_helper = <strong>Don't know how?</strong> Check out GitHub's guide to <a href="%s">create your own SSH keys</a> or solve <a href="%s">common problems</a> you might encounter using SSH.
|
||||
add_new_key = Add SSH Key
|
||||
key_name = Key Name
|
||||
key_content = Content
|
||||
@@ -250,12 +251,12 @@ unbind_success = Social account has been unbound.
|
||||
manage_access_token = Manage Personal Access Tokens
|
||||
generate_new_token = Generate New Token
|
||||
tokens_desc = Tokens you have generated that can be used to access the Gogs API.
|
||||
new_token_desc = As for now, every token will have full access to your account.
|
||||
new_token_desc = Each token will have full access to your account.
|
||||
token_name = Token Name
|
||||
generate_token = Generate Token
|
||||
generate_token_succees = New access token has been generated successfully! Make sure to copy your new personal access token now. You won't be able to see it again!
|
||||
generate_token_succees = Your access token was successfully generated! Make sure to copy it right now, as you won't be able to see it again later!
|
||||
delete_token = Delete
|
||||
delete_token_success = Personal access token has been deleted successfully! Don't forget to update your applications as well.
|
||||
delete_token_success = This personal access token has been successfully removed successfully! Don't forget to update your applications as well.
|
||||
|
||||
delete_account = Delete Your Account
|
||||
delete_prompt = The operation will delete your account permanently, and <strong>CANNOT</strong> be undone!
|
||||
@@ -266,12 +267,12 @@ delete_account_desc = This account is going to be deleted permanently, do you wa
|
||||
[repo]
|
||||
owner = Owner
|
||||
repo_name = Repository Name
|
||||
repo_name_helper = Great repository names are short, memorable and <strong>unique</strong>.
|
||||
repo_name_helper = A good repository name is usually composed of short, memorable and unique keywords.
|
||||
visibility = Visibility
|
||||
visiblity_helper = This repository is <span class="label label-red label-radius">Private</span>
|
||||
fork_repo = Fork Repository
|
||||
fork_from = Fork From
|
||||
fork_visiblity_helper = Forked repository cannot change its visiblity
|
||||
fork_visiblity_helper = You cannot alter the visibility of a forked repository.
|
||||
repo_desc = Description
|
||||
repo_lang = Language
|
||||
repo_lang_helper = Select a .gitignore file
|
||||
@@ -281,13 +282,13 @@ init_readme = Initialize this repository with a README.md
|
||||
create_repo = Create Repository
|
||||
default_branch = Default Branch
|
||||
mirror_interval = Mirror Interval (hour)
|
||||
goget_meta = Go-Get Meta
|
||||
goget_meta_helper = This repository will be <span class="label label-blue label-radius">Go-Getable</span>
|
||||
|
||||
need_auth = Need Authorization
|
||||
migrate_type = Migration Type
|
||||
migrate_type_helper = This repository will be a <span class="label label-blue label-radius">Mirror</span>
|
||||
migrate_type_helper = This repository will be a <span class="label label-blue label-radius">mirror</span>
|
||||
migrate_repo = Migrate Repository
|
||||
migrate.clone_address = Clone Address
|
||||
migrate.invalid_local_path = Invalid local path, it does not exist or not a directory.
|
||||
|
||||
copy_link = Copy
|
||||
click_to_copy = Copy to clipboard
|
||||
@@ -337,13 +338,13 @@ settings.danger_zone = Danger Zone
|
||||
settings.site = Official Site
|
||||
settings.update_settings = Update Settings
|
||||
settings.change_reponame = Repository Name Changed
|
||||
settings.change_reponame_desc = Repository name has been changed, do you want to continue? This will affect all links relate to this repository.
|
||||
settings.change_reponame_desc = Repository name was changed. This will affect how links relate to the repository. Do you want to continue?
|
||||
settings.transfer = Transfer Ownership
|
||||
settings.transfer_desc = Transfer this repo to another user or to an organization where you have admin rights.
|
||||
settings.new_owner_has_same_repo = New owner already has a repository with same name.
|
||||
settings.transfer_desc = Transfer this repository to another user or to an organization in which you have admin rights.
|
||||
settings.new_owner_has_same_repo = The new owner already has a repository with same name. Please choose another name.
|
||||
settings.delete = Delete This Repository
|
||||
settings.delete_desc = Once you delete a repository, there is no going back. Please be certain.
|
||||
settings.transfer_notices = <p>- You will lose access if new owner is a individual user.</p><p>- You will remain access if new owner is an organization and you're one of the owners.</p>
|
||||
settings.transfer_notices = <p>- You will lose access if new owner is a individual user.</p><p>- You will conserve access if new owner is an organization and if you're one of the owners.</p>
|
||||
settings.update_settings_success = Repository options has been updated successfully.
|
||||
settings.transfer_owner = New Owner
|
||||
settings.make_transfer = Make Transfer
|
||||
@@ -354,21 +355,21 @@ settings.add_collaborator_success = New collaborator has been added.
|
||||
settings.remove_collaborator_success = Collaborator has been removed.
|
||||
settings.user_is_org_member = User is organization member who cannot be added as a collaborator.
|
||||
settings.add_webhook = Add Webhook
|
||||
settings.hooks_desc = Webhooks allow external services to be notified when certain events happen on Gogs. When the specified events happen, we'll send a POST request to each of the URLs you provide. Learn more in our <a target="_blank" href="%s">Webhooks Guide</a>.
|
||||
settings.githooks_desc = Git Hooks are powered by Git itself, you can edit files of supported hooks in the list below to apply custom operations.
|
||||
settings.githook_edit_desc = If hook is not active, sample content will be presented. Leave content to be blank will disable this hook.
|
||||
settings.hooks_desc = Webhooks are much like basic HTTP POST event triggers. Whenever something occurs in Gogs, we will handle the notification to the target host you specify. Learn more in this <a target="_blank" href="%s">Webhooks Guide</a>.
|
||||
settings.githooks_desc = Git Hooks are powered by Git itself, you can edit files of supported hooks in the list below to perform custom operations.
|
||||
settings.githook_edit_desc = If the hook is inactive, sample content will be presented. Leaving content to an empty value will disable this hook.
|
||||
settings.githook_name = Hook Name
|
||||
settings.githook_content = Hook Content
|
||||
settings.update_githook = Update Hook
|
||||
settings.remove_hook_success = Webhook has been removed.
|
||||
settings.add_webhook_desc = We’ll send a <code>POST</code> request to the URL below with details of any subscribed events. You can also specify which data format you'd like to receive (JSON, <code>x-www-form-urlencoded</code>, <em>etc</em>). More information can be found in <a target="_blank" href="%s">Webhooks Guide</a>.
|
||||
settings.add_webhook_desc = Gogs will send a <code>POST</code> request to the URL you specify, along with regarding the event that occured. You can also specify what kind of data format you'd like to get upon triggering the hook (JSON, x-www-form-urlencoded, XML, etc). More information can be found in our <a target="_blank" href="%s">Webhooks Guide</a>.
|
||||
settings.payload_url = Payload URL
|
||||
settings.content_type = Content Type
|
||||
settings.secret = Secret
|
||||
settings.event_desc = Which events would you like to trigger this webhook?
|
||||
settings.event_desc = Upon which events should this webhook be triggered?
|
||||
settings.event_push_only = Just the <code>push</code> event.
|
||||
settings.active = Active
|
||||
settings.active_helper = We will deliver event details when this hook is triggered.
|
||||
settings.active_helper = Details regarding the event which triggered the hook will be delivered as well.
|
||||
settings.add_hook_success = New webhook has been added.
|
||||
settings.update_webhook = Update Webhook
|
||||
settings.update_hook_success = Webhook has been updated.
|
||||
@@ -407,7 +408,7 @@ release.preview = Preview
|
||||
release.content_placeholder = Write some content
|
||||
release.loading = Loading...
|
||||
release.prerelease_desc = This is a pre-release
|
||||
release.prerelease_helper = We’ll point out that this release is identified as non-production ready.
|
||||
release.prerelease_helper = We’ll point out that this release is not production-ready.
|
||||
release.publish = Publish Release
|
||||
release.save_draft = Save Draft
|
||||
release.edit_release = Edit Release
|
||||
@@ -439,11 +440,11 @@ settings.website = Website
|
||||
settings.location = Location
|
||||
settings.update_settings = Update Settings
|
||||
settings.change_orgname = Organization Name Changed
|
||||
settings.change_orgname_desc = Organization name has been changed, do you want to continue? This will affect all links relate to this organization.
|
||||
settings.update_setting_success = Organization setting has been updated successfully.
|
||||
settings.delete = Delete Organization
|
||||
settings.change_orgname_desc = Organization name has been changed. This will affect how links relate to the organization. Do you want to continue?
|
||||
settings.update_setting_success = Organization settings were successfully updated.
|
||||
settings.delete = Delete Organization
|
||||
settings.delete_account = Delete This Organization
|
||||
settings.delete_prompt = The operation will delete this organization permanently, and <strong>CANNOT</strong> be undone!
|
||||
settings.delete_prompt = The organization will be permanently removed, and this <strong>CANNOT</strong> be undone!
|
||||
settings.confirm_delete_account = Confirm Deletion
|
||||
settings.delete_org_title = Organization Deletion
|
||||
settings.delete_org_desc = This organization is going to be deleted permanently, do you want to continue?
|
||||
@@ -477,7 +478,7 @@ teams.update_settings = Update Settings
|
||||
teams.delete_team = Delete This Team
|
||||
teams.add_team_member = Add Team Member
|
||||
teams.delete_team_title = Team Deletion
|
||||
teams.delete_team_desc = This team is going to be deleted, do you want to continue? Members of this team may lose access to some repositories.
|
||||
teams.delete_team_desc = As this team will be deleted, members of this team may lose access to some repositories. Do you want to continue?
|
||||
teams.delete_team_success = Given team has been deleted successfully.
|
||||
teams.read_permission_desc = This team grants <strong>Read</strong> access: members can view and clone the team's repositories.
|
||||
teams.write_permission_desc = This team grants <strong>Write</strong> access: members can read from and push to the team's repositories.
|
||||
@@ -567,8 +568,8 @@ users.is_admin = This account has administrator permissions
|
||||
users.allow_git_hook = This account has permissions to create Git hooks
|
||||
users.update_profile = Update Account Profile
|
||||
users.delete_account = Delete This Account
|
||||
users.still_own_repo = This account still have ownership of repository, you have to delete or transfer them first.
|
||||
users.still_has_org = This account still have membership of organization, you have to left or delete them first.
|
||||
users.still_own_repo = This account still has ownership over at least one repository, you have to delete or transfer them first.
|
||||
users.still_has_org = This account still has membership in at least one organization, you have to leave or delete the organizations first.
|
||||
|
||||
orgs.org_manage_panel = Organization Manage Panel
|
||||
orgs.name = Name
|
||||
@@ -595,7 +596,10 @@ auths.domain = Domain
|
||||
auths.host = Host
|
||||
auths.port = Port
|
||||
auths.base_dn = Base DN
|
||||
auths.attributes = Search Attributes
|
||||
auths.attribute_username = Username attribute
|
||||
auths.attribute_name = First name attribute
|
||||
auths.attribute_surname = Surname attribute
|
||||
auths.attribute_mail = E-mail attribute
|
||||
auths.filter = Search Filter
|
||||
auths.ms_ad_sa = Ms Ad SA
|
||||
auths.smtp_auth = SMTP Authorization Type
|
||||
@@ -693,12 +697,12 @@ notices.op = Op.
|
||||
notices.delete_success = System notice has been deleted successfully.
|
||||
|
||||
[action]
|
||||
create_repo = created repository <a href="%s/%s">%s</a>
|
||||
commit_repo = pushed to <a href="%s/%s/src/%s">%s</a> at <a href="%s/%s">%s</a>
|
||||
create_issue = `opened issue <a href="%s/issues/%s">%[1]s#%[2]s</a>`
|
||||
comment_issue = `commented on issue <a href="%s/issues/%s">%[1]s#%[2]s</a>`
|
||||
transfer_repo = transfered repository <code>%s</code> to <a href="/%s%s">%s</a>
|
||||
push_tag = pushed tag <a href="%s/%s/src/%s">%s</a> to <a href="%s/%s">%s</a>
|
||||
create_repo = created repository <a href="%s">%s</a>
|
||||
commit_repo = pushed to <a href="%s/src/%s">%[2]s</a> at <a href="%[1]s">%[3]s</a>
|
||||
create_issue = `opened issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
comment_issue = `commented on issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
transfer_repo = transfered repository <code>%s</code> to <a href="%s">%s</a>
|
||||
push_tag = pushed tag <a href="%s/src/%s">%[2]s</a> to <a href="%[1]s">%[3]s</a>
|
||||
compare_2_commits = View comparison for these 2 commits
|
||||
|
||||
[tool]
|
||||
|
||||
@@ -281,13 +281,13 @@ init_readme=Crear este repositorio con un fichero README.md
|
||||
create_repo=Crear Repositorio
|
||||
default_branch=Rama por defecto
|
||||
mirror_interval=Intervalo de mirror(en horas)
|
||||
goget_meta=Go-Get Meta
|
||||
goget_meta_helper=Este repositorio será <span class="label label-blue label-radius">Go-Getable</span>
|
||||
|
||||
need_auth=Requiere Autorización
|
||||
migrate_type=Tipo de Migración
|
||||
migrate_type_helper=Este repositorio será un <span class="label label-blue label-radius">Mirror</span>
|
||||
migrate_repo=Migrar Repositorio
|
||||
migrate.clone_address=Clonar Dirección
|
||||
migrate.invalid_local_path=Rutal local inválida, no existe o no es un directorio.
|
||||
|
||||
copy_link=Copiar
|
||||
click_to_copy=Copiar al portapapeles
|
||||
@@ -516,8 +516,8 @@ dashboard.git_gc_repos=Ejecutar la recolección de basura en los repositorios
|
||||
dashboard.git_gc_repos_success=Todos los repositorios han ejecutado correctamente el recolector de basuras.
|
||||
dashboard.resync_all_sshkeys=Reescribir el fichero '.ssh/authorized_key'(atención: se perderán las claves que no pertenezcan a Gogs)
|
||||
dashboard.resync_all_sshkeys_success=Todas las claves públicas se han reescrito correctamente.
|
||||
dashboard.resync_all_update_hooks=Rewrite all update hook of repositories (needed when custom config path is changed)
|
||||
dashboard.resync_all_update_hooks_success=All repositories' update hook have been rewritten successfully.
|
||||
dashboard.resync_all_update_hooks=Reescribir todos los hooks de actualización de los repositorios (necesario cuando se modifica la ruta de configuración personalizada)
|
||||
dashboard.resync_all_update_hooks_success=Todos los hooks de actualización de los repositorios se han reescrito correctamente.
|
||||
|
||||
dashboard.server_uptime=Uptime del Servidor
|
||||
dashboard.current_goroutine=Gorutinas Actuales
|
||||
@@ -547,62 +547,65 @@ dashboard.last_gc_time=Tiempo desde el Último GC
|
||||
dashboard.total_gc_time=Pausa Total por GC
|
||||
dashboard.total_gc_pause=Pausa Total por GC
|
||||
dashboard.last_gc_pause=Última Pausa por GC
|
||||
dashboard.gc_times=GC Times
|
||||
dashboard.gc_times=Ejecuciones GC
|
||||
|
||||
users.user_manage_panel=User Manage Panel
|
||||
users.new_account=Create New Account
|
||||
users.name=Name
|
||||
users.activated=Activated
|
||||
users.admin=Admin
|
||||
users.repos=Repos
|
||||
users.created=Created
|
||||
users.edit=Edit
|
||||
users.auth_source=Authorization Source
|
||||
users.user_manage_panel=Panel de Gestión de Usuarios
|
||||
users.new_account=Crear Nueva Cuenta
|
||||
users.name=Nombre
|
||||
users.activated=Activado
|
||||
users.admin=Administrador
|
||||
users.repos=Repositorios
|
||||
users.created=Creado
|
||||
users.edit=Editar
|
||||
users.auth_source=Origen de Autorización
|
||||
users.local=Local
|
||||
users.auth_login_name=Authorization Login Name
|
||||
users.update_profile_success=Account profile has been updated successfully.
|
||||
users.auth_login_name=Nombre de Usuario de Autorización
|
||||
users.update_profile_success=El perfil de la cuenta se ha actualizado correctamente.
|
||||
users.edit_account=Editar Cuenta
|
||||
users.is_activated=Esta cuenta está activada
|
||||
users.is_admin=This account has administrator permissions
|
||||
users.allow_git_hook=This account has permissions to create Git hooks
|
||||
users.update_profile=Update Account Profile
|
||||
users.delete_account=Delete This Account
|
||||
users.still_own_repo=This account still have ownership of repository, you have to delete or transfer them first.
|
||||
users.still_has_org=This account still have membership of organization, you have to left or delete them first.
|
||||
users.is_admin=Esta cuenta tiene permisos de administrador
|
||||
users.allow_git_hook=Esta cuenta tiene permisos para crear hooks de Git
|
||||
users.update_profile=Actualizar Perfil de la Cuenta
|
||||
users.delete_account=Eliminar esta Cuenta
|
||||
users.still_own_repo=Esta cuenta es propietaria de uno o más repositorios, tienes que borrarlos o transferirlos primero.
|
||||
users.still_has_org=Esta cuenta es miembro de una o más organizaciones, tienes que abandonarlas o eliminarlas primero.
|
||||
|
||||
orgs.org_manage_panel=Organization Manage Panel
|
||||
orgs.name=Name
|
||||
orgs.teams=Teams
|
||||
orgs.members=Members
|
||||
orgs.org_manage_panel=Panel de Gestión de Organización
|
||||
orgs.name=Nombre
|
||||
orgs.teams=Equipos
|
||||
orgs.members=Miembros
|
||||
|
||||
repos.repo_manage_panel=Repository Manage Panel
|
||||
repos.owner=Owner
|
||||
repos.name=Name
|
||||
repos.private=Private
|
||||
repos.watches=Watches
|
||||
repos.stars=Stars
|
||||
repos.issues=Issues
|
||||
repos.repo_manage_panel=Panel de Gestión de Repositorios
|
||||
repos.owner=Propietario
|
||||
repos.name=Nombre
|
||||
repos.private=Privado
|
||||
repos.watches=Vigilantes
|
||||
repos.stars=Estrellas
|
||||
repos.issues=Incidencias
|
||||
|
||||
auths.auth_manage_panel=Authorization Manage Panel
|
||||
auths.new=Add New Authorization Source
|
||||
auths.name=Name
|
||||
auths.type=Type
|
||||
auths.enabled=Enabled
|
||||
auths.updated=Updated
|
||||
auths.auth_type=Authorization Type
|
||||
auths.auth_name=Authorization Name
|
||||
auths.domain=Domain
|
||||
auths.auth_manage_panel=Panel de Gestión de Autorizaciones
|
||||
auths.new=Añadir nuevo origen de autorización
|
||||
auths.name=Nombre
|
||||
auths.type=Tipo
|
||||
auths.enabled=Activo
|
||||
auths.updated=Actualizado
|
||||
auths.auth_type=Tipo de Autorización
|
||||
auths.auth_name=Nombre de Autorización
|
||||
auths.domain=Dominio
|
||||
auths.host=Host
|
||||
auths.port=Port
|
||||
auths.port=Puerto
|
||||
auths.base_dn=Base DN
|
||||
auths.attributes=Search Attributes
|
||||
auths.filter=Search Filter
|
||||
auths.attribute_username=Atributo username
|
||||
auths.attribute_name=Atributo nombre
|
||||
auths.attribute_surname=Atributo apellido
|
||||
auths.attribute_mail=Atributo correo electrónico
|
||||
auths.filter=Filtro de Búsqueda
|
||||
auths.ms_ad_sa=Ms Ad SA
|
||||
auths.smtp_auth=SMTP Authorization Type
|
||||
auths.smtp_auth=Tipo de Autorización SMTP
|
||||
auths.smtphost=SMTP Host
|
||||
auths.smtpport=SMTP Port
|
||||
auths.enable_tls=Enable TLS Encryption
|
||||
auths.enable_auto_register=Enable Auto Registration
|
||||
auths.smtpport=Puerto SMTP
|
||||
auths.enable_tls=Habilitar Cifrado TLS
|
||||
auths.enable_auto_register=Hablilitar Auto-Registro
|
||||
auths.tips=Consejos
|
||||
auths.edit=Editar la Configuración de Autorización
|
||||
auths.activated=Esta autenticación ha sido activada
|
||||
@@ -625,7 +628,7 @@ config.repo_root_path=Ruta del Repositorio
|
||||
config.static_file_root_path=Ruta de los Ficheros Estáticos
|
||||
config.log_file_root_path=Ruta de los Ficheros de Log
|
||||
config.script_type=Tipo de Script
|
||||
config.reverse_auth_user=Reverse Authentication User
|
||||
config.reverse_auth_user=Autenticación Inversa de Usuario
|
||||
config.db_config=Configuración de la Base de Datos
|
||||
config.db_type=Tipo
|
||||
config.db_host=Host
|
||||
@@ -642,83 +645,83 @@ config.show_registration_button=Mostrar Botón de Registro
|
||||
config.require_sign_in_view=Solicitar la Vista de Inicio de Sesión
|
||||
config.mail_notify=Notificación por Correo Electrónico
|
||||
config.enable_cache_avatar=Activar la Caché de Avatar
|
||||
config.active_code_lives=Active Code Lives
|
||||
config.reset_password_code_lives=Reset Password Code Lives
|
||||
config.webhook_config=Webhook Configuration
|
||||
config.task_interval=Task Interval
|
||||
config.deliver_timeout=Deliver Timeout
|
||||
config.skip_tls_verify=Skip TLS Verify
|
||||
config.mailer_config=Mailer Configuration
|
||||
config.mailer_enabled=Enabled
|
||||
config.mailer_name=Name
|
||||
config.active_code_lives=Habilitar Vida del Código
|
||||
config.reset_password_code_lives=Restablecer Contraseña de Vida del Código
|
||||
config.webhook_config=Configuración de Webhooks
|
||||
config.task_interval=Intervalo de Tareas
|
||||
config.deliver_timeout=Timeout de Entrega
|
||||
config.skip_tls_verify=Omitir la Verificación TLS
|
||||
config.mailer_config=Configuración del Mailer
|
||||
config.mailer_enabled=Activado
|
||||
config.mailer_name=Nombre
|
||||
config.mailer_host=Host
|
||||
config.mailer_user=User
|
||||
config.oauth_config=OAuth Configuration
|
||||
config.oauth_enabled=Enabled
|
||||
config.cache_config=Cache Configuration
|
||||
config.cache_adapter=Cache Adapter
|
||||
config.cache_interval=Cache Interval
|
||||
config.cache_conn=Cache Connection
|
||||
config.session_config=Session Configuration
|
||||
config.session_provider=Session Provider
|
||||
config.provider_config=Provider Config
|
||||
config.cookie_name=Cookie Name
|
||||
config.enable_set_cookie=Enable Set Cookie
|
||||
config.gc_interval_time=GC Interval Time
|
||||
config.session_life_time=Session Life Time
|
||||
config.https_only=HTTPS Only
|
||||
config.cookie_life_time=Cookie Life Time
|
||||
config.picture_config=Picture Configuration
|
||||
config.picture_service=Picture Service
|
||||
config.disable_gravatar=Disable Gravatar
|
||||
config.log_config=Log Configuration
|
||||
config.log_mode=Log Mode
|
||||
config.mailer_user=Usuario
|
||||
config.oauth_config=Configuración OAuth
|
||||
config.oauth_enabled=Activado
|
||||
config.cache_config=Configuración de la Caché
|
||||
config.cache_adapter=Adaptador de la Caché
|
||||
config.cache_interval=Intervalo de la Caché
|
||||
config.cache_conn=Conexión de la Caché
|
||||
config.session_config=Configuración de la Sesión
|
||||
config.session_provider=Proveedor de la Sesión
|
||||
config.provider_config=Configuración del Proveedor
|
||||
config.cookie_name=Nombre de la Cookie
|
||||
config.enable_set_cookie=Activar Establecimiento de Cookie
|
||||
config.gc_interval_time=Intervalo de tiempo del GC
|
||||
config.session_life_time=Tiempo de Vida de la Sesión
|
||||
config.https_only=Sólo HTTPS
|
||||
config.cookie_life_time=Tiempo de Vida de la Cookie
|
||||
config.picture_config=Configuración de Imagen
|
||||
config.picture_service=Servicio de Imágen
|
||||
config.disable_gravatar=Desactivar Gravatar
|
||||
config.log_config=Configuración del Log
|
||||
config.log_mode=Modo del Log
|
||||
|
||||
monitor.cron=Cron Tasks
|
||||
monitor.name=Name
|
||||
monitor.schedule=Schedule
|
||||
monitor.next=Next Time
|
||||
monitor.previous=Previous Time
|
||||
monitor.execute_times=Execute Times
|
||||
monitor.process=Running Processes
|
||||
monitor.desc=Description
|
||||
monitor.start=Start Time
|
||||
monitor.execute_time=Execution Time
|
||||
monitor.cron=Tareas de Cron
|
||||
monitor.name=Nombre
|
||||
monitor.schedule=Agenda
|
||||
monitor.next=Próxima Vez
|
||||
monitor.previous=Vez Anterior
|
||||
monitor.execute_times=Ejecuciones
|
||||
monitor.process=Procesos en Ejecución
|
||||
monitor.desc=Descripción
|
||||
monitor.start=Hora de Inicio
|
||||
monitor.execute_time=Tiempo de ejecución
|
||||
|
||||
notices.system_notice_list=System Notices
|
||||
notices.type=Type
|
||||
notices.type_1=Repository
|
||||
notices.desc=Description
|
||||
notices.system_notice_list=Notificaciones del Sistema
|
||||
notices.type=Tipo
|
||||
notices.type_1=Repositorio
|
||||
notices.desc=Descripción
|
||||
notices.op=Op.
|
||||
notices.delete_success=System notice has been deleted successfully.
|
||||
notices.delete_success=La notificación del sistema se ha eliminado correctamente.
|
||||
|
||||
[action]
|
||||
create_repo=created repository <a href="%s/%s">%s</a>
|
||||
commit_repo=pushed to <a href="%s/%s/src/%s">%s</a> at <a href="%s/%s">%s</a>
|
||||
create_issue=`opened issue <a href="%s/issues/%s">%[1]s#%[2]s</a>`
|
||||
comment_issue=`commented on issue <a href="%s/issues/%s">%[1]s#%[2]s</a>`
|
||||
transfer_repo=transfered repository <code>%s</code> to <a href="/%s%s">%s</a>
|
||||
push_tag=pushed tag <a href="%s/%s/src/%s">%s</a> to <a href="%s/%s">%s</a>
|
||||
compare_2_commits=View comparison for these 2 commits
|
||||
create_repo=Repositorio creado <a href="%s">%s</a>
|
||||
commit_repo=hizo push a <a href="%s/src/%s">%[2]s</a> en <a href="%[1]s">%[3]s</a>
|
||||
create_issue=`incidencia abierta <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
comment_issue=`comentó en la incidencia <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
transfer_repo=transfirió el repositorio <code>%s</code> a <a href="%s">%s</a>
|
||||
push_tag=hizo push del tag <a href="%s/src/%s">%[2]s</a> a <a href="%[1]s">%[3]s</a>
|
||||
compare_2_commits=Ver la comparación de estos 2 commits
|
||||
|
||||
[tool]
|
||||
ago=ago
|
||||
from_now=from now
|
||||
now=now
|
||||
1s=1 second %s
|
||||
1m=1 minute %s
|
||||
1h=1 hour %s
|
||||
1d=1 day %s
|
||||
1w=1 week %s
|
||||
1mon=1 month %s
|
||||
1y=1 year %s
|
||||
seconds=%d seconds %s
|
||||
minutes=%d minutes %s
|
||||
hours=%d hours %s
|
||||
days=%d days %s
|
||||
weeks=%d weeks %s
|
||||
months=%d months %s
|
||||
years=%d years %s
|
||||
raw_seconds=seconds
|
||||
raw_minutes=minutes
|
||||
ago=hace
|
||||
from_now=desde ahora
|
||||
now=ahora
|
||||
1s=1 segundo %s
|
||||
1m=1 minuto %s
|
||||
1h=1 hora %s
|
||||
1d=1 día %s
|
||||
1w=1 semana %s
|
||||
1mon=1 mes %s
|
||||
1y=1 año %s
|
||||
seconds=%d segundos %s
|
||||
minutes=%d minutos %s
|
||||
hours=%d horas %s
|
||||
days=%d días %s
|
||||
weeks=%d semanas %s
|
||||
months=%d meses %s
|
||||
years=%d años %s
|
||||
raw_seconds=segundos
|
||||
raw_minutes=minutos
|
||||
|
||||
|
||||
@@ -59,8 +59,8 @@ run_user=Entrer un Utilisateur
|
||||
run_user_helper=L'utilisateur doit avoir accès à la Racine du Référentiel et éxécuter Gogs.
|
||||
domain=Domaine
|
||||
domain_helper=Cela affecte les doublons d'URL SSH.
|
||||
http_port=HTTP Port
|
||||
http_port_helper=Port number which application will listen on.
|
||||
http_port=Port HTTP
|
||||
http_port_helper=Numéro de port que l'application écoutera.
|
||||
app_url=URL de l'Application
|
||||
app_url_helper=Cela affecte les doublons d'URL HTTP/HTTPS et le contenu d'e-mail.
|
||||
email_title=Paramètres du Service de Messagerie (Facultatif)
|
||||
@@ -281,13 +281,13 @@ init_readme=Initialiser ce Référentiel avec un README.md
|
||||
create_repo=Créer un Référentiel
|
||||
default_branch=Branche par défaut
|
||||
mirror_interval=Intervalle du miroir (heure)
|
||||
goget_meta=Méta Go-Get
|
||||
goget_meta_helper=Ce Référentiel sera <span class="label label-blue label-radius">Go-Getable</span>
|
||||
|
||||
need_auth=Nécessite une Autorisation
|
||||
migrate_type=Type de Migration
|
||||
migrate_type_helper=Ce Référentiel sera un <span class="label label-blue label-radius">Miroir</span>
|
||||
migrate_repo=Migrer le Référentiel
|
||||
migrate.clone_address=Adresse du clone
|
||||
migrate.invalid_local_path=Chemin local non valide, non existant ou n'étant pas un dossier.
|
||||
|
||||
copy_link=Copier
|
||||
click_to_copy=Copier dans le presse-papier
|
||||
@@ -514,10 +514,10 @@ 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.resync_all_sshkeys=Rewrite '.ssh/autorized_key' file (caution: non-Gogs keys will be lost)
|
||||
dashboard.resync_all_sshkeys_success=All public keys have been rewritten successfully.
|
||||
dashboard.resync_all_update_hooks=Rewrite all update hook of repositories (needed when custom config path is changed)
|
||||
dashboard.resync_all_update_hooks_success=All repositories' update hook have been rewritten successfully.
|
||||
dashboard.resync_all_sshkeys=Ré-écrire le fichier '.ssh/autorized_key' (attention : les clés hors-Gogs vont être perdues)
|
||||
dashboard.resync_all_sshkeys_success=Toutes les clés publiques ont été ré-écrites avec succès.
|
||||
dashboard.resync_all_update_hooks=Ré-écrire tous les hooks de mises à jour des dépôts (requis quand le chemin de la configuration personnalisé est modifié)
|
||||
dashboard.resync_all_update_hooks_success=Tous les hooks de mises à jour des dépôts ont été ré-écris avec succès.
|
||||
|
||||
dashboard.server_uptime=Durée de Marche Serveur
|
||||
dashboard.current_goroutine=Goroutines actuelles
|
||||
@@ -595,7 +595,10 @@ auths.domain=Domaine
|
||||
auths.host=Hôte
|
||||
auths.port=Port
|
||||
auths.base_dn=Base DN (Nom Distingué)
|
||||
auths.attributes=Rechercher les Attributs
|
||||
auths.attribute_username=Attribut du nom d'utilisateur
|
||||
auths.attribute_name=Attribut du prénom
|
||||
auths.attribute_surname=Attribut du nom de famille
|
||||
auths.attribute_mail=Attribut de l'e-mail
|
||||
auths.filter=Filtre de recherche
|
||||
auths.ms_ad_sa=Ms Ad SA
|
||||
auths.smtp_auth=Type d'Autorisation SMTP
|
||||
@@ -638,7 +641,7 @@ config.db_path_helper=("sqlite3" uniquement)
|
||||
config.service_config=Configuration du Service
|
||||
config.register_email_confirm=Nécessite une confirmation par courriel
|
||||
config.disable_register=Désactiver l'Enregistrement
|
||||
config.show_registration_button=Show Register Button
|
||||
config.show_registration_button=Afficher le bouton d'enregistrement
|
||||
config.require_sign_in_view=Connexion Obligatoire pour Visualiser
|
||||
config.mail_notify=Mailer les Notifications
|
||||
config.enable_cache_avatar=Activer le Cache d'Avatar
|
||||
@@ -647,7 +650,7 @@ config.reset_password_code_lives=Réinitialiser le Mot De Passe des Limites de C
|
||||
config.webhook_config=Configuration Webhook
|
||||
config.task_interval=Intervalles de Tâches
|
||||
config.deliver_timeout=Expiration d'Envoi
|
||||
config.skip_tls_verify=Skip TLS Verify
|
||||
config.skip_tls_verify=Ne pas vérifier TLS
|
||||
config.mailer_config=Configuration du Maileur
|
||||
config.mailer_enabled=Activé
|
||||
config.mailer_name=Nom
|
||||
@@ -693,12 +696,12 @@ notices.op=Auteur
|
||||
notices.delete_success=Note système supprimée avec succès.
|
||||
|
||||
[action]
|
||||
create_repo=a crée le Référentiel <a href="%s/%s">%s</a>
|
||||
commit_repo=a soumis à <a href="%s/%s/src/%s">%s</a> chez <a href="%s/%s">%s</a>
|
||||
create_issue=`a ouvert un problème <a href="%s/issues/%s">%[1]s#%[2]s</a>`
|
||||
comment_issue=`a commenté le problème <a href="%s/issues/%s">%[1]s#%[2]s</a>`
|
||||
transfer_repo=a transféré le Référentiel <code>%s</code> à <a href="/%s%s">%s</a>
|
||||
push_tag=a tagé <a href="%s/%s/src/%s">%s</a> à <a href="%s/%s">%s</a>
|
||||
create_repo=a crée le Référentiel <a href="%s">%s</a>
|
||||
commit_repo=a soumis à <a href="%s/src/%s">%[2]s</a> chez <a href="%[1]s">%[3]s</a>
|
||||
create_issue=`a ouvert un problème <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
comment_issue=`a commenté le problème <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
transfer_repo=a transféré le Référentiel <code>%s</code> à <a href="%s">%s</a>
|
||||
push_tag=a tagé <a href="%s/src/%s">%[2]s</a> à <a href="%[1]s">%[3]s</a>
|
||||
compare_2_commits=Comparer ces 2 commissions
|
||||
|
||||
[tool]
|
||||
|
||||
@@ -281,13 +281,13 @@ init_readme=README.md 付きでリポジトリを初期化
|
||||
create_repo=リポジトリを作成
|
||||
default_branch=デフォルトのブランチ
|
||||
mirror_interval=ミラー 間隔(時)
|
||||
goget_meta=Go-Get メタ
|
||||
goget_meta_helper=このリポジトリは <span class="label label-blue label-radius"> Go-Getable </span> になります
|
||||
|
||||
need_auth=認証が必要
|
||||
migrate_type=マイグレーションの種類
|
||||
migrate_type_helper=このリポジトリは <span class="label label-blue label-radius"> ミラー</span> になります
|
||||
migrate_repo=リポジトリを移行
|
||||
migrate.clone_address=クローンアドレス
|
||||
migrate.invalid_local_path=ローカルパスが無効です。存在しないかディレクトリではありません。
|
||||
|
||||
copy_link=コピー
|
||||
click_to_copy=クリップボードにコピー
|
||||
@@ -595,7 +595,10 @@ auths.domain=ドメイン
|
||||
auths.host=ホスト
|
||||
auths.port=ポート
|
||||
auths.base_dn=ベースのドメイン名
|
||||
auths.attributes=属性検索
|
||||
auths.attribute_username=ユーザー名属性
|
||||
auths.attribute_name=名前属性
|
||||
auths.attribute_surname=名字属性
|
||||
auths.attribute_mail=Eメール属性
|
||||
auths.filter=検索フィルター
|
||||
auths.ms_ad_sa=Ms Ad SA
|
||||
auths.smtp_auth=SMTP 認証の種類
|
||||
@@ -693,12 +696,12 @@ notices.op=Op。
|
||||
notices.delete_success=システム通知が正常に削除されました。
|
||||
|
||||
[action]
|
||||
create_repo=リポジトリ <a href="%s/%s"> %s</a>を作成しました
|
||||
commit_repo=<a href="%s/%s">%s</a>を<a href="%s/%s/src/%s">%s</a>にプッシュしました
|
||||
create_issue=`問題 <a href="%s/issues/%s">%[1]s#%[2]s</a> を開きました`
|
||||
comment_issue=`問題 <a href="%s/issues/%s">%[1]s#%[2]s</a> のコメント`
|
||||
transfer_repo=リポジトリ <code>%s</code> を <a href="/%s%s">%s</a> へ転送しました
|
||||
push_tag=<a href="%s/%s">%s</a> に タグ <a href="%s/%s/src/%s">%s</a> をプッシュしました
|
||||
create_repo=リポジトリ <a href="%s"> %s</a>を作成しました
|
||||
commit_repo=<a href="%[1]s">%[3]s</a>を<a href="%[1]s/src/%[2]s">%[2]s</a>にプッシュしました
|
||||
create_issue=`問題 <a href="%s/issues/%s">%s#%[2]s</a> を開きました`
|
||||
comment_issue=`問題 <a href="%s/issues/%s">%s#%[2]s</a> のコメント`
|
||||
transfer_repo=リポジトリ <code>%s</code> を <a href="%s">%s</a> へ転送しました
|
||||
push_tag=<a href="%[1]s">%[3]s</a> に タグ <a href="%[1]s/src/%[2]s">%[2]s</a> をプッシュしました
|
||||
compare_2_commits=これら 2 のコミットの比較を閲覧する
|
||||
|
||||
[tool]
|
||||
|
||||
@@ -281,13 +281,13 @@ 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
|
||||
migrate.clone_address=Clone Address
|
||||
migrate.invalid_local_path=Invalid local path, it does not exist or not a directory.
|
||||
|
||||
copy_link=Kopēt
|
||||
click_to_copy=Kopēt uz starpliktuvi
|
||||
@@ -516,8 +516,8 @@ 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.resync_all_sshkeys=Pārrakstīt '.ssh/authorized_key' failu (brīdinājums: ne-Git atslēgas tiks pazaudētas)
|
||||
dashboard.resync_all_sshkeys_success=Visas publiskās atslēgas tika veiksmīgi pārrakstītas.
|
||||
dashboard.resync_all_update_hooks=Rewrite all update hook of repositories (needed when custom config path is changed)
|
||||
dashboard.resync_all_update_hooks_success=All repositories' update hook have been rewritten successfully.
|
||||
dashboard.resync_all_update_hooks=Pārrakstīt visu repozitoriju izmaiņu āķus (nepieciešams, ja tiek mainīta konfigurācijas faila atrašanās vieta)
|
||||
dashboard.resync_all_update_hooks_success=Visu repozitoriju izmaiņu āķi tika veiksmīgi pārrakstīti.
|
||||
|
||||
dashboard.server_uptime=Servera darbības laiks
|
||||
dashboard.current_goroutine=Izmantotās Gorutīnas
|
||||
@@ -595,7 +595,10 @@ auths.domain=Domēns
|
||||
auths.host=Resursdators
|
||||
auths.port=Ports
|
||||
auths.base_dn=Pamata DN
|
||||
auths.attributes=Meklēšanas atribūti
|
||||
auths.attribute_username=Username attribute
|
||||
auths.attribute_name=First name attribute
|
||||
auths.attribute_surname=Surname attribute
|
||||
auths.attribute_mail=E-mail attribute
|
||||
auths.filter=Meklēšanas filtrs
|
||||
auths.ms_ad_sa=MS Ad SA
|
||||
auths.smtp_auth=SMTP autorizācijas veids
|
||||
@@ -647,7 +650,7 @@ 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.skip_tls_verify=Skip TLS Verify
|
||||
config.skip_tls_verify=Izlaist TLS pārbaudi
|
||||
config.mailer_config=Sūtītāja konfigurācija
|
||||
config.mailer_enabled=Iespējots
|
||||
config.mailer_name=Nosaukums
|
||||
@@ -693,12 +696,12 @@ 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/issues/%s">%[1]s#%[2]s</a>`
|
||||
comment_issue=`pievienoja komentāru problēmai <a href="%s/issues/%s">%[1]s#%[2]s</a>`
|
||||
transfer_repo=mainīja repozitorija <code>%s</code> īpašnieku uz <a href="/%s%s">%s</a>
|
||||
push_tag=pievienoja tagu <a href="%s/%s/src/%s">%s</a> repozitorijam <a href="%s/%s">%s</a>
|
||||
create_repo=izveidoja repozitoriju <a href="%s">%s</a>
|
||||
commit_repo=veica izmaiņu nosūtīšanu atzaram <a href="%s/src/%s">%[2]s</a> repozitorijā <a href="%[1]s">%[3]s</a>
|
||||
create_issue=`reģistrēja problēmu <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
comment_issue=`pievienoja komentāru problēmai <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
transfer_repo=mainīja repozitorija <code>%s</code> īpašnieku uz <a href="%s">%s</a>
|
||||
push_tag=pievienoja tagu <a href="%s/src/%s">%[2]s</a> repozitorijam <a href="%[1]s">%[3]s</a>
|
||||
compare_2_commits=Veikt salīdzināšanu starp šīm 2 revīzijām
|
||||
|
||||
[tool]
|
||||
|
||||
@@ -281,13 +281,13 @@ init_readme=Initialiseer deze repositorie met een README.md
|
||||
create_repo=Nieuwe Repositorie
|
||||
default_branch=Standaard branch
|
||||
mirror_interval=Mirror interval(uur)
|
||||
goget_meta=Go-Get Meta
|
||||
goget_meta_helper=Deze repositorie is nu beschikbaar voor <span class="label label-blue label-radius">Go-Get</span>
|
||||
|
||||
need_auth=Autorisatie vereist
|
||||
migrate_type=Migratie type
|
||||
migrate_type_helper=Deze repositorie zal een <span class="label label-blue label-radius">mirror</span> worden
|
||||
migrate_repo=Migreer repositorie
|
||||
migrate.clone_address=Clone Address
|
||||
migrate.invalid_local_path=Invalid local path, it does not exist or not a directory.
|
||||
|
||||
copy_link=Kopieer
|
||||
click_to_copy=Kopieer link naar plakbord
|
||||
@@ -595,7 +595,10 @@ auths.domain=Domein
|
||||
auths.host=Host
|
||||
auths.port=Poort
|
||||
auths.base_dn=Base DN
|
||||
auths.attributes=Zoek attributen
|
||||
auths.attribute_username=Username attribute
|
||||
auths.attribute_name=First name attribute
|
||||
auths.attribute_surname=Surname attribute
|
||||
auths.attribute_mail=E-mail attribute
|
||||
auths.filter=Zoek filter
|
||||
auths.ms_ad_sa=MS Ad SA
|
||||
auths.smtp_auth=SMTP authenticatietype
|
||||
@@ -693,12 +696,12 @@ notices.op=Op.
|
||||
notices.delete_success=Systeem bericht is met succes verwijderd.
|
||||
|
||||
[action]
|
||||
create_repo=repositorie aangemaakt in <a href="%s/%s">%s</a>
|
||||
commit_repo=push update naar <a href="%s/%s/src/%s">%s</a> in <a href="%s/%s">%s</a
|
||||
create_issue=`opende issue in <a href="%s/issues/%s">%[1]s#%[2]s</a>`
|
||||
comment_issue=`reactie op issue <a href="%s/issues/%s">%[1]s#%[2]s</a>`
|
||||
transfer_repo=repositorie verplaatst naar <code>%s</code> naar <a href="/%s%s">%s</a>
|
||||
push_tag=geduwd label <a href="%s/%s/src/%s"> %s</a> naar <a href="%s/%s"> %s</a>
|
||||
create_repo=repositorie aangemaakt in <a href="%s">%s</a>
|
||||
commit_repo=push update naar <a href="%s/src/%s">%[2]s</a> in <a href="%[1]s">%[3]s</a>
|
||||
create_issue=`opende issue in <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
comment_issue=`reactie op issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
transfer_repo=repositorie verplaatst naar <code>%s</code> naar <a href="%s">%s</a>
|
||||
push_tag=geduwd label <a href="%s/src/%s"> %[2]s</a> naar <a href="%[1]s"> %[3]s</a>
|
||||
compare_2_commits=Weergave vergelijking voor deze 2 commits
|
||||
|
||||
[tool]
|
||||
|
||||
727
conf/locale/locale_pt-BR.ini
Executable file
727
conf/locale/locale_pt-BR.ini
Executable file
@@ -0,0 +1,727 @@
|
||||
app_desc=Um serviço de Git auto-hospedado e amigável escrito em Go
|
||||
|
||||
home=Página Inicial
|
||||
dashboard=Painel de controle
|
||||
explore=Explorar
|
||||
help=Ajuda
|
||||
sign_in=Entrar
|
||||
social_sign_in=Entrada Social: 2ª etapa <small>associar uma conta</small>
|
||||
sign_out=Sair
|
||||
sign_up=Cadastrar
|
||||
register=Registrar
|
||||
website=Site
|
||||
version=Versão
|
||||
page=Página
|
||||
template=Modelo
|
||||
language=Idioma
|
||||
|
||||
username=Usuário
|
||||
email=E-mail
|
||||
password=Senha
|
||||
re_type=Redigite
|
||||
captcha=Captcha
|
||||
|
||||
repository=Repositório
|
||||
organization=Organização
|
||||
mirror=Espelho
|
||||
new_repo=Novo Repositório
|
||||
new_migrate=Nova Migração
|
||||
new_fork=Novo Fork de Repositório
|
||||
new_org=Nova Organização
|
||||
manage_org=Gerenciar Organizações
|
||||
admin_panel=Painel do Administrador
|
||||
account_settings=Configurações da Conta
|
||||
settings=Configurações
|
||||
|
||||
news_feed=Feed de Notícias
|
||||
pull_requests=Solicitações de Pull
|
||||
issues=Problemas
|
||||
|
||||
cancel=Cancelar
|
||||
|
||||
[install]
|
||||
install=Instalação
|
||||
title=Etapas de instalação para Primeira Execução
|
||||
requite_db_desc=Gogs requer MySQL, PostgreSQL ou SQLite3.
|
||||
db_type=Tipo do Banco de Dados
|
||||
host=Host
|
||||
user=Usuário
|
||||
password=Senha
|
||||
db_name=Nome do Banco de Dados
|
||||
db_helper=Por favor, use o mecanismo INNODB com o conjunto de caracteres utf8_general_ci para MySQL.
|
||||
ssl_mode=Modo SSL
|
||||
path=Caminho
|
||||
sqlite_helper=O caminho do arquivo do banco de dados do SQLite3.
|
||||
general_title=Configurações Gerais do Gogs
|
||||
repo_path=Caminho da Raiz do Repositório
|
||||
repo_path_helper=Todos os repositórios remotos do Git serão salvos neste diretório.
|
||||
run_user=Executar Usuário
|
||||
run_user_helper=O usuário deve ter acesso ao caminho raiz do repositório e executar o Gogs
|
||||
domain=Domínio
|
||||
domain_helper=Isto afeta URLs para clonagem via SSH.
|
||||
http_port=Porta HTTP
|
||||
http_port_helper=Número da porta em que a aplicação irá executar.
|
||||
app_url=URL do Aplicativo
|
||||
app_url_helper=Isto afeta a URL de clonagem via HTTP/HTTPs e também o email.
|
||||
email_title=Configurações do Serviço de E-mail(Opcionais)
|
||||
smtp_host=Host SMTP
|
||||
mailer_user=E-mail do Remetente
|
||||
mailer_password=Senha do Remetente
|
||||
notify_title=Configurações de Notificação (Opcional)
|
||||
register_confirm=Habilitar Confirmação de Registro
|
||||
mail_notify=Habilitar Notificação de Correio
|
||||
admin_title=Configurações da Conta de Administrador
|
||||
admin_name=Nome de Usuário
|
||||
admin_password=Senha
|
||||
confirm_password=Confirmar Senha
|
||||
admin_email=E-mail
|
||||
install_gogs=Instalar Gogs
|
||||
test_git_failed=Falha ao testar o comando 'git': %v
|
||||
sqlite3_not_available=Sua versão não suporta SQLite3, por favor faça o download da versão binária oficial em %s, NÃO da versão gobuild.
|
||||
invalid_db_setting=Configuração do banco de dados não está correta: %v
|
||||
invalid_repo_path=A raiz do repositório é inválida: %v
|
||||
run_user_not_match=O usuário da execução não é o usuário atual: %s -> %s
|
||||
save_config_failed=Falha ao salvar a configuração: %v
|
||||
invalid_admin_setting=Configuração da conta de administrador está inválida: %v
|
||||
install_success=Bem-vindo! Estamos contentes que você escolheu o Gogs, divirta-se e tenha cuidado.
|
||||
|
||||
[home]
|
||||
uname_holder=Nome de Usuário ou E-mail
|
||||
password_holder=Senha
|
||||
switch_dashboard_context=Trocar Contexto do Painel de Controle
|
||||
my_repos=Meus Repositórios
|
||||
collaborative_repos=Repositórios Colaborativos
|
||||
my_orgs=Minhas Organizações
|
||||
my_mirrors=Meus Espelhos
|
||||
|
||||
[explore]
|
||||
repos=Repositórios
|
||||
|
||||
[auth]
|
||||
create_new_account=Criar Nova Conta
|
||||
register_hepler_msg=Já tem uma conta? Entre agora!
|
||||
social_register_hepler_msg=Já tem uma conta? Junte-se agora!
|
||||
disable_register_prompt=Desculpe, novos registros estão desabilitados. Por favor entre em contato com o administrador do site.
|
||||
disable_register_mail=Desculpe, a confirmação de registro por email foi desabilitada.
|
||||
remember_me=Lembrar de Mim
|
||||
forgot_password=Esqueci a Senha
|
||||
forget_password=Esqueceu a senha?
|
||||
sign_up_now=Precisa de uma conta? Cadastre-se agora.
|
||||
confirmation_mail_sent_prompt=Um novo e-mail de confirmação foi enviado para <b>%s</b>, por favor, verifique sua caixa de entrada nas próximas %d horas para completar seu registro.
|
||||
sign_in_email=Entre com seu e-mail
|
||||
active_your_account=Ativar Sua Conta
|
||||
resent_limit_prompt=Desculpe, você está enviando um e-mail de ativação com muita frequência. Por favor, aguarde 3 minutos.
|
||||
has_unconfirmed_mail=Oi %s, você possui um endereço de e-mail não confirmado (<b>%s</b>). Se você não recebeu um e-mail de confirmação ou precisa reenviar um novo, clique no botão abaixo.
|
||||
resend_mail=Clique aqui para reenviar seu e-mail de ativação
|
||||
email_not_associate=Este endereço de e-mail não é associado à nenhuma conta.
|
||||
send_reset_mail=Clique aqui para (re)enviar seu e-mail de redefinição da senha
|
||||
reset_password=Redefinir Sua Senha
|
||||
invalid_code=Desculpe, seu código de confirmação expirou ou não é válido.
|
||||
reset_password_helper=Clique aqui para redefinir sua senha
|
||||
password_too_short=O comprimento da senha não pode ser menor que 6.
|
||||
|
||||
[form]
|
||||
UserName=Nome de usuário
|
||||
RepoName=Nome do repositório
|
||||
Email=Endereço de e-mail
|
||||
Password=Senha
|
||||
Retype=Redigite a senha
|
||||
SSHTitle=Nome da chave SSH
|
||||
HttpsUrl=URL HTTPS
|
||||
PayloadUrl=URL de carga
|
||||
TeamName=Nome da equipe
|
||||
AuthName=Nome de autorização
|
||||
AdminEmail=E-mail do Administrador
|
||||
|
||||
require_error=` não pode estar vazio.`
|
||||
alpha_dash_error=` devem ser caracteres alfanuméricos ou hífen (-) ou sublinhado (_).`
|
||||
alpha_dash_dot_error=` devem ser caracteres alfanuméricos ou hífen (-) ou sublinhado (_).`
|
||||
min_size_error=` deve conter pelo menos %s caracteres.`
|
||||
max_size_error=` deve conter no máximo %s caracteres.`
|
||||
email_error=` não é um endereço de e-mail válido.`
|
||||
url_error=`não é uma URL válida.`
|
||||
unknown_error=Erro desconhecido:
|
||||
captcha_incorrect=O captcha não correspondeu.
|
||||
password_not_match=Senha e confirmar senha não são as mesmas.
|
||||
|
||||
username_been_taken=Nome de usuário já foi tomado.
|
||||
repo_name_been_taken=Nome do repositório já foi tomado.
|
||||
org_name_been_taken=Nome da organização já foi tomado.
|
||||
team_name_been_taken=Nome da equipe já foi tomado.
|
||||
email_been_used=Endereço de e-mail já foi usado.
|
||||
ssh_key_been_used=Nome da chave pública foi usado.
|
||||
illegal_username=Seu nome de usuário contém caracteres ilegais.
|
||||
illegal_repo_name=Nome do repositório contém caracteres ilegais.
|
||||
illegal_org_name=Nome da organização contém caracteres ilegais.
|
||||
illegal_team_name=O nome da equipe contém caracteres ilegais.
|
||||
username_password_incorrect=Usuário ou senha incorretos.
|
||||
enterred_invalid_repo_name=Por favor certifique-se que informou o nome do repositório corretamente.
|
||||
enterred_invalid_owner_name=Por favor, verifique se o nome do proprietário está correto.
|
||||
enterred_invalid_password=Por favor, verifique se a senha que você digitou está correta.
|
||||
user_not_exist=O usuário dado não existe.
|
||||
last_org_owner=O usuário a ser removido é o último membro na equipe de proprietários. Deve haver um outro proprietário.
|
||||
|
||||
invalid_ssh_key=Desculpe, não conseguimos verificar a sua chave SSH: %s
|
||||
unable_verify_ssh_key=Gogs não pode verificar sua chave SSH, mas assumimos que é válida, por favor, verifique a chave pessoalmente.
|
||||
auth_failed=A autenticação falhou: %v
|
||||
|
||||
still_own_repo=Sua conta ainda tem propriedade do repositório, você tem que excluir ou transferí-la primeiro.
|
||||
still_has_org=Sua conta ainda faz parte da organização, você deve sair ou excluí-la primeiro.
|
||||
org_still_own_repo=Esta organização ainda tem a propriedade do repositório, você deve excluir ou transferí-la primeiro.
|
||||
|
||||
still_own_user=Esta autenticação ainda é usada por alguns usuários, você deve movê-los e depois apagar novamente.
|
||||
|
||||
target_branch_not_exist=O ramo de destino não existe.
|
||||
|
||||
[user]
|
||||
change_avatar=Altere o seu avatar em gravatar.com
|
||||
change_custom_avatar=Altere seu avatar nas configurações
|
||||
join_on=Inscreveu-se em
|
||||
repositories=Repositórios
|
||||
activity=Atividade Pública
|
||||
followers=Seguidores
|
||||
starred=Marcado
|
||||
following=Seguindo
|
||||
|
||||
[settings]
|
||||
profile=Perfil
|
||||
password=Senha
|
||||
ssh_keys=Chaves SSH
|
||||
social=Contas Sociais
|
||||
applications=Aplicativos
|
||||
orgs=Organizações
|
||||
delete=Deletar Conta
|
||||
uid=Uid
|
||||
|
||||
public_profile=Perfil Público
|
||||
profile_desc=Seu endereço de E-mail é publico e será usado para qualquer notificação relacionada à conta, e qualquer operação na web feita através do site.
|
||||
full_name=Nome Completo
|
||||
website=Site
|
||||
location=Localização
|
||||
update_profile=Atualizar o Perfil
|
||||
update_profile_success=O seu perfil foi atualizado com sucesso.
|
||||
change_username=Nome de Usuário Alterado
|
||||
change_username_desc=O nome de usuário foi alterado, você quer continuar? Isto afetará todos os links relacionados à sua conta.
|
||||
continue=Continuar
|
||||
cancel=Cancelar
|
||||
|
||||
enable_custom_avatar=Habilitar Avatar Customizado
|
||||
enable_custom_avatar_helper=Habilite para desativar a busca no Gravatar
|
||||
choose_new_avatar=Escolha um novo avatar
|
||||
update_avatar=Atualizar configuração de Avatar
|
||||
uploaded_avatar_not_a_image=O arquivo enviado não é uma imagem.
|
||||
no_custom_avatar_available=Nenhum avatar personalizado disponível, não pode habilitá-lo.
|
||||
update_avatar_success=Sua configuração de avatar foi atualizada com sucesso.
|
||||
|
||||
change_password=Alterar a Senha
|
||||
old_password=Senha Atual
|
||||
new_password=Nova Senha
|
||||
password_incorrect=A senha atual não está correta.
|
||||
change_password_success=A senha está alterada com sucesso. Você pode agora entrar com a senha nova.
|
||||
|
||||
emails=Endereços de E-mail
|
||||
manage_emails=Gerenciar endereços de e-mail
|
||||
email_desc=Seu endereço de email principal será usado para notificações e outras operações.
|
||||
primary=Principal
|
||||
primary_email=Definir como principal
|
||||
delete_email=Deletar
|
||||
add_new_email=Adicionar novo endereço de e-mail
|
||||
add_email=Adicionar e-mail
|
||||
add_email_success=Seu novo endereço de E-mail foi adicionado com sucesso.
|
||||
|
||||
manage_ssh_keys=Gerenciar Chaves SSH
|
||||
add_key=Adicionar Chave
|
||||
ssh_desc=Esta é uma lista de chaves SSH associadas com a sua conta. Remova quaisquer chaves que você não reconheça.
|
||||
ssh_helper=<strong>Precisa de ajuda?</strong> Confira nosso guia para <a href="%s">gerar chaves SSH</a> ou solucionar <a href="%s">problemas comuns com SSH</a>.
|
||||
add_new_key=Adicionar Chave SSH
|
||||
key_name=Nome da Chave
|
||||
key_content=Conteúdo
|
||||
add_key_success=Nova Chave SSH foi adicionada!
|
||||
delete_key=Deletar
|
||||
add_on=Adicionado em
|
||||
last_used=Última vez usado em
|
||||
no_activity=Nenhuma atividade recente
|
||||
|
||||
manage_social=Gerenciar Contas Sociais Associadas
|
||||
social_desc=Esta é uma lista de contas sociais. Remova qualquer ligação que você não reconheça.
|
||||
unbind=Desvincular
|
||||
unbind_success=A conta social foi desvinculada.
|
||||
|
||||
manage_access_token=Gerenciar Tokens de Acesso pessoais
|
||||
generate_new_token=Gerar novo Token
|
||||
tokens_desc=Tokens gerados por você que podem ser usados para acessar a API Gogs.
|
||||
new_token_desc=Por enquanto, todo token terá acesso completo à sua conta.
|
||||
token_name=Nome do Token
|
||||
generate_token=Gerar Token
|
||||
generate_token_succees=Novo token de acesso gerado com sucesso! Certifique-se de copiar seu novo token de acesso pessoal agora. Você não poderá vê-lo novamente!
|
||||
delete_token=Excluir
|
||||
delete_token_success=Token de acesso pessoal deletado com sucesso! Não esqueça-se de atualizar seus aplicativos também.
|
||||
|
||||
delete_account=Deletar Sua Conta
|
||||
delete_prompt=A operação deletará sua conta permanentemente, e <strong>NÃO PODERÁ</strong> ser desfeita!
|
||||
confirm_delete_account=Confirmar Deleção
|
||||
delete_account_title=Deleção da Conta
|
||||
delete_account_desc=Esta conta será deletada permanentemente, você quer continuar?
|
||||
|
||||
[repo]
|
||||
owner=Dono
|
||||
repo_name=Nome do Repositório
|
||||
repo_name_helper=Nomes de repositórios bons são pequenos, memorizáveis e <strong>únicos</strong>.
|
||||
visibility=Visibilidade
|
||||
visiblity_helper=Este repositório é <span class="label label-red label-radius">Privado</span>
|
||||
fork_repo=Fork o Repositório
|
||||
fork_from=Fork de
|
||||
fork_visiblity_helper=Não é possível alterar a visibilidade de um repositório bifurcado
|
||||
repo_desc=Descrição
|
||||
repo_lang=Idioma
|
||||
repo_lang_helper=Selecione um arquivo .gitignore
|
||||
license=Licença
|
||||
license_helper=Selecione um arquivo de licença
|
||||
init_readme=Inicialize este repositório com um LEIAME.md
|
||||
create_repo=Criar Repositório
|
||||
default_branch=Ramo padrão
|
||||
mirror_interval=Intervalo de Espelho (hora)
|
||||
|
||||
need_auth=Precisa de Autorização
|
||||
migrate_type=Tipo de Migração
|
||||
migrate_type_helper=Este repositório será um <span class="label label-blue label-radius">Espelho</span>
|
||||
migrate_repo=Migrar Repositório
|
||||
migrate.clone_address=Endereço de Clone
|
||||
migrate.invalid_local_path=Caminho local inválido, não existe ou não é um diretório.
|
||||
|
||||
copy_link=Copiar
|
||||
click_to_copy=Copiar para a área de transferência
|
||||
copied=Copiado com sucesso
|
||||
clone_helper=Precisa de ajuda com a clonagem? Visite a <a target="_blank" href="%s">Ajuda</a>!
|
||||
unwatch=Deixar de Observar
|
||||
watch=Observar
|
||||
unstar=Remover favorito
|
||||
star=Favorito
|
||||
fork=Fork
|
||||
|
||||
no_desc=Nenhuma Descrição
|
||||
quick_guide=Guia Rápido
|
||||
clone_this_repo=Clonar este repositório
|
||||
create_new_repo_command=Criar um novo repositório na linha de comando
|
||||
push_exist_repo=Push um repositório existente na linha de comando
|
||||
|
||||
branch=Ramo
|
||||
tree=Árvore
|
||||
branch_and_tags=Ramos & Tags
|
||||
branches=Ramos
|
||||
tags=Tags
|
||||
issues=Problemas
|
||||
commits=Commits
|
||||
releases=Lançamentos
|
||||
file_raw=Cru
|
||||
file_history=Histórico
|
||||
file_view_raw=Ver cru
|
||||
|
||||
commits.commits=Commits
|
||||
commits.search=Pesquisar commits
|
||||
commits.find=Buscar
|
||||
commits.author=Autor
|
||||
commits.message=Mensagem
|
||||
commits.date=Data
|
||||
commits.older=Mais Antigo
|
||||
commits.newer=Mais Novo
|
||||
|
||||
settings=Configurações
|
||||
settings.options=Opções
|
||||
settings.collaboration=Colaboração
|
||||
settings.hooks=Hooks da web
|
||||
settings.githooks=Hooks do Git
|
||||
settings.deploy_keys=Chaves de Deploy
|
||||
settings.basic_settings=Configurações Básicas
|
||||
settings.danger_zone=Zona de Perigo
|
||||
settings.site=Site Oficial
|
||||
settings.update_settings=Configurações de Atualização
|
||||
settings.change_reponame=Nome do Repositório Alterado
|
||||
settings.change_reponame_desc=O nome do repositório foi alterado, você quer continuar? Isto afetará todos os links relacionados à este repositório.
|
||||
settings.transfer=Transferir Propriedade
|
||||
settings.transfer_desc=Transferir este repositório para outro usuário ou para uma organização onde você tem direitos de administrador.
|
||||
settings.new_owner_has_same_repo=O novo dono já tem um repositório com o mesmo nome.
|
||||
settings.delete=Deletar Este Repositório
|
||||
settings.delete_desc=Uma vez que você deleta um repositório, não tem volta. Por favor, tenha certeza.
|
||||
settings.transfer_notices=<p>- Você perderá acesso se o novo dono é um usuário individual.</p><p>- Você permanecerá com o acesso se o novo dono é uma organização e você é um dos donos.</p>
|
||||
settings.update_settings_success=As opções do repositório foram atualizadas com sucesso.
|
||||
settings.transfer_owner=Novo Dono
|
||||
settings.make_transfer=Fazer Transferência
|
||||
settings.transfer_succeed=A posse do repositório foi transferido com sucesso.
|
||||
settings.confirm_delete=Confirmar Deleção
|
||||
settings.add_collaborator=Adicionar um Novo Colaborador
|
||||
settings.add_collaborator_success=O novo colaborador foi adicionado.
|
||||
settings.remove_collaborator_success=O colaborador foi removido.
|
||||
settings.user_is_org_member=O usuário é um membro da organização que não pode ser adicionado como um colaborador.
|
||||
settings.add_webhook=Adicionar Webhook
|
||||
settings.hooks_desc=Hooks da web ou Webhooks permitem serviços externos serem notificados quando certos eventos acontecem no Gogs. Quando acontecem os eventos especificados, enviaremos uma solicitação POST para cada uma das URLs que você fornecer. Saiba mais no nosso <a target="_blank" href="%s"> Guia de Webhooks</a>.
|
||||
settings.githooks_desc=Hooks do Git são ofertados pelo próprio Git, você pode editar arquivos de hooks suportados na lista abaixo para aplicar operações personalizadas.
|
||||
settings.githook_edit_desc=Se o hook não estiver ativo, o conteúdo de exemplo será apresentado. Deixar o conteúdo em branco irá desativar esse hook.
|
||||
settings.githook_name=Nome do Hook
|
||||
settings.githook_content=Conteúdo do Hook
|
||||
settings.update_githook=Atualizar Hook
|
||||
settings.remove_hook_success=O hook da web foi removido.
|
||||
settings.add_webhook_desc=Enviaremos uma solicitação <code>POST</code> para o URL abaixo com detalhes de quaisquer eventos inscritos. Você pode também especificar qual formato de dados você gostaria de receber (JSON, <code>x-www-form-urlencoded</code>, <em>etc</em>). Mais informação pode ser encontrada em <a target="_blank" href="%s">Webhooks Guide</a>.
|
||||
settings.payload_url=URL de carga
|
||||
settings.content_type=Tipo de Conteúdo
|
||||
settings.secret=Secreto
|
||||
settings.event_desc=Quais eventos você gostaria de acionar a esse hook da web?
|
||||
settings.event_push_only=Apenas o evento <code>push</code>.
|
||||
settings.active=Ativar
|
||||
settings.active_helper=Enviaremos detalhes do evento quando este hook for acionado.
|
||||
settings.add_hook_success=Novos hooks de web foram adicionados.
|
||||
settings.update_webhook=Atualizar Hook da Web
|
||||
settings.update_hook_success=Hook da web atualizado.
|
||||
settings.delete_webhook=Excluir Hook da Web
|
||||
settings.recent_deliveries=Entregas Recentes
|
||||
settings.hook_type=Tipo de Hook
|
||||
settings.add_slack_hook_desc=Adicionar <a href="%s">Slack</a> de integração para o seu repositório.
|
||||
settings.slack_token=Token
|
||||
settings.slack_domain=Domínio
|
||||
settings.slack_channel=Canal
|
||||
|
||||
diff.browse_source=Ver Fontes
|
||||
diff.parent=pai
|
||||
diff.commit=commit
|
||||
diff.data_not_available=Dados Diff não disponíveis.
|
||||
diff.show_diff_stats=Mostrar estatísticas do Diff
|
||||
diff.stats_desc=<strong> %d arquivos alterados</strong> com <strong>%d adições</strong> e <strong>%d exclusões</strong>
|
||||
diff.bin=BIN
|
||||
diff.view_file=Ver Arquivo
|
||||
|
||||
release.releases=Lançamentos
|
||||
release.new_release=Novo Lançamento
|
||||
release.draft=Rascunho
|
||||
release.prerelease=Pré-Lançamento
|
||||
release.stable=Estável
|
||||
release.edit=editar
|
||||
release.ahead=<strong>%d</strong> commits para %s depois desta versão
|
||||
release.source_code=Código-fonte
|
||||
release.tag_name=Nome da tag
|
||||
release.target=Destino
|
||||
release.tag_helper=Escolha uma tag existente, ou crie uma nova tag em publicar.
|
||||
release.release_title=Título da Versão
|
||||
release.content_with_md=Conteúdo com <a href="%s">Markdown</a>
|
||||
release.write=Escrever
|
||||
release.preview=Visualizar
|
||||
release.content_placeholder=Escreva algum conteúdo
|
||||
release.loading=Carregando...
|
||||
release.prerelease_desc=Esta é uma versão prévia
|
||||
release.prerelease_helper=Vou salientar que esta versão é identificada como não pronta para produção.
|
||||
release.publish=Publicar Versão
|
||||
release.save_draft=Salvar Rascunho
|
||||
release.edit_release=Editar Versão
|
||||
release.tag_name_already_exist=Já existiu versão com esse nome de tag.
|
||||
|
||||
[org]
|
||||
org_name_holder=Nome da Organização
|
||||
org_name_helper=Nomes de grandes organizações são curtos e memoráveis.
|
||||
org_email_helper=O E-mail da organização receberá todas as notificações e as confirmações.
|
||||
create_org=Criar Organização
|
||||
repo_updated=Atualizado
|
||||
people=Pessoas
|
||||
invite_someone=Convidar Alguém
|
||||
teams=Equipes
|
||||
lower_members=membros
|
||||
lower_repositories=repositórios
|
||||
create_new_team=Criar Nova Equipe
|
||||
org_desc=Descrição
|
||||
team_name=Nome da Equipe
|
||||
team_desc=Descrição
|
||||
team_name_helper=Você usará este nome para mencionar esta equipe em conversas.
|
||||
team_desc_helper=Do que trata essa equipe?
|
||||
team_permission_desc=Que nível de permissão esta equipe deve ter?
|
||||
|
||||
settings=Configurações
|
||||
settings.options=Opções
|
||||
settings.full_name=Nome Completo
|
||||
settings.website=Site
|
||||
settings.location=Localização
|
||||
settings.update_settings=Atualizar Configurações
|
||||
settings.change_orgname=Nome da Organização Alterado
|
||||
settings.change_orgname_desc=O nome da organização foi alterado, você quer continuar? Isto afetará todos os links que se relacionam a esta organização.
|
||||
settings.update_setting_success=Configuração da organização atualizada com sucesso.
|
||||
settings.delete=Deletar Organização
|
||||
settings.delete_account=Deletar Esta Organização
|
||||
settings.delete_prompt=A operação deletará esta organização permanentemente, e <strong>NÃO PODERÁ</strong> ser desfeita!
|
||||
settings.confirm_delete_account=Confirmar Deleção
|
||||
settings.delete_org_title=Deleção da Organização
|
||||
settings.delete_org_desc=Esta organização será deletada permanentemente, você quer continuar?
|
||||
settings.hooks_desc=Adicionar Hooks da Web que serão acionados para <strong>todos os repositórios</strong> dessa organização.
|
||||
|
||||
members.public=Público
|
||||
members.public_helper=tornar privado
|
||||
members.private=Privado
|
||||
members.private_helper=torar público
|
||||
members.owner=Dono
|
||||
members.member=Membro
|
||||
members.conceal=Ocultar
|
||||
members.remove=Remover
|
||||
members.leave=Sair
|
||||
members.invite_desc=Comece digitando um nome de usuário para convidá-lo como novo membro para %s:
|
||||
members.invite_now=Convidar Agora
|
||||
|
||||
teams.join=Juntar-se
|
||||
teams.leave=Deixar
|
||||
teams.read_access=Acesso de Leitura
|
||||
teams.read_access_helper=Esta equipe poderá ver e clonar os repositórios dela.
|
||||
teams.write_access=Acesso de Escrita
|
||||
teams.write_access_helper=Esta equipa será capaz de ler os seus repositórios, bem como fazer push para eles.
|
||||
teams.admin_access=Acesso do Administrador
|
||||
teams.admin_access_helper=Esta equipe será capaz de fazer push/pull em seus repositórios, bem como adicionar-lhes outros colaboradores.
|
||||
teams.no_desc=Esta equipe não tem descrição
|
||||
teams.settings=Configurações
|
||||
teams.owners_permission_desc=Donos tem acesso total a <strong>todos repositórios</strong> e também <strong>direitos de administrador</strong> para a organização.
|
||||
teams.members=Membros da Equipe
|
||||
teams.update_settings=Atualizar Configurações
|
||||
teams.delete_team=Deletar Esta Equipe
|
||||
teams.add_team_member=Adicionar Membro da Equipe
|
||||
teams.delete_team_title=Deleção da Equipe
|
||||
teams.delete_team_desc=Este equipe será deletada, você quer continuar? Membros desta equipe poderão perder acesso a alguns repositórios.
|
||||
teams.delete_team_success=A equipe dada foi deletada com sucesso.
|
||||
teams.read_permission_desc=Essa equipe concede acesso para <strong>Leitura</strong>: membros podem ver e clonar os repositórios da equipe.
|
||||
teams.write_permission_desc=Esta equipe concede acesso para <strong>escrita</strong>: Membros podem ler e fazer push para os repositórios da equipe.
|
||||
teams.admin_permission_desc=Esta equipe concede acesso de <strong>Administrador</strong>: Membros podem ler, fazer push e adicionar outros colaboradores para os repositórios da equipe.
|
||||
teams.repositories=Repositórios da Equipe
|
||||
teams.add_team_repository=Adicionar Repositório da Equipe
|
||||
teams.remove_repo=Remover
|
||||
teams.add_nonexistent_repo=O repositório que você está tentando adicionar não existe, por favor, crie-o primeiro.
|
||||
|
||||
[admin]
|
||||
dashboard=Painel de controle
|
||||
users=Usuários
|
||||
organizations=Organizações
|
||||
repositories=Repositórios
|
||||
authentication=Autenticações
|
||||
config=Configuração
|
||||
notices=Sistema de notificações
|
||||
monitor=Monitoramento
|
||||
prev=Anterior
|
||||
next=Próximo
|
||||
|
||||
dashboard.statistic=Estatística
|
||||
dashboard.operations=Operações
|
||||
dashboard.system_status=Status do Monitor de Sistema
|
||||
dashboard.statistic_info=O banco de dados do Gogs contém <b>%d</b> usuários, <b>%d</b> organizações, <b>%d</b> chaves públicas, <b>%d</b> repositórios, <b>%d</b> observadores, <b>%d</b> estrelas, <b>%d</b> ações, <b>%d</b> acessos, <b>%d</b> questões, <b>%d</b> comentários, <b>%d</b> contas sociais, <b>%d</b> seguidores, <b>%d</b> espelhos, <b>%d</b> versões, <b>%d</b> origens de login, <b>%d</b> Hooks da Web, <b>%d</b> milestones, <b>%d</b> labels, <b>%d</b> tarefas hook, <b>%d</b> equipes, <b>%d</b> tarefas de atualização, <b>%d</b> anexos.
|
||||
dashboard.operation_name=Nome da Operação
|
||||
dashboard.operation_switch=Trocar
|
||||
dashboard.operation_run=Executar
|
||||
dashboard.clean_unbind_oauth=Limpar OAuthes não acoplados
|
||||
dashboard.clean_unbind_oauth_success=Todos OAuthes desvinculados foram excluídos com sucesso.
|
||||
dashboard.delete_inactivate_accounts=Excluir todas as contas inativas
|
||||
dashboard.delete_inactivate_accounts_success=Todas as contas inativas foram excluídas com sucesso.
|
||||
dashboard.delete_repo_archives=Excluir todos os arquivos dos repositórios
|
||||
dashboard.delete_repo_archives_success=Todos os arquivos dos repositórios foram excluídos com sucesso.
|
||||
dashboard.git_gc_repos=Fazer coleta de lixo nos repositórios
|
||||
dashboard.git_gc_repos_success=Em todos repositórios, a coleta de lixo foi realizada com sucesso.
|
||||
dashboard.resync_all_sshkeys=Reescrever o arquivo '.ssh/autorized_key' (atenção: chaves que não sejam do Gogs serão perdidas)
|
||||
dashboard.resync_all_sshkeys_success=Todas as chaves públicas foram reescritas com sucesso.
|
||||
dashboard.resync_all_update_hooks=Reescrever todos os hooks de atualização dos repositórios (necessário quando o caminho de configuração customizado é alterado)
|
||||
dashboard.resync_all_update_hooks_success=Os hooks de atualização de todos os repositórios foram reescritos com sucesso.
|
||||
|
||||
dashboard.server_uptime=Servidor Ligado
|
||||
dashboard.current_goroutine=Goroutines Atuais
|
||||
dashboard.current_memory_usage=Uso de Memória Atual
|
||||
dashboard.total_memory_allocated=Total de Memória Alocada
|
||||
dashboard.memory_obtained=Memória Obtida
|
||||
dashboard.pointer_lookup_times=Nº de Consultas a Ponteiros
|
||||
dashboard.memory_allocate_times=Nº de Alocações de Memória
|
||||
dashboard.memory_free_times=Nº de Liberações de Memória
|
||||
dashboard.current_heap_usage=Uso Atual da Heap
|
||||
dashboard.heap_memory_obtained=Memória de Heap Obtida
|
||||
dashboard.heap_memory_idle=Memória da Heap Ociosa
|
||||
dashboard.heap_memory_in_use=Memória da Heap em Uso
|
||||
dashboard.heap_memory_released=Memória da Heap Liberada
|
||||
dashboard.heap_objects=Objetos na Heap
|
||||
dashboard.bootstrap_stack_usage=Uso de Pilha Bootstrap
|
||||
dashboard.stack_memory_obtained=Memória de Pilha Obtida
|
||||
dashboard.mspan_structures_usage=Uso de Estruturas de MSpan
|
||||
dashboard.mspan_structures_obtained=Estruturas de MSpan Obtidas
|
||||
dashboard.mcache_structures_usage=Uso de Estruturas de MCache
|
||||
dashboard.mcache_structures_obtained=Estruturas de MCache Obtidas
|
||||
dashboard.profiling_bucket_hash_table_obtained=Perfil Obtido da Bucket Hash Table
|
||||
dashboard.gc_metadata_obtained=Metadados do GC Obtidos
|
||||
dashboard.other_system_allocation_obtained=Outra Alocação de Sistema Obtida
|
||||
dashboard.next_gc_recycle=Próxima Reciclagem do GC
|
||||
dashboard.last_gc_time=Desde da Última Vez do GC
|
||||
dashboard.total_gc_time=Pausa Total do GC
|
||||
dashboard.total_gc_pause=Pausa Total do GC
|
||||
dashboard.last_gc_pause=Última Pausa do GC
|
||||
dashboard.gc_times=Nº Execuções do GC
|
||||
|
||||
users.user_manage_panel=Painel de Gerenciamento do Usuário
|
||||
users.new_account=Criar Nova Conta
|
||||
users.name=Nome
|
||||
users.activated=Ativado
|
||||
users.admin=Administrador
|
||||
users.repos=Repos
|
||||
users.created=Criado
|
||||
users.edit=Editar
|
||||
users.auth_source=Fonte de Autorização
|
||||
users.local=Local
|
||||
users.auth_login_name=Nome de Autorização de Login
|
||||
users.update_profile_success=O perfil da conta foi atualizado com sucesso.
|
||||
users.edit_account=Editar Conta
|
||||
users.is_activated=Esta conta está ativada
|
||||
users.is_admin=Esta conta tem permissões de administrador
|
||||
users.allow_git_hook=Esta conta tem permissões para criar ganchos Git
|
||||
users.update_profile=Atualizar Perfil da Conta
|
||||
users.delete_account=Deletar Esta Conta
|
||||
users.still_own_repo=Sua conta ainda é proprietária do repositório, você tem que excluir ou transferi-lo primeiro.
|
||||
users.still_has_org=Sua conta ainda faz parte da organização, você deve sair ou excluí-la primeiro.
|
||||
|
||||
orgs.org_manage_panel=Painel de Gerenciamento da Organização
|
||||
orgs.name=Nome
|
||||
orgs.teams=Equipes
|
||||
orgs.members=Membros
|
||||
|
||||
repos.repo_manage_panel=Painel de Gerenciamento do Repositório
|
||||
repos.owner=Dono
|
||||
repos.name=Nome
|
||||
repos.private=Privado
|
||||
repos.watches=Observadores
|
||||
repos.stars=Estrelas
|
||||
repos.issues=Problemas
|
||||
|
||||
auths.auth_manage_panel=Painel de Gerenciamento da Autorização
|
||||
auths.new=Adicionar Nova Fonte de Autorização
|
||||
auths.name=Nome
|
||||
auths.type=Tipo
|
||||
auths.enabled=Habilitado
|
||||
auths.updated=Atualizado
|
||||
auths.auth_type=Tipo da Autorização
|
||||
auths.auth_name=Nome da Autorização
|
||||
auths.domain=Domínio
|
||||
auths.host=Host
|
||||
auths.port=Porta
|
||||
auths.base_dn=Base DN
|
||||
auths.attribute_username=Atributo nome de usuário
|
||||
auths.attribute_name=Atributo primeiro nome
|
||||
auths.attribute_surname=Atributo sobrenome
|
||||
auths.attribute_mail=Atributo e-mail
|
||||
auths.filter=Filtro de Pesquisa
|
||||
auths.ms_ad_sa=Ms Ad SA
|
||||
auths.smtp_auth=Tipo de Autorização de SMTP
|
||||
auths.smtphost=Host SMTP
|
||||
auths.smtpport=Porta SMTP
|
||||
auths.enable_tls=Habilitar Criptografia TLS
|
||||
auths.enable_auto_register=Habilitar Registro Automático
|
||||
auths.tips=Dicas
|
||||
auths.edit=Editar Configuração da Autorização
|
||||
auths.activated=Esta autenticação foi ativada
|
||||
auths.update_success=A configuração da autorização foi atualizada com sucesso.
|
||||
auths.update=Atualizar Configuração da Autorização
|
||||
auths.delete=Excluir Esta Autorização
|
||||
auths.delete_auth_title=Exclusão da Autorização
|
||||
auths.delete_auth_desc=Esta autorização será excluída, deseja continuar?
|
||||
|
||||
config.server_config=Configuração do Servidor
|
||||
config.app_name=Nome do Aplicativo
|
||||
config.app_ver=Versão do Aplicativo
|
||||
config.app_url=URL do Aplicativo
|
||||
config.domain=Domínio
|
||||
config.offline_mode=Modo Offline
|
||||
config.disable_router_log=Desabilitar o Log do Roteador
|
||||
config.run_user=Usuário de Execução
|
||||
config.run_mode=Modo de Execução
|
||||
config.repo_root_path=Caminho Raiz do Repositório
|
||||
config.static_file_root_path=Caminho Raiz para Arquivo Estático
|
||||
config.log_file_root_path=Caminho Raiz para Arquivo de Log
|
||||
config.script_type=Tipo de Script
|
||||
config.reverse_auth_user=Usuário de Autenticação Reversa
|
||||
config.db_config=Configuração do Banco de Dados
|
||||
config.db_type=Tipo
|
||||
config.db_host=Host
|
||||
config.db_name=Nome
|
||||
config.db_user=Usuário
|
||||
config.db_ssl_mode=Modo SSL
|
||||
config.db_ssl_mode_helper=(apenas para "postgres")
|
||||
config.db_path=Caminho
|
||||
config.db_path_helper=(apenas para "sqlite3")
|
||||
config.service_config=Configuração do Serviço
|
||||
config.register_email_confirm=Requerer Confirmação de E-mail
|
||||
config.disable_register=Desabilitar Registro
|
||||
config.show_registration_button=Mostrar Botão de Registo
|
||||
config.require_sign_in_view=Requerer Entrar no Gogs para Ver
|
||||
config.mail_notify=Notificação de Correio
|
||||
config.enable_cache_avatar=Habilitar Cache de Avatar
|
||||
config.active_code_lives=Ativar Code Lives
|
||||
config.reset_password_code_lives=Redefinir Senha de Code Lives
|
||||
config.webhook_config=Configuração de Hook da Web
|
||||
config.task_interval=Intervalo da Tarefa
|
||||
config.deliver_timeout=Intervalo de Entrega
|
||||
config.skip_tls_verify=Pular Verificar TLS
|
||||
config.mailer_config=Configuração de Correio
|
||||
config.mailer_enabled=Habilitado
|
||||
config.mailer_name=Nome
|
||||
config.mailer_host=Host
|
||||
config.mailer_user=Usuário
|
||||
config.oauth_config=Configuração do OAuth
|
||||
config.oauth_enabled=Habilitado
|
||||
config.cache_config=Configuração de Cache
|
||||
config.cache_adapter=Adaptador de Cache
|
||||
config.cache_interval=Intervalo de Cache
|
||||
config.cache_conn=Conexão de Cache
|
||||
config.session_config=Configuração da Sessão
|
||||
config.session_provider=Provedor da Sessão
|
||||
config.provider_config=Configuração do Provedor
|
||||
config.cookie_name=Nome do Cookie
|
||||
config.enable_set_cookie=Habilitar Uso de Cookie
|
||||
config.gc_interval_time=Tempo de Intervalo do GC
|
||||
config.session_life_time=Tempo de Vida da Sessão
|
||||
config.https_only=Apenas HTTPS
|
||||
config.cookie_life_time=Tempo de Vida do Cookie
|
||||
config.picture_config=Configuração da Imagem
|
||||
config.picture_service=Serviço de Imagens
|
||||
config.disable_gravatar=Desativar Gravatar
|
||||
config.log_config=Configuração de Log
|
||||
config.log_mode=Modo do Log
|
||||
|
||||
monitor.cron=Tarefas Cron
|
||||
monitor.name=Nome
|
||||
monitor.schedule=Cronograma
|
||||
monitor.next=Próxima Vez
|
||||
monitor.previous=Última Vez
|
||||
monitor.execute_times=Nº de Execuções
|
||||
monitor.process=Processos em Execução
|
||||
monitor.desc=Descrição
|
||||
monitor.start=Hora de Início
|
||||
monitor.execute_time=Tempo de Execução
|
||||
|
||||
notices.system_notice_list=Sistema de Notificações
|
||||
notices.type=Tipo
|
||||
notices.type_1=Repositório
|
||||
notices.desc=Descrição
|
||||
notices.op=Op.
|
||||
notices.delete_success=Aviso do sistema foi deletado com sucesso.
|
||||
|
||||
[action]
|
||||
create_repo=repositório criado <a href="%s"> %s</a>
|
||||
commit_repo=pushed para <a href="%s/src/%s">%[2]s</a> em <a href="%[1]s">%[3]s</a>
|
||||
create_issue='questão aberta <a href="%s/issues/%s">%s#%[2]s</a>'
|
||||
comment_issue='comentou sobre a questão <a href="%s/issues/%s">%s#%[2]s</a>'
|
||||
transfer_repo=repositório transferido de <code>%s</code> para <a href="%s">%s</a>
|
||||
push_tag=Foi feito push na tag <a href="%s/src/%s">%[2]s</a> para <a href="%[1]s">%[3]s</a>
|
||||
compare_2_commits=Ver comparação desses 2 commits
|
||||
|
||||
[tool]
|
||||
ago=atrás
|
||||
from_now=a partir de agora
|
||||
now=agora
|
||||
1s=1 segundo %s
|
||||
1m=1 minuto %s
|
||||
1h=1 hora %s
|
||||
1d=1 dia %s
|
||||
1w=1 semana %s
|
||||
1mon=1 mês %s
|
||||
1y=1 ano %s
|
||||
seconds=%d segundos %s
|
||||
minutes=%d minutos %s
|
||||
hours=%d horas %s
|
||||
days=%d dias %s
|
||||
weeks=%d semanas %s
|
||||
months=%d meses %s
|
||||
years=%d anos %s
|
||||
raw_seconds=segundos
|
||||
raw_minutes=minutos
|
||||
|
||||
@@ -281,13 +281,13 @@ init_readme=Создать репозиторий с файлом README.md
|
||||
create_repo=Создание репозитория
|
||||
default_branch=Ветка по умолчанию
|
||||
mirror_interval=Интервал зеркалирования (час)
|
||||
goget_meta=Meta-тег для go get
|
||||
goget_meta_helper=Репозиторий будет доступен для <span class="label label-blue label-radius">go get</span>
|
||||
|
||||
need_auth=Требуется авторизация
|
||||
migrate_type=Тип миграции
|
||||
migrate_type_helper=Этот репозиторий будет <span class="label label-blue label-radius">зеркалом</span>
|
||||
migrate_repo=Перенос репозитория
|
||||
migrate.clone_address=Скопировать адрес
|
||||
migrate.invalid_local_path=Недопустимый локальный путь. Возможно он не существует или является не папкой.
|
||||
|
||||
copy_link=Копировать
|
||||
click_to_copy=Скопировать в буфер обмена
|
||||
@@ -313,9 +313,9 @@ tags=Метки
|
||||
issues=Обсуждения
|
||||
commits=Коммиты
|
||||
releases=Релизы
|
||||
file_raw=Raw
|
||||
file_raw=Исходник
|
||||
file_history=История
|
||||
file_view_raw=View Raw
|
||||
file_view_raw=Посмотреть исходник
|
||||
|
||||
commits.commits=Коммиты
|
||||
commits.search=Поиск коммитов
|
||||
@@ -339,22 +339,22 @@ settings.update_settings=Обновить настройки
|
||||
settings.change_reponame=Имя репозитория изменено
|
||||
settings.change_reponame_desc=Имя хранилища изменено, вы хотите продолжить? Это действие повлияет на все ссылки, относящиеся к этому репозиторию.
|
||||
settings.transfer=Передать права собственности
|
||||
settings.transfer_desc=Transfer this repo to another user or to an organization where you have admin rights.
|
||||
settings.transfer_desc=Передать репозиторий другому пользователю или организации где у вас есть права администратора.
|
||||
settings.new_owner_has_same_repo=У нового владельца уже есть хранилище с таким названием.
|
||||
settings.delete=Удалить этот репозиторий
|
||||
settings.delete_desc=Как только вы удалите репозиторий — пути назад не будет. Удостоверьтесь, что вам это точно нужно.
|
||||
settings.transfer_notices=<p>- You will lose access if new owner is a individual user.</p><p>- You will remain access if new owner is an organization and you're one of the owners.</p>
|
||||
settings.transfer_notices=<p>- Вы потеряете доступ, если новый владелец является индивидуальным пользователем.</p><p>- У Вас останется доступ, если новый владелец является организацией, и вы один из её владельцев.</p>
|
||||
settings.update_settings_success=Настройка репозитория обновлена успешно.
|
||||
settings.transfer_owner=Новый владелец
|
||||
settings.make_transfer=Выполнить передачу
|
||||
settings.transfer_succeed=Repository ownership has been transferred successfully.
|
||||
settings.transfer_succeed=Владение репозиторием было успешно передано.
|
||||
settings.confirm_delete=Подтвердить удаление
|
||||
settings.add_collaborator=Добавить нового соавтора
|
||||
settings.add_collaborator_success=Был добавлен новый соавтор.
|
||||
settings.remove_collaborator_success=Соавтор был удален.
|
||||
settings.user_is_org_member=User is organization member who cannot be added as a collaborator.
|
||||
settings.user_is_org_member=Пользователь является членом организации, члены которой не могут быть добавлены в качестве соавтора.
|
||||
settings.add_webhook=Добавить Webhook
|
||||
settings.hooks_desc=Webhooks allow external services to be notified when certain events happen on Gogs. When the specified events happen, we'll send a POST request to each of the URLs you provide. Learn more in our <a target="_blank" href="%s">Webhooks Guide</a>.
|
||||
settings.hooks_desc=Webhooks позволяют внешним службам получать уведомления при возникновении определенных событий на Gogs. При возникновении указанных событий мы отправим запрос POST на каждый заданный вами URL. Узнать больше можно в нашем <a target="_blank" href="%s">Руководстве по Webhooks</a>.
|
||||
settings.githooks_desc=Git Hooks are powered by Git itself, you can edit files of supported hooks in the list below to apply custom operations.
|
||||
settings.githook_edit_desc=If hook is not active, sample content will be presented. Leave content to be blank will disable this hook.
|
||||
settings.githook_name=Название Hook'a
|
||||
@@ -399,12 +399,12 @@ release.ahead=<strong>%d</strong> commits to %s since this release
|
||||
release.source_code=Исходный код
|
||||
release.tag_name=Имя тега
|
||||
release.target=Цель
|
||||
release.tag_helper=Choose an existing tag, or create a new tag on publish.
|
||||
release.tag_helper=Выберите существующий тег, или создайте новый.
|
||||
release.release_title=Название релиза
|
||||
release.content_with_md=Содержимое с <a href="%s">Markdown</a>
|
||||
release.write=Запись
|
||||
release.preview=Предварительный просмотр
|
||||
release.content_placeholder=Write some content
|
||||
release.content_placeholder=Напишите что-нибудь
|
||||
release.loading=Загрузка...
|
||||
release.prerelease_desc=Это предварительный релиз
|
||||
release.prerelease_helper=We’ll point out that this release is identified as non-production ready.
|
||||
@@ -443,10 +443,10 @@ settings.change_orgname_desc=Organization name has been changed, do you want to
|
||||
settings.update_setting_success=Organization setting has been updated successfully.
|
||||
settings.delete=Удалить Организацию
|
||||
settings.delete_account=Удалить Эту Организацию
|
||||
settings.delete_prompt=The operation will delete this organization permanently, and <strong>CANNOT</strong> be undone!
|
||||
settings.delete_prompt=Это действие безвозвратно удалит эту организацию навсегда.
|
||||
settings.confirm_delete_account=Подтвердить удаление
|
||||
settings.delete_org_title=Удаление Организации
|
||||
settings.delete_org_desc=This organization is going to be deleted permanently, do you want to continue?
|
||||
settings.delete_org_desc=Эта организация будет удалена навсегда. Хотите всё-равно продолжить?
|
||||
settings.hooks_desc=Добавьте автоматическое обновление, который будет вызываться для <strong>всех репозиций</strong> под этой Группой.
|
||||
|
||||
members.public=Публичный
|
||||
@@ -455,7 +455,7 @@ members.private=Приватный
|
||||
members.private_helper=Сделать Публичным
|
||||
members.owner=Владелец
|
||||
members.member=Участник
|
||||
members.conceal=Conceal
|
||||
members.conceal=Скрыть
|
||||
members.remove=Удалить
|
||||
members.leave=Покинуть
|
||||
members.invite_desc=Начните вводить имя пользователя чтобы пригласить нового члена %s:
|
||||
@@ -494,7 +494,7 @@ organizations=Организации
|
||||
repositories=Репозитории
|
||||
authentication=Авторизация
|
||||
config=Настройки
|
||||
notices=System Notices
|
||||
notices=Системные уведомления
|
||||
monitor=Мониторинг
|
||||
prev=Предыдущий.
|
||||
next=Следующий
|
||||
@@ -506,15 +506,15 @@ dashboard.statistic_info=В базе данных Gogs записано <b>%d</b
|
||||
dashboard.operation_name=Operation Name
|
||||
dashboard.operation_switch=Переключить
|
||||
dashboard.operation_run=Запуск
|
||||
dashboard.clean_unbind_oauth=Clean unbound OAuthes
|
||||
dashboard.clean_unbind_oauth_success=All unbind OAuthes have been deleted successfully.
|
||||
dashboard.clean_unbind_oauth=Удалить не привязанные OAUth
|
||||
dashboard.clean_unbind_oauth_success=Не привязанные OAuth аккаунты успешно удалены.
|
||||
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.resync_all_sshkeys=Rewrite '.ssh/autorized_key' file (caution: non-Gogs keys will be lost)
|
||||
dashboard.resync_all_sshkeys=Переписать файл «.ssh/autorized_key» (осторожно: не Gogs ключи будут утеряны)
|
||||
dashboard.resync_all_sshkeys_success=All public keys have been rewritten successfully.
|
||||
dashboard.resync_all_update_hooks=Rewrite all update hook of repositories (needed when custom config path is changed)
|
||||
dashboard.resync_all_update_hooks_success=All repositories' update hook have been rewritten successfully.
|
||||
@@ -595,7 +595,10 @@ auths.domain=Домен
|
||||
auths.host=Хост
|
||||
auths.port=Порт
|
||||
auths.base_dn=Base DN
|
||||
auths.attributes=Search Attributes
|
||||
auths.attribute_username=Username attribute
|
||||
auths.attribute_name=First name attribute
|
||||
auths.attribute_surname=Surname attribute
|
||||
auths.attribute_mail=E-mail attribute
|
||||
auths.filter=Фильтр поиска
|
||||
auths.ms_ad_sa=Ms Ad SA
|
||||
auths.smtp_auth=Тип авторизации SMTP
|
||||
@@ -690,35 +693,35 @@ notices.type=Тип
|
||||
notices.type_1=Репозиторий
|
||||
notices.desc=Описание
|
||||
notices.op=Op.
|
||||
notices.delete_success=System notice has been deleted successfully.
|
||||
notices.delete_success=Системное уведомление успешно удалено.
|
||||
|
||||
[action]
|
||||
create_repo=создан репозиторий <a href="%s/%s"> %s</a>
|
||||
commit_repo=pushed to <a href="%s/%s/src/%s">%s</a> at <a href="%s/%s">%s</a>
|
||||
create_issue=`opened issue <a href="%s/issues/%s">%[1]s#%[2]s</a>`
|
||||
comment_issue=`commented on issue <a href="%s/issues/%s">%[1]s#%[2]s</a>`
|
||||
transfer_repo=transfered repository <code>%s</code> to <a href="/%s%s">%s</a>
|
||||
push_tag=pushed tag <a href="%s/%s/src/%s">%s</a> to <a href="%s/%s">%s</a>
|
||||
compare_2_commits=View comparison for these 2 commits
|
||||
create_repo=создан репозиторий <a href="%s"> %s</a>
|
||||
commit_repo=pushed to <a href="%s/src/%s">%[2]s</a> at <a href="%[1]s">%[3]s</a>
|
||||
create_issue=`opened issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
comment_issue=`commented on issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
transfer_repo=transfered repository <code>%s</code> to <a href="%s">%s</a>
|
||||
push_tag=pushed tag <a href="%s/src/%s">%[2]s</a> to <a href="%[1]s">%[3]s</a>
|
||||
compare_2_commits=Просмотреть сравнение двух коммитов
|
||||
|
||||
[tool]
|
||||
ago=ago
|
||||
from_now=from now
|
||||
now=сейчас
|
||||
1s=1 second %s
|
||||
1m=1 minute %s
|
||||
1h=1 hour %s
|
||||
1d=1 day %s
|
||||
1w=1 week %s
|
||||
1m=1 минута %s
|
||||
1h=1 час %s
|
||||
1d=1 день %s
|
||||
1w=1 неделя %s
|
||||
1mon=1 month %s
|
||||
1y=1 year %s
|
||||
1y=1 год %s
|
||||
seconds=%d секунд %s
|
||||
minutes=%d минут %s
|
||||
hours=%d часов %s
|
||||
days=%d days %s
|
||||
days=%d дней %s
|
||||
weeks=%d weeks %s
|
||||
months=%d months %s
|
||||
years=%d years %s
|
||||
raw_seconds=seconds
|
||||
raw_minutes=minutes
|
||||
raw_seconds=секунд
|
||||
raw_minutes=минут
|
||||
|
||||
|
||||
@@ -281,13 +281,13 @@ init_readme=使用 README.md 文件初始化仓库
|
||||
create_repo=创建仓库
|
||||
default_branch=默认分支
|
||||
mirror_interval=镜像同步周期(小时)
|
||||
goget_meta=Go-Get 支持
|
||||
goget_meta_helper=本仓库将可以通过 <span class="label label-blue label-radius">Go Get</span> 获取
|
||||
|
||||
need_auth=需要授权验证
|
||||
migrate_type=迁移类型
|
||||
migrate_type_helper=本仓库将是 <span class="label label-blue label-radius">镜像</span>
|
||||
migrate_repo=迁移仓库
|
||||
migrate.clone_address=克隆地址
|
||||
migrate.invalid_local_path=无效的本地路径,不存在或不是一个目录!
|
||||
|
||||
copy_link=复制链接
|
||||
click_to_copy=复制到剪切板
|
||||
@@ -595,7 +595,10 @@ auths.domain=域名
|
||||
auths.host=主机地址
|
||||
auths.port=主机端口
|
||||
auths.base_dn=Base DN
|
||||
auths.attributes=Search Attributes
|
||||
auths.attribute_username=用户名属性
|
||||
auths.attribute_name=名字属性
|
||||
auths.attribute_surname=姓氏属性
|
||||
auths.attribute_mail=邮箱属性
|
||||
auths.filter=Search Filter
|
||||
auths.ms_ad_sa=Ms Ad SA
|
||||
auths.smtp_auth=SMTP 授权类型
|
||||
@@ -693,12 +696,12 @@ notices.op=操作
|
||||
notices.delete_success=系统提示删除成功!
|
||||
|
||||
[action]
|
||||
create_repo=创建了仓库 <a href="%s/%s">%s</a>
|
||||
commit_repo=推送了 <a href="%s/%s/src/%s">%s</a> 分支的代码到 <a href="%s/%s">%s</a>
|
||||
create_issue=`创建了工单 <a href="%s/issues/%s">%[1]s#%[2]s</a>`
|
||||
comment_issue=`评论了工单 <a href="%s/issues/%s">%[1]s#%[2]s</a>`
|
||||
transfer_repo=将仓库 <code>%s</code> 转移至 <a href="/%s%s">%s</a>
|
||||
push_tag=推送了标签 <a href="%s/%s/src/%s">%s</a> 到 <a href="%s/%s">%s</a>
|
||||
create_repo=创建了仓库 <a href="%s">%s</a>
|
||||
commit_repo=推送了 <a href="%s/src/%s">%[2]s</a> 分支的代码到 <a href="%[1]s">%[3]s</a>
|
||||
create_issue=`创建了工单 <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
comment_issue=`评论了工单 <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
transfer_repo=将仓库 <code>%s</code> 转移至 <a href="%s">%s</a>
|
||||
push_tag=推送了标签 <a href="%s/src/%s">%[2]s</a> 到 <a href="%[1]s">%[3]s</a>
|
||||
compare_2_commits=查看 2 次提交的内容对比
|
||||
|
||||
[tool]
|
||||
|
||||
@@ -281,13 +281,13 @@ init_readme=使用 README.md 文件初始化倉庫
|
||||
create_repo=創建倉庫
|
||||
default_branch=默認分支
|
||||
mirror_interval=鏡像同步周期(小時)
|
||||
goget_meta=Go-Get 支持
|
||||
goget_meta_helper=本倉庫將可以通過 <span class="label label-blue label-radius">Go Get</span> 獲取
|
||||
|
||||
need_auth=需要授權驗證
|
||||
migrate_type=遷移類型
|
||||
migrate_type_helper=本倉庫將是 <span class="label label-blue label-radius">鏡像</span>
|
||||
migrate_repo=遷移倉庫
|
||||
migrate.clone_address=複製地址
|
||||
migrate.invalid_local_path=無效的本地路徑,該路徑不存在或不是一個目錄!
|
||||
|
||||
copy_link=複製連結
|
||||
click_to_copy=複製到剪切簿
|
||||
@@ -516,8 +516,8 @@ dashboard.git_gc_repos=對倉庫進行垃圾回收
|
||||
dashboard.git_gc_repos_success=所有倉庫的垃圾回收已成功完成!
|
||||
dashboard.resync_all_sshkeys=重新生成 '.ssh/autorized_key' 文件(警告:不是 Gogs 的密鑰也會被刪除)
|
||||
dashboard.resync_all_sshkeys_success=所有公鑰重新生成成功!
|
||||
dashboard.resync_all_update_hooks=Rewrite all update hook of repositories (needed when custom config path is changed)
|
||||
dashboard.resync_all_update_hooks_success=All repositories' update hook have been rewritten successfully.
|
||||
dashboard.resync_all_update_hooks=重新生成所有倉庫的 Update 鈎子(用於被修改的自定義配置文件)
|
||||
dashboard.resync_all_update_hooks_success=已成功重新生成所有倉庫的 Update 鈎子!
|
||||
|
||||
dashboard.server_uptime=服務執行時間
|
||||
dashboard.current_goroutine=當前 Goroutines 數量
|
||||
@@ -595,7 +595,10 @@ auths.domain=域名
|
||||
auths.host=主機地址
|
||||
auths.port=主機端口
|
||||
auths.base_dn=Base DN
|
||||
auths.attributes=搜尋屬性
|
||||
auths.attribute_username=用戶名屬性
|
||||
auths.attribute_name=名子屬性
|
||||
auths.attribute_surname=姓氏屬性
|
||||
auths.attribute_mail=電子郵箱屬性
|
||||
auths.filter=搜尋過濾
|
||||
auths.ms_ad_sa=Ms Ad SA
|
||||
auths.smtp_auth=SMTP 授權類型
|
||||
@@ -647,7 +650,7 @@ config.reset_password_code_lives=重置密碼連結有效期
|
||||
config.webhook_config=Web 鉤子配置
|
||||
config.task_interval=任務周期
|
||||
config.deliver_timeout=推送超時
|
||||
config.skip_tls_verify=Skip TLS Verify
|
||||
config.skip_tls_verify=忽略 TLS 驗證
|
||||
config.mailer_config=郵件配置
|
||||
config.mailer_enabled=啟用服務
|
||||
config.mailer_name=發送者名稱
|
||||
@@ -693,12 +696,12 @@ notices.op=操作
|
||||
notices.delete_success=系統提示刪除成功!
|
||||
|
||||
[action]
|
||||
create_repo=創建了倉庫 <a href="%s/%s">%s</a>
|
||||
commit_repo=推送了 <a href="%s/%s/src/%s">%s</a> 分支的代碼到 <a href="%s/%s">%s</a>
|
||||
create_issue=`創建了問題 <a href="%s/issues/%s">%[1]s#%[2]s</a>`
|
||||
comment_issue=`評論了問題 <a href="%s/issues/%s">%[1]s#%[2]s</a>`
|
||||
transfer_repo=將倉庫 <code>%s</code> 轉移至 <a href="/%s%s">%s</a>
|
||||
push_tag=推送了標籤 <a href="%s/%s/src/%s">%s</a> 到 <a href="%s/%s">%s</a>
|
||||
create_repo=創建了倉庫 <a href="%s">%s</a>
|
||||
commit_repo=推送了 <a href="%s/src/%s">%[2]s</a> 分支的代碼到 <a href="%[1]s">%[3]s</a>
|
||||
create_issue=`創建了問題 <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
comment_issue=`評論了問題 <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
transfer_repo=將倉庫 <code>%s</code> 轉移至 <a href="%s">%s</a>
|
||||
push_tag=推送了標籤 <a href="%s/src/%s">%[2]s</a> 到 <a href="%[1]s">%[3]s</a>
|
||||
compare_2_commits=查看 2 次提交的內容對比
|
||||
|
||||
[tool]
|
||||
|
||||
12
docker-compose.yml
Normal file
12
docker-compose.yml
Normal file
@@ -0,0 +1,12 @@
|
||||
web:
|
||||
build: .
|
||||
links:
|
||||
- mysql
|
||||
ports:
|
||||
- "3000:3000"
|
||||
|
||||
mysql:
|
||||
image: mysql
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=gogs
|
||||
- MYSQL_DATABASE=gogs
|
||||
@@ -4,7 +4,7 @@ FROM ubuntu:14.04
|
||||
|
||||
RUN apt-get update && apt-get install -y \
|
||||
build-essential ca-certificates curl \
|
||||
bzr git mercurial \
|
||||
bzr git mercurial openssh-client\
|
||||
--no-install-recommends
|
||||
|
||||
ENV GOLANG_VERSION 1.3
|
||||
|
||||
@@ -5,7 +5,7 @@ FROM ubuntu:14.04
|
||||
RUN DEBIAN_FRONTEND=noninteractive apt-get update && \
|
||||
apt-get install -qy \
|
||||
build-essential ca-certificates curl \
|
||||
bzr git mercurial \
|
||||
bzr git mercurial openssh-client\
|
||||
--no-install-recommends
|
||||
|
||||
ENV GOLANG_VERSION 1.3
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ ! -d "$DIRECTORY" ]; then
|
||||
if [ ! -d "$GOGS_CUSTOM_CONF_PATH" ]; then
|
||||
mkdir -p $GOGS_CUSTOM_CONF_PATH
|
||||
|
||||
echo "
|
||||
|
||||
2
gogs.go
2
gogs.go
@@ -17,7 +17,7 @@ import (
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
const APP_VER = "0.5.13.0212 Beta"
|
||||
const APP_VER = "0.6.0.0319 Beta"
|
||||
|
||||
func init() {
|
||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||
|
||||
220
models/access.go
220
models/access.go
@@ -5,76 +5,196 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-xorm/xorm"
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
)
|
||||
|
||||
type AccessType int
|
||||
type AccessMode int
|
||||
|
||||
const (
|
||||
READABLE AccessType = iota + 1
|
||||
WRITABLE
|
||||
ACCESS_MODE_NONE AccessMode = iota
|
||||
ACCESS_MODE_READ
|
||||
ACCESS_MODE_WRITE
|
||||
ACCESS_MODE_ADMIN
|
||||
ACCESS_MODE_OWNER
|
||||
)
|
||||
|
||||
// Access represents the accessibility of user to repository.
|
||||
// Access represents the highest access level of a user to the repository. The only access type
|
||||
// that is not in this table is the real owner of a repository. In case of an organization
|
||||
// repository, the members of the owners team are in this table.
|
||||
type Access struct {
|
||||
Id int64
|
||||
UserName string `xorm:"UNIQUE(s)"`
|
||||
RepoName string `xorm:"UNIQUE(s)"` // <user name>/<repo name>
|
||||
Mode AccessType `xorm:"UNIQUE(s)"`
|
||||
Created time.Time `xorm:"CREATED"`
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
UserID int64 `xorm:"UNIQUE(s)"`
|
||||
RepoID int64 `xorm:"UNIQUE(s)"`
|
||||
Mode AccessMode
|
||||
}
|
||||
|
||||
// AddAccess adds new access record.
|
||||
func AddAccess(access *Access) error {
|
||||
access.UserName = strings.ToLower(access.UserName)
|
||||
access.RepoName = strings.ToLower(access.RepoName)
|
||||
_, err := x.Insert(access)
|
||||
return err
|
||||
func accessLevel(e Engine, u *User, repo *Repository) (AccessMode, error) {
|
||||
mode := ACCESS_MODE_NONE
|
||||
if !repo.IsPrivate {
|
||||
mode = ACCESS_MODE_READ
|
||||
}
|
||||
|
||||
if u != nil {
|
||||
if u.Id == repo.OwnerId {
|
||||
return ACCESS_MODE_OWNER, nil
|
||||
}
|
||||
|
||||
a := &Access{UserID: u.Id, RepoID: repo.Id}
|
||||
if has, err := e.Get(a); !has || err != nil {
|
||||
return mode, err
|
||||
}
|
||||
return a.Mode, nil
|
||||
}
|
||||
|
||||
return mode, nil
|
||||
}
|
||||
|
||||
// UpdateAccess updates access information.
|
||||
func UpdateAccess(access *Access) error {
|
||||
access.UserName = strings.ToLower(access.UserName)
|
||||
access.RepoName = strings.ToLower(access.RepoName)
|
||||
_, err := x.Id(access.Id).Update(access)
|
||||
return err
|
||||
// AccessLevel returns the Access a user has to a repository. Will return NoneAccess if the
|
||||
// user does not have access. User can be nil!
|
||||
func AccessLevel(u *User, repo *Repository) (AccessMode, error) {
|
||||
return accessLevel(x, u, repo)
|
||||
}
|
||||
|
||||
// DeleteAccess deletes access record.
|
||||
func DeleteAccess(access *Access) error {
|
||||
_, err := x.Delete(access)
|
||||
return err
|
||||
func hasAccess(e Engine, u *User, repo *Repository, testMode AccessMode) (bool, error) {
|
||||
mode, err := accessLevel(e, u, repo)
|
||||
return testMode <= mode, err
|
||||
}
|
||||
|
||||
// UpdateAccess updates access information with session for rolling back.
|
||||
func UpdateAccessWithSession(sess *xorm.Session, access *Access) error {
|
||||
if _, err := sess.Id(access.Id).Update(access); err != nil {
|
||||
sess.Rollback()
|
||||
return err
|
||||
// HasAccess returns true if someone has the request access level. User can be nil!
|
||||
func HasAccess(u *User, repo *Repository, testMode AccessMode) (bool, error) {
|
||||
return hasAccess(x, u, repo, testMode)
|
||||
}
|
||||
|
||||
// GetAccessibleRepositories finds all repositories where a user has access to,
|
||||
// besides his own.
|
||||
func (u *User) GetAccessibleRepositories() (map[*Repository]AccessMode, error) {
|
||||
accesses := make([]*Access, 0, 10)
|
||||
if err := x.Find(&accesses, &Access{UserID: u.Id}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
repos := make(map[*Repository]AccessMode, len(accesses))
|
||||
for _, access := range accesses {
|
||||
repo, err := GetRepositoryById(access.RepoID)
|
||||
if err != nil {
|
||||
if IsErrRepoNotExist(err) {
|
||||
log.Error(4, "%v", err)
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if err = repo.GetOwner(); err != nil {
|
||||
return nil, err
|
||||
} else if repo.OwnerId == u.Id {
|
||||
continue
|
||||
}
|
||||
repos[repo] = access.Mode
|
||||
}
|
||||
|
||||
// FIXME: should we generate an ordered list here? Random looks weird.
|
||||
return repos, nil
|
||||
}
|
||||
|
||||
func maxAccessMode(modes ...AccessMode) AccessMode {
|
||||
max := ACCESS_MODE_NONE
|
||||
for _, mode := range modes {
|
||||
if mode > max {
|
||||
max = mode
|
||||
}
|
||||
}
|
||||
return max
|
||||
}
|
||||
|
||||
// FIXME: do corss-comparison so reduce deletions and additions to the minimum?
|
||||
func (repo *Repository) refreshAccesses(e Engine, accessMap map[int64]AccessMode) (err error) {
|
||||
minMode := ACCESS_MODE_READ
|
||||
if !repo.IsPrivate {
|
||||
minMode = ACCESS_MODE_WRITE
|
||||
}
|
||||
|
||||
newAccesses := make([]Access, 0, len(accessMap))
|
||||
for userID, mode := range accessMap {
|
||||
if mode < minMode {
|
||||
continue
|
||||
}
|
||||
newAccesses = append(newAccesses, Access{
|
||||
UserID: userID,
|
||||
RepoID: repo.Id,
|
||||
Mode: mode,
|
||||
})
|
||||
}
|
||||
|
||||
// Delete old accesses and insert new ones for repository.
|
||||
if _, err = e.Delete(&Access{RepoID: repo.Id}); err != nil {
|
||||
return fmt.Errorf("delete old accesses: %v", err)
|
||||
} else if _, err = e.Insert(newAccesses); err != nil {
|
||||
return fmt.Errorf("insert new accesses: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// HasAccess returns true if someone can read or write to given repository.
|
||||
// The repoName should be in format <username>/<reponame>.
|
||||
func HasAccess(uname, repoName string, mode AccessType) (bool, error) {
|
||||
if len(repoName) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
access := &Access{
|
||||
UserName: strings.ToLower(uname),
|
||||
RepoName: strings.ToLower(repoName),
|
||||
}
|
||||
has, err := x.Get(access)
|
||||
// FIXME: should be able to have read-only access.
|
||||
// Give all collaborators write access.
|
||||
func (repo *Repository) refreshCollaboratorAccesses(e Engine, accessMap map[int64]AccessMode) error {
|
||||
collaborators, err := repo.getCollaborators(e)
|
||||
if err != nil {
|
||||
return false, err
|
||||
} else if !has {
|
||||
return false, nil
|
||||
} else if mode > access.Mode {
|
||||
return false, nil
|
||||
return fmt.Errorf("getCollaborators: %v", err)
|
||||
}
|
||||
return true, nil
|
||||
for _, c := range collaborators {
|
||||
accessMap[c.Id] = ACCESS_MODE_WRITE
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// recalculateTeamAccesses recalculates new accesses for teams of an organization
|
||||
// except the team whose ID is given. It is used to assign a team ID when
|
||||
// remove repository from that team.
|
||||
func (repo *Repository) recalculateTeamAccesses(e Engine, ignTeamID int64) (err error) {
|
||||
accessMap := make(map[int64]AccessMode, 20)
|
||||
|
||||
if err = repo.refreshCollaboratorAccesses(e, accessMap); err != nil {
|
||||
return fmt.Errorf("refreshCollaboratorAccesses: %v", err)
|
||||
}
|
||||
|
||||
if err = repo.getOwner(e); err != nil {
|
||||
return err
|
||||
}
|
||||
if repo.Owner.IsOrganization() {
|
||||
if err = repo.Owner.getTeams(e); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, t := range repo.Owner.Teams {
|
||||
if t.ID == ignTeamID {
|
||||
continue
|
||||
}
|
||||
if t.IsOwnerTeam() {
|
||||
t.Authorize = ACCESS_MODE_OWNER
|
||||
}
|
||||
|
||||
if err = t.getMembers(e); err != nil {
|
||||
return fmt.Errorf("getMembers '%d': %v", t.ID, err)
|
||||
}
|
||||
for _, m := range t.Members {
|
||||
accessMap[m.Id] = maxAccessMode(accessMap[m.Id], t.Authorize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return repo.refreshAccesses(e, accessMap)
|
||||
}
|
||||
|
||||
func (repo *Repository) recalculateAccesses(e Engine) error {
|
||||
accessMap := make(map[int64]AccessMode, 20)
|
||||
if err := repo.refreshCollaboratorAccesses(e, accessMap); err != nil {
|
||||
return fmt.Errorf("refreshCollaboratorAccesses: %v", err)
|
||||
}
|
||||
return repo.refreshAccesses(e, accessMap)
|
||||
}
|
||||
|
||||
// RecalculateAccesses recalculates all accesses for repository.
|
||||
func (r *Repository) RecalculateAccesses() error {
|
||||
return r.recalculateAccesses(x)
|
||||
}
|
||||
|
||||
154
models/action.go
154
models/action.go
@@ -61,14 +61,14 @@ func init() {
|
||||
// Action represents user operation type and other information to repository.,
|
||||
// it implemented interface base.Actioner so that can be used in template render.
|
||||
type Action struct {
|
||||
Id int64
|
||||
UserId int64 // Receiver user id.
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
UserID int64 // Receiver user id.
|
||||
OpType ActionType
|
||||
ActUserId int64 // Action user id.
|
||||
ActUserID int64 // Action user id.
|
||||
ActUserName string // Action user name.
|
||||
ActEmail string
|
||||
ActAvatar string `xorm:"-"`
|
||||
RepoId int64
|
||||
RepoID int64
|
||||
RepoUserName string
|
||||
RepoName string
|
||||
RefName string
|
||||
@@ -97,8 +97,15 @@ func (a Action) GetRepoName() string {
|
||||
return a.RepoName
|
||||
}
|
||||
|
||||
func (a Action) GetRepoPath() string {
|
||||
return path.Join(a.RepoUserName, a.RepoName)
|
||||
}
|
||||
|
||||
func (a Action) GetRepoLink() string {
|
||||
return path.Join(setting.AppSubUrl, a.RepoUserName, a.RepoName)
|
||||
if len(setting.AppSubUrl) > 0 {
|
||||
return path.Join(setting.AppSubUrl, a.GetRepoPath())
|
||||
}
|
||||
return "/" + a.GetRepoPath()
|
||||
}
|
||||
|
||||
func (a Action) GetBranch() string {
|
||||
@@ -182,6 +189,17 @@ func updateIssuesCommit(userId, repoId int64, repoUserName, repoName string, com
|
||||
}
|
||||
issue.IsClosed = true
|
||||
|
||||
if err = issue.GetLabels(); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, label := range issue.Labels {
|
||||
label.NumClosedIssues++
|
||||
|
||||
if err = UpdateLabel(label); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err = UpdateIssue(issue); err != nil {
|
||||
return err
|
||||
} else if err = UpdateIssueUserPairsByStatus(issue.Id, issue.IsClosed); err != nil {
|
||||
@@ -230,6 +248,17 @@ func updateIssuesCommit(userId, repoId int64, repoUserName, repoName string, com
|
||||
}
|
||||
issue.IsClosed = false
|
||||
|
||||
if err = issue.GetLabels(); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, label := range issue.Labels {
|
||||
label.NumClosedIssues--
|
||||
|
||||
if err = UpdateLabel(label); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err = UpdateIssue(issue); err != nil {
|
||||
return err
|
||||
} else if err = UpdateIssueUserPairsByStatus(issue.Id, issue.IsClosed); err != nil {
|
||||
@@ -280,7 +309,7 @@ func CommitRepoAction(userId, repoUserId int64, userName, actEmail string,
|
||||
return errors.New("action.CommitRepoAction(GetRepositoryByName): " + err.Error())
|
||||
}
|
||||
repo.IsBare = false
|
||||
if err = UpdateRepository(repo); err != nil {
|
||||
if err = UpdateRepository(repo, false); err != nil {
|
||||
return errors.New("action.CommitRepoAction(UpdateRepository): " + err.Error())
|
||||
}
|
||||
|
||||
@@ -290,10 +319,18 @@ func CommitRepoAction(userId, repoUserId int64, userName, actEmail string,
|
||||
log.Debug("action.CommitRepoAction(updateIssuesCommit): ", err)
|
||||
}
|
||||
|
||||
if err = NotifyWatchers(&Action{ActUserId: userId, ActUserName: userName, ActEmail: actEmail,
|
||||
OpType: opType, Content: string(bs), RepoId: repoId, RepoUserName: repoUserName,
|
||||
RepoName: repoName, RefName: refName,
|
||||
IsPrivate: repo.IsPrivate}); err != nil {
|
||||
if err = NotifyWatchers(&Action{
|
||||
ActUserID: userId,
|
||||
ActUserName: userName,
|
||||
ActEmail: actEmail,
|
||||
OpType: opType,
|
||||
Content: string(bs),
|
||||
RepoID: repoId,
|
||||
RepoUserName: repoUserName,
|
||||
RepoName: repoName,
|
||||
RefName: refName,
|
||||
IsPrivate: repo.IsPrivate,
|
||||
}); err != nil {
|
||||
return errors.New("action.CommitRepoAction(NotifyWatchers): " + err.Error())
|
||||
|
||||
}
|
||||
@@ -380,78 +417,87 @@ func CommitRepoAction(userId, repoUserId int64, userName, actEmail string,
|
||||
continue
|
||||
}
|
||||
|
||||
var payload BasePayload
|
||||
switch w.HookTaskType {
|
||||
case SLACK:
|
||||
{
|
||||
s, err := GetSlackPayload(p, w.Meta)
|
||||
if err != nil {
|
||||
return errors.New("action.GetSlackPayload: " + err.Error())
|
||||
}
|
||||
CreateHookTask(&HookTask{
|
||||
Type: w.HookTaskType,
|
||||
Url: w.Url,
|
||||
BasePayload: s,
|
||||
ContentType: w.ContentType,
|
||||
IsSsl: w.IsSsl,
|
||||
})
|
||||
s, err := GetSlackPayload(p, w.Meta)
|
||||
if err != nil {
|
||||
return errors.New("action.GetSlackPayload: " + err.Error())
|
||||
}
|
||||
payload = s
|
||||
default:
|
||||
{
|
||||
p.Secret = w.Secret
|
||||
CreateHookTask(&HookTask{
|
||||
Type: w.HookTaskType,
|
||||
Url: w.Url,
|
||||
BasePayload: p,
|
||||
ContentType: w.ContentType,
|
||||
IsSsl: w.IsSsl,
|
||||
})
|
||||
}
|
||||
payload = p
|
||||
p.Secret = w.Secret
|
||||
}
|
||||
|
||||
if err = CreateHookTask(&HookTask{
|
||||
Type: w.HookTaskType,
|
||||
Url: w.Url,
|
||||
BasePayload: payload,
|
||||
ContentType: w.ContentType,
|
||||
EventType: HOOK_EVENT_PUSH,
|
||||
IsSsl: w.IsSsl,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("CreateHookTask: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewRepoAction adds new action for creating repository.
|
||||
func NewRepoAction(u *User, repo *Repository) (err error) {
|
||||
if err = NotifyWatchers(&Action{ActUserId: u.Id, ActUserName: u.Name, ActEmail: u.Email,
|
||||
OpType: CREATE_REPO, RepoId: repo.Id, RepoUserName: repo.Owner.Name, RepoName: repo.Name,
|
||||
IsPrivate: repo.IsPrivate}); err != nil {
|
||||
log.Error(4, "NotifyWatchers: %d/%s", u.Id, repo.Name)
|
||||
return err
|
||||
func newRepoAction(e Engine, u *User, repo *Repository) (err error) {
|
||||
if err = notifyWatchers(e, &Action{
|
||||
ActUserID: u.Id,
|
||||
ActUserName: u.Name,
|
||||
ActEmail: u.Email,
|
||||
OpType: CREATE_REPO,
|
||||
RepoID: repo.Id,
|
||||
RepoUserName: repo.Owner.Name,
|
||||
RepoName: repo.Name,
|
||||
IsPrivate: repo.IsPrivate,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("notify watchers '%d/%s'", u.Id, repo.Id)
|
||||
}
|
||||
|
||||
log.Trace("action.NewRepoAction: %s/%s", u.Name, repo.Name)
|
||||
return err
|
||||
}
|
||||
|
||||
// TransferRepoAction adds new action for transferring repository.
|
||||
func TransferRepoAction(u, newUser *User, repo *Repository) (err error) {
|
||||
// NewRepoAction adds new action for creating repository.
|
||||
func NewRepoAction(u *User, repo *Repository) (err error) {
|
||||
return newRepoAction(x, u, repo)
|
||||
}
|
||||
|
||||
func transferRepoAction(e Engine, actUser, oldOwner, newOwner *User, repo *Repository) (err error) {
|
||||
action := &Action{
|
||||
ActUserId: u.Id,
|
||||
ActUserName: u.Name,
|
||||
ActEmail: u.Email,
|
||||
ActUserID: actUser.Id,
|
||||
ActUserName: actUser.Name,
|
||||
ActEmail: actUser.Email,
|
||||
OpType: TRANSFER_REPO,
|
||||
RepoId: repo.Id,
|
||||
RepoUserName: newUser.Name,
|
||||
RepoID: repo.Id,
|
||||
RepoUserName: newOwner.Name,
|
||||
RepoName: repo.Name,
|
||||
IsPrivate: repo.IsPrivate,
|
||||
Content: path.Join(repo.Owner.LowerName, repo.LowerName),
|
||||
Content: path.Join(oldOwner.LowerName, repo.LowerName),
|
||||
}
|
||||
if err = NotifyWatchers(action); err != nil {
|
||||
log.Error(4, "NotifyWatchers: %d/%s", u.Id, repo.Name)
|
||||
return err
|
||||
if err = notifyWatchers(e, action); err != nil {
|
||||
return fmt.Errorf("notify watchers '%d/%s'", actUser.Id, repo.Id)
|
||||
}
|
||||
|
||||
// Remove watch for organization.
|
||||
if repo.Owner.IsOrganization() {
|
||||
if err = WatchRepo(repo.Owner.Id, repo.Id, false); err != nil {
|
||||
log.Error(4, "WatchRepo", err)
|
||||
if err = watchRepo(e, repo.Owner.Id, repo.Id, false); err != nil {
|
||||
return fmt.Errorf("watch repository: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
log.Trace("action.TransferRepoAction: %s/%s", u.Name, repo.Name)
|
||||
return err
|
||||
log.Trace("action.TransferRepoAction: %s/%s", actUser.Name, repo.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// TransferRepoAction adds new action for transferring repository.
|
||||
func TransferRepoAction(actUser, oldOwner, newOwner *User, repo *Repository) (err error) {
|
||||
return transferRepoAction(x, actUser, oldOwner, newOwner, repo)
|
||||
}
|
||||
|
||||
// GetFeeds returns action list of given user in given context.
|
||||
|
||||
84
models/error.go
Normal file
84
models/error.go
Normal file
@@ -0,0 +1,84 @@
|
||||
// Copyright 2015 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// ____ ___
|
||||
// | | \______ ___________
|
||||
// | | / ___// __ \_ __ \
|
||||
// | | /\___ \\ ___/| | \/
|
||||
// |______//____ >\___ >__|
|
||||
// \/ \/
|
||||
|
||||
type ErrUserOwnRepos struct {
|
||||
UID int64
|
||||
}
|
||||
|
||||
func IsErrUserOwnRepos(err error) bool {
|
||||
_, ok := err.(ErrUserOwnRepos)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrUserOwnRepos) Error() string {
|
||||
return fmt.Sprintf("user still has ownership of repositories: [uid: %d]", err.UID)
|
||||
}
|
||||
|
||||
type ErrUserHasOrgs struct {
|
||||
UID int64
|
||||
}
|
||||
|
||||
func IsErrUserHasOrgs(err error) bool {
|
||||
_, ok := err.(ErrUserHasOrgs)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrUserHasOrgs) Error() string {
|
||||
return fmt.Sprintf("user still has membership of organizations: [uid: %d]", err.UID)
|
||||
}
|
||||
|
||||
// ________ .__ __ .__
|
||||
// \_____ \_______ _________ ____ |__|____________ _/ |_|__| ____ ____
|
||||
// / | \_ __ \/ ___\__ \ / \| \___ /\__ \\ __\ |/ _ \ / \
|
||||
// / | \ | \/ /_/ > __ \| | \ |/ / / __ \| | | ( <_> ) | \
|
||||
// \_______ /__| \___ (____ /___| /__/_____ \(____ /__| |__|\____/|___| /
|
||||
// \/ /_____/ \/ \/ \/ \/ \/
|
||||
|
||||
type ErrLastOrgOwner struct {
|
||||
UID int64
|
||||
}
|
||||
|
||||
func IsErrLastOrgOwner(err error) bool {
|
||||
_, ok := err.(ErrLastOrgOwner)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrLastOrgOwner) Error() string {
|
||||
return fmt.Sprintf("user is the last member of owner team: [uid: %d]", err.UID)
|
||||
}
|
||||
|
||||
// __________ .__ __
|
||||
// \______ \ ____ ______ ____ _____|__|/ |_ ___________ ___.__.
|
||||
// | _// __ \\____ \ / _ \/ ___/ \ __\/ _ \_ __ < | |
|
||||
// | | \ ___/| |_> > <_> )___ \| || | ( <_> ) | \/\___ |
|
||||
// |____|_ /\___ > __/ \____/____ >__||__| \____/|__| / ____|
|
||||
// \/ \/|__| \/ \/
|
||||
|
||||
type ErrRepoNotExist struct {
|
||||
ID int64
|
||||
UID int64
|
||||
Name string
|
||||
}
|
||||
|
||||
func IsErrRepoNotExist(err error) bool {
|
||||
_, ok := err.(ErrRepoNotExist)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrRepoNotExist) Error() string {
|
||||
return fmt.Sprintf("repository does not exist [id: %d, uid: %d, name: %s]", err.ID, err.UID, err.Name)
|
||||
}
|
||||
@@ -282,30 +282,33 @@ type IssueUser struct {
|
||||
}
|
||||
|
||||
// NewIssueUserPairs adds new issue-user pairs for new issue of repository.
|
||||
func NewIssueUserPairs(rid, iid, oid, pid, aid int64, repoName string) (err error) {
|
||||
iu := &IssueUser{IssueId: iid, RepoId: rid}
|
||||
|
||||
us, err := GetCollaborators(repoName)
|
||||
func NewIssueUserPairs(repo *Repository, issueID, orgID, posterID, assigneeID int64) (err error) {
|
||||
users, err := repo.GetCollaborators()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
iu := &IssueUser{
|
||||
IssueId: issueID,
|
||||
RepoId: repo.Id,
|
||||
}
|
||||
|
||||
isNeedAddPoster := true
|
||||
for _, u := range us {
|
||||
for _, u := range users {
|
||||
iu.Uid = u.Id
|
||||
iu.IsPoster = iu.Uid == pid
|
||||
iu.IsPoster = iu.Uid == posterID
|
||||
if isNeedAddPoster && iu.IsPoster {
|
||||
isNeedAddPoster = false
|
||||
}
|
||||
iu.IsAssigned = iu.Uid == aid
|
||||
iu.IsAssigned = iu.Uid == assigneeID
|
||||
if _, err = x.Insert(iu); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if isNeedAddPoster {
|
||||
iu.Uid = pid
|
||||
iu.Uid = posterID
|
||||
iu.IsPoster = true
|
||||
iu.IsAssigned = iu.Uid == aid
|
||||
iu.IsAssigned = iu.Uid == assigneeID
|
||||
if _, err = x.Insert(iu); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -561,7 +564,7 @@ func GetLabels(repoId int64) ([]*Label, error) {
|
||||
|
||||
// UpdateLabel updates label information.
|
||||
func UpdateLabel(l *Label) error {
|
||||
_, err := x.Id(l.Id).Update(l)
|
||||
_, err := x.Id(l.Id).AllCols().Update(l)
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
101
models/login.go
101
models/login.go
@@ -169,61 +169,57 @@ func UserSignIn(uname, passwd string) (*User, error) {
|
||||
// For plain login, user must exist to reach this line.
|
||||
// Now verify password.
|
||||
if u.LoginType == PLAIN {
|
||||
newUser := &User{Passwd: passwd, Salt: u.Salt}
|
||||
newUser.EncodePasswd()
|
||||
if u.Passwd != newUser.Passwd {
|
||||
if !u.ValidtePassword(passwd) {
|
||||
return nil, ErrUserNotExist
|
||||
}
|
||||
return u, nil
|
||||
} else {
|
||||
if !has {
|
||||
var sources []LoginSource
|
||||
if err = x.UseBool().Find(&sources,
|
||||
&LoginSource{IsActived: true, AllowAutoRegister: true}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, source := range sources {
|
||||
if source.Type == LDAP {
|
||||
u, err := LoginUserLdapSource(nil, uname, passwd,
|
||||
source.Id, source.Cfg.(*LDAPConfig), true)
|
||||
if err == nil {
|
||||
return u, nil
|
||||
}
|
||||
log.Warn("Fail to login(%s) by LDAP(%s): %v", uname, source.Name, err)
|
||||
} else if source.Type == SMTP {
|
||||
u, err := LoginUserSMTPSource(nil, uname, passwd,
|
||||
source.Id, source.Cfg.(*SMTPConfig), true)
|
||||
if err == nil {
|
||||
return u, nil
|
||||
}
|
||||
log.Warn("Fail to login(%s) by SMTP(%s): %v", uname, source.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, ErrUserNotExist
|
||||
}
|
||||
|
||||
var source LoginSource
|
||||
hasSource, err := x.Id(u.LoginSource).Get(&source)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !hasSource {
|
||||
return nil, ErrLoginSourceNotExist
|
||||
} else if !source.IsActived {
|
||||
return nil, ErrLoginSourceNotActived
|
||||
}
|
||||
|
||||
switch u.LoginType {
|
||||
case LDAP:
|
||||
return LoginUserLdapSource(u, u.LoginName, passwd,
|
||||
source.Id, source.Cfg.(*LDAPConfig), false)
|
||||
case SMTP:
|
||||
return LoginUserSMTPSource(u, u.LoginName, passwd,
|
||||
source.Id, source.Cfg.(*SMTPConfig), false)
|
||||
}
|
||||
return nil, ErrUnsupportedLoginType
|
||||
}
|
||||
|
||||
if !has {
|
||||
var sources []LoginSource
|
||||
if err = x.UseBool().Find(&sources,
|
||||
&LoginSource{IsActived: true, AllowAutoRegister: true}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, source := range sources {
|
||||
if source.Type == LDAP {
|
||||
u, err := LoginUserLdapSource(nil, uname, passwd,
|
||||
source.Id, source.Cfg.(*LDAPConfig), true)
|
||||
if err == nil {
|
||||
return u, nil
|
||||
}
|
||||
log.Warn("Fail to login(%s) by LDAP(%s): %v", uname, source.Name, err)
|
||||
} else if source.Type == SMTP {
|
||||
u, err := LoginUserSMTPSource(nil, uname, passwd,
|
||||
source.Id, source.Cfg.(*SMTPConfig), true)
|
||||
if err == nil {
|
||||
return u, nil
|
||||
}
|
||||
log.Warn("Fail to login(%s) by SMTP(%s): %v", uname, source.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, ErrUserNotExist
|
||||
}
|
||||
|
||||
var source LoginSource
|
||||
hasSource, err := x.Id(u.LoginSource).Get(&source)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !hasSource {
|
||||
return nil, ErrLoginSourceNotExist
|
||||
} else if !source.IsActived {
|
||||
return nil, ErrLoginSourceNotActived
|
||||
}
|
||||
|
||||
switch u.LoginType {
|
||||
case LDAP:
|
||||
return LoginUserLdapSource(u, u.LoginName, passwd, source.Id, source.Cfg.(*LDAPConfig), false)
|
||||
case SMTP:
|
||||
return LoginUserSMTPSource(u, u.LoginName, passwd, source.Id, source.Cfg.(*SMTPConfig), false)
|
||||
}
|
||||
return nil, ErrUnsupportedLoginType
|
||||
}
|
||||
|
||||
// Query if name/passwd can login against the LDAP directory pool
|
||||
@@ -231,7 +227,7 @@ func UserSignIn(uname, passwd string) (*User, error) {
|
||||
// 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)
|
||||
name, fn, sn, mail, logged := cfg.Ldapsource.SearchEntry(name, passwd)
|
||||
if !logged {
|
||||
// User not in LDAP, do nothing
|
||||
return nil, ErrUserNotExist
|
||||
@@ -247,6 +243,7 @@ func LoginUserLdapSource(u *User, name, passwd string, sourceId int64, cfg *LDAP
|
||||
|
||||
u = &User{
|
||||
Name: name,
|
||||
FullName: fn + " " + sn,
|
||||
LoginType: LDAP,
|
||||
LoginSource: sourceId,
|
||||
LoginName: name,
|
||||
|
||||
@@ -1,12 +1,44 @@
|
||||
// Copyright 2015 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/go-xorm/xorm"
|
||||
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
type migration func(*xorm.Engine) error
|
||||
const _MIN_DB_VER = 0
|
||||
|
||||
type Migration interface {
|
||||
Description() string
|
||||
Migrate(*xorm.Engine) error
|
||||
}
|
||||
|
||||
type migration struct {
|
||||
description string
|
||||
migrate func(*xorm.Engine) error
|
||||
}
|
||||
|
||||
func NewMigration(desc string, fn func(*xorm.Engine) error) Migration {
|
||||
return &migration{desc, fn}
|
||||
}
|
||||
|
||||
func (m *migration) Description() string {
|
||||
return m.description
|
||||
}
|
||||
|
||||
func (m *migration) Migrate(x *xorm.Engine) error {
|
||||
return m.migrate(x)
|
||||
}
|
||||
|
||||
// The version table. Should have only one row with id==1
|
||||
type Version struct {
|
||||
@@ -15,30 +47,55 @@ type Version struct {
|
||||
}
|
||||
|
||||
// This is a sequence of migrations. Add new migrations to the bottom of the list.
|
||||
// If you want to "retire" a migration, replace it with "expiredMigration"
|
||||
var migrations = []migration{}
|
||||
// If you want to "retire" a migration, remove it from the top of the list and
|
||||
// update _MIN_VER_DB accordingly
|
||||
var migrations = []Migration{
|
||||
NewMigration("generate collaboration from access", accessToCollaboration), // V0 -> V1
|
||||
NewMigration("make authorize 4 if team is owners", ownerTeamUpdate), // V1 -> V2
|
||||
NewMigration("refactor access table to use id's", accessRefactor), // V2 -> V3
|
||||
NewMigration("generate team-repo from team", teamToTeamRepo), // V3 -> V4
|
||||
}
|
||||
|
||||
// Migrate database to current version
|
||||
func Migrate(x *xorm.Engine) error {
|
||||
if err := x.Sync(new(Version)); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("sync: %v", err)
|
||||
}
|
||||
|
||||
currentVersion := &Version{Id: 1}
|
||||
has, err := x.Get(currentVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("get: %v", err)
|
||||
} else if !has {
|
||||
if _, err = x.InsertOne(currentVersion); err != nil {
|
||||
// If the user table does not exist it is a fresh installation and we
|
||||
// can skip all migrations.
|
||||
needsMigration, err := x.IsTableExist("user")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if needsMigration {
|
||||
isEmpty, err := x.IsTableEmpty("user")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// If the user table is empty it is a fresh installation and we can
|
||||
// skip all migrations.
|
||||
needsMigration = !isEmpty
|
||||
}
|
||||
if !needsMigration {
|
||||
currentVersion.Version = int64(_MIN_DB_VER + len(migrations))
|
||||
}
|
||||
|
||||
if _, err = x.InsertOne(currentVersion); err != nil {
|
||||
return fmt.Errorf("insert: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
v := currentVersion.Version
|
||||
|
||||
for i, migration := range migrations[v:] {
|
||||
if err = migration(x); err != nil {
|
||||
return err
|
||||
for i, m := range migrations[v-_MIN_DB_VER:] {
|
||||
log.Info("Migration: %s", m.Description())
|
||||
if err = m.Migrate(x); err != nil {
|
||||
return fmt.Errorf("do migrate: %v", err)
|
||||
}
|
||||
currentVersion.Version = v + int64(i) + 1
|
||||
if _, err = x.Id(1).Update(currentVersion); err != nil {
|
||||
@@ -48,6 +105,270 @@ func Migrate(x *xorm.Engine) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func expiredMigration(x *xorm.Engine) error {
|
||||
return errors.New("You are migrating from a too old gogs version")
|
||||
func sessionRelease(sess *xorm.Session) {
|
||||
if !sess.IsCommitedOrRollbacked {
|
||||
sess.Rollback()
|
||||
}
|
||||
sess.Close()
|
||||
}
|
||||
|
||||
func accessToCollaboration(x *xorm.Engine) (err error) {
|
||||
type Collaboration struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
RepoID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"`
|
||||
UserID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"`
|
||||
Created time.Time
|
||||
}
|
||||
|
||||
if err = x.Sync(new(Collaboration)); err != nil {
|
||||
return fmt.Errorf("sync: %v", err)
|
||||
}
|
||||
|
||||
results, err := x.Query("SELECT u.id AS `uid`, a.repo_name AS `repo`, a.mode AS `mode`, a.created as `created` FROM `access` a JOIN `user` u ON a.user_name=u.lower_name")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
offset := strings.Split(time.Now().String(), " ")[2]
|
||||
for _, result := range results {
|
||||
mode := com.StrTo(result["mode"]).MustInt64()
|
||||
// Collaborators must have write access.
|
||||
if mode < 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
userID := com.StrTo(result["uid"]).MustInt64()
|
||||
repoRefName := string(result["repo"])
|
||||
|
||||
var created time.Time
|
||||
switch {
|
||||
case setting.UseSQLite3:
|
||||
created, _ = time.Parse(time.RFC3339, string(result["created"]))
|
||||
case setting.UseMySQL:
|
||||
created, _ = time.Parse("2006-01-02 15:04:05-0700", string(result["created"])+offset)
|
||||
case setting.UsePostgreSQL:
|
||||
created, _ = time.Parse("2006-01-02T15:04:05Z-0700", string(result["created"])+offset)
|
||||
}
|
||||
|
||||
// find owner of repository
|
||||
parts := strings.SplitN(repoRefName, "/", 2)
|
||||
ownerName := parts[0]
|
||||
repoName := parts[1]
|
||||
|
||||
results, err := sess.Query("SELECT u.id as `uid`, ou.uid as `memberid` FROM `user` u LEFT JOIN org_user ou ON ou.org_id=u.id WHERE u.lower_name=?", ownerName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(results) < 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
ownerID := com.StrTo(results[0]["uid"]).MustInt64()
|
||||
if ownerID == userID {
|
||||
continue
|
||||
}
|
||||
|
||||
// test if user is member of owning organization
|
||||
isMember := false
|
||||
for _, member := range results {
|
||||
memberID := com.StrTo(member["memberid"]).MustInt64()
|
||||
// We can skip all cases that a user is member of the owning organization
|
||||
if memberID == userID {
|
||||
isMember = true
|
||||
}
|
||||
}
|
||||
if isMember {
|
||||
continue
|
||||
}
|
||||
|
||||
results, err = sess.Query("SELECT id FROM `repository` WHERE owner_id=? AND lower_name=?", ownerID, repoName)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if len(results) < 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
collaboration := &Collaboration{
|
||||
UserID: userID,
|
||||
RepoID: com.StrTo(results[0]["id"]).MustInt64(),
|
||||
}
|
||||
has, err := sess.Get(collaboration)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if has {
|
||||
continue
|
||||
}
|
||||
|
||||
collaboration.Created = created
|
||||
if _, err = sess.InsertOne(collaboration); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
func ownerTeamUpdate(x *xorm.Engine) (err error) {
|
||||
if _, err := x.Exec("UPDATE `team` SET authorize=4 WHERE lower_name=?", "owners"); err != nil {
|
||||
return fmt.Errorf("update owner team table: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func accessRefactor(x *xorm.Engine) (err error) {
|
||||
type (
|
||||
AccessMode int
|
||||
Access struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
UserID int64 `xorm:"UNIQUE(s)"`
|
||||
RepoID int64 `xorm:"UNIQUE(s)"`
|
||||
Mode AccessMode
|
||||
}
|
||||
UserRepo struct {
|
||||
UserID int64
|
||||
RepoID int64
|
||||
}
|
||||
)
|
||||
|
||||
// We consiously don't start a session yet as we make only reads for now, no writes
|
||||
|
||||
accessMap := make(map[UserRepo]AccessMode, 50)
|
||||
|
||||
results, err := x.Query("SELECT r.id AS `repo_id`, r.is_private AS `is_private`, r.owner_id AS `owner_id`, u.type AS `owner_type` FROM `repository` r LEFT JOIN `user` u ON r.owner_id=u.id")
|
||||
if err != nil {
|
||||
return fmt.Errorf("select repositories: %v", err)
|
||||
}
|
||||
for _, repo := range results {
|
||||
repoID := com.StrTo(repo["repo_id"]).MustInt64()
|
||||
isPrivate := com.StrTo(repo["is_private"]).MustInt() > 0
|
||||
ownerID := com.StrTo(repo["owner_id"]).MustInt64()
|
||||
ownerIsOrganization := com.StrTo(repo["owner_type"]).MustInt() > 0
|
||||
|
||||
results, err := x.Query("SELECT `user_id` FROM `collaboration` WHERE repo_id=?", repoID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("select collaborators: %v", err)
|
||||
}
|
||||
for _, user := range results {
|
||||
userID := com.StrTo(user["user_id"]).MustInt64()
|
||||
accessMap[UserRepo{userID, repoID}] = 2 // WRITE ACCESS
|
||||
}
|
||||
|
||||
if !ownerIsOrganization {
|
||||
continue
|
||||
}
|
||||
|
||||
// The minimum level to add a new access record,
|
||||
// because public repository has implicit open access.
|
||||
minAccessLevel := AccessMode(0)
|
||||
if !isPrivate {
|
||||
minAccessLevel = 1
|
||||
}
|
||||
|
||||
repoString := "$" + string(repo["repo_id"]) + "|"
|
||||
|
||||
results, err = x.Query("SELECT `id`,`authorize`,`repo_ids` FROM `team` WHERE org_id=? AND authorize>? ORDER BY `authorize` ASC", ownerID, int(minAccessLevel))
|
||||
if err != nil {
|
||||
return fmt.Errorf("select teams from org: %v", err)
|
||||
}
|
||||
|
||||
for _, team := range results {
|
||||
if !strings.Contains(string(team["repo_ids"]), repoString) {
|
||||
continue
|
||||
}
|
||||
teamID := com.StrTo(team["id"]).MustInt64()
|
||||
mode := AccessMode(com.StrTo(team["authorize"]).MustInt())
|
||||
|
||||
results, err := x.Query("SELECT `uid` FROM `team_user` WHERE team_id=?", teamID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("select users from team: %v", err)
|
||||
}
|
||||
for _, user := range results {
|
||||
userID := com.StrTo(user["uid"]).MustInt64()
|
||||
accessMap[UserRepo{userID, repoID}] = mode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Drop table can't be in a session (at least not in sqlite)
|
||||
if _, err = x.Exec("DROP TABLE `access`"); err != nil {
|
||||
return fmt.Errorf("drop access table: %v", err)
|
||||
}
|
||||
|
||||
// Now we start writing so we make a session
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = sess.Sync2(new(Access)); err != nil {
|
||||
return fmt.Errorf("sync: %v", err)
|
||||
}
|
||||
|
||||
accesses := make([]*Access, 0, len(accessMap))
|
||||
for ur, mode := range accessMap {
|
||||
accesses = append(accesses, &Access{UserID: ur.UserID, RepoID: ur.RepoID, Mode: mode})
|
||||
}
|
||||
|
||||
if _, err = sess.Insert(accesses); err != nil {
|
||||
return fmt.Errorf("insert accesses: %v", err)
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
func teamToTeamRepo(x *xorm.Engine) error {
|
||||
type TeamRepo struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
OrgID int64 `xorm:"INDEX"`
|
||||
TeamID int64 `xorm:"UNIQUE(s)"`
|
||||
RepoID int64 `xorm:"UNIQUE(s)"`
|
||||
}
|
||||
|
||||
teamRepos := make([]*TeamRepo, 0, 50)
|
||||
|
||||
results, err := x.Query("SELECT `id`,`org_id`,`repo_ids` FROM `team`")
|
||||
if err != nil {
|
||||
return fmt.Errorf("select teams: %v", err)
|
||||
}
|
||||
for _, team := range results {
|
||||
orgID := com.StrTo(team["org_id"]).MustInt64()
|
||||
teamID := com.StrTo(team["id"]).MustInt64()
|
||||
|
||||
// #1032: legacy code can have duplicated IDs for same repository.
|
||||
mark := make(map[int64]bool)
|
||||
for _, idStr := range strings.Split(string(team["repo_ids"]), "|") {
|
||||
repoID := com.StrTo(strings.TrimPrefix(idStr, "$")).MustInt64()
|
||||
if repoID == 0 || mark[repoID] {
|
||||
continue
|
||||
}
|
||||
|
||||
mark[repoID] = true
|
||||
teamRepos = append(teamRepos, &TeamRepo{
|
||||
OrgID: orgID,
|
||||
TeamID: teamID,
|
||||
RepoID: repoID,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = sess.Sync2(new(TeamRepo)); err != nil {
|
||||
return fmt.Errorf("sync: %v", err)
|
||||
} else if _, err = sess.Insert(teamRepos); err != nil {
|
||||
return fmt.Errorf("insert team-repos: %v", err)
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
@@ -12,10 +12,11 @@ import (
|
||||
"strings"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/go-xorm/core"
|
||||
"github.com/go-xorm/xorm"
|
||||
_ "github.com/lib/pq"
|
||||
|
||||
// "github.com/gogits/gogs/models/migrations"
|
||||
"github.com/gogits/gogs/models/migrations"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
@@ -23,12 +24,22 @@ import (
|
||||
type Engine interface {
|
||||
Delete(interface{}) (int64, error)
|
||||
Exec(string, ...interface{}) (sql.Result, error)
|
||||
Find(interface{}, ...interface{}) error
|
||||
Get(interface{}) (bool, error)
|
||||
Insert(...interface{}) (int64, error)
|
||||
InsertOne(interface{}) (int64, error)
|
||||
Id(interface{}) *xorm.Session
|
||||
Sql(string, ...interface{}) *xorm.Session
|
||||
Where(string, ...interface{}) *xorm.Session
|
||||
}
|
||||
|
||||
func sessionRelease(sess *xorm.Session) {
|
||||
if !sess.IsCommitedOrRollbacked {
|
||||
sess.Rollback()
|
||||
}
|
||||
sess.Close()
|
||||
}
|
||||
|
||||
var (
|
||||
x *xorm.Engine
|
||||
tables []interface{}
|
||||
@@ -39,24 +50,30 @@ var (
|
||||
}
|
||||
|
||||
EnableSQLite3 bool
|
||||
UseSQLite3 bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
tables = append(tables,
|
||||
new(User), new(PublicKey), new(Follow), new(Oauth2), new(AccessToken),
|
||||
new(Repository), new(Watch), new(Star), new(Action), new(Access),
|
||||
new(User), new(PublicKey), new(Oauth2), new(AccessToken),
|
||||
new(Repository), new(Collaboration), new(Access),
|
||||
new(Watch), new(Star), new(Follow), new(Action),
|
||||
new(Issue), new(Comment), new(Attachment), new(IssueUser), new(Label), new(Milestone),
|
||||
new(Mirror), new(Release), new(LoginSource), new(Webhook),
|
||||
new(UpdateTask), new(HookTask), new(Team), new(OrgUser), new(TeamUser),
|
||||
new(UpdateTask), new(HookTask),
|
||||
new(Team), new(OrgUser), new(TeamUser), new(TeamRepo),
|
||||
new(Notice), new(EmailAddress))
|
||||
}
|
||||
|
||||
func LoadModelsConfig() {
|
||||
sec := setting.Cfg.Section("database")
|
||||
DbCfg.Type = sec.Key("DB_TYPE").String()
|
||||
if DbCfg.Type == "sqlite3" {
|
||||
UseSQLite3 = true
|
||||
switch DbCfg.Type {
|
||||
case "sqlite3":
|
||||
setting.UseSQLite3 = true
|
||||
case "mysql":
|
||||
setting.UseMySQL = true
|
||||
case "postgres":
|
||||
setting.UsePostgreSQL = true
|
||||
}
|
||||
DbCfg.Host = sec.Key("HOST").String()
|
||||
DbCfg.Name = sec.Key("NAME").String()
|
||||
@@ -72,8 +89,13 @@ func getEngine() (*xorm.Engine, error) {
|
||||
cnnstr := ""
|
||||
switch DbCfg.Type {
|
||||
case "mysql":
|
||||
cnnstr = fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8",
|
||||
DbCfg.User, DbCfg.Passwd, DbCfg.Host, DbCfg.Name)
|
||||
if DbCfg.Host[0] == '/' { // looks like a unix socket
|
||||
cnnstr = fmt.Sprintf("%s:%s@unix(%s)/%s?charset=utf8",
|
||||
DbCfg.User, DbCfg.Passwd, DbCfg.Host, DbCfg.Name)
|
||||
} else {
|
||||
cnnstr = fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8",
|
||||
DbCfg.User, DbCfg.Passwd, DbCfg.Host, DbCfg.Name)
|
||||
}
|
||||
case "postgres":
|
||||
var host, port = "127.0.0.1", "5432"
|
||||
fields := strings.Split(DbCfg.Host, ":")
|
||||
@@ -103,6 +125,7 @@ func NewTestEngine(x *xorm.Engine) (err error) {
|
||||
return fmt.Errorf("connect to database: %v", err)
|
||||
}
|
||||
|
||||
x.SetMapper(core.GonicMapper{})
|
||||
return x.Sync(tables...)
|
||||
}
|
||||
|
||||
@@ -112,6 +135,8 @@ func SetEngine() (err error) {
|
||||
return fmt.Errorf("connect to database: %v", err)
|
||||
}
|
||||
|
||||
x.SetMapper(core.GonicMapper{})
|
||||
|
||||
// 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")
|
||||
@@ -121,7 +146,7 @@ func SetEngine() (err error) {
|
||||
if err != nil {
|
||||
return fmt.Errorf("models.init(fail to create xorm.log): %v", err)
|
||||
}
|
||||
x.Logger = xorm.NewSimpleLogger(f)
|
||||
x.SetLogger(xorm.NewSimpleLogger(f))
|
||||
|
||||
x.ShowSQL = true
|
||||
x.ShowInfo = true
|
||||
@@ -136,13 +161,14 @@ func NewEngine() (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
// if err = migrations.Migrate(x); err != nil {
|
||||
// return err
|
||||
// }
|
||||
if err = migrations.Migrate(x); err != nil {
|
||||
return fmt.Errorf("migrate: %v", err)
|
||||
}
|
||||
|
||||
if err = x.StoreEngine("InnoDB").Sync2(tables...); err != nil {
|
||||
return fmt.Errorf("sync database struct error: %v\n", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
686
models/org.go
686
models/org.go
File diff suppressed because it is too large
Load Diff
@@ -130,7 +130,6 @@ func extractTypeFromBase64Key(key string) (string, error) {
|
||||
|
||||
// Parse any key string in openssh or ssh2 format to clean openssh string (rfc4253)
|
||||
func ParseKeyString(content string) (string, error) {
|
||||
|
||||
// Transform all legal line endings to a single "\n"
|
||||
s := strings.Replace(strings.Replace(strings.TrimSpace(content), "\r\n", "\n", -1), "\r", "\n", -1)
|
||||
|
||||
@@ -255,15 +254,16 @@ func saveAuthorizedKeyFile(keys ...*PublicKey) error {
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
finfo, err := f.Stat()
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// FIXME: following command does not support in Windows.
|
||||
if !setting.IsWindows {
|
||||
if finfo.Mode().Perm() > 0600 {
|
||||
log.Error(4, "authorized_keys file has unusual permission flags: %s - setting to -rw-------", finfo.Mode().Perm().String())
|
||||
// .ssh directory should have mode 700, and authorized_keys file should have mode 600.
|
||||
if fi.Mode().Perm() > 0600 {
|
||||
log.Error(4, "authorized_keys file has unusual permission flags: %s - setting to -rw-------", fi.Mode().Perm().String())
|
||||
if err = f.Chmod(0600); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -434,7 +434,7 @@ func RewriteAllPublicKeys() error {
|
||||
defer sshOpLocker.Unlock()
|
||||
|
||||
tmpPath := filepath.Join(SSHPath, "authorized_keys.tmp")
|
||||
f, err := os.Create(tmpPath)
|
||||
f, err := os.OpenFile(tmpPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
951
models/repo.go
951
models/repo.go
File diff suppressed because it is too large
Load Diff
179
models/user.go
179
models/user.go
@@ -36,8 +36,6 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
ErrUserOwnRepos = errors.New("User still have ownership of repositories")
|
||||
ErrUserHasOrgs = errors.New("User still have membership of organization")
|
||||
ErrUserAlreadyExist = errors.New("User already exist")
|
||||
ErrUserNotExist = errors.New("User does not exist")
|
||||
ErrUserNotKeyOwner = errors.New("User does not the owner of public key")
|
||||
@@ -124,7 +122,7 @@ func (u *User) AvatarLink() string {
|
||||
switch {
|
||||
case u.UseCustomAvatar:
|
||||
return setting.AppSubUrl + "/avatars/" + com.ToStr(u.Id)
|
||||
case setting.DisableGravatar:
|
||||
case setting.DisableGravatar, setting.OfflineMode:
|
||||
return setting.AppSubUrl + "/img/avatar_default.jpg"
|
||||
case setting.Service.EnableCacheAvatar:
|
||||
return setting.AppSubUrl + "/avatar/" + u.Avatar
|
||||
@@ -231,7 +229,7 @@ func (u *User) GetOrganizations() error {
|
||||
|
||||
u.Orgs = make([]*User, len(ous))
|
||||
for i, ou := range ous {
|
||||
u.Orgs[i], err = GetUserById(ou.OrgId)
|
||||
u.Orgs[i], err = GetUserById(ou.OrgID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -249,11 +247,13 @@ func (u *User) GetFullNameFallback() string {
|
||||
|
||||
// IsUserExist checks if given user name exist,
|
||||
// the user name should be noncased unique.
|
||||
func IsUserExist(name string) (bool, error) {
|
||||
// If uid is presented, then check will rule out that one,
|
||||
// it is used when update a user name in settings page.
|
||||
func IsUserExist(uid int64, name string) (bool, error) {
|
||||
if len(name) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
return x.Get(&User{LowerName: strings.ToLower(name)})
|
||||
return x.Where("id!=?", uid).Get(&User{LowerName: strings.ToLower(name)})
|
||||
}
|
||||
|
||||
// IsEmailUsed returns true if the e-mail has been used.
|
||||
@@ -278,7 +278,7 @@ func CreateUser(u *User) error {
|
||||
return ErrUserNameIllegal
|
||||
}
|
||||
|
||||
isExist, err := IsUserExist(u.Name)
|
||||
isExist, err := IsUserExist(0, u.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if isExist {
|
||||
@@ -396,64 +396,12 @@ func ChangeUserName(u *User, newUserName string) (err error) {
|
||||
return ErrUserNameIllegal
|
||||
}
|
||||
|
||||
newUserName = strings.ToLower(newUserName)
|
||||
|
||||
// Update accesses of user.
|
||||
accesses := make([]Access, 0, 10)
|
||||
if err = x.Find(&accesses, &Access{UserName: u.LowerName}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range accesses {
|
||||
accesses[i].UserName = newUserName
|
||||
if strings.HasPrefix(accesses[i].RepoName, u.LowerName+"/") {
|
||||
accesses[i].RepoName = strings.Replace(accesses[i].RepoName, u.LowerName, newUserName, 1)
|
||||
}
|
||||
if err = UpdateAccessWithSession(sess, &accesses[i]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
repos, err := GetRepositories(u.Id, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for i := range repos {
|
||||
accesses = make([]Access, 0, 10)
|
||||
// Update accesses of user repository.
|
||||
if err = x.Find(&accesses, &Access{RepoName: u.LowerName + "/" + repos[i].LowerName}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for j := range accesses {
|
||||
// if the access is not the user's access (already updated above)
|
||||
if accesses[j].UserName != u.LowerName {
|
||||
accesses[j].RepoName = newUserName + "/" + repos[i].LowerName
|
||||
if err = UpdateAccessWithSession(sess, &accesses[j]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Change user directory name.
|
||||
if err = os.Rename(UserPath(u.LowerName), UserPath(newUserName)); err != nil {
|
||||
sess.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
return os.Rename(UserPath(u.LowerName), UserPath(newUserName))
|
||||
}
|
||||
|
||||
// UpdateUser updates user's information.
|
||||
func UpdateUser(u *User) error {
|
||||
has, err := x.Where("id!=?", u.Id).And("type=?", INDIVIDUAL).And("email=?", u.Email).Get(new(User))
|
||||
has, err := x.Where("id!=?", u.Id).And("type=?", u.Type).And("email=?", u.Email).Get(new(User))
|
||||
if err != nil {
|
||||
return err
|
||||
} else if has {
|
||||
@@ -482,55 +430,75 @@ func UpdateUser(u *User) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteBeans deletes all given beans, beans should contain delete conditions.
|
||||
func DeleteBeans(e Engine, beans ...interface{}) (err error) {
|
||||
for i := range beans {
|
||||
if _, err = e.Delete(beans[i]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FIXME: need some kind of mechanism to record failure. HINT: system notice
|
||||
// DeleteUser completely and permanently deletes everything of user.
|
||||
func DeleteUser(u *User) error {
|
||||
// Check ownership of repository.
|
||||
count, err := GetRepositoryCount(u)
|
||||
if err != nil {
|
||||
return errors.New("GetRepositoryCount: " + err.Error())
|
||||
return fmt.Errorf("GetRepositoryCount: %v", err)
|
||||
} else if count > 0 {
|
||||
return ErrUserOwnRepos
|
||||
return ErrUserOwnRepos{UID: u.Id}
|
||||
}
|
||||
|
||||
// Check membership of organization.
|
||||
count, err = u.GetOrganizationCount()
|
||||
if err != nil {
|
||||
return errors.New("GetOrganizationCount: " + err.Error())
|
||||
return fmt.Errorf("GetOrganizationCount: %v", err)
|
||||
} else if count > 0 {
|
||||
return ErrUserHasOrgs
|
||||
return ErrUserHasOrgs{UID: u.Id}
|
||||
}
|
||||
|
||||
// Get watches before session.
|
||||
watches := make([]*Watch, 0, 10)
|
||||
if err = x.Where("user_id=?", u.Id).Find(&watches); err != nil {
|
||||
return fmt.Errorf("get all watches: %v", err)
|
||||
}
|
||||
repoIDs := make([]int64, 0, len(watches))
|
||||
for i := range watches {
|
||||
repoIDs = append(repoIDs, watches[i].RepoID)
|
||||
}
|
||||
|
||||
// FIXME: check issues, other repos' commits
|
||||
// FIXME: roll backable in some point.
|
||||
|
||||
// Delete all followers.
|
||||
if _, err = x.Delete(&Follow{FollowId: u.Id}); err != nil {
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
// Delete oauth2.
|
||||
if _, err = x.Delete(&Oauth2{Uid: u.Id}); err != nil {
|
||||
|
||||
if err = DeleteBeans(sess,
|
||||
&Follow{FollowID: u.Id},
|
||||
&Oauth2{Uid: u.Id},
|
||||
&Action{UserID: u.Id},
|
||||
&Access{UserID: u.Id},
|
||||
&Collaboration{UserID: u.Id},
|
||||
&EmailAddress{Uid: u.Id},
|
||||
&Watch{UserID: u.Id},
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
// Delete all feeds.
|
||||
if _, err = x.Delete(&Action{UserId: u.Id}); err != nil {
|
||||
return err
|
||||
}
|
||||
// Delete all watches.
|
||||
if _, err = x.Delete(&Watch{UserId: u.Id}); err != nil {
|
||||
return err
|
||||
}
|
||||
// Delete all accesses.
|
||||
if _, err = x.Delete(&Access{UserName: u.LowerName}); err != nil {
|
||||
return err
|
||||
}
|
||||
// Delete all alternative email addresses
|
||||
if _, err = x.Delete(&EmailAddress{Uid: u.Id}); err != nil {
|
||||
return err
|
||||
|
||||
// Decrease all watch numbers.
|
||||
for i := range repoIDs {
|
||||
if _, err = sess.Exec("UPDATE `repository` SET num_watches=num_watches-1 WHERE id=?", repoIDs[i]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Delete all SSH keys.
|
||||
keys := make([]*PublicKey, 0, 10)
|
||||
if err = x.Find(&keys, &PublicKey{OwnerId: u.Id}); err != nil {
|
||||
if err = sess.Find(&keys, &PublicKey{OwnerId: u.Id}); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, key := range keys {
|
||||
@@ -539,13 +507,16 @@ func DeleteUser(u *User) error {
|
||||
}
|
||||
}
|
||||
|
||||
if _, err = sess.Delete(u); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete user directory.
|
||||
if err = os.RemoveAll(UserPath(u.Name)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = x.Delete(u)
|
||||
return err
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
// DeleteInactivateUsers deletes all inactivate users and email addresses.
|
||||
@@ -564,8 +535,7 @@ func UserPath(userName string) string {
|
||||
|
||||
func GetUserByKeyId(keyId int64) (*User, error) {
|
||||
user := new(User)
|
||||
rawSql := "SELECT a.* FROM `user` AS a, public_key AS b WHERE a.id = b.owner_id AND b.id=?"
|
||||
has, err := x.Sql(rawSql, keyId).Get(user)
|
||||
has, err := x.Sql("SELECT a.* FROM `user` AS a, public_key AS b WHERE a.id = b.owner_id AND b.id=?", keyId).Get(user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !has {
|
||||
@@ -574,10 +544,9 @@ func GetUserByKeyId(keyId int64) (*User, error) {
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// GetUserById returns the user object by given ID if exists.
|
||||
func GetUserById(id int64) (*User, error) {
|
||||
func getUserById(e Engine, id int64) (*User, error) {
|
||||
u := new(User)
|
||||
has, err := x.Id(id).Get(u)
|
||||
has, err := e.Id(id).Get(u)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !has {
|
||||
@@ -586,6 +555,11 @@ func GetUserById(id int64) (*User, error) {
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// GetUserById returns the user object by given ID if exists.
|
||||
func GetUserById(id int64) (*User, error) {
|
||||
return getUserById(x, id)
|
||||
}
|
||||
|
||||
// GetUserByName returns user by given name.
|
||||
func GetUserByName(name string) (*User, error) {
|
||||
if len(name) == 0 {
|
||||
@@ -627,7 +601,7 @@ func GetUserIdsByNames(names []string) []int64 {
|
||||
return ids
|
||||
}
|
||||
|
||||
// Get all email addresses
|
||||
// GetEmailAddresses returns all e-mail addresses belongs to given user.
|
||||
func GetEmailAddresses(uid int64) ([]*EmailAddress, error) {
|
||||
emails := make([]*EmailAddress, 0, 5)
|
||||
err := x.Where("uid=?", uid).Find(&emails)
|
||||
@@ -641,7 +615,6 @@ func GetEmailAddresses(uid int64) ([]*EmailAddress, error) {
|
||||
}
|
||||
|
||||
isPrimaryFound := false
|
||||
|
||||
for _, email := range emails {
|
||||
if email.Email == u.Email {
|
||||
isPrimaryFound = true
|
||||
@@ -654,7 +627,11 @@ func GetEmailAddresses(uid int64) ([]*EmailAddress, error) {
|
||||
// We alway want the primary email address displayed, even if it's not in
|
||||
// the emailaddress table (yet)
|
||||
if !isPrimaryFound {
|
||||
emails = append(emails, &EmailAddress{Email: u.Email, IsActivated: true, IsPrimary: true})
|
||||
emails = append(emails, &EmailAddress{
|
||||
Email: u.Email,
|
||||
IsActivated: true,
|
||||
IsPrimary: true,
|
||||
})
|
||||
}
|
||||
return emails, nil
|
||||
}
|
||||
@@ -821,8 +798,8 @@ func SearchUserByName(opt SearchOption) (us []*User, err error) {
|
||||
// Follow is connection request for receiving user notification.
|
||||
type Follow struct {
|
||||
Id int64
|
||||
UserId int64 `xorm:"unique(follow)"`
|
||||
FollowId int64 `xorm:"unique(follow)"`
|
||||
UserID int64 `xorm:"unique(follow)"`
|
||||
FollowID int64 `xorm:"unique(follow)"`
|
||||
}
|
||||
|
||||
// FollowUser marks someone be another's follower.
|
||||
@@ -831,7 +808,7 @@ func FollowUser(userId int64, followId int64) (err error) {
|
||||
defer sess.Close()
|
||||
sess.Begin()
|
||||
|
||||
if _, err = sess.Insert(&Follow{UserId: userId, FollowId: followId}); err != nil {
|
||||
if _, err = sess.Insert(&Follow{UserID: userId, FollowID: followId}); err != nil {
|
||||
sess.Rollback()
|
||||
return err
|
||||
}
|
||||
@@ -856,7 +833,7 @@ func UnFollowUser(userId int64, unFollowId int64) (err error) {
|
||||
defer session.Close()
|
||||
session.Begin()
|
||||
|
||||
if _, err = session.Delete(&Follow{UserId: userId, FollowId: unFollowId}); err != nil {
|
||||
if _, err = session.Delete(&Follow{UserID: userId, FollowID: unFollowId}); err != nil {
|
||||
session.Rollback()
|
||||
return err
|
||||
}
|
||||
@@ -904,7 +881,7 @@ func UpdateMentions(userNames []string, issueId int64) error {
|
||||
}
|
||||
|
||||
for _, orgUser := range orgUsers {
|
||||
tempIds = append(tempIds, orgUser.Id)
|
||||
tempIds = append(tempIds, orgUser.ID)
|
||||
}
|
||||
|
||||
ids = append(ids, tempIds...)
|
||||
|
||||
@@ -205,7 +205,7 @@ func IsValidHookTaskType(name string) bool {
|
||||
type HookEventType string
|
||||
|
||||
const (
|
||||
PUSH HookEventType = "push"
|
||||
HOOK_EVENT_PUSH HookEventType = "push"
|
||||
)
|
||||
|
||||
// FIXME: just use go-gogs-client structs maybe?
|
||||
|
||||
@@ -11,15 +11,15 @@ import (
|
||||
)
|
||||
|
||||
type AdminEditUserForm struct {
|
||||
Email string `form:"email" binding:"Required;Email;MaxSize(50)"`
|
||||
Passwd string `form:"password"`
|
||||
Website string `form:"website" binding:"MaxSize(50)"`
|
||||
Location string `form:"location" binding:"MaxSize(50)"`
|
||||
Avatar string `form:"avatar" binding:"Required;Email;MaxSize(50)"`
|
||||
Active bool `form:"active"`
|
||||
Admin bool `form:"admin"`
|
||||
AllowGitHook bool `form:"allow_git_hook"`
|
||||
LoginType int `form:"login_type"`
|
||||
Email string `binding:"Required;Email;MaxSize(50)"`
|
||||
Password string `binding:"OmitEmpty;MinSize(6);MaxSize(255)"`
|
||||
Website string `binding:"MaxSize(50)"`
|
||||
Location string `binding:"MaxSize(50)"`
|
||||
Avatar string `binding:"Required;Email;MaxSize(50)"`
|
||||
Active bool
|
||||
Admin bool
|
||||
AllowGitHook bool
|
||||
LoginType int
|
||||
}
|
||||
|
||||
func (f *AdminEditUserForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
|
||||
@@ -108,17 +108,16 @@ func SignedInUser(req *http.Request, sess session.Store) (*models.User, bool) {
|
||||
auths := strings.Fields(baHead)
|
||||
if len(auths) == 2 && auths[0] == "Basic" {
|
||||
uname, passwd, _ := base.BasicAuthDecode(auths[1])
|
||||
u, err := models.GetUserByName(uname)
|
||||
|
||||
u, err := models.UserSignIn(uname, passwd)
|
||||
if err != nil {
|
||||
if err != models.ErrUserNotExist {
|
||||
log.Error(4, "GetUserByName: %v", err)
|
||||
log.Error(4, "UserSignIn: %v", err)
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
if u.ValidtePassword(passwd) {
|
||||
return u, true
|
||||
}
|
||||
return u, true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
|
||||
@@ -18,7 +18,10 @@ type AuthenticationForm struct {
|
||||
Port int `form:"port"`
|
||||
UseSSL bool `form:"usessl"`
|
||||
BaseDN string `form:"base_dn"`
|
||||
Attributes string `form:"attributes"`
|
||||
AttributeUsername string `form:"attribute_username"`
|
||||
AttributeName string `form:"attribute_name"`
|
||||
AttributeSurname string `form:"attribute_surname"`
|
||||
AttributeMail string `form:"attribute_mail"`
|
||||
Filter string `form:"filter"`
|
||||
MsAdSA string `form:"ms_ad_sa"`
|
||||
IsActived bool `form:"is_actived"`
|
||||
|
||||
@@ -15,15 +15,18 @@ import (
|
||||
|
||||
// Basic LDAP authentication service
|
||||
type Ldapsource struct {
|
||||
Name string // canonical name (ie. corporate.ad)
|
||||
Host string // LDAP host
|
||||
Port int // port number
|
||||
UseSSL bool // Use SSL
|
||||
BaseDN string // Base DN
|
||||
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
|
||||
Name string // canonical name (ie. corporate.ad)
|
||||
Host string // LDAP host
|
||||
Port int // port number
|
||||
UseSSL bool // Use SSL
|
||||
BaseDN string // Base DN
|
||||
AttributeUsername string // Username attribute
|
||||
AttributeName string // First name attribute
|
||||
AttributeSurname string // Surname attribute
|
||||
AttributeMail string // E-mail attribute
|
||||
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
|
||||
}
|
||||
|
||||
//Global LDAP directory pool
|
||||
@@ -32,18 +35,18 @@ var (
|
||||
)
|
||||
|
||||
// Add a new source (LDAP directory) to the global pool
|
||||
func AddSource(name string, host string, port int, usessl bool, basedn string, attributes string, filter string, msadsaformat string) {
|
||||
ldaphost := Ldapsource{name, host, port, usessl, basedn, attributes, filter, msadsaformat, true}
|
||||
func AddSource(name string, host string, port int, usessl bool, basedn string, attribcn string, attribname string, attribsn string, attribmail string, filter string, msadsaformat string) {
|
||||
ldaphost := Ldapsource{name, host, port, usessl, basedn, attribcn, attribname, attribsn, attribmail, filter, msadsaformat, true}
|
||||
Authensource = append(Authensource, ldaphost)
|
||||
}
|
||||
|
||||
//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) {
|
||||
func LoginUser(name, passwd string) (cn, fn, sn, mail string, r bool) {
|
||||
r = false
|
||||
for _, ls := range Authensource {
|
||||
a, r = ls.SearchEntry(name, passwd)
|
||||
cn, fn, sn, mail, r = ls.SearchEntry(name, passwd)
|
||||
if r {
|
||||
return
|
||||
}
|
||||
@@ -52,12 +55,12 @@ func LoginUser(name, passwd string) (a string, r bool) {
|
||||
}
|
||||
|
||||
// searchEntry : search an LDAP source if an entry (name, passwd) is valide and in the specific filter
|
||||
func (ls Ldapsource) SearchEntry(name, passwd string) (string, bool) {
|
||||
func (ls Ldapsource) SearchEntry(name, passwd string) (string, string, string, string, bool) {
|
||||
l, err := ldapDial(ls)
|
||||
if err != nil {
|
||||
log.Error(4, "LDAP Connect error, %s:%v", ls.Host, err)
|
||||
ls.Enabled = false
|
||||
return "", false
|
||||
return "", "", "", "", false
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
@@ -65,26 +68,29 @@ func (ls Ldapsource) SearchEntry(name, passwd string) (string, bool) {
|
||||
err = l.Bind(nx, passwd)
|
||||
if err != nil {
|
||||
log.Debug("LDAP Authan failed for %s, reason: %s", nx, err.Error())
|
||||
return "", false
|
||||
return "", "", "", "", false
|
||||
}
|
||||
|
||||
search := ldap.NewSearchRequest(
|
||||
ls.BaseDN,
|
||||
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
||||
fmt.Sprintf(ls.Filter, name),
|
||||
[]string{ls.Attributes},
|
||||
[]string{ls.AttributeUsername, ls.AttributeName, ls.AttributeSurname, ls.AttributeMail},
|
||||
nil)
|
||||
sr, err := l.Search(search)
|
||||
if err != nil {
|
||||
log.Debug("LDAP Authen OK but not in filter %s", name)
|
||||
return "", false
|
||||
return "", "", "", "", false
|
||||
}
|
||||
log.Debug("LDAP Authen OK: %s", name)
|
||||
if len(sr.Entries) > 0 {
|
||||
r := sr.Entries[0].GetAttributeValue(ls.Attributes)
|
||||
return r, true
|
||||
cn := sr.Entries[0].GetAttributeValue(ls.AttributeUsername)
|
||||
name := sr.Entries[0].GetAttributeValue(ls.AttributeName)
|
||||
sn := sr.Entries[0].GetAttributeValue(ls.AttributeSurname)
|
||||
mail := sr.Entries[0].GetAttributeValue(ls.AttributeMail)
|
||||
return cn, name, sn, mail, true
|
||||
}
|
||||
return "", true
|
||||
return "", "", "", "", true
|
||||
}
|
||||
|
||||
func ldapDial(ls Ldapsource) (*ldap.Conn, error) {
|
||||
|
||||
@@ -31,14 +31,14 @@ func (f *CreateRepoForm) Validate(ctx *macaron.Context, errs binding.Errors) bin
|
||||
}
|
||||
|
||||
type MigrateRepoForm struct {
|
||||
HttpsUrl string `form:"url" binding:"Required;Url"`
|
||||
AuthUserName string `form:"auth_username"`
|
||||
AuthPasswd string `form:"auth_password"`
|
||||
Uid int64 `form:"uid" binding:"Required"`
|
||||
RepoName string `form:"repo_name" binding:"Required;AlphaDashDot;MaxSize(100)"`
|
||||
Mirror bool `form:"mirror"`
|
||||
Private bool `form:"private"`
|
||||
Description string `form:"desc" binding:"MaxSize(255)"`
|
||||
CloneAddr string `binding:"Required"`
|
||||
AuthUsername string
|
||||
AuthPassword string
|
||||
Uid int64 `binding:"Required"`
|
||||
RepoName string `binding:"Required;AlphaDashDot;MaxSize(100)"`
|
||||
Mirror bool
|
||||
Private bool
|
||||
Description string `binding:"MaxSize(255)"`
|
||||
}
|
||||
|
||||
func (f *MigrateRepoForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
@@ -52,7 +52,6 @@ type RepoSettingForm struct {
|
||||
Branch string `form:"branch"`
|
||||
Interval int `form:"interval"`
|
||||
Private bool `form:"private"`
|
||||
GoGet bool `form:"goget"`
|
||||
}
|
||||
|
||||
func (f *RepoSettingForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
|
||||
@@ -99,7 +99,7 @@ func (f *UploadAvatarForm) Validate(ctx *macaron.Context, errs binding.Errors) b
|
||||
}
|
||||
|
||||
type AddEmailForm struct {
|
||||
Email string `form:"email" binding:"Required;Email;MaxSize(50)"`
|
||||
Email string `binding:"Required;Email;MaxSize(50)"`
|
||||
}
|
||||
|
||||
func (f *AddEmailForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
|
||||
@@ -41,6 +41,10 @@ func List(l *list.List) chan interface{} {
|
||||
return c
|
||||
}
|
||||
|
||||
func Sha1(str string) string {
|
||||
return EncodeSha1(str)
|
||||
}
|
||||
|
||||
func ShortSha(sha1 string) string {
|
||||
if len(sha1) == 40 {
|
||||
return sha1[:10]
|
||||
@@ -126,8 +130,13 @@ var TemplateFuncs template.FuncMap = map[string]interface{}{
|
||||
return a + b
|
||||
},
|
||||
"ActionIcon": ActionIcon,
|
||||
"DateFormat": DateFormat,
|
||||
"List": List,
|
||||
"DateFmtLong": func(t time.Time) string {
|
||||
return t.Format(time.RFC1123Z)
|
||||
},
|
||||
"DateFmtShort": func(t time.Time) string {
|
||||
return t.Format("Jan 02, 2006")
|
||||
},
|
||||
"List": List,
|
||||
"Mail2Domain": func(mail string) string {
|
||||
if !strings.Contains(mail, "@") {
|
||||
return "try.gogs.io"
|
||||
@@ -155,6 +164,7 @@ var TemplateFuncs template.FuncMap = map[string]interface{}{
|
||||
},
|
||||
"DiffTypeToStr": DiffTypeToStr,
|
||||
"DiffLineTypeToStr": DiffLineTypeToStr,
|
||||
"Sha1": Sha1,
|
||||
"ShortSha": ShortSha,
|
||||
"Md5": EncodeMd5,
|
||||
"ActionContent2Commits": ActionContent2Commits,
|
||||
|
||||
@@ -126,7 +126,7 @@ func VerifyTimeLimitCode(data string, minutes int, code string) bool {
|
||||
retCode := CreateTimeLimitCode(data, minutes, start)
|
||||
if retCode == code && minutes > 0 {
|
||||
// check time is expired or not
|
||||
before, _ := DateParse(start, "YmdHi")
|
||||
before, _ := time.ParseInLocation("200601021504", start, time.Local)
|
||||
now := time.Now()
|
||||
if before.Add(time.Minute*time.Duration(minutes)).Unix() > now.Unix() {
|
||||
return true
|
||||
@@ -141,7 +141,7 @@ const TimeLimitCodeLength = 12 + 6 + 40
|
||||
// create a time limit code
|
||||
// code format: 12 length date time string + 6 minutes string + 40 sha1 encoded string
|
||||
func CreateTimeLimitCode(data string, minutes int, startInf interface{}) string {
|
||||
format := "YmdHi"
|
||||
format := "200601021504"
|
||||
|
||||
var start, end time.Time
|
||||
var startStr, endStr string
|
||||
@@ -149,16 +149,16 @@ func CreateTimeLimitCode(data string, minutes int, startInf interface{}) string
|
||||
if startInf == nil {
|
||||
// Use now time create code
|
||||
start = time.Now()
|
||||
startStr = DateFormat(start, format)
|
||||
startStr = start.Format(format)
|
||||
} else {
|
||||
// use start string create code
|
||||
startStr = startInf.(string)
|
||||
start, _ = DateParse(startStr, format)
|
||||
startStr = DateFormat(start, format)
|
||||
start, _ = time.ParseInLocation(format, startStr, time.Local)
|
||||
startStr = start.Format(format)
|
||||
}
|
||||
|
||||
end = start.Add(time.Minute * time.Duration(minutes))
|
||||
endStr = DateFormat(end, format)
|
||||
endStr = end.Format(format)
|
||||
|
||||
// create sha1 encode string
|
||||
sh := sha1.New()
|
||||
@@ -171,7 +171,7 @@ func CreateTimeLimitCode(data string, minutes int, startInf interface{}) string
|
||||
|
||||
// AvatarLink returns avatar link by given e-mail.
|
||||
func AvatarLink(email string) string {
|
||||
if setting.DisableGravatar {
|
||||
if setting.DisableGravatar || setting.OfflineMode {
|
||||
return setting.AppSubUrl + "/img/avatar_default.jpg"
|
||||
}
|
||||
|
||||
@@ -420,58 +420,3 @@ func Subtract(left interface{}, right interface{}) interface{} {
|
||||
return fleft + float64(rleft) - (fright + float64(rright))
|
||||
}
|
||||
}
|
||||
|
||||
// DateFormat pattern rules.
|
||||
var datePatterns = []string{
|
||||
// year
|
||||
"Y", "2006", // A full numeric representation of a year, 4 digits Examples: 1999 or 2003
|
||||
"y", "06", //A two digit representation of a year Examples: 99 or 03
|
||||
|
||||
// month
|
||||
"m", "01", // Numeric representation of a month, with leading zeros 01 through 12
|
||||
"n", "1", // Numeric representation of a month, without leading zeros 1 through 12
|
||||
"M", "Jan", // A short textual representation of a month, three letters Jan through Dec
|
||||
"F", "January", // A full textual representation of a month, such as January or March January through December
|
||||
|
||||
// day
|
||||
"d", "02", // Day of the month, 2 digits with leading zeros 01 to 31
|
||||
"j", "2", // Day of the month without leading zeros 1 to 31
|
||||
|
||||
// week
|
||||
"D", "Mon", // A textual representation of a day, three letters Mon through Sun
|
||||
"l", "Monday", // A full textual representation of the day of the week Sunday through Saturday
|
||||
|
||||
// time
|
||||
"g", "3", // 12-hour format of an hour without leading zeros 1 through 12
|
||||
"G", "15", // 24-hour format of an hour without leading zeros 0 through 23
|
||||
"h", "03", // 12-hour format of an hour with leading zeros 01 through 12
|
||||
"H", "15", // 24-hour format of an hour with leading zeros 00 through 23
|
||||
|
||||
"a", "pm", // Lowercase Ante meridiem and Post meridiem am or pm
|
||||
"A", "PM", // Uppercase Ante meridiem and Post meridiem AM or PM
|
||||
|
||||
"i", "04", // Minutes with leading zeros 00 to 59
|
||||
"s", "05", // Seconds, with leading zeros 00 through 59
|
||||
|
||||
// time zone
|
||||
"T", "MST",
|
||||
"P", "-07:00",
|
||||
"O", "-0700",
|
||||
|
||||
// RFC 2822
|
||||
"r", time.RFC1123Z,
|
||||
}
|
||||
|
||||
// Parse Date use PHP time format.
|
||||
func DateParse(dateString, format string) (time.Time, error) {
|
||||
replacer := strings.NewReplacer(datePatterns...)
|
||||
format = replacer.Replace(format)
|
||||
return time.ParseInLocation(format, dateString, time.Local)
|
||||
}
|
||||
|
||||
// Date takes a PHP like date func to Go's time format.
|
||||
func DateFormat(t time.Time, format string) string {
|
||||
replacer := strings.NewReplacer(datePatterns...)
|
||||
format = replacer.Replace(format)
|
||||
return t.Format(format)
|
||||
}
|
||||
|
||||
1041
modules/bindata/bindata.go
Normal file
1041
modules/bindata/bindata.go
Normal file
File diff suppressed because one or more lines are too long
@@ -88,11 +88,11 @@ func (c *Commit) GetCommitOfRelPath(relPath string) (*Commit, error) {
|
||||
}
|
||||
|
||||
func (c *Commit) GetSubModule(entryname string) (*SubModule, error) {
|
||||
moduels, err := c.GetSubModules()
|
||||
modules, err := c.GetSubModules()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return moduels[entryname], nil
|
||||
return modules[entryname], nil
|
||||
}
|
||||
|
||||
func (c *Commit) GetSubModules() (map[string]*SubModule, error) {
|
||||
|
||||
@@ -17,24 +17,35 @@ type Signature struct {
|
||||
When time.Time
|
||||
}
|
||||
|
||||
// Helper to get a signature from the commit line, which looks like this:
|
||||
// Helper to get a signature from the commit line, which looks like these:
|
||||
// author Patrick Gundlach <gundlach@speedata.de> 1378823654 +0200
|
||||
// author Patrick Gundlach <gundlach@speedata.de> Thu, 07 Apr 2005 22:13:13 +0200
|
||||
// but without the "author " at the beginning (this method should)
|
||||
// be used for author and committer.
|
||||
//
|
||||
// FIXME: include timezone!
|
||||
func newSignatureFromCommitline(line []byte) (*Signature, error) {
|
||||
// FIXME: include timezone for timestamp!
|
||||
func newSignatureFromCommitline(line []byte) (_ *Signature, err error) {
|
||||
sig := new(Signature)
|
||||
emailstart := bytes.IndexByte(line, '<')
|
||||
sig.Name = string(line[:emailstart-1])
|
||||
emailstop := bytes.IndexByte(line, '>')
|
||||
sig.Email = string(line[emailstart+1 : emailstop])
|
||||
timestop := bytes.IndexByte(line[emailstop+2:], ' ')
|
||||
timestring := string(line[emailstop+2 : emailstop+2+timestop])
|
||||
seconds, err := strconv.ParseInt(timestring, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
// Check date format.
|
||||
firstChar := line[emailstop+2]
|
||||
if firstChar >= 48 && firstChar <= 57 {
|
||||
timestop := bytes.IndexByte(line[emailstop+2:], ' ')
|
||||
timestring := string(line[emailstop+2 : emailstop+2+timestop])
|
||||
seconds, err := strconv.ParseInt(timestring, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sig.When = time.Unix(seconds, 0)
|
||||
} else {
|
||||
sig.When, err = time.Parse("Mon Jan _2 15:04:05 2006 -0700", string(line[emailstop+2:]))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
sig.When = time.Unix(seconds, 0)
|
||||
return sig, nil
|
||||
}
|
||||
|
||||
@@ -31,6 +31,10 @@ func NewSubModuleFile(c *Commit, refUrl, refId string) *SubModuleFile {
|
||||
|
||||
// RefUrl guesses and returns reference URL.
|
||||
func (sf *SubModuleFile) RefUrl() string {
|
||||
if sf.refUrl == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
url := strings.TrimSuffix(sf.refUrl, ".git")
|
||||
|
||||
// git://xxx/user/repo
|
||||
|
||||
@@ -163,7 +163,7 @@ func SendIssueNotifyMail(u, owner *models.User, repo *models.Repository, issue *
|
||||
|
||||
tos := make([]string, 0, len(ws))
|
||||
for i := range ws {
|
||||
uid := ws[i].UserId
|
||||
uid := ws[i].UserID
|
||||
if u.Id == uid {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"net"
|
||||
"net/mail"
|
||||
"net/smtp"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
@@ -77,6 +78,14 @@ func sendMail(settings *setting.Mailer, recipients []string, msgContent []byte)
|
||||
ServerName: host,
|
||||
}
|
||||
|
||||
if settings.UseCertificate {
|
||||
cert, err := tls.LoadX509KeyPair(settings.CertFile, settings.KeyFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tlsconfig.Certificates = []tls.Certificate{cert}
|
||||
}
|
||||
|
||||
conn, err := net.Dial("tcp", net.JoinHostPort(host, port))
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -95,6 +104,15 @@ func sendMail(settings *setting.Mailer, recipients []string, msgContent []byte)
|
||||
return err
|
||||
}
|
||||
|
||||
hostname, err := os.Hostname()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = client.Hello(hostname); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If not using SMTPS, alway use STARTTLS if available
|
||||
hasStartTLS, _ := client.Extension("STARTTLS")
|
||||
if !isSecureConn && hasStartTLS {
|
||||
|
||||
@@ -30,7 +30,7 @@ func Toggle(options *ToggleOptions) macaron.Handler {
|
||||
|
||||
// Checking non-logged users landing page.
|
||||
if !ctx.IsSigned && ctx.Req.RequestURI == "/" && setting.LandingPageUrl != setting.LANDING_PAGE_HOME {
|
||||
ctx.Redirect(string(setting.LandingPageUrl))
|
||||
ctx.Redirect(setting.AppSubUrl + string(setting.LandingPageUrl))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -38,29 +38,7 @@ type Context struct {
|
||||
IsSigned bool
|
||||
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 models.CloneLink
|
||||
CommitsCount int
|
||||
Mirror *models.Mirror
|
||||
}
|
||||
Repo RepoContext
|
||||
|
||||
Org struct {
|
||||
IsOwner bool
|
||||
@@ -73,6 +51,37 @@ type Context struct {
|
||||
}
|
||||
}
|
||||
|
||||
type RepoContext struct {
|
||||
AccessMode models.AccessMode
|
||||
IsWatching bool
|
||||
IsBranch bool
|
||||
IsTag bool
|
||||
IsCommit 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
|
||||
}
|
||||
|
||||
// Return if the current user has write access for this repository
|
||||
func (r RepoContext) IsOwner() bool {
|
||||
return r.AccessMode >= models.ACCESS_MODE_WRITE
|
||||
}
|
||||
|
||||
// Return if the current user has read access for this repository
|
||||
func (r RepoContext) HasAccess() bool {
|
||||
return r.AccessMode >= models.ACCESS_MODE_READ
|
||||
}
|
||||
|
||||
// HasError returns true if error occurs in form validation.
|
||||
func (ctx *Context) HasApiError() bool {
|
||||
hasErr, ok := ctx.Data["HasError"]
|
||||
@@ -130,6 +139,18 @@ func (ctx *Context) Handle(status int, title string, err error) {
|
||||
ctx.HTML(status, base.TplName(fmt.Sprintf("status/%d", status)))
|
||||
}
|
||||
|
||||
func (ctx *Context) HandleAPI(status int, obj interface{}) {
|
||||
var message string
|
||||
if err, ok := obj.(error); ok {
|
||||
message = err.Error()
|
||||
} else {
|
||||
message = obj.(string)
|
||||
}
|
||||
ctx.JSON(status, map[string]string{
|
||||
"message": message,
|
||||
})
|
||||
}
|
||||
|
||||
func (ctx *Context) ServeContent(name string, r io.ReadSeeker, params ...interface{}) {
|
||||
modtime := time.Now()
|
||||
for _, p := range params {
|
||||
|
||||
@@ -87,7 +87,7 @@ func OrgAssignment(redirect bool, args ...bool) macaron.Handler {
|
||||
return
|
||||
}
|
||||
ctx.Data["Team"] = ctx.Org.Team
|
||||
ctx.Org.IsAdminTeam = ctx.Org.Team.IsOwnerTeam() || ctx.Org.Team.Authorize == models.ORG_ADMIN
|
||||
ctx.Org.IsAdminTeam = ctx.Org.Team.IsOwnerTeam() || ctx.Org.Team.Authorize >= models.ACCESS_MODE_ADMIN
|
||||
}
|
||||
ctx.Data["IsAdminTeam"] = ctx.Org.IsAdminTeam
|
||||
if requireAdminTeam && !ctx.Org.IsAdminTeam {
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
@@ -29,17 +28,10 @@ func ApiRepoAssignment() macaron.Handler {
|
||||
err error
|
||||
)
|
||||
|
||||
// Collaborators who have write access can be seen as owners.
|
||||
if ctx.IsSigned {
|
||||
ctx.Repo.IsOwner, err = models.HasAccess(ctx.User.Name, userName+"/"+repoName, models.WRITABLE)
|
||||
if err != nil {
|
||||
ctx.JSON(500, &base.ApiJsonErr{"HasAccess: " + err.Error(), base.DOC_URL})
|
||||
return
|
||||
}
|
||||
ctx.Repo.IsTrueOwner = ctx.User.LowerName == strings.ToLower(userName)
|
||||
}
|
||||
|
||||
if !ctx.Repo.IsTrueOwner {
|
||||
// Check if the user is the same as the repository owner.
|
||||
if ctx.IsSigned && ctx.User.LowerName == strings.ToLower(userName) {
|
||||
u = ctx.User
|
||||
} else {
|
||||
u, err = models.GetUserByName(userName)
|
||||
if err != nil {
|
||||
if err == models.ErrUserNotExist {
|
||||
@@ -49,66 +41,36 @@ func ApiRepoAssignment() macaron.Handler {
|
||||
}
|
||||
return
|
||||
}
|
||||
} else {
|
||||
u = ctx.User
|
||||
}
|
||||
ctx.Repo.Owner = u
|
||||
|
||||
// Organization owner team members are true owners as well.
|
||||
if ctx.IsSigned && ctx.Repo.Owner.IsOrganization() && ctx.Repo.Owner.IsOwnedBy(ctx.User.Id) {
|
||||
ctx.Repo.IsTrueOwner = true
|
||||
}
|
||||
|
||||
// Get repository.
|
||||
repo, err := models.GetRepositoryByName(u.Id, repoName)
|
||||
if err != nil {
|
||||
if err == models.ErrRepoNotExist {
|
||||
if models.IsErrRepoNotExist(err) {
|
||||
ctx.Error(404)
|
||||
return
|
||||
} else {
|
||||
ctx.JSON(500, &base.ApiJsonErr{"GetRepositoryByName: " + err.Error(), base.DOC_URL})
|
||||
}
|
||||
ctx.JSON(500, &base.ApiJsonErr{"GetRepositoryByName: " + err.Error(), base.DOC_URL})
|
||||
return
|
||||
} else if err = repo.GetOwner(); err != nil {
|
||||
ctx.JSON(500, &base.ApiJsonErr{"GetOwner: " + err.Error(), base.DOC_URL})
|
||||
return
|
||||
}
|
||||
|
||||
// Check if the mirror repository owner(mirror repository doesn't have access).
|
||||
if ctx.IsSigned && !ctx.Repo.IsOwner {
|
||||
if repo.OwnerId == ctx.User.Id {
|
||||
ctx.Repo.IsOwner = true
|
||||
}
|
||||
// Check if current user has admin permission to repository.
|
||||
if u.IsOrganization() {
|
||||
auth, err := models.GetHighestAuthorize(u.Id, ctx.User.Id, repo.Id, 0)
|
||||
if err != nil {
|
||||
ctx.JSON(500, &base.ApiJsonErr{"GetHighestAuthorize: " + err.Error(), base.DOC_URL})
|
||||
return
|
||||
}
|
||||
if auth == models.ORG_ADMIN {
|
||||
ctx.Repo.IsOwner = true
|
||||
ctx.Repo.IsAdmin = true
|
||||
}
|
||||
}
|
||||
mode, err := models.AccessLevel(ctx.User, repo)
|
||||
if err != nil {
|
||||
ctx.JSON(500, &base.ApiJsonErr{"AccessLevel: " + err.Error(), base.DOC_URL})
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Repo.AccessMode = mode
|
||||
|
||||
// Check access.
|
||||
if repo.IsPrivate && !ctx.Repo.IsOwner {
|
||||
if ctx.User == nil {
|
||||
ctx.Error(404)
|
||||
return
|
||||
}
|
||||
|
||||
hasAccess, err := models.HasAccess(ctx.User.Name, ctx.Repo.Owner.Name+"/"+repo.Name, models.READABLE)
|
||||
if err != nil {
|
||||
ctx.JSON(500, &base.ApiJsonErr{"HasAccess: " + err.Error(), base.DOC_URL})
|
||||
return
|
||||
} else if !hasAccess {
|
||||
ctx.Error(404)
|
||||
return
|
||||
}
|
||||
if ctx.Repo.AccessMode == models.ACCESS_MODE_NONE {
|
||||
ctx.Error(404)
|
||||
return
|
||||
}
|
||||
ctx.Repo.HasAccess = true
|
||||
|
||||
ctx.Repo.Repository = repo
|
||||
}
|
||||
@@ -242,101 +204,49 @@ func RepoAssignment(redirect bool, args ...bool) macaron.Handler {
|
||||
refName = ctx.Params(":path")
|
||||
}
|
||||
|
||||
// Collaborators who have write access can be seen as owners.
|
||||
if ctx.IsSigned {
|
||||
ctx.Repo.IsOwner, err = models.HasAccess(ctx.User.Name, userName+"/"+repoName, models.WRITABLE)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "HasAccess", err)
|
||||
return
|
||||
}
|
||||
ctx.Repo.IsTrueOwner = ctx.User.LowerName == strings.ToLower(userName)
|
||||
}
|
||||
|
||||
if !ctx.Repo.IsTrueOwner {
|
||||
// Check if the user is the same as the repository owner
|
||||
if ctx.IsSigned && ctx.User.LowerName == strings.ToLower(userName) {
|
||||
u = ctx.User
|
||||
} else {
|
||||
u, err = models.GetUserByName(userName)
|
||||
if err != nil {
|
||||
if err == models.ErrUserNotExist {
|
||||
ctx.Handle(404, "GetUserByName", err)
|
||||
} else if redirect {
|
||||
log.Error(4, "GetUserByName", err)
|
||||
ctx.Redirect(setting.AppSubUrl + "/")
|
||||
} else {
|
||||
ctx.Handle(500, "GetUserByName", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
} else {
|
||||
u = ctx.User
|
||||
}
|
||||
|
||||
if u == nil {
|
||||
if redirect {
|
||||
ctx.Redirect(setting.AppSubUrl + "/")
|
||||
return
|
||||
}
|
||||
ctx.Handle(404, "RepoAssignment", errors.New("invliad user account for single repository"))
|
||||
return
|
||||
}
|
||||
ctx.Repo.Owner = u
|
||||
|
||||
// Organization owner team members are true owners as well.
|
||||
if ctx.IsSigned && ctx.Repo.Owner.IsOrganization() && ctx.Repo.Owner.IsOwnedBy(ctx.User.Id) {
|
||||
ctx.Repo.IsTrueOwner = true
|
||||
}
|
||||
|
||||
// Get repository.
|
||||
repo, err := models.GetRepositoryByName(u.Id, repoName)
|
||||
if err != nil {
|
||||
if err == models.ErrRepoNotExist {
|
||||
if models.IsErrRepoNotExist(err) {
|
||||
ctx.Handle(404, "GetRepositoryByName", err)
|
||||
return
|
||||
} else if redirect {
|
||||
ctx.Redirect(setting.AppSubUrl + "/")
|
||||
return
|
||||
} else {
|
||||
ctx.Handle(500, "GetRepositoryByName", err)
|
||||
}
|
||||
ctx.Handle(500, "GetRepositoryByName", err)
|
||||
return
|
||||
} else if err = repo.GetOwner(); err != nil {
|
||||
ctx.Handle(500, "GetOwner", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Check if the mirror repository owner(mirror repository doesn't have access).
|
||||
if ctx.IsSigned && !ctx.Repo.IsOwner {
|
||||
if repo.OwnerId == ctx.User.Id {
|
||||
ctx.Repo.IsOwner = true
|
||||
}
|
||||
// Check if current user has admin permission to repository.
|
||||
if u.IsOrganization() {
|
||||
auth, err := models.GetHighestAuthorize(u.Id, ctx.User.Id, repo.Id, 0)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "GetHighestAuthorize", err)
|
||||
return
|
||||
}
|
||||
if auth == models.ORG_ADMIN {
|
||||
ctx.Repo.IsOwner = true
|
||||
ctx.Repo.IsAdmin = true
|
||||
}
|
||||
}
|
||||
mode, err := models.AccessLevel(ctx.User, repo)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "AccessLevel", err)
|
||||
return
|
||||
}
|
||||
ctx.Repo.AccessMode = mode
|
||||
|
||||
// Check access.
|
||||
if repo.IsPrivate && !ctx.Repo.IsOwner {
|
||||
if ctx.User == nil {
|
||||
ctx.Handle(404, "HasAccess", nil)
|
||||
return
|
||||
}
|
||||
|
||||
hasAccess, err := models.HasAccess(ctx.User.Name, ctx.Repo.Owner.Name+"/"+repo.Name, models.READABLE)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "HasAccess", err)
|
||||
return
|
||||
} else if !hasAccess {
|
||||
ctx.Handle(404, "HasAccess", nil)
|
||||
return
|
||||
}
|
||||
if ctx.Repo.AccessMode == models.ACCESS_MODE_NONE {
|
||||
ctx.Handle(404, "no access right", err)
|
||||
return
|
||||
}
|
||||
ctx.Repo.HasAccess = true
|
||||
|
||||
ctx.Data["HasAccess"] = true
|
||||
|
||||
if repo.IsMirror {
|
||||
@@ -383,8 +293,8 @@ func RepoAssignment(redirect bool, args ...bool) macaron.Handler {
|
||||
ctx.Data["Title"] = u.Name + "/" + repo.Name
|
||||
ctx.Data["Repository"] = repo
|
||||
ctx.Data["Owner"] = ctx.Repo.Repository.Owner
|
||||
ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner
|
||||
ctx.Data["IsRepositoryTrueOwner"] = ctx.Repo.IsTrueOwner
|
||||
ctx.Data["IsRepositoryOwner"] = ctx.Repo.AccessMode >= models.ACCESS_MODE_WRITE
|
||||
ctx.Data["IsRepositoryAdmin"] = ctx.Repo.AccessMode >= models.ACCESS_MODE_ADMIN
|
||||
|
||||
ctx.Data["DisableSSH"] = setting.DisableSSH
|
||||
ctx.Repo.CloneLink, err = repo.CloneLink()
|
||||
@@ -394,8 +304,7 @@ func RepoAssignment(redirect bool, args ...bool) macaron.Handler {
|
||||
}
|
||||
ctx.Data["CloneLink"] = ctx.Repo.CloneLink
|
||||
|
||||
if ctx.Repo.Repository.IsGoget {
|
||||
ctx.Data["GoGetLink"] = fmt.Sprintf("%s%s/%s", setting.AppUrl, u.LowerName, repo.LowerName)
|
||||
if ctx.Query("go-get") == "1" {
|
||||
ctx.Data["GoGetImport"] = fmt.Sprintf("%s/%s/%s", setting.Domain, u.LowerName, repo.LowerName)
|
||||
}
|
||||
|
||||
@@ -439,9 +348,9 @@ func RepoAssignment(redirect bool, args ...bool) macaron.Handler {
|
||||
}
|
||||
}
|
||||
|
||||
func RequireTrueOwner() macaron.Handler {
|
||||
func RequireAdmin() macaron.Handler {
|
||||
return func(ctx *Context) {
|
||||
if !ctx.Repo.IsTrueOwner && !ctx.Repo.IsAdmin {
|
||||
if ctx.Repo.AccessMode < models.ACCESS_MODE_ADMIN {
|
||||
if !ctx.IsSigned {
|
||||
ctx.SetCookie("redirect_to", "/"+url.QueryEscape(setting.AppSubUrl+ctx.Req.RequestURI), 0, setting.AppSubUrl)
|
||||
ctx.Redirect(setting.AppSubUrl + "/user/login")
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"github.com/macaron-contrib/session"
|
||||
"gopkg.in/ini.v1"
|
||||
|
||||
"github.com/gogits/gogs/modules/bindata"
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
// "github.com/gogits/gogs/modules/ssh"
|
||||
)
|
||||
@@ -67,6 +68,11 @@ var (
|
||||
CookieRememberName string
|
||||
ReverseProxyAuthUser string
|
||||
|
||||
// Database settings.
|
||||
UseSQLite3 bool
|
||||
UseMySQL bool
|
||||
UsePostgreSQL bool
|
||||
|
||||
// Webhook settings.
|
||||
Webhook struct {
|
||||
TaskInterval int
|
||||
@@ -126,7 +132,6 @@ var (
|
||||
|
||||
// Global setting objects.
|
||||
Cfg *ini.File
|
||||
ConfRootPath string
|
||||
CustomPath string // Custom directory path.
|
||||
CustomConf string
|
||||
ProdMode bool
|
||||
@@ -158,6 +163,12 @@ func WorkDir() (string, error) {
|
||||
return path.Dir(strings.Replace(execPath, "\\", "/", -1)), err
|
||||
}
|
||||
|
||||
func forcePathSeparator(path string) {
|
||||
if strings.Contains(path, "\\") {
|
||||
log.Fatal(4, "Do not use '\\' or '\\\\' in paths, instead, please use '/' in all places")
|
||||
}
|
||||
}
|
||||
|
||||
// NewConfigContext initializes configuration context.
|
||||
// NOTE: do not print any log except error.
|
||||
func NewConfigContext() {
|
||||
@@ -165,9 +176,8 @@ func NewConfigContext() {
|
||||
if err != nil {
|
||||
log.Fatal(4, "Fail to get work directory: %v", err)
|
||||
}
|
||||
ConfRootPath = path.Join(workDir, "conf")
|
||||
|
||||
Cfg, err = ini.Load(path.Join(workDir, "conf/app.ini"))
|
||||
Cfg, err = ini.Load(bindata.MustAsset("conf/app.ini"))
|
||||
if err != nil {
|
||||
log.Fatal(4, "Fail to parse 'conf/app.ini': %v", err)
|
||||
}
|
||||
@@ -191,6 +201,7 @@ func NewConfigContext() {
|
||||
Cfg.NameMapper = ini.AllCapsUnderscore
|
||||
|
||||
LogRootPath = Cfg.Section("log").Key("ROOT_PATH").MustString(path.Join(workDir, "log"))
|
||||
forcePathSeparator(LogRootPath)
|
||||
|
||||
sec := Cfg.Section("server")
|
||||
AppName = Cfg.Section("").Key("APP_NAME").MustString("Gogs: Go Git Service")
|
||||
@@ -240,7 +251,10 @@ func NewConfigContext() {
|
||||
ReverseProxyAuthUser = sec.Key("REVERSE_PROXY_AUTHENTICATION_USER").MustString("X-WEBAUTH-USER")
|
||||
|
||||
sec = Cfg.Section("attachment")
|
||||
AttachmentPath = path.Join(workDir, sec.Key("PATH").MustString("data/attachments"))
|
||||
AttachmentPath = sec.Key("PATH").MustString("data/attachments")
|
||||
if !filepath.IsAbs(AttachmentPath) {
|
||||
AttachmentPath = path.Join(workDir, AttachmentPath)
|
||||
}
|
||||
AttachmentAllowedTypes = sec.Key("ALLOWED_TYPES").MustString("image/jpeg|image/png")
|
||||
AttachmentMaxSize = sec.Key("MAX_SIZE").MustInt64(32)
|
||||
AttachmentMaxFiles = sec.Key("MAX_FILES").MustInt(10)
|
||||
@@ -264,10 +278,6 @@ func NewConfigContext() {
|
||||
"StampNano": time.StampNano,
|
||||
}[Cfg.Section("time").Key("FORMAT").MustString("RFC1123")]
|
||||
|
||||
if err = os.MkdirAll(AttachmentPath, os.ModePerm); err != nil {
|
||||
log.Fatal(4, "Could not create directory %s: %s", AttachmentPath, err)
|
||||
}
|
||||
|
||||
RunUser = Cfg.Section("").Key("RUN_USER").String()
|
||||
curUser := os.Getenv("USER")
|
||||
if len(curUser) == 0 {
|
||||
@@ -283,22 +293,25 @@ func NewConfigContext() {
|
||||
if err != nil {
|
||||
log.Fatal(4, "Fail to get home directory: %v", err)
|
||||
}
|
||||
homeDir = strings.Replace(homeDir, "\\", "/", -1)
|
||||
|
||||
sec = Cfg.Section("repository")
|
||||
RepoRootPath = sec.Key("ROOT").MustString(filepath.Join(homeDir, "gogs-repositories"))
|
||||
RepoRootPath = sec.Key("ROOT").MustString(path.Join(homeDir, "gogs-repositories"))
|
||||
forcePathSeparator(RepoRootPath)
|
||||
if !filepath.IsAbs(RepoRootPath) {
|
||||
RepoRootPath = filepath.Join(workDir, RepoRootPath)
|
||||
RepoRootPath = path.Join(workDir, RepoRootPath)
|
||||
} else {
|
||||
RepoRootPath = filepath.Clean(RepoRootPath)
|
||||
}
|
||||
if err = os.MkdirAll(RepoRootPath, os.ModePerm); err != nil {
|
||||
log.Fatal(4, "Fail to create repository root path(%s): %v", RepoRootPath, err)
|
||||
RepoRootPath = path.Clean(RepoRootPath)
|
||||
}
|
||||
ScriptType = sec.Key("SCRIPT_TYPE").MustString("bash")
|
||||
|
||||
sec = Cfg.Section("picture")
|
||||
PictureService = sec.Key("SERVICE").In("server", []string{"server"})
|
||||
AvatarUploadPath = path.Join(workDir, sec.Key("AVATAR_UPLOAD_PATH").MustString("data/avatars"))
|
||||
os.MkdirAll(AvatarUploadPath, os.ModePerm)
|
||||
AvatarUploadPath = sec.Key("AVATAR_UPLOAD_PATH").MustString("data/avatars")
|
||||
forcePathSeparator(AvatarUploadPath)
|
||||
if !filepath.IsAbs(AvatarUploadPath) {
|
||||
AvatarUploadPath = path.Join(workDir, AvatarUploadPath)
|
||||
}
|
||||
switch sec.Key("GRAVATAR_SOURCE").MustString("gravatar") {
|
||||
case "duoshuo":
|
||||
GravatarSource = "http://gravatar.duoshuo.com/avatar/"
|
||||
@@ -338,7 +351,7 @@ func newService() {
|
||||
Service.RequireSignInView = Cfg.Section("service").Key("REQUIRE_SIGNIN_VIEW").MustBool()
|
||||
Service.EnableCacheAvatar = Cfg.Section("service").Key("ENABLE_CACHE_AVATAR").MustBool()
|
||||
Service.EnableReverseProxyAuth = Cfg.Section("service").Key("ENABLE_REVERSE_PROXY_AUTHENTICATION").MustBool()
|
||||
Service.EnableReverseProxyAutoRegister = Cfg.Section("service").Key("ENABLE_REVERSE_PROXY_AUTO_REGISTERATION").MustBool()
|
||||
Service.EnableReverseProxyAutoRegister = Cfg.Section("service").Key("ENABLE_REVERSE_PROXY_AUTO_REGISTRATION").MustBool()
|
||||
}
|
||||
|
||||
var logLevels = map[string]string{
|
||||
@@ -363,9 +376,11 @@ func newLogService() {
|
||||
log.Fatal(4, "Unknown log mode: %s", mode)
|
||||
}
|
||||
|
||||
validLevels := []string{"Trace", "Debug", "Info", "Warn", "Error", "Critical"}
|
||||
// Log level.
|
||||
levelName := Cfg.Section("log."+mode).Key("LEVEL").In("Trace",
|
||||
[]string{"Trace", "Debug", "Info", "Warn", "Error", "Critical"})
|
||||
levelName := Cfg.Section("log."+mode).Key("LEVEL").In(
|
||||
Cfg.Section("log").Key("LEVEL").In("Trace", validLevels),
|
||||
validLevels)
|
||||
level, ok := logLevels[levelName]
|
||||
if !ok {
|
||||
log.Fatal(4, "Unknown log level: %s", levelName)
|
||||
@@ -446,11 +461,13 @@ func newSessionService() {
|
||||
|
||||
// Mailer represents mail service.
|
||||
type Mailer struct {
|
||||
Name string
|
||||
Host string
|
||||
From string
|
||||
User, Passwd string
|
||||
SkipVerify bool
|
||||
Name string
|
||||
Host string
|
||||
From string
|
||||
User, Passwd string
|
||||
SkipVerify bool
|
||||
UseCertificate bool
|
||||
CertFile, KeyFile string
|
||||
}
|
||||
|
||||
type OauthInfo struct {
|
||||
@@ -478,11 +495,14 @@ func newMailService() {
|
||||
}
|
||||
|
||||
MailService = &Mailer{
|
||||
Name: sec.Key("NAME").MustString(AppName),
|
||||
Host: sec.Key("HOST").String(),
|
||||
User: sec.Key("USER").String(),
|
||||
Passwd: sec.Key("PASSWD").String(),
|
||||
SkipVerify: sec.Key("SKIP_VERIFY").MustBool(),
|
||||
Name: sec.Key("NAME").MustString(AppName),
|
||||
Host: sec.Key("HOST").String(),
|
||||
User: sec.Key("USER").String(),
|
||||
Passwd: sec.Key("PASSWD").String(),
|
||||
SkipVerify: sec.Key("SKIP_VERIFY").MustBool(),
|
||||
UseCertificate: sec.Key("USE_CERTIFICATE").MustBool(),
|
||||
CertFile: sec.Key("CERT_FILE").String(),
|
||||
KeyFile: sec.Key("KEY_FILE").String(),
|
||||
}
|
||||
MailService.From = sec.Key("FROM").MustString(MailService.User)
|
||||
log.Info("Mail Service Enabled")
|
||||
|
||||
@@ -1066,9 +1066,6 @@ The register and sign-in page style
|
||||
#repo-header-download-drop .btn > i {
|
||||
margin-right: 6px;
|
||||
}
|
||||
#repo-header-download-drop input {
|
||||
cursor: default;
|
||||
}
|
||||
#repo-header-download-drop button,
|
||||
#repo-header-download-drop input {
|
||||
font-size: 11px;
|
||||
@@ -1089,6 +1086,7 @@ The register and sign-in page style
|
||||
border-right: none;
|
||||
width: 190px;
|
||||
border-left: none;
|
||||
cursor: default;
|
||||
}
|
||||
#repo-clone-help {
|
||||
clear: both;
|
||||
|
||||
@@ -209,27 +209,28 @@ var Gogs = {};
|
||||
$list.parents('tr').removeClass('end-selected-line');
|
||||
$list.parents('tr').find('td').removeClass('selected-line');
|
||||
if ($from) {
|
||||
var expr = new RegExp(/diff-(\d+)L(\d+)/);
|
||||
var expr = new RegExp(/diff-(\w+)([LR]\d+)/);
|
||||
var selectMatches = $select.attr('rel').match(expr)
|
||||
var fromMatches = $from.attr('rel').match(expr)
|
||||
var a = parseInt(selectMatches[2]);
|
||||
var b = parseInt(fromMatches[2]);
|
||||
var linesIntToStr = {};
|
||||
linesIntToStr[a] = selectMatches[2];
|
||||
linesIntToStr[b] = fromMatches[2];
|
||||
var selectTop = $select.offset().top;
|
||||
var fromTop = $from.offset().top;
|
||||
var hash;
|
||||
|
||||
var c;
|
||||
if (a != b) {
|
||||
if (a > b) {
|
||||
c = a;
|
||||
a = b;
|
||||
b = c;
|
||||
if (selectMatches[2] != fromMatches[2]) {
|
||||
if ((selectTop > fromTop)) {
|
||||
$startElem = $from;
|
||||
$endElem = $select;
|
||||
hash = fromMatches[1]+fromMatches[2] + '-' + selectMatches[2];
|
||||
} else {
|
||||
$startElem = $select;
|
||||
$endElem = $from;
|
||||
hash = selectMatches[1]+selectMatches[2] + '-' + fromMatches[2];
|
||||
}
|
||||
$('[rel=diff-'+fromMatches[1]+'L' + linesIntToStr[b] + ']').parents('tr').next().addClass('end-selected-line');
|
||||
var $selectedLines = $('[rel=diff-'+fromMatches[1]+'L' + linesIntToStr[a] + ']').parents('tr').nextUntil('.end-selected-line').andSelf();
|
||||
$endElem.parents('tr').next().addClass('end-selected-line');
|
||||
var $selectedLines = $startElem.parents('tr').nextUntil('.end-selected-line').andSelf();
|
||||
$selectedLines.find('td.lines-num > span').addClass('active')
|
||||
$selectedLines.find('td').addClass('selected-line');
|
||||
$.changeHash('#diff-'+fromMatches[1]+'L' + linesIntToStr[a] + '-L' + linesIntToStr[b]);
|
||||
$.changeHash('#diff-'+hash);
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -262,7 +263,7 @@ var Gogs = {};
|
||||
});
|
||||
|
||||
$(window).on('hashchange', function (e) {
|
||||
var m = window.location.hash.match(/^#diff-(\d+)(L\d+)\-(L\d+)$/);
|
||||
var m = window.location.hash.match(/^#diff-(\w+)([LR]\d+)\-([LR]\d+)$/);
|
||||
var $list = $('.code-diff td.lines-num > span');
|
||||
var $first;
|
||||
if (m) {
|
||||
@@ -271,7 +272,7 @@ var Gogs = {};
|
||||
$("html, body").scrollTop($first.offset().top - 200);
|
||||
return;
|
||||
}
|
||||
m = window.location.hash.match(/^#diff-(\d+)(L\d+)$/);
|
||||
m = window.location.hash.match(/^#diff-(\w+)([LR]\d+)$/);
|
||||
if (m) {
|
||||
$first = $list.filter('[rel=diff-' + m[1] + m[2] + ']');
|
||||
selectRange($list, $first);
|
||||
|
||||
@@ -81,9 +81,6 @@
|
||||
.btn>i {
|
||||
margin-right: 6px;
|
||||
}
|
||||
input {
|
||||
cursor: default;
|
||||
}
|
||||
button, input {
|
||||
font-size: 11px;
|
||||
}
|
||||
@@ -104,6 +101,7 @@
|
||||
border-right: none;
|
||||
width: 190px;
|
||||
border-left: none;
|
||||
cursor: default;
|
||||
}
|
||||
#repo-clone-help {
|
||||
clear: both;
|
||||
|
||||
@@ -63,15 +63,18 @@ func NewAuthSourcePost(ctx *middleware.Context, form auth.AuthenticationForm) {
|
||||
case models.LDAP:
|
||||
u = &models.LDAPConfig{
|
||||
Ldapsource: ldap.Ldapsource{
|
||||
Host: form.Host,
|
||||
Port: form.Port,
|
||||
UseSSL: form.UseSSL,
|
||||
BaseDN: form.BaseDN,
|
||||
Attributes: form.Attributes,
|
||||
Filter: form.Filter,
|
||||
MsAdSAFormat: form.MsAdSA,
|
||||
Enabled: true,
|
||||
Name: form.AuthName,
|
||||
Host: form.Host,
|
||||
Port: form.Port,
|
||||
UseSSL: form.UseSSL,
|
||||
BaseDN: form.BaseDN,
|
||||
AttributeUsername: form.AttributeUsername,
|
||||
AttributeName: form.AttributeName,
|
||||
AttributeSurname: form.AttributeSurname,
|
||||
AttributeMail: form.AttributeMail,
|
||||
Filter: form.Filter,
|
||||
MsAdSAFormat: form.MsAdSA,
|
||||
Enabled: true,
|
||||
Name: form.AuthName,
|
||||
},
|
||||
}
|
||||
case models.SMTP:
|
||||
@@ -142,15 +145,18 @@ func EditAuthSourcePost(ctx *middleware.Context, form auth.AuthenticationForm) {
|
||||
case models.LDAP:
|
||||
config = &models.LDAPConfig{
|
||||
Ldapsource: ldap.Ldapsource{
|
||||
Host: form.Host,
|
||||
Port: form.Port,
|
||||
UseSSL: form.UseSSL,
|
||||
BaseDN: form.BaseDN,
|
||||
Attributes: form.Attributes,
|
||||
Filter: form.Filter,
|
||||
MsAdSAFormat: form.MsAdSA,
|
||||
Enabled: true,
|
||||
Name: form.AuthName,
|
||||
Host: form.Host,
|
||||
Port: form.Port,
|
||||
UseSSL: form.UseSSL,
|
||||
BaseDN: form.BaseDN,
|
||||
AttributeUsername: form.AttributeUsername,
|
||||
AttributeName: form.AttributeName,
|
||||
AttributeSurname: form.AttributeSurname,
|
||||
AttributeMail: form.AttributeMail,
|
||||
Filter: form.Filter,
|
||||
MsAdSAFormat: form.MsAdSA,
|
||||
Enabled: true,
|
||||
Name: form.AuthName,
|
||||
},
|
||||
}
|
||||
case models.SMTP:
|
||||
|
||||
@@ -168,6 +168,7 @@ func EditUserPost(ctx *middleware.Context, form auth.AdminEditUserForm) {
|
||||
ctx.Handle(500, "GetUserById", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["User"] = u
|
||||
|
||||
if ctx.HasError() {
|
||||
ctx.HTML(200, USER_EDIT)
|
||||
@@ -175,8 +176,8 @@ func EditUserPost(ctx *middleware.Context, form auth.AdminEditUserForm) {
|
||||
}
|
||||
|
||||
// FIXME: need password length check
|
||||
if len(form.Passwd) > 0 {
|
||||
u.Passwd = form.Passwd
|
||||
if len(form.Password) > 0 {
|
||||
u.Passwd = form.Password
|
||||
u.Salt = models.GetUserSalt()
|
||||
u.EncodePasswd()
|
||||
}
|
||||
@@ -193,8 +194,6 @@ func EditUserPost(ctx *middleware.Context, form auth.AdminEditUserForm) {
|
||||
u.IsAdmin = form.Admin
|
||||
u.AllowGitHook = form.AllowGitHook
|
||||
|
||||
ctx.Data["User"] = u
|
||||
|
||||
if err := models.UpdateUser(u); err != nil {
|
||||
if err == models.ErrEmailAlreadyUsed {
|
||||
ctx.Data["Err_Email"] = true
|
||||
@@ -223,11 +222,11 @@ func DeleteUser(ctx *middleware.Context) {
|
||||
}
|
||||
|
||||
if err = models.DeleteUser(u); err != nil {
|
||||
switch err {
|
||||
case models.ErrUserOwnRepos:
|
||||
switch {
|
||||
case models.IsErrUserOwnRepos(err):
|
||||
ctx.Flash.Error(ctx.Tr("admin.users.still_own_repo"))
|
||||
ctx.Redirect(setting.AppSubUrl + "/admin/users/" + ctx.Params(":userid"))
|
||||
case models.ErrUserHasOrgs:
|
||||
case models.IsErrUserHasOrgs(err):
|
||||
ctx.Flash.Error(ctx.Tr("admin.users.still_has_org"))
|
||||
ctx.Redirect(setting.AppSubUrl + "/admin/users/" + ctx.Params(":userid"))
|
||||
default:
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
@@ -156,17 +156,15 @@ func CreateOrgRepo(ctx *middleware.Context, opt api.CreateRepoOption) {
|
||||
func MigrateRepo(ctx *middleware.Context, form auth.MigrateRepoForm) {
|
||||
u, err := models.GetUserByName(ctx.Query("username"))
|
||||
if err != nil {
|
||||
ctx.JSON(500, map[string]interface{}{
|
||||
"ok": false,
|
||||
"error": err.Error(),
|
||||
})
|
||||
if err == models.ErrUserNotExist {
|
||||
ctx.HandleAPI(422, err)
|
||||
} else {
|
||||
ctx.HandleAPI(500, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if !u.ValidtePassword(ctx.Query("password")) {
|
||||
ctx.JSON(500, map[string]interface{}{
|
||||
"ok": false,
|
||||
"error": "username or password is not correct",
|
||||
})
|
||||
ctx.HandleAPI(422, "Username or password is not correct.")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -175,56 +173,59 @@ func MigrateRepo(ctx *middleware.Context, form auth.MigrateRepoForm) {
|
||||
if form.Uid != u.Id {
|
||||
org, err := models.GetUserById(form.Uid)
|
||||
if err != nil {
|
||||
log.Error(4, "GetUserById: %v", err)
|
||||
ctx.Error(500)
|
||||
if err == models.ErrUserNotExist {
|
||||
ctx.HandleAPI(422, err)
|
||||
} else {
|
||||
ctx.HandleAPI(500, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
ctxUser = org
|
||||
}
|
||||
|
||||
if ctx.HasError() {
|
||||
ctx.JSON(422, map[string]interface{}{
|
||||
"ok": false,
|
||||
"error": ctx.GetErrMsg(),
|
||||
})
|
||||
ctx.HandleAPI(422, ctx.GetErrMsg())
|
||||
return
|
||||
}
|
||||
|
||||
if ctxUser.IsOrganization() {
|
||||
// Check ownership of organization.
|
||||
if !ctxUser.IsOwnedBy(u.Id) {
|
||||
ctx.JSON(403, map[string]interface{}{
|
||||
"ok": false,
|
||||
"error": "given user is not owner of organization",
|
||||
})
|
||||
ctx.HandleAPI(403, "Given user is not owner of organization.")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
authStr := strings.Replace(fmt.Sprintf("://%s:%s",
|
||||
form.AuthUserName, form.AuthPasswd), "@", "%40", -1)
|
||||
url := strings.Replace(form.HttpsUrl, "://", authStr+"@", 1)
|
||||
repo, err := models.MigrateRepository(ctxUser, form.RepoName, form.Description, form.Private,
|
||||
form.Mirror, url)
|
||||
if err == nil {
|
||||
log.Trace("Repository migrated: %s/%s", ctxUser.Name, form.RepoName)
|
||||
ctx.JSON(200, map[string]interface{}{
|
||||
"ok": true,
|
||||
"data": "/" + ctxUser.Name + "/" + form.RepoName,
|
||||
})
|
||||
// Remote address can be HTTP/HTTPS URL or local path.
|
||||
remoteAddr := form.CloneAddr
|
||||
if strings.HasPrefix(form.CloneAddr, "http") {
|
||||
u, err := url.Parse(form.CloneAddr)
|
||||
if err != nil {
|
||||
ctx.HandleAPI(422, err)
|
||||
return
|
||||
}
|
||||
if len(form.AuthUsername) > 0 || len(form.AuthPassword) > 0 {
|
||||
u.User = url.UserPassword(form.AuthUsername, form.AuthPassword)
|
||||
}
|
||||
remoteAddr = u.String()
|
||||
} else if !com.IsDir(remoteAddr) {
|
||||
ctx.HandleAPI(422, "Invalid local path, it does not exist or not a directory.")
|
||||
return
|
||||
}
|
||||
|
||||
if repo != nil {
|
||||
if errDelete := models.DeleteRepository(ctxUser.Id, repo.Id, ctxUser.Name); errDelete != nil {
|
||||
log.Error(4, "DeleteRepository: %v", errDelete)
|
||||
repo, err := models.MigrateRepository(ctxUser, form.RepoName, form.Description, form.Private, form.Mirror, remoteAddr)
|
||||
if err != nil {
|
||||
if repo != nil {
|
||||
if errDelete := models.DeleteRepository(ctxUser.Id, repo.Id, ctxUser.Name); errDelete != nil {
|
||||
log.Error(4, "DeleteRepository: %v", errDelete)
|
||||
}
|
||||
}
|
||||
ctx.HandleAPI(500, err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(500, map[string]interface{}{
|
||||
"ok": false,
|
||||
"error": err.Error(),
|
||||
})
|
||||
log.Trace("Repository migrated: %s/%s", ctxUser.Name, form.RepoName)
|
||||
ctx.WriteHeader(200)
|
||||
}
|
||||
|
||||
// GET /user/repos
|
||||
@@ -237,28 +238,31 @@ func ListMyRepos(ctx *middleware.Context) {
|
||||
}
|
||||
numOwnRepos := len(ownRepos)
|
||||
|
||||
collaRepos, err := models.GetCollaborativeRepos(ctx.User.Name)
|
||||
accessibleRepos, err := ctx.User.GetAccessibleRepositories()
|
||||
if err != nil {
|
||||
ctx.JSON(500, &base.ApiJsonErr{"GetCollaborativeRepos: " + err.Error(), base.DOC_URL})
|
||||
ctx.JSON(500, &base.ApiJsonErr{"GetAccessibleRepositories: " + err.Error(), base.DOC_URL})
|
||||
return
|
||||
}
|
||||
|
||||
repos := make([]*api.Repository, numOwnRepos+len(collaRepos))
|
||||
repos := make([]*api.Repository, numOwnRepos+len(accessibleRepos))
|
||||
for i := range ownRepos {
|
||||
repos[i] = ToApiRepository(ctx.User, ownRepos[i], api.Permission{true, true, true})
|
||||
}
|
||||
for i := range collaRepos {
|
||||
if err = collaRepos[i].GetOwner(); err != nil {
|
||||
i := numOwnRepos
|
||||
|
||||
for repo, access := range accessibleRepos {
|
||||
if err = repo.GetOwner(); err != nil {
|
||||
ctx.JSON(500, &base.ApiJsonErr{"GetOwner: " + err.Error(), base.DOC_URL})
|
||||
return
|
||||
}
|
||||
j := i + numOwnRepos
|
||||
repos[j] = ToApiRepository(collaRepos[i].Owner, collaRepos[i].Repository, api.Permission{false, collaRepos[i].CanPush, true})
|
||||
|
||||
repos[i] = ToApiRepository(repo.Owner, repo, api.Permission{false, access >= models.ACCESS_MODE_WRITE, true})
|
||||
|
||||
// FIXME: cache result to reduce DB query?
|
||||
if collaRepos[i].Owner.IsOrganization() && collaRepos[i].Owner.IsOwnedBy(ctx.User.Id) {
|
||||
repos[j].Permissions.Admin = true
|
||||
if repo.Owner.IsOrganization() && repo.Owner.IsOwnedBy(ctx.User.Id) {
|
||||
repos[i].Permissions.Admin = true
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
ctx.JSON(200, &repos)
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
func GetRepoRawFile(ctx *middleware.Context) {
|
||||
if ctx.Repo.Repository.IsPrivate && !ctx.Repo.HasAccess {
|
||||
if !ctx.Repo.HasAccess() {
|
||||
ctx.Error(404)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -224,6 +224,7 @@ func InstallPost(ctx *middleware.Context, form auth.InstallForm) {
|
||||
cfg.Section("session").Key("PROVIDER").SetValue("file")
|
||||
|
||||
cfg.Section("log").Key("MODE").SetValue("file")
|
||||
cfg.Section("log").Key("LEVEL").SetValue("Info")
|
||||
|
||||
cfg.Section("security").Key("INSTALL_LOCK").SetValue("true")
|
||||
cfg.Section("security").Key("SECRET_KEY").SetValue(base.GetRandomString(15))
|
||||
|
||||
@@ -61,14 +61,14 @@ func MembersAction(ctx *middleware.Context) {
|
||||
return
|
||||
}
|
||||
err = org.RemoveMember(uid)
|
||||
if err == models.ErrLastOrgOwner {
|
||||
if models.IsErrLastOrgOwner(err) {
|
||||
ctx.Flash.Error(ctx.Tr("form.last_org_owner"))
|
||||
ctx.Redirect(ctx.Org.OrgLink + "/members")
|
||||
return
|
||||
}
|
||||
case "leave":
|
||||
err = org.RemoveMember(ctx.User.Id)
|
||||
if err == models.ErrLastOrgOwner {
|
||||
if models.IsErrLastOrgOwner(err) {
|
||||
ctx.Flash.Error(ctx.Tr("form.last_org_owner"))
|
||||
ctx.Redirect(ctx.Org.OrgLink + "/members")
|
||||
return
|
||||
|
||||
@@ -39,18 +39,18 @@ func SettingsPost(ctx *middleware.Context, form auth.UpdateOrgSettingForm) {
|
||||
|
||||
// Check if organization name has been changed.
|
||||
if org.Name != form.OrgUserName {
|
||||
isExist, err := models.IsUserExist(form.OrgUserName)
|
||||
isExist, err := models.IsUserExist(org.Id, form.OrgUserName)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "IsUserExist", err)
|
||||
return
|
||||
} else if isExist {
|
||||
ctx.Data["Err_UserName"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.username_been_taken"), SETTINGS_OPTIONS, &form)
|
||||
return
|
||||
} else if err = models.ChangeUserName(org, form.OrgUserName); err != nil {
|
||||
if err == models.ErrUserNameIllegal {
|
||||
ctx.Flash.Error(ctx.Tr("form.illegal_username"))
|
||||
ctx.Redirect(setting.AppSubUrl + "/org/" + org.LowerName + "/settings")
|
||||
return
|
||||
ctx.Data["Err_UserName"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.illegal_username"), SETTINGS_OPTIONS, &form)
|
||||
} else {
|
||||
ctx.Handle(500, "ChangeUserName", err)
|
||||
}
|
||||
@@ -68,7 +68,12 @@ func SettingsPost(ctx *middleware.Context, form auth.UpdateOrgSettingForm) {
|
||||
org.Avatar = base.EncodeMd5(form.Avatar)
|
||||
org.AvatarEmail = form.Avatar
|
||||
if err := models.UpdateUser(org); err != nil {
|
||||
ctx.Handle(500, "UpdateUser", err)
|
||||
if err == models.ErrEmailAlreadyUsed {
|
||||
ctx.Data["Err_Email"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), SETTINGS_OPTIONS, &form)
|
||||
} else {
|
||||
ctx.Handle(500, "UpdateUser", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
log.Trace("Organization setting updated: %s", org.Name)
|
||||
@@ -82,13 +87,12 @@ func SettingsDelete(ctx *middleware.Context) {
|
||||
|
||||
org := ctx.Org.Organization
|
||||
if ctx.Req.Method == "POST" {
|
||||
// TODO: validate password.
|
||||
// FIXME: validate password.
|
||||
if err := models.DeleteOrganization(org); err != nil {
|
||||
switch err {
|
||||
case models.ErrUserOwnRepos:
|
||||
if models.IsErrUserOwnRepos(err) {
|
||||
ctx.Flash.Error(ctx.Tr("form.org_still_own_repo"))
|
||||
ctx.Redirect(setting.AppSubUrl + "/org/" + org.LowerName + "/settings/delete")
|
||||
default:
|
||||
} else {
|
||||
ctx.Handle(500, "DeleteOrganization", err)
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -91,7 +91,7 @@ func TeamsAction(ctx *middleware.Context) {
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if err == models.ErrLastOrgOwner {
|
||||
if models.IsErrLastOrgOwner(err) {
|
||||
ctx.Flash.Error(ctx.Tr("form.last_org_owner"))
|
||||
} else {
|
||||
log.Error(3, "Action(%s): %v", ctx.Params(":action"), err)
|
||||
@@ -124,7 +124,7 @@ func TeamsRepoAction(ctx *middleware.Context) {
|
||||
var repo *models.Repository
|
||||
repo, err = models.GetRepositoryByName(ctx.Org.Organization.Id, repoName)
|
||||
if err != nil {
|
||||
if err == models.ErrRepoNotExist {
|
||||
if models.IsErrRepoNotExist(err) {
|
||||
ctx.Flash.Error(ctx.Tr("org.teams.add_nonexistent_repo"))
|
||||
ctx.Redirect(ctx.Org.OrgLink + "/teams/" + ctx.Org.Team.LowerName + "/repositories")
|
||||
return
|
||||
@@ -165,14 +165,14 @@ func NewTeamPost(ctx *middleware.Context, form auth.CreateTeamForm) {
|
||||
}
|
||||
|
||||
// Validate permission level.
|
||||
var auth models.AuthorizeType
|
||||
var auth models.AccessMode
|
||||
switch form.Permission {
|
||||
case "read":
|
||||
auth = models.ORG_READABLE
|
||||
auth = models.ACCESS_MODE_READ
|
||||
case "write":
|
||||
auth = models.ORG_WRITABLE
|
||||
auth = models.ACCESS_MODE_WRITE
|
||||
case "admin":
|
||||
auth = models.ORG_ADMIN
|
||||
auth = models.ACCESS_MODE_ADMIN
|
||||
default:
|
||||
ctx.Error(401)
|
||||
return
|
||||
@@ -181,7 +181,7 @@ func NewTeamPost(ctx *middleware.Context, form auth.CreateTeamForm) {
|
||||
org := ctx.Org.Organization
|
||||
|
||||
t := &models.Team{
|
||||
OrgId: org.Id,
|
||||
OrgID: org.Id,
|
||||
Name: form.TeamName,
|
||||
Description: form.Description,
|
||||
Authorize: auth,
|
||||
@@ -246,14 +246,14 @@ func EditTeamPost(ctx *middleware.Context, form auth.CreateTeamForm) {
|
||||
isAuthChanged := false
|
||||
if !t.IsOwnerTeam() {
|
||||
// Validate permission level.
|
||||
var auth models.AuthorizeType
|
||||
var auth models.AccessMode
|
||||
switch form.Permission {
|
||||
case "read":
|
||||
auth = models.ORG_READABLE
|
||||
auth = models.ACCESS_MODE_READ
|
||||
case "write":
|
||||
auth = models.ORG_WRITABLE
|
||||
auth = models.ACCESS_MODE_WRITE
|
||||
case "admin":
|
||||
auth = models.ORG_ADMIN
|
||||
auth = models.ACCESS_MODE_ADMIN
|
||||
default:
|
||||
ctx.Error(401)
|
||||
return
|
||||
|
||||
@@ -65,7 +65,7 @@ func Http(ctx *middleware.Context) {
|
||||
|
||||
repo, err := models.GetRepositoryByName(repoUser.Id, reponame)
|
||||
if err != nil {
|
||||
if err == models.ErrRepoNotExist {
|
||||
if models.IsErrRepoNotExist(err) {
|
||||
ctx.Handle(404, "GetRepositoryByName", nil)
|
||||
} else {
|
||||
ctx.Handle(500, "GetRepositoryByName", err)
|
||||
@@ -105,10 +105,10 @@ func Http(ctx *middleware.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
authUser, err = models.GetUserByName(authUsername)
|
||||
authUser, err = models.UserSignIn(authUsername, authPasswd)
|
||||
if err != nil {
|
||||
if err != models.ErrUserNotExist {
|
||||
ctx.Handle(500, "GetUserByName", err)
|
||||
ctx.Handle(500, "UserSignIn error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -128,27 +128,21 @@ func Http(ctx *middleware.Context) {
|
||||
return
|
||||
}
|
||||
authUsername = authUser.Name
|
||||
} else {
|
||||
// Check user's password when username is correctly presented.
|
||||
if !authUser.ValidtePassword(authPasswd) {
|
||||
ctx.Handle(401, "invalid password", nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !isPublicPull {
|
||||
var tp = models.WRITABLE
|
||||
var tp = models.ACCESS_MODE_WRITE
|
||||
if isPull {
|
||||
tp = models.READABLE
|
||||
tp = models.ACCESS_MODE_READ
|
||||
}
|
||||
|
||||
has, err := models.HasAccess(authUsername, username+"/"+reponame, tp)
|
||||
has, err := models.HasAccess(authUser, repo, tp)
|
||||
if err != nil {
|
||||
ctx.Handle(401, "no basic auth and digit auth", nil)
|
||||
return
|
||||
} else if !has {
|
||||
if tp == models.READABLE {
|
||||
has, err = models.HasAccess(authUsername, username+"/"+reponame, models.WRITABLE)
|
||||
if tp == models.ACCESS_MODE_READ {
|
||||
has, err = models.HasAccess(authUser, repo, models.ACCESS_MODE_WRITE)
|
||||
if err != nil || !has {
|
||||
ctx.Handle(401, "no basic auth and digit auth", nil)
|
||||
return
|
||||
@@ -158,10 +152,15 @@ func Http(ctx *middleware.Context) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !isPull && repo.IsMirror {
|
||||
ctx.Handle(401, "can't push to mirror", nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var f = func(rpc string, input []byte) {
|
||||
callback := func(rpc string, input []byte) {
|
||||
if rpc == "receive-pack" {
|
||||
var lastLine int64 = 0
|
||||
|
||||
@@ -190,6 +189,7 @@ func Http(ctx *middleware.Context) {
|
||||
newCommitId := fields[1]
|
||||
refName := fields[2]
|
||||
|
||||
// FIXME: handle error.
|
||||
models.Update(refName, oldCommitId, newCommitId, authUsername, username, reponame, authUser.Id)
|
||||
}
|
||||
lastLine = lastLine + size
|
||||
@@ -200,25 +200,23 @@ func Http(ctx *middleware.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
config := Config{setting.RepoRootPath, "git", true, true, f}
|
||||
HTTPBackend(&Config{
|
||||
RepoRootPath: setting.RepoRootPath,
|
||||
GitBinPath: "git",
|
||||
UploadPack: true,
|
||||
ReceivePack: true,
|
||||
OnSucceed: callback,
|
||||
})(ctx.Resp, ctx.Req.Request)
|
||||
|
||||
handler := HttpBackend(&config)
|
||||
handler(ctx.Resp, ctx.Req.Request)
|
||||
runtime.GC()
|
||||
}
|
||||
|
||||
type route struct {
|
||||
cr *regexp.Regexp
|
||||
method string
|
||||
handler func(handler)
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
ReposRoot string
|
||||
GitBinPath string
|
||||
UploadPack bool
|
||||
ReceivePack bool
|
||||
OnSucceed func(rpc string, input []byte)
|
||||
RepoRootPath string
|
||||
GitBinPath string
|
||||
UploadPack bool
|
||||
ReceivePack bool
|
||||
OnSucceed func(rpc string, input []byte)
|
||||
}
|
||||
|
||||
type handler struct {
|
||||
@@ -229,6 +227,12 @@ type handler struct {
|
||||
File string
|
||||
}
|
||||
|
||||
type route struct {
|
||||
cr *regexp.Regexp
|
||||
method string
|
||||
handler func(handler)
|
||||
}
|
||||
|
||||
var routes = []route{
|
||||
{regexp.MustCompile("(.*?)/git-upload-pack$"), "POST", serviceUploadPack},
|
||||
{regexp.MustCompile("(.*?)/git-receive-pack$"), "POST", serviceReceivePack},
|
||||
@@ -244,7 +248,7 @@ var routes = []route{
|
||||
}
|
||||
|
||||
// Request handling function
|
||||
func HttpBackend(config *Config) http.HandlerFunc {
|
||||
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
|
||||
@@ -286,8 +290,7 @@ func serviceReceivePack(hr handler) {
|
||||
func serviceRpc(rpc string, hr handler) {
|
||||
w, r, dir := hr.w, hr.r, hr.Dir
|
||||
|
||||
access := hasAccess(r, hr.Config, dir, rpc, true)
|
||||
if access == false {
|
||||
if !hasAccess(r, hr.Config, dir, rpc, true) {
|
||||
renderNoAccess(w)
|
||||
return
|
||||
}
|
||||
@@ -338,7 +341,6 @@ func serviceRpc(rpc string, hr handler) {
|
||||
if hr.Config.OnSucceed != nil {
|
||||
hr.Config.OnSucceed(rpc, input)
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
func getInfoRefs(hr handler) {
|
||||
@@ -409,7 +411,7 @@ func sendFile(contentType string, hr handler) {
|
||||
}
|
||||
|
||||
func getGitDir(config *Config, fPath string) (string, error) {
|
||||
root := config.ReposRoot
|
||||
root := config.RepoRootPath
|
||||
|
||||
if root == "" {
|
||||
cwd, err := os.Getwd()
|
||||
|
||||
@@ -174,7 +174,7 @@ func CreateIssue(ctx *middleware.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
us, err := models.GetCollaborators(strings.TrimPrefix(ctx.Repo.RepoLink, "/"))
|
||||
us, err := ctx.Repo.Repository.GetCollaborators()
|
||||
if err != nil {
|
||||
ctx.Handle(500, "issue.CreateIssue(GetCollaborators)", err)
|
||||
return
|
||||
@@ -218,7 +218,7 @@ func CreateIssuePost(ctx *middleware.Context, form auth.CreateIssueForm) {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = models.GetCollaborators(strings.TrimPrefix(ctx.Repo.RepoLink, "/"))
|
||||
_, err = ctx.Repo.Repository.GetCollaborators()
|
||||
if err != nil {
|
||||
send(500, nil, err)
|
||||
return
|
||||
@@ -230,7 +230,7 @@ func CreateIssuePost(ctx *middleware.Context, form auth.CreateIssueForm) {
|
||||
}
|
||||
|
||||
// Only collaborators can assign.
|
||||
if !ctx.Repo.IsOwner {
|
||||
if !ctx.Repo.IsOwner() {
|
||||
form.AssigneeId = 0
|
||||
}
|
||||
issue := &models.Issue{
|
||||
@@ -246,8 +246,8 @@ func CreateIssuePost(ctx *middleware.Context, form auth.CreateIssueForm) {
|
||||
if err := models.NewIssue(issue); err != nil {
|
||||
send(500, nil, err)
|
||||
return
|
||||
} else if err := models.NewIssueUserPairs(issue.RepoId, issue.Id, ctx.Repo.Owner.Id,
|
||||
ctx.User.Id, form.AssigneeId, ctx.Repo.Repository.Name); err != nil {
|
||||
} else if err := models.NewIssueUserPairs(ctx.Repo.Repository, issue.Id, ctx.Repo.Owner.Id,
|
||||
ctx.User.Id, form.AssigneeId); err != nil {
|
||||
send(500, nil, err)
|
||||
return
|
||||
}
|
||||
@@ -270,12 +270,12 @@ func CreateIssuePost(ctx *middleware.Context, form auth.CreateIssueForm) {
|
||||
}
|
||||
|
||||
act := &models.Action{
|
||||
ActUserId: ctx.User.Id,
|
||||
ActUserID: ctx.User.Id,
|
||||
ActUserName: ctx.User.Name,
|
||||
ActEmail: ctx.User.Email,
|
||||
OpType: models.CREATE_ISSUE,
|
||||
Content: fmt.Sprintf("%d|%s", issue.Index, issue.Name),
|
||||
RepoId: ctx.Repo.Repository.Id,
|
||||
RepoID: ctx.Repo.Repository.Id,
|
||||
RepoUserName: ctx.Repo.Owner.Name,
|
||||
RepoName: ctx.Repo.Repository.Name,
|
||||
RefName: ctx.Repo.BranchName,
|
||||
@@ -384,7 +384,7 @@ func ViewIssue(ctx *middleware.Context) {
|
||||
}
|
||||
|
||||
// Get all collaborators.
|
||||
ctx.Data["Collaborators"], err = models.GetCollaborators(strings.TrimPrefix(ctx.Repo.RepoLink, "/"))
|
||||
ctx.Data["Collaborators"], err = ctx.Repo.Repository.GetCollaborators()
|
||||
if err != nil {
|
||||
ctx.Handle(500, "issue.CreateIssue(GetCollaborators)", err)
|
||||
return
|
||||
@@ -434,7 +434,7 @@ func ViewIssue(ctx *middleware.Context) {
|
||||
ctx.Data["Title"] = issue.Name
|
||||
ctx.Data["Issue"] = issue
|
||||
ctx.Data["Comments"] = comments
|
||||
ctx.Data["IsIssueOwner"] = ctx.Repo.IsOwner || (ctx.IsSigned && issue.PosterId == ctx.User.Id)
|
||||
ctx.Data["IsIssueOwner"] = ctx.Repo.IsOwner() || (ctx.IsSigned && issue.PosterId == ctx.User.Id)
|
||||
ctx.Data["IsRepoToolbarIssues"] = true
|
||||
ctx.Data["IsRepoToolbarIssuesList"] = false
|
||||
ctx.HTML(200, ISSUE_VIEW)
|
||||
@@ -457,7 +457,7 @@ func UpdateIssue(ctx *middleware.Context, form auth.CreateIssueForm) {
|
||||
return
|
||||
}
|
||||
|
||||
if ctx.User.Id != issue.PosterId && !ctx.Repo.IsOwner {
|
||||
if ctx.User.Id != issue.PosterId && !ctx.Repo.IsOwner() {
|
||||
ctx.Error(403)
|
||||
return
|
||||
}
|
||||
@@ -484,7 +484,7 @@ func UpdateIssue(ctx *middleware.Context, form auth.CreateIssueForm) {
|
||||
}
|
||||
|
||||
func UpdateIssueLabel(ctx *middleware.Context) {
|
||||
if !ctx.Repo.IsOwner {
|
||||
if !ctx.Repo.IsOwner() {
|
||||
ctx.Error(403)
|
||||
return
|
||||
}
|
||||
@@ -549,6 +549,7 @@ func UpdateIssueLabel(ctx *middleware.Context) {
|
||||
label.NumClosedIssues--
|
||||
}
|
||||
}
|
||||
|
||||
if err = models.UpdateLabel(label); err != nil {
|
||||
ctx.Handle(500, "issue.UpdateIssueLabel(UpdateLabel)", err)
|
||||
return
|
||||
@@ -560,7 +561,7 @@ func UpdateIssueLabel(ctx *middleware.Context) {
|
||||
}
|
||||
|
||||
func UpdateIssueMilestone(ctx *middleware.Context) {
|
||||
if !ctx.Repo.IsOwner {
|
||||
if !ctx.Repo.IsOwner() {
|
||||
ctx.Error(403)
|
||||
return
|
||||
}
|
||||
@@ -606,7 +607,7 @@ func UpdateIssueMilestone(ctx *middleware.Context) {
|
||||
}
|
||||
|
||||
func UpdateAssignee(ctx *middleware.Context) {
|
||||
if !ctx.Repo.IsOwner {
|
||||
if !ctx.Repo.IsOwner() {
|
||||
ctx.Error(403)
|
||||
return
|
||||
}
|
||||
@@ -752,7 +753,7 @@ func Comment(ctx *middleware.Context) {
|
||||
|
||||
// Check if issue owner changes the status of issue.
|
||||
var newStatus string
|
||||
if ctx.Repo.IsOwner || issue.PosterId == ctx.User.Id {
|
||||
if ctx.Repo.IsOwner() || issue.PosterId == ctx.User.Id {
|
||||
newStatus = ctx.Query("change_status")
|
||||
}
|
||||
if len(newStatus) > 0 {
|
||||
@@ -767,6 +768,24 @@ func Comment(ctx *middleware.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if err = issue.GetLabels(); err != nil {
|
||||
send(500, nil, err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, label := range issue.Labels {
|
||||
if issue.IsClosed {
|
||||
label.NumClosedIssues++
|
||||
} else {
|
||||
label.NumClosedIssues--
|
||||
}
|
||||
|
||||
if err = models.UpdateLabel(label); err != nil {
|
||||
send(500, nil, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Change open/closed issue counter for the associated milestone
|
||||
if issue.MilestoneId > 0 {
|
||||
if err = models.ChangeMilestoneIssueStats(issue); err != nil {
|
||||
@@ -826,12 +845,12 @@ func Comment(ctx *middleware.Context) {
|
||||
|
||||
// Notify watchers.
|
||||
act := &models.Action{
|
||||
ActUserId: ctx.User.Id,
|
||||
ActUserID: ctx.User.Id,
|
||||
ActUserName: ctx.User.LowerName,
|
||||
ActEmail: ctx.User.Email,
|
||||
OpType: models.COMMENT_ISSUE,
|
||||
Content: fmt.Sprintf("%d|%s", issue.Index, strings.Split(content, "\n")[0]),
|
||||
RepoId: ctx.Repo.Repository.Id,
|
||||
RepoID: ctx.Repo.Repository.Id,
|
||||
RepoUserName: ctx.Repo.Owner.LowerName,
|
||||
RepoName: ctx.Repo.Repository.LowerName,
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ func Releases(ctx *middleware.Context) {
|
||||
tags := make([]*models.Release, len(rawTags))
|
||||
for i, rawTag := range rawTags {
|
||||
for j, rel := range rels {
|
||||
if rel == nil || (rel.IsDraft && !ctx.Repo.IsOwner) {
|
||||
if rel == nil || (rel.IsDraft && !ctx.Repo.IsOwner()) {
|
||||
continue
|
||||
}
|
||||
if rel.TagName == rawTag {
|
||||
@@ -140,7 +140,7 @@ func Releases(ctx *middleware.Context) {
|
||||
}
|
||||
|
||||
func NewRelease(ctx *middleware.Context) {
|
||||
if !ctx.Repo.IsOwner {
|
||||
if !ctx.Repo.IsOwner() {
|
||||
ctx.Handle(403, "release.ReleasesNew", nil)
|
||||
return
|
||||
}
|
||||
@@ -153,7 +153,7 @@ func NewRelease(ctx *middleware.Context) {
|
||||
}
|
||||
|
||||
func NewReleasePost(ctx *middleware.Context, form auth.NewReleaseForm) {
|
||||
if !ctx.Repo.IsOwner {
|
||||
if !ctx.Repo.IsOwner() {
|
||||
ctx.Handle(403, "release.ReleasesNew", nil)
|
||||
return
|
||||
}
|
||||
@@ -211,7 +211,7 @@ func NewReleasePost(ctx *middleware.Context, form auth.NewReleaseForm) {
|
||||
}
|
||||
|
||||
func EditRelease(ctx *middleware.Context) {
|
||||
if !ctx.Repo.IsOwner {
|
||||
if !ctx.Repo.IsOwner() {
|
||||
ctx.Handle(403, "release.ReleasesEdit", nil)
|
||||
return
|
||||
}
|
||||
@@ -234,7 +234,7 @@ func EditRelease(ctx *middleware.Context) {
|
||||
}
|
||||
|
||||
func EditReleasePost(ctx *middleware.Context, form auth.EditReleaseForm) {
|
||||
if !ctx.Repo.IsOwner {
|
||||
if !ctx.Repo.IsOwner() {
|
||||
ctx.Handle(403, "release.EditReleasePost", nil)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -181,20 +181,26 @@ func MigratePost(ctx *middleware.Context, form auth.MigrateRepoForm) {
|
||||
}
|
||||
}
|
||||
|
||||
u, err := url.Parse(form.HttpsUrl)
|
||||
|
||||
if err != nil || u.Scheme != "https" {
|
||||
ctx.Data["Err_HttpsUrl"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.url_error"), MIGRATE, &form)
|
||||
// Remote address can be HTTP/HTTPS URL or local path.
|
||||
remoteAddr := form.CloneAddr
|
||||
if strings.HasPrefix(form.CloneAddr, "http") {
|
||||
u, err := url.Parse(form.CloneAddr)
|
||||
if err != nil {
|
||||
ctx.Data["Err_CloneAddr"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.url_error"), MIGRATE, &form)
|
||||
return
|
||||
}
|
||||
if len(form.AuthUsername) > 0 || len(form.AuthPassword) > 0 {
|
||||
u.User = url.UserPassword(form.AuthUsername, form.AuthPassword)
|
||||
}
|
||||
remoteAddr = u.String()
|
||||
} else if !com.IsDir(remoteAddr) {
|
||||
ctx.Data["Err_CloneAddr"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("repo.migrate.invalid_local_path"), MIGRATE, &form)
|
||||
return
|
||||
}
|
||||
|
||||
if len(form.AuthUserName) > 0 || len(form.AuthPasswd) > 0 {
|
||||
u.User = url.UserPassword(form.AuthUserName, form.AuthPasswd)
|
||||
}
|
||||
|
||||
repo, err := models.MigrateRepository(ctxUser, form.RepoName, form.Description, form.Private,
|
||||
form.Mirror, u.String())
|
||||
repo, err := models.MigrateRepository(ctxUser, form.RepoName, form.Description, form.Private, form.Mirror, remoteAddr)
|
||||
if err == nil {
|
||||
log.Trace("Repository migrated: %s/%s", ctxUser.Name, form.RepoName)
|
||||
ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + form.RepoName)
|
||||
@@ -245,7 +251,7 @@ func Fork(ctx *middleware.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("new_fork")
|
||||
|
||||
if _, err := getForkRepository(ctx); err != nil {
|
||||
if err == models.ErrRepoNotExist {
|
||||
if models.IsErrRepoNotExist(err) {
|
||||
ctx.Redirect(setting.AppSubUrl + "/")
|
||||
} else {
|
||||
ctx.Handle(500, "getForkRepository", err)
|
||||
@@ -269,7 +275,7 @@ func ForkPost(ctx *middleware.Context, form auth.CreateRepoForm) {
|
||||
|
||||
forkRepo, err := getForkRepository(ctx)
|
||||
if err != nil {
|
||||
if err == models.ErrRepoNotExist {
|
||||
if models.IsErrRepoNotExist(err) {
|
||||
ctx.Redirect(setting.AppSubUrl + "/")
|
||||
} else {
|
||||
ctx.Handle(500, "getForkRepository", err)
|
||||
@@ -343,14 +349,14 @@ func Action(ctx *middleware.Context) {
|
||||
case "unstar":
|
||||
err = models.StarRepo(ctx.User.Id, ctx.Repo.Repository.Id, false)
|
||||
case "desc":
|
||||
if !ctx.Repo.IsOwner {
|
||||
if !ctx.Repo.IsOwner() {
|
||||
ctx.Error(404)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Repo.Repository.Description = ctx.Query("desc")
|
||||
ctx.Repo.Repository.Website = ctx.Query("site")
|
||||
err = models.UpdateRepository(ctx.Repo.Repository)
|
||||
err = models.UpdateRepository(ctx.Repo.Repository, false)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
"path"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
|
||||
@@ -54,15 +53,11 @@ func SettingsPost(ctx *middleware.Context, form auth.RepoSettingForm) {
|
||||
newRepoName := form.RepoName
|
||||
// Check if repository name has been changed.
|
||||
if ctx.Repo.Repository.Name != newRepoName {
|
||||
isExist, err := models.IsRepositoryExist(ctx.Repo.Owner, newRepoName)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "IsRepositoryExist", err)
|
||||
return
|
||||
} else if isExist {
|
||||
if models.IsRepositoryExist(ctx.Repo.Owner, newRepoName) {
|
||||
ctx.Data["Err_RepoName"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), SETTINGS_OPTIONS, nil)
|
||||
return
|
||||
} else if err = models.ChangeRepositoryName(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name, newRepoName); err != nil {
|
||||
} else if err := models.ChangeRepositoryName(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name, newRepoName); err != nil {
|
||||
if err == models.ErrRepoNameIllegal {
|
||||
ctx.Data["Err_RepoName"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.illegal_repo_name"), SETTINGS_OPTIONS, nil)
|
||||
@@ -83,9 +78,9 @@ func SettingsPost(ctx *middleware.Context, form auth.RepoSettingForm) {
|
||||
}
|
||||
ctx.Repo.Repository.Description = form.Description
|
||||
ctx.Repo.Repository.Website = form.Website
|
||||
visibilityChanged := ctx.Repo.Repository.IsPrivate != form.Private
|
||||
ctx.Repo.Repository.IsPrivate = form.Private
|
||||
ctx.Repo.Repository.IsGoget = form.GoGet
|
||||
if err := models.UpdateRepository(ctx.Repo.Repository); err != nil {
|
||||
if err := models.UpdateRepository(ctx.Repo.Repository, visibilityChanged); err != nil {
|
||||
ctx.Handle(404, "UpdateRepository", err)
|
||||
return
|
||||
}
|
||||
@@ -110,17 +105,25 @@ func SettingsPost(ctx *middleware.Context, form auth.RepoSettingForm) {
|
||||
}
|
||||
|
||||
newOwner := ctx.Query("new_owner_name")
|
||||
isExist, err := models.IsUserExist(newOwner)
|
||||
isExist, err := models.IsUserExist(0, newOwner)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "IsUserExist", err)
|
||||
return
|
||||
} else if !isExist {
|
||||
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_owner_name"), SETTINGS_OPTIONS, nil)
|
||||
return
|
||||
} else if !ctx.User.ValidtePassword(ctx.Query("password")) {
|
||||
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_password"), SETTINGS_OPTIONS, nil)
|
||||
}
|
||||
|
||||
if _, err = models.UserSignIn(ctx.User.Name, ctx.Query("password")); err != nil {
|
||||
if err == models.ErrUserNotExist {
|
||||
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_password"), SETTINGS_OPTIONS, nil)
|
||||
} else {
|
||||
ctx.Handle(500, "UserSignIn", err)
|
||||
}
|
||||
return
|
||||
} else if err = models.TransferOwnership(ctx.User, newOwner, ctx.Repo.Repository); err != nil {
|
||||
}
|
||||
|
||||
if err = models.TransferOwnership(ctx.User, newOwner, ctx.Repo.Repository); err != nil {
|
||||
if err == models.ErrRepoAlreadyExist {
|
||||
ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), SETTINGS_OPTIONS, nil)
|
||||
} else {
|
||||
@@ -142,15 +145,15 @@ func SettingsPost(ctx *middleware.Context, form auth.RepoSettingForm) {
|
||||
ctx.Error(404)
|
||||
return
|
||||
}
|
||||
if !ctx.User.ValidtePassword(ctx.Query("password")) {
|
||||
}
|
||||
|
||||
if _, err := models.UserSignIn(ctx.User.Name, ctx.Query("password")); err != nil {
|
||||
if err == models.ErrUserNotExist {
|
||||
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_password"), SETTINGS_OPTIONS, nil)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if !ctx.Repo.Owner.ValidtePassword(ctx.Query("password")) {
|
||||
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_password"), SETTINGS_OPTIONS, nil)
|
||||
return
|
||||
} else {
|
||||
ctx.Handle(500, "UserSignIn", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err := models.DeleteRepository(ctx.Repo.Owner.Id, ctx.Repo.Repository.Id, ctx.Repo.Owner.Name); err != nil {
|
||||
@@ -170,22 +173,12 @@ func SettingsCollaboration(ctx *middleware.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("repo.settings")
|
||||
ctx.Data["PageIsSettingsCollaboration"] = true
|
||||
|
||||
repoLink := path.Join(ctx.Repo.Owner.LowerName, ctx.Repo.Repository.LowerName)
|
||||
|
||||
if ctx.Req.Method == "POST" {
|
||||
name := strings.ToLower(ctx.Query("collaborator"))
|
||||
if len(name) == 0 || ctx.Repo.Owner.LowerName == name {
|
||||
ctx.Redirect(setting.AppSubUrl + ctx.Req.URL.Path)
|
||||
return
|
||||
}
|
||||
has, err := models.HasAccess(name, repoLink, models.WRITABLE)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "HasAccess", err)
|
||||
return
|
||||
} else if has {
|
||||
ctx.Redirect(setting.AppSubUrl + ctx.Req.URL.Path)
|
||||
return
|
||||
}
|
||||
|
||||
u, err := models.GetUserByName(name)
|
||||
if err != nil {
|
||||
@@ -205,9 +198,8 @@ func SettingsCollaboration(ctx *middleware.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if err = models.AddAccess(&models.Access{UserName: name, RepoName: repoLink,
|
||||
Mode: models.WRITABLE}); err != nil {
|
||||
ctx.Handle(500, "AddAccess", err)
|
||||
if err = ctx.Repo.Repository.AddCollaborator(u); err != nil {
|
||||
ctx.Handle(500, "AddCollaborator", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -226,50 +218,27 @@ func SettingsCollaboration(ctx *middleware.Context) {
|
||||
// Delete collaborator.
|
||||
remove := strings.ToLower(ctx.Query("remove"))
|
||||
if len(remove) > 0 && remove != ctx.Repo.Owner.LowerName {
|
||||
needDelete := true
|
||||
if ctx.User.IsOrganization() {
|
||||
// Check if user belongs to a team that has access to this repository.
|
||||
auth, err := models.GetHighestAuthorize(ctx.Repo.Owner.Id, ctx.User.Id, ctx.Repo.Repository.Id, 0)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "GetHighestAuthorize", err)
|
||||
return
|
||||
}
|
||||
if auth > 0 {
|
||||
needDelete = false
|
||||
}
|
||||
u, err := models.GetUserByName(remove)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "GetUserByName", err)
|
||||
return
|
||||
}
|
||||
|
||||
if needDelete {
|
||||
if err := models.DeleteAccess(&models.Access{UserName: remove, RepoName: repoLink}); err != nil {
|
||||
ctx.Handle(500, "DeleteAccess", err)
|
||||
return
|
||||
}
|
||||
if err := ctx.Repo.Repository.DeleteCollaborator(u); err != nil {
|
||||
ctx.Handle(500, "DeleteCollaborator", err)
|
||||
return
|
||||
}
|
||||
ctx.Flash.Success(ctx.Tr("repo.settings.remove_collaborator_success"))
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
|
||||
return
|
||||
}
|
||||
|
||||
names, err := models.GetCollaboratorNames(repoLink)
|
||||
users, err := ctx.Repo.Repository.GetCollaborators()
|
||||
if err != nil {
|
||||
ctx.Handle(500, "GetCollaborators", err)
|
||||
return
|
||||
}
|
||||
|
||||
collaborators := make([]*models.User, 0, len(names))
|
||||
for _, name := range names {
|
||||
u, err := models.GetUserByName(name)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "GetUserByName", err)
|
||||
return
|
||||
}
|
||||
// Does not show organization members.
|
||||
if ctx.Repo.Owner.IsOrganization() && ctx.Repo.Owner.IsOrgMember(u.Id) {
|
||||
continue
|
||||
}
|
||||
collaborators = append(collaborators, u)
|
||||
}
|
||||
ctx.Data["Collaborators"] = collaborators
|
||||
ctx.Data["Collaborators"] = users
|
||||
ctx.HTML(200, COLLABORATION)
|
||||
}
|
||||
|
||||
|
||||
@@ -141,13 +141,17 @@ func Home(ctx *middleware.Context) {
|
||||
ctx.Handle(500, "GetSubModule", err)
|
||||
return
|
||||
}
|
||||
smUrl := ""
|
||||
if sm != nil {
|
||||
smUrl = sm.Url
|
||||
}
|
||||
|
||||
c, err := ctx.Repo.Commit.GetCommitOfRelPath(filepath.Join(treePath, te.Name()))
|
||||
if err != nil {
|
||||
ctx.Handle(500, "GetCommitOfRelPath", err)
|
||||
return
|
||||
}
|
||||
files = append(files, []interface{}{te, git.NewSubModuleFile(c, sm.Url, te.Id.String())})
|
||||
files = append(files, []interface{}{te, git.NewSubModuleFile(c, smUrl, te.Id.String())})
|
||||
}
|
||||
}
|
||||
ctx.Data["Files"] = files
|
||||
|
||||
@@ -351,15 +351,12 @@ func ActivateEmail(ctx *middleware.Context) {
|
||||
|
||||
// Verify code.
|
||||
if email := models.VerifyActiveEmailCode(code, email_string); email != nil {
|
||||
err := email.Activate()
|
||||
if err != nil {
|
||||
if err := email.Activate(); err != nil {
|
||||
ctx.Handle(500, "ActivateEmail", err)
|
||||
}
|
||||
|
||||
log.Trace("Email activated: %s", email.Email)
|
||||
|
||||
ctx.Flash.Success(ctx.Tr("settings.activate_email_success"))
|
||||
|
||||
}
|
||||
|
||||
ctx.Redirect(setting.AppSubUrl + "/user/settings/email")
|
||||
|
||||
@@ -49,13 +49,19 @@ func Dashboard(ctx *middleware.Context) {
|
||||
} else {
|
||||
// Normal user.
|
||||
ctxUser = ctx.User
|
||||
collaborates, err := models.GetCollaborativeRepos(ctxUser.Name)
|
||||
collaborates, err := ctx.User.GetAccessibleRepositories()
|
||||
if err != nil {
|
||||
ctx.Handle(500, "GetCollaborativeRepos", err)
|
||||
ctx.Handle(500, "GetAccessibleRepositories", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["CollaborateCount"] = len(collaborates)
|
||||
ctx.Data["CollaborativeRepos"] = collaborates
|
||||
|
||||
repositories := make([]*models.Repository, 0, len(collaborates))
|
||||
for repo := range collaborates {
|
||||
repositories = append(repositories, repo)
|
||||
}
|
||||
|
||||
ctx.Data["CollaborateCount"] = len(repositories)
|
||||
ctx.Data["CollaborativeRepos"] = repositories
|
||||
}
|
||||
ctx.Data["ContextUser"] = ctxUser
|
||||
|
||||
@@ -97,10 +103,14 @@ func Dashboard(ctx *middleware.Context) {
|
||||
feeds := make([]*models.Action, 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
|
||||
// This prevents having to retrieve the repository for each action
|
||||
repo := &models.Repository{Id: act.RepoID, IsPrivate: true}
|
||||
if act.RepoUserName != ctx.User.LowerName {
|
||||
if has, _ := models.HasAccess(ctx.User, repo, models.ACCESS_MODE_READ); !has {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// FIXME: cache results?
|
||||
u, err := models.GetUserByName(act.ActUserName)
|
||||
@@ -205,10 +215,14 @@ func Profile(ctx *middleware.Context) {
|
||||
if !ctx.IsSigned {
|
||||
continue
|
||||
}
|
||||
if has, _ := models.HasAccess(ctx.User.Name, act.RepoUserName+"/"+act.RepoName,
|
||||
models.READABLE); !has {
|
||||
continue
|
||||
// This prevents having to retrieve the repository for each action
|
||||
repo := &models.Repository{Id: act.RepoID, IsPrivate: true}
|
||||
if act.RepoUserName != ctx.User.LowerName {
|
||||
if has, _ := models.HasAccess(ctx.User, repo, models.ACCESS_MODE_READ); !has {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// FIXME: cache results?
|
||||
u, err := models.GetUserByName(act.ActUserName)
|
||||
@@ -340,7 +354,7 @@ func Issues(ctx *middleware.Context) {
|
||||
|
||||
issues[i].Repo, err = models.GetRepositoryById(issues[i].RepoId)
|
||||
if err != nil {
|
||||
if err == models.ErrRepoNotExist {
|
||||
if models.IsErrRepoNotExist(err) {
|
||||
log.Warn("user.Issues(GetRepositoryById #%d): repository not exist", issues[i].RepoId)
|
||||
continue
|
||||
} else {
|
||||
|
||||
@@ -50,7 +50,7 @@ func SettingsPost(ctx *middleware.Context, form auth.UpdateProfileForm) {
|
||||
|
||||
// Check if user name has been changed.
|
||||
if ctx.User.Name != form.UserName {
|
||||
isExist, err := models.IsUserExist(form.UserName)
|
||||
isExist, err := models.IsUserExist(ctx.User.Id, form.UserName)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "IsUserExist", err)
|
||||
return
|
||||
@@ -58,11 +58,14 @@ func SettingsPost(ctx *middleware.Context, form auth.UpdateProfileForm) {
|
||||
ctx.RenderWithErr(ctx.Tr("form.username_been_taken"), SETTINGS_PROFILE, &form)
|
||||
return
|
||||
} else if err = models.ChangeUserName(ctx.User, form.UserName); err != nil {
|
||||
if err == models.ErrUserNameIllegal {
|
||||
switch err {
|
||||
case models.ErrUserNameIllegal:
|
||||
ctx.Flash.Error(ctx.Tr("form.illegal_username"))
|
||||
ctx.Redirect(setting.AppSubUrl + "/user/settings")
|
||||
return
|
||||
} else {
|
||||
case models.ErrEmailAlreadyUsed:
|
||||
ctx.Flash.Error(ctx.Tr("form.email_been_used"))
|
||||
ctx.Redirect(setting.AppSubUrl + "/user/settings")
|
||||
default:
|
||||
ctx.Handle(500, "ChangeUserName", err)
|
||||
}
|
||||
return
|
||||
@@ -133,13 +136,12 @@ func SettingsEmails(ctx *middleware.Context) {
|
||||
ctx.Data["PageIsUserSettings"] = true
|
||||
ctx.Data["PageIsSettingsEmails"] = true
|
||||
|
||||
var err error
|
||||
ctx.Data["Emails"], err = models.GetEmailAddresses(ctx.User.Id)
|
||||
|
||||
emails, err := models.GetEmailAddresses(ctx.User.Id)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "email.GetEmailAddresses", err)
|
||||
ctx.Handle(500, "GetEmailAddresses", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["Emails"] = emails
|
||||
|
||||
ctx.HTML(200, SETTINGS_EMAILS)
|
||||
}
|
||||
@@ -149,16 +151,16 @@ func SettingsEmailPost(ctx *middleware.Context, form auth.AddEmailForm) {
|
||||
ctx.Data["PageIsUserSettings"] = true
|
||||
ctx.Data["PageIsSettingsEmails"] = true
|
||||
|
||||
var err error
|
||||
ctx.Data["Emails"], err = models.GetEmailAddresses(ctx.User.Id)
|
||||
emails, err := models.GetEmailAddresses(ctx.User.Id)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "email.GetEmailAddresses", err)
|
||||
ctx.Handle(500, "GetEmailAddresses", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["Emails"] = emails
|
||||
|
||||
// Delete Email address.
|
||||
// Delete E-mail address.
|
||||
if ctx.Query("_method") == "DELETE" {
|
||||
id := com.StrTo(ctx.Query("id")).MustInt64()
|
||||
id := ctx.QueryInt64("id")
|
||||
if id <= 0 {
|
||||
return
|
||||
}
|
||||
@@ -174,7 +176,7 @@ func SettingsEmailPost(ctx *middleware.Context, form auth.AddEmailForm) {
|
||||
|
||||
// Make emailaddress primary.
|
||||
if ctx.Query("_method") == "PRIMARY" {
|
||||
id := com.StrTo(ctx.Query("id")).MustInt64()
|
||||
id := ctx.QueryInt64("id")
|
||||
if id <= 0 {
|
||||
return
|
||||
}
|
||||
@@ -189,46 +191,41 @@ func SettingsEmailPost(ctx *middleware.Context, form auth.AddEmailForm) {
|
||||
}
|
||||
|
||||
// Add Email address.
|
||||
if ctx.Req.Method == "POST" {
|
||||
if ctx.HasError() {
|
||||
ctx.HTML(200, SETTINGS_EMAILS)
|
||||
if ctx.HasError() {
|
||||
ctx.HTML(200, SETTINGS_EMAILS)
|
||||
return
|
||||
}
|
||||
|
||||
cleanEmail := strings.Replace(form.Email, "\n", "", -1)
|
||||
e := &models.EmailAddress{
|
||||
Uid: ctx.User.Id,
|
||||
Email: cleanEmail,
|
||||
IsActivated: !setting.Service.RegisterEmailConfirm,
|
||||
}
|
||||
|
||||
if err := models.AddEmailAddress(e); err != nil {
|
||||
if err == models.ErrEmailAlreadyUsed {
|
||||
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), SETTINGS_EMAILS, &form)
|
||||
return
|
||||
}
|
||||
ctx.Handle(500, "AddEmailAddress", err)
|
||||
return
|
||||
} else {
|
||||
// Send confirmation e-mail
|
||||
if setting.Service.RegisterEmailConfirm {
|
||||
mailer.SendActivateEmail(ctx.Render, ctx.User, e)
|
||||
|
||||
cleanEmail := strings.Replace(form.Email, "\n", "", -1)
|
||||
e := &models.EmailAddress{
|
||||
Uid: ctx.User.Id,
|
||||
Email: cleanEmail,
|
||||
IsActivated: !setting.Service.RegisterEmailConfirm,
|
||||
}
|
||||
|
||||
if err := models.AddEmailAddress(e); err != nil {
|
||||
if err == models.ErrEmailAlreadyUsed {
|
||||
ctx.RenderWithErr(ctx.Tr("form.email_has_been_used"), SETTINGS_EMAILS, &form)
|
||||
return
|
||||
if err := ctx.Cache.Put("MailResendLimit_"+ctx.User.LowerName, ctx.User.LowerName, 180); err != nil {
|
||||
log.Error(4, "Set cache(MailResendLimit) fail: %v", err)
|
||||
}
|
||||
ctx.Handle(500, "email.AddEmailAddress", err)
|
||||
return
|
||||
ctx.Flash.Info(ctx.Tr("settings.add_email_confirmation_sent", cleanEmail, setting.Service.ActiveCodeLives/60))
|
||||
} else {
|
||||
|
||||
// Send confirmation e-mail
|
||||
if setting.Service.RegisterEmailConfirm {
|
||||
mailer.SendActivateEmail(ctx.Render, ctx.User, e)
|
||||
|
||||
if err := ctx.Cache.Put("MailResendLimit_"+ctx.User.LowerName, ctx.User.LowerName, 180); err != nil {
|
||||
log.Error(4, "Set cache(MailResendLimit) fail: %v", err)
|
||||
}
|
||||
ctx.Flash.Success(ctx.Tr("settings.add_email_success_confirmation_email_sent"))
|
||||
} else {
|
||||
ctx.Flash.Success(ctx.Tr("settings.add_email_success"))
|
||||
}
|
||||
|
||||
log.Trace("Email address added: %s", e.Email)
|
||||
|
||||
ctx.Redirect(setting.AppSubUrl + "/user/settings/email")
|
||||
return
|
||||
ctx.Flash.Success(ctx.Tr("settings.add_email_success"))
|
||||
}
|
||||
|
||||
log.Trace("Email address added: %s", e.Email)
|
||||
ctx.Redirect(setting.AppSubUrl + "/user/settings/email")
|
||||
return
|
||||
}
|
||||
|
||||
ctx.HTML(200, SETTINGS_EMAILS)
|
||||
@@ -454,20 +451,13 @@ func SettingsDelete(ctx *middleware.Context) {
|
||||
ctx.Data["PageIsSettingsDelete"] = true
|
||||
|
||||
if ctx.Req.Method == "POST" {
|
||||
// tmpUser := models.User{
|
||||
// Passwd: ctx.Query("password"),
|
||||
// Salt: ctx.User.Salt,
|
||||
// }
|
||||
// tmpUser.EncodePasswd()
|
||||
// if tmpUser.Passwd != ctx.User.Passwd {
|
||||
// ctx.Flash.Error("Password is not correct. Make sure you are owner of this account.")
|
||||
// } else {
|
||||
// FIXME: validate password.
|
||||
if err := models.DeleteUser(ctx.User); err != nil {
|
||||
switch err {
|
||||
case models.ErrUserOwnRepos:
|
||||
switch {
|
||||
case models.IsErrUserOwnRepos(err):
|
||||
ctx.Flash.Error(ctx.Tr("form.still_own_repo"))
|
||||
ctx.Redirect(setting.AppSubUrl + "/user/settings/delete")
|
||||
case models.ErrUserHasOrgs:
|
||||
case models.IsErrUserHasOrgs(err):
|
||||
ctx.Flash.Error(ctx.Tr("form.still_has_org"))
|
||||
ctx.Redirect(setting.AppSubUrl + "/user/settings/delete")
|
||||
default:
|
||||
|
||||
@@ -28,7 +28,6 @@ GOGS_HOME=/home/git/gogs
|
||||
GOGS_PATH=${GOGS_HOME}/$NAME
|
||||
GOGS_USER=git
|
||||
SERVICENAME="Gogs Go Git Service"
|
||||
PID=/var/run/$NAME.pid
|
||||
LOCKFILE=/var/lock/subsys/gogs
|
||||
LOGFILE=${GOGS_HOME}/log/gogs.log
|
||||
RETVAL=0
|
||||
@@ -39,7 +38,7 @@ RETVAL=0
|
||||
# Don't do anything if nothing is installed
|
||||
[ -x ${GOGS_PATH} ] || exit 0
|
||||
|
||||
DAEMON_OPTS=""
|
||||
DAEMON_OPTS="--check $NAME"
|
||||
|
||||
# Set additional options, if any
|
||||
[ ! -z "$GOGS_USER" ] && DAEMON_OPTS="$DAEMON_OPTS --user=${GOGS_USER}"
|
||||
@@ -47,8 +46,7 @@ DAEMON_OPTS=""
|
||||
start() {
|
||||
cd ${GOGS_HOME}
|
||||
echo -n "Starting ${SERVICENAME}: "
|
||||
daemon $DAEMON_OPTS --pidfile=${PID} "${GOGS_PATH} web 2>&1 > ${LOGFILE} &"
|
||||
echo $! > ${PID}
|
||||
daemon $DAEMON_OPTS "${GOGS_PATH} web > ${LOGFILE} 2>&1 &"
|
||||
RETVAL=$?
|
||||
echo
|
||||
[ $RETVAL = 0 ] && touch ${LOCKFILE}
|
||||
@@ -59,10 +57,10 @@ start() {
|
||||
stop() {
|
||||
cd ${GOGS_HOME}
|
||||
echo -n "Shutting down ${SERVICENAME}: "
|
||||
killproc -p ${PID} ${NAME}
|
||||
killproc ${NAME}
|
||||
RETVAL=$?
|
||||
echo
|
||||
[ $RETVAL = 0 ] && rm -f ${LOCKFILE} ${PID}
|
||||
[ $RETVAL = 0 ] && rm -f ${LOCKFILE}
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
@@ -74,7 +72,7 @@ case "$1" in
|
||||
stop
|
||||
;;
|
||||
status)
|
||||
status -p ${PID} ${NAME}
|
||||
status ${NAME}
|
||||
;;
|
||||
restart)
|
||||
stop
|
||||
|
||||
5
scripts/less.sh
Executable file
5
scripts/less.sh
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
echo "compiling LESS Files"
|
||||
lessc ../public/ng/less/gogs.less ../public/ng/css/gogs.css
|
||||
lessc ../public/ng/less/ui.less ../public/ng/css/ui.css
|
||||
echo "done"
|
||||
@@ -1,15 +0,0 @@
|
||||
#!/bin/sh -
|
||||
# Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
# Use of this source code is governed by a MIT-style
|
||||
# license that can be found in the LICENSE file.
|
||||
#
|
||||
# MUST EXECUTE THIS AT ROOT DIRECTORY: ./scripts/start.sh
|
||||
#
|
||||
IFS='
|
||||
'
|
||||
PATH=/bin:/usr/bin:/usr/local/bin
|
||||
USER=$(whoami)
|
||||
HOME=$(grep "^$USER:" /etc/passwd | cut -d: -f6)
|
||||
export USER HOME PATH
|
||||
|
||||
cd "$(dirname "$0")/.." && exec ./gogs web
|
||||
@@ -1,5 +1,5 @@
|
||||
[Unit]
|
||||
Description=Gogs (Go Git Service) server
|
||||
Description=Gogs (Go Git Service)
|
||||
After=syslog.target
|
||||
After=network.target
|
||||
#After=mysqld.service
|
||||
@@ -11,8 +11,10 @@ After=network.target
|
||||
Type=simple
|
||||
User=git
|
||||
Group=git
|
||||
ExecStart=/home/git/gogs/gogs/start.sh
|
||||
WorkingDirectory=/home/git/gogs
|
||||
ExecStart=/home/git/gogs/gogs web
|
||||
Restart=always
|
||||
Environment="USER=git","HOME=/home/git"
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
@@ -1 +1 @@
|
||||
0.5.13.0212 Beta
|
||||
0.6.0.0319 Beta
|
||||
@@ -12,7 +12,7 @@
|
||||
<div class="panel-header">
|
||||
<strong>{{.i18n.Tr "admin.auths.edit"}}</strong>
|
||||
</div>
|
||||
<form class="form form-align panel-body" id="auth-setting-form" action="{{AppSubUrl}}/admin/auths/{{.Source.Id}}" data-delete-url="/admin/auths/{{.Source.Id}}/delete" method="post">
|
||||
<form class="form form-align panel-body" id="auth-setting-form" action="{{AppSubUrl}}/admin/auths/{{.Source.Id}}" data-delete-url="{{AppSubUrl}}/admin/auths/{{.Source.Id}}/delete" method="post">
|
||||
{{.CsrfTokenHtml}}
|
||||
<input type="hidden" value="{{.Source.Id}}" name="id"/>
|
||||
{{$type := .Source.Type}}
|
||||
@@ -48,8 +48,20 @@
|
||||
<input class="ipt ipt-large ipt-radius {{if .Err_BaseDN}}ipt-error{{end}}" id="base_dn" name="base_dn" value="{{.Source.LDAP.BaseDN}}" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="req" for="attributes">{{.i18n.Tr "admin.auths.attributes"}}</label>
|
||||
<input class="ipt ipt-large ipt-radius {{if .Err_Attributes}}ipt-error{{end}}" id="attributes" name="attributes" value="{{.Source.LDAP.Attributes}}" />
|
||||
<label class="req" for="attribute_username">{{.i18n.Tr "admin.auths.attribute_username"}}</label>
|
||||
<input class="ipt ipt-large ipt-radius {{if .Err_Attributes}}ipt-error{{end}}" id="attribute_username" name="attribute_username" value="{{.Source.LDAP.AttributeUsername}}" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="req" for="attribute_name">{{.i18n.Tr "admin.auths.attribute_name"}}</label>
|
||||
<input class="ipt ipt-large ipt-radius {{if .Err_Attributes}}ipt-error{{end}}" id="attribute_name" name="attribute_name" value="{{.Source.LDAP.AttributeName}}" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="req" for="attribute_surname">{{.i18n.Tr "admin.auths.attribute_surname"}}</label>
|
||||
<input class="ipt ipt-large ipt-radius {{if .Err_Attributes}}ipt-error{{end}}" id="attribute_surname" name="attribute_surname" value="{{.Source.LDAP.AttributeSurname}}" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="req" for="attribute_mail">{{.i18n.Tr "admin.auths.attribute_mail"}}</label>
|
||||
<input class="ipt ipt-large ipt-radius {{if .Err_Attributes}}ipt-error{{end}}" id="attribute_mail" name="attribute_mail" value="{{.Source.LDAP.AttributeMail}}" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="req" for="filter">{{.i18n.Tr "admin.auths.filter"}}</label>
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
<td><a href="{{AppSubUrl}}/admin/auths/{{.Id}}">{{.Name}}</a></td>
|
||||
<td>{{.TypeString}}</td>
|
||||
<td><i class="fa fa{{if .IsActived}}-check{{end}}-square-o"></i></td>
|
||||
<td><span title="{{DateFormat .Updated "r"}}">{{DateFormat .Updated "M d, Y"}}</span></td>
|
||||
<td><span title="{{DateFormat .Created "r"}}">{{DateFormat .Created "M d, Y"}}</span></td>
|
||||
<td><span title="{{DateFmtLong .Updated}}">{{DateFmtShort .Updated}}</span></td>
|
||||
<td><span title="{{DateFmtLong .Created}}">{{DateFmtShort .Created}}</span></td>
|
||||
<td><a href="{{AppSubUrl}}/admin/auths/{{.Id}}"><i class="fa fa-pencil-square-o"></i></a></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<td>{{.NumTeams}}</td>
|
||||
<td>{{.NumMembers}}</td>
|
||||
<td>{{.NumRepos}}</td>
|
||||
<td><span title="{{DateFormat .Created "r"}}">{{DateFormat .Created "M d, Y"}}</span></td>
|
||||
<td><span title="{{DateFmtLong .Created}}">{{DateFmtShort .Created}}</span></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
<td>{{.NumWatches}}</td>
|
||||
<td>{{.NumStars}}</td>
|
||||
<td>{{.NumIssues}}</td>
|
||||
<td><span title="{{DateFormat .Created "r"}}">{{DateFormat .Created "M d, Y"}}</span></td>
|
||||
<td><span title="{{DateFmtLong .Created}}">{{DateFmtShort .Created}}</span></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div class="panel-header">
|
||||
<strong>{{.i18n.Tr "admin.users.edit_account"}}</strong>
|
||||
</div>
|
||||
<form class="form form-align panel-body" id="user-profile-form" action="{{AppSubUrl}}/admin/users/{{.User.Id}}" method="post" data-delete-url="/admin/users/{{.User.Id}}/delete">
|
||||
<form class="form form-align panel-body" id="user-profile-form" action="{{AppSubUrl}}/admin/users/{{.User.Id}}" method="post" data-delete-url="{{AppSubUrl}}/admin/users/{{.User.Id}}/delete">
|
||||
{{.CsrfTokenHtml}}
|
||||
<div class="field">
|
||||
<label class="req">{{.i18n.Tr "admin.users.auth_source"}}</label>
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
<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>
|
||||
<td>{{.NumRepos}}</td>
|
||||
<td><span title="{{DateFormat .Created "r"}}">{{DateFormat .Created "M d, Y"}}</span></td>
|
||||
<td><span title="{{DateFmtLong .Created}}">{{DateFmtShort .Created }}</span></td>
|
||||
<td><a href="{{AppSubUrl}}/admin/users/{{.Id}}"><i class="fa fa-pencil-square-o"></i></a></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<meta name="description" content="Gogs(Go Git Service) is a GitHub-like clone in the Go Programming Language" />
|
||||
<meta name="keywords" content="go, git">
|
||||
<meta name="_csrf" content="{{.CsrfToken}}" />
|
||||
{{if .Repository.IsGoget}}<meta name="go-import" content="{{.GoGetImport}} git {{.CloneLink.HTTPS}}">{{end}}
|
||||
{{if .GoGetImport}}<meta name="go-import" content="{{.GoGetImport}} git {{.CloneLink.HTTPS}}">{{end}}
|
||||
|
||||
<!-- Stylesheets -->
|
||||
{{if CdnMode}}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{{if .Flash.ErrorMsg}}<span class="alert alert-red alert-radius block text-bold"><i class="octicon octicon-alert"></i>{{.Flash.ErrorMsg}}</span>{{end}}
|
||||
{{if .Flash.SuccessMsg}}<div class="alert alert-green alert-radius block"><i class="octicon octicon-check"></i>{{.Flash.SuccessMsg}}</div>{{end}}
|
||||
{{if .Flash.InfoMsg}}<div class="alert alert-blue alert-radius block"><i class="octicon octicon-info"></i>{{.Flash.InfoMsg}}</div>{{end}}
|
||||
{{if .Flash.ErrorMsg}}<span class="alert alert-red alert-radius block text-bold"><i class="octicon octicon-alert"></i>{{.Flash.ErrorMsg|Str2html}}</span>{{end}}
|
||||
{{if .Flash.SuccessMsg}}<div class="alert alert-green alert-radius block"><i class="octicon octicon-check"></i>{{.Flash.SuccessMsg|Str2html}}</div>{{end}}
|
||||
{{if .Flash.InfoMsg}}<div class="alert alert-blue alert-radius block"><i class="octicon octicon-info"></i>{{.Flash.InfoMsg|Str2html}}</div>{{end}}
|
||||
@@ -1,7 +1,7 @@
|
||||
</div>
|
||||
<footer id="footer">
|
||||
<div class="container clear">
|
||||
<p class="left" id="footer-rights">© 2015 GoGits · {{.i18n.Tr "version"}}: {{AppVer}} · {{.i18n.Tr "page"}}: <strong>{{LoadTimes .PageStartTime}}</strong> ·
|
||||
<p class="left" id="footer-rights">© 2015 Gogs · {{.i18n.Tr "version"}}: {{AppVer}} · {{.i18n.Tr "page"}}: <strong>{{LoadTimes .PageStartTime}}</strong> ·
|
||||
{{.i18n.Tr "template"}}: <strong>{{call .TmplLoadTimes}}</strong></p>
|
||||
|
||||
<div class="right" id="footer-links">
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<meta name="description" content="Gogs(Go Git Service) a painless self-hosted Git Service written in Go" />
|
||||
<meta name="keywords" content="go, git, self-hosted, gogs">
|
||||
<meta name="_csrf" content="{{.CsrfToken}}" />
|
||||
{{if .Repository.IsGoget}}<meta name="go-import" content="{{.GoGetImport}} git {{.CloneLink.HTTPS}}">{{end}}
|
||||
{{if .GoGetImport}}<meta name="go-import" content="{{.GoGetImport}} git {{.CloneLink.HTTPS}}">{{end}}
|
||||
|
||||
<link rel="shortcut icon" href="{{AppSubUrl}}/img/favicon.png" />
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="container">
|
||||
<a class="text-black left" href="{{AppSubUrl}}/org/{{.Org.LowerName}}">
|
||||
<img class="avatar-48 left" src="{{.Org.AvatarLink}}?s=100">
|
||||
<span class="org-name">{{.Org.FullName}}</span>
|
||||
<span class="org-name">{{if .Org.FullName}}{{.Org.FullName}}{{else}}{{.Org.Name}}{{end}}</span>
|
||||
</a>
|
||||
<ul class="menu menu-line container">
|
||||
<li class="right">
|
||||
|
||||
@@ -9,85 +9,85 @@
|
||||
{{if .IsOrganizationOwner}}<a class="text-grey" href="{{.OrgLink}}/settings"><span class="octicon octicon-gear"></span></a>{{end}}
|
||||
</h2>
|
||||
{{if .Org.Description}}<p>{{.Org.Description}}</p>{{end}}
|
||||
<ul class="text-grey">
|
||||
{{if .Org.Location}}<li><span class="octicon octicon-location"></span> <span>{{.Org.Location}}</span></li>{{end}}
|
||||
{{if .Org.Website}}<li><span class="octicon octicon-link"></span> <a target="_blank" href="{{.Org.Website}}">{{.Org.Website}}</a></li>{{end}}
|
||||
{{if .Org.Email}}<li><span class="octicon octicon-mail"></span> <a href="mailto:{{.Org.Email}}">{{.Org.Email}}</a></li>{{end}}
|
||||
</ul>
|
||||
<ul class="text-grey">
|
||||
{{if .Org.Location}}<li><span class="octicon octicon-location"></span> <span>{{.Org.Location}}</span></li>{{end}}
|
||||
{{if .Org.Website}}<li><span class="octicon octicon-link"></span> <a target="_blank" href="{{.Org.Website}}">{{.Org.Website}}</a></li>{{end}}
|
||||
{{if .Org.Email}}<li><span class="octicon octicon-mail"></span> <a href="mailto:{{.Org.Email}}">{{.Org.Email}}</a></li>{{end}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
{{$isMember := .Org.IsOrgMember $.SignedUser.Id}}
|
||||
<div id="org-home-repo-list" class="left grid-2-3">
|
||||
<div class="clear">
|
||||
{{if .IsOrganizationOwner}}
|
||||
<a class="btn btn-green btn-large btn-link btn-radius right" href="{{AppSubUrl}}/repo/create?org={{.Org.Id}}"><i class="octicon octicon-repo-create"></i> {{.i18n.Tr "new_repo"}}</a>
|
||||
{{end}}
|
||||
</div>
|
||||
<div id="org-repo-list">
|
||||
{{range .Repos}}
|
||||
{{if .HasAccess $.SignedUser.Name}}
|
||||
<div class="org-repo-item">
|
||||
<ul class="org-repo-status right">
|
||||
<li><i class="octicon octicon-star"></i> {{.NumStars}}</li>
|
||||
<li><i class="octicon octicon-git-branch"></i> {{.NumForks}}</li>
|
||||
</ul>
|
||||
<h2><a href="{{AppSubUrl}}/{{$.Org.Name}}/{{.Name}}">{{.Name}}</a></h2>
|
||||
<p class="org-repo-description">{{.Description}}</p>
|
||||
<p class="org-repo-updated">{{$.i18n.Tr "org.repo_updated"}} {{TimeSince .Updated $.i18n.Lang}}</p>
|
||||
</div>
|
||||
{{end}}
|
||||
<div id="org-home-repo-list" class="left grid-2-3">
|
||||
<div class="clear">
|
||||
{{if .IsOrganizationOwner}}
|
||||
<a class="btn btn-green btn-large btn-link btn-radius right" href="{{AppSubUrl}}/repo/create?org={{.Org.Id}}"><i class="octicon octicon-repo-create"></i> {{.i18n.Tr "new_repo"}}</a>
|
||||
{{end}}
|
||||
</div>
|
||||
<div id="org-repo-list">
|
||||
{{range .Repos}}
|
||||
{{if or (not .IsPrivate) (.HasAccess $.SignedUser)}}
|
||||
<div class="org-repo-item">
|
||||
<ul class="org-repo-status right">
|
||||
<li><i class="octicon octicon-star"></i> {{.NumStars}}</li>
|
||||
<li><i class="octicon octicon-git-branch"></i> {{.NumForks}}</li>
|
||||
</ul>
|
||||
<h2><a href="{{AppSubUrl}}/{{$.Org.Name}}/{{.Name}}">{{.Name}}</a></h2>
|
||||
<p class="org-repo-description">{{.Description}}</p>
|
||||
<p class="org-repo-updated">{{$.i18n.Tr "org.repo_updated"}} {{TimeSince .Updated $.i18n.Lang}}</p>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="grid-1-3 right">
|
||||
<div class="org-sidebar">
|
||||
<div class="panel panel-radius">
|
||||
<div class="panel-header">
|
||||
{{if $isMember}}
|
||||
<a class="text-grey right" href="{{AppSubUrl}}/org/{{.Org.LowerName}}/members"><strong>{{.Org.NumMembers}}</strong><span class="octicon octicon-chevron-right"></span></a>
|
||||
{{end}}
|
||||
<strong>{{.i18n.Tr "org.people"}}</strong>
|
||||
</div>
|
||||
<div class="panel-body member-avatar-group">
|
||||
{{range .Members}}
|
||||
</div>
|
||||
<div class="grid-1-3 right">
|
||||
<div class="org-sidebar">
|
||||
<div class="panel panel-radius">
|
||||
<div class="panel-header">
|
||||
{{if $isMember}}
|
||||
<a class="text-grey right" href="{{AppSubUrl}}/org/{{.Org.LowerName}}/members"><strong>{{.Org.NumMembers}}</strong><span class="octicon octicon-chevron-right"></span></a>
|
||||
{{end}}
|
||||
<strong>{{.i18n.Tr "org.people"}}</strong>
|
||||
</div>
|
||||
<div class="panel-body member-avatar-group">
|
||||
{{range .Members}}
|
||||
{{if or $isMember (.IsPublicMember $.Org.Id)}}
|
||||
<a href="{{AppSubUrl}}/{{.Name}}" title="{{.Name}}"><img src="{{.AvatarLink}}"></a>
|
||||
{{end}}
|
||||
<a href="{{AppSubUrl}}/{{.Name}}" title="{{.Name}}"><img src="{{.AvatarLink}}"></a>
|
||||
{{end}}
|
||||
</div>
|
||||
{{if .IsOrganizationOwner}}
|
||||
<div class="panel-footer">
|
||||
<a class="btn btn-medium btn-blue btn-link btn-radius" href="{{AppSubUrl}}/org/{{.Org.LowerName}}/invitations/new">{{.i18n.Tr "org.invite_someone"}}</a>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{if $isMember}}
|
||||
<br>
|
||||
<div class="panel panel-radius">
|
||||
<div class="panel-header">
|
||||
<a class="text-grey right" href="{{AppSubUrl}}/org/{{.Org.LowerName}}/teams"><strong>{{.Org.NumTeams}}</strong><span class="octicon octicon-chevron-right"></span></a>
|
||||
<strong>{{.i18n.Tr "org.teams"}}</strong>
|
||||
</div>
|
||||
<div class="panel-body" id="org-home-team-list">
|
||||
<ul>
|
||||
{{range .Teams}}
|
||||
<li>
|
||||
<a class="text-black" href="{{AppSubUrl}}/org/{{$.Org.LowerName}}/teams/{{.LowerName}}"><strong class="team-name">{{.Name}}</strong></a>
|
||||
<p class="team-meta">{{.NumMembers}} {{$.i18n.Tr "org.lower_members"}} · {{.NumRepos}} {{$.i18n.Tr "org.lower_repositories"}}</p>
|
||||
</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
</div>
|
||||
{{if .IsOrganizationOwner}}
|
||||
<div class="panel-footer">
|
||||
<a class="btn btn-medium btn-blue btn-link btn-radius" href="{{AppSubUrl}}/org/{{$.Org.LowerName}}/teams/new">{{.i18n.Tr "org.create_new_team"}}</a>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
{{if .IsOrganizationOwner}}
|
||||
<div class="panel-footer">
|
||||
<a class="btn btn-medium btn-blue btn-link btn-radius" href="{{AppSubUrl}}/org/{{.Org.LowerName}}/invitations/new">{{.i18n.Tr "org.invite_someone"}}</a>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{if $isMember}}
|
||||
<br>
|
||||
<div class="panel panel-radius">
|
||||
<div class="panel-header">
|
||||
<a class="text-grey right" href="{{AppSubUrl}}/org/{{.Org.LowerName}}/teams"><strong>{{.Org.NumTeams}}</strong><span class="octicon octicon-chevron-right"></span></a>
|
||||
<strong>{{.i18n.Tr "org.teams"}}</strong>
|
||||
</div>
|
||||
<div class="panel-body" id="org-home-team-list">
|
||||
<ul>
|
||||
{{range .Teams}}
|
||||
<li>
|
||||
<a class="text-black" href="{{AppSubUrl}}/org/{{$.Org.LowerName}}/teams/{{.LowerName}}"><strong class="team-name">{{.Name}}</strong></a>
|
||||
<p class="team-meta">{{.NumMembers}} {{$.i18n.Tr "org.lower_members"}} · {{.NumRepos}} {{$.i18n.Tr "org.lower_repositories"}}</p>
|
||||
</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
</div>
|
||||
{{if .IsOrganizationOwner}}
|
||||
<div class="panel-footer">
|
||||
<a class="btn btn-medium btn-blue btn-link btn-radius" href="{{AppSubUrl}}/org/{{$.Org.LowerName}}/teams/new">{{.i18n.Tr "org.create_new_team"}}</a>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{template "ng/base/footer" .}}
|
||||
@@ -1,12 +1,12 @@
|
||||
<div id="setting-menu" class="grid-1-5 panel panel-radius left">
|
||||
<div class="panel-header">
|
||||
<strong>{{.i18n.Tr "org.settings"}}</strong>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<ul class="menu menu-vertical switching-list grid-1-5 left">
|
||||
<li {{if .PageIsSettingsOptions}}class="current"{{end}}><a href="{{AppSubUrl}}/org/{{.Org.LowerName}}/settings">{{.i18n.Tr "org.settings.options"}}</a></li>
|
||||
<li {{if .PageIsSettingsHooks}}class="current"{{end}}><a href="{{AppSubUrl}}/org/{{.Org.LowerName}}/settings/hooks">{{.i18n.Tr "repo.settings.hooks"}}</a></li>
|
||||
<li {{if .PageIsSettingsDelete}}class="current"{{end}}><a href="{{AppSubUrl}}/org/{{.Org.LowerName}}/settings/delete">{{.i18n.Tr "org.settings.delete"}}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="panel-header">
|
||||
<strong>{{.i18n.Tr "org.settings"}}</strong>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<ul class="menu menu-vertical switching-list grid-1-5 left">
|
||||
<li {{if .PageIsSettingsOptions}}class="current"{{end}}><a href="{{AppSubUrl}}/org/{{.Org.Name}}/settings">{{.i18n.Tr "org.settings.options"}}</a></li>
|
||||
<li {{if .PageIsSettingsHooks}}class="current"{{end}}><a href="{{AppSubUrl}}/org/{{.Org.Name}}/settings/hooks">{{.i18n.Tr "repo.settings.hooks"}}</a></li>
|
||||
<li {{if .PageIsSettingsDelete}}class="current"{{end}}><a href="{{AppSubUrl}}/org/{{.Org.Name}}/settings/delete">{{.i18n.Tr "org.settings.delete"}}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user