mirror of
https://github.com/gogs/gogs.git
synced 2026-02-28 17:20:59 +01:00
Compare commits
77 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb005f3f9a | ||
|
|
e6dbfd918c | ||
|
|
c2f0711db0 | ||
|
|
92153fd898 | ||
|
|
a9d2480c7f | ||
|
|
fd70d503e0 | ||
|
|
8b73c8076f | ||
|
|
971a96a962 | ||
|
|
e9838a83ce | ||
|
|
837fc9847d | ||
|
|
7e883f891a | ||
|
|
e19a69442d | ||
|
|
ebd95dd082 | ||
|
|
f7b7d008b6 | ||
|
|
b39454ca16 | ||
|
|
00943a025f | ||
|
|
600f748cb0 | ||
|
|
038b107c3d | ||
|
|
c6e08d76fd | ||
|
|
6daac151b8 | ||
|
|
e08161a302 | ||
|
|
341eafcf04 | ||
|
|
dd649eb4cc | ||
|
|
d43f5f17fd | ||
|
|
193cc3ba9a | ||
|
|
fd667ca1d8 | ||
|
|
9d40b8a83c | ||
|
|
b0169ba064 | ||
|
|
9ace35ee8b | ||
|
|
ca2cfaf71e | ||
|
|
b06f299748 | ||
|
|
beea014343 | ||
|
|
70072e2842 | ||
|
|
f0086e66ae | ||
|
|
7fe13e72d8 | ||
|
|
87f0ce793d | ||
|
|
25cf755f30 | ||
|
|
c7a8051a71 | ||
|
|
a47553b7aa | ||
|
|
d7954014a4 | ||
|
|
429345b9df | ||
|
|
eaab01fa49 | ||
|
|
4f9c5981a9 | ||
|
|
b3757e424f | ||
|
|
2381fe72cb | ||
|
|
e28bc7023f | ||
|
|
aff8fb28bd | ||
|
|
6a543c8066 | ||
|
|
4d90527a6e | ||
|
|
c64b842df9 | ||
|
|
27c4252548 | ||
|
|
10b93efc4a | ||
|
|
0696d430c9 | ||
|
|
68b231bd89 | ||
|
|
6ec859f2b0 | ||
|
|
452551fa23 | ||
|
|
ec05c64ead | ||
|
|
cd15a17970 | ||
|
|
6072e9a52c | ||
|
|
b78e03934d | ||
|
|
3c0d162961 | ||
|
|
48cf9edcf5 | ||
|
|
0c8c1ee96f | ||
|
|
7d80c5a722 | ||
|
|
5ec21d56ef | ||
|
|
266c8f5a85 | ||
|
|
162504e90c | ||
|
|
5ea0592f61 | ||
|
|
054e97d614 | ||
|
|
28983c94ff | ||
|
|
0cfa489cf0 | ||
|
|
e0af5c280d | ||
|
|
d21dc0da78 | ||
|
|
60aca9ea18 | ||
|
|
6a8ad0b357 | ||
|
|
bd970b8b27 | ||
|
|
0f3155660e |
1
.github/ISSUE_TEMPLATE.md
vendored
1
.github/ISSUE_TEMPLATE.md
vendored
@@ -13,6 +13,7 @@ The issue will be closed without any reasons if it does not satisfy any of follo
|
||||
- Database (use `[x]`):
|
||||
- [ ] PostgreSQL
|
||||
- [ ] MySQL
|
||||
- [ ] MSSQL
|
||||
- [ ] SQLite
|
||||
- Can you reproduce the bug at https://try.gogs.io:
|
||||
- [ ] Yes (provide example URL)
|
||||
|
||||
@@ -20,7 +20,7 @@ github.com/go-xorm/xorm = commit:19f6dfc
|
||||
github.com/gogits/chardet = commit:2404f77
|
||||
github.com/gogits/cron = commit:2fc07a4
|
||||
github.com/gogits/git-module = commit:1b9552b
|
||||
github.com/gogits/go-gogs-client = commit:98046bb
|
||||
github.com/gogits/go-gogs-client = commit:264a3d5
|
||||
github.com/gogits/go-libravatar = commit:cd1abbd
|
||||
github.com/issue9/identicon = commit:d36b545
|
||||
github.com/jaytaylor/html2text = commit:d16d412
|
||||
|
||||
@@ -19,6 +19,8 @@ targets:
|
||||
centos-6: &el
|
||||
build_dependencies:
|
||||
- pam-devel
|
||||
# required for go buildpack
|
||||
- perl-Digest-SHA
|
||||
dependencies:
|
||||
- pam
|
||||
- git
|
||||
@@ -26,7 +28,7 @@ targets:
|
||||
<<: *el
|
||||
before:
|
||||
- mv packager/Procfile .
|
||||
- mv packager/.godir .
|
||||
after:
|
||||
- mv bin/main gogs
|
||||
- mv bin/gogs gogs
|
||||
after_install: ./packager/hooks/postinst
|
||||
buildpack: https://github.com/heroku/heroku-buildpack-go.git#v62
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
FROM aarch64/alpine:3.5
|
||||
MAINTAINER atzoum@gmail.com
|
||||
|
||||
# Install system utils & Gogs runtime dependencies
|
||||
ADD https://github.com/tianon/gosu/releases/download/1.9/gosu-arm64 /usr/sbin/gosu
|
||||
@@ -8,9 +7,12 @@ RUN chmod +x /usr/sbin/gosu \
|
||||
|
||||
ENV GOGS_CUSTOM /data/gogs
|
||||
|
||||
COPY . /app/gogs/
|
||||
WORKDIR /app/gogs/
|
||||
RUN ./docker/build.sh
|
||||
COPY . /app/gogs/build
|
||||
WORKDIR /app/gogs/build
|
||||
|
||||
RUN ./docker/build-go.sh \
|
||||
&& ./docker/build.sh \
|
||||
&& ./docker/finalize.sh
|
||||
|
||||
# Configure LibC Name Service
|
||||
COPY docker/nsswitch.conf /etc/nsswitch.conf
|
||||
@@ -18,5 +20,5 @@ COPY docker/nsswitch.conf /etc/nsswitch.conf
|
||||
# Configure Docker Container
|
||||
VOLUME ["/data"]
|
||||
EXPOSE 22 3000
|
||||
ENTRYPOINT ["docker/start.sh"]
|
||||
ENTRYPOINT ["/app/gogs/docker/start.sh"]
|
||||
CMD ["/bin/s6-svscan", "/app/gogs/docker/s6/"]
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
FROM hypriot/rpi-alpine-scratch:v3.2
|
||||
MAINTAINER jp@roemer.im, raxetul@gmail.com
|
||||
FROM armhf/alpine:3.5
|
||||
|
||||
# Install system utils & Gogs runtime dependencies
|
||||
ADD https://github.com/tianon/gosu/releases/download/1.9/gosu-armhf /usr/sbin/gosu
|
||||
RUN chmod +x /usr/sbin/gosu \
|
||||
&& echo "http://dl-4.alpinelinux.org/alpine/v3.3/main/" | tee /etc/apk/repositories \
|
||||
&& echo "http://dl-4.alpinelinux.org/alpine/v3.3/community/" | tee -a /etc/apk/repositories \
|
||||
&& apk -U --no-progress upgrade && rm -f /var/cache/apk/APKINDEX.* \
|
||||
&& apk --no-cache --no-progress add ca-certificates bash git linux-pam s6 curl openssh socat tzdata
|
||||
|
||||
ENV GOGS_CUSTOM /data/gogs
|
||||
|
||||
COPY . /app/gogs/
|
||||
WORKDIR /app/gogs/
|
||||
RUN ./docker/build.sh
|
||||
COPY . /app/gogs/build
|
||||
WORKDIR /app/gogs/build
|
||||
|
||||
RUN ./docker/build-go.sh \
|
||||
&& ./docker/build.sh \
|
||||
&& ./docker/finalize.sh
|
||||
|
||||
# Configure LibC Name Service
|
||||
COPY docker/nsswitch.conf /etc/nsswitch.conf
|
||||
@@ -21,5 +20,5 @@ COPY docker/nsswitch.conf /etc/nsswitch.conf
|
||||
# Configure Docker Container
|
||||
VOLUME ["/data"]
|
||||
EXPOSE 22 3000
|
||||
ENTRYPOINT ["docker/start.sh"]
|
||||
ENTRYPOINT ["/app/gogs/docker/start.sh"]
|
||||
CMD ["/bin/s6-svscan", "/app/gogs/docker/s6/"]
|
||||
|
||||
@@ -3,7 +3,7 @@ Gogs [](http
|
||||
|
||||

|
||||
|
||||
##### Current tip version: [`.VERSION`](templates/.VERSION) (see [Releases](https://github.com/gogits/gogs/releases) for binary versions ~~or submit a task on [alpha stage automated binary building system](https://build.gogs.io/)~~)
|
||||
##### Current tip version: [`.VERSION`](templates/.VERSION) (see [Releases](https://github.com/gogits/gogs/releases) for binary versions)
|
||||
|
||||
| Web | UI | Preview |
|
||||
|:-------------:|:-------:|:-------:|
|
||||
@@ -98,7 +98,6 @@ There are 5 ways to install Gogs:
|
||||
- [OpenShift](https://github.com/tkisme/gogs-openshift)
|
||||
- [Cloudron](https://cloudron.io/appstore.html#io.gogs.cloudronapp)
|
||||
- [Scaleway](https://www.scaleway.com/imagehub/gogs/)
|
||||
- [Portal](https://portaldemo.xyz/cloud/)
|
||||
- [Sandstorm](https://github.com/cem/gogs-sandstorm)
|
||||
- [sloppy.io](https://github.com/sloppyio/quickstarters/tree/master/gogs)
|
||||
- [YunoHost](https://github.com/YunoHost-Apps/gogs_ynh)
|
||||
@@ -122,8 +121,6 @@ There are 5 ways to install Gogs:
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
- Router and middleware mechanism of [Macaron](https://github.com/go-macaron/macaron).
|
||||
- System Monitor Status is inspired by [GoBlog](https://github.com/fuxiaohei/goblog).
|
||||
- Thanks [Egon Elbre](https://twitter.com/egonelbre) for designing logo.
|
||||
- Thanks [Crowdin](https://crowdin.com/project/gogs) for providing open source translation plan.
|
||||
- Thanks [DigitalOcean](https://www.digitalocean.com) for hosting home and demo sites.
|
||||
@@ -131,8 +128,7 @@ There are 5 ways to install Gogs:
|
||||
|
||||
## Contributors
|
||||
|
||||
- Ex-team members [@lunny](https://github.com/lunny), [@fuxiaohei](https://github.com/fuxiaohei) and [@slene](https://github.com/slene).
|
||||
- See [contributors page](https://github.com/gogits/gogs/graphs/contributors) for full list of contributors.
|
||||
- See [contributors page](https://github.com/gogits/gogs/graphs/contributors) for top 100 contributors.
|
||||
- See [TRANSLATORS](conf/locale/TRANSLATORS) for public list of translators.
|
||||
|
||||
## License
|
||||
|
||||
@@ -67,7 +67,6 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
|
||||
- [OpenShift](https://github.com/tkisme/gogs-openshift)
|
||||
- [Cloudron](https://cloudron.io/appstore.html#io.gogs.cloudronapp)
|
||||
- [Scaleway](https://www.scaleway.com/imagehub/gogs/)
|
||||
- [Portal](https://portaldemo.xyz/cloud/)
|
||||
- [Sandstorm](https://github.com/cem/gogs-sandstorm)
|
||||
- [sloppy.io](https://github.com/sloppyio/quickstarters/tree/master/gogs)
|
||||
- [YunoHost](https://github.com/mbugeia/gogs_ynh)
|
||||
@@ -91,8 +90,6 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
|
||||
|
||||
## 特别鸣谢
|
||||
|
||||
- 基于 [Macaron](https://github.com/go-macaron/macaron) 的路由与中间件机制。
|
||||
- 基于 [GoBlog](https://github.com/fuxiaohei/goblog) 修改的系统监视状态。
|
||||
- 感谢 [Egon Elbre](https://twitter.com/egonelbre) 设计的 Logo。
|
||||
- 感谢 [Crowdin](https://crowdin.com/project/gogs) 提供免费的开源项目本地化支持。
|
||||
- 感谢 [DigitalOcean](https://www.digitalocean.com) 提供主站和体验站点的服务器赞助。
|
||||
@@ -100,8 +97,7 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
|
||||
|
||||
## 贡献成员
|
||||
|
||||
- 前团队成员 [@lunny](https://github.com/lunny)、[@fuxiaohei](https://github.com/fuxiaohei) 和 [@slene](https://github.com/slene)。
|
||||
- 您可以通过查看 [贡献者页面](https://github.com/gogits/gogs/graphs/contributors) 获取完整的贡献者列表。
|
||||
- 您可以通过查看 [贡献者页面](https://github.com/gogits/gogs/graphs/contributors) 获取 TOP 100 的贡献者列表。
|
||||
- 您可以通过查看 [TRANSLATORS](conf/locale/TRANSLATORS) 文件获取公开的翻译人员列表。
|
||||
|
||||
## 授权许可
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
CmdAdmin = cli.Command{
|
||||
Admin = cli.Command{
|
||||
Name: "admin",
|
||||
Usage: "Preform admin operations on command line",
|
||||
Description: `Allow using internal logic of Gogs without hacking into the source code
|
||||
|
||||
135
cmd/backup.go
Normal file
135
cmd/backup.go
Normal file
@@ -0,0 +1,135 @@
|
||||
// Copyright 2017 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 cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/Unknwon/cae/zip"
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/urfave/cli"
|
||||
log "gopkg.in/clog.v1"
|
||||
"gopkg.in/ini.v1"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
var Backup = cli.Command{
|
||||
Name: "backup",
|
||||
Usage: "Backup files and database",
|
||||
Description: `Backup dumps and compresses all related files and database into zip file,
|
||||
which can be used for migrating Gogs to another server. The output format is meant to be
|
||||
portable among all supported database engines.`,
|
||||
Action: runBackup,
|
||||
Flags: []cli.Flag{
|
||||
stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"),
|
||||
boolFlag("verbose, v", "Show process details"),
|
||||
stringFlag("tempdir, t", os.TempDir(), "Temporary directory path"),
|
||||
stringFlag("target", "./", "Target directory path to save backup archive"),
|
||||
boolFlag("database-only", "Only dump database"),
|
||||
boolFlag("exclude-repos", "Exclude repositories"),
|
||||
},
|
||||
}
|
||||
|
||||
const _ARCHIVE_ROOT_DIR = "gogs-backup"
|
||||
|
||||
func runBackup(c *cli.Context) error {
|
||||
zip.Verbose = c.Bool("verbose")
|
||||
if c.IsSet("config") {
|
||||
setting.CustomConf = c.String("config")
|
||||
}
|
||||
setting.NewContext()
|
||||
models.LoadConfigs()
|
||||
models.SetEngine()
|
||||
|
||||
tmpDir := c.String("tempdir")
|
||||
if !com.IsExist(tmpDir) {
|
||||
log.Fatal(0, "'--tempdir' does not exist: %s", tmpDir)
|
||||
}
|
||||
rootDir, err := ioutil.TempDir(tmpDir, "gogs-backup-")
|
||||
if err != nil {
|
||||
log.Fatal(0, "Fail to create backup root directory '%s': %v", rootDir, err)
|
||||
}
|
||||
log.Info("Backup root directory: %s", rootDir)
|
||||
|
||||
// Metadata
|
||||
metaFile := path.Join(rootDir, "metadata.ini")
|
||||
metadata := ini.Empty()
|
||||
metadata.Section("").Key("VERSION").SetValue("1")
|
||||
metadata.Section("").Key("DATE_TIME").SetValue(time.Now().String())
|
||||
metadata.Section("").Key("GOGS_VERSION").SetValue(setting.AppVer)
|
||||
if err = metadata.SaveTo(metaFile); err != nil {
|
||||
log.Fatal(0, "Fail to save metadata '%s': %v", metaFile, err)
|
||||
}
|
||||
|
||||
archiveName := path.Join(c.String("target"), fmt.Sprintf("gogs-backup-%d.zip", time.Now().Unix()))
|
||||
log.Info("Packing backup files to: %s", archiveName)
|
||||
|
||||
z, err := zip.Create(archiveName)
|
||||
if err != nil {
|
||||
log.Fatal(0, "Fail to create backup archive '%s': %v", archiveName, err)
|
||||
}
|
||||
if err = z.AddFile(_ARCHIVE_ROOT_DIR+"/metadata.ini", metaFile); err != nil {
|
||||
log.Fatal(0, "Fail to include 'metadata.ini': %v", err)
|
||||
}
|
||||
|
||||
// Database
|
||||
dbDir := path.Join(rootDir, "db")
|
||||
if err = models.DumpDatabase(dbDir); err != nil {
|
||||
log.Fatal(0, "Fail to dump database: %v", err)
|
||||
}
|
||||
if err = z.AddDir(_ARCHIVE_ROOT_DIR+"/db", dbDir); err != nil {
|
||||
log.Fatal(0, "Fail to include 'db': %v", err)
|
||||
}
|
||||
|
||||
// Custom files
|
||||
if !c.Bool("database-only") {
|
||||
if err = z.AddDir(_ARCHIVE_ROOT_DIR+"/custom", setting.CustomPath); err != nil {
|
||||
log.Fatal(0, "Fail to include 'custom': %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Data files
|
||||
if !c.Bool("database-only") {
|
||||
for _, dir := range []string{"attachments", "avatars"} {
|
||||
dirPath := path.Join(setting.AppDataPath, dir)
|
||||
if !com.IsDir(dirPath) {
|
||||
continue
|
||||
}
|
||||
|
||||
if err = z.AddDir(path.Join(_ARCHIVE_ROOT_DIR+"/data", dir), dirPath); err != nil {
|
||||
log.Fatal(0, "Fail to include 'data': %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Repositories
|
||||
if !c.Bool("exclude-repos") && !c.Bool("database-only") {
|
||||
reposDump := path.Join(rootDir, "repositories.zip")
|
||||
log.Info("Dumping repositories in '%s'", setting.RepoRootPath)
|
||||
if err = zip.PackTo(setting.RepoRootPath, reposDump, true); err != nil {
|
||||
log.Fatal(0, "Fail to dump repositories: %v", err)
|
||||
}
|
||||
log.Info("Repositories dumped to: %s", reposDump)
|
||||
|
||||
if err = z.AddFile(_ARCHIVE_ROOT_DIR+"/repositories.zip", reposDump); err != nil {
|
||||
log.Fatal(0, "Fail to include 'repositories.zip': %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err = z.Close(); err != nil {
|
||||
log.Fatal(0, "Fail to save backup archive '%s': %v", archiveName, err)
|
||||
}
|
||||
|
||||
os.RemoveAll(rootDir)
|
||||
log.Info("Backup succeed! Archive is located at: %s", archiveName)
|
||||
log.Shutdown()
|
||||
return nil
|
||||
}
|
||||
@@ -25,10 +25,10 @@ import (
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var CmdCert = cli.Command{
|
||||
var Cert = cli.Command{
|
||||
Name: "cert",
|
||||
Usage: "Generate self-signed certificate",
|
||||
Description: `Generate a self-signed X.509 certificate for a TLS server.
|
||||
Description: `Generate a self-signed X.509 certificate for a TLS server.
|
||||
Outputs to 'cert.pem' and 'key.pem' and will overwrite existing files.`,
|
||||
Action: runCert,
|
||||
Flags: []cli.Flag{
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var CmdCert = cli.Command{
|
||||
var Cert = cli.Command{
|
||||
Name: "cert",
|
||||
Usage: "Generate self-signed certificate",
|
||||
Description: `Please use build tags "cert" to rebuild Gogs in order to have this ability`,
|
||||
|
||||
122
cmd/dump.go
122
cmd/dump.go
@@ -1,122 +0,0 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/Unknwon/cae/zip"
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/urfave/cli"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
var CmdDump = cli.Command{
|
||||
Name: "dump",
|
||||
Usage: "Dump Gogs files and database",
|
||||
Description: `Dump compresses all related files and database into zip file.
|
||||
It can be used for backup and capture Gogs server image to send to maintainer`,
|
||||
Action: runDump,
|
||||
Flags: []cli.Flag{
|
||||
stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"),
|
||||
boolFlag("verbose, v", "Show process details"),
|
||||
stringFlag("tempdir, t", os.TempDir(), "Temporary dir path"),
|
||||
},
|
||||
}
|
||||
|
||||
func runDump(ctx *cli.Context) error {
|
||||
if ctx.IsSet("config") {
|
||||
setting.CustomConf = ctx.String("config")
|
||||
}
|
||||
setting.NewContext()
|
||||
models.LoadConfigs()
|
||||
models.SetEngine()
|
||||
|
||||
tmpDir := ctx.String("tempdir")
|
||||
if _, err := os.Stat(tmpDir); os.IsNotExist(err) {
|
||||
log.Fatalf("Path does not exist: %s", tmpDir)
|
||||
}
|
||||
TmpWorkDir, err := ioutil.TempDir(tmpDir, "gogs-dump-")
|
||||
if err != nil {
|
||||
log.Fatalf("Fail to create tmp work directory: %v", err)
|
||||
}
|
||||
log.Printf("Creating tmp work dir: %s", TmpWorkDir)
|
||||
|
||||
reposDump := path.Join(TmpWorkDir, "gogs-repo.zip")
|
||||
dbDump := path.Join(TmpWorkDir, "gogs-db.sql")
|
||||
|
||||
log.Printf("Dumping local repositories...%s", setting.RepoRootPath)
|
||||
zip.Verbose = ctx.Bool("verbose")
|
||||
if err := zip.PackTo(setting.RepoRootPath, reposDump, true); err != nil {
|
||||
log.Fatalf("Fail to dump local repositories: %v", err)
|
||||
}
|
||||
|
||||
log.Printf("Dumping database...")
|
||||
if err := models.DumpDatabase(dbDump); err != nil {
|
||||
log.Fatalf("Fail to dump database: %v", err)
|
||||
}
|
||||
|
||||
fileName := fmt.Sprintf("gogs-dump-%d.zip", time.Now().Unix())
|
||||
log.Printf("Packing dump files...")
|
||||
z, err := zip.Create(fileName)
|
||||
if err != nil {
|
||||
os.Remove(fileName)
|
||||
log.Fatalf("Fail to create %s: %v", fileName, err)
|
||||
}
|
||||
|
||||
if err := z.AddFile("gogs-repo.zip", reposDump); err != nil {
|
||||
log.Fatalf("Fail to include gogs-repo.zip: %v", err)
|
||||
}
|
||||
if err := z.AddFile("gogs-db.sql", dbDump); err != nil {
|
||||
log.Fatalf("Fail to include gogs-db.sql: %v", err)
|
||||
}
|
||||
customDir, err := os.Stat(setting.CustomPath)
|
||||
if err == nil && customDir.IsDir() {
|
||||
if err := z.AddDir("custom", setting.CustomPath); err != nil {
|
||||
log.Fatalf("Fail to include custom: %v", err)
|
||||
}
|
||||
} else {
|
||||
log.Printf("Custom dir %s doesn't exist, skipped", setting.CustomPath)
|
||||
}
|
||||
|
||||
if err := z.AddDir("log", setting.LogRootPath); err != nil {
|
||||
log.Fatalf("Fail to include log: %v", err)
|
||||
}
|
||||
|
||||
for _, dir := range []string{"attachments", "avatars"} {
|
||||
dirPath := path.Join(setting.AppDataPath, dir)
|
||||
if !com.IsDir(dirPath) {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := z.AddDir(path.Join("data", dir), dirPath); err != nil {
|
||||
log.Fatalf("Fail to include '%s': %v", dirPath, err)
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: SSH key file.
|
||||
if err = z.Close(); err != nil {
|
||||
os.Remove(fileName)
|
||||
log.Fatalf("Fail to save %s: %v", fileName, err)
|
||||
}
|
||||
|
||||
if err := os.Chmod(fileName, 0600); err != nil {
|
||||
log.Printf("Can't change file access permissions mask to 0600: %v", err)
|
||||
}
|
||||
|
||||
log.Printf("Removing tmp work dir: %s", TmpWorkDir)
|
||||
os.RemoveAll(TmpWorkDir)
|
||||
log.Printf("Finish dumping in file %s", fileName)
|
||||
|
||||
return nil
|
||||
}
|
||||
14
cmd/hook.go
14
cmd/hook.go
@@ -27,7 +27,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
CmdHook = cli.Command{
|
||||
Hook = cli.Command{
|
||||
Name: "hook",
|
||||
Usage: "Delegate commands to corresponding Git hooks",
|
||||
Description: "All sub-commands should only be called by Git",
|
||||
@@ -100,6 +100,12 @@ func runHookPreReceive(c *cli.Context) error {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if whitelist is enabled
|
||||
userID := com.StrTo(os.Getenv(http.ENV_AUTH_USER_ID)).MustInt64()
|
||||
if protectBranch.EnableWhitelist && !models.IsUserInProtectBranchWhitelist(repoID, userID, branchName) {
|
||||
fail(fmt.Sprintf("Branch '%s' is protected and you are not in the push whitelist", branchName), "")
|
||||
}
|
||||
|
||||
// Check if branch allows direct push
|
||||
if protectBranch.RequirePullRequest {
|
||||
fail(fmt.Sprintf("Branch '%s' is protected and commits must be merged through pull request", branchName), "")
|
||||
@@ -111,7 +117,8 @@ func runHookPreReceive(c *cli.Context) error {
|
||||
}
|
||||
|
||||
// Check force push
|
||||
output, err := git.NewCommand("rev-list", oldCommitID, "^"+newCommitID).Run()
|
||||
output, err := git.NewCommand("rev-list", oldCommitID, "^"+newCommitID).
|
||||
RunInDir(models.RepoPath(os.Getenv(http.ENV_REPO_OWNER_NAME), os.Getenv(http.ENV_REPO_NAME)))
|
||||
if err != nil {
|
||||
fail("Internal error", "Fail to detect force push: %v", err)
|
||||
} else if len(output) > 0 {
|
||||
@@ -125,6 +132,7 @@ func runHookPreReceive(c *cli.Context) error {
|
||||
}
|
||||
|
||||
hookCmd := exec.Command(customHooksPath)
|
||||
hookCmd.Dir = models.RepoPath(os.Getenv(http.ENV_REPO_OWNER_NAME), os.Getenv(http.ENV_REPO_NAME))
|
||||
hookCmd.Stdout = os.Stdout
|
||||
hookCmd.Stdin = buf
|
||||
hookCmd.Stderr = os.Stderr
|
||||
@@ -153,6 +161,7 @@ func runHookUpdate(c *cli.Context) error {
|
||||
}
|
||||
|
||||
hookCmd := exec.Command(customHooksPath, args...)
|
||||
hookCmd.Dir = models.RepoPath(os.Getenv(http.ENV_REPO_OWNER_NAME), os.Getenv(http.ENV_REPO_NAME))
|
||||
hookCmd.Stdout = os.Stdout
|
||||
hookCmd.Stdin = os.Stdin
|
||||
hookCmd.Stderr = os.Stderr
|
||||
@@ -225,6 +234,7 @@ func runHookPostReceive(c *cli.Context) error {
|
||||
}
|
||||
|
||||
hookCmd := exec.Command(customHooksPath)
|
||||
hookCmd.Dir = models.RepoPath(os.Getenv(http.ENV_REPO_OWNER_NAME), os.Getenv(http.ENV_REPO_NAME))
|
||||
hookCmd.Stdout = os.Stdout
|
||||
hookCmd.Stdin = buf
|
||||
hookCmd.Stderr = os.Stderr
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
CmdImport = cli.Command{
|
||||
Import = cli.Command{
|
||||
Name: "import",
|
||||
Usage: "Import portable data as local Gogs data",
|
||||
Description: `Allow user import data from other Gogs installations to local instance
|
||||
|
||||
129
cmd/restore.go
Normal file
129
cmd/restore.go
Normal file
@@ -0,0 +1,129 @@
|
||||
// Copyright 2017 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 cmd
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/Unknwon/cae/zip"
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/mcuadros/go-version"
|
||||
"github.com/urfave/cli"
|
||||
log "gopkg.in/clog.v1"
|
||||
"gopkg.in/ini.v1"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
var Restore = cli.Command{
|
||||
Name: "restore",
|
||||
Usage: "Restore files and database from backup",
|
||||
Description: `Restore imports all related files and database from a backup archive.
|
||||
The backup version must lower or equal to current Gogs version. You can also import
|
||||
backup from other database engines, which is useful for database migrating.
|
||||
|
||||
If corresponding files or database tables are not presented in the archive, they will
|
||||
be skipped and remian unchanged.`,
|
||||
Action: runRestore,
|
||||
Flags: []cli.Flag{
|
||||
stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"),
|
||||
boolFlag("verbose, v", "Show process details"),
|
||||
stringFlag("tempdir, t", os.TempDir(), "Temporary directory path"),
|
||||
stringFlag("from", "", "Path to backup archive"),
|
||||
boolFlag("database-only", "Only import database"),
|
||||
boolFlag("exclude-repos", "Exclude repositories"),
|
||||
},
|
||||
}
|
||||
|
||||
func runRestore(c *cli.Context) error {
|
||||
zip.Verbose = c.Bool("verbose")
|
||||
|
||||
tmpDir := c.String("tempdir")
|
||||
if !com.IsExist(tmpDir) {
|
||||
log.Fatal(0, "'--tempdir' does not exist: %s", tmpDir)
|
||||
}
|
||||
|
||||
log.Info("Restore backup from: %s", c.String("from"))
|
||||
if err := zip.ExtractTo(c.String("from"), tmpDir); err != nil {
|
||||
log.Fatal(0, "Fail to extract backup archive: %v", err)
|
||||
}
|
||||
archivePath := path.Join(tmpDir, _ARCHIVE_ROOT_DIR)
|
||||
|
||||
// Check backup version
|
||||
metaFile := path.Join(archivePath, "metadata.ini")
|
||||
if !com.IsExist(metaFile) {
|
||||
log.Fatal(0, "File 'metadata.ini' is missing")
|
||||
}
|
||||
metadata, err := ini.Load(metaFile)
|
||||
if err != nil {
|
||||
log.Fatal(0, "Fail to load metadata '%s': %v", metaFile, err)
|
||||
}
|
||||
backupVersion := metadata.Section("").Key("GOGS_VERSION").MustString("999.0")
|
||||
if version.Compare(setting.AppVer, backupVersion, "<") {
|
||||
log.Fatal(0, "Current Gogs version is lower than backup version: %s < %s", setting.AppVer, backupVersion)
|
||||
}
|
||||
|
||||
// If config file is not present in backup, user must set this file via flag.
|
||||
// Otherwise, it's optional to set config file flag.
|
||||
configFile := path.Join(archivePath, "custom/conf/app.ini")
|
||||
if c.IsSet("config") {
|
||||
setting.CustomConf = c.String("config")
|
||||
} else if !com.IsExist(configFile) {
|
||||
log.Fatal(0, "'--config' is not specified and custom config file is not found in backup")
|
||||
} else {
|
||||
setting.CustomConf = configFile
|
||||
}
|
||||
setting.NewContext()
|
||||
models.LoadConfigs()
|
||||
models.SetEngine()
|
||||
|
||||
// Database
|
||||
dbDir := path.Join(archivePath, "db")
|
||||
if err = models.ImportDatabase(dbDir); err != nil {
|
||||
log.Fatal(0, "Fail to import database: %v", err)
|
||||
}
|
||||
|
||||
// Custom files
|
||||
if !c.Bool("database-only") {
|
||||
if com.IsExist(setting.CustomPath) {
|
||||
if err = os.Rename(setting.CustomPath, setting.CustomPath+".bak"); err != nil {
|
||||
log.Fatal(0, "Fail to backup current 'custom': %v", err)
|
||||
}
|
||||
}
|
||||
if err = os.Rename(path.Join(archivePath, "custom"), setting.CustomPath); err != nil {
|
||||
log.Fatal(0, "Fail to import 'custom': %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Data files
|
||||
if !c.Bool("database-only") {
|
||||
for _, dir := range []string{"attachments", "avatars"} {
|
||||
dirPath := path.Join(setting.AppDataPath, dir)
|
||||
if com.IsExist(dirPath) {
|
||||
if err = os.Rename(dirPath, dirPath+".bak"); err != nil {
|
||||
log.Fatal(0, "Fail to backup current 'data': %v", err)
|
||||
}
|
||||
}
|
||||
if err = os.Rename(path.Join(archivePath, "data", dir), dirPath); err != nil {
|
||||
log.Fatal(0, "Fail to import 'data': %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Repositories
|
||||
reposPath := path.Join(archivePath, "repositories.zip")
|
||||
if !c.Bool("exclude-repos") && !c.Bool("database-only") && com.IsExist(reposPath) {
|
||||
if err := zip.ExtractTo(reposPath, path.Dir(setting.RepoRootPath)); err != nil {
|
||||
log.Fatal(0, "Fail to extract 'repositories.zip': %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
os.RemoveAll(path.Join(tmpDir, _ARCHIVE_ROOT_DIR))
|
||||
log.Info("Restore succeed!")
|
||||
log.Shutdown()
|
||||
return nil
|
||||
}
|
||||
@@ -199,7 +199,7 @@ func runServ(c *cli.Context) error {
|
||||
fail("Internal error", "Fail to get user by key ID '%d': %v", key.ID, err)
|
||||
}
|
||||
|
||||
mode, err := models.AccessLevel(user, repo)
|
||||
mode, err := models.AccessLevel(user.ID, repo)
|
||||
if err != nil {
|
||||
fail("Internal error", "Fail to check access: %v", err)
|
||||
}
|
||||
|
||||
139
cmd/web.go
139
cmd/web.go
@@ -34,9 +34,9 @@ import (
|
||||
"github.com/gogits/go-gogs-client"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/auth"
|
||||
"github.com/gogits/gogs/modules/bindata"
|
||||
"github.com/gogits/gogs/modules/context"
|
||||
"github.com/gogits/gogs/modules/form"
|
||||
"github.com/gogits/gogs/modules/mailer"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
"github.com/gogits/gogs/modules/template"
|
||||
@@ -49,9 +49,9 @@ import (
|
||||
"github.com/gogits/gogs/routers/user"
|
||||
)
|
||||
|
||||
var CmdWeb = cli.Command{
|
||||
var Web = cli.Command{
|
||||
Name: "web",
|
||||
Usage: "Start Gogs web server",
|
||||
Usage: "Start web server",
|
||||
Description: `Gogs web server is the only thing you need to run,
|
||||
and it takes care of all the other things for you`,
|
||||
Action: runWeb,
|
||||
@@ -219,35 +219,35 @@ func runWeb(ctx *cli.Context) error {
|
||||
m.Get("/organizations", routers.ExploreOrganizations)
|
||||
}, ignSignIn)
|
||||
m.Combo("/install", routers.InstallInit).Get(routers.Install).
|
||||
Post(bindIgnErr(auth.InstallForm{}), routers.InstallPost)
|
||||
Post(bindIgnErr(form.Install{}), routers.InstallPost)
|
||||
m.Get("/^:type(issues|pulls)$", reqSignIn, user.Issues)
|
||||
|
||||
// ***** START: User *****
|
||||
m.Group("/user", func() {
|
||||
m.Get("/login", user.SignIn)
|
||||
m.Post("/login", bindIgnErr(auth.SignInForm{}), user.SignInPost)
|
||||
m.Post("/login", bindIgnErr(form.SignIn{}), user.SignInPost)
|
||||
m.Get("/sign_up", user.SignUp)
|
||||
m.Post("/sign_up", bindIgnErr(auth.RegisterForm{}), user.SignUpPost)
|
||||
m.Post("/sign_up", bindIgnErr(form.Register{}), user.SignUpPost)
|
||||
m.Get("/reset_password", user.ResetPasswd)
|
||||
m.Post("/reset_password", user.ResetPasswdPost)
|
||||
}, reqSignOut)
|
||||
|
||||
m.Group("/user/settings", func() {
|
||||
m.Get("", user.Settings)
|
||||
m.Post("", bindIgnErr(auth.UpdateProfileForm{}), user.SettingsPost)
|
||||
m.Post("", bindIgnErr(form.UpdateProfile{}), user.SettingsPost)
|
||||
m.Combo("/avatar").Get(user.SettingsAvatar).
|
||||
Post(binding.MultipartForm(auth.AvatarForm{}), user.SettingsAvatarPost)
|
||||
Post(binding.MultipartForm(form.Avatar{}), user.SettingsAvatarPost)
|
||||
m.Post("/avatar/delete", user.SettingsDeleteAvatar)
|
||||
m.Combo("/email").Get(user.SettingsEmails).
|
||||
Post(bindIgnErr(auth.AddEmailForm{}), user.SettingsEmailPost)
|
||||
Post(bindIgnErr(form.AddEmail{}), user.SettingsEmailPost)
|
||||
m.Post("/email/delete", user.DeleteEmail)
|
||||
m.Get("/password", user.SettingsPassword)
|
||||
m.Post("/password", bindIgnErr(auth.ChangePasswordForm{}), user.SettingsPasswordPost)
|
||||
m.Post("/password", bindIgnErr(form.ChangePassword{}), user.SettingsPasswordPost)
|
||||
m.Combo("/ssh").Get(user.SettingsSSHKeys).
|
||||
Post(bindIgnErr(auth.AddSSHKeyForm{}), user.SettingsSSHKeysPost)
|
||||
Post(bindIgnErr(form.AddSSHKey{}), user.SettingsSSHKeysPost)
|
||||
m.Post("/ssh/delete", user.DeleteSSHKey)
|
||||
m.Combo("/applications").Get(user.SettingsApplications).
|
||||
Post(bindIgnErr(auth.NewAccessTokenForm{}), user.SettingsApplicationsPost)
|
||||
Post(bindIgnErr(form.NewAccessToken{}), user.SettingsApplicationsPost)
|
||||
m.Post("/applications/delete", user.SettingsDeleteApplication)
|
||||
|
||||
m.Group("/organizations", func() {
|
||||
@@ -261,7 +261,7 @@ func runWeb(ctx *cli.Context) error {
|
||||
})
|
||||
|
||||
m.Group("/user", func() {
|
||||
// r.Get("/feeds", binding.Bind(auth.FeedsForm{}), user.Feeds)
|
||||
// r.Get("/feeds", binding.Bind(form.Feeds{}), user.Feeds)
|
||||
m.Any("/activate", user.Activate)
|
||||
m.Any("/activate_email", user.ActivateEmail)
|
||||
m.Get("/email2user", user.Email2User)
|
||||
@@ -282,8 +282,8 @@ func runWeb(ctx *cli.Context) error {
|
||||
|
||||
m.Group("/users", func() {
|
||||
m.Get("", admin.Users)
|
||||
m.Combo("/new").Get(admin.NewUser).Post(bindIgnErr(auth.AdminCrateUserForm{}), admin.NewUserPost)
|
||||
m.Combo("/:userid").Get(admin.EditUser).Post(bindIgnErr(auth.AdminEditUserForm{}), admin.EditUserPost)
|
||||
m.Combo("/new").Get(admin.NewUser).Post(bindIgnErr(form.AdminCrateUser{}), admin.NewUserPost)
|
||||
m.Combo("/:userid").Get(admin.EditUser).Post(bindIgnErr(form.AdminEditUser{}), admin.EditUserPost)
|
||||
m.Post("/:userid/delete", admin.DeleteUser)
|
||||
})
|
||||
|
||||
@@ -298,9 +298,9 @@ func runWeb(ctx *cli.Context) error {
|
||||
|
||||
m.Group("/auths", func() {
|
||||
m.Get("", admin.Authentications)
|
||||
m.Combo("/new").Get(admin.NewAuthSource).Post(bindIgnErr(auth.AuthenticationForm{}), admin.NewAuthSourcePost)
|
||||
m.Combo("/new").Get(admin.NewAuthSource).Post(bindIgnErr(form.Authentication{}), admin.NewAuthSourcePost)
|
||||
m.Combo("/:authid").Get(admin.EditAuthSource).
|
||||
Post(bindIgnErr(auth.AuthenticationForm{}), admin.EditAuthSourcePost)
|
||||
Post(bindIgnErr(form.Authentication{}), admin.EditAuthSourcePost)
|
||||
m.Post("/:authid/delete", admin.DeleteAuthSource)
|
||||
})
|
||||
|
||||
@@ -365,7 +365,7 @@ func runWeb(ctx *cli.Context) error {
|
||||
m.Group("/org", func() {
|
||||
m.Group("", func() {
|
||||
m.Get("/create", org.Create)
|
||||
m.Post("/create", bindIgnErr(auth.CreateOrgForm{}), org.CreatePost)
|
||||
m.Post("/create", bindIgnErr(form.CreateOrg{}), org.CreatePost)
|
||||
}, func(ctx *context.Context) {
|
||||
if !ctx.User.CanCreateOrganization() {
|
||||
ctx.NotFound()
|
||||
@@ -390,28 +390,28 @@ func runWeb(ctx *cli.Context) error {
|
||||
|
||||
m.Group("/:org", func() {
|
||||
m.Get("/teams/new", org.NewTeam)
|
||||
m.Post("/teams/new", bindIgnErr(auth.CreateTeamForm{}), org.NewTeamPost)
|
||||
m.Post("/teams/new", bindIgnErr(form.CreateTeam{}), org.NewTeamPost)
|
||||
m.Get("/teams/:team/edit", org.EditTeam)
|
||||
m.Post("/teams/:team/edit", bindIgnErr(auth.CreateTeamForm{}), org.EditTeamPost)
|
||||
m.Post("/teams/:team/edit", bindIgnErr(form.CreateTeam{}), org.EditTeamPost)
|
||||
m.Post("/teams/:team/delete", org.DeleteTeam)
|
||||
|
||||
m.Group("/settings", func() {
|
||||
m.Combo("").Get(org.Settings).
|
||||
Post(bindIgnErr(auth.UpdateOrgSettingForm{}), org.SettingsPost)
|
||||
m.Post("/avatar", binding.MultipartForm(auth.AvatarForm{}), org.SettingsAvatar)
|
||||
Post(bindIgnErr(form.UpdateOrgSetting{}), org.SettingsPost)
|
||||
m.Post("/avatar", binding.MultipartForm(form.Avatar{}), org.SettingsAvatar)
|
||||
m.Post("/avatar/delete", org.SettingsDeleteAvatar)
|
||||
|
||||
m.Group("/hooks", func() {
|
||||
m.Get("", org.Webhooks)
|
||||
m.Post("/delete", org.DeleteWebhook)
|
||||
m.Get("/:type/new", repo.WebhooksNew)
|
||||
m.Post("/gogs/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost)
|
||||
m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost)
|
||||
m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
|
||||
m.Post("/gogs/new", bindIgnErr(form.NewWebhook{}), repo.WebHooksNewPost)
|
||||
m.Post("/slack/new", bindIgnErr(form.NewSlackHook{}), repo.SlackHooksNewPost)
|
||||
m.Post("/discord/new", bindIgnErr(form.NewDiscordHook{}), repo.DiscordHooksNewPost)
|
||||
m.Get("/:id", repo.WebHooksEdit)
|
||||
m.Post("/gogs/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost)
|
||||
m.Post("/slack/:id", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost)
|
||||
m.Post("/discord/:id", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
|
||||
m.Post("/gogs/:id", bindIgnErr(form.NewWebhook{}), repo.WebHooksEditPost)
|
||||
m.Post("/slack/:id", bindIgnErr(form.NewSlackHook{}), repo.SlackHooksEditPost)
|
||||
m.Post("/discord/:id", bindIgnErr(form.NewDiscordHook{}), repo.DiscordHooksEditPost)
|
||||
})
|
||||
|
||||
m.Route("/delete", "GET,POST", org.SettingsDelete)
|
||||
@@ -425,17 +425,17 @@ func runWeb(ctx *cli.Context) error {
|
||||
// ***** START: Repository *****
|
||||
m.Group("/repo", func() {
|
||||
m.Get("/create", repo.Create)
|
||||
m.Post("/create", bindIgnErr(auth.CreateRepoForm{}), repo.CreatePost)
|
||||
m.Post("/create", bindIgnErr(form.CreateRepo{}), repo.CreatePost)
|
||||
m.Get("/migrate", repo.Migrate)
|
||||
m.Post("/migrate", bindIgnErr(auth.MigrateRepoForm{}), repo.MigratePost)
|
||||
m.Post("/migrate", bindIgnErr(form.MigrateRepo{}), repo.MigratePost)
|
||||
m.Combo("/fork/:repoid").Get(repo.Fork).
|
||||
Post(bindIgnErr(auth.CreateRepoForm{}), repo.ForkPost)
|
||||
Post(bindIgnErr(form.CreateRepo{}), repo.ForkPost)
|
||||
}, reqSignIn)
|
||||
|
||||
m.Group("/:username/:reponame", func() {
|
||||
m.Group("/settings", func() {
|
||||
m.Combo("").Get(repo.Settings).
|
||||
Post(bindIgnErr(auth.RepoSettingForm{}), repo.SettingsPost)
|
||||
Post(bindIgnErr(form.RepoSetting{}), repo.SettingsPost)
|
||||
m.Group("/collaboration", func() {
|
||||
m.Combo("").Get(repo.SettingsCollaboration).Post(repo.SettingsCollaborationPost)
|
||||
m.Post("/access_mode", repo.ChangeCollaborationAccessMode)
|
||||
@@ -445,7 +445,7 @@ func runWeb(ctx *cli.Context) error {
|
||||
m.Get("", repo.SettingsBranches)
|
||||
m.Post("/default_branch", repo.UpdateDefaultBranch)
|
||||
m.Combo("/*").Get(repo.SettingsProtectedBranch).
|
||||
Post(bindIgnErr(auth.ProtectBranchForm{}), repo.SettingsProtectedBranchPost)
|
||||
Post(bindIgnErr(form.ProtectBranch{}), repo.SettingsProtectedBranchPost)
|
||||
}, func(ctx *context.Context) {
|
||||
if ctx.Repo.Repository.IsMirror {
|
||||
ctx.NotFound()
|
||||
@@ -457,14 +457,14 @@ func runWeb(ctx *cli.Context) error {
|
||||
m.Get("", repo.Webhooks)
|
||||
m.Post("/delete", repo.DeleteWebhook)
|
||||
m.Get("/:type/new", repo.WebhooksNew)
|
||||
m.Post("/gogs/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost)
|
||||
m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost)
|
||||
m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
|
||||
m.Post("/gogs/new", bindIgnErr(form.NewWebhook{}), repo.WebHooksNewPost)
|
||||
m.Post("/slack/new", bindIgnErr(form.NewSlackHook{}), repo.SlackHooksNewPost)
|
||||
m.Post("/discord/new", bindIgnErr(form.NewDiscordHook{}), repo.DiscordHooksNewPost)
|
||||
m.Get("/:id", repo.WebHooksEdit)
|
||||
m.Post("/:id/test", repo.TestWebhook)
|
||||
m.Post("/gogs/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost)
|
||||
m.Post("/slack/:id", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost)
|
||||
m.Post("/discord/:id", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
|
||||
m.Post("/gogs/:id", bindIgnErr(form.NewWebhook{}), repo.WebHooksEditPost)
|
||||
m.Post("/slack/:id", bindIgnErr(form.NewSlackHook{}), repo.SlackHooksEditPost)
|
||||
m.Post("/discord/:id", bindIgnErr(form.NewDiscordHook{}), repo.DiscordHooksEditPost)
|
||||
|
||||
m.Group("/git", func() {
|
||||
m.Get("", repo.SettingsGitHooks)
|
||||
@@ -475,7 +475,7 @@ func runWeb(ctx *cli.Context) error {
|
||||
|
||||
m.Group("/keys", func() {
|
||||
m.Combo("").Get(repo.SettingsDeployKeys).
|
||||
Post(bindIgnErr(auth.AddSSHKeyForm{}), repo.SettingsDeployKeysPost)
|
||||
Post(bindIgnErr(form.AddSSHKey{}), repo.SettingsDeployKeysPost)
|
||||
m.Post("/delete", repo.DeleteDeployKey)
|
||||
})
|
||||
|
||||
@@ -490,7 +490,7 @@ func runWeb(ctx *cli.Context) error {
|
||||
// So they can apply their own enable/disable logic on routers.
|
||||
m.Group("/issues", func() {
|
||||
m.Combo("/new", repo.MustEnableIssues).Get(context.RepoRef(), repo.NewIssue).
|
||||
Post(bindIgnErr(auth.CreateIssueForm{}), repo.NewIssuePost)
|
||||
Post(bindIgnErr(form.CreateIssue{}), repo.NewIssuePost)
|
||||
|
||||
m.Group("/:index", func() {
|
||||
m.Post("/label", repo.UpdateIssueLabel)
|
||||
@@ -501,7 +501,7 @@ func runWeb(ctx *cli.Context) error {
|
||||
m.Group("/:index", func() {
|
||||
m.Post("/title", repo.UpdateIssueTitle)
|
||||
m.Post("/content", repo.UpdateIssueContent)
|
||||
m.Combo("/comments").Post(bindIgnErr(auth.CreateCommentForm{}), repo.NewComment)
|
||||
m.Combo("/comments").Post(bindIgnErr(form.CreateComment{}), repo.NewComment)
|
||||
})
|
||||
})
|
||||
m.Group("/comments/:id", func() {
|
||||
@@ -509,65 +509,49 @@ func runWeb(ctx *cli.Context) error {
|
||||
m.Post("/delete", repo.DeleteComment)
|
||||
})
|
||||
m.Group("/labels", func() {
|
||||
m.Post("/new", bindIgnErr(auth.CreateLabelForm{}), repo.NewLabel)
|
||||
m.Post("/edit", bindIgnErr(auth.CreateLabelForm{}), repo.UpdateLabel)
|
||||
m.Post("/new", bindIgnErr(form.CreateLabel{}), repo.NewLabel)
|
||||
m.Post("/edit", bindIgnErr(form.CreateLabel{}), repo.UpdateLabel)
|
||||
m.Post("/delete", repo.DeleteLabel)
|
||||
m.Post("/initialize", bindIgnErr(auth.InitializeLabelsForm{}), repo.InitializeLabels)
|
||||
m.Post("/initialize", bindIgnErr(form.InitializeLabels{}), repo.InitializeLabels)
|
||||
}, reqRepoWriter, context.RepoRef())
|
||||
m.Group("/milestones", func() {
|
||||
m.Combo("/new").Get(repo.NewMilestone).
|
||||
Post(bindIgnErr(auth.CreateMilestoneForm{}), repo.NewMilestonePost)
|
||||
Post(bindIgnErr(form.CreateMilestone{}), repo.NewMilestonePost)
|
||||
m.Get("/:id/edit", repo.EditMilestone)
|
||||
m.Post("/:id/edit", bindIgnErr(auth.CreateMilestoneForm{}), repo.EditMilestonePost)
|
||||
m.Post("/:id/edit", bindIgnErr(form.CreateMilestone{}), repo.EditMilestonePost)
|
||||
m.Get("/:id/:action", repo.ChangeMilestonStatus)
|
||||
m.Post("/delete", repo.DeleteMilestone)
|
||||
}, reqRepoWriter, context.RepoRef())
|
||||
|
||||
m.Group("/releases", func() {
|
||||
m.Get("/new", repo.NewRelease)
|
||||
m.Post("/new", bindIgnErr(auth.NewReleaseForm{}), repo.NewReleasePost)
|
||||
m.Post("/new", bindIgnErr(form.NewRelease{}), repo.NewReleasePost)
|
||||
m.Post("/delete", repo.DeleteRelease)
|
||||
}, reqRepoWriter, context.RepoRef())
|
||||
|
||||
m.Group("/releases", func() {
|
||||
m.Get("/edit/*", repo.EditRelease)
|
||||
m.Post("/edit/*", bindIgnErr(auth.EditReleaseForm{}), repo.EditReleasePost)
|
||||
}, reqRepoWriter, func(ctx *context.Context) {
|
||||
var err error
|
||||
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "GetBranchCommit", err)
|
||||
return
|
||||
}
|
||||
ctx.Repo.CommitsCount, err = ctx.Repo.Commit.CommitsCount()
|
||||
if err != nil {
|
||||
ctx.Handle(500, "CommitsCount", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount
|
||||
})
|
||||
m.Post("/edit/*", bindIgnErr(form.EditRelease{}), repo.EditReleasePost)
|
||||
}, reqRepoWriter, context.RepoRef())
|
||||
|
||||
// FIXME: Should use ctx.Repo.PullRequest to unify template, currently we have inconsistent URL
|
||||
// for PR in same repository. After select branch on the page, the URL contains redundant head user name.
|
||||
// e.g. /org1/test-repo/compare/master...org1:develop
|
||||
// which should be /org1/test-repo/compare/master...develop
|
||||
m.Combo("/compare/*", repo.MustAllowPulls).Get(repo.CompareAndPullRequest).
|
||||
Post(bindIgnErr(auth.CreateIssueForm{}), repo.CompareAndPullRequestPost)
|
||||
Post(bindIgnErr(form.CreateIssue{}), repo.CompareAndPullRequestPost)
|
||||
|
||||
m.Group("", func() {
|
||||
m.Combo("/_edit/*").Get(repo.EditFile).
|
||||
Post(bindIgnErr(auth.EditRepoFileForm{}), repo.EditFilePost)
|
||||
Post(bindIgnErr(form.EditRepoFile{}), repo.EditFilePost)
|
||||
m.Combo("/_new/*").Get(repo.NewFile).
|
||||
Post(bindIgnErr(auth.EditRepoFileForm{}), repo.NewFilePost)
|
||||
m.Post("/_preview/*", bindIgnErr(auth.EditPreviewDiffForm{}), repo.DiffPreviewPost)
|
||||
Post(bindIgnErr(form.EditRepoFile{}), repo.NewFilePost)
|
||||
m.Post("/_preview/*", bindIgnErr(form.EditPreviewDiff{}), repo.DiffPreviewPost)
|
||||
m.Combo("/_delete/*").Get(repo.DeleteFile).
|
||||
Post(bindIgnErr(auth.DeleteRepoFileForm{}), repo.DeleteFilePost)
|
||||
Post(bindIgnErr(form.DeleteRepoFile{}), repo.DeleteFilePost)
|
||||
|
||||
m.Group("", func() {
|
||||
m.Combo("/_upload/*").Get(repo.UploadFile).
|
||||
Post(bindIgnErr(auth.UploadRepoFileForm{}), repo.UploadFilePost)
|
||||
Post(bindIgnErr(form.UploadRepoFile{}), repo.UploadFilePost)
|
||||
m.Post("/upload-file", repo.UploadFileToServer)
|
||||
m.Post("/upload-remove", bindIgnErr(auth.RemoveUploadFileForm{}), repo.RemoveUploadFileFromServer)
|
||||
m.Post("/upload-remove", bindIgnErr(form.RemoveUploadFile{}), repo.RemoveUploadFileFromServer)
|
||||
}, func(ctx *context.Context) {
|
||||
if !setting.Repository.Upload.Enabled {
|
||||
ctx.NotFound()
|
||||
@@ -600,9 +584,9 @@ func runWeb(ctx *cli.Context) error {
|
||||
|
||||
m.Group("", func() {
|
||||
m.Combo("/_new").Get(repo.NewWiki).
|
||||
Post(bindIgnErr(auth.NewWikiForm{}), repo.NewWikiPost)
|
||||
Post(bindIgnErr(form.NewWiki{}), repo.NewWikiPost)
|
||||
m.Combo("/:page/_edit").Get(repo.EditWiki).
|
||||
Post(bindIgnErr(auth.NewWikiForm{}), repo.EditWikiPost)
|
||||
Post(bindIgnErr(form.NewWiki{}), repo.EditWikiPost)
|
||||
m.Post("/:page/delete", repo.DeleteWikiPagePost)
|
||||
}, reqSignIn, reqRepoWriter)
|
||||
}, repo.MustEnableWiki, context.RepoRef())
|
||||
@@ -639,11 +623,14 @@ func runWeb(ctx *cli.Context) error {
|
||||
m.Group("/:reponame", func() {
|
||||
m.Head("/tasks/trigger", repo.TriggerTask)
|
||||
})
|
||||
// Use the regexp to match the repository name validation
|
||||
// Use the regexp to match the repository name
|
||||
// Duplicated routes to enable different ways of accessing same set of URLs,
|
||||
// e.g. with or without ".git" suffix.
|
||||
m.Group("/:reponame([\\d\\w-_\\.]+\\.git$)", func() {
|
||||
m.Get("", ignSignIn, context.RepoAssignment(true), context.RepoRef(), repo.Home)
|
||||
m.Route("/*", "GET,POST", ignSignInAndCsrf, repo.HTTPContexter(), repo.HTTP)
|
||||
})
|
||||
m.Route("/:reponame/*", "GET,POST", ignSignInAndCsrf, repo.HTTPContexter(), repo.HTTP)
|
||||
})
|
||||
// ***** END: Repository *****
|
||||
|
||||
|
||||
10
conf/app.ini
10
conf/app.ini
@@ -181,6 +181,8 @@ ENABLE_REVERSE_PROXY_AUTO_REGISTRATION = false
|
||||
ENABLE_CAPTCHA = true
|
||||
|
||||
[webhook]
|
||||
; Types are enabled for users to use, can be "gogs", "slack", "discord"
|
||||
TYPES = gogs, slack, discord
|
||||
; Hook task queue length, increase if webhook shooting starts hanging
|
||||
QUEUE_LENGTH = 1000
|
||||
; Deliver timeout in seconds
|
||||
@@ -216,8 +218,8 @@ FROM =
|
||||
; Mailer user name and password
|
||||
USER =
|
||||
PASSWD =
|
||||
; Use text/html as alternative format of content
|
||||
ENABLE_HTML_ALTERNATIVE = false
|
||||
; Use text/plain as format of content
|
||||
USE_PLAIN_TEXT = false
|
||||
|
||||
[cache]
|
||||
; Either "memory", "redis", or "memcache", default is "memory"
|
||||
@@ -248,6 +250,8 @@ ENABLE_SET_COOKIE = true
|
||||
GC_INTERVAL_TIME = 86400
|
||||
; Session life time, default is 86400
|
||||
SESSION_LIFE_TIME = 86400
|
||||
; Cookie name for CSRF
|
||||
CSRF_COOKIE_NAME = _csrf
|
||||
|
||||
[picture]
|
||||
; Path to store user uploaded avatars
|
||||
@@ -407,7 +411,7 @@ REPO_PAGING_NUM = 15
|
||||
|
||||
[i18n]
|
||||
LANGS = en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,ja-JP,es-ES,pt-BR,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR,gl-ES,uk-UA
|
||||
NAMES = English,简体中文,繁體中文(香港),繁體中文(台湾),Deutsch,Français,Nederlands,Latviešu,Русский,日本語,Español,Português do Brasil,Polski,български,Italiano,Suomalainen,Türkçe,čeština,Српски,Svenska,한국어,Galego,Український
|
||||
NAMES = English,简体中文,繁體中文(香港),繁體中文(台湾),Deutsch,Français,Nederlands,Latviešu,Русский,日本語,Español,Português do Brasil,Polski,български,Italiano,Suomalainen,Türkçe,čeština,Српски,Svenska,한국어,Galego,Українська
|
||||
|
||||
; Used for datetimepicker
|
||||
[i18n.datelang]
|
||||
|
||||
@@ -1,24 +1,25 @@
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
@@ -9,6 +9,7 @@ Aleksey Tarakin <hukendo AT yandex DOT ru>
|
||||
Alexander Steinhöfer <kontakt AT lx-s DOT de>
|
||||
Alexandre Espinosa Menor <aemenor DOT gmail DOT com>
|
||||
Alexandre Magno <alexandre DOT mbm AT gmail DOT com>
|
||||
Anders B. Hansen <anders AT birkoe DOT com>
|
||||
András Schenkerik <moviesharkteam AT gmail DOT com>
|
||||
Andrey Nering <andrey AT nering DOT com DOT br>
|
||||
Andrey Paskal <apaskal AT gmail DOT com>
|
||||
@@ -17,12 +18,15 @@ Antoine GIRARD <sapk AT sapk DOT fr>
|
||||
Arthur Aslanyan <arthur DOT e DOT aslanyan AT gmail DOT com>
|
||||
Aurelien Darragon <aurelien DOT darragon AT gmail DOT com>
|
||||
Barış Arda Yılmaz <ardayilmazgamer AT gmail DOT com>
|
||||
Bo-Yi Wu <appleboy DOT tw AT gmail DOT com>
|
||||
Breton Corentin <contact AT neodarz DOT net>
|
||||
Camille Baronnet <gogs AT camillebaronnet DOT fr>
|
||||
Christoph Kisfeld <christoph DOT kisfeld AT gmail DOT com>
|
||||
Cysioland
|
||||
Damaris Padieu <damizx AT hotmail DOT fr>
|
||||
Daniel Speichert <daniel AT speichert DOT pl>
|
||||
David Yzaguirre <dvdyzag AT gmail DOT com>
|
||||
Denys Khomenko
|
||||
Dmitriy Nogay <me AT catwhocode DOT ga>
|
||||
Enrico Testori hypertesto AT gmail DOT com
|
||||
Ezequiel Gonzalez Rial <gonrial AT gmail DOT com>
|
||||
|
||||
@@ -656,6 +656,10 @@ settings.protect_require_pull_request=Require pull request instead direct pushin
|
||||
settings.protect_require_pull_request_desc=Enable this option to disable direct pushing to this branch. Commits have to be pushed to another non-protected branch and merged to this branch through pull request.
|
||||
settings.protect_whitelist_committers=Whitelist who can push to this branch
|
||||
settings.protect_whitelist_committers_desc=Add people or teams to whitelist of direct push to this branch.
|
||||
settings.protect_whitelist_users=Users who can push to this branch
|
||||
settings.protect_whitelist_search_users=Search users
|
||||
settings.protect_whitelist_teams=Teams for which members of them can push to this branch
|
||||
settings.protect_whitelist_search_teams=Search teams
|
||||
settings.update_protect_branch_success=Protect options for this branch has been updated successfully!
|
||||
settings.hooks=Уеб-куки
|
||||
settings.githooks=Git куки
|
||||
@@ -684,6 +688,7 @@ settings.tracker_issue_style.alphanumeric=Символен
|
||||
settings.tracker_url_format_desc=Можете да използвате текстови маркери <code>{user} {repo} {index}</code> за потребителско име, име на хранилище и индекс на задача съответно.
|
||||
settings.pulls_desc=Включва заявки за сливане за да може да се приемат външни доработки
|
||||
settings.danger_zone=Опасна зона
|
||||
settings.cannot_fork_to_same_owner=You cannot fork a repository to its original owner.
|
||||
settings.new_owner_has_same_repo=Новият притежател вече има хранилище със същото име. Изберете друго име.
|
||||
settings.convert=Промени към редовно хранилище
|
||||
settings.convert_desc=Можете да промените това огледало към редовно хранилище. Конверсията не може да се отмени.
|
||||
@@ -718,7 +723,6 @@ settings.collaborator_deletion_desc=Този потребител няма да
|
||||
settings.remove_collaborator_success=Сътрудникът е премахнат.
|
||||
settings.search_user_placeholder=Име на потребител...
|
||||
settings.org_not_allowed_to_be_collaborator=Невъзможно добавяне на организация като сътрудник.
|
||||
settings.user_is_org_member=Потребителят вече участва в организацията и не може да бъде добавен като сътрудник.
|
||||
settings.add_webhook=Добави уеб-кука
|
||||
settings.hooks_desc=Уеб-куките много приличат на обикновен HTTP POST тригер. Когато нещо се случи в Gogs, ние ще изпратим уведомление до сървъра, който посочите. Научете повече в <a target="_blank" href="%s">Ръководство за уеб-куки</a>.
|
||||
settings.webhook_deletion=Изтрий уеб-кука
|
||||
@@ -741,6 +745,7 @@ settings.add_webhook_desc=Gogs ще изпрати <code>POST</code> заявк
|
||||
settings.payload_url=URL адрес на изпращане
|
||||
settings.content_type=Тип на съдържанието
|
||||
settings.secret=Тайна
|
||||
settings.secret_desc=Secret will be sent as SHA256 HMAC hex digest of payload via <code>X-Gogs-Signature</code> header.
|
||||
settings.slack_username=Потребителско име
|
||||
settings.slack_icon_url=URL адрес на икона
|
||||
settings.slack_color=Цвят
|
||||
|
||||
@@ -656,6 +656,10 @@ settings.protect_require_pull_request=Require pull request instead direct pushin
|
||||
settings.protect_require_pull_request_desc=Enable this option to disable direct pushing to this branch. Commits have to be pushed to another non-protected branch and merged to this branch through pull request.
|
||||
settings.protect_whitelist_committers=Whitelist who can push to this branch
|
||||
settings.protect_whitelist_committers_desc=Add people or teams to whitelist of direct push to this branch.
|
||||
settings.protect_whitelist_users=Users who can push to this branch
|
||||
settings.protect_whitelist_search_users=Search users
|
||||
settings.protect_whitelist_teams=Teams for which members of them can push to this branch
|
||||
settings.protect_whitelist_search_teams=Search teams
|
||||
settings.update_protect_branch_success=Protect options for this branch has been updated successfully!
|
||||
settings.hooks=Webové háčky
|
||||
settings.githooks=Háčky Gitu
|
||||
@@ -684,6 +688,7 @@ settings.tracker_issue_style.alphanumeric=Alfanumerický
|
||||
settings.tracker_url_format_desc=Můžete použít zástupné výrazy <code>{user} {repo} {index}</code> pro uživatelské jméno, název repositáře a index úkolu.
|
||||
settings.pulls_desc=Povolit požadavky na stažení, aby veřejné příspěvky mohly být akceptovány
|
||||
settings.danger_zone=Nebezpečná zóna
|
||||
settings.cannot_fork_to_same_owner=You cannot fork a repository to its original owner.
|
||||
settings.new_owner_has_same_repo=Nový vlastník již repositář se stejným názvem má. Vyberte, prosíme, jiné jméno.
|
||||
settings.convert=Převést na běžný repositář
|
||||
settings.convert_desc=Můžete převést toto zrcadlo na běžný repositář. Tato změna nemůže být vrácena.
|
||||
@@ -718,7 +723,6 @@ settings.collaborator_deletion_desc=Tento uživatel po tom, co bude smazán, ji
|
||||
settings.remove_collaborator_success=Spolupracovník byl smazán.
|
||||
settings.search_user_placeholder=Hledat uživatele...
|
||||
settings.org_not_allowed_to_be_collaborator=Není dovoleno přidat organizaci jako spolupracovníka.
|
||||
settings.user_is_org_member=Uživatel je již členem organizace, tudíž nemůže být přidán jako spolupracovník.
|
||||
settings.add_webhook=Přidat webový háček
|
||||
settings.hooks_desc=Webové háčky jsou podobné základním spouštím HTTP POST událostí. Kdykoliv se něco stane v Gogs, bude postaráno o oznámení specifikovanému cílovému serveru. Více se o daném dozvíte v <a target="_blank" href="%s">příručce webových háčků</a>.
|
||||
settings.webhook_deletion=Smazat webový háček
|
||||
@@ -741,6 +745,7 @@ settings.add_webhook_desc=Gogs zašle požadavek typu <code>POST</code> na zadan
|
||||
settings.payload_url=URL obsahu
|
||||
settings.content_type=Typ obsahu
|
||||
settings.secret=Tajný klíč
|
||||
settings.secret_desc=Secret will be sent as SHA256 HMAC hex digest of payload via <code>X-Gogs-Signature</code> header.
|
||||
settings.slack_username=Uživatelské jméno
|
||||
settings.slack_icon_url=URL ikony uživatele
|
||||
settings.slack_color=Barva
|
||||
|
||||
@@ -48,7 +48,7 @@ cancel=Abbrechen
|
||||
install=Installation
|
||||
title=Installationsschritte für den ersten Start
|
||||
docker_helper=Wenn Gogs innerhalb von Docker läuft, lesen Sie sich bitte den <a target="_blank" href="%s">Leitfaden</a> genau durch, bevor Sie irgendwas auf dieser Seite ändern!
|
||||
requite_db_desc=Gogs requires MySQL, PostgreSQL, SQLite3, MSSQL or TiDB.
|
||||
requite_db_desc=Gogs benötigt MySQL, PostgreSQL, SQLite3, MSSQL oder TiDB.
|
||||
db_title=Datenbankeinstellungen
|
||||
db_type=Datenbanktyp
|
||||
host=Host
|
||||
@@ -58,8 +58,8 @@ db_name=Datenbankname
|
||||
db_helper=Bitte verwenden Sie in MySQL die InnoDB-Engine mit dem Zeichensatz utf8_general_ci.
|
||||
ssl_mode=SSL-Modus
|
||||
path=Pfad
|
||||
sqlite_helper=The file path of SQLite3 database. <br>Please use absolute path when you start as service.
|
||||
err_empty_db_path=SQLite3 database path cannot be empty.
|
||||
sqlite_helper=Der Dateipfad zur SQLite3-Datenbank. <br>Bitte verwenden Sie einen absoluten Pfad, wenn Gogs als Service gestartet wird.
|
||||
err_empty_db_path=SQLite3 Datenbankpfad darf nicht leer sein.
|
||||
no_admin_and_disable_registration=Sie können die Registrierung nicht deaktivieren, ohne ein Administratorkonto zu erstellen.
|
||||
err_empty_admin_password=Das Administrator-Passwort darf nicht leer sein.
|
||||
|
||||
@@ -74,8 +74,8 @@ domain=Domain
|
||||
domain_helper=Dies hat Auswirkung auf die SSH Klon-URLs.
|
||||
ssh_port=SSH Port
|
||||
ssh_port_helper=Der Port Ihres SSH-Servers. Leer lassen um SSH zu deaktivieren.
|
||||
use_builtin_ssh_server=Use Builtin SSH Server
|
||||
use_builtin_ssh_server_popup=Start builtin SSH server for Git operations to distinguish from system SSH daemon.
|
||||
use_builtin_ssh_server=Eingebauten SSH-Server verwenden
|
||||
use_builtin_ssh_server_popup=Starte eingebauten SSH-Server für git-Aufgaben, um es vom System-SSH-Dämon zu trennen.
|
||||
http_port=HTTP Port
|
||||
http_port_helper=Auf dieser Port Nummer wird Gogs erreichbar sein.
|
||||
app_url=Anwendungs-URL
|
||||
@@ -117,7 +117,7 @@ sqlite3_not_available=Ihre Gogs-Version unterstützt SQLite3 nicht. Bitte laden
|
||||
invalid_db_setting=Datenbankeinstellungen sind nicht korrekt: %v
|
||||
invalid_repo_path=Repository Verzeichnis ist ungültig: %v
|
||||
run_user_not_match=Der ausführende Benutzer ist nicht der aktuelle Benutzer: %s -> %s
|
||||
invalid_smtp_from=SMPT ist nicht gültig im Feld: %v
|
||||
invalid_smtp_from=SMTP Absender Feld ist nicht gültig: %v
|
||||
save_config_failed=Fehler beim Speichern der Konfiguration: %v
|
||||
invalid_admin_setting=Admin-Konto Einstellungen sind ungültig: %v
|
||||
install_success=Herzlich Willkommen! Wir sind froh, dass Sie sich für Gogs entschieden haben. Wir wünschen viel Vergnügen damit.
|
||||
@@ -462,7 +462,7 @@ editor.cancel=Abbrechen
|
||||
editor.filename_cannot_be_empty=Der Dateiname darf nicht leer sein.
|
||||
editor.branch_already_exists=Branch '%s' existiert bereits in diesem Repository.
|
||||
editor.directory_is_a_file='%s' im übergeordneten Verzeichnis ist eine Datei und kein Verzeichnis.
|
||||
editor.file_is_a_symlink=Die Datei '%s' ist ein Symlink die nicht im Webeditor verändert werden kann.
|
||||
editor.file_is_a_symlink=Die Datei '%s' ist ein Symlink, der im Webeditor nicht bearbeitet werden kann.
|
||||
editor.filename_is_a_directory=Die Datei '%s' existiert bereits als Verzeichnis in diesem Repository.
|
||||
editor.file_editing_no_longer_exists=Die Datei '%s', welche Sie bearbeiten, existiert in diesem Repository nicht mehr.
|
||||
editor.file_changed_while_editing=Seit dem Start der Bearbeitung hat sich die Datei geändert. <a target="_blank" href="%s">Hier klicken</a> um die Änderungen zu sehen, oder nochmals <strong>Commit drücken</strong> um die Änderungen zu überschreiben.
|
||||
@@ -473,7 +473,7 @@ editor.add_subdir=Unterverzeichnis erstellen...
|
||||
editor.unable_to_upload_files=Fehler beim Hochladen der Dateien zu '%s'. Fehler: %v
|
||||
editor.upload_files_to_dir=Dateien hochladen nach '%s'
|
||||
|
||||
commits.commit_history=Commit History
|
||||
commits.commit_history=Commit Verlauf
|
||||
commits.commits=Commits
|
||||
commits.search=Commits durchsuchen
|
||||
commits.find=Finden
|
||||
@@ -641,22 +641,26 @@ settings.collaboration.write=Schreibrechte
|
||||
settings.collaboration.read=Leserechte
|
||||
settings.collaboration.undefined=Nicht definiert
|
||||
settings.branches=Branches
|
||||
settings.default_branch=Default Branch
|
||||
settings.default_branch_desc=The default branch is considered the "base" branch for code commits, pull requests and online editing.
|
||||
settings.update=Update
|
||||
settings.update_default_branch_success=Default branch of this repository has been updated successfully!
|
||||
settings.default_branch=Standard-Branch
|
||||
settings.default_branch_desc=Der Standard-Branch gilt als Basis für Commits, Pull-Requests und Online-Bearbeitung.
|
||||
settings.update=Aktualisieren
|
||||
settings.update_default_branch_success=Standard-Branch dieses Repositories wurde erfolgreich aktualisiert!
|
||||
settings.protected_branches=Protected Branches
|
||||
settings.protected_branches_desc=Protect branches from force pushing, accidental deletion and whitelist code committers.
|
||||
settings.choose_a_branch=Choose a branch...
|
||||
settings.branch_protection=Branch Protection
|
||||
settings.branch_protection_desc=Please choose protect options for branch <b>%s</b>.
|
||||
settings.protect_this_branch=Protect this branch
|
||||
settings.protect_this_branch_desc=Disable force pushes and prevent from deletion.
|
||||
settings.protect_require_pull_request=Require pull request instead direct pushing
|
||||
settings.protect_require_pull_request_desc=Enable this option to disable direct pushing to this branch. Commits have to be pushed to another non-protected branch and merged to this branch through pull request.
|
||||
settings.protect_whitelist_committers=Whitelist who can push to this branch
|
||||
settings.protect_whitelist_committers_desc=Add people or teams to whitelist of direct push to this branch.
|
||||
settings.update_protect_branch_success=Protect options for this branch has been updated successfully!
|
||||
settings.protected_branches_desc=Schützt Branches vor forcierten Pushes und versehentlichem Löschen. Comitter können freigeschaltet werden.
|
||||
settings.choose_a_branch=Wählen Sie einen Branch...
|
||||
settings.branch_protection=Branch-Schutz
|
||||
settings.branch_protection_desc=Bitte wählen Sie Schutzoptionen für den Branch <b>%s</b>.
|
||||
settings.protect_this_branch=Diesen Branch schützen
|
||||
settings.protect_this_branch_desc=Verhindere forcierte Pushes sowie Löschungen.
|
||||
settings.protect_require_pull_request=Verlange Pull-Request an Stelle von direkten Pushes
|
||||
settings.protect_require_pull_request_desc=Aktivieren Sie diese Option, um direktes Pushen in diesen Branch zu verhindern. Commits müssen in einen anderen, ungeschützten Branch gepusht werden und dann per Pull-Request in diesen Branch überführt werden.
|
||||
settings.protect_whitelist_committers=Hinzufügen von Benutzern oder Teams zur Whitelist, die in diesen Branch pushen dürfen
|
||||
settings.protect_whitelist_committers_desc=Benutzer oder Teams zur Whitelist hinzufügen.
|
||||
settings.protect_whitelist_users=Benutzer, die in diesen Branch pushen können
|
||||
settings.protect_whitelist_search_users=Benutzer suchen
|
||||
settings.protect_whitelist_teams=Teams, deren Mitglieder in diesen Branch pushen können
|
||||
settings.protect_whitelist_search_teams=Teams suchen
|
||||
settings.update_protect_branch_success=Schutzoptionen für diesen Branch wurden erfolgreich aktualisiert!
|
||||
settings.hooks=Webhooks
|
||||
settings.githooks=Git-Hooks
|
||||
settings.basic_settings=Grundeinstellungen
|
||||
@@ -675,7 +679,7 @@ settings.external_wiki_url_desc=Besucher werden auf diese URL umgeleitet, wenn s
|
||||
settings.issues_desc=Issue-Tracker einschalten
|
||||
settings.use_internal_issue_tracker=Eingebauten Issue-Tracker verwenden
|
||||
settings.use_external_issue_tracker=Externes Issue-System verwenden
|
||||
settings.external_tracker_url=Externe Issue-Tracker URL
|
||||
settings.external_tracker_url=URL eines externen Issue Trackers
|
||||
settings.external_tracker_url_desc=Besucher werden auf diese URL umgeleitet, wenn sie auf den Tab klicken.
|
||||
settings.tracker_url_format=URL-Format des externen Issue-Systems
|
||||
settings.tracker_issue_style=Namenskonvention des externen Issue-Trackers:
|
||||
@@ -684,6 +688,7 @@ settings.tracker_issue_style.alphanumeric=Alphanumerisch
|
||||
settings.tracker_url_format_desc=Sie können die Platzhalter <code>{user} {repo} {index}</code> für den Benutzernamen, den Namen des Repositories und die Issue-Nummer verwenden.
|
||||
settings.pulls_desc=Pull-Requests aktivieren, um öffentliche Mitwirkung zu ermöglichen
|
||||
settings.danger_zone=Gefahrenzone
|
||||
settings.cannot_fork_to_same_owner=Besitzer kann das Repository nicht forken.
|
||||
settings.new_owner_has_same_repo=Der neue Eigentümer hat bereits ein Repository mit dem gleichen Namen. Bitte wählen Sie einen anderen Namen.
|
||||
settings.convert=In ein normales Repository umwandeln
|
||||
settings.convert_desc=Dieser Mirror kann in ein normales Repository umgewandelt werden. Dies kann nicht rückgängig gemacht werden.
|
||||
@@ -718,7 +723,6 @@ settings.collaborator_deletion_desc=Nach dem Löschen wird dieser Benutzer keine
|
||||
settings.remove_collaborator_success=Mitarbeiter wurde entfernt.
|
||||
settings.search_user_placeholder=Benutzer suchen...
|
||||
settings.org_not_allowed_to_be_collaborator=Eine Organisation kann nicht als Mitarbeiter hinzugefügt werden.
|
||||
settings.user_is_org_member=Benutzer ist ein Organisationsmitglied und kann nicht als Mitarbeiter hinzugefügt werden.
|
||||
settings.add_webhook=Webhook hinzufügen
|
||||
settings.hooks_desc=Webhooks erlauben es Ihnen, externe Dienste zu informieren, wenn etwas Bestimmtes in Ihrem Repository passiert. Gogs sendet dann einen POST-Request an alle angegebenen URLs. Erfahren Sie mehr in unserem <a target="_blank" href="%s">Webhooks Guide</a>.
|
||||
settings.webhook_deletion=Webhook entfernen
|
||||
@@ -741,6 +745,7 @@ settings.add_webhook_desc=Gogs sendet einen <code>POST</code>-Request an die unt
|
||||
settings.payload_url=Payload URL
|
||||
settings.content_type=Inhaltstyp
|
||||
settings.secret=Secret
|
||||
settings.secret_desc=Das Secret wird im <code>X-Gogs-Signature</code> Header als hexadezimalem SHA256 HMAC Stempel der Nutzlast.
|
||||
settings.slack_username=Benutzername
|
||||
settings.slack_icon_url=Icon URL
|
||||
settings.slack_color=Farbe
|
||||
@@ -763,12 +768,12 @@ settings.delete_webhook=Webhook löschen
|
||||
settings.recent_deliveries=Letzte Zustellungen
|
||||
settings.hook_type=Hook Typ
|
||||
settings.add_slack_hook_desc=Fügen Sie <a href="%s">Slack</a>-Integration zu Ihrem Repository hinzu.
|
||||
settings.add_discord_hook_desc=Add <a href="%s">Discord</a> integration to your repository.
|
||||
settings.add_discord_hook_desc=Fügen Sie <a href="%s">Discord</a>-Integration zu Ihrem Repository hinzu.
|
||||
settings.slack_token=Token
|
||||
settings.slack_domain=Domain
|
||||
settings.slack_channel=Kanal
|
||||
settings.deploy_keys=Deploy-Schlüssel
|
||||
settings.deploy_keys_helper=<b>Common Gotcha!</b> If you're looking for adding personal public keys, please add them in your <a href="%s%s">account settings</a>.
|
||||
settings.deploy_keys_helper=<b>Häufiger Fehler!</b> Wenn Sie öffentliche Schlüssel hinzufügen wollen, gehen Sie zu Ihren <a href="%s%s"> Kontoeinstellungen</a>.
|
||||
settings.add_deploy_key=Deploy-Schlüssel hinzufügen
|
||||
settings.deploy_key_desc=Deploy-Schlüssel haben nur lesenden Zugriff. Sie sind nicht identisch mit dem SSH-Schlüssel des persönlichen Kontos.
|
||||
settings.no_deploy_keys=Sie haben noch keine Deploy-Schlüssel hinzugefügt.
|
||||
@@ -847,7 +852,7 @@ team_permission_desc=Welche Berechtigungsstufe soll das Team haben?
|
||||
|
||||
form.name_reserved=Organisationsname '%s' ist bereits vergeben.
|
||||
form.name_pattern_not_allowed=Organisationsnamen der Form '%s' sind nicht erlaubt.
|
||||
form.team_name_reserved=Team name '%s' is reserved.
|
||||
form.team_name_reserved=Der Teamname '%s' ist reserviert.
|
||||
|
||||
settings=Einstellungen
|
||||
settings.options=Optionen
|
||||
@@ -938,8 +943,8 @@ dashboard.git_gc_repos=Garbage Collection auf Repositories ausführen
|
||||
dashboard.git_gc_repos_success=Garbage Collection wurde auf allen Repositories erfolgreich ausgeführt.
|
||||
dashboard.resync_all_sshkeys=Datei '.ssh/authorized_keys' neu anlegen (Achtung: Schlüssel, die nicht zu Gogs gehören gehen verloren)
|
||||
dashboard.resync_all_sshkeys_success=Alle öffentlichen Keys wurden erfolgreich neu geschrieben.
|
||||
dashboard.resync_all_hooks=Resync pre-receive, update and post-receive hooks of all repositories
|
||||
dashboard.resync_all_hooks_success=All repositories' pre-receive, update and post-receive hooks have been resynced successfully.
|
||||
dashboard.resync_all_hooks=Synchronisiere pre-receive, update und post-receive Hooks für alle Repositorien
|
||||
dashboard.resync_all_hooks_success=Pre-receive, update und post-receive Hooks aller Repositorien wurden erfolgreich synchronisiert.
|
||||
dashboard.reinit_missing_repos=Alle Repository-Datensätze mit verloren gegangenen Git-Dateien neu initialisieren
|
||||
dashboard.reinit_missing_repos_success=Alle Repository-Datensätze, die Git-Dateien verloren haben wurden erfolgreich neu initialisiert.
|
||||
|
||||
@@ -1089,15 +1094,15 @@ config.ssh_keygen_path=Keygen ('ssh-keygen') Pfad
|
||||
config.ssh_minimum_key_size_check=Prüfung der Mindestschlüssellänge
|
||||
config.ssh_minimum_key_sizes=Minimale Schlüssellängen
|
||||
|
||||
config.repo_config=Repository Configuration
|
||||
config.repo_config=Repository-Konfiguration
|
||||
config.repo_root_path=Repository-Verzeichnis
|
||||
config.script_type=Skript-Typ
|
||||
config.repo_force_private=Force Private
|
||||
config.max_creation_limit=Max Creation Limit
|
||||
config.preferred_licenses=Preferred Licenses
|
||||
config.disable_http_git=Disable HTTP Git
|
||||
config.enable_local_path_migration=Enable Local Path Migration
|
||||
config.commits_fetch_concurrency=Commits Fetch Concurrency
|
||||
config.repo_force_private=Erzwinge privat
|
||||
config.max_creation_limit=Maximal erstellbare Anzahl
|
||||
config.preferred_licenses=Bevorzugte Lizenzen
|
||||
config.disable_http_git=Deaktiviere HTTP-Git
|
||||
config.enable_local_path_migration=Erlaube Migration von lokalem Pfad
|
||||
config.commits_fetch_concurrency=Anzahl gleichzeitiger Commit-/Fetch-Prozesse
|
||||
|
||||
config.db_config=Datenbankkonfiguration
|
||||
config.db_type=Typ
|
||||
|
||||
@@ -201,6 +201,7 @@ Content = Content
|
||||
require_error = ` cannot be empty.`
|
||||
alpha_dash_error = ` must be valid alpha or numeric or dash(-_) characters.`
|
||||
alpha_dash_dot_error = ` must be valid alpha or numeric or dash(-_) or dot characters.`
|
||||
alpha_dash_dot_slash_error = ` must be valid alpha or numeric or dash(-_) or dot characters or slashes.`
|
||||
size_error = ` must be size %s.`
|
||||
min_size_error = ` must contain at least %s characters.`
|
||||
max_size_error = ` must contain at most %s characters.`
|
||||
@@ -656,6 +657,10 @@ settings.protect_require_pull_request = Require pull request instead direct push
|
||||
settings.protect_require_pull_request_desc = Enable this option to disable direct pushing to this branch. Commits have to be pushed to another non-protected branch and merged to this branch through pull request.
|
||||
settings.protect_whitelist_committers = Whitelist who can push to this branch
|
||||
settings.protect_whitelist_committers_desc = Add people or teams to whitelist of direct push to this branch.
|
||||
settings.protect_whitelist_users = Users who can push to this branch
|
||||
settings.protect_whitelist_search_users = Search users
|
||||
settings.protect_whitelist_teams = Teams for which members of them can push to this branch
|
||||
settings.protect_whitelist_search_teams = Search teams
|
||||
settings.update_protect_branch_success = Protect options for this branch has been updated successfully!
|
||||
settings.hooks = Webhooks
|
||||
settings.githooks = Git Hooks
|
||||
@@ -684,6 +689,7 @@ settings.tracker_issue_style.alphanumeric = Alphanumeric
|
||||
settings.tracker_url_format_desc = You can use placeholder <code>{user} {repo} {index}</code> for user name, repository name and issue index.
|
||||
settings.pulls_desc = Enable pull requests to accept public contributions
|
||||
settings.danger_zone = Danger Zone
|
||||
settings.cannot_fork_to_same_owner = You cannot fork a repository to its original owner.
|
||||
settings.new_owner_has_same_repo = The new owner already has a repository with same name. Please choose another name.
|
||||
settings.convert = Convert To Regular Repository
|
||||
settings.convert_desc = You can convert this mirror to a regular repository. This cannot be reversed.
|
||||
@@ -718,7 +724,6 @@ settings.collaborator_deletion_desc = This user will no longer have collaboratio
|
||||
settings.remove_collaborator_success = Collaborator has been removed.
|
||||
settings.search_user_placeholder = Search user...
|
||||
settings.org_not_allowed_to_be_collaborator = Organization is not allowed to be added as a collaborator.
|
||||
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 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.webhook_deletion = Delete Webhook
|
||||
@@ -741,6 +746,7 @@ settings.add_webhook_desc = Gogs will send a <code>POST</code> request to the UR
|
||||
settings.payload_url = Payload URL
|
||||
settings.content_type = Content Type
|
||||
settings.secret = Secret
|
||||
settings.secret_desc = Secret will be sent as SHA256 HMAC hex digest of payload via <code>X-Gogs-Signature</code> header.
|
||||
settings.slack_username = Username
|
||||
settings.slack_icon_url = Icon URL
|
||||
settings.slack_color = Color
|
||||
@@ -749,7 +755,11 @@ settings.event_push_only = Just the <code>push</code> event.
|
||||
settings.event_send_everything = I need <strong>everything</strong>.
|
||||
settings.event_choose = Let me choose what I need.
|
||||
settings.event_create = Create
|
||||
settings.event_create_desc = Branch, or tag created
|
||||
settings.event_create_desc = Branch or tag created
|
||||
settings.event_delete = Delete
|
||||
settings.event_delete_desc = Branch or tag deleted
|
||||
settings.event_fork = Fork
|
||||
settings.event_fork_desc = Repository forked
|
||||
settings.event_pull_request = Pull Request
|
||||
settings.event_pull_request_desc = Pull request opened, closed, reopened, edited, assigned, unassigned, label updated, label cleared, or synchronized.
|
||||
settings.event_push = Push
|
||||
@@ -1171,7 +1181,8 @@ config.git_pull_timeout = Pull Operation Timeout
|
||||
config.git_gc_timeout = GC Operation Timeout
|
||||
|
||||
config.log_config = Log Configuration
|
||||
config.log_mode = Log Mode
|
||||
config.log_mode = Mode
|
||||
config.log_options = Options
|
||||
|
||||
monitor.cron = Cron Tasks
|
||||
monitor.name = Name
|
||||
@@ -1200,19 +1211,23 @@ notices.delete_success = System notices have been deleted successfully.
|
||||
|
||||
[action]
|
||||
create_repo = created repository <a href="%s">%s</a>
|
||||
fork_repo = forked a repository to <a href="%s">%s</a>
|
||||
rename_repo = renamed repository from <code>%[1]s</code> to <a href="%[2]s">%[3]s</a>
|
||||
commit_repo = pushed to <a href="%[1]s/src/%[2]s">%[3]s</a> at <a href="%[1]s">%[4]s</a>
|
||||
compare_commits = View comparison for these %d commits
|
||||
transfer_repo = transfered repository <code>%s</code> to <a href="%s">%s</a>
|
||||
create_issue = `opened issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
close_issue = `closed issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
reopen_issue = `reopened issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
comment_issue = `commented on issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
create_pull_request = `created pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
close_pull_request = `closed pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
reopen_pull_request = `reopened pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
comment_issue = `commented on issue <a href="%s/issues/%s">%s#%[2]s</a>`
|
||||
merge_pull_request = `merged pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
|
||||
transfer_repo = transfered repository <code>%s</code> to <a href="%s">%s</a>
|
||||
create_branch = created new branch <a href="%[1]s/src/%[2]s">%[3]s</a> at <a href="%[1]s">%[4]s</a>
|
||||
delete_branch = deleted branch <code>%[2]s</code> at <a href="%[1]s">%[3]s</a>
|
||||
push_tag = pushed tag <a href="%s/src/%s">%[2]s</a> to <a href="%[1]s">%[3]s</a>
|
||||
compare_commits = View comparison for these %d commits
|
||||
delete_tag = deleted tag <code>%[2]s</code> at <a href="%[1]s">%[3]s</a>
|
||||
|
||||
[tool]
|
||||
ago = ago
|
||||
|
||||
@@ -656,6 +656,10 @@ settings.protect_require_pull_request=Requiere una solicitud pull, en lugar de u
|
||||
settings.protect_require_pull_request_desc=Active esta opción para deshabilitar un push directo a esta rama. Los commits tienen que ser empujados a otra rama no protegida y fusionados a esta rama a través de la solicitud pull.
|
||||
settings.protect_whitelist_committers=Lista blanca de quienes pueden empujar a esta rama
|
||||
settings.protect_whitelist_committers_desc=Añadir personas o equipos a la lista blanca de empuje directo a esta rama.
|
||||
settings.protect_whitelist_users=Users who can push to this branch
|
||||
settings.protect_whitelist_search_users=Search users
|
||||
settings.protect_whitelist_teams=Teams for which members of them can push to this branch
|
||||
settings.protect_whitelist_search_teams=Search teams
|
||||
settings.update_protect_branch_success=Protect options for this branch has been updated successfully!
|
||||
settings.hooks=Webhooks
|
||||
settings.githooks=Git Hooks
|
||||
@@ -684,6 +688,7 @@ settings.tracker_issue_style.alphanumeric=Alfanumérico
|
||||
settings.tracker_url_format_desc=Puedes usar las plantillas <code>{user} {repo} {index}</code> para el nombre de usuario, nombre del repositorio e índice de la incidencia.
|
||||
settings.pulls_desc=Habilitar Pull Requests para aceptar contribuciones públicas
|
||||
settings.danger_zone=Zona de Peligro
|
||||
settings.cannot_fork_to_same_owner=You cannot fork a repository to its original owner.
|
||||
settings.new_owner_has_same_repo=El nuevo propietario tiene un repositorio con el mismo nombre.
|
||||
settings.convert=Convertir en un repositorio normal
|
||||
settings.convert_desc=Puedes convertir este repositorio en un repositorio normal. Este cambio no se puede deshacer.
|
||||
@@ -718,7 +723,6 @@ settings.collaborator_deletion_desc=Este usuario no podrá colaborar en este rep
|
||||
settings.remove_collaborator_success=El colaborador ha sido eliminado.
|
||||
settings.search_user_placeholder=Buscar usuario...
|
||||
settings.org_not_allowed_to_be_collaborator=Las organizaciones no tiene permitido ser añadidas como colaboradores.
|
||||
settings.user_is_org_member=El usuario es miembro de la organización, no puede ser añadido como colaborador.
|
||||
settings.add_webhook=Añadir Webhook
|
||||
settings.hooks_desc=Los Webhooks permiten a servicios externos recibir notificaciones cuando sucedan ciertos eventos en Gogs. Cuando sucedan los eventos especificados, enviaremos una petición POST a cada una de las URLs indicadas. Para obtener más información, consulta nuestra <a target="_blank" href="%s">Guía de Webhooks</a>.
|
||||
settings.webhook_deletion=Eliminar Webhook
|
||||
@@ -741,6 +745,7 @@ settings.add_webhook_desc=Enviaremos una petición <code>POST</code> a la siguie
|
||||
settings.payload_url=URL de Payload
|
||||
settings.content_type=Tipo de contenido
|
||||
settings.secret=Secreto
|
||||
settings.secret_desc=Secret will be sent as SHA256 HMAC hex digest of payload via <code>X-Gogs-Signature</code> header.
|
||||
settings.slack_username=Nombre de usuario
|
||||
settings.slack_icon_url=URL de icono
|
||||
settings.slack_color=Color
|
||||
|
||||
@@ -656,6 +656,10 @@ settings.protect_require_pull_request=Vaadi pull-pyyntö suoran push-operaation
|
||||
settings.protect_require_pull_request_desc=Estä suorat push-operaatiot tähän haaraan. Commitit täytyy pushata ei-suojattuun haaraan ja yhdistää tähän haaraan pull-pyynnön kautta.
|
||||
settings.protect_whitelist_committers=Lista sallituista, jotka voivat pushata tähän haaraan
|
||||
settings.protect_whitelist_committers_desc=Lisää ihmisiä tai tiimejä sallittujen listaan, jotka voivat pushata suoraan tähän haaraan.
|
||||
settings.protect_whitelist_users=Users who can push to this branch
|
||||
settings.protect_whitelist_search_users=Search users
|
||||
settings.protect_whitelist_teams=Teams for which members of them can push to this branch
|
||||
settings.protect_whitelist_search_teams=Search teams
|
||||
settings.update_protect_branch_success=Protect options for this branch has been updated successfully!
|
||||
settings.hooks=Webkoukut
|
||||
settings.githooks=Git koukut
|
||||
@@ -684,6 +688,7 @@ settings.tracker_issue_style.alphanumeric=Aakkosnumeerinen
|
||||
settings.tracker_url_format_desc=Voit käyttää paikkamerkkiä <code>{user} {repo} {index}</code> käyttäjänimelle, reponimelle ja vikanumerolle.
|
||||
settings.pulls_desc=Ota käyttöön pull-pyynnöt salliaksesi julkiset koodilahjoitukset
|
||||
settings.danger_zone=Vaaravyöhyke
|
||||
settings.cannot_fork_to_same_owner=You cannot fork a repository to its original owner.
|
||||
settings.new_owner_has_same_repo=Uudella omistajalla on jo samanniminen repo. Ole hyvä ja valitse toinen nimi.
|
||||
settings.convert=Muunna tavalliseksi repoksi
|
||||
settings.convert_desc=Voit muuntaa tämän peilin tavalliseksi repoksi. Tätä ei voi peruuttaa.
|
||||
@@ -718,7 +723,6 @@ settings.collaborator_deletion_desc=Tällä käyttäjällä ei tule enää olema
|
||||
settings.remove_collaborator_success=Yhteistyökumppani on poistettu.
|
||||
settings.search_user_placeholder=Etsi käyttäjä...
|
||||
settings.org_not_allowed_to_be_collaborator=Yhteistyökumppaniksi ei voi lisätä organisaatiota.
|
||||
settings.user_is_org_member=Käyttäjä on organisaation jäsen, jota ei voi lisätä yhteistyökumppaniksi.
|
||||
settings.add_webhook=Lisää webkoukku
|
||||
settings.hooks_desc=Webkoukut muistuttavat paljon perus HTTP POST tapahtuma laukaisimia. Aina kun jotain tapahtuu Gogsissa, käsittelemme ilmoituksen määrittäämääsi kohteeseen. Lisätietoja <a target="_blank" href="%s">webkoukku oppaassa</a>.
|
||||
settings.webhook_deletion=Poista webkoukku
|
||||
@@ -741,6 +745,7 @@ settings.add_webhook_desc=Gogs lähettää <code>POST</code> requestin määritt
|
||||
settings.payload_url=Payload URL
|
||||
settings.content_type=Sisältötyyppi
|
||||
settings.secret=Salaus
|
||||
settings.secret_desc=Secret will be sent as SHA256 HMAC hex digest of payload via <code>X-Gogs-Signature</code> header.
|
||||
settings.slack_username=Käyttäjätunnus
|
||||
settings.slack_icon_url=Kuvakkeen URL
|
||||
settings.slack_color=Väri
|
||||
|
||||
@@ -399,7 +399,7 @@ migrate.failed=Echec de migration: %v
|
||||
mirror_from=miroir de
|
||||
forked_from=forké depuis
|
||||
copy_link=Copier
|
||||
copy_link_success=Copié!
|
||||
copy_link_success=Copié !
|
||||
copy_link_error=Appuyez sur ⌘-C ou Ctrl-C pour copier
|
||||
copied=Copié
|
||||
unwatch=Ne plus suivre
|
||||
@@ -423,7 +423,7 @@ branches=Branches
|
||||
tags=Tags
|
||||
issues=Tickets
|
||||
pulls=Pull Requests
|
||||
labels=Etiquettes
|
||||
labels=Étiquettes
|
||||
milestones=Jalons
|
||||
commits=Commits
|
||||
releases=Publications
|
||||
@@ -473,7 +473,7 @@ editor.add_subdir=Ajouter un sous-répertoire...
|
||||
editor.unable_to_upload_files=Échec lors de l'envoie du fichier '%s' avec l’erreur : %v
|
||||
editor.upload_files_to_dir=Transférer les fichiers vers '%s'
|
||||
|
||||
commits.commit_history=Commit History
|
||||
commits.commit_history=Historique des commits
|
||||
commits.commits=Commits
|
||||
commits.search=Rechercher des commits
|
||||
commits.find=Trouver
|
||||
@@ -484,7 +484,7 @@ commits.older=Précédemment
|
||||
commits.newer=Récemment
|
||||
|
||||
issues.new=Nouveau ticket
|
||||
issues.new.labels=Etiquettes
|
||||
issues.new.labels=Étiquettes
|
||||
issues.new.no_label=Pas d'étiquette
|
||||
issues.new.clear_labels=Effacer les étiquettes
|
||||
issues.new.milestone=Jalon
|
||||
@@ -656,7 +656,11 @@ settings.protect_require_pull_request=Exiger une requête de fusion plutôt qu'u
|
||||
settings.protect_require_pull_request_desc=Activez cette option pour empêcher la publication immédiate vers cette branche. Les commits devront être publiés vers une autre branche (non protégée) et fusionnée dans cette branche avec une requête de fusion.
|
||||
settings.protect_whitelist_committers=Liste blanche de personnes pouvant publier sur cette branche
|
||||
settings.protect_whitelist_committers_desc=Ajouter des personnes ou des équipes à la liste blanche de publication directe vers cette branche.
|
||||
settings.update_protect_branch_success=Protect options for this branch has been updated successfully!
|
||||
settings.protect_whitelist_users=Utilisateurs qui peuvent pousser sur cette branche
|
||||
settings.protect_whitelist_search_users=Rechercher des utilisateurs
|
||||
settings.protect_whitelist_teams=Les équipes pour lesquelles les membres peuvent pousser sur cette branche
|
||||
settings.protect_whitelist_search_teams=Rechercher des équipes
|
||||
settings.update_protect_branch_success=Les options de protection de cette branches ont été mises à jour avec succès.
|
||||
settings.hooks=Webhooks
|
||||
settings.githooks=Git Hooks
|
||||
settings.basic_settings=Paramètres de base
|
||||
@@ -684,6 +688,7 @@ settings.tracker_issue_style.alphanumeric=Alphanumérique
|
||||
settings.tracker_url_format_desc=Vous pouvez utiliser l'espace réservé <code>{user} {repo} {index}</code> pour le nom d'utilisateur, le nom du dépôt et le numéro de bug.
|
||||
settings.pulls_desc=Activer les pull requests pour accepter les contributions publiques
|
||||
settings.danger_zone=Zone de danger
|
||||
settings.cannot_fork_to_same_owner=Vous ne pouvez par créer un fork d'un dépot à son propriétaire actuel.
|
||||
settings.new_owner_has_same_repo=Le nouveau propriétaire a déjà un dépôt nommé ainsi.
|
||||
settings.convert=Convertir en dépôt ordinaire
|
||||
settings.convert_desc=Vous pouvez convertir ce miroir en dépôt ordinaire. Cela ne peut pas être inversée.
|
||||
@@ -718,7 +723,6 @@ settings.collaborator_deletion_desc=Cet utilisateur n'aura plus accès pour coll
|
||||
settings.remove_collaborator_success=Collaborateur supprimé.
|
||||
settings.search_user_placeholder=Rechercher un utilisateur...
|
||||
settings.org_not_allowed_to_be_collaborator=Une organisation n'est pas autorisée à être ajoutée en tant que collaborateur.
|
||||
settings.user_is_org_member=Cet utilisateur ne peut pas être ajouté en tant que collaborateur car il fait partie d'une organisation.
|
||||
settings.add_webhook=Ajouter un Webhook
|
||||
settings.hooks_desc=Les Webhooks sont des déclencheurs de POST HTTP . Lorsque qu'un événement se produit dans Gogs, une notification sera envoyée vers l'hôte cible préalablement spécifié. Apprenez-en davantage dans le <a target="_blank" href="%s">Guide des Webhooks</a>.
|
||||
settings.webhook_deletion=Supprimer le Webhook
|
||||
@@ -741,6 +745,7 @@ settings.add_webhook_desc=Une requête <code>POST</code> sera transmise vers l'U
|
||||
settings.payload_url=URL des Données Utiles
|
||||
settings.content_type=Type de contenu
|
||||
settings.secret=Confidentiel
|
||||
settings.secret_desc=Le secret sera envoyé comme digest de payload SHA256 HMAC hex avec l'entête <code>X-Gogs-Signature</code>.
|
||||
settings.slack_username=Nom d'utilisateur
|
||||
settings.slack_icon_url=URL de l'icône
|
||||
settings.slack_color=Couleur
|
||||
@@ -781,7 +786,7 @@ settings.deploy_key_deletion=Supprimer la Clé de Déploiement
|
||||
settings.deploy_key_deletion_desc=Supprimer cette clé de déploiement effacera tous les accès relatifs pour ce référentiel. Voulez-vous continuer ?
|
||||
settings.deploy_key_deletion_success=La clé de déploiement a été supprimée avec succès !
|
||||
|
||||
diff.browse_source=Parcourir la Source
|
||||
diff.browse_source=Parcourir la source
|
||||
diff.parent=Parent
|
||||
diff.commit=commit
|
||||
diff.data_not_available=Données Diff indisponibles.
|
||||
|
||||
@@ -531,7 +531,7 @@ issues.next=Páxina seguinte
|
||||
issues.open_title=Aberta
|
||||
issues.closed_title=Cerrada
|
||||
issues.num_comments=%d comentarios
|
||||
issues.commented_at='comentado <a href="#%s"> %s'</a>
|
||||
issues.commented_at=`comentado <a href="#%s"> %s'</a>`
|
||||
issues.delete_comment_confirm=Seguro que desexas eliminar este comentario?
|
||||
issues.no_content=Aínda non existe contido.
|
||||
issues.close_issue=Cerrar
|
||||
@@ -656,6 +656,10 @@ settings.protect_require_pull_request=Require pull request instead direct pushin
|
||||
settings.protect_require_pull_request_desc=Enable this option to disable direct pushing to this branch. Commits have to be pushed to another non-protected branch and merged to this branch through pull request.
|
||||
settings.protect_whitelist_committers=Whitelist who can push to this branch
|
||||
settings.protect_whitelist_committers_desc=Add people or teams to whitelist of direct push to this branch.
|
||||
settings.protect_whitelist_users=Users who can push to this branch
|
||||
settings.protect_whitelist_search_users=Search users
|
||||
settings.protect_whitelist_teams=Teams for which members of them can push to this branch
|
||||
settings.protect_whitelist_search_teams=Search teams
|
||||
settings.update_protect_branch_success=Protect options for this branch has been updated successfully!
|
||||
settings.hooks=Webhooks
|
||||
settings.githooks=Git Hooks
|
||||
@@ -684,6 +688,7 @@ settings.tracker_issue_style.alphanumeric=Alfanumérico
|
||||
settings.tracker_url_format_desc=Podes usar os modelos <code>{user} {repo} {index}</code> para o nome de usuario, nome do repositorio e índice da incidencia.
|
||||
settings.pulls_desc=Habilitar Pull Requests para aceptar contribucións públicas
|
||||
settings.danger_zone=Zona de perigo
|
||||
settings.cannot_fork_to_same_owner=You cannot fork a repository to its original owner.
|
||||
settings.new_owner_has_same_repo=O novo propietario ten un repositorio co mesmo nome.
|
||||
settings.convert=Converter nun repositorio normal
|
||||
settings.convert_desc=Podes converter este repositorio nun repositorio normal. Este cambio non se pode desfacer.
|
||||
@@ -718,7 +723,6 @@ settings.collaborator_deletion_desc=Este usuario non poderá colaborar neste rep
|
||||
settings.remove_collaborator_success=O colaborador foi eliminado.
|
||||
settings.search_user_placeholder=Buscar usuario...
|
||||
settings.org_not_allowed_to_be_collaborator=As organizacións non teñen permitido ser engadidas como colaboradores.
|
||||
settings.user_is_org_member=O usuario é membro da organización, non pode ser engadido como colaborador.
|
||||
settings.add_webhook=Engadir Webhook
|
||||
settings.hooks_desc=Os Webhooks permiten a servizos externos recibir notificacións cando sucedan certos eventos en Gogs. Cando sucedan os eventos especificados, enviaremos unha petición POST a cada unha das URLs indicadas. Para obter máis información, consulta a nosa <a target="_blank" href="%s">Guía de Webhooks</a>.
|
||||
settings.webhook_deletion=Eliminar Webhook
|
||||
@@ -741,6 +745,7 @@ settings.add_webhook_desc=Enviaremos unha petición <code>POST</code> á seguint
|
||||
settings.payload_url=URL de Payload
|
||||
settings.content_type=Tipo de contido
|
||||
settings.secret=Secreto
|
||||
settings.secret_desc=Secret will be sent as SHA256 HMAC hex digest of payload via <code>X-Gogs-Signature</code> header.
|
||||
settings.slack_username=Nome da persoa usuaria
|
||||
settings.slack_icon_url=URL da icona
|
||||
settings.slack_color=Cor
|
||||
|
||||
@@ -656,6 +656,10 @@ settings.protect_require_pull_request=Require pull request instead direct pushin
|
||||
settings.protect_require_pull_request_desc=Enable this option to disable direct pushing to this branch. Commits have to be pushed to another non-protected branch and merged to this branch through pull request.
|
||||
settings.protect_whitelist_committers=Whitelist who can push to this branch
|
||||
settings.protect_whitelist_committers_desc=Add people or teams to whitelist of direct push to this branch.
|
||||
settings.protect_whitelist_users=Users who can push to this branch
|
||||
settings.protect_whitelist_search_users=Search users
|
||||
settings.protect_whitelist_teams=Teams for which members of them can push to this branch
|
||||
settings.protect_whitelist_search_teams=Search teams
|
||||
settings.update_protect_branch_success=Protect options for this branch has been updated successfully!
|
||||
settings.hooks=Webhooks
|
||||
settings.githooks=Git Hooks
|
||||
@@ -684,6 +688,7 @@ settings.tracker_issue_style.alphanumeric=Alphanumeric
|
||||
settings.tracker_url_format_desc=You can use placeholder <code>{user} {repo} {index}</code> for user name, repository name and issue index.
|
||||
settings.pulls_desc=Abilita le pull requests per accettare contributi pubblici
|
||||
settings.danger_zone=Zona Pericolosa
|
||||
settings.cannot_fork_to_same_owner=You cannot fork a repository to its original owner.
|
||||
settings.new_owner_has_same_repo=Il nuovo proprietario ha già un repository con lo stesso nome. Per favore scegli un altro nome.
|
||||
settings.convert=Converti in Repository Regolare
|
||||
settings.convert_desc=Puoi convertire questo mirror in un repository regolare. Questa operazione non può essere annullata.
|
||||
@@ -718,7 +723,6 @@ settings.collaborator_deletion_desc=Questo utente non potrà più collaborare a
|
||||
settings.remove_collaborator_success=Il collaboratore è stato rimosso.
|
||||
settings.search_user_placeholder=Cerca utente...
|
||||
settings.org_not_allowed_to_be_collaborator=Un'organizzazione non può essere aggiunta come collaboratore.
|
||||
settings.user_is_org_member=L'utente è un membro dell'organizzazione che non può essere aggiunto come collaboratore.
|
||||
settings.add_webhook=Aggiungi Webhook
|
||||
settings.hooks_desc=I Webhooks sono molto simili a un basilare evento trigger HTTP POST. Ogni volta che qualcosa si verifica in Gogs, tratteremo la notifica all'host di destinazione specificato. Ulteriori informazioni in questa <a target="_blank" href="%s">Guida ai Webhooks</a>.
|
||||
settings.webhook_deletion=Elimina Webhook
|
||||
@@ -741,6 +745,7 @@ settings.add_webhook_desc=Gogs manderà una richiesta <code>POST</code> all'URL
|
||||
settings.payload_url=Payload URL
|
||||
settings.content_type=Content Type
|
||||
settings.secret=Secret
|
||||
settings.secret_desc=Secret will be sent as SHA256 HMAC hex digest of payload via <code>X-Gogs-Signature</code> header.
|
||||
settings.slack_username=Nome utente
|
||||
settings.slack_icon_url=URL icona
|
||||
settings.slack_color=Colore
|
||||
|
||||
@@ -656,6 +656,10 @@ settings.protect_require_pull_request=Require pull request instead direct pushin
|
||||
settings.protect_require_pull_request_desc=Enable this option to disable direct pushing to this branch. Commits have to be pushed to another non-protected branch and merged to this branch through pull request.
|
||||
settings.protect_whitelist_committers=Whitelist who can push to this branch
|
||||
settings.protect_whitelist_committers_desc=Add people or teams to whitelist of direct push to this branch.
|
||||
settings.protect_whitelist_users=Users who can push to this branch
|
||||
settings.protect_whitelist_search_users=Search users
|
||||
settings.protect_whitelist_teams=Teams for which members of them can push to this branch
|
||||
settings.protect_whitelist_search_teams=Search teams
|
||||
settings.update_protect_branch_success=Protect options for this branch has been updated successfully!
|
||||
settings.hooks=Webhooks
|
||||
settings.githooks=Git のフック
|
||||
@@ -684,6 +688,7 @@ settings.tracker_issue_style.alphanumeric=Alphanumeric
|
||||
settings.tracker_url_format_desc=You can use placeholder <code>{user} {repo} {index}</code> for user name, repository name and issue index.
|
||||
settings.pulls_desc=Enable pull requests to accept public contributions
|
||||
settings.danger_zone=危険地帯
|
||||
settings.cannot_fork_to_same_owner=You cannot fork a repository to its original owner.
|
||||
settings.new_owner_has_same_repo=新しいオーナーは、既に同じ名前のリポジトリを持っています。
|
||||
settings.convert=Convert To Regular Repository
|
||||
settings.convert_desc=You can convert this mirror to a regular repository. This cannot be reversed.
|
||||
@@ -718,7 +723,6 @@ settings.collaborator_deletion_desc=This user will no longer have collaboration
|
||||
settings.remove_collaborator_success=共同編集者が削除されました。
|
||||
settings.search_user_placeholder=Search users
|
||||
settings.org_not_allowed_to_be_collaborator=組織を共同編集者として追加することはできません。
|
||||
settings.user_is_org_member=ユーザーは組織の一員なので、共同編集者として追加することはできません。
|
||||
settings.add_webhook=Webhook を追加
|
||||
settings.hooks_desc=Webhooksは、Gogsで特定のイベントの発生時に指定された外部サービスに通知を許可します。イベントが発生すると、それぞれ指定されたUrlに、POSTリクエストが送られます。詳細はこちらのの <a target="_blank"href="%s"> Webhooks ガイド</a>をご覧ください。
|
||||
settings.webhook_deletion=Webhook を削除
|
||||
@@ -741,6 +745,7 @@ settings.add_webhook_desc=私たちは、指定されたURLに購読されたイ
|
||||
settings.payload_url=ペイロードの URL
|
||||
settings.content_type=コンテンツ タイプ
|
||||
settings.secret=秘密
|
||||
settings.secret_desc=Secret will be sent as SHA256 HMAC hex digest of payload via <code>X-Gogs-Signature</code> header.
|
||||
settings.slack_username=ユーザ名
|
||||
settings.slack_icon_url=アイコン URL
|
||||
settings.slack_color=カラー
|
||||
|
||||
@@ -657,6 +657,10 @@ settings.protect_require_pull_request=Require pull request instead direct pushin
|
||||
settings.protect_require_pull_request_desc=Enable this option to disable direct pushing to this branch. Commits have to be pushed to another non-protected branch and merged to this branch through pull request.
|
||||
settings.protect_whitelist_committers=Whitelist who can push to this branch
|
||||
settings.protect_whitelist_committers_desc=Add people or teams to whitelist of direct push to this branch.
|
||||
settings.protect_whitelist_users=Users who can push to this branch
|
||||
settings.protect_whitelist_search_users=Search users
|
||||
settings.protect_whitelist_teams=Teams for which members of them can push to this branch
|
||||
settings.protect_whitelist_search_teams=Search teams
|
||||
settings.update_protect_branch_success=Protect options for this branch has been updated successfully!
|
||||
settings.hooks=Webhooks
|
||||
settings.githooks=Git Hooks
|
||||
@@ -685,6 +689,7 @@ settings.tracker_issue_style.alphanumeric=문자 숫자
|
||||
settings.tracker_url_format_desc=<code>{user} {repo} {index}</code> 사용자 명, 저장소 명, 이슈 인덱스를 사용하여 표시자를 사용할 수 있습니다.
|
||||
settings.pulls_desc=끌어오기 요청을 공개적으로 기여받을 수 있도록 활성화합니다.
|
||||
settings.danger_zone=위험 설정
|
||||
settings.cannot_fork_to_same_owner=You cannot fork a repository to its original owner.
|
||||
settings.new_owner_has_same_repo=새로운 소유자가 같은 이름의 저장소를 이미 가지고 있습니다. 다른 이름을 선택해주세요.
|
||||
settings.convert=일반 리파지토리로 변환
|
||||
settings.convert_desc=이 미러를 일반 리파지토리로 변환할 수 없습니다. 반대로는 할 수 없습니다.
|
||||
@@ -719,7 +724,6 @@ settings.collaborator_deletion_desc=이 사용자는 더 이상 이 저장소의
|
||||
settings.remove_collaborator_success=공동작업자가 삭제 되었습니다.
|
||||
settings.search_user_placeholder=사용자 검색...
|
||||
settings.org_not_allowed_to_be_collaborator=조직을 공동 작업자로 추가할 수 없습니다.
|
||||
settings.user_is_org_member=사용자가 조직 구성원이므로 공동 작업자로 추가할 수 없습니다.
|
||||
settings.add_webhook=Webhook 추가
|
||||
settings.hooks_desc=웹후크는 기본적인 HTTP POST 이벤트 트리거입니다. Gogs에서 무슨 일이 발생할 때마다, 지정한 대상 호스트에 알림을 보냅니다. <a target="_blank" href="%s">웹후크 안내서</a>에서 자세히 알아보십시오.
|
||||
settings.webhook_deletion=Webhook 삭제
|
||||
@@ -742,6 +746,7 @@ settings.add_webhook_desc=Gogs는 발생한 이벤트와 관련하여 지정한
|
||||
settings.payload_url=페이로드 URL
|
||||
settings.content_type=컨텐츠 타입
|
||||
settings.secret=비밀
|
||||
settings.secret_desc=Secret will be sent as SHA256 HMAC hex digest of payload via <code>X-Gogs-Signature</code> header.
|
||||
settings.slack_username=사용자 이름
|
||||
settings.slack_icon_url=아이콘 URL
|
||||
settings.slack_color=색
|
||||
|
||||
@@ -656,6 +656,10 @@ settings.protect_require_pull_request=Require pull request instead direct pushin
|
||||
settings.protect_require_pull_request_desc=Enable this option to disable direct pushing to this branch. Commits have to be pushed to another non-protected branch and merged to this branch through pull request.
|
||||
settings.protect_whitelist_committers=Whitelist who can push to this branch
|
||||
settings.protect_whitelist_committers_desc=Add people or teams to whitelist of direct push to this branch.
|
||||
settings.protect_whitelist_users=Users who can push to this branch
|
||||
settings.protect_whitelist_search_users=Search users
|
||||
settings.protect_whitelist_teams=Teams for which members of them can push to this branch
|
||||
settings.protect_whitelist_search_teams=Search teams
|
||||
settings.update_protect_branch_success=Protect options for this branch has been updated successfully!
|
||||
settings.hooks=Tīmekļa āķi
|
||||
settings.githooks=Git āķi
|
||||
@@ -684,6 +688,7 @@ settings.tracker_issue_style.alphanumeric=Burti un cipari
|
||||
settings.tracker_url_format_desc=Jūs varat izmantot <code>{user}{repo}{index}</code> lietotājvārdam, repozitorija nosaukumam un problēmas identifikātoram.
|
||||
settings.pulls_desc=Iespējot izmaiņu pieprasījumus lai saņemtu publiskus ieguldījumus
|
||||
settings.danger_zone=Bīstamā zona
|
||||
settings.cannot_fork_to_same_owner=You cannot fork a repository to its original owner.
|
||||
settings.new_owner_has_same_repo=Jaunajam īpašniekam jau ir repozitorijs ar šādu nosaukumu.
|
||||
settings.convert=Konvertēt uz parastu repozitoriju
|
||||
settings.convert_desc=Šo spoguli ir iespējams konvertēt par parastu repozitoriju. Šī ir neatgriezeniska darbība.
|
||||
@@ -718,7 +723,6 @@ settings.collaborator_deletion_desc=Šim lietotājam pēc dzēšanas vairs nebū
|
||||
settings.remove_collaborator_success=Līdzstrādnieks tika noņemts.
|
||||
settings.search_user_placeholder=Meklēt lietotāju...
|
||||
settings.org_not_allowed_to_be_collaborator=Organizāciju nav atļauts pievienot kā līdzstrādnieku.
|
||||
settings.user_is_org_member=Lietotājs ir organizācijas biedrs, kas nevar tikt pievienots kā līdzstrādnieks.
|
||||
settings.add_webhook=Pievienot tīmekļa āķi
|
||||
settings.hooks_desc=Tīmekļa āķi ļauj paziņot ārējiem servisiem par noteiktiem notikomiem, kas notiek Git servisā. Kad iestāsies kāds notikums, katram ārējā servisa URL tiks nosūtīts POST pieprasījums. Lai uzzinātu sīkāk skatieties <a target="_blank" href="%s">Tīmekļa āķu rokasgrāmatā</a>.
|
||||
settings.webhook_deletion=Dzēst tīmekļa āķi
|
||||
@@ -741,6 +745,7 @@ settings.add_webhook_desc=Uz norādīto URL tiks nosūtīts <code>POST</code> pi
|
||||
settings.payload_url=Vērtuma URL
|
||||
settings.content_type=Satura tips
|
||||
settings.secret=Noslēpums
|
||||
settings.secret_desc=Secret will be sent as SHA256 HMAC hex digest of payload via <code>X-Gogs-Signature</code> header.
|
||||
settings.slack_username=Lietotājvārds
|
||||
settings.slack_icon_url=Ikonas URL
|
||||
settings.slack_color=Krāsa
|
||||
|
||||
@@ -656,6 +656,10 @@ settings.protect_require_pull_request=Require pull request instead direct pushin
|
||||
settings.protect_require_pull_request_desc=Enable this option to disable direct pushing to this branch. Commits have to be pushed to another non-protected branch and merged to this branch through pull request.
|
||||
settings.protect_whitelist_committers=Whitelist who can push to this branch
|
||||
settings.protect_whitelist_committers_desc=Add people or teams to whitelist of direct push to this branch.
|
||||
settings.protect_whitelist_users=Users who can push to this branch
|
||||
settings.protect_whitelist_search_users=Search users
|
||||
settings.protect_whitelist_teams=Teams for which members of them can push to this branch
|
||||
settings.protect_whitelist_search_teams=Search teams
|
||||
settings.update_protect_branch_success=Protect options for this branch has been updated successfully!
|
||||
settings.hooks=Webhooks
|
||||
settings.githooks=Git-hooks
|
||||
@@ -684,6 +688,7 @@ settings.tracker_issue_style.alphanumeric=Alfanummeriek
|
||||
settings.tracker_url_format_desc=U kan de aanduidingen <code>{user} {repo} {index}</code> gebruiken voor de gebruikersnaam, de naam van de repository en de lijst van open tickets.
|
||||
settings.pulls_desc=Schakel 'pull request' in om publieke bijdragen te mogelijk te maken
|
||||
settings.danger_zone=Gevaren zone
|
||||
settings.cannot_fork_to_same_owner=You cannot fork a repository to its original owner.
|
||||
settings.new_owner_has_same_repo=De nieuwe eigenaar heeft al een repositorie met deze naam
|
||||
settings.convert=Converteren naar gewone repository
|
||||
settings.convert_desc=U kunt deze mirror converteren naar een gewone repository. Dit kan niet ongedaan worden gemaakt.
|
||||
@@ -718,7 +723,6 @@ settings.collaborator_deletion_desc=Deze gebruiker zal niet langer toegang hebbe
|
||||
settings.remove_collaborator_success=medewerker is verwijderd.
|
||||
settings.search_user_placeholder=Zoek gebruiker...
|
||||
settings.org_not_allowed_to_be_collaborator=De organisatie kan niet toegevoegd worden als medewerker.
|
||||
settings.user_is_org_member=Gebruiker is lid van de organisatie die als een medewerker kan niet worden toegevoegd.
|
||||
settings.add_webhook=Webhook toevoegen
|
||||
settings.hooks_desc=Webhooks dat de externe diensten om kennisgevingen te ontvangen wanneer bepaalde gebeurtenissen op Gogs plaatsvinden. Wanneer de opgegeven gebeurtenissen plaatsvinden, sturen we een POST-aanvraag naar elk van de URL's die u opgeeft. Meer informatie vindt u in onze <a target="_blank" href="%s"> Webhooks gids</a>.
|
||||
settings.webhook_deletion=Webhook verwijderen
|
||||
@@ -741,6 +745,7 @@ settings.add_webhook_desc=We sturen een <code>POST</code>-aanvraag naar de onder
|
||||
settings.payload_url=Nettolading URL
|
||||
settings.content_type=Content type
|
||||
settings.secret=Geheim
|
||||
settings.secret_desc=Secret will be sent as SHA256 HMAC hex digest of payload via <code>X-Gogs-Signature</code> header.
|
||||
settings.slack_username=Gebruikersnaam
|
||||
settings.slack_icon_url=Icoon URL
|
||||
settings.slack_color=Kleur
|
||||
|
||||
@@ -656,6 +656,10 @@ settings.protect_require_pull_request=Require pull request instead direct pushin
|
||||
settings.protect_require_pull_request_desc=Enable this option to disable direct pushing to this branch. Commits have to be pushed to another non-protected branch and merged to this branch through pull request.
|
||||
settings.protect_whitelist_committers=Whitelist who can push to this branch
|
||||
settings.protect_whitelist_committers_desc=Add people or teams to whitelist of direct push to this branch.
|
||||
settings.protect_whitelist_users=Users who can push to this branch
|
||||
settings.protect_whitelist_search_users=Search users
|
||||
settings.protect_whitelist_teams=Teams for which members of them can push to this branch
|
||||
settings.protect_whitelist_search_teams=Search teams
|
||||
settings.update_protect_branch_success=Protect options for this branch has been updated successfully!
|
||||
settings.hooks=Webhooki
|
||||
settings.githooks=Hooki Git
|
||||
@@ -684,6 +688,7 @@ settings.tracker_issue_style.alphanumeric=Alfanumeryczne
|
||||
settings.tracker_url_format_desc=Symbole zastępcze <code>{user} {repo} {index}</code> mogą być użyte dla nazwy użytkownika, nazwy repozytorium i numeru problemu.
|
||||
settings.pulls_desc=Włącz obsługę pull request, aby akceptować publiczny wkład
|
||||
settings.danger_zone=Strefa niebezpieczeństwa
|
||||
settings.cannot_fork_to_same_owner=You cannot fork a repository to its original owner.
|
||||
settings.new_owner_has_same_repo=Nowy właściciel już posiada repozytorium o tej samej nazwie.
|
||||
settings.convert=Konwersja na repozytorium regularne
|
||||
settings.convert_desc=Możesz przekonwertować ten mirror na repozytorium regularne. Ta czynność nie może być odwrócona.
|
||||
@@ -718,7 +723,6 @@ settings.collaborator_deletion_desc=Ten użytkownik nie będzie miał dostępu w
|
||||
settings.remove_collaborator_success=Współpracownik został usunięty.
|
||||
settings.search_user_placeholder=Szukaj użytkownika...
|
||||
settings.org_not_allowed_to_be_collaborator=Organizacji nie można dodać jako współpracownika.
|
||||
settings.user_is_org_member=Użytkownik jest członkiem organizacji, który nie może być dodany jako współpracownik.
|
||||
settings.add_webhook=Dodaj webhooka
|
||||
settings.hooks_desc=Webooki działają tak jak proste wywołania HTTP POST. Jeśli cokolwiek zdarzy się w Gogs, wyślemy powiadomienie do wybranego hosta. Więcej informacji można znaleźć w <a target="_blank" href="%s">przewodniku webhooków</a>.
|
||||
settings.webhook_deletion=Usuń webhooka
|
||||
@@ -741,6 +745,7 @@ settings.add_webhook_desc=Wyślemy żądanie <code>POST</code> pod poniższy adr
|
||||
settings.payload_url=URL do wywołania
|
||||
settings.content_type=Typ zawartości
|
||||
settings.secret=Sekret
|
||||
settings.secret_desc=Secret will be sent as SHA256 HMAC hex digest of payload via <code>X-Gogs-Signature</code> header.
|
||||
settings.slack_username=Użytkownik
|
||||
settings.slack_icon_url=Adres URL ikony
|
||||
settings.slack_color=Kolor
|
||||
|
||||
@@ -656,6 +656,10 @@ settings.protect_require_pull_request=Require pull request instead direct pushin
|
||||
settings.protect_require_pull_request_desc=Enable this option to disable direct pushing to this branch. Commits have to be pushed to another non-protected branch and merged to this branch through pull request.
|
||||
settings.protect_whitelist_committers=Whitelist who can push to this branch
|
||||
settings.protect_whitelist_committers_desc=Add people or teams to whitelist of direct push to this branch.
|
||||
settings.protect_whitelist_users=Users who can push to this branch
|
||||
settings.protect_whitelist_search_users=Search users
|
||||
settings.protect_whitelist_teams=Teams for which members of them can push to this branch
|
||||
settings.protect_whitelist_search_teams=Search teams
|
||||
settings.update_protect_branch_success=Protect options for this branch has been updated successfully!
|
||||
settings.hooks=Webhooks
|
||||
settings.githooks=Hooks do Git
|
||||
@@ -684,6 +688,7 @@ settings.tracker_issue_style.alphanumeric=Alfanumérico
|
||||
settings.tracker_url_format_desc=Você pode usar o espaço reservado <code>{user} {repo} {index}</code> para o nome do usuário, índice de nome e a questão do repositório.
|
||||
settings.pulls_desc=Habilitar Pull Requests para aceitar contribuições públicas
|
||||
settings.danger_zone=Zona de perigo
|
||||
settings.cannot_fork_to_same_owner=You cannot fork a repository to its original owner.
|
||||
settings.new_owner_has_same_repo=O novo dono já tem um repositório com o mesmo nome. Por favor, escolha outro nome.
|
||||
settings.convert=Converter para repositório tradicional
|
||||
settings.convert_desc=Você pode converter este espelho em um repositório tradicional. Esta ação não pode ser revertida.
|
||||
@@ -718,7 +723,6 @@ settings.collaborator_deletion_desc=Este usuário não terá mais acesso de cola
|
||||
settings.remove_collaborator_success=O colaborador foi removido.
|
||||
settings.search_user_placeholder=Pesquisar usuário...
|
||||
settings.org_not_allowed_to_be_collaborator=Organização não tem permissão para ser adicionada como um colaborador.
|
||||
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.webhook_deletion=Deletar Webhook
|
||||
@@ -741,6 +745,7 @@ settings.add_webhook_desc=Enviaremos uma solicitação <code>POST</code> para o
|
||||
settings.payload_url=URL de Payload
|
||||
settings.content_type=Tipo de conteúdo
|
||||
settings.secret=Secreto
|
||||
settings.secret_desc=Secret will be sent as SHA256 HMAC hex digest of payload via <code>X-Gogs-Signature</code> header.
|
||||
settings.slack_username=Nome de usuário
|
||||
settings.slack_icon_url=URL do ícone
|
||||
settings.slack_color=Cor
|
||||
|
||||
@@ -531,7 +531,7 @@ issues.next=Следующая страница
|
||||
issues.open_title=Открыто
|
||||
issues.closed_title=Закрыто
|
||||
issues.num_comments=комментариев: %d
|
||||
issues.commented_at=«прокомментировал <a href="#%s"> %s</a>»
|
||||
issues.commented_at=`прокомментировал <a href="#%s"> %s</a>`
|
||||
issues.delete_comment_confirm=Вы уверены, что хотите удалить этот комментарий?
|
||||
issues.no_content=Пока нет содержимого.
|
||||
issues.close_issue=Закрыть
|
||||
@@ -656,6 +656,10 @@ settings.protect_require_pull_request=Require pull request instead direct pushin
|
||||
settings.protect_require_pull_request_desc=Enable this option to disable direct pushing to this branch. Commits have to be pushed to another non-protected branch and merged to this branch through pull request.
|
||||
settings.protect_whitelist_committers=Whitelist who can push to this branch
|
||||
settings.protect_whitelist_committers_desc=Add people or teams to whitelist of direct push to this branch.
|
||||
settings.protect_whitelist_users=Users who can push to this branch
|
||||
settings.protect_whitelist_search_users=Search users
|
||||
settings.protect_whitelist_teams=Teams for which members of them can push to this branch
|
||||
settings.protect_whitelist_search_teams=Search teams
|
||||
settings.update_protect_branch_success=Protect options for this branch has been updated successfully!
|
||||
settings.hooks=Автоматическое обновление
|
||||
settings.githooks=Git хуки
|
||||
@@ -684,6 +688,7 @@ settings.tracker_issue_style.alphanumeric=Буквенноцифровой
|
||||
settings.tracker_url_format_desc=Вы можете использовать шаблон <code>{user} {repo} {index}</code> для имени пользователя, репозитория и номера задачи.
|
||||
settings.pulls_desc=Включить публичные запросы на слияние
|
||||
settings.danger_zone=Опасная зона
|
||||
settings.cannot_fork_to_same_owner=You cannot fork a repository to its original owner.
|
||||
settings.new_owner_has_same_repo=У нового владельца уже есть хранилище с таким названием.
|
||||
settings.convert=Преобразовать в обычный репозиторий
|
||||
settings.convert_desc=Это зеркало можно преобразовать в обычный репозиторий. Это не может быть отменено.
|
||||
@@ -718,7 +723,6 @@ settings.collaborator_deletion_desc=Этот пользователь больш
|
||||
settings.remove_collaborator_success=Соавтор был удален.
|
||||
settings.search_user_placeholder=Поиск пользователя...
|
||||
settings.org_not_allowed_to_be_collaborator=Организации не могут быть добавлены как соавторы.
|
||||
settings.user_is_org_member=Пользователь является членом организации, члены которой не могут быть добавлены в качестве соавтора.
|
||||
settings.add_webhook=Добавить Webhook
|
||||
settings.hooks_desc=Webhooks позволяют внешним службам получать уведомления при возникновении определенных событий на Gogs. При возникновении указанных событий мы отправим запрос POST на каждый заданный вами URL. Узнать больше можно в нашем <a target="_blank" href="%s">Руководстве по Webhooks</a>.
|
||||
settings.webhook_deletion=Удалить веб-хук
|
||||
@@ -741,6 +745,7 @@ settings.add_webhook_desc=Мы отправим запрос <code>POST</code>
|
||||
settings.payload_url=URL обработчика
|
||||
settings.content_type=Тип содержимого
|
||||
settings.secret=Secret
|
||||
settings.secret_desc=Secret will be sent as SHA256 HMAC hex digest of payload via <code>X-Gogs-Signature</code> header.
|
||||
settings.slack_username=Имя пользователя
|
||||
settings.slack_icon_url=URL иконки
|
||||
settings.slack_color=Цвет
|
||||
|
||||
@@ -656,6 +656,10 @@ settings.protect_require_pull_request=Require pull request instead direct pushin
|
||||
settings.protect_require_pull_request_desc=Enable this option to disable direct pushing to this branch. Commits have to be pushed to another non-protected branch and merged to this branch through pull request.
|
||||
settings.protect_whitelist_committers=Whitelist who can push to this branch
|
||||
settings.protect_whitelist_committers_desc=Add people or teams to whitelist of direct push to this branch.
|
||||
settings.protect_whitelist_users=Users who can push to this branch
|
||||
settings.protect_whitelist_search_users=Search users
|
||||
settings.protect_whitelist_teams=Teams for which members of them can push to this branch
|
||||
settings.protect_whitelist_search_teams=Search teams
|
||||
settings.update_protect_branch_success=Protect options for this branch has been updated successfully!
|
||||
settings.hooks=Webhooks
|
||||
settings.githooks=Git хуки
|
||||
@@ -684,6 +688,7 @@ settings.tracker_issue_style.alphanumeric=Алфанумерично
|
||||
settings.tracker_url_format_desc=Можете да користите шаблон <code>{user} {repo} {index}</code> за корисничко име, спремишта и задатака.
|
||||
settings.pulls_desc=Омогући систем захтева за спајање да би сте преузели јавних доприноса
|
||||
settings.danger_zone=Опасна зона
|
||||
settings.cannot_fork_to_same_owner=You cannot fork a repository to its original owner.
|
||||
settings.new_owner_has_same_repo=Нови власник већ има спремиште по истим називом. Молимо вас изаберите друго име.
|
||||
settings.convert=Претворити у обично спремиште
|
||||
settings.convert_desc=Можете претворити огледало у обично спремиште, али та операција не може се укинути.
|
||||
@@ -718,7 +723,6 @@ settings.collaborator_deletion_desc=Овај корисник неће имат
|
||||
settings.remove_collaborator_success=Сарадник је уклоњен.
|
||||
settings.search_user_placeholder=Претрага корисника...
|
||||
settings.org_not_allowed_to_be_collaborator=Неможе се додати организација као сарадник.
|
||||
settings.user_is_org_member=Корисник је члан организације и потом неможе бити додат као сарадник.
|
||||
settings.add_webhook=Додај Webhook
|
||||
settings.hooks_desc=Webhooks омогућавају спољашњим услугама да приме обавештења када се нешто одређено догоди на Gogs. Сазнајте више у овом <a target="_blank" href="%s">водичу за Webhooks</a>.
|
||||
settings.webhook_deletion=Уклони Webhook
|
||||
@@ -741,6 +745,7 @@ settings.add_webhook_desc=Послаћемо захтев <code>POST</code> на
|
||||
settings.payload_url=URL адреса за слање
|
||||
settings.content_type=Тип садржаја
|
||||
settings.secret=Тајна
|
||||
settings.secret_desc=Secret will be sent as SHA256 HMAC hex digest of payload via <code>X-Gogs-Signature</code> header.
|
||||
settings.slack_username=Корисничко име
|
||||
settings.slack_icon_url=URL адреса иконице
|
||||
settings.slack_color=Боја
|
||||
|
||||
@@ -656,6 +656,10 @@ settings.protect_require_pull_request=Require pull request instead direct pushin
|
||||
settings.protect_require_pull_request_desc=Enable this option to disable direct pushing to this branch. Commits have to be pushed to another non-protected branch and merged to this branch through pull request.
|
||||
settings.protect_whitelist_committers=Whitelist who can push to this branch
|
||||
settings.protect_whitelist_committers_desc=Add people or teams to whitelist of direct push to this branch.
|
||||
settings.protect_whitelist_users=Users who can push to this branch
|
||||
settings.protect_whitelist_search_users=Search users
|
||||
settings.protect_whitelist_teams=Teams for which members of them can push to this branch
|
||||
settings.protect_whitelist_search_teams=Search teams
|
||||
settings.update_protect_branch_success=Protect options for this branch has been updated successfully!
|
||||
settings.hooks=Webbhookar
|
||||
settings.githooks=Githookar
|
||||
@@ -684,6 +688,7 @@ settings.tracker_issue_style.alphanumeric=Alfanumerisk
|
||||
settings.tracker_url_format_desc=Du kan använda platshållaren <code>{user} {repo} {index}</code> för användarnamn, reponamn, och ärendenummer.
|
||||
settings.pulls_desc=Aktivera pullförfrågningar för att ta emot publika bidrag
|
||||
settings.danger_zone=Högrisksområde
|
||||
settings.cannot_fork_to_same_owner=You cannot fork a repository to its original owner.
|
||||
settings.new_owner_has_same_repo=Den nya ägaren har redan ett repo med det namnet. Vänligen välj ett annat namn.
|
||||
settings.convert=Konvertera Till Vanligt Repo
|
||||
settings.convert_desc=Du kan konvertera denna spegling till ett vanligt förråd. Detta kan inte ångras.
|
||||
@@ -718,7 +723,6 @@ settings.collaborator_deletion_desc=Denna användare kommer förlora sin åtkoms
|
||||
settings.remove_collaborator_success=Deltagare har tagits bort.
|
||||
settings.search_user_placeholder=Sök användare...
|
||||
settings.org_not_allowed_to_be_collaborator=Organisationen kan inte läggas till som en deltagare.
|
||||
settings.user_is_org_member=Änvändaren är en organisationsmedlem som inte kan bli tillagd som deltagare.
|
||||
settings.add_webhook=Lägg Till Webbhook
|
||||
settings.hooks_desc=Webbhookar påminner mycket om vanliga HTTP POST-händelseutlösare. När något inträffar i Gogs, kommer vi att meddela måldatorn som du anger. Läs mera i <a target="_blank" href="%s">Webbhook Guide</a>.
|
||||
settings.webhook_deletion=Ta Bort Webbhook
|
||||
@@ -741,6 +745,7 @@ settings.add_webhook_desc=Gogs kommer skicka <code>POST</code>-anrop till webbad
|
||||
settings.payload_url=Adress till innehåll
|
||||
settings.content_type=Typ av innehåll
|
||||
settings.secret=Hemlighet
|
||||
settings.secret_desc=Secret will be sent as SHA256 HMAC hex digest of payload via <code>X-Gogs-Signature</code> header.
|
||||
settings.slack_username=Användarnamn
|
||||
settings.slack_icon_url=URL för ikon
|
||||
settings.slack_color=Färg
|
||||
|
||||
@@ -656,6 +656,10 @@ settings.protect_require_pull_request=Require pull request instead direct pushin
|
||||
settings.protect_require_pull_request_desc=Enable this option to disable direct pushing to this branch. Commits have to be pushed to another non-protected branch and merged to this branch through pull request.
|
||||
settings.protect_whitelist_committers=Whitelist who can push to this branch
|
||||
settings.protect_whitelist_committers_desc=Add people or teams to whitelist of direct push to this branch.
|
||||
settings.protect_whitelist_users=Users who can push to this branch
|
||||
settings.protect_whitelist_search_users=Search users
|
||||
settings.protect_whitelist_teams=Teams for which members of them can push to this branch
|
||||
settings.protect_whitelist_search_teams=Search teams
|
||||
settings.update_protect_branch_success=Protect options for this branch has been updated successfully!
|
||||
settings.hooks=Web İstekleri
|
||||
settings.githooks=Git İstekleri
|
||||
@@ -684,6 +688,7 @@ settings.tracker_issue_style.alphanumeric=Alfanumerik
|
||||
settings.tracker_url_format_desc=Kullanıcı adı, depo ismi ve hata indeksi için <code>{kullanıcı} {depo} {indeks}</code> tutucusunu kullanabilirsiniz.
|
||||
settings.pulls_desc=Herkese açık katkıları kabul etmek için değişiklik isteklerini etkinleştirin
|
||||
settings.danger_zone=Tehlike Alanı
|
||||
settings.cannot_fork_to_same_owner=You cannot fork a repository to its original owner.
|
||||
settings.new_owner_has_same_repo=Yeni sahibin aynı isimde başka bir deposu var. Lütfen farklı bir isim seçin.
|
||||
settings.convert=Düzenli Depoya Dönüştür
|
||||
settings.convert_desc=Bu yansıyı düzenli bir depoya dönüştürebilirsiniz. Bu işlem geri alınamaz.
|
||||
@@ -718,7 +723,6 @@ settings.collaborator_deletion_desc=Kullanıcı, silme işleminden sonra bu depo
|
||||
settings.remove_collaborator_success=Katkıcı silindi.
|
||||
settings.search_user_placeholder=Kullanıcı ara...
|
||||
settings.org_not_allowed_to_be_collaborator=Organizasyon, bir katkıcı olarak eklenemez.
|
||||
settings.user_is_org_member=Kullanıcı organizasyon üyesi olduğu için katkıcı olarak eklenemez.
|
||||
settings.add_webhook=Web İsteği Ekle
|
||||
settings.hooks_desc=Web istekleri, HTTP POST olay tetikleyicileri gibidirler. Gogs'ta ne zaman bir şey olsa, hedef belirttiğiniz sunuculara bildirim yapabilecek duruma geliriz. Daha fazla bilgiyi <a target="_blank" href="%s">Web İstekleri Kılavuzu</a>'nda bulabilirsiniz.
|
||||
settings.webhook_deletion=Web İsteğini Sil
|
||||
@@ -741,6 +745,7 @@ settings.add_webhook_desc=Gogs, meydana gelen olay ile birlikte belirttiğiniz b
|
||||
settings.payload_url=Yük Bağlantısı
|
||||
settings.content_type=İçerik Türü
|
||||
settings.secret=Gizli
|
||||
settings.secret_desc=Secret will be sent as SHA256 HMAC hex digest of payload via <code>X-Gogs-Signature</code> header.
|
||||
settings.slack_username=Kullanıcı Adı
|
||||
settings.slack_icon_url=Simge Bağlantısı
|
||||
settings.slack_color=Renk
|
||||
|
||||
@@ -39,7 +39,7 @@ your_profile=Ваш профіль
|
||||
your_settings=Ваші налаштування
|
||||
|
||||
activities=Дії
|
||||
pull_requests=пропозиція змін
|
||||
pull_requests=Запити на злиття
|
||||
issues=Обговорення
|
||||
|
||||
cancel=Скасувати
|
||||
@@ -69,7 +69,7 @@ app_name_helper=Вкажіть назву вашої організації, в
|
||||
repo_path=Кореневий шлях репозиторія
|
||||
repo_path_helper=До цього каталогу буде збережено всі зовнішні сховища Git.
|
||||
run_user=Запустити як
|
||||
run_user_helper=Користувач повинен мати доступ до папки репозиторіїв і запустити Gogs.
|
||||
run_user_helper=Користувач мусить мати доступ до кореню репозиторіїв та право на запуск Gogs.
|
||||
domain=Домен
|
||||
domain_helper=Це впливає на клонування через SSH.
|
||||
ssh_port=SSH порт
|
||||
@@ -192,9 +192,9 @@ AuthName=Назва авторизації
|
||||
AdminEmail=Електронна пошта адміністратора
|
||||
|
||||
NewBranchName=Ім'я нової гілки
|
||||
CommitSummary=Резюме комміту
|
||||
CommitMessage=Зафіксувати повідомлення
|
||||
CommitChoice=Зробити вибір
|
||||
CommitSummary=Резюме коміту
|
||||
CommitMessage=Повідомлення коміту
|
||||
CommitChoice=Зафіксувати вибір
|
||||
TreeName=Шлях до файлу
|
||||
Content=Вміст
|
||||
|
||||
@@ -305,7 +305,7 @@ add_email_success=Вашу нову адресу електронної пошт
|
||||
manage_ssh_keys=Керувати ключами SSH
|
||||
add_key=Додати ключ
|
||||
ssh_desc=Це список ключів SSH, пов'язані з вашим обліковим записом. Видаліть будь-які ключі, які не є вашими.
|
||||
ssh_helper=<strong>Потрібна допомога?</strong> Дивіться наш гід до <a href="%s"> генерації ключів SSH</a> або виправлення <a href="%s"> типових неполадок SSH</a>.
|
||||
ssh_helper=<strong>Потрібна допомога?</strong> Дивіться гід на GitHub з <a href="%s"> генерації ключів SSH</a> або виправлення <a href="%s">типових неполадок SSH</a>.
|
||||
add_new_key=Додати SSH ключа
|
||||
ssh_key_been_used=Було використано публічний ключ.
|
||||
ssh_key_name_used=Відкритий ключ з таким іменем уже існує.
|
||||
@@ -422,7 +422,7 @@ filter_branch_and_tag=Фільтрувати гілку або тег
|
||||
branches=Гілки
|
||||
tags=Теги
|
||||
issues=Проблеми
|
||||
pulls=Пропозиція Змін
|
||||
pulls=Запити на злиття
|
||||
labels=Мітка
|
||||
milestones=Проміжні етапи
|
||||
commits=Коміти
|
||||
@@ -449,12 +449,12 @@ editor.name_your_file=Дайте назву файлу...
|
||||
editor.filename_help=Щоб додати каталог, просто наберіть його ім'я, та натисніть /. Щоб видалити каталог, перейдіь на початок поля й натисніть клавішу backspace.
|
||||
editor.or=Або
|
||||
editor.cancel_lower=Скасувати
|
||||
editor.commit_changes=Порівняти зміни
|
||||
editor.commit_changes=Зафіксувати зміни
|
||||
editor.add_tmpl=Додати '%s/<filename>'
|
||||
editor.add=Додати '%s'
|
||||
editor.update=Оновити '%s'
|
||||
editor.delete=Видалити '%s'
|
||||
editor.commit_message_desc=Додати необов'язкове розширене описання...
|
||||
editor.commit_message_desc=Додати необов'язковий розширений опис...
|
||||
editor.commit_directly_to_this_branch=Зробіть комміт прямо в гілку <strong class="branch-name">%s</strong>.
|
||||
editor.create_new_branch=Створіть <strong>нову гілку</strong> для цього коміту та відкривайте запит на втягування.
|
||||
editor.new_branch_name_desc=Ім'я нової гілки...
|
||||
@@ -473,7 +473,7 @@ editor.add_subdir=Додати підкаталогу...
|
||||
editor.unable_to_upload_files=Не вдалося завантажити файли до '%s' через помилку: %v
|
||||
editor.upload_files_to_dir=Завантажувати файли до '%s'
|
||||
|
||||
commits.commit_history=Commit History
|
||||
commits.commit_history=Історія комітів
|
||||
commits.commits=Коміти
|
||||
commits.search=Знайти коміт
|
||||
commits.find=Пошук
|
||||
@@ -515,7 +515,7 @@ issues.filter_assginee_no_select=Етап не обрано
|
||||
issues.filter_type=Тип
|
||||
issues.filter_type.all_issues=Всі проблемы
|
||||
issues.filter_type.assigned_to_you=Призначене вам
|
||||
issues.filter_type.created_by_you=Створено тобою
|
||||
issues.filter_type.created_by_you=Створено вами
|
||||
issues.filter_type.mentioning_you=Вас згадано
|
||||
issues.filter_sort=Сортування
|
||||
issues.filter_sort.latest=Найновіші
|
||||
@@ -656,7 +656,11 @@ settings.protect_require_pull_request=Вимагати запрос на зли
|
||||
settings.protect_require_pull_request_desc=Увімкніть цю опцію для заборони прямого push у цю гілку. Коміт має бути запушений у іншу, незахищену гілку та влитий у цю через запрос на злиття.
|
||||
settings.protect_whitelist_committers=Білий список тих, хто може робити push у цю гілку
|
||||
settings.protect_whitelist_committers_desc=Додати людей або команди у білий список для виконання push до цієї гілки.
|
||||
settings.update_protect_branch_success=Protect options for this branch has been updated successfully!
|
||||
settings.protect_whitelist_users=Користувачі що можуть виконувати push до цієї гілки
|
||||
settings.protect_whitelist_search_users=Пошук користувачів
|
||||
settings.protect_whitelist_teams=Команди, члени яких можуть виконувати push до цієї гілки
|
||||
settings.protect_whitelist_search_teams=Пошук команд
|
||||
settings.update_protect_branch_success=Опції захисту цієї гілки було успішно оновлено!
|
||||
settings.hooks=Webhooks
|
||||
settings.githooks=Git Hooks
|
||||
settings.basic_settings=Основні налаштування
|
||||
@@ -684,6 +688,7 @@ settings.tracker_issue_style.alphanumeric=Буквено-цифровий
|
||||
settings.tracker_url_format_desc=Ви можете використовувати заповнювач <code>{user} {repo} {index}</code> для ім'я користувача, назви репозиторію на номеру проблеми.
|
||||
settings.pulls_desc=Увімкнути публічні запроси на злиття
|
||||
settings.danger_zone=Небезпечна зона
|
||||
settings.cannot_fork_to_same_owner=Ви не можете клонувати репозиторій його ж власнику.
|
||||
settings.new_owner_has_same_repo=Новий власник вже має репозиторій з такою назвою.
|
||||
settings.convert=Перетворити на звичайний репозиторій
|
||||
settings.convert_desc=Ви можете сконвертувати це дзеркало у звичайний репозиторій. Це не може бути повернуто.
|
||||
@@ -718,7 +723,6 @@ settings.collaborator_deletion_desc=Цей користувач більше н
|
||||
settings.remove_collaborator_success=Співавтора було видалено.
|
||||
settings.search_user_placeholder=Пошук користувача...
|
||||
settings.org_not_allowed_to_be_collaborator=Організації не можуть бути додані як співавтори.
|
||||
settings.user_is_org_member=Користувач входить в організацію, член якої не може бути доданий як співавтор.
|
||||
settings.add_webhook=Додати Webhook
|
||||
settings.hooks_desc=Web-хуки схожі на HTTP POST тригери подій. Яка б подія не виникла в Gogs, ми можемо обробити повідомлення про неї на сторонньому хості який ви задаєте. Взнайте більше у <a target="_blank" href="%s">Webhooks Guide</a>.
|
||||
settings.webhook_deletion=Видалити Webhook
|
||||
@@ -741,6 +745,7 @@ settings.add_webhook_desc=Gogs відправляє <code>POST</code> запит
|
||||
settings.payload_url=URL розробника
|
||||
settings.content_type=Тип змісту
|
||||
settings.secret=Таємний код
|
||||
settings.secret_desc=Секрет буде вислано SHA256 HMAC hex-сумою вміста у хідері <code>X-Gogs-Signature</code>.
|
||||
settings.slack_username=Ім'я користувача
|
||||
settings.slack_icon_url=URL іконки
|
||||
settings.slack_color=Колір
|
||||
@@ -783,7 +788,7 @@ settings.deploy_key_deletion_success=Ключі для розгортуванн
|
||||
|
||||
diff.browse_source=Переглянути джерело
|
||||
diff.parent=батько
|
||||
diff.commit=комміт
|
||||
diff.commit=коміт
|
||||
diff.data_not_available=Жодних diff даних не доступно.
|
||||
diff.show_diff_stats=Показати статистику Diff
|
||||
diff.show_split_view=Розділений вигляд
|
||||
|
||||
@@ -656,6 +656,10 @@ settings.protect_require_pull_request=要求通过合并请求提交代码
|
||||
settings.protect_require_pull_request_desc=启用该选项后代码将不能直接被推送到此分支,所有的代码提交都必须通过另一个非保护分支发起合并请求进行合并。
|
||||
settings.protect_whitelist_committers=限制可以推送代码的成员
|
||||
settings.protect_whitelist_committers_desc=添加用户或团队到可直接推送代码的白名单。
|
||||
settings.protect_whitelist_users=允许推送到此分支的用户
|
||||
settings.protect_whitelist_search_users=搜索用户
|
||||
settings.protect_whitelist_teams=允许其成员推送到此分支的团队
|
||||
settings.protect_whitelist_search_teams=搜索团队
|
||||
settings.update_protect_branch_success=此分支的保护选项更新成功!
|
||||
settings.hooks=管理 Web 钩子
|
||||
settings.githooks=管理 Git 钩子
|
||||
@@ -684,6 +688,7 @@ settings.tracker_issue_style.alphanumeric=英文字母数字组合形式
|
||||
settings.tracker_url_format_desc=您可以使用 <code>{user} {repo} {index}</code> 分别作为用户名、仓库名和工单索引的占位符。
|
||||
settings.pulls_desc=启用合并请求以接受社区贡献
|
||||
settings.danger_zone=危险操作区
|
||||
settings.cannot_fork_to_same_owner=您不能派生仓库到其当前的所有者。
|
||||
settings.new_owner_has_same_repo=新的仓库拥有者已经存在同名仓库!
|
||||
settings.convert=转换为普通仓库
|
||||
settings.convert_desc=您可以将该镜像仓库转换为普通仓库,且此操作不可逆。
|
||||
@@ -718,7 +723,6 @@ settings.collaborator_deletion_desc=此用户被删除后将不再拥有相关
|
||||
settings.remove_collaborator_success=被操作的协作者已经被收回权限!
|
||||
settings.search_user_placeholder=搜索用户...
|
||||
settings.org_not_allowed_to_be_collaborator=组织不允许被添加为仓库协作者!
|
||||
settings.user_is_org_member=被操作的用户是组织成员,因此无法添加为协作者!
|
||||
settings.add_webhook=添加 Web 钩子
|
||||
settings.hooks_desc=Web 钩子允许您设定在 Gogs 上发生指定事件时对指定 URL 发送 POST 通知。查看 <a target="_blank" href="%s">Webhooks 文档</a> 获取更多信息。
|
||||
settings.webhook_deletion=删除 Web 钩子
|
||||
@@ -741,6 +745,7 @@ settings.add_webhook_desc=我们会通过 <code>POST</code> 请求将订阅事
|
||||
settings.payload_url=推送地址
|
||||
settings.content_type=数据格式
|
||||
settings.secret=密钥文本
|
||||
settings.secret_desc=密钥文本将被用于计算推送内容的 SHA256 HMAC 哈希值,并设置为 <code>X-Gogs-Signature</code> 请求头的值。
|
||||
settings.slack_username=服务名称
|
||||
settings.slack_icon_url=图标 URL
|
||||
settings.slack_color=颜色代码
|
||||
|
||||
@@ -656,6 +656,10 @@ settings.protect_require_pull_request=Require pull request instead direct pushin
|
||||
settings.protect_require_pull_request_desc=Enable this option to disable direct pushing to this branch. Commits have to be pushed to another non-protected branch and merged to this branch through pull request.
|
||||
settings.protect_whitelist_committers=Whitelist who can push to this branch
|
||||
settings.protect_whitelist_committers_desc=Add people or teams to whitelist of direct push to this branch.
|
||||
settings.protect_whitelist_users=Users who can push to this branch
|
||||
settings.protect_whitelist_search_users=Search users
|
||||
settings.protect_whitelist_teams=Teams for which members of them can push to this branch
|
||||
settings.protect_whitelist_search_teams=Search teams
|
||||
settings.update_protect_branch_success=Protect options for this branch has been updated successfully!
|
||||
settings.hooks=管理 Web 鉤子
|
||||
settings.githooks=管理 Git 鉤子
|
||||
@@ -684,6 +688,7 @@ settings.tracker_issue_style.alphanumeric=Alphanumeric
|
||||
settings.tracker_url_format_desc=您可以使用 <code>{user} {repo} {index}</code> 分別作為用戶名、倉庫名和問題索引的占位符。
|
||||
settings.pulls_desc=啟用合併請求以接受社區貢獻
|
||||
settings.danger_zone=危險操作區
|
||||
settings.cannot_fork_to_same_owner=You cannot fork a repository to its original owner.
|
||||
settings.new_owner_has_same_repo=新的倉庫擁有者已經存在同名倉庫!
|
||||
settings.convert=轉換為正規倉庫
|
||||
settings.convert_desc=您可以將此鏡像轉成正規倉庫。此動做不可逆。
|
||||
@@ -718,7 +723,6 @@ settings.collaborator_deletion_desc=This user will no longer have collaboration
|
||||
settings.remove_collaborator_success=被操作的協作者已經被收回權限!
|
||||
settings.search_user_placeholder=搜索用戶...
|
||||
settings.org_not_allowed_to_be_collaborator=Organization is not allowed to be added as a collaborator.
|
||||
settings.user_is_org_member=被操作的用戶是組織成員,因此無法添加為協作者!
|
||||
settings.add_webhook=添加 Web 鉤子
|
||||
settings.hooks_desc=Web 鉤子允許您設定在 Gogs 上發生指定事件時對指定 URL 發送 POST 通知。查看 <a target="_blank" href="%s">Webhooks 文檔</a> 獲取更多信息。
|
||||
settings.webhook_deletion=刪除 Web 鉤子
|
||||
@@ -741,6 +745,7 @@ settings.add_webhook_desc=我們會通過 <code>POST</code> 請求將訂閱事
|
||||
settings.payload_url=推送地址
|
||||
settings.content_type=數據格式
|
||||
settings.secret=密鑰文本
|
||||
settings.secret_desc=Secret will be sent as SHA256 HMAC hex digest of payload via <code>X-Gogs-Signature</code> header.
|
||||
settings.slack_username=服務名稱
|
||||
settings.slack_icon_url=圖標 URL
|
||||
settings.slack_color=顏色代碼
|
||||
|
||||
@@ -473,7 +473,7 @@ editor.add_subdir=新增子目錄...
|
||||
editor.unable_to_upload_files=上傳檔案失敗到 '%s', 錯誤訊息: %v
|
||||
editor.upload_files_to_dir=上傳檔案到 '%s'
|
||||
|
||||
commits.commit_history=Commit History
|
||||
commits.commit_history=提交歷史
|
||||
commits.commits=次代碼提交
|
||||
commits.search=搜索提交歷史
|
||||
commits.find=查找
|
||||
@@ -656,7 +656,11 @@ settings.protect_require_pull_request=請使用 pull request 來更新(合併)
|
||||
settings.protect_require_pull_request_desc=啟用這個選項之後,程式碼將無法直接 Push 到這個分支,所有 Commit 必須先 Push 到另一個非保護的分支,再透過 Pull Request 來要求合併。
|
||||
settings.protect_whitelist_committers=限制誰可以 Push 到這個分支
|
||||
settings.protect_whitelist_committers_desc=新增用戶或團隊到可以直接push到這個分支的白名單。
|
||||
settings.update_protect_branch_success=Protect options for this branch has been updated successfully!
|
||||
settings.protect_whitelist_users=限制那些使用者可以 push 到這個分支
|
||||
settings.protect_whitelist_search_users=搜尋用戶
|
||||
settings.protect_whitelist_teams=Teams for which members of them can push to this branch
|
||||
settings.protect_whitelist_search_teams=搜尋團隊
|
||||
settings.update_protect_branch_success=此分支設置保護已更新成功!
|
||||
settings.hooks=管理 Web 鉤子
|
||||
settings.githooks=管理 Git 鉤子
|
||||
settings.basic_settings=基本設置
|
||||
@@ -684,6 +688,7 @@ settings.tracker_issue_style.alphanumeric=字母及數字
|
||||
settings.tracker_url_format_desc=您可以使用 <code>{user} {repo} {index}</code> 分別作為用戶名、倉庫名和問題索引的占位符。
|
||||
settings.pulls_desc=啟用合併請求以接受社區貢獻
|
||||
settings.danger_zone=危險操作區
|
||||
settings.cannot_fork_to_same_owner=You cannot fork a repository to its original owner.
|
||||
settings.new_owner_has_same_repo=新的倉庫擁有者已經存在同名倉庫!
|
||||
settings.convert=轉換為正規倉庫
|
||||
settings.convert_desc=您可以將此鏡像轉成正規倉庫。此動做不可逆。
|
||||
@@ -718,7 +723,6 @@ settings.collaborator_deletion_desc=刪除後此使用者將不再有協同者
|
||||
settings.remove_collaborator_success=被操作的協作者已經被收回權限!
|
||||
settings.search_user_placeholder=搜索用戶...
|
||||
settings.org_not_allowed_to_be_collaborator=組織不允許被加為協同者。
|
||||
settings.user_is_org_member=被操作的用戶是組織成員,因此無法添加為協作者!
|
||||
settings.add_webhook=添加 Web 鉤子
|
||||
settings.hooks_desc=Web 鉤子允許您設定在 Gogs 上發生指定事件時對指定 URL 發送 POST 通知。查看 <a target="_blank" href="%s">Webhooks 文檔</a> 獲取更多信息。
|
||||
settings.webhook_deletion=刪除 Web 鉤子
|
||||
@@ -741,6 +745,7 @@ settings.add_webhook_desc=我們會通過 <code>POST</code> 請求將訂閱事
|
||||
settings.payload_url=推送地址
|
||||
settings.content_type=數據格式
|
||||
settings.secret=密鑰文本
|
||||
settings.secret_desc=Secret will be sent as SHA256 HMAC hex digest of payload via <code>X-Gogs-Signature</code> header.
|
||||
settings.slack_username=服務名稱
|
||||
settings.slack_icon_url=圖標 URL
|
||||
settings.slack_color=顏色代碼
|
||||
|
||||
@@ -65,7 +65,7 @@ $ docker run --name=gogs -p 10022:22 -p 10080:3000 -v gogs-data:/data gogs/gogs
|
||||
Most of settings are obvious and easy to understand, but there are some settings can be confusing by running Gogs inside Docker:
|
||||
|
||||
- **Repository Root Path**: keep it as default value `/home/git/gogs-repositories` because `start.sh` already made a symbolic link for you.
|
||||
- **Run User**: keep it as default value `git` because `start.sh` already setup a user with name `git`.
|
||||
- **Run User**: keep it as default value `git` because `build.sh` already setup a user with name `git`.
|
||||
- **Domain**: fill in with Docker container IP (e.g. `192.168.99.100`). But if you want to access your Gogs instance from a different physical machine, please fill in with the hostname or IP address of the Docker host machine.
|
||||
- **SSH Port**: Use the exposed port from Docker container. For example, your SSH server listens on `22` inside Docker, **but** you expose it by `10022:22`, then use `10022` for this value. **Builtin SSH server is not recommended inside Docker Container**
|
||||
- **HTTP Port**: Use port you want Gogs to listen on inside Docker container. For example, your Gogs listens on `3000` inside Docker, **and** you expose it by `10080:3000`, but you still use `3000` for this value.
|
||||
@@ -112,4 +112,4 @@ Steps to upgrade Gogs with Docker:
|
||||
|
||||
## Useful Links
|
||||
|
||||
- [Share port 22 between Gogs inside Docker & the local system](http://www.ateijelo.com/blog/2016/07/09/share-port-22-between-docker-gogs-ssh-and-local-system)
|
||||
- [Share port 22 between Gogs inside Docker & the local system](http://www.ateijelo.com/blog/2016/07/09/share-port-22-between-docker-gogs-ssh-and-local-system)
|
||||
|
||||
15
gogs.go
15
gogs.go
@@ -16,7 +16,7 @@ import (
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
const APP_VER = "0.9.164.0220 / 0.10 RC"
|
||||
const APP_VER = "0.10.8.0307"
|
||||
|
||||
func init() {
|
||||
setting.AppVer = APP_VER
|
||||
@@ -28,13 +28,14 @@ func main() {
|
||||
app.Usage = "A painless self-hosted Git service"
|
||||
app.Version = APP_VER
|
||||
app.Commands = []cli.Command{
|
||||
cmd.CmdWeb,
|
||||
cmd.Web,
|
||||
cmd.Serv,
|
||||
cmd.CmdHook,
|
||||
cmd.CmdDump,
|
||||
cmd.CmdCert,
|
||||
cmd.CmdAdmin,
|
||||
cmd.CmdImport,
|
||||
cmd.Hook,
|
||||
cmd.Cert,
|
||||
cmd.Admin,
|
||||
cmd.Import,
|
||||
cmd.Backup,
|
||||
cmd.Restore,
|
||||
}
|
||||
app.Flags = append(app.Flags, []cli.Flag{}...)
|
||||
app.Run(os.Args)
|
||||
|
||||
@@ -57,41 +57,45 @@ type Access struct {
|
||||
Mode AccessMode
|
||||
}
|
||||
|
||||
func accessLevel(e Engine, u *User, repo *Repository) (AccessMode, error) {
|
||||
func accessLevel(e Engine, userID int64, repo *Repository) (AccessMode, error) {
|
||||
mode := ACCESS_MODE_NONE
|
||||
// Everyone has read access to public repository
|
||||
if !repo.IsPrivate {
|
||||
mode = ACCESS_MODE_READ
|
||||
}
|
||||
|
||||
if u == nil {
|
||||
if userID <= 0 {
|
||||
return mode, nil
|
||||
}
|
||||
|
||||
if u.ID == repo.OwnerID {
|
||||
if userID == repo.OwnerID {
|
||||
return ACCESS_MODE_OWNER, nil
|
||||
}
|
||||
|
||||
a := &Access{UserID: u.ID, RepoID: repo.ID}
|
||||
if has, err := e.Get(a); !has || err != nil {
|
||||
access := &Access{
|
||||
UserID: userID,
|
||||
RepoID: repo.ID,
|
||||
}
|
||||
if has, err := e.Get(access); !has || err != nil {
|
||||
return mode, err
|
||||
}
|
||||
return a.Mode, nil
|
||||
return access.Mode, nil
|
||||
}
|
||||
|
||||
// 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)
|
||||
// user does not have access.
|
||||
func AccessLevel(userID int64, repo *Repository) (AccessMode, error) {
|
||||
return accessLevel(x, userID, repo)
|
||||
}
|
||||
|
||||
func hasAccess(e Engine, u *User, repo *Repository, testMode AccessMode) (bool, error) {
|
||||
mode, err := accessLevel(e, u, repo)
|
||||
func hasAccess(e Engine, userID int64, repo *Repository, testMode AccessMode) (bool, error) {
|
||||
mode, err := accessLevel(e, userID, repo)
|
||||
return mode >= testMode, 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)
|
||||
func HasAccess(userID int64, repo *Repository, testMode AccessMode) (bool, error) {
|
||||
return hasAccess(x, userID, repo, testMode)
|
||||
}
|
||||
|
||||
// GetRepositoryAccesses finds all repositories with their access mode where a user has access but does not own.
|
||||
@@ -225,7 +229,7 @@ func (repo *Repository) recalculateAccesses(e Engine) error {
|
||||
return repo.recalculateTeamAccesses(e, 0)
|
||||
}
|
||||
|
||||
accessMap := make(map[int64]AccessMode, 20)
|
||||
accessMap := make(map[int64]AccessMode, 10)
|
||||
if err := repo.refreshCollaboratorAccesses(e, accessMap); err != nil {
|
||||
return fmt.Errorf("refreshCollaboratorAccesses: %v", err)
|
||||
}
|
||||
|
||||
148
models/action.go
148
models/action.go
@@ -26,6 +26,7 @@ import (
|
||||
|
||||
type ActionType int
|
||||
|
||||
// To maintain backward compatibility only append to the end of list
|
||||
const (
|
||||
ACTION_CREATE_REPO ActionType = iota + 1 // 1
|
||||
ACTION_RENAME_REPO // 2
|
||||
@@ -42,6 +43,10 @@ const (
|
||||
ACTION_REOPEN_ISSUE // 13
|
||||
ACTION_CLOSE_PULL_REQUEST // 14
|
||||
ACTION_REOPEN_PULL_REQUEST // 15
|
||||
ACTION_CREATE_BRANCH // 16
|
||||
ACTION_DELETE_BRANCH // 17
|
||||
ACTION_DELETE_TAG // 18
|
||||
ACTION_FORK_REPO // 19
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -66,7 +71,7 @@ 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 `xorm:"pk autoincr"`
|
||||
ID int64
|
||||
UserID int64 // Receiver user id.
|
||||
OpType ActionType
|
||||
ActUserID int64 // Action user id.
|
||||
@@ -172,26 +177,26 @@ func (a *Action) GetIssueContent() string {
|
||||
return issue.Content
|
||||
}
|
||||
|
||||
func newRepoAction(e Engine, u *User, repo *Repository) (err error) {
|
||||
if err = notifyWatchers(e, &Action{
|
||||
ActUserID: u.ID,
|
||||
ActUserName: u.Name,
|
||||
OpType: ACTION_CREATE_REPO,
|
||||
func newRepoAction(e Engine, doer, owner *User, repo *Repository) (err error) {
|
||||
opType := ACTION_CREATE_REPO
|
||||
if repo.IsFork {
|
||||
opType = ACTION_FORK_REPO
|
||||
}
|
||||
|
||||
return notifyWatchers(e, &Action{
|
||||
ActUserID: doer.ID,
|
||||
ActUserName: doer.Name,
|
||||
OpType: opType,
|
||||
RepoID: repo.ID,
|
||||
RepoUserName: repo.Owner.Name,
|
||||
RepoName: repo.Name,
|
||||
IsPrivate: repo.IsPrivate,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("notify watchers '%d/%d': %v", u.ID, repo.ID, err)
|
||||
}
|
||||
|
||||
log.Trace("action.newRepoAction: %s/%s", u.Name, repo.Name)
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
// NewRepoAction adds new action for creating repository.
|
||||
func NewRepoAction(u *User, repo *Repository) (err error) {
|
||||
return newRepoAction(x, u, repo)
|
||||
func NewRepoAction(doer, owner *User, repo *Repository) (err error) {
|
||||
return newRepoAction(x, doer, owner, repo)
|
||||
}
|
||||
|
||||
func renameRepoAction(e Engine, actUser *User, oldRepoName string, repo *Repository) (err error) {
|
||||
@@ -335,7 +340,12 @@ func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit) err
|
||||
}
|
||||
refMarked[issue.ID] = true
|
||||
|
||||
message := fmt.Sprintf(`<a href="%s/commit/%s">%s</a>`, repo.Link(), c.Sha1, c.Message)
|
||||
msgLines := strings.Split(c.Message, "\n")
|
||||
shortMsg := msgLines[0]
|
||||
if len(msgLines) > 2 {
|
||||
shortMsg += "..."
|
||||
}
|
||||
message := fmt.Sprintf(`<a href="%s/commit/%s">%s</a>`, repo.Link(), c.Sha1, shortMsg)
|
||||
if err = CreateRefComment(doer, repo, issue, message, c.Sha1); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -453,18 +463,16 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
|
||||
return fmt.Errorf("UpdateRepository: %v", err)
|
||||
}
|
||||
|
||||
isNewBranch := false
|
||||
isNewRef := opts.OldCommitID == git.EMPTY_SHA
|
||||
isDelRef := opts.NewCommitID == git.EMPTY_SHA
|
||||
|
||||
opType := ACTION_COMMIT_REPO
|
||||
// Check it's tag push or branch.
|
||||
// Check if it's tag push or branch.
|
||||
if strings.HasPrefix(opts.RefFullName, git.TAG_PREFIX) {
|
||||
opType = ACTION_PUSH_TAG
|
||||
opts.Commits = &PushCommits{}
|
||||
} else {
|
||||
// TODO: detect branch deletion
|
||||
// if not the first commit, set the compare URL.
|
||||
if opts.OldCommitID == git.EMPTY_SHA {
|
||||
isNewBranch = true
|
||||
} else {
|
||||
if !isNewRef && !isDelRef {
|
||||
opts.Commits.CompareURL = repo.ComposeCompareURL(opts.OldCommitID, opts.NewCommitID)
|
||||
}
|
||||
|
||||
@@ -483,38 +491,57 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
|
||||
}
|
||||
|
||||
refName := git.RefEndName(opts.RefFullName)
|
||||
if err = NotifyWatchers(&Action{
|
||||
action := &Action{
|
||||
ActUserID: pusher.ID,
|
||||
ActUserName: pusher.Name,
|
||||
OpType: opType,
|
||||
Content: string(data),
|
||||
RepoID: repo.ID,
|
||||
RepoUserName: repo.MustOwner().Name,
|
||||
RepoName: repo.Name,
|
||||
RefName: refName,
|
||||
IsPrivate: repo.IsPrivate,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("NotifyWatchers: %v", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
go HookQueue.Add(repo.ID)
|
||||
}()
|
||||
|
||||
apiPusher := pusher.APIFormat()
|
||||
apiRepo := repo.APIFormat(nil)
|
||||
apiPusher := pusher.APIFormat()
|
||||
switch opType {
|
||||
case ACTION_COMMIT_REPO: // Push
|
||||
if isDelRef {
|
||||
if err = PrepareWebhooks(repo, HOOK_EVENT_DELETE, &api.DeletePayload{
|
||||
Ref: refName,
|
||||
RefType: "branch",
|
||||
PusherType: api.PUSHER_TYPE_USER,
|
||||
Repo: apiRepo,
|
||||
Sender: apiPusher,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("PrepareWebhooks.(delete branch): %v", err)
|
||||
}
|
||||
|
||||
action.OpType = ACTION_DELETE_BRANCH
|
||||
if err = NotifyWatchers(action); err != nil {
|
||||
return fmt.Errorf("NotifyWatchers.(delete branch): %v", err)
|
||||
}
|
||||
|
||||
// Delete branch doesn't have anything to push or compare
|
||||
return nil
|
||||
}
|
||||
|
||||
compareURL := setting.AppUrl + opts.Commits.CompareURL
|
||||
if isNewBranch {
|
||||
if isNewRef {
|
||||
compareURL = ""
|
||||
if err = PrepareWebhooks(repo, HOOK_EVENT_CREATE, &api.CreatePayload{
|
||||
Ref: refName,
|
||||
RefType: "branch",
|
||||
Repo: apiRepo,
|
||||
Sender: apiPusher,
|
||||
Ref: refName,
|
||||
RefType: "branch",
|
||||
DefaultBranch: repo.DefaultBranch,
|
||||
Repo: apiRepo,
|
||||
Sender: apiPusher,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("PrepareWebhooks (new branch): %v", err)
|
||||
return fmt.Errorf("PrepareWebhooks.(new branch): %v", err)
|
||||
}
|
||||
|
||||
action.OpType = ACTION_CREATE_BRANCH
|
||||
if err = NotifyWatchers(action); err != nil {
|
||||
return fmt.Errorf("NotifyWatchers.(new branch): %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -528,16 +555,47 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
|
||||
Pusher: apiPusher,
|
||||
Sender: apiPusher,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("PrepareWebhooks (new commit): %v", err)
|
||||
return fmt.Errorf("PrepareWebhooks.(new commit): %v", err)
|
||||
}
|
||||
|
||||
case ACTION_PUSH_TAG: // Create
|
||||
return PrepareWebhooks(repo, HOOK_EVENT_CREATE, &api.CreatePayload{
|
||||
Ref: refName,
|
||||
RefType: "tag",
|
||||
Repo: apiRepo,
|
||||
Sender: apiPusher,
|
||||
})
|
||||
action.OpType = ACTION_COMMIT_REPO
|
||||
if err = NotifyWatchers(action); err != nil {
|
||||
return fmt.Errorf("NotifyWatchers.(new commit): %v", err)
|
||||
}
|
||||
|
||||
case ACTION_PUSH_TAG: // Tag
|
||||
if isDelRef {
|
||||
if err = PrepareWebhooks(repo, HOOK_EVENT_DELETE, &api.DeletePayload{
|
||||
Ref: refName,
|
||||
RefType: "tag",
|
||||
PusherType: api.PUSHER_TYPE_USER,
|
||||
Repo: apiRepo,
|
||||
Sender: apiPusher,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("PrepareWebhooks.(delete tag): %v", err)
|
||||
}
|
||||
|
||||
action.OpType = ACTION_DELETE_TAG
|
||||
if err = NotifyWatchers(action); err != nil {
|
||||
return fmt.Errorf("NotifyWatchers.(delete tag): %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if err = PrepareWebhooks(repo, HOOK_EVENT_CREATE, &api.CreatePayload{
|
||||
Ref: refName,
|
||||
RefType: "tag",
|
||||
DefaultBranch: repo.DefaultBranch,
|
||||
Repo: apiRepo,
|
||||
Sender: apiPusher,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("PrepareWebhooks.(new tag): %v", err)
|
||||
}
|
||||
|
||||
action.OpType = ACTION_PUSH_TAG
|
||||
if err = NotifyWatchers(action); err != nil {
|
||||
return fmt.Errorf("NotifyWatchers.(new tag): %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -366,8 +366,10 @@ func ParsePatch(maxLines, maxLineCharacteres, maxFiles int, reader io.Reader) (*
|
||||
case strings.HasPrefix(line, "index"):
|
||||
if curFile.IsDeleted {
|
||||
curFile.Index = line[6:46]
|
||||
} else {
|
||||
} else if len(line) >= 88 {
|
||||
curFile.Index = line[49:88]
|
||||
} else {
|
||||
curFile.Index = curFile.Name
|
||||
}
|
||||
break CHECK_TYPE
|
||||
case strings.HasPrefix(line, "similarity index 100%"):
|
||||
|
||||
@@ -618,7 +618,7 @@ func newIssue(e *xorm.Session, opts NewIssueOptions) (err error) {
|
||||
// Assume assignee is invalid and drop silently.
|
||||
opts.Issue.AssigneeID = 0
|
||||
if assignee != nil {
|
||||
valid, err := hasAccess(e, assignee, opts.Repo, ACCESS_MODE_READ)
|
||||
valid, err := hasAccess(e, assignee.ID, opts.Repo, ACCESS_MODE_READ)
|
||||
if err != nil {
|
||||
return fmt.Errorf("hasAccess [user_id: %d, repo_id: %d]: %v", assignee.ID, opts.Repo.ID, err)
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ func (m *migration) Migrate(x *xorm.Engine) error {
|
||||
|
||||
// The version table. Should have only one row with id==1
|
||||
type Version struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
ID int64
|
||||
Version int64
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
@@ -13,6 +15,7 @@ import (
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
_ "github.com/denisenkom/go-mssqldb"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/go-xorm/core"
|
||||
@@ -66,7 +69,7 @@ func init() {
|
||||
new(Issue), new(PullRequest), new(Comment), new(Attachment), new(IssueUser),
|
||||
new(Label), new(IssueLabel), new(Milestone),
|
||||
new(Mirror), new(Release), new(LoginSource), new(Webhook), new(HookTask),
|
||||
new(ProtectBranch),
|
||||
new(ProtectBranch), new(ProtectBranchWhitelist),
|
||||
new(Team), new(OrgUser), new(TeamUser), new(TeamRepo),
|
||||
new(Notice), new(EmailAddress))
|
||||
|
||||
@@ -262,7 +265,89 @@ func Ping() error {
|
||||
return x.Ping()
|
||||
}
|
||||
|
||||
// DumpDatabase dumps all data from database to file system.
|
||||
func DumpDatabase(filePath string) error {
|
||||
return x.DumpAllToFile(filePath)
|
||||
// The version table. Should have only one row with id==1
|
||||
type Version struct {
|
||||
ID int64
|
||||
Version int64
|
||||
}
|
||||
|
||||
// DumpDatabase dumps all data from database to file system in JSON format.
|
||||
func DumpDatabase(dirPath string) (err error) {
|
||||
os.MkdirAll(dirPath, os.ModePerm)
|
||||
// Purposely create a local variable to not modify global variable
|
||||
tables := append(tables, new(Version))
|
||||
for _, table := range tables {
|
||||
tableName := strings.TrimPrefix(fmt.Sprintf("%T", table), "*models.")
|
||||
tableFile := path.Join(dirPath, tableName+".json")
|
||||
f, err := os.Create(tableFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("fail to create JSON file: %v", err)
|
||||
}
|
||||
|
||||
if err = x.Asc("id").Iterate(table, func(idx int, bean interface{}) (err error) {
|
||||
enc := json.NewEncoder(f)
|
||||
return enc.Encode(bean)
|
||||
}); err != nil {
|
||||
f.Close()
|
||||
return fmt.Errorf("fail to dump table '%s': %v", tableName, err)
|
||||
}
|
||||
f.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ImportDatabase imports data from backup archive.
|
||||
func ImportDatabase(dirPath string) (err error) {
|
||||
// Purposely create a local variable to not modify global variable
|
||||
tables := append(tables, new(Version))
|
||||
for _, table := range tables {
|
||||
tableName := strings.TrimPrefix(fmt.Sprintf("%T", table), "*models.")
|
||||
tableFile := path.Join(dirPath, tableName+".json")
|
||||
if !com.IsExist(tableFile) {
|
||||
continue
|
||||
}
|
||||
|
||||
if err = x.DropTables(table); err != nil {
|
||||
return fmt.Errorf("fail to drop table '%s': %v", tableName, err)
|
||||
} else if err = x.Sync2(table); err != nil {
|
||||
return fmt.Errorf("fail to sync table '%s': %v", tableName, err)
|
||||
}
|
||||
|
||||
f, err := os.Open(tableFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("fail to open JSON file: %v", err)
|
||||
}
|
||||
scanner := bufio.NewScanner(f)
|
||||
for scanner.Scan() {
|
||||
switch bean := table.(type) {
|
||||
case *LoginSource:
|
||||
meta := make(map[string]interface{})
|
||||
if err = json.Unmarshal(scanner.Bytes(), &meta); err != nil {
|
||||
return fmt.Errorf("fail to unmarshal to map: %v", err)
|
||||
}
|
||||
|
||||
tp := LoginType(com.StrTo(com.ToStr(meta["Type"])).MustInt64())
|
||||
switch tp {
|
||||
case LOGIN_LDAP, LOGIN_DLDAP:
|
||||
bean.Cfg = new(LDAPConfig)
|
||||
case LOGIN_SMTP:
|
||||
bean.Cfg = new(SMTPConfig)
|
||||
case LOGIN_PAM:
|
||||
bean.Cfg = new(PAMConfig)
|
||||
default:
|
||||
return fmt.Errorf("unrecognized login source type:: %v", tp)
|
||||
}
|
||||
table = bean
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(scanner.Bytes(), table); err != nil {
|
||||
return fmt.Errorf("fail to unmarshal to struct: %v", err)
|
||||
}
|
||||
|
||||
if _, err = x.Insert(table); err != nil {
|
||||
return fmt.Errorf("fail to insert strcut: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
120
models/org.go
120
models/org.go
@@ -10,10 +10,8 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/go-xorm/builder"
|
||||
"github.com/go-xorm/xorm"
|
||||
log "gopkg.in/clog.v1"
|
||||
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -22,8 +20,8 @@ var (
|
||||
)
|
||||
|
||||
// IsOwnedBy returns true if given user is in the owner team.
|
||||
func (org *User) IsOwnedBy(uid int64) bool {
|
||||
return IsOrganizationOwner(org.ID, uid)
|
||||
func (org *User) IsOwnedBy(userID int64) bool {
|
||||
return IsOrganizationOwner(org.ID, userID)
|
||||
}
|
||||
|
||||
// IsOrgMember returns true if given user is member of organization.
|
||||
@@ -32,10 +30,10 @@ func (org *User) IsOrgMember(uid int64) bool {
|
||||
}
|
||||
|
||||
func (org *User) getTeam(e Engine, name string) (*Team, error) {
|
||||
return getTeam(e, org.ID, name)
|
||||
return getTeamOfOrgByName(e, org.ID, name)
|
||||
}
|
||||
|
||||
// GetTeam returns named team of organization.
|
||||
// GetTeamOfOrgByName returns named team of organization.
|
||||
func (org *User) GetTeam(name string) (*Team, error) {
|
||||
return org.getTeam(x, name)
|
||||
}
|
||||
@@ -49,8 +47,9 @@ func (org *User) GetOwnerTeam() (*Team, error) {
|
||||
return org.getOwnerTeam(x)
|
||||
}
|
||||
|
||||
func (org *User) getTeams(e Engine) error {
|
||||
return e.Where("org_id=?", org.ID).Find(&org.Teams)
|
||||
func (org *User) getTeams(e Engine) (err error) {
|
||||
org.Teams, err = getTeamsByOrgID(e, org.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetTeams returns all teams that belong to organization.
|
||||
@@ -58,6 +57,11 @@ func (org *User) GetTeams() error {
|
||||
return org.getTeams(x)
|
||||
}
|
||||
|
||||
// TeamsHaveAccessToRepo returns all teamsthat have given access level to the repository.
|
||||
func (org *User) TeamsHaveAccessToRepo(repoID int64, mode AccessMode) ([]*Team, error) {
|
||||
return GetTeamsHaveAccessToRepo(org.ID, repoID, mode)
|
||||
}
|
||||
|
||||
// GetMembers returns all members of organization.
|
||||
func (org *User) GetMembers() error {
|
||||
ous, err := GetOrgUsersByOrgID(org.ID)
|
||||
@@ -242,8 +246,8 @@ type OrgUser struct {
|
||||
}
|
||||
|
||||
// IsOrganizationOwner returns true if given user is in the owner team.
|
||||
func IsOrganizationOwner(orgId, uid int64) bool {
|
||||
has, _ := x.Where("is_owner=?", true).And("uid=?", uid).And("org_id=?", orgId).Get(new(OrgUser))
|
||||
func IsOrganizationOwner(orgID, userID int64) bool {
|
||||
has, _ := x.Where("is_owner = ?", true).And("uid = ?", userID).And("org_id = ?", orgID).Get(new(OrgUser))
|
||||
return has
|
||||
}
|
||||
|
||||
@@ -299,16 +303,15 @@ func GetOwnedOrgsByUserIDDesc(userID int64, desc string) ([]*User, error) {
|
||||
return getOwnedOrgsByUserID(sess.Desc(desc), userID)
|
||||
}
|
||||
|
||||
// GetOrgUsersByUserID returns all organization-user relations by user ID.
|
||||
func GetOrgUsersByUserID(uid int64, all bool) ([]*OrgUser, error) {
|
||||
ous := make([]*OrgUser, 0, 10)
|
||||
sess := x.Where("uid=?", uid)
|
||||
if !all {
|
||||
// Only show public organizations
|
||||
sess.And("is_public=?", true)
|
||||
// GetOrgIDsByUserID returns a list of organization IDs that user belongs to.
|
||||
// The showPrivate indicates whether to include private memberships.
|
||||
func GetOrgIDsByUserID(userID int64, showPrivate bool) ([]int64, error) {
|
||||
orgIDs := make([]int64, 0, 5)
|
||||
sess := x.Table("org_user").Where("uid = ?", userID)
|
||||
if !showPrivate {
|
||||
sess.And("is_public = ?", true)
|
||||
}
|
||||
err := sess.Find(&ous)
|
||||
return ous, err
|
||||
return orgIDs, sess.Distinct("org_id").Find(&orgIDs)
|
||||
}
|
||||
|
||||
func getOrgUsersByOrgID(e Engine, orgID int64) ([]*OrgUser, error) {
|
||||
@@ -483,8 +486,7 @@ func (org *User) GetUserTeams(userID int64) ([]*Team, error) {
|
||||
return org.getUserTeams(x, userID)
|
||||
}
|
||||
|
||||
// GetUserRepositories returns a range of repositories in organization
|
||||
// that the user with the given userID has access to,
|
||||
// GetUserRepositories returns a range of repositories in organization which the user has access to,
|
||||
// and total number of records based on given condition.
|
||||
func (org *User) GetUserRepositories(userID int64, page, pageSize int) ([]*Repository, int64, error) {
|
||||
teamIDs, err := org.GetUserTeamIDs(userID)
|
||||
@@ -493,43 +495,43 @@ func (org *User) GetUserRepositories(userID int64, page, pageSize int) ([]*Repos
|
||||
}
|
||||
if len(teamIDs) == 0 {
|
||||
// user has no team but "IN ()" is invalid SQL
|
||||
teamIDs = []int64{-1} // there is no repo with id=-1
|
||||
teamIDs = []int64{-1} // there is no team with id=-1
|
||||
}
|
||||
|
||||
var teamRepoIDs []int64
|
||||
if err = x.Table("team_repo").In("team_id", teamIDs).Distinct("repo_id").Find(&teamRepoIDs); err != nil {
|
||||
return nil, 0, fmt.Errorf("get team repository IDs: %v", err)
|
||||
}
|
||||
if len(teamRepoIDs) == 0 {
|
||||
// team has no repo but "IN ()" is invalid SQL
|
||||
teamRepoIDs = []int64{-1} // there is no repo with id=-1
|
||||
}
|
||||
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
repos := make([]*Repository, 0, pageSize)
|
||||
// FIXME: use XORM chain operations instead of raw SQL.
|
||||
if err = x.Sql(fmt.Sprintf(`SELECT repository.* FROM repository
|
||||
INNER JOIN team_repo
|
||||
ON team_repo.repo_id = repository.id
|
||||
WHERE (repository.owner_id = ? AND repository.is_private = ?) OR team_repo.team_id IN (%s)
|
||||
GROUP BY repository.id
|
||||
ORDER BY updated_unix DESC
|
||||
LIMIT %d OFFSET %d`,
|
||||
strings.Join(base.Int64sToStrings(teamIDs), ","), pageSize, (page-1)*pageSize),
|
||||
org.ID, false).Find(&repos); err != nil {
|
||||
return nil, 0, fmt.Errorf("get repositories: %v", err)
|
||||
if err = x.Where("owner_id = ?", org.ID).
|
||||
And("is_private = ?", false).
|
||||
Or(builder.In("id", teamRepoIDs)).
|
||||
Desc("updated_unix").
|
||||
Limit(pageSize, (page-1)*pageSize).
|
||||
Find(&repos); err != nil {
|
||||
return nil, 0, fmt.Errorf("get user repositories: %v", err)
|
||||
}
|
||||
|
||||
results, err := x.Query(fmt.Sprintf(`SELECT repository.id FROM repository
|
||||
INNER JOIN team_repo
|
||||
ON team_repo.repo_id = repository.id
|
||||
WHERE (repository.owner_id = ? AND repository.is_private = ?) OR team_repo.team_id IN (%s)
|
||||
GROUP BY repository.id
|
||||
ORDER BY updated_unix DESC`,
|
||||
strings.Join(base.Int64sToStrings(teamIDs), ",")),
|
||||
org.ID, false)
|
||||
repoCount, err := x.Where("owner_id = ?", org.ID).
|
||||
And("is_private = ?", false).
|
||||
Or(builder.In("id", teamRepoIDs)).
|
||||
Count(new(Repository))
|
||||
if err != nil {
|
||||
log.Error(4, "count user repositories in organization: %v", err)
|
||||
return nil, 0, fmt.Errorf("count user repositories: %v", err)
|
||||
}
|
||||
|
||||
return repos, int64(len(results)), nil
|
||||
return repos, repoCount, nil
|
||||
}
|
||||
|
||||
// GetUserRepositories returns mirror repositories of the organization
|
||||
// that the user with the given userID has access to.
|
||||
// GetUserMirrorRepositories returns mirror repositories of the organization which the user has access to.
|
||||
func (org *User) GetUserMirrorRepositories(userID int64) ([]*Repository, error) {
|
||||
teamIDs, err := org.GetUserTeamIDs(userID)
|
||||
if err != nil {
|
||||
@@ -539,16 +541,24 @@ func (org *User) GetUserMirrorRepositories(userID int64) ([]*Repository, error)
|
||||
teamIDs = []int64{-1}
|
||||
}
|
||||
|
||||
var teamRepoIDs []int64
|
||||
err = x.Table("team_repo").In("team_id", teamIDs).Distinct("repo_id").Find(&teamRepoIDs)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get team repository ids: %v", err)
|
||||
}
|
||||
if len(teamRepoIDs) == 0 {
|
||||
// team has no repo but "IN ()" is invalid SQL
|
||||
teamRepoIDs = []int64{-1} // there is no repo with id=-1
|
||||
}
|
||||
|
||||
repos := make([]*Repository, 0, 10)
|
||||
if err = x.Sql(fmt.Sprintf(`SELECT repository.* FROM repository
|
||||
INNER JOIN team_repo
|
||||
ON team_repo.repo_id = repository.id AND repository.is_mirror = ?
|
||||
WHERE (repository.owner_id = ? AND repository.is_private = ?) OR team_repo.team_id IN (%s)
|
||||
GROUP BY repository.id
|
||||
ORDER BY updated_unix DESC`,
|
||||
strings.Join(base.Int64sToStrings(teamIDs), ",")),
|
||||
true, org.ID, false).Find(&repos); err != nil {
|
||||
return nil, fmt.Errorf("get repositories: %v", err)
|
||||
if err = x.Where("owner_id = ?", org.ID).
|
||||
And("is_private = ?", false).
|
||||
Or(builder.In("id", teamRepoIDs)).
|
||||
And("is_mirror = ?", true). // Don't move up because it's an independent condition
|
||||
Desc("updated_unix").
|
||||
Find(&repos); err != nil {
|
||||
return nil, fmt.Errorf("get user repositories: %v", err)
|
||||
}
|
||||
return repos, nil
|
||||
}
|
||||
|
||||
@@ -43,9 +43,14 @@ func (t *Team) IsOwnerTeam() bool {
|
||||
return t.Name == OWNER_TEAM
|
||||
}
|
||||
|
||||
// HasWriteAccess returns true if team has at least write level access mode.
|
||||
func (t *Team) HasWriteAccess() bool {
|
||||
return t.Authorize >= ACCESS_MODE_WRITE
|
||||
}
|
||||
|
||||
// IsTeamMember returns true if given user is a member of team.
|
||||
func (t *Team) IsMember(uid int64) bool {
|
||||
return IsTeamMember(t.OrgID, t.ID, uid)
|
||||
func (t *Team) IsMember(userID int64) bool {
|
||||
return IsTeamMember(t.OrgID, t.ID, userID)
|
||||
}
|
||||
|
||||
func (t *Team) getRepositories(e Engine) (err error) {
|
||||
@@ -166,15 +171,15 @@ func (t *Team) removeRepository(e Engine, repo *Repository, recalculate bool) (e
|
||||
if err = t.getMembers(e); err != nil {
|
||||
return fmt.Errorf("get team members: %v", err)
|
||||
}
|
||||
for _, u := range t.Members {
|
||||
has, err := hasAccess(e, u, repo, ACCESS_MODE_READ)
|
||||
for _, member := range t.Members {
|
||||
has, err := hasAccess(e, member.ID, repo, ACCESS_MODE_READ)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if has {
|
||||
continue
|
||||
}
|
||||
|
||||
if err = watchRepo(e, u.ID, repo.ID, false); err != nil {
|
||||
if err = watchRepo(e, member.ID, repo.ID, false); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -260,9 +265,9 @@ func NewTeam(t *Team) error {
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
func getTeam(e Engine, orgId int64, name string) (*Team, error) {
|
||||
func getTeamOfOrgByName(e Engine, orgID int64, name string) (*Team, error) {
|
||||
t := &Team{
|
||||
OrgID: orgId,
|
||||
OrgID: orgID,
|
||||
LowerName: strings.ToLower(name),
|
||||
}
|
||||
has, err := e.Get(t)
|
||||
@@ -274,14 +279,14 @@ func getTeam(e Engine, orgId int64, name string) (*Team, error) {
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// GetTeam returns team by given team name and organization.
|
||||
func GetTeam(orgId int64, name string) (*Team, error) {
|
||||
return getTeam(x, orgId, name)
|
||||
// GetTeamOfOrgByName returns team by given team name and organization.
|
||||
func GetTeamOfOrgByName(orgID int64, name string) (*Team, error) {
|
||||
return getTeamOfOrgByName(x, orgID, name)
|
||||
}
|
||||
|
||||
func getTeamByID(e Engine, teamId int64) (*Team, error) {
|
||||
func getTeamByID(e Engine, teamID int64) (*Team, error) {
|
||||
t := new(Team)
|
||||
has, err := e.Id(teamId).Get(t)
|
||||
has, err := e.Id(teamID).Get(t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !has {
|
||||
@@ -291,8 +296,18 @@ func getTeamByID(e Engine, teamId int64) (*Team, error) {
|
||||
}
|
||||
|
||||
// GetTeamByID returns team by given ID.
|
||||
func GetTeamByID(teamId int64) (*Team, error) {
|
||||
return getTeamByID(x, teamId)
|
||||
func GetTeamByID(teamID int64) (*Team, error) {
|
||||
return getTeamByID(x, teamID)
|
||||
}
|
||||
|
||||
func getTeamsByOrgID(e Engine, orgID int64) ([]*Team, error) {
|
||||
teams := make([]*Team, 0, 3)
|
||||
return teams, e.Where("org_id = ?", orgID).Find(&teams)
|
||||
}
|
||||
|
||||
// GetTeamsByOrgID returns all teams belong to given organization.
|
||||
func GetTeamsByOrgID(orgID int64) ([]*Team, error) {
|
||||
return getTeamsByOrgID(x, orgID)
|
||||
}
|
||||
|
||||
// UpdateTeam updates information of team.
|
||||
@@ -429,39 +444,34 @@ func GetTeamMembers(teamID int64) ([]*User, error) {
|
||||
return getTeamMembers(x, teamID)
|
||||
}
|
||||
|
||||
func getUserTeams(e Engine, orgId, uid int64) ([]*Team, error) {
|
||||
tus := make([]*TeamUser, 0, 5)
|
||||
if err := e.Where("uid=?", uid).And("org_id=?", orgId).Find(&tus); err != nil {
|
||||
func getUserTeams(e Engine, orgID, userID int64) ([]*Team, error) {
|
||||
teamUsers := make([]*TeamUser, 0, 5)
|
||||
if err := e.Where("uid = ?", userID).And("org_id = ?", orgID).Find(&teamUsers); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ts := make([]*Team, len(tus))
|
||||
for i, tu := range tus {
|
||||
t := new(Team)
|
||||
has, err := e.Id(tu.TeamID).Get(t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !has {
|
||||
return nil, ErrTeamNotExist
|
||||
}
|
||||
ts[i] = t
|
||||
teamIDs := make([]int64, len(teamUsers))
|
||||
for i := range teamUsers {
|
||||
teamIDs[i] = teamUsers[i].TeamID
|
||||
}
|
||||
return ts, nil
|
||||
|
||||
teams := make([]*Team, 0, len(teamIDs))
|
||||
return teams, e.Where("org_id = ?", orgID).In("id", teamIDs).Find(&teams)
|
||||
}
|
||||
|
||||
// GetUserTeams returns all teams that user belongs to in given organization.
|
||||
func GetUserTeams(orgId, uid int64) ([]*Team, error) {
|
||||
return getUserTeams(x, orgId, uid)
|
||||
func GetUserTeams(orgID, userID int64) ([]*Team, error) {
|
||||
return getUserTeams(x, orgID, userID)
|
||||
}
|
||||
|
||||
// AddTeamMember adds new membership of given team to given organization,
|
||||
// the user will have membership to given organization automatically when needed.
|
||||
func AddTeamMember(orgID, teamID, uid int64) error {
|
||||
if IsTeamMember(orgID, teamID, uid) {
|
||||
func AddTeamMember(orgID, teamID, userID int64) error {
|
||||
if IsTeamMember(orgID, teamID, userID) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := AddOrgUser(orgID, uid); err != nil {
|
||||
if err := AddOrgUser(orgID, userID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -483,7 +493,7 @@ func AddTeamMember(orgID, teamID, uid int64) error {
|
||||
}
|
||||
|
||||
tu := &TeamUser{
|
||||
UID: uid,
|
||||
UID: userID,
|
||||
OrgID: orgID,
|
||||
TeamID: teamID,
|
||||
}
|
||||
@@ -502,7 +512,7 @@ func AddTeamMember(orgID, teamID, uid int64) error {
|
||||
|
||||
// We make sure it exists before.
|
||||
ou := new(OrgUser)
|
||||
if _, err = sess.Where("uid = ?", uid).And("org_id = ?", orgID).Get(ou); err != nil {
|
||||
if _, err = sess.Where("uid = ?", userID).And("org_id = ?", orgID).Get(ou); err != nil {
|
||||
return err
|
||||
}
|
||||
ou.NumTeams++
|
||||
@@ -600,18 +610,18 @@ func RemoveTeamMember(orgID, teamID, uid int64) error {
|
||||
|
||||
// TeamRepo represents an team-repository relation.
|
||||
type TeamRepo struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
ID int64
|
||||
OrgID int64 `xorm:"INDEX"`
|
||||
TeamID int64 `xorm:"UNIQUE(s)"`
|
||||
RepoID int64 `xorm:"UNIQUE(s)"`
|
||||
}
|
||||
|
||||
func hasTeamRepo(e Engine, orgID, teamID, repoID int64) bool {
|
||||
has, _ := e.Where("org_id=?", orgID).And("team_id=?", teamID).And("repo_id=?", repoID).Get(new(TeamRepo))
|
||||
has, _ := e.Where("org_id = ?", orgID).And("team_id = ?", teamID).And("repo_id = ?", repoID).Get(new(TeamRepo))
|
||||
return has
|
||||
}
|
||||
|
||||
// HasTeamRepo returns true if given repository belongs to team.
|
||||
// HasTeamRepo returns true if given team has access to the repository of the organization.
|
||||
func HasTeamRepo(orgID, teamID, repoID int64) bool {
|
||||
return hasTeamRepo(x, orgID, teamID, repoID)
|
||||
}
|
||||
@@ -642,3 +652,13 @@ func removeTeamRepo(e Engine, teamID, repoID int64) error {
|
||||
func RemoveTeamRepo(teamID, repoID int64) error {
|
||||
return removeTeamRepo(x, teamID, repoID)
|
||||
}
|
||||
|
||||
// GetTeamsHaveAccessToRepo returns all teams in an organization that have given access level to the repository.
|
||||
func GetTeamsHaveAccessToRepo(orgID, repoID int64, mode AccessMode) ([]*Team, error) {
|
||||
teams := make([]*Team, 0, 5)
|
||||
return teams, x.Where("team.authorize >= ?", mode).
|
||||
Join("INNER", "team_repo", "team_repo.team_id = team.id").
|
||||
And("team_repo.org_id = ?", orgID).
|
||||
And("team_repo.repo_id = ?", repoID).
|
||||
Find(&teams)
|
||||
}
|
||||
|
||||
143
models/repo.go
143
models/repo.go
@@ -329,14 +329,14 @@ func (repo *Repository) DeleteWiki() {
|
||||
}
|
||||
}
|
||||
|
||||
// getAssignees returns a list of users who can be assigned to issues in this repository.
|
||||
func (repo *Repository) getAssignees(e Engine) (_ []*User, err error) {
|
||||
// getUsersWithAccesMode returns users that have at least given access mode to the repository.
|
||||
func (repo *Repository) getUsersWithAccesMode(e Engine, mode AccessMode) (_ []*User, err error) {
|
||||
if err = repo.getOwner(e); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
accesses := make([]*Access, 0, 10)
|
||||
if err = e.Where("repo_id = ? AND mode >= ?", repo.ID, ACCESS_MODE_READ).Find(&accesses); err != nil {
|
||||
if err = e.Where("repo_id = ? AND mode >= ?", repo.ID, mode).Find(&accesses); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -360,7 +360,12 @@ func (repo *Repository) getAssignees(e Engine) (_ []*User, err error) {
|
||||
return users, nil
|
||||
}
|
||||
|
||||
// GetAssignees returns all users that have write access and can be assigned to issues
|
||||
// getAssignees returns a list of users who can be assigned to issues in this repository.
|
||||
func (repo *Repository) getAssignees(e Engine) (_ []*User, err error) {
|
||||
return repo.getUsersWithAccesMode(e, ACCESS_MODE_READ)
|
||||
}
|
||||
|
||||
// GetAssignees returns all users that have read access and can be assigned to issues
|
||||
// of the repository,
|
||||
func (repo *Repository) GetAssignees() (_ []*User, err error) {
|
||||
return repo.getAssignees(x)
|
||||
@@ -371,6 +376,11 @@ func (repo *Repository) GetAssigneeByID(userID int64) (*User, error) {
|
||||
return GetAssigneeByID(repo, userID)
|
||||
}
|
||||
|
||||
// GetWriters returns all users that have write access to the repository.
|
||||
func (repo *Repository) GetWriters() (_ []*User, err error) {
|
||||
return repo.getUsersWithAccesMode(x, ACCESS_MODE_WRITE)
|
||||
}
|
||||
|
||||
// GetMilestoneByID returns the milestone belongs to repository by given ID.
|
||||
func (repo *Repository) GetMilestoneByID(milestoneID int64) (*Milestone, error) {
|
||||
return GetMilestoneByRepoID(repo.ID, milestoneID)
|
||||
@@ -419,8 +429,8 @@ func (repo *Repository) ComposeCompareURL(oldCommitID, newCommitID string) strin
|
||||
return fmt.Sprintf("%s/%s/compare/%s...%s", repo.MustOwner().Name, repo.Name, oldCommitID, newCommitID)
|
||||
}
|
||||
|
||||
func (repo *Repository) HasAccess(u *User) bool {
|
||||
has, _ := HasAccess(u, repo, ACCESS_MODE_READ)
|
||||
func (repo *Repository) HasAccess(userID int64) bool {
|
||||
has, _ := HasAccess(userID, repo, ACCESS_MODE_READ)
|
||||
return has
|
||||
}
|
||||
|
||||
@@ -618,8 +628,8 @@ func wikiRemoteURL(remote string) string {
|
||||
}
|
||||
|
||||
// MigrateRepository migrates a existing repository from other project hosting.
|
||||
func MigrateRepository(u *User, opts MigrateRepoOptions) (*Repository, error) {
|
||||
repo, err := CreateRepository(u, CreateRepoOptions{
|
||||
func MigrateRepository(doer, owner *User, opts MigrateRepoOptions) (*Repository, error) {
|
||||
repo, err := CreateRepository(doer, owner, CreateRepoOptions{
|
||||
Name: opts.Name,
|
||||
Description: opts.Description,
|
||||
IsPrivate: opts.IsPrivate,
|
||||
@@ -629,11 +639,11 @@ func MigrateRepository(u *User, opts MigrateRepoOptions) (*Repository, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
repoPath := RepoPath(u.Name, opts.Name)
|
||||
wikiPath := WikiPath(u.Name, opts.Name)
|
||||
repoPath := RepoPath(owner.Name, opts.Name)
|
||||
wikiPath := WikiPath(owner.Name, opts.Name)
|
||||
|
||||
if u.IsOrganization() {
|
||||
t, err := u.GetOwnerTeam()
|
||||
if owner.IsOrganization() {
|
||||
t, err := owner.GetOwnerTeam()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -655,14 +665,14 @@ func MigrateRepository(u *User, opts MigrateRepoOptions) (*Repository, error) {
|
||||
|
||||
wikiRemotePath := wikiRemoteURL(opts.RemoteAddr)
|
||||
if len(wikiRemotePath) > 0 {
|
||||
RemoveAllWithNotice("Repository wiki path erase before creation", repoPath)
|
||||
RemoveAllWithNotice("Repository wiki path erase before creation", wikiPath)
|
||||
if err = git.Clone(wikiRemotePath, wikiPath, git.CloneRepoOptions{
|
||||
Mirror: true,
|
||||
Quiet: true,
|
||||
Timeout: migrateTimeout,
|
||||
}); err != nil {
|
||||
log.Trace("Fail to clone wiki: %v", err)
|
||||
RemoveAllWithNotice("Delete repository wiki for initialization failure", repoPath)
|
||||
RemoveAllWithNotice("Delete repository wiki for initialization failure", wikiPath)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -872,8 +882,8 @@ func prepareRepoCommit(repo *Repository, tmpDir, repoPath string, opts CreateRep
|
||||
return nil
|
||||
}
|
||||
|
||||
// InitRepository initializes README and .gitignore if needed.
|
||||
func initRepository(e Engine, repoPath string, u *User, repo *Repository, opts CreateRepoOptions) (err error) {
|
||||
// initRepository performs initial commit with chosen setup files on behave of doer.
|
||||
func initRepository(e Engine, repoPath string, doer *User, repo *Repository, opts CreateRepoOptions) (err error) {
|
||||
// Somehow the directory could exist.
|
||||
if com.IsExist(repoPath) {
|
||||
return fmt.Errorf("initRepository: path already exists: %s", repoPath)
|
||||
@@ -898,7 +908,7 @@ func initRepository(e Engine, repoPath string, u *User, repo *Repository, opts C
|
||||
}
|
||||
|
||||
// Apply changes and commit.
|
||||
if err = initRepoCommit(tmpDir, u.NewGitSig()); err != nil {
|
||||
if err = initRepoCommit(tmpDir, doer.NewGitSig()); err != nil {
|
||||
return fmt.Errorf("initRepoCommit: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -931,32 +941,32 @@ func IsUsableRepoName(name string) error {
|
||||
return isUsableName(reservedRepoNames, reservedRepoPatterns, name)
|
||||
}
|
||||
|
||||
func createRepository(e *xorm.Session, u *User, repo *Repository) (err error) {
|
||||
func createRepository(e *xorm.Session, doer, owner *User, repo *Repository) (err error) {
|
||||
if err = IsUsableRepoName(repo.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
has, err := isRepositoryExist(e, u, repo.Name)
|
||||
has, err := isRepositoryExist(e, owner, repo.Name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("IsRepositoryExist: %v", err)
|
||||
} else if has {
|
||||
return ErrRepoAlreadyExist{u.Name, repo.Name}
|
||||
return ErrRepoAlreadyExist{owner.Name, repo.Name}
|
||||
}
|
||||
|
||||
if _, err = e.Insert(repo); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
u.NumRepos++
|
||||
owner.NumRepos++
|
||||
// Remember visibility preference.
|
||||
u.LastRepoVisibility = repo.IsPrivate
|
||||
if err = updateUser(e, u); err != nil {
|
||||
owner.LastRepoVisibility = repo.IsPrivate
|
||||
if err = updateUser(e, owner); err != nil {
|
||||
return fmt.Errorf("updateUser: %v", err)
|
||||
}
|
||||
|
||||
// Give access to all members in owner team.
|
||||
if u.IsOrganization() {
|
||||
t, err := u.getOwnerTeam(e)
|
||||
if owner.IsOrganization() {
|
||||
t, err := owner.getOwnerTeam(e)
|
||||
if err != nil {
|
||||
return fmt.Errorf("getOwnerTeam: %v", err)
|
||||
} else if err = t.addRepository(e, repo); err != nil {
|
||||
@@ -969,9 +979,9 @@ func createRepository(e *xorm.Session, u *User, repo *Repository) (err error) {
|
||||
}
|
||||
}
|
||||
|
||||
if err = watchRepo(e, u.ID, repo.ID, true); err != nil {
|
||||
if err = watchRepo(e, owner.ID, repo.ID, true); err != nil {
|
||||
return fmt.Errorf("watchRepo: %v", err)
|
||||
} else if err = newRepoAction(e, u, repo); err != nil {
|
||||
} else if err = newRepoAction(e, doer, owner, repo); err != nil {
|
||||
return fmt.Errorf("newRepoAction: %v", err)
|
||||
}
|
||||
|
||||
@@ -979,14 +989,14 @@ func createRepository(e *xorm.Session, u *User, repo *Repository) (err error) {
|
||||
}
|
||||
|
||||
// CreateRepository creates a repository for given user or organization.
|
||||
func CreateRepository(u *User, opts CreateRepoOptions) (_ *Repository, err error) {
|
||||
if !u.CanCreateRepo() {
|
||||
return nil, ErrReachLimitOfRepo{u.MaxRepoCreation}
|
||||
func CreateRepository(doer, owner *User, opts CreateRepoOptions) (_ *Repository, err error) {
|
||||
if !owner.CanCreateRepo() {
|
||||
return nil, ErrReachLimitOfRepo{owner.MaxRepoCreation}
|
||||
}
|
||||
|
||||
repo := &Repository{
|
||||
OwnerID: u.ID,
|
||||
Owner: u,
|
||||
OwnerID: owner.ID,
|
||||
Owner: owner,
|
||||
Name: opts.Name,
|
||||
LowerName: strings.ToLower(opts.Name),
|
||||
Description: opts.Description,
|
||||
@@ -1002,23 +1012,23 @@ func CreateRepository(u *User, opts CreateRepoOptions) (_ *Repository, err error
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = createRepository(sess, u, repo); err != nil {
|
||||
if err = createRepository(sess, doer, owner, repo); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// No need for init mirror.
|
||||
if !opts.IsMirror {
|
||||
repoPath := RepoPath(u.Name, repo.Name)
|
||||
if err = initRepository(sess, repoPath, u, repo, opts); err != nil {
|
||||
repoPath := RepoPath(owner.Name, repo.Name)
|
||||
if err = initRepository(sess, repoPath, doer, repo, opts); err != nil {
|
||||
RemoveAllWithNotice("Delete repository for initialization failure", repoPath)
|
||||
return nil, fmt.Errorf("initRepository: %v", err)
|
||||
}
|
||||
|
||||
_, stderr, err := process.ExecDir(-1,
|
||||
repoPath, fmt.Sprintf("CreateRepository(git update-server-info): %s", repoPath),
|
||||
repoPath, fmt.Sprintf("CreateRepository 'git update-server-info': %s", repoPath),
|
||||
"git", "update-server-info")
|
||||
if err != nil {
|
||||
return nil, errors.New("CreateRepository(git update-server-info): " + stderr)
|
||||
return nil, errors.New("CreateRepository 'git update-server-info': " + stderr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1391,6 +1401,8 @@ func DeleteRepository(uid, repoID int64) error {
|
||||
&Release{RepoID: repoID},
|
||||
&Collaboration{RepoID: repoID},
|
||||
&PullRequest{BaseRepoID: repoID},
|
||||
&ProtectBranch{RepoID: repoID},
|
||||
&ProtectBranchWhitelist{RepoID: repoID},
|
||||
); err != nil {
|
||||
return fmt.Errorf("deleteBeans: %v", err)
|
||||
}
|
||||
@@ -2056,25 +2068,28 @@ func (repo *Repository) GetWatchers(page int) ([]*User, error) {
|
||||
|
||||
func notifyWatchers(e Engine, act *Action) error {
|
||||
// Add feeds for user self and all watchers.
|
||||
watches, err := getWatchers(e, act.RepoID)
|
||||
watchers, err := getWatchers(e, act.RepoID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("get watchers: %v", err)
|
||||
return fmt.Errorf("getWatchers: %v", err)
|
||||
}
|
||||
|
||||
// Reset ID to reuse Action object
|
||||
act.ID = 0
|
||||
|
||||
// Add feed for actioner.
|
||||
act.UserID = act.ActUserID
|
||||
if _, err = e.InsertOne(act); err != nil {
|
||||
return fmt.Errorf("insert new actioner: %v", err)
|
||||
if _, err = e.Insert(act); err != nil {
|
||||
return fmt.Errorf("insert new action: %v", err)
|
||||
}
|
||||
|
||||
for i := range watches {
|
||||
if act.ActUserID == watches[i].UserID {
|
||||
for i := range watchers {
|
||||
if act.ActUserID == watchers[i].UserID {
|
||||
continue
|
||||
}
|
||||
|
||||
act.ID = 0
|
||||
act.UserID = watches[i].UserID
|
||||
if _, err = e.InsertOne(act); err != nil {
|
||||
act.UserID = watchers[i].UserID
|
||||
if _, err = e.Insert(act); err != nil {
|
||||
return fmt.Errorf("insert new action: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -2149,24 +2164,26 @@ func (repo *Repository) GetStargazers(page int) ([]*User, error) {
|
||||
// \___ / \____/|__| |__|_ \
|
||||
// \/ \/
|
||||
|
||||
// HasForkedRepo checks if given user has already forked a repository with given ID.
|
||||
// HasForkedRepo checks if given user has already forked a repository.
|
||||
// When user has already forked, it returns true along with the repository.
|
||||
func HasForkedRepo(ownerID, repoID int64) (*Repository, bool) {
|
||||
repo := new(Repository)
|
||||
has, _ := x.Where("owner_id=? AND fork_id=?", ownerID, repoID).Get(repo)
|
||||
has, _ := x.Where("owner_id = ? AND fork_id = ?", ownerID, repoID).Get(repo)
|
||||
return repo, has
|
||||
}
|
||||
|
||||
func ForkRepository(u *User, oldRepo *Repository, name, desc string) (_ *Repository, err error) {
|
||||
// ForkRepository creates a fork of target repository under another user domain.
|
||||
func ForkRepository(doer, owner *User, baseRepo *Repository, name, desc string) (_ *Repository, err error) {
|
||||
repo := &Repository{
|
||||
OwnerID: u.ID,
|
||||
Owner: u,
|
||||
OwnerID: owner.ID,
|
||||
Owner: owner,
|
||||
Name: name,
|
||||
LowerName: strings.ToLower(name),
|
||||
Description: desc,
|
||||
DefaultBranch: oldRepo.DefaultBranch,
|
||||
IsPrivate: oldRepo.IsPrivate,
|
||||
DefaultBranch: baseRepo.DefaultBranch,
|
||||
IsPrivate: baseRepo.IsPrivate,
|
||||
IsFork: true,
|
||||
ForkID: oldRepo.ID,
|
||||
ForkID: baseRepo.ID,
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
@@ -2175,18 +2192,16 @@ func ForkRepository(u *User, oldRepo *Repository, name, desc string) (_ *Reposit
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = createRepository(sess, u, repo); err != nil {
|
||||
if err = createRepository(sess, doer, owner, repo); err != nil {
|
||||
return nil, err
|
||||
} else if _, err = sess.Exec("UPDATE `repository` SET num_forks=num_forks+1 WHERE id=?", baseRepo.ID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err = sess.Exec("UPDATE `repository` SET num_forks=num_forks+1 WHERE id=?", oldRepo.ID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
repoPath := RepoPath(u.Name, repo.Name)
|
||||
repoPath := repo.repoPath(sess)
|
||||
_, stderr, err := process.ExecTimeout(10*time.Minute,
|
||||
fmt.Sprintf("ForkRepository 'git clone': %s/%s", u.Name, repo.Name),
|
||||
"git", "clone", "--bare", oldRepo.RepoPath(), repoPath)
|
||||
fmt.Sprintf("ForkRepository 'git clone': %s/%s", owner.Name, repo.Name),
|
||||
"git", "clone", "--bare", baseRepo.RepoPath(), repoPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("git clone: %v", stderr)
|
||||
}
|
||||
@@ -2200,6 +2215,12 @@ func ForkRepository(u *User, oldRepo *Repository, name, desc string) (_ *Reposit
|
||||
|
||||
if err = createDelegateHooks(repoPath); err != nil {
|
||||
return nil, fmt.Errorf("createDelegateHooks: %v", err)
|
||||
} else if err = prepareWebhooks(sess, baseRepo, HOOK_EVENT_FORK, &api.ForkPayload{
|
||||
Forkee: repo.APIFormat(nil),
|
||||
Repo: baseRepo.APIFormat(nil),
|
||||
Sender: doer.APIFormat(),
|
||||
}); err != nil {
|
||||
return nil, fmt.Errorf("prepareWebhooks: %v", err)
|
||||
}
|
||||
|
||||
return repo, sess.Commit()
|
||||
|
||||
@@ -6,8 +6,12 @@ package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/gogits/git-module"
|
||||
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
)
|
||||
|
||||
type Branch struct {
|
||||
@@ -58,6 +62,20 @@ func (br *Branch) GetCommit() (*git.Commit, error) {
|
||||
return gitRepo.GetBranchCommit(br.Name)
|
||||
}
|
||||
|
||||
type ProtectBranchWhitelist struct {
|
||||
ID int64
|
||||
ProtectBranchID int64
|
||||
RepoID int64 `xorm:"UNIQUE(protect_branch_whitelist)"`
|
||||
Name string `xorm:"UNIQUE(protect_branch_whitelist)"`
|
||||
UserID int64 `xorm:"UNIQUE(protect_branch_whitelist)"`
|
||||
}
|
||||
|
||||
// IsUserInProtectBranchWhitelist returns true if given user is in the whitelist of a branch in a repository.
|
||||
func IsUserInProtectBranchWhitelist(repoID, userID int64, branch string) bool {
|
||||
has, err := x.Where("repo_id = ?", repoID).And("user_id = ?", userID).And("name = ?", branch).Get(new(ProtectBranchWhitelist))
|
||||
return has && err == nil
|
||||
}
|
||||
|
||||
// ProtectBranch contains options of a protected branch.
|
||||
type ProtectBranch struct {
|
||||
ID int64
|
||||
@@ -65,6 +83,9 @@ type ProtectBranch struct {
|
||||
Name string `xorm:"UNIQUE(protect_branch)"`
|
||||
Protected bool
|
||||
RequirePullRequest bool
|
||||
EnableWhitelist bool
|
||||
WhitelistUserIDs string `xorm:"TEXT"`
|
||||
WhitelistTeamIDs string `xorm:"TEXT"`
|
||||
}
|
||||
|
||||
// GetProtectBranchOfRepoByName returns *ProtectBranch by branch name in given repostiory.
|
||||
@@ -94,15 +115,134 @@ func IsBranchOfRepoRequirePullRequest(repoID int64, name string) bool {
|
||||
// UpdateProtectBranch saves branch protection options.
|
||||
// If ID is 0, it creates a new record. Otherwise, updates existing record.
|
||||
func UpdateProtectBranch(protectBranch *ProtectBranch) (err error) {
|
||||
if protectBranch.ID == 0 {
|
||||
if _, err = x.Insert(protectBranch); err != nil {
|
||||
return fmt.Errorf("Insert: %v", err)
|
||||
}
|
||||
return
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = x.Id(protectBranch.ID).AllCols().Update(protectBranch)
|
||||
return err
|
||||
if protectBranch.ID == 0 {
|
||||
if _, err = sess.Insert(protectBranch); err != nil {
|
||||
return fmt.Errorf("Insert: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if _, err = sess.Id(protectBranch.ID).AllCols().Update(protectBranch); err != nil {
|
||||
return fmt.Errorf("Update: %v", err)
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
// UpdateOrgProtectBranch saves branch protection options of organizational repository.
|
||||
// If ID is 0, it creates a new record. Otherwise, updates existing record.
|
||||
// This function also performs check if whitelist user and team's IDs have been changed
|
||||
// to avoid unnecessary whitelist delete and regenerate.
|
||||
func UpdateOrgProtectBranch(repo *Repository, protectBranch *ProtectBranch, whitelistUserIDs, whitelistTeamIDs string) (err error) {
|
||||
if err = repo.GetOwner(); err != nil {
|
||||
return fmt.Errorf("GetOwner: %v", err)
|
||||
} else if !repo.Owner.IsOrganization() {
|
||||
return fmt.Errorf("expect repository owner to be an organization")
|
||||
}
|
||||
|
||||
hasUsersChanged := false
|
||||
validUserIDs := base.StringsToInt64s(strings.Split(protectBranch.WhitelistUserIDs, ","))
|
||||
if protectBranch.WhitelistUserIDs != whitelistUserIDs {
|
||||
hasUsersChanged = true
|
||||
userIDs := base.StringsToInt64s(strings.Split(whitelistUserIDs, ","))
|
||||
validUserIDs = make([]int64, 0, len(userIDs))
|
||||
for _, userID := range userIDs {
|
||||
has, err := HasAccess(userID, repo, ACCESS_MODE_WRITE)
|
||||
if err != nil {
|
||||
return fmt.Errorf("HasAccess [user_id: %d, repo_id: %d]: %v", userID, protectBranch.RepoID, err)
|
||||
} else if !has {
|
||||
continue // Drop invalid user ID
|
||||
}
|
||||
|
||||
validUserIDs = append(validUserIDs, userID)
|
||||
}
|
||||
|
||||
protectBranch.WhitelistUserIDs = strings.Join(base.Int64sToStrings(validUserIDs), ",")
|
||||
}
|
||||
|
||||
hasTeamsChanged := false
|
||||
validTeamIDs := base.StringsToInt64s(strings.Split(protectBranch.WhitelistTeamIDs, ","))
|
||||
if protectBranch.WhitelistTeamIDs != whitelistTeamIDs {
|
||||
hasTeamsChanged = true
|
||||
teamIDs := base.StringsToInt64s(strings.Split(whitelistTeamIDs, ","))
|
||||
teams, err := GetTeamsHaveAccessToRepo(repo.OwnerID, repo.ID, ACCESS_MODE_WRITE)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetTeamsHaveAccessToRepo [org_id: %d, repo_id: %d]: %v", repo.OwnerID, repo.ID, err)
|
||||
}
|
||||
validTeamIDs = make([]int64, 0, len(teams))
|
||||
for i := range teams {
|
||||
if teams[i].HasWriteAccess() && com.IsSliceContainsInt64(teamIDs, teams[i].ID) {
|
||||
validTeamIDs = append(validTeamIDs, teams[i].ID)
|
||||
}
|
||||
}
|
||||
|
||||
protectBranch.WhitelistTeamIDs = strings.Join(base.Int64sToStrings(validTeamIDs), ",")
|
||||
}
|
||||
|
||||
// Merge users and members of teams
|
||||
var whitelists []*ProtectBranchWhitelist
|
||||
if hasUsersChanged || hasTeamsChanged {
|
||||
mergedUserIDs := make(map[int64]bool)
|
||||
for _, userID := range validUserIDs {
|
||||
// Empty whitelist users can cause an ID with 0
|
||||
if userID != 0 {
|
||||
mergedUserIDs[userID] = true
|
||||
}
|
||||
}
|
||||
|
||||
for _, teamID := range validTeamIDs {
|
||||
members, err := GetTeamMembers(teamID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetTeamMembers [team_id: %d]: %v", teamID, err)
|
||||
}
|
||||
|
||||
for i := range members {
|
||||
mergedUserIDs[members[i].ID] = true
|
||||
}
|
||||
}
|
||||
|
||||
whitelists = make([]*ProtectBranchWhitelist, 0, len(mergedUserIDs))
|
||||
for userID := range mergedUserIDs {
|
||||
whitelists = append(whitelists, &ProtectBranchWhitelist{
|
||||
ProtectBranchID: protectBranch.ID,
|
||||
RepoID: repo.ID,
|
||||
Name: protectBranch.Name,
|
||||
UserID: userID,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if protectBranch.ID == 0 {
|
||||
if _, err = sess.Insert(protectBranch); err != nil {
|
||||
return fmt.Errorf("Insert: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if _, err = sess.Id(protectBranch.ID).AllCols().Update(protectBranch); err != nil {
|
||||
return fmt.Errorf("Update: %v", err)
|
||||
}
|
||||
|
||||
// Refresh whitelists
|
||||
if hasUsersChanged || hasTeamsChanged {
|
||||
if _, err = sess.Delete(&ProtectBranchWhitelist{ProtectBranchID: protectBranch.ID}); err != nil {
|
||||
return fmt.Errorf("delete old protect branch whitelists: %v", err)
|
||||
} else if _, err = sess.Insert(whitelists); err != nil {
|
||||
return fmt.Errorf("insert new protect branch whitelists: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
// GetProtectBranchesByRepoID returns a list of *ProtectBranch in given repostiory.
|
||||
|
||||
@@ -62,17 +62,10 @@ func (repo *Repository) AddCollaborator(u *User) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = sess.InsertOne(collaboration); err != nil {
|
||||
if _, err = sess.Insert(collaboration); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if repo.Owner.IsOrganization() {
|
||||
err = repo.recalculateTeamAccesses(sess, 0)
|
||||
} else {
|
||||
err = repo.recalculateAccesses(sess)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("recalculateAccesses 'team=%v': %v", repo.Owner.IsOrganization(), err)
|
||||
} else if err = repo.recalculateAccesses(sess); err != nil {
|
||||
return fmt.Errorf("recalculateAccesses [repo_id: %v]: %v", repo.ID, err)
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
@@ -148,6 +141,19 @@ func (repo *Repository) ChangeCollaborationAccessMode(userID int64, mode AccessM
|
||||
}
|
||||
collaboration.Mode = mode
|
||||
|
||||
// If it's an organizational repository, merge with team access level for highest permission
|
||||
if repo.Owner.IsOrganization() {
|
||||
teams, err := GetUserTeams(repo.OwnerID, userID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetUserTeams: [org_id: %d, user_id: %d]: %v", repo.OwnerID, userID, err)
|
||||
}
|
||||
for i := range teams {
|
||||
if mode < teams[i].Authorize {
|
||||
mode = teams[i].Authorize
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sessionRelease(sess)
|
||||
if err = sess.Begin(); err != nil {
|
||||
@@ -173,7 +179,7 @@ func (repo *Repository) ChangeCollaborationAccessMode(userID int64, mode AccessM
|
||||
_, err = sess.Insert(access)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("update access table: %v", err)
|
||||
return fmt.Errorf("update/insert access table: %v", err)
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
|
||||
@@ -736,7 +736,7 @@ func DeleteDeployKey(doer *User, id int64) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetRepositoryByID: %v", err)
|
||||
}
|
||||
yes, err := HasAccess(doer, repo, ACCESS_MODE_ADMIN)
|
||||
yes, err := HasAccess(doer.ID, repo, ACCESS_MODE_ADMIN)
|
||||
if err != nil {
|
||||
return fmt.Errorf("HasAccess: %v", err)
|
||||
} else if !yes {
|
||||
|
||||
@@ -10,8 +10,6 @@ import (
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
log "gopkg.in/clog.v1"
|
||||
|
||||
git "github.com/gogits/git-module"
|
||||
)
|
||||
|
||||
@@ -29,6 +27,10 @@ func CommitToPushCommit(commit *git.Commit) *PushCommit {
|
||||
}
|
||||
|
||||
func ListToPushCommits(l *list.List) *PushCommits {
|
||||
if l == nil {
|
||||
return &PushCommits{}
|
||||
}
|
||||
|
||||
commits := make([]*PushCommit, 0)
|
||||
var actEmail string
|
||||
for e := l.Front(); e != nil; e = e.Next() {
|
||||
@@ -68,12 +70,6 @@ func PushUpdate(opts PushUpdateOptions) (err error) {
|
||||
return fmt.Errorf("Fail to call 'git update-server-info': %v", err)
|
||||
}
|
||||
|
||||
if isDelRef {
|
||||
log.Trace("Reference '%s' has been deleted from '%s/%s' by %s",
|
||||
opts.RefFullName, opts.RepoUserName, opts.RepoName, opts.PusherName)
|
||||
return nil
|
||||
}
|
||||
|
||||
gitRepo, err := git.OpenRepository(repoPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("OpenRepository: %v", err)
|
||||
@@ -100,27 +96,30 @@ func PushUpdate(opts PushUpdateOptions) (err error) {
|
||||
NewCommitID: opts.NewCommitID,
|
||||
Commits: &PushCommits{},
|
||||
}); err != nil {
|
||||
return fmt.Errorf("CommitRepoAction (tag): %v", err)
|
||||
return fmt.Errorf("CommitRepoAction.(tag): %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
newCommit, err := gitRepo.GetCommit(opts.NewCommitID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("gitRepo.GetCommit: %v", err)
|
||||
}
|
||||
|
||||
// Push new branch.
|
||||
var l *list.List
|
||||
if isNewRef {
|
||||
l, err = newCommit.CommitsBeforeLimit(10)
|
||||
// Skip read parent commits when delete branch
|
||||
if !isDelRef {
|
||||
// Push new branch.
|
||||
newCommit, err := gitRepo.GetCommit(opts.NewCommitID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("newCommit.CommitsBeforeLimit: %v", err)
|
||||
return fmt.Errorf("GetCommit [commit_id: %s]: %v", opts.NewCommitID, err)
|
||||
}
|
||||
} else {
|
||||
l, err = newCommit.CommitsBeforeUntil(opts.OldCommitID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("newCommit.CommitsBeforeUntil: %v", err)
|
||||
|
||||
if isNewRef {
|
||||
l, err = newCommit.CommitsBeforeLimit(10)
|
||||
if err != nil {
|
||||
return fmt.Errorf("CommitsBeforeLimit [commit_id: %s]: %v", newCommit.ID, err)
|
||||
}
|
||||
} else {
|
||||
l, err = newCommit.CommitsBeforeUntil(opts.OldCommitID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("CommitsBeforeUntil [commit_id: %s]: %v", opts.OldCommitID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,7 +132,7 @@ func PushUpdate(opts PushUpdateOptions) (err error) {
|
||||
NewCommitID: opts.NewCommitID,
|
||||
Commits: ListToPushCommits(l),
|
||||
}); err != nil {
|
||||
return fmt.Errorf("CommitRepoAction (branch): %v", err)
|
||||
return fmt.Errorf("CommitRepoAction.(branch): %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -385,18 +385,18 @@ func (u *User) DeleteAvatar() error {
|
||||
|
||||
// IsAdminOfRepo returns true if user has admin or higher access of repository.
|
||||
func (u *User) IsAdminOfRepo(repo *Repository) bool {
|
||||
has, err := HasAccess(u, repo, ACCESS_MODE_ADMIN)
|
||||
has, err := HasAccess(u.ID, repo, ACCESS_MODE_ADMIN)
|
||||
if err != nil {
|
||||
log.Error(3, "HasAccess: %v", err)
|
||||
log.Error(2, "HasAccess: %v", err)
|
||||
}
|
||||
return has
|
||||
}
|
||||
|
||||
// IsWriterOfRepo returns true if user has write access to given repository.
|
||||
func (u *User) IsWriterOfRepo(repo *Repository) bool {
|
||||
has, err := HasAccess(u, repo, ACCESS_MODE_WRITE)
|
||||
has, err := HasAccess(u.ID, repo, ACCESS_MODE_WRITE)
|
||||
if err != nil {
|
||||
log.Error(3, "HasAccess: %v", err)
|
||||
log.Error(2, "HasAccess: %v", err)
|
||||
}
|
||||
return has
|
||||
}
|
||||
@@ -448,18 +448,15 @@ func (u *User) GetOwnedOrganizations() (err error) {
|
||||
}
|
||||
|
||||
// GetOrganizations returns all organizations that user belongs to.
|
||||
func (u *User) GetOrganizations(all bool) error {
|
||||
ous, err := GetOrgUsersByUserID(u.ID, all)
|
||||
func (u *User) GetOrganizations(showPrivate bool) error {
|
||||
orgIDs, err := GetOrgIDsByUserID(u.ID, showPrivate)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("GetOrgIDsByUserID: %v", err)
|
||||
}
|
||||
|
||||
u.Orgs = make([]*User, len(ous))
|
||||
for i, ou := range ous {
|
||||
u.Orgs[i], err = GetUserByID(ou.OrgID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
u.Orgs = make([]*User, 0, len(orgIDs))
|
||||
if err = x.In("id", orgIDs).Find(&u.Orgs); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -685,7 +682,13 @@ func ChangeUserName(u *User, newUserName string) (err error) {
|
||||
return fmt.Errorf("Delete repository wiki local copy: %v", err)
|
||||
}
|
||||
|
||||
return os.Rename(UserPath(u.Name), UserPath(newUserName))
|
||||
// Rename or create user base directory
|
||||
baseDir := UserPath(u.Name)
|
||||
newBaseDir := UserPath(newUserName)
|
||||
if com.IsExist(baseDir) {
|
||||
return os.Rename(baseDir, newBaseDir)
|
||||
}
|
||||
return os.MkdirAll(newBaseDir, os.ModePerm)
|
||||
}
|
||||
|
||||
func updateUser(e Engine, u *User) error {
|
||||
@@ -911,7 +914,7 @@ func GetUserByID(id int64) (*User, error) {
|
||||
|
||||
// GetAssigneeByID returns the user with write access of repository by given ID.
|
||||
func GetAssigneeByID(repo *Repository, userID int64) (*User, error) {
|
||||
has, err := HasAccess(&User{ID: userID}, repo, ACCESS_MODE_READ)
|
||||
has, err := HasAccess(userID, repo, ACCESS_MODE_READ)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !has {
|
||||
|
||||
@@ -5,7 +5,10 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"crypto/tls"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
@@ -60,6 +63,8 @@ func IsValidHookContentType(name string) bool {
|
||||
|
||||
type HookEvents struct {
|
||||
Create bool `json:"create"`
|
||||
Delete bool `json:"delete"`
|
||||
Fork bool `json:"fork"`
|
||||
Push bool `json:"push"`
|
||||
PullRequest bool `json:"pull_request"`
|
||||
}
|
||||
@@ -118,7 +123,7 @@ func (w *Webhook) AfterSet(colName string, _ xorm.Cell) {
|
||||
case "events":
|
||||
w.HookEvent = &HookEvent{}
|
||||
if err = json.Unmarshal([]byte(w.Events), w.HookEvent); err != nil {
|
||||
log.Error(3, "Unmarshal[%d]: %v", w.ID, err)
|
||||
log.Error(3, "Unmarshal [%d]: %v", w.ID, err)
|
||||
}
|
||||
case "created_unix":
|
||||
w.Created = time.Unix(w.CreatedUnix, 0).Local()
|
||||
@@ -130,7 +135,7 @@ func (w *Webhook) AfterSet(colName string, _ xorm.Cell) {
|
||||
func (w *Webhook) GetSlackHook() *SlackMeta {
|
||||
s := &SlackMeta{}
|
||||
if err := json.Unmarshal([]byte(w.Meta), s); err != nil {
|
||||
log.Error(4, "webhook.GetSlackHook(%d): %v", w.ID, err)
|
||||
log.Error(2, "GetSlackHook [%d]: %v", w.ID, err)
|
||||
}
|
||||
return s
|
||||
}
|
||||
@@ -153,6 +158,18 @@ func (w *Webhook) HasCreateEvent() bool {
|
||||
(w.ChooseEvents && w.HookEvents.Create)
|
||||
}
|
||||
|
||||
// HasDeleteEvent returns true if hook enabled delete event.
|
||||
func (w *Webhook) HasDeleteEvent() bool {
|
||||
return w.SendEverything ||
|
||||
(w.ChooseEvents && w.HookEvents.Delete)
|
||||
}
|
||||
|
||||
// HasForkEvent returns true if hook enabled fork event.
|
||||
func (w *Webhook) HasForkEvent() bool {
|
||||
return w.SendEverything ||
|
||||
(w.ChooseEvents && w.HookEvents.Fork)
|
||||
}
|
||||
|
||||
// HasPushEvent returns true if hook enabled push event.
|
||||
func (w *Webhook) HasPushEvent() bool {
|
||||
return w.PushOnly || w.SendEverything ||
|
||||
@@ -166,15 +183,21 @@ func (w *Webhook) HasPullRequestEvent() bool {
|
||||
}
|
||||
|
||||
func (w *Webhook) EventsArray() []string {
|
||||
events := make([]string, 0, 3)
|
||||
events := make([]string, 0, 5)
|
||||
if w.HasCreateEvent() {
|
||||
events = append(events, "create")
|
||||
events = append(events, string(HOOK_EVENT_CREATE))
|
||||
}
|
||||
if w.HasDeleteEvent() {
|
||||
events = append(events, string(HOOK_EVENT_DELETE))
|
||||
}
|
||||
if w.HasForkEvent() {
|
||||
events = append(events, string(HOOK_EVENT_FORK))
|
||||
}
|
||||
if w.HasPushEvent() {
|
||||
events = append(events, "push")
|
||||
events = append(events, string(HOOK_EVENT_PUSH))
|
||||
}
|
||||
if w.HasPullRequestEvent() {
|
||||
events = append(events, "pull_request")
|
||||
events = append(events, string(HOOK_EVENT_PULL_REQUEST))
|
||||
}
|
||||
return events
|
||||
}
|
||||
@@ -197,8 +220,17 @@ func getWebhook(bean *Webhook) (*Webhook, error) {
|
||||
return bean, nil
|
||||
}
|
||||
|
||||
// GetWebhookByRepoID returns webhook of repository by given ID.
|
||||
func GetWebhookByRepoID(repoID, id int64) (*Webhook, error) {
|
||||
// GetWebhookByID returns webhook by given ID.
|
||||
// Use this function with caution of accessing unauthorized webhook,
|
||||
// which means should only be used in non-user interactive functions.
|
||||
func GetWebhookByID(id int64) (*Webhook, error) {
|
||||
return getWebhook(&Webhook{
|
||||
ID: id,
|
||||
})
|
||||
}
|
||||
|
||||
// GetWebhookOfRepoByID returns webhook of repository by given ID.
|
||||
func GetWebhookOfRepoByID(repoID, id int64) (*Webhook, error) {
|
||||
return getWebhook(&Webhook{
|
||||
ID: id,
|
||||
RepoID: repoID,
|
||||
@@ -213,10 +245,10 @@ func GetWebhookByOrgID(orgID, id int64) (*Webhook, error) {
|
||||
})
|
||||
}
|
||||
|
||||
// GetActiveWebhooksByRepoID returns all active webhooks of repository.
|
||||
func GetActiveWebhooksByRepoID(repoID int64) ([]*Webhook, error) {
|
||||
// getActiveWebhooksByRepoID returns all active webhooks of repository.
|
||||
func getActiveWebhooksByRepoID(e Engine, repoID int64) ([]*Webhook, error) {
|
||||
webhooks := make([]*Webhook, 0, 5)
|
||||
return webhooks, x.Where("repo_id = ?", repoID).And("is_active = ?", true).Find(&webhooks)
|
||||
return webhooks, e.Where("repo_id = ?", repoID).And("is_active = ?", true).Find(&webhooks)
|
||||
}
|
||||
|
||||
// GetWebhooksByRepoID returns all webhooks of a repository.
|
||||
@@ -271,10 +303,10 @@ func GetWebhooksByOrgID(orgID int64) (ws []*Webhook, err error) {
|
||||
return ws, err
|
||||
}
|
||||
|
||||
// GetActiveWebhooksByOrgID returns all active webhooks for an organization.
|
||||
func GetActiveWebhooksByOrgID(orgID int64) (ws []*Webhook, err error) {
|
||||
err = x.Where("org_id=?", orgID).And("is_active=?", true).Find(&ws)
|
||||
return ws, err
|
||||
// getActiveWebhooksByOrgID returns all active webhooks for an organization.
|
||||
func getActiveWebhooksByOrgID(e Engine, orgID int64) ([]*Webhook, error) {
|
||||
ws := make([]*Webhook, 0, 3)
|
||||
return ws, e.Where("org_id=?", orgID).And("is_active=?", true).Find(&ws)
|
||||
}
|
||||
|
||||
// ___ ___ __ ___________ __
|
||||
@@ -293,8 +325,9 @@ const (
|
||||
)
|
||||
|
||||
var hookTaskTypes = map[string]HookTaskType{
|
||||
"gogs": GOGS,
|
||||
"slack": SLACK,
|
||||
"gogs": GOGS,
|
||||
"slack": SLACK,
|
||||
"discord": DISCORD,
|
||||
}
|
||||
|
||||
// ToHookTaskType returns HookTaskType by given name.
|
||||
@@ -308,6 +341,8 @@ func (t HookTaskType) Name() string {
|
||||
return "gogs"
|
||||
case SLACK:
|
||||
return "slack"
|
||||
case DISCORD:
|
||||
return "discord"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -322,6 +357,8 @@ type HookEventType string
|
||||
|
||||
const (
|
||||
HOOK_EVENT_CREATE HookEventType = "create"
|
||||
HOOK_EVENT_DELETE HookEventType = "delete"
|
||||
HOOK_EVENT_FORK HookEventType = "fork"
|
||||
HOOK_EVENT_PUSH HookEventType = "push"
|
||||
HOOK_EVENT_PULL_REQUEST HookEventType = "pull_request"
|
||||
)
|
||||
@@ -346,6 +383,7 @@ type HookTask struct {
|
||||
UUID string
|
||||
Type HookTaskType
|
||||
URL string `xorm:"TEXT"`
|
||||
Signature string `xorm:"TEXT"`
|
||||
api.Payloader `xorm:"-"`
|
||||
PayloadContent string `xorm:"TEXT"`
|
||||
ContentType HookContentType
|
||||
@@ -414,16 +452,16 @@ func HookTasks(hookID int64, page int) ([]*HookTask, error) {
|
||||
return tasks, x.Limit(setting.Webhook.PagingNum, (page-1)*setting.Webhook.PagingNum).Where("hook_id=?", hookID).Desc("id").Find(&tasks)
|
||||
}
|
||||
|
||||
// CreateHookTask creates a new hook task,
|
||||
// createHookTask creates a new hook task,
|
||||
// it handles conversion from Payload to PayloadContent.
|
||||
func CreateHookTask(t *HookTask) error {
|
||||
func createHookTask(e Engine, t *HookTask) error {
|
||||
data, err := t.Payloader.JSONPayload()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.UUID = gouuid.NewV4().String()
|
||||
t.PayloadContent = string(data)
|
||||
_, err = x.Insert(t)
|
||||
_, err = e.Insert(t)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -433,34 +471,23 @@ func UpdateHookTask(t *HookTask) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// PrepareWebhooks adds new webhooks to task queue for given payload.
|
||||
func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) error {
|
||||
ws, err := GetActiveWebhooksByRepoID(repo.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetActiveWebhooksByRepoID: %v", err)
|
||||
}
|
||||
|
||||
// check if repo belongs to org and append additional webhooks
|
||||
if repo.MustOwner().IsOrganization() {
|
||||
// get hooks for org
|
||||
orgws, err := GetActiveWebhooksByOrgID(repo.OwnerID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetActiveWebhooksByOrgID: %v", err)
|
||||
}
|
||||
ws = append(ws, orgws...)
|
||||
}
|
||||
|
||||
if len(ws) == 0 {
|
||||
// prepareHookTasks adds list of webhooks to task queue.
|
||||
func prepareHookTasks(e Engine, repo *Repository, event HookEventType, p api.Payloader, webhooks []*Webhook) (err error) {
|
||||
if len(webhooks) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var payloader api.Payloader
|
||||
for _, w := range ws {
|
||||
for _, w := range webhooks {
|
||||
switch event {
|
||||
case HOOK_EVENT_CREATE:
|
||||
if !w.HasCreateEvent() {
|
||||
continue
|
||||
}
|
||||
case HOOK_EVENT_DELETE:
|
||||
if !w.HasDeleteEvent() {
|
||||
continue
|
||||
}
|
||||
case HOOK_EVENT_PUSH:
|
||||
if !w.HasPushEvent() {
|
||||
continue
|
||||
@@ -484,32 +511,80 @@ func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) err
|
||||
return fmt.Errorf("GetDiscordPayload: %v", err)
|
||||
}
|
||||
default:
|
||||
p.SetSecret(w.Secret)
|
||||
payloader = p
|
||||
}
|
||||
|
||||
if err = CreateHookTask(&HookTask{
|
||||
var signature string
|
||||
if len(w.Secret) > 0 {
|
||||
data, err := payloader.JSONPayload()
|
||||
if err != nil {
|
||||
log.Error(2, "prepareWebhooks.JSONPayload: %v", err)
|
||||
}
|
||||
sig := hmac.New(sha256.New, []byte(w.Secret))
|
||||
sig.Write(data)
|
||||
signature = hex.EncodeToString(sig.Sum(nil))
|
||||
}
|
||||
|
||||
if err = createHookTask(e, &HookTask{
|
||||
RepoID: repo.ID,
|
||||
HookID: w.ID,
|
||||
Type: w.HookTaskType,
|
||||
URL: w.URL,
|
||||
Signature: signature,
|
||||
Payloader: payloader,
|
||||
ContentType: w.ContentType,
|
||||
EventType: event,
|
||||
IsSSL: w.IsSSL,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("CreateHookTask: %v", err)
|
||||
return fmt.Errorf("createHookTask: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// It's safe to fail when the whole function is called during hook execution
|
||||
// because resource released after exit.
|
||||
go HookQueue.Add(repo.ID)
|
||||
return nil
|
||||
}
|
||||
|
||||
func prepareWebhooks(e Engine, repo *Repository, event HookEventType, p api.Payloader) error {
|
||||
webhooks, err := getActiveWebhooksByRepoID(e, repo.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("getActiveWebhooksByRepoID [%d]: %v", repo.ID, err)
|
||||
}
|
||||
|
||||
// check if repo belongs to org and append additional webhooks
|
||||
if repo.mustOwner(e).IsOrganization() {
|
||||
// get hooks for org
|
||||
orgws, err := getActiveWebhooksByOrgID(e, repo.OwnerID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("getActiveWebhooksByOrgID [%d]: %v", repo.OwnerID, err)
|
||||
}
|
||||
webhooks = append(webhooks, orgws...)
|
||||
}
|
||||
return prepareHookTasks(e, repo, event, p, webhooks)
|
||||
}
|
||||
|
||||
// PrepareWebhooks adds all active webhooks to task queue.
|
||||
func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) error {
|
||||
return prepareWebhooks(x, repo, event, p)
|
||||
}
|
||||
|
||||
// TestWebhook adds the test webhook matches the ID to task queue.
|
||||
func TestWebhook(repo *Repository, event HookEventType, p api.Payloader, webhookID int64) error {
|
||||
webhook, err := GetWebhookOfRepoByID(repo.ID, webhookID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetWebhookOfRepoByID [repo_id: %d, id: %d]: %v", repo.ID, webhookID, err)
|
||||
}
|
||||
return prepareHookTasks(x, repo, event, p, []*Webhook{webhook})
|
||||
}
|
||||
|
||||
func (t *HookTask) deliver() {
|
||||
t.IsDelivered = true
|
||||
|
||||
timeout := time.Duration(setting.Webhook.DeliverTimeout) * time.Second
|
||||
req := httplib.Post(t.URL).SetTimeout(timeout, timeout).
|
||||
Header("X-Gogs-Delivery", t.UUID).
|
||||
Header("X-Gogs-Signature", t.Signature).
|
||||
Header("X-Gogs-Event", string(t.EventType)).
|
||||
SetTLSClientConfig(&tls.Config{InsecureSkipVerify: setting.Webhook.SkipTLSVerify})
|
||||
|
||||
@@ -541,9 +616,9 @@ func (t *HookTask) deliver() {
|
||||
}
|
||||
|
||||
// Update webhook last delivery status.
|
||||
w, err := GetWebhookByRepoID(t.RepoID, t.HookID)
|
||||
w, err := GetWebhookByID(t.HookID)
|
||||
if err != nil {
|
||||
log.Error(5, "GetWebhookByID: %v", err)
|
||||
log.Error(3, "GetWebhookByID: %v", err)
|
||||
return
|
||||
}
|
||||
if t.IsSucceed {
|
||||
@@ -552,7 +627,7 @@ func (t *HookTask) deliver() {
|
||||
w.LastStatus = HOOK_STATUS_FAILED
|
||||
}
|
||||
if err = UpdateWebhook(w); err != nil {
|
||||
log.Error(5, "UpdateWebhook: %v", err)
|
||||
log.Error(3, "UpdateWebhook: %v", err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -12,6 +12,8 @@ import (
|
||||
|
||||
"github.com/gogits/git-module"
|
||||
api "github.com/gogits/go-gogs-client"
|
||||
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
type DiscordEmbedFooterObject struct {
|
||||
@@ -46,8 +48,6 @@ type DiscordPayload struct {
|
||||
Embeds []*DiscordEmbedObject `json:"embeds"`
|
||||
}
|
||||
|
||||
func (p *DiscordPayload) SetSecret(_ string) {}
|
||||
|
||||
func (p *DiscordPayload) JSONPayload() ([]byte, error) {
|
||||
data, err := json.MarshalIndent(p, "", " ")
|
||||
if err != nil {
|
||||
@@ -56,6 +56,10 @@ func (p *DiscordPayload) JSONPayload() ([]byte, error) {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func DiscordTextFormatter(s string) string {
|
||||
return strings.Split(s, "\n")[0]
|
||||
}
|
||||
|
||||
func DiscordLinkFormatter(url string, text string) string {
|
||||
return fmt.Sprintf("[%s](%s)", text, url)
|
||||
}
|
||||
@@ -64,21 +68,50 @@ func DiscordSHALinkFormatter(url string, text string) string {
|
||||
return fmt.Sprintf("[`%s`](%s)", text, url)
|
||||
}
|
||||
|
||||
func getDiscordCreatePayload(p *api.CreatePayload, slack *SlackMeta) (*DiscordPayload, error) {
|
||||
// Created tag/branch
|
||||
// getDiscordCreatePayload composes Discord payload for create new branch or tag.
|
||||
func getDiscordCreatePayload(p *api.CreatePayload) (*DiscordPayload, error) {
|
||||
refName := git.RefEndName(p.Ref)
|
||||
|
||||
repoLink := DiscordLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
|
||||
refLink := DiscordLinkFormatter(p.Repo.HTMLURL+"/src/"+refName, refName)
|
||||
content := fmt.Sprintf("Created new %s: %s/%s", p.RefType, repoLink, refLink)
|
||||
|
||||
color, _ := strconv.ParseInt(strings.TrimLeft(slack.Color, "#"), 16, 32)
|
||||
return &DiscordPayload{
|
||||
Username: slack.Username,
|
||||
AvatarURL: slack.IconURL,
|
||||
Embeds: []*DiscordEmbedObject{{
|
||||
Description: content,
|
||||
Color: int(color),
|
||||
URL: setting.AppUrl + p.Sender.UserName,
|
||||
Author: &DiscordEmbedAuthorObject{
|
||||
Name: p.Sender.UserName,
|
||||
IconURL: p.Sender.AvatarUrl,
|
||||
},
|
||||
}},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// getDiscordDeletePayload composes Discord payload for delete a branch or tag.
|
||||
func getDiscordDeletePayload(p *api.DeletePayload) (*DiscordPayload, error) {
|
||||
refName := git.RefEndName(p.Ref)
|
||||
repoLink := DiscordLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
|
||||
content := fmt.Sprintf("Deleted %s: %s/%s", p.RefType, repoLink, refName)
|
||||
return &DiscordPayload{
|
||||
Embeds: []*DiscordEmbedObject{{
|
||||
Description: content,
|
||||
URL: setting.AppUrl + p.Sender.UserName,
|
||||
Author: &DiscordEmbedAuthorObject{
|
||||
Name: p.Sender.UserName,
|
||||
IconURL: p.Sender.AvatarUrl,
|
||||
},
|
||||
}},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// getDiscordForkPayload composes Discord payload for forked by a repository.
|
||||
func getDiscordForkPayload(p *api.ForkPayload) (*DiscordPayload, error) {
|
||||
baseLink := DiscordLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
|
||||
forkLink := DiscordLinkFormatter(p.Forkee.HTMLURL, p.Forkee.FullName)
|
||||
content := fmt.Sprintf("%s is forked to %s", baseLink, forkLink)
|
||||
return &DiscordPayload{
|
||||
Embeds: []*DiscordEmbedObject{{
|
||||
Description: content,
|
||||
URL: setting.AppUrl + p.Sender.UserName,
|
||||
Author: &DiscordEmbedAuthorObject{
|
||||
Name: p.Sender.UserName,
|
||||
IconURL: p.Sender.AvatarUrl,
|
||||
@@ -113,7 +146,7 @@ func getDiscordPushPayload(p *api.PushPayload, slack *SlackMeta) (*DiscordPayloa
|
||||
|
||||
// for each commit, generate attachment text
|
||||
for i, commit := range p.Commits {
|
||||
content += fmt.Sprintf("%s %s - %s", DiscordSHALinkFormatter(commit.URL, commit.ID[:7]), SlackShortTextFormatter(commit.Message), commit.Author.Name)
|
||||
content += fmt.Sprintf("%s %s - %s", DiscordSHALinkFormatter(commit.URL, commit.ID[:7]), DiscordTextFormatter(commit.Message), commit.Author.Name)
|
||||
// add linebreak to each commit but the last
|
||||
if i < len(p.Commits)-1 {
|
||||
content += "\n"
|
||||
@@ -126,6 +159,7 @@ func getDiscordPushPayload(p *api.PushPayload, slack *SlackMeta) (*DiscordPayloa
|
||||
AvatarURL: slack.IconURL,
|
||||
Embeds: []*DiscordEmbedObject{{
|
||||
Description: content,
|
||||
URL: setting.AppUrl + p.Sender.UserName,
|
||||
Color: int(color),
|
||||
Author: &DiscordEmbedAuthorObject{
|
||||
Name: p.Sender.UserName,
|
||||
@@ -200,22 +234,34 @@ func getDiscordPullRequestPayload(p *api.PullRequestPayload, slack *SlackMeta) (
|
||||
}, nil
|
||||
}
|
||||
|
||||
func GetDiscordPayload(p api.Payloader, event HookEventType, meta string) (*DiscordPayload, error) {
|
||||
d := new(DiscordPayload)
|
||||
|
||||
func GetDiscordPayload(p api.Payloader, event HookEventType, meta string) (payload *DiscordPayload, err error) {
|
||||
slack := &SlackMeta{}
|
||||
if err := json.Unmarshal([]byte(meta), &slack); err != nil {
|
||||
return d, fmt.Errorf("GetDiscordPayload meta json: %v", err)
|
||||
return nil, fmt.Errorf("json.Unmarshal: %v", err)
|
||||
}
|
||||
|
||||
switch event {
|
||||
case HOOK_EVENT_CREATE:
|
||||
return getDiscordCreatePayload(p.(*api.CreatePayload), slack)
|
||||
payload, err = getDiscordCreatePayload(p.(*api.CreatePayload))
|
||||
case HOOK_EVENT_DELETE:
|
||||
payload, err = getDiscordDeletePayload(p.(*api.DeletePayload))
|
||||
case HOOK_EVENT_FORK:
|
||||
payload, err = getDiscordForkPayload(p.(*api.ForkPayload))
|
||||
case HOOK_EVENT_PUSH:
|
||||
return getDiscordPushPayload(p.(*api.PushPayload), slack)
|
||||
payload, err = getDiscordPushPayload(p.(*api.PushPayload), slack)
|
||||
case HOOK_EVENT_PULL_REQUEST:
|
||||
return getDiscordPullRequestPayload(p.(*api.PullRequestPayload), slack)
|
||||
payload, err = getDiscordPullRequestPayload(p.(*api.PullRequestPayload), slack)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("event '%s': %v", event, err)
|
||||
}
|
||||
|
||||
return d, nil
|
||||
payload.Username = slack.Username
|
||||
payload.AvatarURL = slack.IconURL
|
||||
if len(payload.Embeds) > 0 {
|
||||
color, _ := strconv.ParseInt(strings.TrimLeft(slack.Color, "#"), 16, 32)
|
||||
payload.Embeds[0].Color = int(color)
|
||||
}
|
||||
|
||||
return payload, nil
|
||||
}
|
||||
|
||||
@@ -39,8 +39,6 @@ type SlackPayload struct {
|
||||
Attachments []*SlackAttachment `json:"attachments"`
|
||||
}
|
||||
|
||||
func (p *SlackPayload) SetSecret(_ string) {}
|
||||
|
||||
func (p *SlackPayload) JSONPayload() ([]byte, error) {
|
||||
data, err := json.MarshalIndent(p, "", " ")
|
||||
if err != nil {
|
||||
@@ -71,19 +69,34 @@ func SlackLinkFormatter(url string, text string) string {
|
||||
return fmt.Sprintf("<%s|%s>", url, SlackTextFormatter(text))
|
||||
}
|
||||
|
||||
func getSlackCreatePayload(p *api.CreatePayload, slack *SlackMeta) (*SlackPayload, error) {
|
||||
// Created tag/branch
|
||||
// getSlackCreatePayload composes Slack payload for create new branch or tag.
|
||||
func getSlackCreatePayload(p *api.CreatePayload) (*SlackPayload, error) {
|
||||
refName := git.RefEndName(p.Ref)
|
||||
|
||||
repoLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
|
||||
refLink := SlackLinkFormatter(p.Repo.HTMLURL+"/src/"+refName, refName)
|
||||
text := fmt.Sprintf("[%s:%s] %s created by %s", repoLink, refLink, p.RefType, p.Sender.UserName)
|
||||
|
||||
return &SlackPayload{
|
||||
Channel: slack.Channel,
|
||||
Text: text,
|
||||
Username: slack.Username,
|
||||
IconURL: slack.IconURL,
|
||||
Text: text,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// getSlackDeletePayload composes Slack payload for delete a branch or tag.
|
||||
func getSlackDeletePayload(p *api.DeletePayload) (*SlackPayload, error) {
|
||||
refName := git.RefEndName(p.Ref)
|
||||
repoLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
|
||||
text := fmt.Sprintf("[%s:%s] %s deleted by %s", repoLink, refName, p.RefType, p.Sender.UserName)
|
||||
return &SlackPayload{
|
||||
Text: text,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// getSlackForkPayload composes Slack payload for forked by a repository.
|
||||
func getSlackForkPayload(p *api.ForkPayload) (*SlackPayload, error) {
|
||||
baseLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
|
||||
forkLink := SlackLinkFormatter(p.Forkee.HTMLURL, p.Forkee.FullName)
|
||||
text := fmt.Sprintf("%s is forked to %s", baseLink, forkLink)
|
||||
return &SlackPayload{
|
||||
Text: text,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -180,22 +193,34 @@ func getSlackPullRequestPayload(p *api.PullRequestPayload, slack *SlackMeta) (*S
|
||||
}, nil
|
||||
}
|
||||
|
||||
func GetSlackPayload(p api.Payloader, event HookEventType, meta string) (*SlackPayload, error) {
|
||||
s := new(SlackPayload)
|
||||
|
||||
func GetSlackPayload(p api.Payloader, event HookEventType, meta string) (payload *SlackPayload, err error) {
|
||||
slack := &SlackMeta{}
|
||||
if err := json.Unmarshal([]byte(meta), &slack); err != nil {
|
||||
return s, fmt.Errorf("GetSlackPayload meta json: %v", err)
|
||||
return nil, fmt.Errorf("json.Unmarshal: %v", err)
|
||||
}
|
||||
|
||||
switch event {
|
||||
case HOOK_EVENT_CREATE:
|
||||
return getSlackCreatePayload(p.(*api.CreatePayload), slack)
|
||||
payload, err = getSlackCreatePayload(p.(*api.CreatePayload))
|
||||
case HOOK_EVENT_DELETE:
|
||||
payload, err = getSlackDeletePayload(p.(*api.DeletePayload))
|
||||
case HOOK_EVENT_FORK:
|
||||
payload, err = getSlackForkPayload(p.(*api.ForkPayload))
|
||||
case HOOK_EVENT_PUSH:
|
||||
return getSlackPushPayload(p.(*api.PushPayload), slack)
|
||||
payload, err = getSlackPushPayload(p.(*api.PushPayload), slack)
|
||||
case HOOK_EVENT_PULL_REQUEST:
|
||||
return getSlackPullRequestPayload(p.(*api.PullRequestPayload), slack)
|
||||
payload, err = getSlackPullRequestPayload(p.(*api.PullRequestPayload), slack)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("event '%s': %v", event, err)
|
||||
}
|
||||
|
||||
return s, nil
|
||||
payload.Channel = slack.Channel
|
||||
payload.Username = slack.Username
|
||||
payload.IconURL = slack.IconURL
|
||||
if len(payload.Attachments) > 0 {
|
||||
payload.Attachments[0].Color = slack.Color
|
||||
}
|
||||
|
||||
return payload, nil
|
||||
}
|
||||
|
||||
@@ -5,12 +5,9 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/go-macaron/binding"
|
||||
"github.com/go-macaron/session"
|
||||
gouuid "github.com/satori/go.uuid"
|
||||
log "gopkg.in/clog.v1"
|
||||
@@ -147,130 +144,3 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (*models.User, bool)
|
||||
}
|
||||
return u, false
|
||||
}
|
||||
|
||||
type Form interface {
|
||||
binding.Validator
|
||||
}
|
||||
|
||||
func init() {
|
||||
binding.SetNameMapper(com.ToSnakeCase)
|
||||
}
|
||||
|
||||
// AssignForm assign form values back to the template data.
|
||||
func AssignForm(form interface{}, data map[string]interface{}) {
|
||||
typ := reflect.TypeOf(form)
|
||||
val := reflect.ValueOf(form)
|
||||
|
||||
if typ.Kind() == reflect.Ptr {
|
||||
typ = typ.Elem()
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
for i := 0; i < typ.NumField(); i++ {
|
||||
field := typ.Field(i)
|
||||
|
||||
fieldName := field.Tag.Get("form")
|
||||
// Allow ignored fields in the struct
|
||||
if fieldName == "-" {
|
||||
continue
|
||||
} else if len(fieldName) == 0 {
|
||||
fieldName = com.ToSnakeCase(field.Name)
|
||||
}
|
||||
|
||||
data[fieldName] = val.Field(i).Interface()
|
||||
}
|
||||
}
|
||||
|
||||
func getRuleBody(field reflect.StructField, prefix string) string {
|
||||
for _, rule := range strings.Split(field.Tag.Get("binding"), ";") {
|
||||
if strings.HasPrefix(rule, prefix) {
|
||||
return rule[len(prefix) : len(rule)-1]
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func GetSize(field reflect.StructField) string {
|
||||
return getRuleBody(field, "Size(")
|
||||
}
|
||||
|
||||
func GetMinSize(field reflect.StructField) string {
|
||||
return getRuleBody(field, "MinSize(")
|
||||
}
|
||||
|
||||
func GetMaxSize(field reflect.StructField) string {
|
||||
return getRuleBody(field, "MaxSize(")
|
||||
}
|
||||
|
||||
func GetInclude(field reflect.StructField) string {
|
||||
return getRuleBody(field, "Include(")
|
||||
}
|
||||
|
||||
// FIXME: struct contains a struct
|
||||
func validateStruct(obj interface{}) binding.Errors {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func validate(errs binding.Errors, data map[string]interface{}, f Form, l macaron.Locale) binding.Errors {
|
||||
if errs.Len() == 0 {
|
||||
return errs
|
||||
}
|
||||
|
||||
data["HasError"] = true
|
||||
AssignForm(f, data)
|
||||
|
||||
typ := reflect.TypeOf(f)
|
||||
val := reflect.ValueOf(f)
|
||||
|
||||
if typ.Kind() == reflect.Ptr {
|
||||
typ = typ.Elem()
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
for i := 0; i < typ.NumField(); i++ {
|
||||
field := typ.Field(i)
|
||||
|
||||
fieldName := field.Tag.Get("form")
|
||||
// Allow ignored fields in the struct
|
||||
if fieldName == "-" {
|
||||
continue
|
||||
}
|
||||
|
||||
if errs[0].FieldNames[0] == field.Name {
|
||||
data["Err_"+field.Name] = true
|
||||
|
||||
trName := field.Tag.Get("locale")
|
||||
if len(trName) == 0 {
|
||||
trName = l.Tr("form." + field.Name)
|
||||
} else {
|
||||
trName = l.Tr(trName)
|
||||
}
|
||||
|
||||
switch errs[0].Classification {
|
||||
case binding.ERR_REQUIRED:
|
||||
data["ErrorMsg"] = trName + l.Tr("form.require_error")
|
||||
case binding.ERR_ALPHA_DASH:
|
||||
data["ErrorMsg"] = trName + l.Tr("form.alpha_dash_error")
|
||||
case binding.ERR_ALPHA_DASH_DOT:
|
||||
data["ErrorMsg"] = trName + l.Tr("form.alpha_dash_dot_error")
|
||||
case binding.ERR_SIZE:
|
||||
data["ErrorMsg"] = trName + l.Tr("form.size_error", GetSize(field))
|
||||
case binding.ERR_MIN_SIZE:
|
||||
data["ErrorMsg"] = trName + l.Tr("form.min_size_error", GetMinSize(field))
|
||||
case binding.ERR_MAX_SIZE:
|
||||
data["ErrorMsg"] = trName + l.Tr("form.max_size_error", GetMaxSize(field))
|
||||
case binding.ERR_EMAIL:
|
||||
data["ErrorMsg"] = trName + l.Tr("form.email_error")
|
||||
case binding.ERR_URL:
|
||||
data["ErrorMsg"] = trName + l.Tr("form.url_error")
|
||||
case binding.ERR_INCLUDE:
|
||||
data["ErrorMsg"] = trName + l.Tr("form.include_error", GetInclude(field))
|
||||
default:
|
||||
data["ErrorMsg"] = l.Tr("form.unknown_error") + " " + errs[0].Classification
|
||||
}
|
||||
return errs
|
||||
}
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"github.com/go-macaron/binding"
|
||||
"gopkg.in/macaron.v1"
|
||||
)
|
||||
|
||||
// ________ .__ __ .__
|
||||
// \_____ \_______ _________ ____ |__|____________ _/ |_|__| ____ ____
|
||||
// / | \_ __ \/ ___\__ \ / \| \___ /\__ \\ __\ |/ _ \ / \
|
||||
// / | \ | \/ /_/ > __ \| | \ |/ / / __ \| | | ( <_> ) | \
|
||||
// \_______ /__| \___ (____ /___| /__/_____ \(____ /__| |__|\____/|___| /
|
||||
// \/ /_____/ \/ \/ \/ \/ \/
|
||||
|
||||
type CreateOrgForm struct {
|
||||
OrgName string `binding:"Required;AlphaDashDot;MaxSize(35)" locale:"org.org_name_holder"`
|
||||
}
|
||||
|
||||
func (f *CreateOrgForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
type UpdateOrgSettingForm struct {
|
||||
Name string `binding:"Required;AlphaDashDot;MaxSize(35)" locale:"org.org_name_holder"`
|
||||
FullName string `binding:"MaxSize(100)"`
|
||||
Description string `binding:"MaxSize(255)"`
|
||||
Website string `binding:"Url;MaxSize(100)"`
|
||||
Location string `binding:"MaxSize(50)"`
|
||||
MaxRepoCreation int
|
||||
}
|
||||
|
||||
func (f *UpdateOrgSettingForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
// ___________
|
||||
// \__ ___/___ _____ _____
|
||||
// | |_/ __ \\__ \ / \
|
||||
// | |\ ___/ / __ \| Y Y \
|
||||
// |____| \___ >____ /__|_| /
|
||||
// \/ \/ \/
|
||||
|
||||
type CreateTeamForm struct {
|
||||
TeamName string `binding:"Required;AlphaDashDot;MaxSize(30)"`
|
||||
Description string `binding:"MaxSize(255)"`
|
||||
Permission string
|
||||
}
|
||||
|
||||
func (f *CreateTeamForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
@@ -186,7 +186,7 @@ func AvatarLink(email string) (url string) {
|
||||
var err error
|
||||
url, err = setting.LibravatarService.FromEmail(email)
|
||||
if err != nil {
|
||||
log.Error(2, "LibravatarService.FromEmail [%s]: %v", email, err)
|
||||
log.Warn("AvatarLink.LibravatarService.FromEmail [%s]: %v", email, err)
|
||||
}
|
||||
}
|
||||
if len(url) == 0 && !setting.DisableGravatar {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -22,6 +22,7 @@ import (
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/auth"
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/form"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
@@ -78,9 +79,9 @@ func (ctx *Context) HTML(status int, name base.TplName) {
|
||||
}
|
||||
|
||||
// RenderWithErr used for page has form validation but need to prompt error to users.
|
||||
func (ctx *Context) RenderWithErr(msg string, tpl base.TplName, form interface{}) {
|
||||
if form != nil {
|
||||
auth.AssignForm(form, ctx.Data)
|
||||
func (ctx *Context) RenderWithErr(msg string, tpl base.TplName, f interface{}) {
|
||||
if f != nil {
|
||||
form.Assign(f, ctx.Data)
|
||||
}
|
||||
ctx.Flash.ErrorMsg = msg
|
||||
ctx.Data["Flash"] = ctx.Flash
|
||||
|
||||
@@ -98,6 +98,16 @@ func (r *Repository) GetEditorconfig() (*editorconfig.Editorconfig, error) {
|
||||
return editorconfig.ParseBytes(data)
|
||||
}
|
||||
|
||||
// PullRequestURL returns URL for composing a pull request.
|
||||
// This function does not check if the repository can actually compose a pull request.
|
||||
func (r *Repository) PullRequestURL(baseBranch, headBranch string) string {
|
||||
repoLink := r.RepoLink
|
||||
if r.PullRequest.BaseRepo != nil {
|
||||
repoLink = r.PullRequest.BaseRepo.Link()
|
||||
}
|
||||
return fmt.Sprintf("%s/compare/%s...%s:%s", repoLink, baseBranch, r.Owner.Name, headBranch)
|
||||
}
|
||||
|
||||
func RetrieveBaseRepo(ctx *Context, repo *models.Repository) {
|
||||
// Non-fork repository will not return error in this method.
|
||||
if err := repo.GetBaseRepo(); err != nil {
|
||||
@@ -196,7 +206,11 @@ func RepoAssignment(args ...bool) macaron.Handler {
|
||||
if ctx.IsSigned && ctx.User.IsAdmin {
|
||||
ctx.Repo.AccessMode = models.ACCESS_MODE_OWNER
|
||||
} else {
|
||||
mode, err := models.AccessLevel(ctx.User, repo)
|
||||
var userID int64
|
||||
if ctx.IsSigned {
|
||||
userID = ctx.User.ID
|
||||
}
|
||||
mode, err := models.AccessLevel(userID, repo)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "AccessLevel", err)
|
||||
return
|
||||
|
||||
@@ -2,15 +2,14 @@
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package auth
|
||||
package form
|
||||
|
||||
import (
|
||||
"gopkg.in/macaron.v1"
|
||||
|
||||
"github.com/go-macaron/binding"
|
||||
"gopkg.in/macaron.v1"
|
||||
)
|
||||
|
||||
type AdminCrateUserForm struct {
|
||||
type AdminCrateUser struct {
|
||||
LoginType string `binding:"Required"`
|
||||
LoginName string
|
||||
UserName string `binding:"Required;AlphaDashDot;MaxSize(35)"`
|
||||
@@ -19,11 +18,11 @@ type AdminCrateUserForm struct {
|
||||
SendNotify bool
|
||||
}
|
||||
|
||||
func (f *AdminCrateUserForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *AdminCrateUser) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
type AdminEditUserForm struct {
|
||||
type AdminEditUser struct {
|
||||
LoginType string `binding:"Required"`
|
||||
LoginName string
|
||||
FullName string `binding:"MaxSize(100)"`
|
||||
@@ -39,6 +38,6 @@ type AdminEditUserForm struct {
|
||||
ProhibitLogin bool
|
||||
}
|
||||
|
||||
func (f *AdminEditUserForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *AdminEditUser) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
@@ -2,14 +2,14 @@
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package auth
|
||||
package form
|
||||
|
||||
import (
|
||||
"github.com/go-macaron/binding"
|
||||
"gopkg.in/macaron.v1"
|
||||
)
|
||||
|
||||
type AuthenticationForm struct {
|
||||
type Authentication struct {
|
||||
ID int64
|
||||
Type int `binding:"Range(2,5)"`
|
||||
Name string `binding:"Required;MaxSize(30)"`
|
||||
@@ -37,6 +37,6 @@ type AuthenticationForm struct {
|
||||
PAMServiceName string
|
||||
}
|
||||
|
||||
func (f *AuthenticationForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *Authentication) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
155
modules/form/form.go
Normal file
155
modules/form/form.go
Normal file
@@ -0,0 +1,155 @@
|
||||
// Copyright 2017 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 form
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/go-macaron/binding"
|
||||
"gopkg.in/macaron.v1"
|
||||
)
|
||||
|
||||
const ERR_ALPHA_DASH_DOT_SLASH = "AlphaDashDotSlashError"
|
||||
|
||||
var AlphaDashDotSlashPattern = regexp.MustCompile("[^\\d\\w-_\\./]")
|
||||
|
||||
func init() {
|
||||
binding.SetNameMapper(com.ToSnakeCase)
|
||||
binding.AddRule(&binding.Rule{
|
||||
IsMatch: func(rule string) bool {
|
||||
return rule == "AlphaDashDotSlash"
|
||||
},
|
||||
IsValid: func(errs binding.Errors, name string, v interface{}) (bool, binding.Errors) {
|
||||
if AlphaDashDotSlashPattern.MatchString(fmt.Sprintf("%v", v)) {
|
||||
errs.Add([]string{name}, ERR_ALPHA_DASH_DOT_SLASH, "AlphaDashDotSlash")
|
||||
return false, errs
|
||||
}
|
||||
return true, errs
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
type Form interface {
|
||||
binding.Validator
|
||||
}
|
||||
|
||||
// Assign assign form values back to the template data.
|
||||
func Assign(form interface{}, data map[string]interface{}) {
|
||||
typ := reflect.TypeOf(form)
|
||||
val := reflect.ValueOf(form)
|
||||
|
||||
if typ.Kind() == reflect.Ptr {
|
||||
typ = typ.Elem()
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
for i := 0; i < typ.NumField(); i++ {
|
||||
field := typ.Field(i)
|
||||
|
||||
fieldName := field.Tag.Get("form")
|
||||
// Allow ignored fields in the struct
|
||||
if fieldName == "-" {
|
||||
continue
|
||||
} else if len(fieldName) == 0 {
|
||||
fieldName = com.ToSnakeCase(field.Name)
|
||||
}
|
||||
|
||||
data[fieldName] = val.Field(i).Interface()
|
||||
}
|
||||
}
|
||||
|
||||
func getRuleBody(field reflect.StructField, prefix string) string {
|
||||
for _, rule := range strings.Split(field.Tag.Get("binding"), ";") {
|
||||
if strings.HasPrefix(rule, prefix) {
|
||||
return rule[len(prefix) : len(rule)-1]
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getSize(field reflect.StructField) string {
|
||||
return getRuleBody(field, "Size(")
|
||||
}
|
||||
|
||||
func getMinSize(field reflect.StructField) string {
|
||||
return getRuleBody(field, "MinSize(")
|
||||
}
|
||||
|
||||
func getMaxSize(field reflect.StructField) string {
|
||||
return getRuleBody(field, "MaxSize(")
|
||||
}
|
||||
|
||||
func getInclude(field reflect.StructField) string {
|
||||
return getRuleBody(field, "Include(")
|
||||
}
|
||||
|
||||
func validate(errs binding.Errors, data map[string]interface{}, f Form, l macaron.Locale) binding.Errors {
|
||||
if errs.Len() == 0 {
|
||||
return errs
|
||||
}
|
||||
|
||||
data["HasError"] = true
|
||||
Assign(f, data)
|
||||
|
||||
typ := reflect.TypeOf(f)
|
||||
val := reflect.ValueOf(f)
|
||||
|
||||
if typ.Kind() == reflect.Ptr {
|
||||
typ = typ.Elem()
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
for i := 0; i < typ.NumField(); i++ {
|
||||
field := typ.Field(i)
|
||||
|
||||
fieldName := field.Tag.Get("form")
|
||||
// Allow ignored fields in the struct
|
||||
if fieldName == "-" {
|
||||
continue
|
||||
}
|
||||
|
||||
if errs[0].FieldNames[0] == field.Name {
|
||||
data["Err_"+field.Name] = true
|
||||
|
||||
trName := field.Tag.Get("locale")
|
||||
if len(trName) == 0 {
|
||||
trName = l.Tr("form." + field.Name)
|
||||
} else {
|
||||
trName = l.Tr(trName)
|
||||
}
|
||||
|
||||
switch errs[0].Classification {
|
||||
case binding.ERR_REQUIRED:
|
||||
data["ErrorMsg"] = trName + l.Tr("form.require_error")
|
||||
case binding.ERR_ALPHA_DASH:
|
||||
data["ErrorMsg"] = trName + l.Tr("form.alpha_dash_error")
|
||||
case binding.ERR_ALPHA_DASH_DOT:
|
||||
data["ErrorMsg"] = trName + l.Tr("form.alpha_dash_dot_error")
|
||||
case ERR_ALPHA_DASH_DOT_SLASH:
|
||||
data["ErrorMsg"] = trName + l.Tr("form.alpha_dash_dot_slash_error")
|
||||
case binding.ERR_SIZE:
|
||||
data["ErrorMsg"] = trName + l.Tr("form.size_error", getSize(field))
|
||||
case binding.ERR_MIN_SIZE:
|
||||
data["ErrorMsg"] = trName + l.Tr("form.min_size_error", getMinSize(field))
|
||||
case binding.ERR_MAX_SIZE:
|
||||
data["ErrorMsg"] = trName + l.Tr("form.max_size_error", getMaxSize(field))
|
||||
case binding.ERR_EMAIL:
|
||||
data["ErrorMsg"] = trName + l.Tr("form.email_error")
|
||||
case binding.ERR_URL:
|
||||
data["ErrorMsg"] = trName + l.Tr("form.url_error")
|
||||
case binding.ERR_INCLUDE:
|
||||
data["ErrorMsg"] = trName + l.Tr("form.include_error", getInclude(field))
|
||||
default:
|
||||
data["ErrorMsg"] = l.Tr("form.unknown_error") + " " + errs[0].Classification
|
||||
}
|
||||
return errs
|
||||
}
|
||||
}
|
||||
return errs
|
||||
}
|
||||
41
modules/form/org.go
Normal file
41
modules/form/org.go
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package form
|
||||
|
||||
import (
|
||||
"github.com/go-macaron/binding"
|
||||
"gopkg.in/macaron.v1"
|
||||
)
|
||||
|
||||
type CreateOrg struct {
|
||||
OrgName string `binding:"Required;AlphaDashDot;MaxSize(35)" locale:"org.org_name_holder"`
|
||||
}
|
||||
|
||||
func (f *CreateOrg) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
type UpdateOrgSetting struct {
|
||||
Name string `binding:"Required;AlphaDashDot;MaxSize(35)" locale:"org.org_name_holder"`
|
||||
FullName string `binding:"MaxSize(100)"`
|
||||
Description string `binding:"MaxSize(255)"`
|
||||
Website string `binding:"Url;MaxSize(100)"`
|
||||
Location string `binding:"MaxSize(50)"`
|
||||
MaxRepoCreation int
|
||||
}
|
||||
|
||||
func (f *UpdateOrgSetting) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
type CreateTeam struct {
|
||||
TeamName string `binding:"Required;AlphaDashDot;MaxSize(30)"`
|
||||
Description string `binding:"MaxSize(255)"`
|
||||
Permission string
|
||||
}
|
||||
|
||||
func (f *CreateTeam) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package auth
|
||||
package form
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
@@ -22,8 +22,8 @@ import (
|
||||
// |____|_ /_______ / |____| \_______ /_______ /|___| |____| \_______ /____|_ // ______|
|
||||
// \/ \/ \/ \/ \/ \/ \/
|
||||
|
||||
type CreateRepoForm struct {
|
||||
Uid int64 `binding:"Required"`
|
||||
type CreateRepo struct {
|
||||
UserID int64 `binding:"Required"`
|
||||
RepoName string `binding:"Required;AlphaDashDot;MaxSize(100)"`
|
||||
Private bool
|
||||
Description string `binding:"MaxSize(255)"`
|
||||
@@ -33,11 +33,11 @@ type CreateRepoForm struct {
|
||||
Readme string
|
||||
}
|
||||
|
||||
func (f *CreateRepoForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *CreateRepo) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
type MigrateRepoForm struct {
|
||||
type MigrateRepo struct {
|
||||
CloneAddr string `json:"clone_addr" binding:"Required"`
|
||||
AuthUsername string `json:"auth_username"`
|
||||
AuthPassword string `json:"auth_password"`
|
||||
@@ -48,7 +48,7 @@ type MigrateRepoForm struct {
|
||||
Description string `json:"description" binding:"MaxSize(255)"`
|
||||
}
|
||||
|
||||
func (f *MigrateRepoForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *MigrateRepo) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ func (f *MigrateRepoForm) Validate(ctx *macaron.Context, errs binding.Errors) bi
|
||||
// and returns composed URL with needed username and password.
|
||||
// It also checks if given user has permission when remote address
|
||||
// is actually a local path.
|
||||
func (f MigrateRepoForm) ParseRemoteAddr(user *models.User) (string, error) {
|
||||
func (f MigrateRepo) ParseRemoteAddr(user *models.User) (string, error) {
|
||||
remoteAddr := strings.TrimSpace(f.CloneAddr)
|
||||
|
||||
// Remote address can be HTTP/HTTPS/Git URL or local path.
|
||||
@@ -80,7 +80,7 @@ func (f MigrateRepoForm) ParseRemoteAddr(user *models.User) (string, error) {
|
||||
return remoteAddr, nil
|
||||
}
|
||||
|
||||
type RepoSettingForm struct {
|
||||
type RepoSetting struct {
|
||||
RepoName string `binding:"Required;AlphaDashDot;MaxSize(100)"`
|
||||
Description string `binding:"MaxSize(255)"`
|
||||
Website string `binding:"Url;MaxSize(100)"`
|
||||
@@ -102,7 +102,7 @@ type RepoSettingForm struct {
|
||||
EnablePulls bool
|
||||
}
|
||||
|
||||
func (f *RepoSettingForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *RepoSetting) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
@@ -113,12 +113,15 @@ func (f *RepoSettingForm) Validate(ctx *macaron.Context, errs binding.Errors) bi
|
||||
// |______ / |__| (____ /___| /\___ >___| /
|
||||
// \/ \/ \/ \/ \/
|
||||
|
||||
type ProtectBranchForm struct {
|
||||
type ProtectBranch struct {
|
||||
Protected bool
|
||||
RequirePullRequest bool
|
||||
EnableWhitelist bool
|
||||
WhitelistUsers string
|
||||
WhitelistTeams string
|
||||
}
|
||||
|
||||
func (f *ProtectBranchForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *ProtectBranch) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
@@ -129,59 +132,61 @@ func (f *ProtectBranchForm) Validate(ctx *macaron.Context, errs binding.Errors)
|
||||
// \__/\ / \___ >___ /___| /___| /\____/|__|_ \
|
||||
// \/ \/ \/ \/ \/ \/
|
||||
|
||||
type WebhookForm struct {
|
||||
type Webhook struct {
|
||||
Events string
|
||||
Create bool
|
||||
Delete bool
|
||||
Fork bool
|
||||
Push bool
|
||||
PullRequest bool
|
||||
Active bool
|
||||
}
|
||||
|
||||
func (f WebhookForm) PushOnly() bool {
|
||||
func (f Webhook) PushOnly() bool {
|
||||
return f.Events == "push_only"
|
||||
}
|
||||
|
||||
func (f WebhookForm) SendEverything() bool {
|
||||
func (f Webhook) SendEverything() bool {
|
||||
return f.Events == "send_everything"
|
||||
}
|
||||
|
||||
func (f WebhookForm) ChooseEvents() bool {
|
||||
func (f Webhook) ChooseEvents() bool {
|
||||
return f.Events == "choose_events"
|
||||
}
|
||||
|
||||
type NewWebhookForm struct {
|
||||
type NewWebhook struct {
|
||||
PayloadURL string `binding:"Required;Url"`
|
||||
ContentType int `binding:"Required"`
|
||||
Secret string
|
||||
WebhookForm
|
||||
Webhook
|
||||
}
|
||||
|
||||
func (f *NewWebhookForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *NewWebhook) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
type NewSlackHookForm struct {
|
||||
type NewSlackHook struct {
|
||||
PayloadURL string `binding:"Required;Url"`
|
||||
Channel string `binding:"Required"`
|
||||
Username string
|
||||
IconURL string
|
||||
Color string
|
||||
WebhookForm
|
||||
Webhook
|
||||
}
|
||||
|
||||
func (f *NewSlackHookForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *NewSlackHook) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
type NewDiscordHookForm struct {
|
||||
type NewDiscordHook struct {
|
||||
PayloadURL string `binding:"Required;Url"`
|
||||
Username string
|
||||
IconURL string
|
||||
Color string
|
||||
WebhookForm
|
||||
Webhook
|
||||
}
|
||||
|
||||
func (f *NewDiscordHookForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *NewDiscordHook) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
@@ -192,7 +197,7 @@ func (f *NewDiscordHookForm) Validate(ctx *macaron.Context, errs binding.Errors)
|
||||
// |___/____ >____ >____/ \___ >
|
||||
// \/ \/ \/
|
||||
|
||||
type CreateIssueForm struct {
|
||||
type CreateIssue struct {
|
||||
Title string `binding:"Required;MaxSize(255)"`
|
||||
LabelIDs string `form:"label_ids"`
|
||||
MilestoneID int64
|
||||
@@ -201,17 +206,17 @@ type CreateIssueForm struct {
|
||||
Files []string
|
||||
}
|
||||
|
||||
func (f *CreateIssueForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *CreateIssue) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
type CreateCommentForm struct {
|
||||
type CreateComment struct {
|
||||
Content string
|
||||
Status string `binding:"OmitEmpty;In(reopen,close)"`
|
||||
Files []string
|
||||
}
|
||||
|
||||
func (f *CreateCommentForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *CreateComment) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
@@ -222,13 +227,13 @@ func (f *CreateCommentForm) Validate(ctx *macaron.Context, errs binding.Errors)
|
||||
// \____|__ /__|____/\___ >____ > |__| \____/|___| /\___ >
|
||||
// \/ \/ \/ \/ \/
|
||||
|
||||
type CreateMilestoneForm struct {
|
||||
type CreateMilestone struct {
|
||||
Title string `binding:"Required;MaxSize(50)"`
|
||||
Content string
|
||||
Deadline string
|
||||
}
|
||||
|
||||
func (f *CreateMilestoneForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *CreateMilestone) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
@@ -239,21 +244,21 @@ func (f *CreateMilestoneForm) Validate(ctx *macaron.Context, errs binding.Errors
|
||||
// |_______ (____ /___ /\___ >____/
|
||||
// \/ \/ \/ \/
|
||||
|
||||
type CreateLabelForm struct {
|
||||
type CreateLabel struct {
|
||||
ID int64
|
||||
Title string `binding:"Required;MaxSize(50)" locale:"repo.issues.label_name"`
|
||||
Color string `binding:"Required;Size(7)" locale:"repo.issues.label_color"`
|
||||
}
|
||||
|
||||
func (f *CreateLabelForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *CreateLabel) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
type InitializeLabelsForm struct {
|
||||
type InitializeLabels struct {
|
||||
TemplateName string `binding:"Required"`
|
||||
}
|
||||
|
||||
func (f *InitializeLabelsForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *InitializeLabels) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
@@ -264,7 +269,7 @@ func (f *InitializeLabelsForm) Validate(ctx *macaron.Context, errs binding.Error
|
||||
// |____|_ /\___ >____/\___ >____ /____ >\___ >
|
||||
// \/ \/ \/ \/ \/ \/
|
||||
|
||||
type NewReleaseForm struct {
|
||||
type NewRelease struct {
|
||||
TagName string `binding:"Required"`
|
||||
Target string `form:"tag_target" binding:"Required"`
|
||||
Title string `binding:"Required"`
|
||||
@@ -273,18 +278,18 @@ type NewReleaseForm struct {
|
||||
Prerelease bool
|
||||
}
|
||||
|
||||
func (f *NewReleaseForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *NewRelease) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
type EditReleaseForm struct {
|
||||
Title string `form:"title" binding:"Required"`
|
||||
Content string `form:"content"`
|
||||
Draft string `form:"draft"`
|
||||
Prerelease bool `form:"prerelease"`
|
||||
type EditRelease struct {
|
||||
Title string `binding:"Required"`
|
||||
Content string
|
||||
Draft string
|
||||
Prerelease bool
|
||||
}
|
||||
|
||||
func (f *EditReleaseForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *EditRelease) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
@@ -295,7 +300,7 @@ func (f *EditReleaseForm) Validate(ctx *macaron.Context, errs binding.Errors) bi
|
||||
// \__/\ / |__|__|_ \__|
|
||||
// \/ \/
|
||||
|
||||
type NewWikiForm struct {
|
||||
type NewWiki struct {
|
||||
OldTitle string
|
||||
Title string `binding:"Required"`
|
||||
Content string `binding:"Required"`
|
||||
@@ -303,7 +308,7 @@ type NewWikiForm struct {
|
||||
}
|
||||
|
||||
// FIXME: use code generation to generate this method.
|
||||
func (f *NewWikiForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *NewWiki) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
@@ -314,29 +319,29 @@ func (f *NewWikiForm) Validate(ctx *macaron.Context, errs binding.Errors) bindin
|
||||
// /_______ /\____ | |__||__|
|
||||
// \/ \/
|
||||
|
||||
type EditRepoFileForm struct {
|
||||
type EditRepoFile struct {
|
||||
TreePath string `binding:"Required;MaxSize(500)"`
|
||||
Content string `binding:"Required"`
|
||||
CommitSummary string `binding:"MaxSize(100)`
|
||||
CommitMessage string
|
||||
CommitChoice string `binding:"Required;MaxSize(50)"`
|
||||
NewBranchName string `binding:"AlphaDashDot;MaxSize(100)"`
|
||||
NewBranchName string `binding:"AlphaDashDotSlash;MaxSize(100)"`
|
||||
LastCommit string
|
||||
}
|
||||
|
||||
func (f *EditRepoFileForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *EditRepoFile) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
func (f *EditRepoFileForm) IsNewBrnach() bool {
|
||||
func (f *EditRepoFile) IsNewBrnach() bool {
|
||||
return f.CommitChoice == "commit-to-new-branch"
|
||||
}
|
||||
|
||||
type EditPreviewDiffForm struct {
|
||||
type EditPreviewDiff struct {
|
||||
Content string
|
||||
}
|
||||
|
||||
func (f *EditPreviewDiffForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *EditPreviewDiff) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
@@ -348,7 +353,7 @@ func (f *EditPreviewDiffForm) Validate(ctx *macaron.Context, errs binding.Errors
|
||||
// |__| \/ \/
|
||||
//
|
||||
|
||||
type UploadRepoFileForm struct {
|
||||
type UploadRepoFile struct {
|
||||
TreePath string `binding:MaxSize(500)"`
|
||||
CommitSummary string `binding:"MaxSize(100)`
|
||||
CommitMessage string
|
||||
@@ -357,19 +362,19 @@ type UploadRepoFileForm struct {
|
||||
Files []string
|
||||
}
|
||||
|
||||
func (f *UploadRepoFileForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *UploadRepoFile) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
func (f *UploadRepoFileForm) IsNewBrnach() bool {
|
||||
func (f *UploadRepoFile) IsNewBrnach() bool {
|
||||
return f.CommitChoice == "commit-to-new-branch"
|
||||
}
|
||||
|
||||
type RemoveUploadFileForm struct {
|
||||
type RemoveUploadFile struct {
|
||||
File string `binding:"Required;MaxSize(50)"`
|
||||
}
|
||||
|
||||
func (f *RemoveUploadFileForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *RemoveUploadFile) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
@@ -380,17 +385,17 @@ func (f *RemoveUploadFileForm) Validate(ctx *macaron.Context, errs binding.Error
|
||||
// /_______ /\___ >____/\___ >__| \___ >
|
||||
// \/ \/ \/ \/
|
||||
|
||||
type DeleteRepoFileForm struct {
|
||||
type DeleteRepoFile struct {
|
||||
CommitSummary string `binding:"MaxSize(100)`
|
||||
CommitMessage string
|
||||
CommitChoice string `binding:"Required;MaxSize(50)"`
|
||||
NewBranchName string `binding:"AlphaDashDot;MaxSize(100)"`
|
||||
}
|
||||
|
||||
func (f *DeleteRepoFileForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *DeleteRepoFile) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
func (f *DeleteRepoFileForm) IsNewBrnach() bool {
|
||||
func (f *DeleteRepoFile) IsNewBrnach() bool {
|
||||
return f.CommitChoice == "commit-to-new-branch"
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package auth
|
||||
package form
|
||||
|
||||
import (
|
||||
"mime/multipart"
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"gopkg.in/macaron.v1"
|
||||
)
|
||||
|
||||
type InstallForm struct {
|
||||
type Install struct {
|
||||
DbType string `binding:"Required"`
|
||||
DbHost string
|
||||
DbUser string
|
||||
@@ -50,7 +50,7 @@ type InstallForm struct {
|
||||
AdminEmail string `binding:"OmitEmpty;MinSize(3);MaxSize(254);Include(@)" locale:"install.admin_email"`
|
||||
}
|
||||
|
||||
func (f *InstallForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *Install) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
@@ -61,24 +61,24 @@ func (f *InstallForm) Validate(ctx *macaron.Context, errs binding.Errors) bindin
|
||||
// \____|__ /______/ |____| \___|_ /
|
||||
// \/ \/
|
||||
|
||||
type RegisterForm struct {
|
||||
type Register struct {
|
||||
UserName string `binding:"Required;AlphaDashDot;MaxSize(35)"`
|
||||
Email string `binding:"Required;Email;MaxSize(254)"`
|
||||
Password string `binding:"Required;MaxSize(255)"`
|
||||
Retype string
|
||||
}
|
||||
|
||||
func (f *RegisterForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *Register) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
type SignInForm struct {
|
||||
type SignIn struct {
|
||||
UserName string `binding:"Required;MaxSize(254)"`
|
||||
Password string `binding:"Required;MaxSize(255)"`
|
||||
Remember bool
|
||||
}
|
||||
|
||||
func (f *SignInForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *SignIn) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
@@ -89,15 +89,15 @@ func (f *SignInForm) Validate(ctx *macaron.Context, errs binding.Errors) binding
|
||||
// /_______ //_______ / |____| |____| |___\____|__ /\______ /_______ /
|
||||
// \/ \/ \/ \/ \/
|
||||
|
||||
type UpdateProfileForm struct {
|
||||
Name string `binding:"OmitEmpty;MaxSize(35)"`
|
||||
type UpdateProfile struct {
|
||||
Name string `binding:"Required;AlphaDashDot;MaxSize(35)"`
|
||||
FullName string `binding:"MaxSize(100)"`
|
||||
Email string `binding:"Required;Email;MaxSize(254)"`
|
||||
Website string `binding:"Url;MaxSize(100)"`
|
||||
Location string `binding:"MaxSize(50)"`
|
||||
}
|
||||
|
||||
func (f *UpdateProfileForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *UpdateProfile) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
@@ -106,48 +106,48 @@ const (
|
||||
AVATAR_BYMAIL string = "bymail"
|
||||
)
|
||||
|
||||
type AvatarForm struct {
|
||||
type Avatar struct {
|
||||
Source string
|
||||
Avatar *multipart.FileHeader
|
||||
Gravatar string `binding:"OmitEmpty;Email;MaxSize(254)"`
|
||||
Federavatar bool
|
||||
}
|
||||
|
||||
func (f *AvatarForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *Avatar) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
type AddEmailForm struct {
|
||||
type AddEmail struct {
|
||||
Email string `binding:"Required;Email;MaxSize(254)"`
|
||||
}
|
||||
|
||||
func (f *AddEmailForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *AddEmail) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
type ChangePasswordForm struct {
|
||||
OldPassword string `form:"old_password" binding:"Required;MinSize(1);MaxSize(255)"`
|
||||
Password string `form:"password" binding:"Required;MaxSize(255)"`
|
||||
Retype string `form:"retype"`
|
||||
type ChangePassword struct {
|
||||
OldPassword string `binding:"Required;MinSize(1);MaxSize(255)"`
|
||||
Password string `binding:"Required;MaxSize(255)"`
|
||||
Retype string
|
||||
}
|
||||
|
||||
func (f *ChangePasswordForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *ChangePassword) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
type AddSSHKeyForm struct {
|
||||
type AddSSHKey struct {
|
||||
Title string `binding:"Required;MaxSize(50)"`
|
||||
Content string `binding:"Required"`
|
||||
}
|
||||
|
||||
func (f *AddSSHKeyForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *AddSSHKey) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
type NewAccessTokenForm struct {
|
||||
type NewAccessToken struct {
|
||||
Name string `binding:"Required"`
|
||||
}
|
||||
|
||||
func (f *NewAccessTokenForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
func (f *NewAccessToken) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
|
||||
return validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
@@ -36,16 +36,18 @@ func NewMessageFrom(to []string, from, subject, htmlBody string) *Message {
|
||||
msg.SetHeader("Subject", subject)
|
||||
msg.SetDateHeader("Date", time.Now())
|
||||
|
||||
body, err := html2text.FromString(htmlBody)
|
||||
if err != nil {
|
||||
log.Error(4, "html2text.FromString: %v", err)
|
||||
msg.SetBody("text/html", htmlBody)
|
||||
} else {
|
||||
msg.SetBody("text/plain", body)
|
||||
if setting.MailService.EnableHTMLAlternative {
|
||||
msg.AddAlternative("text/html", htmlBody)
|
||||
contentType := "text/html"
|
||||
body := htmlBody
|
||||
if setting.MailService.UsePlainText {
|
||||
plainBody, err := html2text.FromString(htmlBody)
|
||||
if err != nil {
|
||||
log.Error(2, "html2text.FromString: %v", err)
|
||||
} else {
|
||||
contentType = "text/plain"
|
||||
body = plainBody
|
||||
}
|
||||
}
|
||||
msg.SetBody(contentType, body)
|
||||
|
||||
return &Message{
|
||||
Message: msg,
|
||||
|
||||
@@ -192,42 +192,11 @@ func (options *Renderer) ListItem(out *bytes.Buffer, text []byte, flags int) {
|
||||
// Note: this section is for purpose of increase performance and
|
||||
// reduce memory allocation at runtime since they are constant literals.
|
||||
var (
|
||||
svgSuffix = []byte(".svg")
|
||||
svgSuffixWithMark = []byte(".svg?")
|
||||
spaceBytes = []byte(" ")
|
||||
spaceEncodedBytes = []byte("%20")
|
||||
pound = []byte("#")
|
||||
space = " "
|
||||
spaceEncoded = "%20"
|
||||
pound = []byte("#")
|
||||
space = " "
|
||||
spaceEncoded = "%20"
|
||||
)
|
||||
|
||||
// Image defines how images should be processed to produce corresponding HTML elements.
|
||||
func (r *Renderer) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) {
|
||||
prefix := strings.Replace(r.urlPrefix, "/src/", "/raw/", 1)
|
||||
if len(link) > 0 {
|
||||
if isLink(link) {
|
||||
// External link with .svg suffix usually means CI status.
|
||||
// TODO: define a keyword to allow non-svg images render as external link.
|
||||
if bytes.HasSuffix(link, svgSuffix) || bytes.Contains(link, svgSuffixWithMark) {
|
||||
r.Renderer.Image(out, link, title, alt)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if link[0] != '/' {
|
||||
prefix += "/"
|
||||
}
|
||||
link = bytes.Replace([]byte((prefix + string(link))), spaceBytes, spaceEncodedBytes, -1)
|
||||
fmt.Println(333, string(link))
|
||||
}
|
||||
}
|
||||
|
||||
out.WriteString(`<a href="`)
|
||||
out.Write(link)
|
||||
out.WriteString(`">`)
|
||||
r.Renderer.Image(out, link, title, alt)
|
||||
out.WriteString("</a>")
|
||||
}
|
||||
|
||||
// cutoutVerbosePrefix cutouts URL prefix including sub-path to
|
||||
// return a clean unified string of request URL path.
|
||||
func cutoutVerbosePrefix(prefix string) string {
|
||||
@@ -353,14 +322,72 @@ var (
|
||||
rightAngleBracket = []byte(">")
|
||||
)
|
||||
|
||||
var noEndTags = []string{"img", "input", "br", "hr"}
|
||||
var noEndTags = []string{"input", "br", "hr", "img"}
|
||||
|
||||
// wrapImgWithLink warps link to standalone <img> tags.
|
||||
func wrapImgWithLink(urlPrefix string, buf *bytes.Buffer, token html.Token) {
|
||||
var src, alt string
|
||||
// Extract "src" and "alt" attributes
|
||||
for i := range token.Attr {
|
||||
switch token.Attr[i].Key {
|
||||
case "src":
|
||||
src = token.Attr[i].Val
|
||||
case "alt":
|
||||
alt = token.Attr[i].Val
|
||||
}
|
||||
}
|
||||
|
||||
// Skip in case the "src" is empty
|
||||
if len(src) == 0 {
|
||||
buf.WriteString(token.String())
|
||||
return
|
||||
}
|
||||
|
||||
// Prepend repository base URL for internal links
|
||||
needPrepend := !isLink([]byte(src))
|
||||
if needPrepend {
|
||||
urlPrefix = strings.Replace(urlPrefix, "/src/", "/raw/", 1)
|
||||
if src[0] != '/' {
|
||||
urlPrefix += "/"
|
||||
}
|
||||
}
|
||||
|
||||
buf.WriteString(`<a href="`)
|
||||
if needPrepend {
|
||||
buf.WriteString(urlPrefix)
|
||||
buf.WriteString(src)
|
||||
} else {
|
||||
buf.WriteString(src)
|
||||
}
|
||||
buf.WriteString(`">`)
|
||||
|
||||
if needPrepend {
|
||||
src = strings.Replace(urlPrefix+string(src), " ", "%20", -1)
|
||||
buf.WriteString(`<img src="`)
|
||||
buf.WriteString(src)
|
||||
buf.WriteString(`"`)
|
||||
|
||||
if len(alt) > 0 {
|
||||
buf.WriteString(` alt="`)
|
||||
buf.WriteString(alt)
|
||||
buf.WriteString(`"`)
|
||||
}
|
||||
|
||||
buf.WriteString(`>`)
|
||||
|
||||
} else {
|
||||
buf.WriteString(token.String())
|
||||
}
|
||||
|
||||
buf.WriteString(`</a>`)
|
||||
}
|
||||
|
||||
// PostProcess treats different types of HTML differently,
|
||||
// and only renders special links for plain text blocks.
|
||||
func PostProcess(rawHtml []byte, urlPrefix string, metas map[string]string) []byte {
|
||||
func PostProcess(rawHTML []byte, urlPrefix string, metas map[string]string) []byte {
|
||||
startTags := make([]string, 0, 5)
|
||||
var buf bytes.Buffer
|
||||
tokenizer := html.NewTokenizer(bytes.NewReader(rawHtml))
|
||||
buf := bytes.NewBuffer(nil)
|
||||
tokenizer := html.NewTokenizer(bytes.NewReader(rawHTML))
|
||||
|
||||
OUTER_LOOP:
|
||||
for html.ErrorToken != tokenizer.Next() {
|
||||
@@ -370,8 +397,14 @@ OUTER_LOOP:
|
||||
buf.Write(RenderSpecialLink([]byte(token.String()), urlPrefix, metas))
|
||||
|
||||
case html.StartTagToken:
|
||||
buf.WriteString(token.String())
|
||||
tagName := token.Data
|
||||
|
||||
if tagName == "img" {
|
||||
wrapImgWithLink(urlPrefix, buf, token)
|
||||
continue OUTER_LOOP
|
||||
}
|
||||
|
||||
buf.WriteString(token.String())
|
||||
// If this is an excluded tag, we skip processing all output until a close tag is encountered.
|
||||
if strings.EqualFold("a", tagName) || strings.EqualFold("code", tagName) || strings.EqualFold("pre", tagName) {
|
||||
stackNum := 1
|
||||
@@ -381,14 +414,14 @@ OUTER_LOOP:
|
||||
// Copy the token to the output verbatim
|
||||
buf.WriteString(token.String())
|
||||
|
||||
if token.Type == html.StartTagToken {
|
||||
// Stack number doesn't increate for tags without end tags.
|
||||
if token.Type == html.StartTagToken && !com.IsSliceContainsStr(noEndTags, token.Data) {
|
||||
stackNum++
|
||||
}
|
||||
|
||||
// If this is the close tag to the outer-most, we are done
|
||||
if token.Type == html.EndTagToken {
|
||||
stackNum--
|
||||
|
||||
if stackNum <= 0 && strings.EqualFold(tagName, token.Data) {
|
||||
break
|
||||
}
|
||||
@@ -397,8 +430,8 @@ OUTER_LOOP:
|
||||
continue OUTER_LOOP
|
||||
}
|
||||
|
||||
if !com.IsSliceContainsStr(noEndTags, token.Data) {
|
||||
startTags = append(startTags, token.Data)
|
||||
if !com.IsSliceContainsStr(noEndTags, tagName) {
|
||||
startTags = append(startTags, tagName)
|
||||
}
|
||||
|
||||
case html.EndTagToken:
|
||||
@@ -422,7 +455,7 @@ OUTER_LOOP:
|
||||
|
||||
// If we are not at the end of the input, then some other parsing error has occurred,
|
||||
// so return the input verbatim.
|
||||
return rawHtml
|
||||
return rawHTML
|
||||
}
|
||||
|
||||
// Render renders Markdown to HTML with special links.
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
package setting
|
||||
|
||||
import (
|
||||
_ "github.com/kardianos/minwinsvc"
|
||||
_ "github.com/gogits/minwinsvc"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -107,15 +107,6 @@ var (
|
||||
UsePostgreSQL bool
|
||||
UseMSSQL bool
|
||||
|
||||
// Webhook settings
|
||||
Webhook struct {
|
||||
QueueLength int
|
||||
DeliverTimeout int
|
||||
SkipTLSVerify bool
|
||||
Types []string
|
||||
PagingNum int
|
||||
}
|
||||
|
||||
// Repository settings
|
||||
Repository struct {
|
||||
AnsiCharset string
|
||||
@@ -146,6 +137,15 @@ var (
|
||||
RepoRootPath string
|
||||
ScriptType string
|
||||
|
||||
// Webhook settings
|
||||
Webhook struct {
|
||||
Types []string
|
||||
QueueLength int
|
||||
DeliverTimeout int
|
||||
SkipTLSVerify bool `ini:"SKIP_TLS_VERIFY"`
|
||||
PagingNum int
|
||||
}
|
||||
|
||||
// Markdown sttings
|
||||
Markdown struct {
|
||||
EnableHardLineBreak bool
|
||||
@@ -187,7 +187,7 @@ var (
|
||||
|
||||
// Session settings
|
||||
SessionConfig session.Options
|
||||
CSRFCookieName = "_csrf"
|
||||
CSRFCookieName string
|
||||
|
||||
// Cron tasks
|
||||
Cron struct {
|
||||
@@ -579,6 +579,8 @@ func NewContext() {
|
||||
|
||||
if err = Cfg.Section("http").MapTo(&HTTP); err != nil {
|
||||
log.Fatal(2, "Fail to map HTTP settings: %v", err)
|
||||
} else if err = Cfg.Section("webhook").MapTo(&Webhook); err != nil {
|
||||
log.Fatal(2, "Fail to map Webhook settings: %v", err)
|
||||
} else if err = Cfg.Section("markdown").MapTo(&Markdown); err != nil {
|
||||
log.Fatal(2, "Fail to map Markdown settings: %v", err)
|
||||
} else if err = Cfg.Section("admin").MapTo(&Admin); err != nil {
|
||||
@@ -742,24 +744,25 @@ func newSessionService() {
|
||||
SessionConfig.Secure = Cfg.Section("session").Key("COOKIE_SECURE").MustBool()
|
||||
SessionConfig.Gclifetime = Cfg.Section("session").Key("GC_INTERVAL_TIME").MustInt64(86400)
|
||||
SessionConfig.Maxlifetime = Cfg.Section("session").Key("SESSION_LIFE_TIME").MustInt64(86400)
|
||||
CSRFCookieName = Cfg.Section("session").Key("CSRF_COOKIE_NAME").MustString("_csrf")
|
||||
|
||||
log.Info("Session Service Enabled")
|
||||
}
|
||||
|
||||
// Mailer represents mail service.
|
||||
type Mailer struct {
|
||||
QueueLength int
|
||||
Name string
|
||||
Host string
|
||||
From string
|
||||
FromEmail string
|
||||
User, Passwd string
|
||||
DisableHelo bool
|
||||
HeloHostname string
|
||||
SkipVerify bool
|
||||
UseCertificate bool
|
||||
CertFile, KeyFile string
|
||||
EnableHTMLAlternative bool
|
||||
QueueLength int
|
||||
Subject string
|
||||
Host string
|
||||
From string
|
||||
FromEmail string
|
||||
User, Passwd string
|
||||
DisableHelo bool
|
||||
HeloHostname string
|
||||
SkipVerify bool
|
||||
UseCertificate bool
|
||||
CertFile, KeyFile string
|
||||
UsePlainText bool
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -774,18 +777,18 @@ func newMailService() {
|
||||
}
|
||||
|
||||
MailService = &Mailer{
|
||||
QueueLength: sec.Key("SEND_BUFFER_LEN").MustInt(100),
|
||||
Name: sec.Key("NAME").MustString(AppName),
|
||||
Host: sec.Key("HOST").String(),
|
||||
User: sec.Key("USER").String(),
|
||||
Passwd: sec.Key("PASSWD").String(),
|
||||
DisableHelo: sec.Key("DISABLE_HELO").MustBool(),
|
||||
HeloHostname: sec.Key("HELO_HOSTNAME").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(),
|
||||
EnableHTMLAlternative: sec.Key("ENABLE_HTML_ALTERNATIVE").MustBool(),
|
||||
QueueLength: sec.Key("SEND_BUFFER_LEN").MustInt(100),
|
||||
Subject: sec.Key("SUBJECT").MustString(AppName),
|
||||
Host: sec.Key("HOST").String(),
|
||||
User: sec.Key("USER").String(),
|
||||
Passwd: sec.Key("PASSWD").String(),
|
||||
DisableHelo: sec.Key("DISABLE_HELO").MustBool(),
|
||||
HeloHostname: sec.Key("HELO_HOSTNAME").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(),
|
||||
UsePlainText: sec.Key("USE_PLAIN_TEXT").MustBool(),
|
||||
}
|
||||
MailService.From = sec.Key("FROM").MustString(MailService.User)
|
||||
|
||||
@@ -822,15 +825,6 @@ func newNotifyMailService() {
|
||||
log.Info("Notify Mail Service Enabled")
|
||||
}
|
||||
|
||||
func newWebhookService() {
|
||||
sec := Cfg.Section("webhook")
|
||||
Webhook.QueueLength = sec.Key("QUEUE_LENGTH").MustInt(1000)
|
||||
Webhook.DeliverTimeout = sec.Key("DELIVER_TIMEOUT").MustInt(5)
|
||||
Webhook.SkipTLSVerify = sec.Key("SKIP_TLS_VERIFY").MustBool()
|
||||
Webhook.Types = []string{"gogs", "slack", "discord"}
|
||||
Webhook.PagingNum = sec.Key("PAGING_NUM").MustInt(10)
|
||||
}
|
||||
|
||||
func NewService() {
|
||||
newService()
|
||||
}
|
||||
@@ -843,5 +837,4 @@ func NewServices() {
|
||||
newMailService()
|
||||
newRegisterMailService()
|
||||
newNotifyMailService()
|
||||
newWebhookService()
|
||||
}
|
||||
|
||||
@@ -242,12 +242,14 @@ func ActionIcon(opType int) string {
|
||||
switch opType {
|
||||
case 1, 8: // Create and transfer repository
|
||||
return "repo"
|
||||
case 5, 9: // Commit repository
|
||||
case 5: // Commit repository
|
||||
return "git-commit"
|
||||
case 6: // Create issue
|
||||
return "issue-opened"
|
||||
case 7: // New pull request
|
||||
return "git-pull-request"
|
||||
case 9: // Push tag
|
||||
return "tag"
|
||||
case 10: // Comment issue
|
||||
return "comment-discussion"
|
||||
case 11: // Merge pull request
|
||||
@@ -256,6 +258,12 @@ func ActionIcon(opType int) string {
|
||||
return "issue-closed"
|
||||
case 13, 15: // Reopen issue or pull request
|
||||
return "issue-reopened"
|
||||
case 16: // Create branch
|
||||
return "git-branch"
|
||||
case 17, 18: // Delete branch or tag
|
||||
return "alert"
|
||||
case 19: // Fork a repository
|
||||
return "repo-forked"
|
||||
default:
|
||||
return "invalid type"
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
web: ./gogs web
|
||||
web: ./gogs web -p ${PORT:=3000}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"CodeKitInfo": "This is a CodeKit 2.x project configuration file. It is designed to sync project settings across multiple machines. MODIFYING THE CONTENTS OF THIS FILE IS A POOR LIFE DECISION. If you do so, you will likely cause CodeKit to crash. This file is not useful unless accompanied by the project that created it in CodeKit 2. This file is not backwards-compatible with CodeKit 1.x. For more information, see: http:\/\/incident57.com\/codekit",
|
||||
"creatorBuild": "19127",
|
||||
"creatorBuild": "19115",
|
||||
"files": {
|
||||
"\/css\/github.min.css": {
|
||||
"fileType": 16,
|
||||
@@ -22,8 +22,8 @@
|
||||
},
|
||||
"\/css\/semantic-2.2.7.min.css": {
|
||||
"fileType": 16,
|
||||
"ignore": 1,
|
||||
"ignoreWasSetByUser": 1,
|
||||
"ignore": 0,
|
||||
"ignoreWasSetByUser": 0,
|
||||
"inputAbbreviatedPath": "\/css\/semantic-2.2.7.min.css",
|
||||
"outputAbbreviatedPath": "No Output Path",
|
||||
"outputPathIsOutsideProject": 0,
|
||||
@@ -163,8 +163,8 @@
|
||||
},
|
||||
"\/js\/semantic-2.2.7.min.js": {
|
||||
"fileType": 64,
|
||||
"ignore": 1,
|
||||
"ignoreWasSetByUser": 1,
|
||||
"ignore": 0,
|
||||
"ignoreWasSetByUser": 0,
|
||||
"inputAbbreviatedPath": "\/js\/semantic-2.2.7.min.js",
|
||||
"outputAbbreviatedPath": "\/js\/min\/semantic-2.2.7.min-min.js",
|
||||
"outputPathIsOutsideProject": 0,
|
||||
|
||||
@@ -2310,9 +2310,18 @@ footer .ui.language .menu {
|
||||
margin-left: 20px;
|
||||
display: block;
|
||||
}
|
||||
.repository.settings.branches .branch-protection .whitelist {
|
||||
margin-left: 26px;
|
||||
}
|
||||
.repository.settings.branches .branch-protection .whitelist .dropdown img {
|
||||
display: inline-block;
|
||||
}
|
||||
.repository.settings.webhooks .types .menu .item {
|
||||
padding: 10px !important;
|
||||
}
|
||||
.repository.settings.webhook .text.desc {
|
||||
margin-top: 5px;
|
||||
}
|
||||
.repository.settings.webhook .events .column {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
@@ -2905,14 +2914,14 @@ footer .ui.language .menu {
|
||||
margin-bottom: -2px;
|
||||
}
|
||||
.feeds .news .push.news .content ul .text.truncate {
|
||||
width: 80%;
|
||||
width: 60%;
|
||||
margin-bottom: -5px;
|
||||
}
|
||||
.feeds .news .commit-id {
|
||||
font-family: Consolas, monospace;
|
||||
}
|
||||
.feeds .news code {
|
||||
padding: 1px;
|
||||
padding: 3px;
|
||||
font-size: 85%;
|
||||
background-color: rgba(0, 0, 0, 0.04);
|
||||
border-radius: 3px;
|
||||
@@ -3010,6 +3019,19 @@ footer .ui.language .menu {
|
||||
.admin.config #test-mail-btn {
|
||||
margin-left: 5px;
|
||||
}
|
||||
.admin.config table tbody tr td:first-child {
|
||||
font-weight: bold;
|
||||
}
|
||||
.admin.config pre {
|
||||
background-color: #f7f7f7;
|
||||
padding: 5px;
|
||||
}
|
||||
.admin.config .log-config table tbody tr td:first-child {
|
||||
width: 100px;
|
||||
}
|
||||
.admin.config .log-config table tbody tr td:not(first-child) {
|
||||
max-width: 0;
|
||||
}
|
||||
.explore {
|
||||
padding-top: 15px;
|
||||
padding-bottom: 80px;
|
||||
|
||||
@@ -341,7 +341,7 @@ function initRepository() {
|
||||
// Branches
|
||||
if ($('.repository.settings.branches').length > 0) {
|
||||
initFilterSearchDropdown('.protected-branches .dropdown');
|
||||
$('.enable-protection').change(function () {
|
||||
$('.enable-protection, .enable-whitelist').change(function () {
|
||||
if (this.checked) {
|
||||
$($(this).data('target')).removeClass('disabled');
|
||||
} else {
|
||||
@@ -930,6 +930,15 @@ function initWebhook() {
|
||||
}
|
||||
});
|
||||
|
||||
// Highlight payload on first click
|
||||
$('.hook.history.list .toggle.button').click(function () {
|
||||
$($(this).data('target') + ' .nohighlight').each(function () {
|
||||
var $this = $(this);
|
||||
$this.removeClass('nohighlight');
|
||||
setTimeout(function(){ hljs.highlightBlock($this[0]) }, 500);
|
||||
})
|
||||
})
|
||||
|
||||
// Test delivery
|
||||
$('#test-delivery').click(function () {
|
||||
var $this = $(this);
|
||||
@@ -1223,7 +1232,9 @@ $(document).ready(function () {
|
||||
});
|
||||
|
||||
// Semantic UI modules.
|
||||
$('.dropdown').dropdown();
|
||||
$('.ui.dropdown').dropdown({
|
||||
forceSelection: false
|
||||
});
|
||||
$('.jump.dropdown').dropdown({
|
||||
action: 'hide',
|
||||
onShow: function () {
|
||||
|
||||
@@ -62,5 +62,22 @@
|
||||
#test-mail-btn {
|
||||
margin-left: 5px;
|
||||
}
|
||||
table tbody tr td:first-child {
|
||||
font-weight: bold;
|
||||
}
|
||||
pre {
|
||||
background-color: #f7f7f7;
|
||||
padding: 5px;
|
||||
}
|
||||
.log-config {
|
||||
table tbody tr td {
|
||||
&:first-child {
|
||||
width: 100px;
|
||||
}
|
||||
&:not(first-child) {
|
||||
max-width: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
margin-bottom: -2px;
|
||||
}
|
||||
.text.truncate {
|
||||
width: 80%;
|
||||
width: 60%;
|
||||
margin-bottom: -5px;
|
||||
}
|
||||
}
|
||||
@@ -86,7 +86,7 @@
|
||||
font-family: Consolas, monospace;
|
||||
}
|
||||
code {
|
||||
padding: 1px;
|
||||
padding: 3px;
|
||||
font-size: 85%;
|
||||
background-color: rgba(0, 0, 0, 0.04);
|
||||
border-radius: 3px;
|
||||
|
||||
@@ -1330,6 +1330,13 @@
|
||||
margin-left: 20px;
|
||||
display: block;
|
||||
}
|
||||
.whitelist {
|
||||
margin-left: 26px;
|
||||
|
||||
.dropdown img {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1342,6 +1349,9 @@
|
||||
}
|
||||
|
||||
&.webhook {
|
||||
.text.desc {
|
||||
margin-top: 5px;
|
||||
}
|
||||
.events {
|
||||
.column {
|
||||
padding-bottom: 0;
|
||||
|
||||
@@ -240,7 +240,7 @@ func Config(ctx *context.Context) {
|
||||
Mode: strings.Title(setting.LogModes[i]),
|
||||
}
|
||||
|
||||
result, _ := json.Marshal(setting.LogConfigs[i])
|
||||
result, _ := json.MarshalIndent(setting.LogConfigs[i], "", " ")
|
||||
loggers[i].Config = string(result)
|
||||
}
|
||||
ctx.Data["Loggers"] = loggers
|
||||
|
||||
@@ -12,10 +12,10 @@ import (
|
||||
log "gopkg.in/clog.v1"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/auth"
|
||||
"github.com/gogits/gogs/modules/auth/ldap"
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/context"
|
||||
"github.com/gogits/gogs/modules/form"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
@@ -76,64 +76,64 @@ func NewAuthSource(ctx *context.Context) {
|
||||
ctx.HTML(200, AUTH_NEW)
|
||||
}
|
||||
|
||||
func parseLDAPConfig(form auth.AuthenticationForm) *models.LDAPConfig {
|
||||
func parseLDAPConfig(f form.Authentication) *models.LDAPConfig {
|
||||
return &models.LDAPConfig{
|
||||
Source: &ldap.Source{
|
||||
Name: form.Name,
|
||||
Host: form.Host,
|
||||
Port: form.Port,
|
||||
SecurityProtocol: ldap.SecurityProtocol(form.SecurityProtocol),
|
||||
SkipVerify: form.SkipVerify,
|
||||
BindDN: form.BindDN,
|
||||
UserDN: form.UserDN,
|
||||
BindPassword: form.BindPassword,
|
||||
UserBase: form.UserBase,
|
||||
AttributeUsername: form.AttributeUsername,
|
||||
AttributeName: form.AttributeName,
|
||||
AttributeSurname: form.AttributeSurname,
|
||||
AttributeMail: form.AttributeMail,
|
||||
AttributesInBind: form.AttributesInBind,
|
||||
Filter: form.Filter,
|
||||
AdminFilter: form.AdminFilter,
|
||||
Name: f.Name,
|
||||
Host: f.Host,
|
||||
Port: f.Port,
|
||||
SecurityProtocol: ldap.SecurityProtocol(f.SecurityProtocol),
|
||||
SkipVerify: f.SkipVerify,
|
||||
BindDN: f.BindDN,
|
||||
UserDN: f.UserDN,
|
||||
BindPassword: f.BindPassword,
|
||||
UserBase: f.UserBase,
|
||||
AttributeUsername: f.AttributeUsername,
|
||||
AttributeName: f.AttributeName,
|
||||
AttributeSurname: f.AttributeSurname,
|
||||
AttributeMail: f.AttributeMail,
|
||||
AttributesInBind: f.AttributesInBind,
|
||||
Filter: f.Filter,
|
||||
AdminFilter: f.AdminFilter,
|
||||
Enabled: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func parseSMTPConfig(form auth.AuthenticationForm) *models.SMTPConfig {
|
||||
func parseSMTPConfig(f form.Authentication) *models.SMTPConfig {
|
||||
return &models.SMTPConfig{
|
||||
Auth: form.SMTPAuth,
|
||||
Host: form.SMTPHost,
|
||||
Port: form.SMTPPort,
|
||||
AllowedDomains: form.AllowedDomains,
|
||||
TLS: form.TLS,
|
||||
SkipVerify: form.SkipVerify,
|
||||
Auth: f.SMTPAuth,
|
||||
Host: f.SMTPHost,
|
||||
Port: f.SMTPPort,
|
||||
AllowedDomains: f.AllowedDomains,
|
||||
TLS: f.TLS,
|
||||
SkipVerify: f.SkipVerify,
|
||||
}
|
||||
}
|
||||
|
||||
func NewAuthSourcePost(ctx *context.Context, form auth.AuthenticationForm) {
|
||||
func NewAuthSourcePost(ctx *context.Context, f form.Authentication) {
|
||||
ctx.Data["Title"] = ctx.Tr("admin.auths.new")
|
||||
ctx.Data["PageIsAdmin"] = true
|
||||
ctx.Data["PageIsAdminAuthentications"] = true
|
||||
|
||||
ctx.Data["CurrentTypeName"] = models.LoginNames[models.LoginType(form.Type)]
|
||||
ctx.Data["CurrentSecurityProtocol"] = models.SecurityProtocolNames[ldap.SecurityProtocol(form.SecurityProtocol)]
|
||||
ctx.Data["CurrentTypeName"] = models.LoginNames[models.LoginType(f.Type)]
|
||||
ctx.Data["CurrentSecurityProtocol"] = models.SecurityProtocolNames[ldap.SecurityProtocol(f.SecurityProtocol)]
|
||||
ctx.Data["AuthSources"] = authSources
|
||||
ctx.Data["SecurityProtocols"] = securityProtocols
|
||||
ctx.Data["SMTPAuths"] = models.SMTPAuths
|
||||
|
||||
hasTLS := false
|
||||
var config core.Conversion
|
||||
switch models.LoginType(form.Type) {
|
||||
switch models.LoginType(f.Type) {
|
||||
case models.LOGIN_LDAP, models.LOGIN_DLDAP:
|
||||
config = parseLDAPConfig(form)
|
||||
hasTLS = ldap.SecurityProtocol(form.SecurityProtocol) > ldap.SECURITY_PROTOCOL_UNENCRYPTED
|
||||
config = parseLDAPConfig(f)
|
||||
hasTLS = ldap.SecurityProtocol(f.SecurityProtocol) > ldap.SECURITY_PROTOCOL_UNENCRYPTED
|
||||
case models.LOGIN_SMTP:
|
||||
config = parseSMTPConfig(form)
|
||||
config = parseSMTPConfig(f)
|
||||
hasTLS = true
|
||||
case models.LOGIN_PAM:
|
||||
config = &models.PAMConfig{
|
||||
ServiceName: form.PAMServiceName,
|
||||
ServiceName: f.PAMServiceName,
|
||||
}
|
||||
default:
|
||||
ctx.Error(400)
|
||||
@@ -147,23 +147,23 @@ func NewAuthSourcePost(ctx *context.Context, form auth.AuthenticationForm) {
|
||||
}
|
||||
|
||||
if err := models.CreateLoginSource(&models.LoginSource{
|
||||
Type: models.LoginType(form.Type),
|
||||
Name: form.Name,
|
||||
IsActived: form.IsActive,
|
||||
Type: models.LoginType(f.Type),
|
||||
Name: f.Name,
|
||||
IsActived: f.IsActive,
|
||||
Cfg: config,
|
||||
}); err != nil {
|
||||
if models.IsErrLoginSourceAlreadyExist(err) {
|
||||
ctx.Data["Err_Name"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("admin.auths.login_source_exist", err.(models.ErrLoginSourceAlreadyExist).Name), AUTH_NEW, form)
|
||||
ctx.RenderWithErr(ctx.Tr("admin.auths.login_source_exist", err.(models.ErrLoginSourceAlreadyExist).Name), AUTH_NEW, f)
|
||||
} else {
|
||||
ctx.Handle(500, "CreateSource", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
log.Trace("Authentication created by admin(%s): %s", ctx.User.Name, form.Name)
|
||||
log.Trace("Authentication created by admin(%s): %s", ctx.User.Name, f.Name)
|
||||
|
||||
ctx.Flash.Success(ctx.Tr("admin.auths.new_success", form.Name))
|
||||
ctx.Flash.Success(ctx.Tr("admin.auths.new_success", f.Name))
|
||||
ctx.Redirect(setting.AppSubUrl + "/admin/auths")
|
||||
}
|
||||
|
||||
@@ -186,7 +186,7 @@ func EditAuthSource(ctx *context.Context) {
|
||||
ctx.HTML(200, AUTH_EDIT)
|
||||
}
|
||||
|
||||
func EditAuthSourcePost(ctx *context.Context, form auth.AuthenticationForm) {
|
||||
func EditAuthSourcePost(ctx *context.Context, f form.Authentication) {
|
||||
ctx.Data["Title"] = ctx.Tr("admin.auths.edit")
|
||||
ctx.Data["PageIsAdmin"] = true
|
||||
ctx.Data["PageIsAdminAuthentications"] = true
|
||||
@@ -207,22 +207,22 @@ func EditAuthSourcePost(ctx *context.Context, form auth.AuthenticationForm) {
|
||||
}
|
||||
|
||||
var config core.Conversion
|
||||
switch models.LoginType(form.Type) {
|
||||
switch models.LoginType(f.Type) {
|
||||
case models.LOGIN_LDAP, models.LOGIN_DLDAP:
|
||||
config = parseLDAPConfig(form)
|
||||
config = parseLDAPConfig(f)
|
||||
case models.LOGIN_SMTP:
|
||||
config = parseSMTPConfig(form)
|
||||
config = parseSMTPConfig(f)
|
||||
case models.LOGIN_PAM:
|
||||
config = &models.PAMConfig{
|
||||
ServiceName: form.PAMServiceName,
|
||||
ServiceName: f.PAMServiceName,
|
||||
}
|
||||
default:
|
||||
ctx.Error(400)
|
||||
return
|
||||
}
|
||||
|
||||
source.Name = form.Name
|
||||
source.IsActived = form.IsActive
|
||||
source.Name = f.Name
|
||||
source.IsActived = f.IsActive
|
||||
source.Cfg = config
|
||||
if err := models.UpdateSource(source); err != nil {
|
||||
ctx.Handle(500, "UpdateSource", err)
|
||||
@@ -231,7 +231,7 @@ func EditAuthSourcePost(ctx *context.Context, form auth.AuthenticationForm) {
|
||||
log.Trace("Authentication changed by admin(%s): %d", ctx.User.Name, source.ID)
|
||||
|
||||
ctx.Flash.Success(ctx.Tr("admin.auths.update_success"))
|
||||
ctx.Redirect(setting.AppSubUrl + "/admin/auths/" + com.ToStr(form.ID))
|
||||
ctx.Redirect(setting.AppSubUrl + "/admin/auths/" + com.ToStr(f.ID))
|
||||
}
|
||||
|
||||
func DeleteAuthSource(ctx *context.Context) {
|
||||
|
||||
@@ -11,9 +11,9 @@ import (
|
||||
log "gopkg.in/clog.v1"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/auth"
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/context"
|
||||
"github.com/gogits/gogs/modules/form"
|
||||
"github.com/gogits/gogs/modules/mailer"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
"github.com/gogits/gogs/routers"
|
||||
@@ -58,7 +58,7 @@ func NewUser(ctx *context.Context) {
|
||||
ctx.HTML(200, USER_NEW)
|
||||
}
|
||||
|
||||
func NewUserPost(ctx *context.Context, form auth.AdminCrateUserForm) {
|
||||
func NewUserPost(ctx *context.Context, f form.AdminCrateUser) {
|
||||
ctx.Data["Title"] = ctx.Tr("admin.users.new_account")
|
||||
ctx.Data["PageIsAdmin"] = true
|
||||
ctx.Data["PageIsAdminUsers"] = true
|
||||
@@ -78,19 +78,19 @@ func NewUserPost(ctx *context.Context, form auth.AdminCrateUserForm) {
|
||||
}
|
||||
|
||||
u := &models.User{
|
||||
Name: form.UserName,
|
||||
Email: form.Email,
|
||||
Passwd: form.Password,
|
||||
Name: f.UserName,
|
||||
Email: f.Email,
|
||||
Passwd: f.Password,
|
||||
IsActive: true,
|
||||
LoginType: models.LOGIN_PLAIN,
|
||||
}
|
||||
|
||||
if len(form.LoginType) > 0 {
|
||||
fields := strings.Split(form.LoginType, "-")
|
||||
if len(f.LoginType) > 0 {
|
||||
fields := strings.Split(f.LoginType, "-")
|
||||
if len(fields) == 2 {
|
||||
u.LoginType = models.LoginType(com.StrTo(fields[0]).MustInt())
|
||||
u.LoginSource = com.StrTo(fields[1]).MustInt64()
|
||||
u.LoginName = form.LoginName
|
||||
u.LoginName = f.LoginName
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,16 +98,16 @@ func NewUserPost(ctx *context.Context, form auth.AdminCrateUserForm) {
|
||||
switch {
|
||||
case models.IsErrUserAlreadyExist(err):
|
||||
ctx.Data["Err_UserName"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.username_been_taken"), USER_NEW, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("form.username_been_taken"), USER_NEW, &f)
|
||||
case models.IsErrEmailAlreadyUsed(err):
|
||||
ctx.Data["Err_Email"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), USER_NEW, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), USER_NEW, &f)
|
||||
case models.IsErrNameReserved(err):
|
||||
ctx.Data["Err_UserName"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("user.form.name_reserved", err.(models.ErrNameReserved).Name), USER_NEW, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("user.form.name_reserved", err.(models.ErrNameReserved).Name), USER_NEW, &f)
|
||||
case models.IsErrNamePatternNotAllowed(err):
|
||||
ctx.Data["Err_UserName"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("user.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), USER_NEW, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("user.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), USER_NEW, &f)
|
||||
default:
|
||||
ctx.Handle(500, "CreateUser", err)
|
||||
}
|
||||
@@ -116,7 +116,7 @@ func NewUserPost(ctx *context.Context, form auth.AdminCrateUserForm) {
|
||||
log.Trace("Account created by admin (%s): %s", ctx.User.Name, u.Name)
|
||||
|
||||
// Send email notification.
|
||||
if form.SendNotify && setting.MailService != nil {
|
||||
if f.SendNotify && setting.MailService != nil {
|
||||
mailer.SendRegisterNotifyMail(ctx.Context, models.NewMailerUser(u))
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ func EditUser(ctx *context.Context) {
|
||||
ctx.HTML(200, USER_EDIT)
|
||||
}
|
||||
|
||||
func EditUserPost(ctx *context.Context, form auth.AdminEditUserForm) {
|
||||
func EditUserPost(ctx *context.Context, f form.AdminEditUser) {
|
||||
ctx.Data["Title"] = ctx.Tr("admin.users.edit_account")
|
||||
ctx.Data["PageIsAdmin"] = true
|
||||
ctx.Data["PageIsAdminUsers"] = true
|
||||
@@ -182,7 +182,7 @@ func EditUserPost(ctx *context.Context, form auth.AdminEditUserForm) {
|
||||
return
|
||||
}
|
||||
|
||||
fields := strings.Split(form.LoginType, "-")
|
||||
fields := strings.Split(f.LoginType, "-")
|
||||
if len(fields) == 2 {
|
||||
loginType := models.LoginType(com.StrTo(fields[0]).MustInt())
|
||||
loginSource := com.StrTo(fields[1]).MustInt64()
|
||||
@@ -193,8 +193,8 @@ func EditUserPost(ctx *context.Context, form auth.AdminEditUserForm) {
|
||||
}
|
||||
}
|
||||
|
||||
if len(form.Password) > 0 {
|
||||
u.Passwd = form.Password
|
||||
if len(f.Password) > 0 {
|
||||
u.Passwd = f.Password
|
||||
var err error
|
||||
if u.Salt, err = models.GetUserSalt(); err != nil {
|
||||
ctx.Handle(500, "UpdateUser", err)
|
||||
@@ -203,22 +203,22 @@ func EditUserPost(ctx *context.Context, form auth.AdminEditUserForm) {
|
||||
u.EncodePasswd()
|
||||
}
|
||||
|
||||
u.LoginName = form.LoginName
|
||||
u.FullName = form.FullName
|
||||
u.Email = form.Email
|
||||
u.Website = form.Website
|
||||
u.Location = form.Location
|
||||
u.MaxRepoCreation = form.MaxRepoCreation
|
||||
u.IsActive = form.Active
|
||||
u.IsAdmin = form.Admin
|
||||
u.AllowGitHook = form.AllowGitHook
|
||||
u.AllowImportLocal = form.AllowImportLocal
|
||||
u.ProhibitLogin = form.ProhibitLogin
|
||||
u.LoginName = f.LoginName
|
||||
u.FullName = f.FullName
|
||||
u.Email = f.Email
|
||||
u.Website = f.Website
|
||||
u.Location = f.Location
|
||||
u.MaxRepoCreation = f.MaxRepoCreation
|
||||
u.IsActive = f.Active
|
||||
u.IsAdmin = f.Admin
|
||||
u.AllowGitHook = f.AllowGitHook
|
||||
u.AllowImportLocal = f.AllowImportLocal
|
||||
u.ProhibitLogin = f.ProhibitLogin
|
||||
|
||||
if err := models.UpdateUser(u); err != nil {
|
||||
if models.IsErrEmailAlreadyUsed(err) {
|
||||
ctx.Data["Err_Email"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), USER_EDIT, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), USER_EDIT, &f)
|
||||
} else {
|
||||
ctx.Handle(500, "UpdateUser", err)
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@ import (
|
||||
api "github.com/gogits/go-gogs-client"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/auth"
|
||||
"github.com/gogits/gogs/modules/context"
|
||||
"github.com/gogits/gogs/modules/form"
|
||||
"github.com/gogits/gogs/routers/api/v1/admin"
|
||||
"github.com/gogits/gogs/routers/api/v1/misc"
|
||||
"github.com/gogits/gogs/routers/api/v1/org"
|
||||
@@ -65,7 +65,7 @@ func repoAssignment() macaron.Handler {
|
||||
if ctx.IsSigned && ctx.User.IsAdmin {
|
||||
ctx.Repo.AccessMode = models.ACCESS_MODE_OWNER
|
||||
} else {
|
||||
mode, err := models.AccessLevel(ctx.User, repo)
|
||||
mode, err := models.AccessLevel(ctx.User.ID, repo)
|
||||
if err != nil {
|
||||
ctx.Error(500, "AccessLevel", err)
|
||||
return
|
||||
@@ -237,7 +237,7 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||
})
|
||||
|
||||
m.Group("/repos", func() {
|
||||
m.Post("/migrate", bind(auth.MigrateRepoForm{}), repo.Migrate)
|
||||
m.Post("/migrate", bind(form.MigrateRepo{}), repo.Migrate)
|
||||
m.Combo("/:username/:reponame").Get(repo.Get).
|
||||
Delete(repo.Delete)
|
||||
|
||||
|
||||
@@ -99,12 +99,12 @@ func CreateHook(ctx *context.APIContext, form api.CreateHookOption) {
|
||||
|
||||
// https://github.com/gogits/go-gogs-client/wiki/Repositories#edit-a-hook
|
||||
func EditHook(ctx *context.APIContext, form api.EditHookOption) {
|
||||
w, err := models.GetWebhookByRepoID(ctx.Repo.Repository.ID, ctx.ParamsInt64(":id"))
|
||||
w, err := models.GetWebhookOfRepoByID(ctx.Repo.Repository.ID, ctx.ParamsInt64(":id"))
|
||||
if err != nil {
|
||||
if models.IsErrWebhookNotExist(err) {
|
||||
ctx.Status(404)
|
||||
} else {
|
||||
ctx.Error(500, "GetWebhookByID", err)
|
||||
ctx.Error(500, "GetWebhookOfRepoByID", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@ import (
|
||||
api "github.com/gogits/go-gogs-client"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/auth"
|
||||
"github.com/gogits/gogs/modules/context"
|
||||
"github.com/gogits/gogs/modules/form"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
"github.com/gogits/gogs/routers/api/v1/convert"
|
||||
)
|
||||
@@ -149,7 +149,7 @@ func ListOrgRepositories(ctx *context.APIContext) {
|
||||
}
|
||||
|
||||
func CreateUserRepo(ctx *context.APIContext, owner *models.User, opt api.CreateRepoOption) {
|
||||
repo, err := models.CreateRepository(owner, models.CreateRepoOptions{
|
||||
repo, err := models.CreateRepository(ctx.User, owner, models.CreateRepoOptions{
|
||||
Name: opt.Name,
|
||||
Description: opt.Description,
|
||||
Gitignores: opt.Gitignores,
|
||||
@@ -206,12 +206,12 @@ func CreateOrgRepo(ctx *context.APIContext, opt api.CreateRepoOption) {
|
||||
}
|
||||
|
||||
// https://github.com/gogits/go-gogs-client/wiki/Repositories#migrate
|
||||
func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) {
|
||||
func Migrate(ctx *context.APIContext, f form.MigrateRepo) {
|
||||
ctxUser := ctx.User
|
||||
// Not equal means context user is an organization,
|
||||
// or is another user/organization if current user is admin.
|
||||
if form.Uid != ctxUser.ID {
|
||||
org, err := models.GetUserByID(form.Uid)
|
||||
if f.Uid != ctxUser.ID {
|
||||
org, err := models.GetUserByID(f.Uid)
|
||||
if err != nil {
|
||||
if models.IsErrUserNotExist(err) {
|
||||
ctx.Error(422, "", err)
|
||||
@@ -236,7 +236,7 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) {
|
||||
}
|
||||
}
|
||||
|
||||
remoteAddr, err := form.ParseRemoteAddr(ctx.User)
|
||||
remoteAddr, err := f.ParseRemoteAddr(ctx.User)
|
||||
if err != nil {
|
||||
if models.IsErrInvalidCloneAddr(err) {
|
||||
addrErr := err.(models.ErrInvalidCloneAddr)
|
||||
@@ -256,11 +256,11 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) {
|
||||
return
|
||||
}
|
||||
|
||||
repo, err := models.MigrateRepository(ctxUser, models.MigrateRepoOptions{
|
||||
Name: form.RepoName,
|
||||
Description: form.Description,
|
||||
IsPrivate: form.Private || setting.Repository.ForcePrivate,
|
||||
IsMirror: form.Mirror,
|
||||
repo, err := models.MigrateRepository(ctx.User, ctxUser, models.MigrateRepoOptions{
|
||||
Name: f.RepoName,
|
||||
Description: f.Description,
|
||||
IsPrivate: f.Private || setting.Repository.ForcePrivate,
|
||||
IsMirror: f.Mirror,
|
||||
RemoteAddr: remoteAddr,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -273,7 +273,7 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) {
|
||||
return
|
||||
}
|
||||
|
||||
log.Trace("Repository migrated: %s/%s", ctxUser.Name, form.RepoName)
|
||||
log.Trace("Repository migrated: %s/%s", ctxUser.Name, f.RepoName)
|
||||
ctx.JSON(201, repo.APIFormat(&api.Permission{true, true, true}))
|
||||
}
|
||||
|
||||
|
||||
@@ -21,10 +21,10 @@ import (
|
||||
"github.com/gogits/git-module"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/auth"
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/context"
|
||||
"github.com/gogits/gogs/modules/cron"
|
||||
"github.com/gogits/gogs/modules/form"
|
||||
"github.com/gogits/gogs/modules/mailer"
|
||||
"github.com/gogits/gogs/modules/markdown"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
@@ -109,13 +109,13 @@ func InstallInit(ctx *context.Context) {
|
||||
}
|
||||
|
||||
func Install(ctx *context.Context) {
|
||||
form := auth.InstallForm{}
|
||||
f := form.Install{}
|
||||
|
||||
// Database settings
|
||||
form.DbHost = models.DbCfg.Host
|
||||
form.DbUser = models.DbCfg.User
|
||||
form.DbName = models.DbCfg.Name
|
||||
form.DbPath = models.DbCfg.Path
|
||||
f.DbHost = models.DbCfg.Host
|
||||
f.DbUser = models.DbCfg.User
|
||||
f.DbName = models.DbCfg.Name
|
||||
f.DbPath = models.DbCfg.Path
|
||||
|
||||
ctx.Data["CurDbOption"] = "MySQL"
|
||||
switch models.DbCfg.Type {
|
||||
@@ -130,47 +130,47 @@ func Install(ctx *context.Context) {
|
||||
}
|
||||
|
||||
// Application general settings
|
||||
form.AppName = setting.AppName
|
||||
form.RepoRootPath = setting.RepoRootPath
|
||||
f.AppName = setting.AppName
|
||||
f.RepoRootPath = setting.RepoRootPath
|
||||
|
||||
// Note(unknwon): it's hard for Windows users change a running user,
|
||||
// so just use current one if config says default.
|
||||
if setting.IsWindows && setting.RunUser == "git" {
|
||||
form.RunUser = user.CurrentUsername()
|
||||
f.RunUser = user.CurrentUsername()
|
||||
} else {
|
||||
form.RunUser = setting.RunUser
|
||||
f.RunUser = setting.RunUser
|
||||
}
|
||||
|
||||
form.Domain = setting.Domain
|
||||
form.SSHPort = setting.SSH.Port
|
||||
form.UseBuiltinSSHServer = setting.SSH.StartBuiltinServer
|
||||
form.HTTPPort = setting.HTTPPort
|
||||
form.AppUrl = setting.AppUrl
|
||||
form.LogRootPath = setting.LogRootPath
|
||||
f.Domain = setting.Domain
|
||||
f.SSHPort = setting.SSH.Port
|
||||
f.UseBuiltinSSHServer = setting.SSH.StartBuiltinServer
|
||||
f.HTTPPort = setting.HTTPPort
|
||||
f.AppUrl = setting.AppUrl
|
||||
f.LogRootPath = setting.LogRootPath
|
||||
|
||||
// E-mail service settings
|
||||
if setting.MailService != nil {
|
||||
form.SMTPHost = setting.MailService.Host
|
||||
form.SMTPFrom = setting.MailService.From
|
||||
form.SMTPUser = setting.MailService.User
|
||||
f.SMTPHost = setting.MailService.Host
|
||||
f.SMTPFrom = setting.MailService.From
|
||||
f.SMTPUser = setting.MailService.User
|
||||
}
|
||||
form.RegisterConfirm = setting.Service.RegisterEmailConfirm
|
||||
form.MailNotify = setting.Service.EnableNotifyMail
|
||||
f.RegisterConfirm = setting.Service.RegisterEmailConfirm
|
||||
f.MailNotify = setting.Service.EnableNotifyMail
|
||||
|
||||
// Server and other services settings
|
||||
form.OfflineMode = setting.OfflineMode
|
||||
form.DisableGravatar = setting.DisableGravatar
|
||||
form.EnableFederatedAvatar = setting.EnableFederatedAvatar
|
||||
form.DisableRegistration = setting.Service.DisableRegistration
|
||||
form.EnableCaptcha = setting.Service.EnableCaptcha
|
||||
form.RequireSignInView = setting.Service.RequireSignInView
|
||||
f.OfflineMode = setting.OfflineMode
|
||||
f.DisableGravatar = setting.DisableGravatar
|
||||
f.EnableFederatedAvatar = setting.EnableFederatedAvatar
|
||||
f.DisableRegistration = setting.Service.DisableRegistration
|
||||
f.EnableCaptcha = setting.Service.EnableCaptcha
|
||||
f.RequireSignInView = setting.Service.RequireSignInView
|
||||
|
||||
auth.AssignForm(form, ctx.Data)
|
||||
form.Assign(f, ctx.Data)
|
||||
ctx.HTML(200, INSTALL)
|
||||
}
|
||||
|
||||
func InstallPost(ctx *context.Context, form auth.InstallForm) {
|
||||
ctx.Data["CurDbOption"] = form.DbType
|
||||
func InstallPost(ctx *context.Context, f form.Install) {
|
||||
ctx.Data["CurDbOption"] = f.DbType
|
||||
|
||||
if ctx.HasError() {
|
||||
if ctx.HasValue("Err_SMTPEmail") {
|
||||
@@ -187,24 +187,24 @@ func InstallPost(ctx *context.Context, form auth.InstallForm) {
|
||||
}
|
||||
|
||||
if _, err := exec.LookPath("git"); err != nil {
|
||||
ctx.RenderWithErr(ctx.Tr("install.test_git_failed", err), INSTALL, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("install.test_git_failed", err), INSTALL, &f)
|
||||
return
|
||||
}
|
||||
|
||||
// Pass basic check, now test configuration.
|
||||
// Test database setting.
|
||||
dbTypes := map[string]string{"MySQL": "mysql", "PostgreSQL": "postgres", "MSSQL": "mssql", "SQLite3": "sqlite3", "TiDB": "tidb"}
|
||||
models.DbCfg.Type = dbTypes[form.DbType]
|
||||
models.DbCfg.Host = form.DbHost
|
||||
models.DbCfg.User = form.DbUser
|
||||
models.DbCfg.Passwd = form.DbPasswd
|
||||
models.DbCfg.Name = form.DbName
|
||||
models.DbCfg.SSLMode = form.SSLMode
|
||||
models.DbCfg.Path = form.DbPath
|
||||
models.DbCfg.Type = dbTypes[f.DbType]
|
||||
models.DbCfg.Host = f.DbHost
|
||||
models.DbCfg.User = f.DbUser
|
||||
models.DbCfg.Passwd = f.DbPasswd
|
||||
models.DbCfg.Name = f.DbName
|
||||
models.DbCfg.SSLMode = f.SSLMode
|
||||
models.DbCfg.Path = f.DbPath
|
||||
|
||||
if models.DbCfg.Type == "sqlite3" && len(models.DbCfg.Path) == 0 {
|
||||
ctx.Data["Err_DbPath"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("install.err_empty_db_path"), INSTALL, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("install.err_empty_db_path"), INSTALL, &f)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -213,72 +213,72 @@ func InstallPost(ctx *context.Context, form auth.InstallForm) {
|
||||
if err := models.NewTestEngine(x); err != nil {
|
||||
if strings.Contains(err.Error(), `Unknown database type: sqlite3`) {
|
||||
ctx.Data["Err_DbType"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("install.sqlite3_not_available", "https://gogs.io/docs/installation/install_from_binary.html"), INSTALL, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("install.sqlite3_not_available", "https://gogs.io/docs/installation/install_from_binary.html"), INSTALL, &f)
|
||||
} else {
|
||||
ctx.Data["Err_DbSetting"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("install.invalid_db_setting", err), INSTALL, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("install.invalid_db_setting", err), INSTALL, &f)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Test repository root path.
|
||||
form.RepoRootPath = strings.Replace(form.RepoRootPath, "\\", "/", -1)
|
||||
if err := os.MkdirAll(form.RepoRootPath, os.ModePerm); err != nil {
|
||||
f.RepoRootPath = strings.Replace(f.RepoRootPath, "\\", "/", -1)
|
||||
if err := os.MkdirAll(f.RepoRootPath, os.ModePerm); err != nil {
|
||||
ctx.Data["Err_RepoRootPath"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("install.invalid_repo_path", err), INSTALL, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("install.invalid_repo_path", err), INSTALL, &f)
|
||||
return
|
||||
}
|
||||
|
||||
// Test log root path.
|
||||
form.LogRootPath = strings.Replace(form.LogRootPath, "\\", "/", -1)
|
||||
if err := os.MkdirAll(form.LogRootPath, os.ModePerm); err != nil {
|
||||
f.LogRootPath = strings.Replace(f.LogRootPath, "\\", "/", -1)
|
||||
if err := os.MkdirAll(f.LogRootPath, os.ModePerm); err != nil {
|
||||
ctx.Data["Err_LogRootPath"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("install.invalid_log_root_path", err), INSTALL, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("install.invalid_log_root_path", err), INSTALL, &f)
|
||||
return
|
||||
}
|
||||
|
||||
currentUser, match := setting.IsRunUserMatchCurrentUser(form.RunUser)
|
||||
currentUser, match := setting.IsRunUserMatchCurrentUser(f.RunUser)
|
||||
if !match {
|
||||
ctx.Data["Err_RunUser"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("install.run_user_not_match", form.RunUser, currentUser), INSTALL, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("install.run_user_not_match", f.RunUser, currentUser), INSTALL, &f)
|
||||
return
|
||||
}
|
||||
|
||||
// Make sure FROM field is valid
|
||||
if len(form.SMTPFrom) > 0 {
|
||||
_, err := mail.ParseAddress(form.SMTPFrom)
|
||||
if len(f.SMTPFrom) > 0 {
|
||||
_, err := mail.ParseAddress(f.SMTPFrom)
|
||||
if err != nil {
|
||||
ctx.Data["Err_SMTP"] = true
|
||||
ctx.Data["Err_SMTPFrom"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("install.invalid_smtp_from", err), INSTALL, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("install.invalid_smtp_from", err), INSTALL, &f)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Check logic loophole between disable self-registration and no admin account.
|
||||
if form.DisableRegistration && len(form.AdminName) == 0 {
|
||||
if f.DisableRegistration && len(f.AdminName) == 0 {
|
||||
ctx.Data["Err_Services"] = true
|
||||
ctx.Data["Err_Admin"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("install.no_admin_and_disable_registration"), INSTALL, form)
|
||||
ctx.RenderWithErr(ctx.Tr("install.no_admin_and_disable_registration"), INSTALL, f)
|
||||
return
|
||||
}
|
||||
|
||||
// Check admin password.
|
||||
if len(form.AdminName) > 0 && len(form.AdminPasswd) == 0 {
|
||||
if len(f.AdminName) > 0 && len(f.AdminPasswd) == 0 {
|
||||
ctx.Data["Err_Admin"] = true
|
||||
ctx.Data["Err_AdminPasswd"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("install.err_empty_admin_password"), INSTALL, form)
|
||||
ctx.RenderWithErr(ctx.Tr("install.err_empty_admin_password"), INSTALL, f)
|
||||
return
|
||||
}
|
||||
if form.AdminPasswd != form.AdminConfirmPasswd {
|
||||
if f.AdminPasswd != f.AdminConfirmPasswd {
|
||||
ctx.Data["Err_Admin"] = true
|
||||
ctx.Data["Err_AdminPasswd"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.password_not_match"), INSTALL, form)
|
||||
ctx.RenderWithErr(ctx.Tr("form.password_not_match"), INSTALL, f)
|
||||
return
|
||||
}
|
||||
|
||||
if form.AppUrl[len(form.AppUrl)-1] != '/' {
|
||||
form.AppUrl += "/"
|
||||
if f.AppUrl[len(f.AppUrl)-1] != '/' {
|
||||
f.AppUrl += "/"
|
||||
}
|
||||
|
||||
// Save settings.
|
||||
@@ -297,39 +297,39 @@ func InstallPost(ctx *context.Context, form auth.InstallForm) {
|
||||
cfg.Section("database").Key("SSL_MODE").SetValue(models.DbCfg.SSLMode)
|
||||
cfg.Section("database").Key("PATH").SetValue(models.DbCfg.Path)
|
||||
|
||||
cfg.Section("").Key("APP_NAME").SetValue(form.AppName)
|
||||
cfg.Section("repository").Key("ROOT").SetValue(form.RepoRootPath)
|
||||
cfg.Section("").Key("RUN_USER").SetValue(form.RunUser)
|
||||
cfg.Section("server").Key("DOMAIN").SetValue(form.Domain)
|
||||
cfg.Section("server").Key("HTTP_PORT").SetValue(form.HTTPPort)
|
||||
cfg.Section("server").Key("ROOT_URL").SetValue(form.AppUrl)
|
||||
cfg.Section("").Key("APP_NAME").SetValue(f.AppName)
|
||||
cfg.Section("repository").Key("ROOT").SetValue(f.RepoRootPath)
|
||||
cfg.Section("").Key("RUN_USER").SetValue(f.RunUser)
|
||||
cfg.Section("server").Key("DOMAIN").SetValue(f.Domain)
|
||||
cfg.Section("server").Key("HTTP_PORT").SetValue(f.HTTPPort)
|
||||
cfg.Section("server").Key("ROOT_URL").SetValue(f.AppUrl)
|
||||
|
||||
if form.SSHPort == 0 {
|
||||
if f.SSHPort == 0 {
|
||||
cfg.Section("server").Key("DISABLE_SSH").SetValue("true")
|
||||
} else {
|
||||
cfg.Section("server").Key("DISABLE_SSH").SetValue("false")
|
||||
cfg.Section("server").Key("SSH_PORT").SetValue(com.ToStr(form.SSHPort))
|
||||
cfg.Section("server").Key("START_SSH_SERVER").SetValue(com.ToStr(form.UseBuiltinSSHServer))
|
||||
cfg.Section("server").Key("SSH_PORT").SetValue(com.ToStr(f.SSHPort))
|
||||
cfg.Section("server").Key("START_SSH_SERVER").SetValue(com.ToStr(f.UseBuiltinSSHServer))
|
||||
}
|
||||
|
||||
if len(strings.TrimSpace(form.SMTPHost)) > 0 {
|
||||
if len(strings.TrimSpace(f.SMTPHost)) > 0 {
|
||||
cfg.Section("mailer").Key("ENABLED").SetValue("true")
|
||||
cfg.Section("mailer").Key("HOST").SetValue(form.SMTPHost)
|
||||
cfg.Section("mailer").Key("FROM").SetValue(form.SMTPFrom)
|
||||
cfg.Section("mailer").Key("USER").SetValue(form.SMTPUser)
|
||||
cfg.Section("mailer").Key("PASSWD").SetValue(form.SMTPPasswd)
|
||||
cfg.Section("mailer").Key("HOST").SetValue(f.SMTPHost)
|
||||
cfg.Section("mailer").Key("FROM").SetValue(f.SMTPFrom)
|
||||
cfg.Section("mailer").Key("USER").SetValue(f.SMTPUser)
|
||||
cfg.Section("mailer").Key("PASSWD").SetValue(f.SMTPPasswd)
|
||||
} else {
|
||||
cfg.Section("mailer").Key("ENABLED").SetValue("false")
|
||||
}
|
||||
cfg.Section("service").Key("REGISTER_EMAIL_CONFIRM").SetValue(com.ToStr(form.RegisterConfirm))
|
||||
cfg.Section("service").Key("ENABLE_NOTIFY_MAIL").SetValue(com.ToStr(form.MailNotify))
|
||||
cfg.Section("service").Key("REGISTER_EMAIL_CONFIRM").SetValue(com.ToStr(f.RegisterConfirm))
|
||||
cfg.Section("service").Key("ENABLE_NOTIFY_MAIL").SetValue(com.ToStr(f.MailNotify))
|
||||
|
||||
cfg.Section("server").Key("OFFLINE_MODE").SetValue(com.ToStr(form.OfflineMode))
|
||||
cfg.Section("picture").Key("DISABLE_GRAVATAR").SetValue(com.ToStr(form.DisableGravatar))
|
||||
cfg.Section("picture").Key("ENABLE_FEDERATED_AVATAR").SetValue(com.ToStr(form.EnableFederatedAvatar))
|
||||
cfg.Section("service").Key("DISABLE_REGISTRATION").SetValue(com.ToStr(form.DisableRegistration))
|
||||
cfg.Section("service").Key("ENABLE_CAPTCHA").SetValue(com.ToStr(form.EnableCaptcha))
|
||||
cfg.Section("service").Key("REQUIRE_SIGNIN_VIEW").SetValue(com.ToStr(form.RequireSignInView))
|
||||
cfg.Section("server").Key("OFFLINE_MODE").SetValue(com.ToStr(f.OfflineMode))
|
||||
cfg.Section("picture").Key("DISABLE_GRAVATAR").SetValue(com.ToStr(f.DisableGravatar))
|
||||
cfg.Section("picture").Key("ENABLE_FEDERATED_AVATAR").SetValue(com.ToStr(f.EnableFederatedAvatar))
|
||||
cfg.Section("service").Key("DISABLE_REGISTRATION").SetValue(com.ToStr(f.DisableRegistration))
|
||||
cfg.Section("service").Key("ENABLE_CAPTCHA").SetValue(com.ToStr(f.EnableCaptcha))
|
||||
cfg.Section("service").Key("REQUIRE_SIGNIN_VIEW").SetValue(com.ToStr(f.RequireSignInView))
|
||||
|
||||
cfg.Section("").Key("RUN_MODE").SetValue("prod")
|
||||
|
||||
@@ -337,30 +337,30 @@ func InstallPost(ctx *context.Context, form auth.InstallForm) {
|
||||
|
||||
cfg.Section("log").Key("MODE").SetValue("file")
|
||||
cfg.Section("log").Key("LEVEL").SetValue("Info")
|
||||
cfg.Section("log").Key("ROOT_PATH").SetValue(form.LogRootPath)
|
||||
cfg.Section("log").Key("ROOT_PATH").SetValue(f.LogRootPath)
|
||||
|
||||
cfg.Section("security").Key("INSTALL_LOCK").SetValue("true")
|
||||
secretKey, err := base.GetRandomString(15)
|
||||
if err != nil {
|
||||
ctx.RenderWithErr(ctx.Tr("install.secret_key_failed", err), INSTALL, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("install.secret_key_failed", err), INSTALL, &f)
|
||||
return
|
||||
}
|
||||
cfg.Section("security").Key("SECRET_KEY").SetValue(secretKey)
|
||||
|
||||
os.MkdirAll(filepath.Dir(setting.CustomConf), os.ModePerm)
|
||||
if err := cfg.SaveTo(setting.CustomConf); err != nil {
|
||||
ctx.RenderWithErr(ctx.Tr("install.save_config_failed", err), INSTALL, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("install.save_config_failed", err), INSTALL, &f)
|
||||
return
|
||||
}
|
||||
|
||||
GlobalInit()
|
||||
|
||||
// Create admin account
|
||||
if len(form.AdminName) > 0 {
|
||||
if len(f.AdminName) > 0 {
|
||||
u := &models.User{
|
||||
Name: form.AdminName,
|
||||
Email: form.AdminEmail,
|
||||
Passwd: form.AdminPasswd,
|
||||
Name: f.AdminName,
|
||||
Email: f.AdminEmail,
|
||||
Passwd: f.AdminPasswd,
|
||||
IsAdmin: true,
|
||||
IsActive: true,
|
||||
}
|
||||
@@ -369,7 +369,7 @@ func InstallPost(ctx *context.Context, form auth.InstallForm) {
|
||||
setting.InstallLock = false
|
||||
ctx.Data["Err_AdminName"] = true
|
||||
ctx.Data["Err_AdminEmail"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("install.invalid_admin_setting", err), INSTALL, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("install.invalid_admin_setting", err), INSTALL, &f)
|
||||
return
|
||||
}
|
||||
log.Info("Admin account already exist")
|
||||
@@ -383,5 +383,5 @@ func InstallPost(ctx *context.Context, form auth.InstallForm) {
|
||||
|
||||
log.Info("First-time run install finished!")
|
||||
ctx.Flash.Success(ctx.Tr("install.install_success"))
|
||||
ctx.Redirect(form.AppUrl + "user/login")
|
||||
ctx.Redirect(f.AppUrl + "user/login")
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
log "gopkg.in/clog.v1"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/auth"
|
||||
"github.com/gogits/gogs/modules/form"
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/context"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
@@ -23,7 +23,7 @@ func Create(ctx *context.Context) {
|
||||
ctx.HTML(200, CREATE)
|
||||
}
|
||||
|
||||
func CreatePost(ctx *context.Context, form auth.CreateOrgForm) {
|
||||
func CreatePost(ctx *context.Context, f form.CreateOrg) {
|
||||
ctx.Data["Title"] = ctx.Tr("new_org")
|
||||
|
||||
if ctx.HasError() {
|
||||
@@ -32,7 +32,7 @@ func CreatePost(ctx *context.Context, form auth.CreateOrgForm) {
|
||||
}
|
||||
|
||||
org := &models.User{
|
||||
Name: form.OrgName,
|
||||
Name: f.OrgName,
|
||||
IsActive: true,
|
||||
Type: models.USER_TYPE_ORGANIZATION,
|
||||
}
|
||||
@@ -41,11 +41,11 @@ func CreatePost(ctx *context.Context, form auth.CreateOrgForm) {
|
||||
ctx.Data["Err_OrgName"] = true
|
||||
switch {
|
||||
case models.IsErrUserAlreadyExist(err):
|
||||
ctx.RenderWithErr(ctx.Tr("form.org_name_been_taken"), CREATE, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("form.org_name_been_taken"), CREATE, &f)
|
||||
case models.IsErrNameReserved(err):
|
||||
ctx.RenderWithErr(ctx.Tr("org.form.name_reserved", err.(models.ErrNameReserved).Name), CREATE, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("org.form.name_reserved", err.(models.ErrNameReserved).Name), CREATE, &f)
|
||||
case models.IsErrNamePatternNotAllowed(err):
|
||||
ctx.RenderWithErr(ctx.Tr("org.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), CREATE, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("org.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), CREATE, &f)
|
||||
default:
|
||||
ctx.Handle(500, "CreateOrganization", err)
|
||||
}
|
||||
@@ -53,5 +53,5 @@ func CreatePost(ctx *context.Context, form auth.CreateOrgForm) {
|
||||
}
|
||||
log.Trace("Organization created: %s", org.Name)
|
||||
|
||||
ctx.Redirect(setting.AppSubUrl + "/org/" + form.OrgName + "/dashboard")
|
||||
ctx.Redirect(setting.AppSubUrl + "/org/" + f.OrgName + "/dashboard")
|
||||
}
|
||||
|
||||
@@ -10,17 +10,17 @@ import (
|
||||
log "gopkg.in/clog.v1"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/auth"
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/context"
|
||||
"github.com/gogits/gogs/modules/form"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
"github.com/gogits/gogs/routers/user"
|
||||
)
|
||||
|
||||
const (
|
||||
SETTINGS_OPTIONS base.TplName = "org/settings/options"
|
||||
SETTINGS_DELETE base.TplName = "org/settings/delete"
|
||||
SETTINGS_HOOKS base.TplName = "org/settings/hooks"
|
||||
SETTINGS_OPTIONS base.TplName = "org/settings/options"
|
||||
SETTINGS_DELETE base.TplName = "org/settings/delete"
|
||||
SETTINGS_WEBHOOKS base.TplName = "org/settings/webhooks"
|
||||
)
|
||||
|
||||
func Settings(ctx *context.Context) {
|
||||
@@ -29,7 +29,7 @@ func Settings(ctx *context.Context) {
|
||||
ctx.HTML(200, SETTINGS_OPTIONS)
|
||||
}
|
||||
|
||||
func SettingsPost(ctx *context.Context, form auth.UpdateOrgSettingForm) {
|
||||
func SettingsPost(ctx *context.Context, f form.UpdateOrgSetting) {
|
||||
ctx.Data["Title"] = ctx.Tr("org.settings")
|
||||
ctx.Data["PageIsSettingsOptions"] = true
|
||||
|
||||
@@ -41,40 +41,40 @@ func SettingsPost(ctx *context.Context, form auth.UpdateOrgSettingForm) {
|
||||
org := ctx.Org.Organization
|
||||
|
||||
// Check if organization name has been changed.
|
||||
if org.LowerName != strings.ToLower(form.Name) {
|
||||
isExist, err := models.IsUserExist(org.ID, form.Name)
|
||||
if org.LowerName != strings.ToLower(f.Name) {
|
||||
isExist, err := models.IsUserExist(org.ID, f.Name)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "IsUserExist", err)
|
||||
return
|
||||
} else if isExist {
|
||||
ctx.Data["OrgName"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.username_been_taken"), SETTINGS_OPTIONS, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("form.username_been_taken"), SETTINGS_OPTIONS, &f)
|
||||
return
|
||||
} else if err = models.ChangeUserName(org, form.Name); err != nil {
|
||||
} else if err = models.ChangeUserName(org, f.Name); err != nil {
|
||||
if err == models.ErrUserNameIllegal {
|
||||
ctx.Data["OrgName"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.illegal_username"), SETTINGS_OPTIONS, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("form.illegal_username"), SETTINGS_OPTIONS, &f)
|
||||
} else {
|
||||
ctx.Handle(500, "ChangeUserName", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
// reset ctx.org.OrgLink with new name
|
||||
ctx.Org.OrgLink = setting.AppSubUrl + "/org/" + form.Name
|
||||
log.Trace("Organization name changed: %s -> %s", org.Name, form.Name)
|
||||
ctx.Org.OrgLink = setting.AppSubUrl + "/org/" + f.Name
|
||||
log.Trace("Organization name changed: %s -> %s", org.Name, f.Name)
|
||||
}
|
||||
// In case it's just a case change.
|
||||
org.Name = form.Name
|
||||
org.LowerName = strings.ToLower(form.Name)
|
||||
org.Name = f.Name
|
||||
org.LowerName = strings.ToLower(f.Name)
|
||||
|
||||
if ctx.User.IsAdmin {
|
||||
org.MaxRepoCreation = form.MaxRepoCreation
|
||||
org.MaxRepoCreation = f.MaxRepoCreation
|
||||
}
|
||||
|
||||
org.FullName = form.FullName
|
||||
org.Description = form.Description
|
||||
org.Website = form.Website
|
||||
org.Location = form.Location
|
||||
org.FullName = f.FullName
|
||||
org.Description = f.Description
|
||||
org.Website = f.Website
|
||||
org.Location = f.Location
|
||||
if err := models.UpdateUser(org); err != nil {
|
||||
ctx.Handle(500, "UpdateUser", err)
|
||||
return
|
||||
@@ -84,9 +84,9 @@ func SettingsPost(ctx *context.Context, form auth.UpdateOrgSettingForm) {
|
||||
ctx.Redirect(ctx.Org.OrgLink + "/settings")
|
||||
}
|
||||
|
||||
func SettingsAvatar(ctx *context.Context, form auth.AvatarForm) {
|
||||
form.Source = auth.AVATAR_LOCAL
|
||||
if err := user.UpdateAvatarSetting(ctx, form, ctx.Org.Organization); err != nil {
|
||||
func SettingsAvatar(ctx *context.Context, f form.Avatar) {
|
||||
f.Source = form.AVATAR_LOCAL
|
||||
if err := user.UpdateAvatarSetting(ctx, f, ctx.Org.Organization); err != nil {
|
||||
ctx.Flash.Error(err.Error())
|
||||
} else {
|
||||
ctx.Flash.Success(ctx.Tr("org.settings.update_avatar_success"))
|
||||
@@ -140,6 +140,7 @@ func Webhooks(ctx *context.Context) {
|
||||
ctx.Data["PageIsSettingsHooks"] = true
|
||||
ctx.Data["BaseLink"] = ctx.Org.OrgLink
|
||||
ctx.Data["Description"] = ctx.Tr("org.settings.hooks_desc")
|
||||
ctx.Data["Types"] = setting.Webhook.Types
|
||||
|
||||
ws, err := models.GetWebhooksByOrgID(ctx.Org.Organization.ID)
|
||||
if err != nil {
|
||||
@@ -148,7 +149,7 @@ func Webhooks(ctx *context.Context) {
|
||||
}
|
||||
|
||||
ctx.Data["Webhooks"] = ws
|
||||
ctx.HTML(200, SETTINGS_HOOKS)
|
||||
ctx.HTML(200, SETTINGS_WEBHOOKS)
|
||||
}
|
||||
|
||||
func DeleteWebhook(ctx *context.Context) {
|
||||
|
||||
@@ -11,9 +11,9 @@ import (
|
||||
log "gopkg.in/clog.v1"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/auth"
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/context"
|
||||
"github.com/gogits/gogs/modules/form"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -149,16 +149,16 @@ func NewTeam(ctx *context.Context) {
|
||||
ctx.HTML(200, TEAM_NEW)
|
||||
}
|
||||
|
||||
func NewTeamPost(ctx *context.Context, form auth.CreateTeamForm) {
|
||||
func NewTeamPost(ctx *context.Context, f form.CreateTeam) {
|
||||
ctx.Data["Title"] = ctx.Org.Organization.FullName
|
||||
ctx.Data["PageIsOrgTeams"] = true
|
||||
ctx.Data["PageIsOrgTeamsNew"] = true
|
||||
|
||||
t := &models.Team{
|
||||
OrgID: ctx.Org.Organization.ID,
|
||||
Name: form.TeamName,
|
||||
Description: form.Description,
|
||||
Authorize: models.ParseAccessMode(form.Permission),
|
||||
Name: f.TeamName,
|
||||
Description: f.Description,
|
||||
Authorize: models.ParseAccessMode(f.Permission),
|
||||
}
|
||||
ctx.Data["Team"] = t
|
||||
|
||||
@@ -171,9 +171,9 @@ func NewTeamPost(ctx *context.Context, form auth.CreateTeamForm) {
|
||||
ctx.Data["Err_TeamName"] = true
|
||||
switch {
|
||||
case models.IsErrTeamAlreadyExist(err):
|
||||
ctx.RenderWithErr(ctx.Tr("form.team_name_been_taken"), TEAM_NEW, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("form.team_name_been_taken"), TEAM_NEW, &f)
|
||||
case models.IsErrNameReserved(err):
|
||||
ctx.RenderWithErr(ctx.Tr("org.form.team_name_reserved", err.(models.ErrNameReserved).Name), TEAM_NEW, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("org.form.team_name_reserved", err.(models.ErrNameReserved).Name), TEAM_NEW, &f)
|
||||
default:
|
||||
ctx.Handle(500, "NewTeam", err)
|
||||
}
|
||||
@@ -211,7 +211,7 @@ func EditTeam(ctx *context.Context) {
|
||||
ctx.HTML(200, TEAM_NEW)
|
||||
}
|
||||
|
||||
func EditTeamPost(ctx *context.Context, form auth.CreateTeamForm) {
|
||||
func EditTeamPost(ctx *context.Context, f form.CreateTeam) {
|
||||
t := ctx.Org.Team
|
||||
ctx.Data["Title"] = ctx.Org.Organization.FullName
|
||||
ctx.Data["PageIsOrgTeams"] = true
|
||||
@@ -226,7 +226,7 @@ func EditTeamPost(ctx *context.Context, form auth.CreateTeamForm) {
|
||||
if !t.IsOwnerTeam() {
|
||||
// Validate permission level.
|
||||
var auth models.AccessMode
|
||||
switch form.Permission {
|
||||
switch f.Permission {
|
||||
case "read":
|
||||
auth = models.ACCESS_MODE_READ
|
||||
case "write":
|
||||
@@ -238,18 +238,18 @@ func EditTeamPost(ctx *context.Context, form auth.CreateTeamForm) {
|
||||
return
|
||||
}
|
||||
|
||||
t.Name = form.TeamName
|
||||
t.Name = f.TeamName
|
||||
if t.Authorize != auth {
|
||||
isAuthChanged = true
|
||||
t.Authorize = auth
|
||||
}
|
||||
}
|
||||
t.Description = form.Description
|
||||
t.Description = f.Description
|
||||
if err := models.UpdateTeam(t, isAuthChanged); err != nil {
|
||||
ctx.Data["Err_TeamName"] = true
|
||||
switch {
|
||||
case models.IsErrTeamAlreadyExist(err):
|
||||
ctx.RenderWithErr(ctx.Tr("form.team_name_been_taken"), TEAM_NEW, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("form.team_name_been_taken"), TEAM_NEW, &f)
|
||||
default:
|
||||
ctx.Handle(500, "UpdateTeam", err)
|
||||
}
|
||||
|
||||
@@ -15,9 +15,9 @@ import (
|
||||
|
||||
"github.com/gogits/git-module"
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/auth"
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/context"
|
||||
"github.com/gogits/gogs/modules/form"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
"github.com/gogits/gogs/modules/template"
|
||||
)
|
||||
@@ -123,7 +123,7 @@ func NewFile(ctx *context.Context) {
|
||||
editFile(ctx, true)
|
||||
}
|
||||
|
||||
func editFilePost(ctx *context.Context, form auth.EditRepoFileForm, isNewFile bool) {
|
||||
func editFilePost(ctx *context.Context, f form.EditRepoFile, isNewFile bool) {
|
||||
ctx.Data["PageIsEdit"] = true
|
||||
ctx.Data["IsNewFile"] = isNewFile
|
||||
ctx.Data["RequireHighlightJS"] = true
|
||||
@@ -132,26 +132,26 @@ func editFilePost(ctx *context.Context, form auth.EditRepoFileForm, isNewFile bo
|
||||
oldBranchName := ctx.Repo.BranchName
|
||||
branchName := oldBranchName
|
||||
oldTreePath := ctx.Repo.TreePath
|
||||
lastCommit := form.LastCommit
|
||||
form.LastCommit = ctx.Repo.Commit.ID.String()
|
||||
lastCommit := f.LastCommit
|
||||
f.LastCommit = ctx.Repo.Commit.ID.String()
|
||||
|
||||
if form.IsNewBrnach() {
|
||||
branchName = form.NewBranchName
|
||||
if f.IsNewBrnach() {
|
||||
branchName = f.NewBranchName
|
||||
}
|
||||
|
||||
form.TreePath = strings.Trim(form.TreePath, " /")
|
||||
treeNames, treePaths := getParentTreeFields(form.TreePath)
|
||||
f.TreePath = strings.Trim(f.TreePath, " /")
|
||||
treeNames, treePaths := getParentTreeFields(f.TreePath)
|
||||
|
||||
ctx.Data["TreePath"] = form.TreePath
|
||||
ctx.Data["TreePath"] = f.TreePath
|
||||
ctx.Data["TreeNames"] = treeNames
|
||||
ctx.Data["TreePaths"] = treePaths
|
||||
ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + branchName
|
||||
ctx.Data["FileContent"] = form.Content
|
||||
ctx.Data["commit_summary"] = form.CommitSummary
|
||||
ctx.Data["commit_message"] = form.CommitMessage
|
||||
ctx.Data["commit_choice"] = form.CommitChoice
|
||||
ctx.Data["FileContent"] = f.Content
|
||||
ctx.Data["commit_summary"] = f.CommitSummary
|
||||
ctx.Data["commit_message"] = f.CommitMessage
|
||||
ctx.Data["commit_choice"] = f.CommitChoice
|
||||
ctx.Data["new_branch_name"] = branchName
|
||||
ctx.Data["last_commit"] = form.LastCommit
|
||||
ctx.Data["last_commit"] = f.LastCommit
|
||||
ctx.Data["MarkdownFileExts"] = strings.Join(setting.Markdown.FileExtensions, ",")
|
||||
ctx.Data["LineWrapExtensions"] = strings.Join(setting.Repository.Editor.LineWrapExtensions, ",")
|
||||
ctx.Data["PreviewableFileModes"] = strings.Join(setting.Repository.Editor.PreviewableFileModes, ",")
|
||||
@@ -161,16 +161,16 @@ func editFilePost(ctx *context.Context, form auth.EditRepoFileForm, isNewFile bo
|
||||
return
|
||||
}
|
||||
|
||||
if len(form.TreePath) == 0 {
|
||||
if len(f.TreePath) == 0 {
|
||||
ctx.Data["Err_TreePath"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.filename_cannot_be_empty"), EDIT_FILE, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.filename_cannot_be_empty"), EDIT_FILE, &f)
|
||||
return
|
||||
}
|
||||
|
||||
if oldBranchName != branchName {
|
||||
if _, err := ctx.Repo.Repository.GetBranch(branchName); err == nil {
|
||||
ctx.Data["Err_NewBranchName"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.branch_already_exists", branchName), EDIT_FILE, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.branch_already_exists", branchName), EDIT_FILE, &f)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -191,17 +191,17 @@ func editFilePost(ctx *context.Context, form auth.EditRepoFileForm, isNewFile bo
|
||||
if index != len(treeNames)-1 {
|
||||
if !entry.IsDir() {
|
||||
ctx.Data["Err_TreePath"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.directory_is_a_file", part), EDIT_FILE, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.directory_is_a_file", part), EDIT_FILE, &f)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if entry.IsLink() {
|
||||
ctx.Data["Err_TreePath"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.file_is_a_symlink", part), EDIT_FILE, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.file_is_a_symlink", part), EDIT_FILE, &f)
|
||||
return
|
||||
} else if entry.IsDir() {
|
||||
ctx.Data["Err_TreePath"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.filename_is_a_directory", part), EDIT_FILE, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.filename_is_a_directory", part), EDIT_FILE, &f)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -212,7 +212,7 @@ func editFilePost(ctx *context.Context, form auth.EditRepoFileForm, isNewFile bo
|
||||
if err != nil {
|
||||
if git.IsErrNotExist(err) {
|
||||
ctx.Data["Err_TreePath"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.file_editing_no_longer_exists", oldTreePath), EDIT_FILE, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.file_editing_no_longer_exists", oldTreePath), EDIT_FILE, &f)
|
||||
} else {
|
||||
ctx.Handle(500, "GetTreeEntryByPath", err)
|
||||
}
|
||||
@@ -226,17 +226,17 @@ func editFilePost(ctx *context.Context, form auth.EditRepoFileForm, isNewFile bo
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
if file == form.TreePath {
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_editing", ctx.Repo.RepoLink+"/compare/"+lastCommit+"..."+ctx.Repo.CommitID), EDIT_FILE, &form)
|
||||
if file == f.TreePath {
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_editing", ctx.Repo.RepoLink+"/compare/"+lastCommit+"..."+ctx.Repo.CommitID), EDIT_FILE, &f)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if oldTreePath != form.TreePath {
|
||||
if oldTreePath != f.TreePath {
|
||||
// We have a new filename (rename or completely new file) so we need to make sure it doesn't already exist, can't clobber.
|
||||
entry, err := ctx.Repo.Commit.GetTreeEntryByPath(form.TreePath)
|
||||
entry, err := ctx.Repo.Commit.GetTreeEntryByPath(f.TreePath)
|
||||
if err != nil {
|
||||
if !git.IsErrNotExist(err) {
|
||||
ctx.Handle(500, "GetTreeEntryByPath", err)
|
||||
@@ -245,23 +245,23 @@ func editFilePost(ctx *context.Context, form auth.EditRepoFileForm, isNewFile bo
|
||||
}
|
||||
if entry != nil {
|
||||
ctx.Data["Err_TreePath"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.file_already_exists", form.TreePath), EDIT_FILE, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.file_already_exists", f.TreePath), EDIT_FILE, &f)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
message := strings.TrimSpace(form.CommitSummary)
|
||||
message := strings.TrimSpace(f.CommitSummary)
|
||||
if len(message) == 0 {
|
||||
if isNewFile {
|
||||
message = ctx.Tr("repo.editor.add", form.TreePath)
|
||||
message = ctx.Tr("repo.editor.add", f.TreePath)
|
||||
} else {
|
||||
message = ctx.Tr("repo.editor.update", form.TreePath)
|
||||
message = ctx.Tr("repo.editor.update", f.TreePath)
|
||||
}
|
||||
}
|
||||
|
||||
form.CommitMessage = strings.TrimSpace(form.CommitMessage)
|
||||
if len(form.CommitMessage) > 0 {
|
||||
message += "\n\n" + form.CommitMessage
|
||||
f.CommitMessage = strings.TrimSpace(f.CommitMessage)
|
||||
if len(f.CommitMessage) > 0 {
|
||||
message += "\n\n" + f.CommitMessage
|
||||
}
|
||||
|
||||
if err := ctx.Repo.Repository.UpdateRepoFile(ctx.User, models.UpdateRepoFileOptions{
|
||||
@@ -269,32 +269,32 @@ func editFilePost(ctx *context.Context, form auth.EditRepoFileForm, isNewFile bo
|
||||
OldBranch: oldBranchName,
|
||||
NewBranch: branchName,
|
||||
OldTreeName: oldTreePath,
|
||||
NewTreeName: form.TreePath,
|
||||
NewTreeName: f.TreePath,
|
||||
Message: message,
|
||||
Content: strings.Replace(form.Content, "\r", "", -1),
|
||||
Content: strings.Replace(f.Content, "\r", "", -1),
|
||||
IsNewFile: isNewFile,
|
||||
}); err != nil {
|
||||
ctx.Data["Err_TreePath"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.fail_to_update_file", form.TreePath, err), EDIT_FILE, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.fail_to_update_file", f.TreePath, err), EDIT_FILE, &f)
|
||||
return
|
||||
}
|
||||
|
||||
if form.IsNewBrnach() {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + oldBranchName + "..." + form.NewBranchName)
|
||||
if f.IsNewBrnach() && ctx.Repo.PullRequest.Allowed {
|
||||
ctx.Redirect(ctx.Repo.PullRequestURL(oldBranchName, f.NewBranchName))
|
||||
} else {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/src/" + branchName + "/" + template.EscapePound(form.TreePath))
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/src/" + branchName + "/" + template.EscapePound(f.TreePath))
|
||||
}
|
||||
}
|
||||
|
||||
func EditFilePost(ctx *context.Context, form auth.EditRepoFileForm) {
|
||||
editFilePost(ctx, form, false)
|
||||
func EditFilePost(ctx *context.Context, f form.EditRepoFile) {
|
||||
editFilePost(ctx, f, false)
|
||||
}
|
||||
|
||||
func NewFilePost(ctx *context.Context, form auth.EditRepoFileForm) {
|
||||
editFilePost(ctx, form, true)
|
||||
func NewFilePost(ctx *context.Context, f form.EditRepoFile) {
|
||||
editFilePost(ctx, f, true)
|
||||
}
|
||||
|
||||
func DiffPreviewPost(ctx *context.Context, form auth.EditPreviewDiffForm) {
|
||||
func DiffPreviewPost(ctx *context.Context, f form.EditPreviewDiff) {
|
||||
treePath := ctx.Repo.TreePath
|
||||
|
||||
entry, err := ctx.Repo.Commit.GetTreeEntryByPath(treePath)
|
||||
@@ -306,7 +306,7 @@ func DiffPreviewPost(ctx *context.Context, form auth.EditPreviewDiffForm) {
|
||||
return
|
||||
}
|
||||
|
||||
diff, err := ctx.Repo.Repository.GetDiffPreview(ctx.Repo.BranchName, treePath, form.Content)
|
||||
diff, err := ctx.Repo.Repository.GetDiffPreview(ctx.Repo.BranchName, treePath, f.Content)
|
||||
if err != nil {
|
||||
ctx.Error(500, "GetDiffPreview: "+err.Error())
|
||||
return
|
||||
@@ -332,7 +332,7 @@ func DeleteFile(ctx *context.Context) {
|
||||
ctx.HTML(200, DELETE_FILE)
|
||||
}
|
||||
|
||||
func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) {
|
||||
func DeleteFilePost(ctx *context.Context, f form.DeleteRepoFile) {
|
||||
ctx.Data["PageIsDelete"] = true
|
||||
ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchName
|
||||
ctx.Data["TreePath"] = ctx.Repo.TreePath
|
||||
@@ -340,12 +340,12 @@ func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) {
|
||||
oldBranchName := ctx.Repo.BranchName
|
||||
branchName := oldBranchName
|
||||
|
||||
if form.IsNewBrnach() {
|
||||
branchName = form.NewBranchName
|
||||
if f.IsNewBrnach() {
|
||||
branchName = f.NewBranchName
|
||||
}
|
||||
ctx.Data["commit_summary"] = form.CommitSummary
|
||||
ctx.Data["commit_message"] = form.CommitMessage
|
||||
ctx.Data["commit_choice"] = form.CommitChoice
|
||||
ctx.Data["commit_summary"] = f.CommitSummary
|
||||
ctx.Data["commit_message"] = f.CommitMessage
|
||||
ctx.Data["commit_choice"] = f.CommitChoice
|
||||
ctx.Data["new_branch_name"] = branchName
|
||||
|
||||
if ctx.HasError() {
|
||||
@@ -356,19 +356,19 @@ func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) {
|
||||
if oldBranchName != branchName {
|
||||
if _, err := ctx.Repo.Repository.GetBranch(branchName); err == nil {
|
||||
ctx.Data["Err_NewBranchName"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.branch_already_exists", branchName), DELETE_FILE, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.branch_already_exists", branchName), DELETE_FILE, &f)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
message := strings.TrimSpace(form.CommitSummary)
|
||||
message := strings.TrimSpace(f.CommitSummary)
|
||||
if len(message) == 0 {
|
||||
message = ctx.Tr("repo.editor.delete", ctx.Repo.TreePath)
|
||||
}
|
||||
|
||||
form.CommitMessage = strings.TrimSpace(form.CommitMessage)
|
||||
if len(form.CommitMessage) > 0 {
|
||||
message += "\n\n" + form.CommitMessage
|
||||
f.CommitMessage = strings.TrimSpace(f.CommitMessage)
|
||||
if len(f.CommitMessage) > 0 {
|
||||
message += "\n\n" + f.CommitMessage
|
||||
}
|
||||
|
||||
if err := ctx.Repo.Repository.DeleteRepoFile(ctx.User, models.DeleteRepoFileOptions{
|
||||
@@ -382,8 +382,8 @@ func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) {
|
||||
return
|
||||
}
|
||||
|
||||
if form.IsNewBrnach() {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + oldBranchName + "..." + form.NewBranchName)
|
||||
if f.IsNewBrnach() && ctx.Repo.PullRequest.Allowed {
|
||||
ctx.Redirect(ctx.Repo.PullRequestURL(oldBranchName, f.NewBranchName))
|
||||
} else {
|
||||
ctx.Flash.Success(ctx.Tr("repo.editor.file_delete_success", ctx.Repo.TreePath))
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/src/" + branchName)
|
||||
@@ -418,31 +418,31 @@ func UploadFile(ctx *context.Context) {
|
||||
ctx.HTML(200, UPLOAD_FILE)
|
||||
}
|
||||
|
||||
func UploadFilePost(ctx *context.Context, form auth.UploadRepoFileForm) {
|
||||
func UploadFilePost(ctx *context.Context, f form.UploadRepoFile) {
|
||||
ctx.Data["PageIsUpload"] = true
|
||||
renderUploadSettings(ctx)
|
||||
|
||||
oldBranchName := ctx.Repo.BranchName
|
||||
branchName := oldBranchName
|
||||
|
||||
if form.IsNewBrnach() {
|
||||
branchName = form.NewBranchName
|
||||
if f.IsNewBrnach() {
|
||||
branchName = f.NewBranchName
|
||||
}
|
||||
|
||||
form.TreePath = strings.Trim(form.TreePath, " /")
|
||||
treeNames, treePaths := getParentTreeFields(form.TreePath)
|
||||
f.TreePath = strings.Trim(f.TreePath, " /")
|
||||
treeNames, treePaths := getParentTreeFields(f.TreePath)
|
||||
if len(treeNames) == 0 {
|
||||
// We must at least have one element for user to input.
|
||||
treeNames = []string{""}
|
||||
}
|
||||
|
||||
ctx.Data["TreePath"] = form.TreePath
|
||||
ctx.Data["TreePath"] = f.TreePath
|
||||
ctx.Data["TreeNames"] = treeNames
|
||||
ctx.Data["TreePaths"] = treePaths
|
||||
ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + branchName
|
||||
ctx.Data["commit_summary"] = form.CommitSummary
|
||||
ctx.Data["commit_message"] = form.CommitMessage
|
||||
ctx.Data["commit_choice"] = form.CommitChoice
|
||||
ctx.Data["commit_summary"] = f.CommitSummary
|
||||
ctx.Data["commit_message"] = f.CommitMessage
|
||||
ctx.Data["commit_choice"] = f.CommitChoice
|
||||
ctx.Data["new_branch_name"] = branchName
|
||||
|
||||
if ctx.HasError() {
|
||||
@@ -453,7 +453,7 @@ func UploadFilePost(ctx *context.Context, form auth.UploadRepoFileForm) {
|
||||
if oldBranchName != branchName {
|
||||
if _, err := ctx.Repo.Repository.GetBranch(branchName); err == nil {
|
||||
ctx.Data["Err_NewBranchName"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.branch_already_exists", branchName), UPLOAD_FILE, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.branch_already_exists", branchName), UPLOAD_FILE, &f)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -475,38 +475,38 @@ func UploadFilePost(ctx *context.Context, form auth.UploadRepoFileForm) {
|
||||
// User can only upload files to a directory.
|
||||
if !entry.IsDir() {
|
||||
ctx.Data["Err_TreePath"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.directory_is_a_file", part), UPLOAD_FILE, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.directory_is_a_file", part), UPLOAD_FILE, &f)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
message := strings.TrimSpace(form.CommitSummary)
|
||||
message := strings.TrimSpace(f.CommitSummary)
|
||||
if len(message) == 0 {
|
||||
message = ctx.Tr("repo.editor.upload_files_to_dir", form.TreePath)
|
||||
message = ctx.Tr("repo.editor.upload_files_to_dir", f.TreePath)
|
||||
}
|
||||
|
||||
form.CommitMessage = strings.TrimSpace(form.CommitMessage)
|
||||
if len(form.CommitMessage) > 0 {
|
||||
message += "\n\n" + form.CommitMessage
|
||||
f.CommitMessage = strings.TrimSpace(f.CommitMessage)
|
||||
if len(f.CommitMessage) > 0 {
|
||||
message += "\n\n" + f.CommitMessage
|
||||
}
|
||||
|
||||
if err := ctx.Repo.Repository.UploadRepoFiles(ctx.User, models.UploadRepoFileOptions{
|
||||
LastCommitID: ctx.Repo.CommitID,
|
||||
OldBranch: oldBranchName,
|
||||
NewBranch: branchName,
|
||||
TreePath: form.TreePath,
|
||||
TreePath: f.TreePath,
|
||||
Message: message,
|
||||
Files: form.Files,
|
||||
Files: f.Files,
|
||||
}); err != nil {
|
||||
ctx.Data["Err_TreePath"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.unable_to_upload_files", form.TreePath, err), UPLOAD_FILE, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.unable_to_upload_files", f.TreePath, err), UPLOAD_FILE, &f)
|
||||
return
|
||||
}
|
||||
|
||||
if form.IsNewBrnach() {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + oldBranchName + "..." + form.NewBranchName)
|
||||
if f.IsNewBrnach() && ctx.Repo.PullRequest.Allowed {
|
||||
ctx.Redirect(ctx.Repo.PullRequestURL(oldBranchName, f.NewBranchName))
|
||||
} else {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/src/" + branchName + "/" + form.TreePath)
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/src/" + branchName + "/" + f.TreePath)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -553,17 +553,17 @@ func UploadFileToServer(ctx *context.Context) {
|
||||
})
|
||||
}
|
||||
|
||||
func RemoveUploadFileFromServer(ctx *context.Context, form auth.RemoveUploadFileForm) {
|
||||
if len(form.File) == 0 {
|
||||
func RemoveUploadFileFromServer(ctx *context.Context, f form.RemoveUploadFile) {
|
||||
if len(f.File) == 0 {
|
||||
ctx.Status(204)
|
||||
return
|
||||
}
|
||||
|
||||
if err := models.DeleteUploadByUUID(form.File); err != nil {
|
||||
if err := models.DeleteUploadByUUID(f.File); err != nil {
|
||||
ctx.Error(500, fmt.Sprintf("DeleteUploadByUUID: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
log.Trace("Upload file removed: %s", form.File)
|
||||
log.Trace("Upload file removed: %s", f.File)
|
||||
ctx.Status(204)
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import (
|
||||
const (
|
||||
ENV_AUTH_USER_ID = "GOGS_AUTH_USER_ID"
|
||||
ENV_AUTH_USER_NAME = "GOGS_AUTH_USER_NAME"
|
||||
ENV_AUTH_USER_EMAIL = "GOGS_AUTH_USER_EMAIL"
|
||||
ENV_REPO_OWNER_NAME = "GOGS_REPO_OWNER_NAME"
|
||||
ENV_REPO_OWNER_SALT_MD5 = "GOGS_REPO_OWNER_SALT_MD5"
|
||||
ENV_REPO_ID = "GOGS_REPO_ID"
|
||||
@@ -76,6 +77,16 @@ func HTTPContexter() macaron.Handler {
|
||||
return
|
||||
}
|
||||
|
||||
// In case user requested a wrong URL and not intended to access Git objects.
|
||||
action := ctx.Params("*")
|
||||
if !strings.Contains(action, "git-") &&
|
||||
!strings.Contains(action, "info/") &&
|
||||
!strings.Contains(action, "HEAD") &&
|
||||
!strings.Contains(action, "objects/") {
|
||||
ctx.NotFound()
|
||||
return
|
||||
}
|
||||
|
||||
// Handle HTTP Basic Authentication
|
||||
authHead := ctx.Req.Header.Get("Authorization")
|
||||
if len(authHead) == 0 {
|
||||
@@ -127,7 +138,7 @@ func HTTPContexter() macaron.Handler {
|
||||
if isPull {
|
||||
mode = models.ACCESS_MODE_READ
|
||||
}
|
||||
has, err := models.HasAccess(authUser, repo, mode)
|
||||
has, err := models.HasAccess(authUser.ID, repo, mode)
|
||||
if err != nil {
|
||||
ctx.Handle(http.StatusInternalServerError, "HasAccess", err)
|
||||
return
|
||||
@@ -207,6 +218,7 @@ func ComposeHookEnvs(opts ComposeHookEnvsOptions) []string {
|
||||
"SSH_ORIGINAL_COMMAND=1",
|
||||
ENV_AUTH_USER_ID + "=" + com.ToStr(opts.AuthUser.ID),
|
||||
ENV_AUTH_USER_NAME + "=" + opts.AuthUser.Name,
|
||||
ENV_AUTH_USER_EMAIL + "=" + opts.AuthUser.Email,
|
||||
ENV_REPO_OWNER_NAME + "=" + opts.OwnerName,
|
||||
ENV_REPO_OWNER_SALT_MD5 + "=" + base.EncodeMD5(opts.OwnerSalt),
|
||||
ENV_REPO_ID + "=" + com.ToStr(opts.RepoID),
|
||||
|
||||
@@ -19,9 +19,9 @@ import (
|
||||
log "gopkg.in/clog.v1"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/auth"
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/context"
|
||||
"github.com/gogits/gogs/modules/form"
|
||||
"github.com/gogits/gogs/modules/markdown"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
@@ -348,7 +348,7 @@ func NewIssue(ctx *context.Context) {
|
||||
ctx.HTML(200, ISSUE_NEW)
|
||||
}
|
||||
|
||||
func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm) ([]int64, int64, int64) {
|
||||
func ValidateRepoMetas(ctx *context.Context, f form.CreateIssue) ([]int64, int64, int64) {
|
||||
var (
|
||||
repo = ctx.Repo.Repository
|
||||
err error
|
||||
@@ -364,7 +364,7 @@ func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm) ([]int64
|
||||
}
|
||||
|
||||
// Check labels.
|
||||
labelIDs := base.StringsToInt64s(strings.Split(form.LabelIDs, ","))
|
||||
labelIDs := base.StringsToInt64s(strings.Split(f.LabelIDs, ","))
|
||||
labelIDMark := base.Int64sToMap(labelIDs)
|
||||
hasSelected := false
|
||||
for i := range labels {
|
||||
@@ -374,11 +374,11 @@ func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm) ([]int64
|
||||
}
|
||||
}
|
||||
ctx.Data["HasSelectedLabel"] = hasSelected
|
||||
ctx.Data["label_ids"] = form.LabelIDs
|
||||
ctx.Data["label_ids"] = f.LabelIDs
|
||||
ctx.Data["Labels"] = labels
|
||||
|
||||
// Check milestone.
|
||||
milestoneID := form.MilestoneID
|
||||
milestoneID := f.MilestoneID
|
||||
if milestoneID > 0 {
|
||||
ctx.Data["Milestone"], err = repo.GetMilestoneByID(milestoneID)
|
||||
if err != nil {
|
||||
@@ -389,7 +389,7 @@ func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm) ([]int64
|
||||
}
|
||||
|
||||
// Check assignee.
|
||||
assigneeID := form.AssigneeID
|
||||
assigneeID := f.AssigneeID
|
||||
if assigneeID > 0 {
|
||||
ctx.Data["Assignee"], err = repo.GetAssigneeByID(assigneeID)
|
||||
if err != nil {
|
||||
@@ -402,7 +402,7 @@ func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm) ([]int64
|
||||
return labelIDs, milestoneID, assigneeID
|
||||
}
|
||||
|
||||
func NewIssuePost(ctx *context.Context, form auth.CreateIssueForm) {
|
||||
func NewIssuePost(ctx *context.Context, f form.CreateIssue) {
|
||||
ctx.Data["Title"] = ctx.Tr("repo.issues.new")
|
||||
ctx.Data["PageIsIssueList"] = true
|
||||
ctx.Data["RequireHighlightJS"] = true
|
||||
@@ -414,13 +414,13 @@ func NewIssuePost(ctx *context.Context, form auth.CreateIssueForm) {
|
||||
attachments []string
|
||||
)
|
||||
|
||||
labelIDs, milestoneID, assigneeID := ValidateRepoMetas(ctx, form)
|
||||
labelIDs, milestoneID, assigneeID := ValidateRepoMetas(ctx, f)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
if setting.AttachmentEnabled {
|
||||
attachments = form.Files
|
||||
attachments = f.Files
|
||||
}
|
||||
|
||||
if ctx.HasError() {
|
||||
@@ -430,12 +430,12 @@ func NewIssuePost(ctx *context.Context, form auth.CreateIssueForm) {
|
||||
|
||||
issue := &models.Issue{
|
||||
RepoID: repo.ID,
|
||||
Title: form.Title,
|
||||
Title: f.Title,
|
||||
PosterID: ctx.User.ID,
|
||||
Poster: ctx.User,
|
||||
MilestoneID: milestoneID,
|
||||
AssigneeID: assigneeID,
|
||||
Content: form.Content,
|
||||
Content: f.Content,
|
||||
}
|
||||
if err := models.NewIssue(repo, issue, labelIDs, attachments); err != nil {
|
||||
ctx.Handle(500, "NewIssue", err)
|
||||
@@ -805,7 +805,7 @@ func UpdateIssueAssignee(ctx *context.Context) {
|
||||
})
|
||||
}
|
||||
|
||||
func NewComment(ctx *context.Context, form auth.CreateCommentForm) {
|
||||
func NewComment(ctx *context.Context, f form.CreateComment) {
|
||||
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
|
||||
if err != nil {
|
||||
ctx.NotFoundOrServerError("GetIssueByIndex", models.IsErrIssueNotExist, err)
|
||||
@@ -814,7 +814,7 @@ func NewComment(ctx *context.Context, form auth.CreateCommentForm) {
|
||||
|
||||
var attachments []string
|
||||
if setting.AttachmentEnabled {
|
||||
attachments = form.Files
|
||||
attachments = f.Files
|
||||
}
|
||||
|
||||
if ctx.HasError() {
|
||||
@@ -827,13 +827,13 @@ func NewComment(ctx *context.Context, form auth.CreateCommentForm) {
|
||||
defer func() {
|
||||
// Check if issue admin/poster changes the status of issue.
|
||||
if (ctx.Repo.IsWriter() || (ctx.IsSigned && issue.IsPoster(ctx.User.ID))) &&
|
||||
(form.Status == "reopen" || form.Status == "close") &&
|
||||
(f.Status == "reopen" || f.Status == "close") &&
|
||||
!(issue.IsPull && issue.PullRequest.HasMerged) {
|
||||
|
||||
// Duplication and conflict check should apply to reopen pull request.
|
||||
var pr *models.PullRequest
|
||||
|
||||
if form.Status == "reopen" && issue.IsPull {
|
||||
if f.Status == "reopen" && issue.IsPull {
|
||||
pull := issue.PullRequest
|
||||
pr, err = models.GetUnmergedPullRequest(pull.HeadRepoID, pull.BaseRepoID, pull.HeadBranch, pull.BaseBranch)
|
||||
if err != nil {
|
||||
@@ -857,7 +857,7 @@ func NewComment(ctx *context.Context, form auth.CreateCommentForm) {
|
||||
if pr != nil {
|
||||
ctx.Flash.Info(ctx.Tr("repo.pulls.open_unmerged_pull_exists", pr.Index))
|
||||
} else {
|
||||
if err = issue.ChangeStatus(ctx.User, ctx.Repo.Repository, form.Status == "close"); err != nil {
|
||||
if err = issue.ChangeStatus(ctx.User, ctx.Repo.Repository, f.Status == "close"); err != nil {
|
||||
log.Error(4, "ChangeStatus: %v", err)
|
||||
} else {
|
||||
log.Trace("Issue [%d] status changed to closed: %v", issue.ID, issue.IsClosed)
|
||||
@@ -878,11 +878,11 @@ func NewComment(ctx *context.Context, form auth.CreateCommentForm) {
|
||||
}()
|
||||
|
||||
// Fix #321: Allow empty comments, as long as we have attachments.
|
||||
if len(form.Content) == 0 && len(attachments) == 0 {
|
||||
if len(f.Content) == 0 && len(attachments) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
comment, err = models.CreateIssueComment(ctx.User, ctx.Repo.Repository, issue, form.Content, attachments)
|
||||
comment, err = models.CreateIssueComment(ctx.User, ctx.Repo.Repository, issue, f.Content, attachments)
|
||||
if err != nil {
|
||||
ctx.Handle(500, "CreateIssueComment", err)
|
||||
return
|
||||
@@ -955,14 +955,14 @@ func Labels(ctx *context.Context) {
|
||||
ctx.HTML(200, LABELS)
|
||||
}
|
||||
|
||||
func InitializeLabels(ctx *context.Context, form auth.InitializeLabelsForm) {
|
||||
func InitializeLabels(ctx *context.Context, f form.InitializeLabels) {
|
||||
if ctx.HasError() {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/labels")
|
||||
return
|
||||
}
|
||||
list, err := models.GetLabelTemplateFile(form.TemplateName)
|
||||
list, err := models.GetLabelTemplateFile(f.TemplateName)
|
||||
if err != nil {
|
||||
ctx.Flash.Error(ctx.Tr("repo.issues.label_templates.fail_to_load_file", form.TemplateName, err))
|
||||
ctx.Flash.Error(ctx.Tr("repo.issues.label_templates.fail_to_load_file", f.TemplateName, err))
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/labels")
|
||||
return
|
||||
}
|
||||
@@ -982,7 +982,7 @@ func InitializeLabels(ctx *context.Context, form auth.InitializeLabelsForm) {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/labels")
|
||||
}
|
||||
|
||||
func NewLabel(ctx *context.Context, form auth.CreateLabelForm) {
|
||||
func NewLabel(ctx *context.Context, f form.CreateLabel) {
|
||||
ctx.Data["Title"] = ctx.Tr("repo.labels")
|
||||
ctx.Data["PageIsLabels"] = true
|
||||
|
||||
@@ -994,8 +994,8 @@ func NewLabel(ctx *context.Context, form auth.CreateLabelForm) {
|
||||
|
||||
l := &models.Label{
|
||||
RepoID: ctx.Repo.Repository.ID,
|
||||
Name: form.Title,
|
||||
Color: form.Color,
|
||||
Name: f.Title,
|
||||
Color: f.Color,
|
||||
}
|
||||
if err := models.NewLabels(l); err != nil {
|
||||
ctx.Handle(500, "NewLabel", err)
|
||||
@@ -1004,8 +1004,8 @@ func NewLabel(ctx *context.Context, form auth.CreateLabelForm) {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/labels")
|
||||
}
|
||||
|
||||
func UpdateLabel(ctx *context.Context, form auth.CreateLabelForm) {
|
||||
l, err := models.GetLabelByID(form.ID)
|
||||
func UpdateLabel(ctx *context.Context, f form.CreateLabel) {
|
||||
l, err := models.GetLabelByID(f.ID)
|
||||
if err != nil {
|
||||
switch {
|
||||
case models.IsErrLabelNotExist(err):
|
||||
@@ -1016,8 +1016,8 @@ func UpdateLabel(ctx *context.Context, form auth.CreateLabelForm) {
|
||||
return
|
||||
}
|
||||
|
||||
l.Name = form.Title
|
||||
l.Color = form.Color
|
||||
l.Name = f.Title
|
||||
l.Color = f.Color
|
||||
if err := models.UpdateLabel(l); err != nil {
|
||||
ctx.Handle(500, "UpdateLabel", err)
|
||||
return
|
||||
@@ -1090,7 +1090,7 @@ func NewMilestone(ctx *context.Context) {
|
||||
ctx.HTML(200, MILESTONE_NEW)
|
||||
}
|
||||
|
||||
func NewMilestonePost(ctx *context.Context, form auth.CreateMilestoneForm) {
|
||||
func NewMilestonePost(ctx *context.Context, f form.CreateMilestone) {
|
||||
ctx.Data["Title"] = ctx.Tr("repo.milestones.new")
|
||||
ctx.Data["PageIsIssueList"] = true
|
||||
ctx.Data["PageIsMilestones"] = true
|
||||
@@ -1102,27 +1102,27 @@ func NewMilestonePost(ctx *context.Context, form auth.CreateMilestoneForm) {
|
||||
return
|
||||
}
|
||||
|
||||
if len(form.Deadline) == 0 {
|
||||
form.Deadline = "9999-12-31"
|
||||
if len(f.Deadline) == 0 {
|
||||
f.Deadline = "9999-12-31"
|
||||
}
|
||||
deadline, err := time.ParseInLocation("2006-01-02", form.Deadline, time.Local)
|
||||
deadline, err := time.ParseInLocation("2006-01-02", f.Deadline, time.Local)
|
||||
if err != nil {
|
||||
ctx.Data["Err_Deadline"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("repo.milestones.invalid_due_date_format"), MILESTONE_NEW, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("repo.milestones.invalid_due_date_format"), MILESTONE_NEW, &f)
|
||||
return
|
||||
}
|
||||
|
||||
if err = models.NewMilestone(&models.Milestone{
|
||||
RepoID: ctx.Repo.Repository.ID,
|
||||
Name: form.Title,
|
||||
Content: form.Content,
|
||||
Name: f.Title,
|
||||
Content: f.Content,
|
||||
Deadline: deadline,
|
||||
}); err != nil {
|
||||
ctx.Handle(500, "NewMilestone", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Flash.Success(ctx.Tr("repo.milestones.create_success", form.Title))
|
||||
ctx.Flash.Success(ctx.Tr("repo.milestones.create_success", f.Title))
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/milestones")
|
||||
}
|
||||
|
||||
@@ -1150,7 +1150,7 @@ func EditMilestone(ctx *context.Context) {
|
||||
ctx.HTML(200, MILESTONE_NEW)
|
||||
}
|
||||
|
||||
func EditMilestonePost(ctx *context.Context, form auth.CreateMilestoneForm) {
|
||||
func EditMilestonePost(ctx *context.Context, f form.CreateMilestone) {
|
||||
ctx.Data["Title"] = ctx.Tr("repo.milestones.edit")
|
||||
ctx.Data["PageIsMilestones"] = true
|
||||
ctx.Data["PageIsEditMilestone"] = true
|
||||
@@ -1162,13 +1162,13 @@ func EditMilestonePost(ctx *context.Context, form auth.CreateMilestoneForm) {
|
||||
return
|
||||
}
|
||||
|
||||
if len(form.Deadline) == 0 {
|
||||
form.Deadline = "9999-12-31"
|
||||
if len(f.Deadline) == 0 {
|
||||
f.Deadline = "9999-12-31"
|
||||
}
|
||||
deadline, err := time.ParseInLocation("2006-01-02", form.Deadline, time.Local)
|
||||
deadline, err := time.ParseInLocation("2006-01-02", f.Deadline, time.Local)
|
||||
if err != nil {
|
||||
ctx.Data["Err_Deadline"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("repo.milestones.invalid_due_date_format"), MILESTONE_NEW, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("repo.milestones.invalid_due_date_format"), MILESTONE_NEW, &f)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1181,8 +1181,8 @@ func EditMilestonePost(ctx *context.Context, form auth.CreateMilestoneForm) {
|
||||
}
|
||||
return
|
||||
}
|
||||
m.Name = form.Title
|
||||
m.Content = form.Content
|
||||
m.Name = f.Title
|
||||
m.Content = f.Content
|
||||
m.Deadline = deadline
|
||||
if err = models.UpdateMilestone(m); err != nil {
|
||||
ctx.Handle(500, "UpdateMilestone", err)
|
||||
|
||||
@@ -15,9 +15,9 @@ import (
|
||||
"github.com/gogits/git-module"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/auth"
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/context"
|
||||
"github.com/gogits/gogs/modules/form"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
@@ -38,31 +38,27 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
func getForkRepository(ctx *context.Context) *models.Repository {
|
||||
forkRepo, err := models.GetRepositoryByID(ctx.ParamsInt64(":repoid"))
|
||||
func parseBaseRepository(ctx *context.Context) *models.Repository {
|
||||
baseRepo, err := models.GetRepositoryByID(ctx.ParamsInt64(":repoid"))
|
||||
if err != nil {
|
||||
if models.IsErrRepoNotExist(err) {
|
||||
ctx.Handle(404, "GetRepositoryByID", nil)
|
||||
} else {
|
||||
ctx.Handle(500, "GetRepositoryByID", err)
|
||||
}
|
||||
ctx.NotFoundOrServerError("GetRepositoryByID", models.IsErrRepoNotExist, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if !forkRepo.CanBeForked() || !forkRepo.HasAccess(ctx.User) {
|
||||
ctx.Handle(404, "getForkRepository", nil)
|
||||
if !baseRepo.CanBeForked() || !baseRepo.HasAccess(ctx.User.ID) {
|
||||
ctx.NotFound()
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx.Data["repo_name"] = forkRepo.Name
|
||||
ctx.Data["description"] = forkRepo.Description
|
||||
ctx.Data["IsPrivate"] = forkRepo.IsPrivate
|
||||
ctx.Data["repo_name"] = baseRepo.Name
|
||||
ctx.Data["description"] = baseRepo.Description
|
||||
ctx.Data["IsPrivate"] = baseRepo.IsPrivate
|
||||
|
||||
if err = forkRepo.GetOwner(); err != nil {
|
||||
if err = baseRepo.GetOwner(); err != nil {
|
||||
ctx.Handle(500, "GetOwner", err)
|
||||
return nil
|
||||
}
|
||||
ctx.Data["ForkFrom"] = forkRepo.Owner.Name + "/" + forkRepo.Name
|
||||
ctx.Data["ForkFrom"] = baseRepo.Owner.Name + "/" + baseRepo.Name
|
||||
|
||||
if err := ctx.User.GetOrganizations(true); err != nil {
|
||||
ctx.Handle(500, "GetOrganizations", err)
|
||||
@@ -70,13 +66,13 @@ func getForkRepository(ctx *context.Context) *models.Repository {
|
||||
}
|
||||
ctx.Data["Orgs"] = ctx.User.Orgs
|
||||
|
||||
return forkRepo
|
||||
return baseRepo
|
||||
}
|
||||
|
||||
func Fork(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("new_fork")
|
||||
|
||||
getForkRepository(ctx)
|
||||
parseBaseRepository(ctx)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
@@ -85,15 +81,15 @@ func Fork(ctx *context.Context) {
|
||||
ctx.HTML(200, FORK)
|
||||
}
|
||||
|
||||
func ForkPost(ctx *context.Context, form auth.CreateRepoForm) {
|
||||
func ForkPost(ctx *context.Context, f form.CreateRepo) {
|
||||
ctx.Data["Title"] = ctx.Tr("new_fork")
|
||||
|
||||
forkRepo := getForkRepository(ctx)
|
||||
baseRepo := parseBaseRepository(ctx)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
ctxUser := checkContextUser(ctx, form.Uid)
|
||||
ctxUser := checkContextUser(ctx, f.UserID)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
@@ -104,38 +100,42 @@ func ForkPost(ctx *context.Context, form auth.CreateRepoForm) {
|
||||
return
|
||||
}
|
||||
|
||||
repo, has := models.HasForkedRepo(ctxUser.ID, forkRepo.ID)
|
||||
repo, has := models.HasForkedRepo(ctxUser.ID, baseRepo.ID)
|
||||
if has {
|
||||
ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + repo.Name)
|
||||
ctx.Redirect(repo.Link())
|
||||
return
|
||||
}
|
||||
|
||||
// Check ownership of organization.
|
||||
if ctxUser.IsOrganization() {
|
||||
if !ctxUser.IsOwnedBy(ctx.User.ID) {
|
||||
ctx.Error(403)
|
||||
return
|
||||
}
|
||||
if ctxUser.IsOrganization() && !ctxUser.IsOwnedBy(ctx.User.ID) {
|
||||
ctx.Error(403)
|
||||
return
|
||||
}
|
||||
|
||||
repo, err := models.ForkRepository(ctxUser, forkRepo, form.RepoName, form.Description)
|
||||
// Cannot fork to same owner
|
||||
if ctxUser.ID == baseRepo.OwnerID {
|
||||
ctx.RenderWithErr(ctx.Tr("repo.settings.cannot_fork_to_same_owner"), FORK, &f)
|
||||
return
|
||||
}
|
||||
|
||||
repo, err := models.ForkRepository(ctx.User, ctxUser, baseRepo, f.RepoName, f.Description)
|
||||
if err != nil {
|
||||
ctx.Data["Err_RepoName"] = true
|
||||
switch {
|
||||
case models.IsErrRepoAlreadyExist(err):
|
||||
ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), FORK, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), FORK, &f)
|
||||
case models.IsErrNameReserved(err):
|
||||
ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(models.ErrNameReserved).Name), FORK, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(models.ErrNameReserved).Name), FORK, &f)
|
||||
case models.IsErrNamePatternNotAllowed(err):
|
||||
ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), FORK, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), FORK, &f)
|
||||
default:
|
||||
ctx.Handle(500, "ForkPost", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
log.Trace("Repository forked[%d]: %s/%s", forkRepo.ID, ctxUser.Name, repo.Name)
|
||||
ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + repo.Name)
|
||||
log.Trace("Repository forked from '%s' -> '%s'", baseRepo.FullName(), repo.FullName())
|
||||
ctx.Redirect(repo.Link())
|
||||
}
|
||||
|
||||
func checkPullInfo(ctx *context.Context) *models.Issue {
|
||||
@@ -626,10 +626,11 @@ func CompareAndPullRequest(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["IsSplitStyle"] = ctx.Query("style") == "split"
|
||||
ctx.HTML(200, COMPARE_PULL)
|
||||
}
|
||||
|
||||
func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm) {
|
||||
func CompareAndPullRequestPost(ctx *context.Context, f form.CreateIssue) {
|
||||
ctx.Data["Title"] = ctx.Tr("repo.pulls.compare_changes")
|
||||
ctx.Data["PageIsComparePull"] = true
|
||||
ctx.Data["IsDiffCompare"] = true
|
||||
@@ -646,17 +647,17 @@ func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm)
|
||||
return
|
||||
}
|
||||
|
||||
labelIDs, milestoneID, assigneeID := ValidateRepoMetas(ctx, form)
|
||||
labelIDs, milestoneID, assigneeID := ValidateRepoMetas(ctx, f)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
if setting.AttachmentEnabled {
|
||||
attachments = form.Files
|
||||
attachments = f.Files
|
||||
}
|
||||
|
||||
if ctx.HasError() {
|
||||
auth.AssignForm(form, ctx.Data)
|
||||
form.Assign(f, ctx.Data)
|
||||
|
||||
// This stage is already stop creating new pull request, so it does not matter if it has
|
||||
// something to compare or not.
|
||||
@@ -678,13 +679,13 @@ func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm)
|
||||
pullIssue := &models.Issue{
|
||||
RepoID: repo.ID,
|
||||
Index: repo.NextIssueIndex(),
|
||||
Title: form.Title,
|
||||
Title: f.Title,
|
||||
PosterID: ctx.User.ID,
|
||||
Poster: ctx.User,
|
||||
MilestoneID: milestoneID,
|
||||
AssigneeID: assigneeID,
|
||||
IsPull: true,
|
||||
Content: form.Content,
|
||||
Content: f.Content,
|
||||
}
|
||||
pullRequest := &models.PullRequest{
|
||||
HeadRepoID: headRepo.ID,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user