Compare commits

..

43 Commits

Author SHA1 Message Date
Unknwon
bb005f3f9a models/user: better directory handling when change username
Previously, if the user base directory somehow doesn't exist, the
application throws 500 for failure of rename.

Now it detects if the application should rename or just create a
new directory.
2017-03-07 14:12:19 -05:00
Unknwon
e6dbfd918c security: fix vulnerability in changing username
Reported by João Arnaut.
2017-03-07 14:07:20 -05:00
Unknwon
c2f0711db0 Update locale 2017-03-06 23:37:46 -05:00
Unknwon
92153fd898 git_hook: add new env var 'GOGS_AUTH_USER_EMAIL' (#4252) 2017-03-06 23:28:03 -05:00
Unknwon
a9d2480c7f templates/user/profile: fix link to avatar settings (#4251) 2017-03-06 23:23:37 -05:00
Unknwon
fd70d503e0 public: minor fixes on build tool config 2017-03-06 17:59:36 -05:00
Unknwon
8b73c8076f modules/markdown: fix wrong raw link to internal images 2017-03-05 16:54:00 -05:00
Unknwon
971a96a962 Revert "public: update Semantic UI from 2.2.7 -> 2.2.9"
This reverts commit eaab01fa49.
2017-03-05 16:35:35 -05:00
Unknwon
e9838a83ce routers/repo/http: only prompt HTTP Basic Authentication when intended
Sometimes user could simply request wrong URL, but if that wrong URL
has nothing related Git HTTP operations, HTTP Basic Authentication
should not prompted. Instead, clean 404 page should be presented.

The patch also supports Git HTTP operations without '.git' suffix
to the repository name, which addresses #4226 and #4189.
2017-03-04 21:26:32 -05:00
Fastidious
837fc9847d conf/gitignore: use correct OS name (#4240)
This is no more OSX, but macOS. Long live macOS!
2017-03-04 20:17:25 -05:00
Unknwon
7e883f891a scripts: update gogs.service (#4223)
According to https://goo.gl/ea8k9K, it hurts nothing to use
nonexistent services but gains convenient for default settings.
2017-03-04 11:40:37 -05:00
Félix MIKAELIAN
e19a69442d Update README.md (#4238) 2017-03-04 11:19:14 -05:00
Unknwon
ebd95dd082 models/org: reduce to 2 SQL executions for GetOrgIDsByUserID
This also addresses #4231. It is now ignoring nonexistent
organizations returned from 'org_user' table.
This was a bug caused in older version that didn't cleanup
'org_user' table when delete an organization.
2017-03-03 18:26:51 -05:00
Unknwon
f7b7d008b6 setting: fix Webhook.SkipTLSVerify didn't load (#4228) 2017-03-02 22:08:39 -05:00
Unknwon
b39454ca16 scripts: update gogs.service (#4223)
Add 'After=mariadb.service’.

[CI SKIP]
2017-03-02 12:21:31 -05:00
Bo-Yi Wu
00943a025f locale: update TRANSLATORS (#4224) 2017-03-02 11:37:14 -05:00
Unknwon
600f748cb0 vendor: update golang.org/x/crypto/ssh
Related to #4160
2017-03-01 21:33:58 -05:00
Unknwon
038b107c3d Update locale
Also fixes #4213
2017-03-01 12:31:04 -05:00
Unknwon
c6e08d76fd admin/config: minor CSS fix 2017-02-28 23:25:03 -05:00
Unknwon
6daac151b8 miniwinsvc: fix import path 2017-02-28 23:01:51 -05:00
Unknwon
e08161a302 hook: fix can’t be executed while run as service on Windows (#4207) 2017-02-28 22:58:52 -05:00
atzoum
341eafcf04 adapt Dockerfile.aarch64 (#4210) 2017-02-28 16:16:23 -05:00
Unknwon
dd649eb4cc admin: fix template error
Also a try to display key-value pairs in table.
2017-02-28 12:42:16 -05:00
Unknwon
d43f5f17fd webhook: fix push panic to organizational repository (#4206) 2017-02-28 10:28:48 -05:00
Corentin BRETON
193cc3ba9a locale: update TRANSLATORS (#4204) 2017-02-28 07:06:12 -05:00
Unknwon
fd667ca1d8 Merge branch 'master' of github.com:gogits/gogs into develop 2017-02-28 06:22:28 -05:00
Unknwon
9d40b8a83c Bump version 2017-02-28 05:45:50 -05:00
Unknwon
b0169ba064 Merge branch 'master' of github.com:gogits/gogs into develop 2017-02-28 05:34:51 -05:00
Unknwon
9ace35ee8b repo_branch: fix inapproriate logic 2017-02-28 05:33:30 -05:00
Unknwon
ca2cfaf71e cmd: able to backup and restore
Not very robust, must execute under correct workdir.

Addresses #2072, #3708, #648
2017-02-27 22:48:19 -05:00
Unknwon
b06f299748 webhook: add fork event 2017-02-27 22:48:18 -05:00
Unknwon
beea014343 template: add more icons for news feed 2017-02-27 22:47:33 -05:00
Unknwon
70072e2842 dashboard: add delete branch and tag news feeds 2017-02-27 22:47:33 -05:00
Unknwon
f0086e66ae webhook: able to detect delete branch or tag (#2315) 2017-02-27 22:47:21 -05:00
Unknwon
7fe13e72d8 cmd: refactoring command name 2017-02-27 22:47:12 -05:00
Unknwon
87f0ce793d repo: able to perform initial commit on behave of actual user 2017-02-27 22:47:12 -05:00
Unknwon
25cf755f30 editor: fix compile error 2017-02-27 22:46:42 -05:00
Unknwon
c7a8051a71 mailer: make text/html as default format
Change config option from '[mailer] ENABLE_HTML_ALTERNATIVE' to '[mailer] USE_PLAIN_TEXT'
2017-02-27 22:46:42 -05:00
Unknwon
a47553b7aa admin/config: remove duplicated config info 2017-02-27 22:46:32 -05:00
Unknwon
d7954014a4 markdown: fix links for image nested inside a link (#2636) 2017-02-27 22:46:32 -05:00
Unknwon
429345b9df editor: fix cannot create branch with slashes (#3568) 2017-02-27 22:46:32 -05:00
Unknwon
eaab01fa49 public: update Semantic UI from 2.2.7 -> 2.2.9 2017-02-27 22:45:35 -05:00
Unknwon
4f9c5981a9 refactoring: modules/auth/*_form.go -> modules/form 2017-02-27 22:45:35 -05:00
104 changed files with 3419 additions and 2784 deletions

4
.gitattributes vendored
View File

@@ -5,7 +5,7 @@ public/plugins/* linguist-vendored
public/plugins/* linguist-vendored
public/css/themes/* linguist-vendored
public/css/github.min.css linguist-vendored
public/css/semantic-2.2.9.min.css linguist-vendored
public/css/semantic-2.2.7.min.css linguist-vendored
public/js/libs/* linguist-vendored
public/js/jquery-1.11.3.min.js linguist-vendored
public/js/semantic-2.2.9.min.js linguist-vendored
public/js/semantic-2.2.7.min.js linguist-vendored

View File

@@ -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)

View File

@@ -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/"]

View File

@@ -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
View 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
}

View File

@@ -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{

View File

@@ -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`,

View File

@@ -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
}

View File

@@ -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",
@@ -117,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 {
@@ -131,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
@@ -159,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
@@ -231,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

View File

@@ -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
View 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
}

View File

@@ -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,26 +509,26 @@ 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)
m.Get("/edit/*", repo.EditRelease)
m.Post("/edit/*", bindIgnErr(auth.EditReleaseForm{}), repo.EditReleasePost)
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
@@ -536,22 +536,22 @@ func runWeb(ctx *cli.Context) error {
// 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()
@@ -584,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())
@@ -623,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 *****

View File

@@ -218,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"

View File

@@ -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

View File

@@ -18,6 +18,8 @@ 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

View File

@@ -654,7 +654,7 @@ 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=Fügt die Benutzer zu Whitelist hinzu, die in diesen Branch pushen dürfen
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
@@ -688,7 +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=You cannot fork a repository to its original owner.
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.
@@ -745,7 +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=Secret will be sent as SHA256 HMAC hex digest of payload via <code>X-Gogs-Signature</code> header.
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

View File

@@ -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.`
@@ -754,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
@@ -1176,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
@@ -1205,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

View File

@@ -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
@@ -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
@@ -688,7 +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=You cannot fork a repository to its original owner.
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.
@@ -745,7 +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=Secret will be sent as SHA256 HMAC hex digest of payload via <code>X-Gogs-Signature</code> header.
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
@@ -786,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.

View File

@@ -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

View File

@@ -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=Закрыть

View File

@@ -688,7 +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.cannot_fork_to_same_owner=Ви не можете клонувати репозиторій його ж власнику.
settings.new_owner_has_same_repo=Новий власник вже має репозиторій з такою назвою.
settings.convert=Перетворити на звичайний репозиторій
settings.convert_desc=Ви можете сконвертувати це дзеркало у звичайний репозиторій. Це не може бути повернуто.
@@ -745,7 +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.secret_desc=Секрет буде вислано SHA256 HMAC hex-сумою вміста у хідері <code>X-Gogs-Signature</code>.
settings.slack_username=Ім'я користувача
settings.slack_icon_url=URL іконки
settings.slack_color=Колір

View File

@@ -656,10 +656,10 @@ 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.protect_whitelist_users=Users who can push to this branch
settings.protect_whitelist_search_users=Search users
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=Search teams
settings.protect_whitelist_search_teams=搜尋團隊
settings.update_protect_branch_success=此分支設置保護已更新成功!
settings.hooks=管理 Web 鉤子
settings.githooks=管理 Git 鉤子

View File

@@ -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
View File

@@ -16,7 +16,7 @@ import (
"github.com/gogits/gogs/modules/setting"
)
const APP_VER = "0.10.0.0227"
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)

View File

@@ -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) {
@@ -458,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)
}
@@ -488,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)
}
}
@@ -533,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

View File

@@ -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
}

View File

@@ -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"
@@ -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
}

View File

@@ -20,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.
@@ -246,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
}
@@ -303,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) {

View File

@@ -628,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,
@@ -639,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
}
@@ -882,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)
@@ -908,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)
}
}
@@ -941,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 {
@@ -979,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)
}
@@ -989,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,
@@ -1012,14 +1012,14 @@ 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)
}
@@ -2068,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)
}
}
@@ -2161,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()
@@ -2187,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)
}
@@ -2212,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()

View File

@@ -125,7 +125,6 @@ func UpdateProtectBranch(protectBranch *ProtectBranch) (err error) {
if _, err = sess.Insert(protectBranch); err != nil {
return fmt.Errorf("Insert: %v", err)
}
return
}
if _, err = sess.Id(protectBranch.ID).AllCols().Update(protectBranch); err != nil {

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -63,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"`
}
@@ -156,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 ||
@@ -169,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
}
@@ -225,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.
@@ -283,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)
}
// ___ ___ __ ___________ __
@@ -337,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"
)
@@ -430,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
}
@@ -449,8 +471,8 @@ func UpdateHookTask(t *HookTask) error {
return err
}
// prepareWebhooks adds list of webhooks to task queue.
func prepareWebhooks(repo *Repository, event HookEventType, p api.Payloader, webhooks []*Webhook) (err error) {
// 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
}
@@ -462,6 +484,10 @@ func prepareWebhooks(repo *Repository, event HookEventType, p api.Payloader, web
if !w.HasCreateEvent() {
continue
}
case HOOK_EVENT_DELETE:
if !w.HasDeleteEvent() {
continue
}
case HOOK_EVENT_PUSH:
if !w.HasPushEvent() {
continue
@@ -499,7 +525,7 @@ func prepareWebhooks(repo *Repository, event HookEventType, p api.Payloader, web
signature = hex.EncodeToString(sig.Sum(nil))
}
if err = CreateHookTask(&HookTask{
if err = createHookTask(e, &HookTask{
RepoID: repo.ID,
HookID: w.ID,
Type: w.HookTaskType,
@@ -510,29 +536,37 @@ func prepareWebhooks(repo *Repository, event HookEventType, p api.Payloader, web
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 {
webhooks, err := GetActiveWebhooksByRepoID(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().IsOrganization() {
// get hooks for org
orgws, err := GetActiveWebhooksByOrgID(repo.OwnerID)
if err != nil {
return fmt.Errorf("GetActiveWebhooksByOrgID [%d]: %v", repo.OwnerID, err)
}
webhooks = append(webhooks, orgws...)
}
return prepareWebhooks(repo, event, p, webhooks)
return prepareWebhooks(x, repo, event, p)
}
// TestWebhook adds the test webhook matches the ID to task queue.
@@ -541,7 +575,7 @@ func TestWebhook(repo *Repository, event HookEventType, p api.Payloader, webhook
if err != nil {
return fmt.Errorf("GetWebhookOfRepoByID [repo_id: %d, id: %d]: %v", repo.ID, webhookID, err)
}
return prepareWebhooks(repo, event, p, []*Webhook{webhook})
return prepareHookTasks(x, repo, event, p, []*Webhook{webhook})
}
func (t *HookTask) deliver() {

View File

@@ -68,22 +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,
URL: setting.AppUrl + p.Sender.UserName,
Color: int(color),
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,
@@ -206,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
}

View File

@@ -69,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
}
@@ -178,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
}

View File

@@ -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
}

View File

@@ -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)
}

File diff suppressed because one or more lines are too long

View File

@@ -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

View File

@@ -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)
}

View File

@@ -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
View 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
View 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)
}

View File

@@ -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,7 +113,7 @@ func (f *RepoSettingForm) Validate(ctx *macaron.Context, errs binding.Errors) bi
// |______ / |__| (____ /___| /\___ >___| /
// \/ \/ \/ \/ \/
type ProtectBranchForm struct {
type ProtectBranch struct {
Protected bool
RequirePullRequest bool
EnableWhitelist bool
@@ -121,7 +121,7 @@ type ProtectBranchForm struct {
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)
}
@@ -132,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)
}
@@ -195,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
@@ -204,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)
}
@@ -225,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)
}
@@ -242,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)
}
@@ -267,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"`
@@ -276,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)
}
@@ -298,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"`
@@ -306,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)
}
@@ -317,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)
}
@@ -351,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
@@ -360,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)
}
@@ -383,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"
}

View File

@@ -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)
}

View File

@@ -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,

View File

@@ -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.

View File

@@ -7,7 +7,7 @@
package setting
import (
_ "github.com/kardianos/minwinsvc"
_ "github.com/gogits/minwinsvc"
)
func init() {

View File

@@ -142,7 +142,7 @@ var (
Types []string
QueueLength int
DeliverTimeout int
SkipTLSVerify bool
SkipTLSVerify bool `ini:"SKIP_TLS_VERIFY"`
PagingNum int
}
@@ -751,18 +751,18 @@ func newSessionService() {
// 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 (
@@ -777,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)

View File

@@ -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"
}

View File

@@ -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,
@@ -20,11 +20,11 @@
"outputPathIsOutsideProject": 0,
"outputPathIsSetByUser": 0
},
"\/css\/semantic-2.2.9.min.css": {
"\/css\/semantic-2.2.7.min.css": {
"fileType": 16,
"ignore": 1,
"ignoreWasSetByUser": 1,
"inputAbbreviatedPath": "\/css\/semantic-2.2.9.min.css",
"ignore": 0,
"ignoreWasSetByUser": 0,
"inputAbbreviatedPath": "\/css\/semantic-2.2.7.min.css",
"outputAbbreviatedPath": "No Output Path",
"outputPathIsOutsideProject": 0,
"outputPathIsSetByUser": 0
@@ -66,7 +66,7 @@
"fileType": 32768,
"ignore": 0,
"ignoreWasSetByUser": 0,
"initialSize": 514087,
"initialSize": 4048,
"inputAbbreviatedPath": "\/img\/avatar_default.png",
"outputAbbreviatedPath": "\/img\/avatar_default.png",
"outputPathIsOutsideProject": 0,
@@ -161,12 +161,12 @@
"outputStyle": 1,
"syntaxCheckerStyle": 1
},
"\/js\/semantic-2.2.9.min.js": {
"\/js\/semantic-2.2.7.min.js": {
"fileType": 64,
"ignore": 1,
"ignoreWasSetByUser": 1,
"inputAbbreviatedPath": "\/js\/semantic-2.2.9.min.js",
"outputAbbreviatedPath": "\/js\/min\/semantic-2.2.9.min-min.js",
"ignore": 0,
"ignoreWasSetByUser": 0,
"inputAbbreviatedPath": "\/js\/semantic-2.2.7.min.js",
"outputAbbreviatedPath": "\/js\/min\/semantic-2.2.7.min-min.js",
"outputPathIsOutsideProject": 0,
"outputPathIsSetByUser": 0,
"outputStyle": 1,

View File

@@ -2921,7 +2921,7 @@ footer .ui.language .menu {
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;
@@ -3019,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;

View File

@@ -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;
}
}
}
}
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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) {

View File

@@ -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)
}

View File

@@ -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"
@@ -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)

View File

@@ -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}))
}

View File

@@ -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")
}

View File

@@ -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")
}

View File

@@ -10,9 +10,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/setting"
"github.com/gogits/gogs/routers/user"
)
@@ -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"))

View File

@@ -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)
}

View File

@@ -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.Repo.PullRequest.Allowed {
ctx.Redirect(ctx.Repo.PullRequestURL(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.Repo.PullRequest.Allowed {
ctx.Redirect(ctx.Repo.PullRequestURL(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.Repo.PullRequest.Allowed {
ctx.Redirect(ctx.Repo.PullRequestURL(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)
}

View File

@@ -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 {
@@ -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),

View File

@@ -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)

View File

@@ -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.ID) {
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,44 +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
}
}
// Cannot fork to same owner
if ctxUser.ID == forkRepo.OwnerID {
ctx.RenderWithErr(ctx.Tr("repo.settings.cannot_fork_to_same_owner"), FORK, &form)
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 {
@@ -636,7 +630,7 @@ func CompareAndPullRequest(ctx *context.Context) {
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
@@ -653,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.
@@ -685,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,

View File

@@ -10,9 +10,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"
)
@@ -150,7 +150,7 @@ func NewRelease(ctx *context.Context) {
ctx.HTML(200, RELEASE_NEW)
}
func NewReleasePost(ctx *context.Context, form auth.NewReleaseForm) {
func NewReleasePost(ctx *context.Context, f form.NewRelease) {
ctx.Data["Title"] = ctx.Tr("repo.release.new_release")
ctx.Data["PageIsReleaseList"] = true
@@ -159,13 +159,13 @@ func NewReleasePost(ctx *context.Context, form auth.NewReleaseForm) {
return
}
if !ctx.Repo.GitRepo.IsBranchExist(form.Target) {
ctx.RenderWithErr(ctx.Tr("form.target_branch_not_exist"), RELEASE_NEW, &form)
if !ctx.Repo.GitRepo.IsBranchExist(f.Target) {
ctx.RenderWithErr(ctx.Tr("form.target_branch_not_exist"), RELEASE_NEW, &f)
return
}
var tagCreatedUnix int64
tag, err := ctx.Repo.GitRepo.GetTag(form.TagName)
tag, err := ctx.Repo.GitRepo.GetTag(f.TagName)
if err == nil {
commit, err := tag.Commit()
if err == nil {
@@ -173,7 +173,7 @@ func NewReleasePost(ctx *context.Context, form auth.NewReleaseForm) {
}
}
commit, err := ctx.Repo.GitRepo.GetBranchCommit(form.Target)
commit, err := ctx.Repo.GitRepo.GetBranchCommit(f.Target)
if err != nil {
ctx.Handle(500, "GetBranchCommit", err)
return
@@ -188,14 +188,14 @@ func NewReleasePost(ctx *context.Context, form auth.NewReleaseForm) {
rel := &models.Release{
RepoID: ctx.Repo.Repository.ID,
PublisherID: ctx.User.ID,
Title: form.Title,
TagName: form.TagName,
Target: form.Target,
Title: f.Title,
TagName: f.TagName,
Target: f.Target,
Sha1: commit.ID.String(),
NumCommits: commitsCount,
Note: form.Content,
IsDraft: len(form.Draft) > 0,
IsPrerelease: form.Prerelease,
Note: f.Content,
IsDraft: len(f.Draft) > 0,
IsPrerelease: f.Prerelease,
CreatedUnix: tagCreatedUnix,
}
@@ -203,15 +203,15 @@ func NewReleasePost(ctx *context.Context, form auth.NewReleaseForm) {
ctx.Data["Err_TagName"] = true
switch {
case models.IsErrReleaseAlreadyExist(err):
ctx.RenderWithErr(ctx.Tr("repo.release.tag_name_already_exist"), RELEASE_NEW, &form)
ctx.RenderWithErr(ctx.Tr("repo.release.tag_name_already_exist"), RELEASE_NEW, &f)
case models.IsErrInvalidTagName(err):
ctx.RenderWithErr(ctx.Tr("repo.release.tag_name_invalid"), RELEASE_NEW, &form)
ctx.RenderWithErr(ctx.Tr("repo.release.tag_name_invalid"), RELEASE_NEW, &f)
default:
ctx.Handle(500, "CreateRelease", err)
}
return
}
log.Trace("Release created: %s/%s:%s", ctx.User.LowerName, ctx.Repo.Repository.Name, form.TagName)
log.Trace("Release created: %s/%s:%s", ctx.User.LowerName, ctx.Repo.Repository.Name, f.TagName)
ctx.Redirect(ctx.Repo.RepoLink + "/releases")
}
@@ -242,7 +242,7 @@ func EditRelease(ctx *context.Context) {
ctx.HTML(200, RELEASE_NEW)
}
func EditReleasePost(ctx *context.Context, form auth.EditReleaseForm) {
func EditReleasePost(ctx *context.Context, f form.EditRelease) {
ctx.Data["Title"] = ctx.Tr("repo.release.edit_release")
ctx.Data["PageIsReleaseList"] = true
ctx.Data["PageIsEditRelease"] = true
@@ -269,10 +269,10 @@ func EditReleasePost(ctx *context.Context, form auth.EditReleaseForm) {
return
}
rel.Title = form.Title
rel.Note = form.Content
rel.IsDraft = len(form.Draft) > 0
rel.IsPrerelease = form.Prerelease
rel.Title = f.Title
rel.Note = f.Content
rel.IsDraft = len(f.Draft) > 0
rel.IsPrerelease = f.Prerelease
if err = models.UpdateRelease(ctx.Repo.GitRepo, rel); err != nil {
ctx.Handle(500, "UpdateRelease", err)
return

View File

@@ -16,9 +16,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"
)
@@ -102,14 +102,14 @@ func handleCreateError(ctx *context.Context, owner *models.User, err error, name
}
}
func CreatePost(ctx *context.Context, form auth.CreateRepoForm) {
func CreatePost(ctx *context.Context, f form.CreateRepo) {
ctx.Data["Title"] = ctx.Tr("new_repo")
ctx.Data["Gitignores"] = models.Gitignores
ctx.Data["Licenses"] = models.Licenses
ctx.Data["Readmes"] = models.Readmes
ctxUser := checkContextUser(ctx, form.Uid)
ctxUser := checkContextUser(ctx, f.UserID)
if ctx.Written() {
return
}
@@ -120,14 +120,14 @@ func CreatePost(ctx *context.Context, form auth.CreateRepoForm) {
return
}
repo, err := models.CreateRepository(ctxUser, models.CreateRepoOptions{
Name: form.RepoName,
Description: form.Description,
Gitignores: form.Gitignores,
License: form.License,
Readme: form.Readme,
IsPrivate: form.Private || setting.Repository.ForcePrivate,
AutoInit: form.AutoInit,
repo, err := models.CreateRepository(ctx.User, ctxUser, models.CreateRepoOptions{
Name: f.RepoName,
Description: f.Description,
Gitignores: f.Gitignores,
License: f.License,
Readme: f.Readme,
IsPrivate: f.Private || setting.Repository.ForcePrivate,
AutoInit: f.AutoInit,
})
if err == nil {
log.Trace("Repository created [%d]: %s/%s", repo.ID, ctxUser.Name, repo.Name)
@@ -141,7 +141,7 @@ func CreatePost(ctx *context.Context, form auth.CreateRepoForm) {
}
}
handleCreateError(ctx, ctxUser, err, "CreatePost", CREATE, &form)
handleCreateError(ctx, ctxUser, err, "CreatePost", CREATE, &f)
}
func Migrate(ctx *context.Context) {
@@ -159,10 +159,10 @@ func Migrate(ctx *context.Context) {
ctx.HTML(200, MIGRATE)
}
func MigratePost(ctx *context.Context, form auth.MigrateRepoForm) {
func MigratePost(ctx *context.Context, f form.MigrateRepo) {
ctx.Data["Title"] = ctx.Tr("new_migrate")
ctxUser := checkContextUser(ctx, form.Uid)
ctxUser := checkContextUser(ctx, f.Uid)
if ctx.Written() {
return
}
@@ -173,18 +173,18 @@ func MigratePost(ctx *context.Context, form auth.MigrateRepoForm) {
return
}
remoteAddr, err := form.ParseRemoteAddr(ctx.User)
remoteAddr, err := f.ParseRemoteAddr(ctx.User)
if err != nil {
if models.IsErrInvalidCloneAddr(err) {
ctx.Data["Err_CloneAddr"] = true
addrErr := err.(models.ErrInvalidCloneAddr)
switch {
case addrErr.IsURLError:
ctx.RenderWithErr(ctx.Tr("form.url_error"), MIGRATE, &form)
ctx.RenderWithErr(ctx.Tr("form.url_error"), MIGRATE, &f)
case addrErr.IsPermissionDenied:
ctx.RenderWithErr(ctx.Tr("repo.migrate.permission_denied"), MIGRATE, &form)
ctx.RenderWithErr(ctx.Tr("repo.migrate.permission_denied"), MIGRATE, &f)
case addrErr.IsInvalidPath:
ctx.RenderWithErr(ctx.Tr("repo.migrate.invalid_local_path"), MIGRATE, &form)
ctx.RenderWithErr(ctx.Tr("repo.migrate.invalid_local_path"), MIGRATE, &f)
default:
ctx.Handle(500, "Unknown error", err)
}
@@ -194,16 +194,16 @@ func MigratePost(ctx *context.Context, 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 {
log.Trace("Repository migrated [%d]: %s/%s", repo.ID, ctxUser.Name, form.RepoName)
ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + form.RepoName)
log.Trace("Repository migrated [%d]: %s/%s", repo.ID, ctxUser.Name, f.RepoName)
ctx.Redirect(setting.AppSubUrl + "/" + ctxUser.Name + "/" + f.RepoName)
return
}
@@ -216,15 +216,15 @@ func MigratePost(ctx *context.Context, form auth.MigrateRepoForm) {
if strings.Contains(err.Error(), "Authentication failed") ||
strings.Contains(err.Error(), "could not read Username") {
ctx.Data["Err_Auth"] = true
ctx.RenderWithErr(ctx.Tr("form.auth_failed", models.HandleCloneUserCredentials(err.Error(), true)), MIGRATE, &form)
ctx.RenderWithErr(ctx.Tr("form.auth_failed", models.HandleCloneUserCredentials(err.Error(), true)), MIGRATE, &f)
return
} else if strings.Contains(err.Error(), "fatal:") {
ctx.Data["Err_CloneAddr"] = true
ctx.RenderWithErr(ctx.Tr("repo.migrate.failed", models.HandleCloneUserCredentials(err.Error(), true)), MIGRATE, &form)
ctx.RenderWithErr(ctx.Tr("repo.migrate.failed", models.HandleCloneUserCredentials(err.Error(), true)), MIGRATE, &f)
return
}
handleCreateError(ctx, ctxUser, err, "MigratePost", MIGRATE, &form)
handleCreateError(ctx, ctxUser, err, "MigratePost", MIGRATE, &f)
}
func Action(ctx *context.Context) {

View File

@@ -14,9 +14,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/mailer"
"github.com/gogits/gogs/modules/setting"
)
@@ -37,7 +37,7 @@ func Settings(ctx *context.Context) {
ctx.HTML(200, SETTINGS_OPTIONS)
}
func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
func SettingsPost(ctx *context.Context, f form.RepoSetting) {
ctx.Data["Title"] = ctx.Tr("repo.settings")
ctx.Data["PageIsSettingsOptions"] = true
@@ -52,7 +52,7 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
isNameChanged := false
oldRepoName := repo.Name
newRepoName := form.RepoName
newRepoName := f.RepoName
// Check if repository name has been changed.
if repo.LowerName != strings.ToLower(newRepoName) {
isNameChanged = true
@@ -60,11 +60,11 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
ctx.Data["Err_RepoName"] = true
switch {
case models.IsErrRepoAlreadyExist(err):
ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), SETTINGS_OPTIONS, &form)
ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), SETTINGS_OPTIONS, &f)
case models.IsErrNameReserved(err):
ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(models.ErrNameReserved).Name), SETTINGS_OPTIONS, &form)
ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(models.ErrNameReserved).Name), SETTINGS_OPTIONS, &f)
case models.IsErrNamePatternNotAllowed(err):
ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), SETTINGS_OPTIONS, &form)
ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), SETTINGS_OPTIONS, &f)
default:
ctx.Handle(500, "ChangeRepositoryName", err)
}
@@ -77,16 +77,16 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
repo.Name = newRepoName
repo.LowerName = strings.ToLower(newRepoName)
repo.Description = form.Description
repo.Website = form.Website
repo.Description = f.Description
repo.Website = f.Website
// Visibility of forked repository is forced sync with base repository.
if repo.IsFork {
form.Private = repo.BaseRepo.IsPrivate
f.Private = repo.BaseRepo.IsPrivate
}
visibilityChanged := repo.IsPrivate != form.Private
repo.IsPrivate = form.Private
visibilityChanged := repo.IsPrivate != f.Private
repo.IsPrivate = f.Private
if err := models.UpdateRepository(repo, visibilityChanged); err != nil {
ctx.Handle(500, "UpdateRepository", err)
return
@@ -108,16 +108,16 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
return
}
if form.Interval > 0 {
ctx.Repo.Mirror.EnablePrune = form.EnablePrune
ctx.Repo.Mirror.Interval = form.Interval
ctx.Repo.Mirror.NextUpdate = time.Now().Add(time.Duration(form.Interval) * time.Hour)
if f.Interval > 0 {
ctx.Repo.Mirror.EnablePrune = f.EnablePrune
ctx.Repo.Mirror.Interval = f.Interval
ctx.Repo.Mirror.NextUpdate = time.Now().Add(time.Duration(f.Interval) * time.Hour)
if err := models.UpdateMirror(ctx.Repo.Mirror); err != nil {
ctx.Handle(500, "UpdateMirror", err)
return
}
}
if err := ctx.Repo.Mirror.SaveAddress(form.MirrorAddress); err != nil {
if err := ctx.Repo.Mirror.SaveAddress(f.MirrorAddress); err != nil {
ctx.Handle(500, "SaveAddress", err)
return
}
@@ -136,15 +136,15 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
ctx.Redirect(repo.Link() + "/settings")
case "advanced":
repo.EnableWiki = form.EnableWiki
repo.EnableExternalWiki = form.EnableExternalWiki
repo.ExternalWikiURL = form.ExternalWikiURL
repo.EnableIssues = form.EnableIssues
repo.EnableExternalTracker = form.EnableExternalTracker
repo.ExternalTrackerURL = form.ExternalTrackerURL
repo.ExternalTrackerFormat = form.TrackerURLFormat
repo.ExternalTrackerStyle = form.TrackerIssueStyle
repo.EnablePulls = form.EnablePulls
repo.EnableWiki = f.EnableWiki
repo.EnableExternalWiki = f.EnableExternalWiki
repo.ExternalWikiURL = f.ExternalWikiURL
repo.EnableIssues = f.EnableIssues
repo.EnableExternalTracker = f.EnableExternalTracker
repo.ExternalTrackerURL = f.ExternalTrackerURL
repo.ExternalTrackerFormat = f.TrackerURLFormat
repo.ExternalTrackerStyle = f.TrackerIssueStyle
repo.EnablePulls = f.EnablePulls
if err := models.UpdateRepository(repo, false); err != nil {
ctx.Handle(500, "UpdateRepository", err)
@@ -160,7 +160,7 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
ctx.Error(404)
return
}
if repo.Name != form.RepoName {
if repo.Name != f.RepoName {
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), SETTINGS_OPTIONS, nil)
return
}
@@ -194,7 +194,7 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
ctx.Error(404)
return
}
if repo.Name != form.RepoName {
if repo.Name != f.RepoName {
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), SETTINGS_OPTIONS, nil)
return
}
@@ -233,7 +233,7 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
ctx.Error(404)
return
}
if repo.Name != form.RepoName {
if repo.Name != f.RepoName {
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), SETTINGS_OPTIONS, nil)
return
}
@@ -259,7 +259,7 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
ctx.Error(404)
return
}
if repo.Name != form.RepoName {
if repo.Name != f.RepoName {
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), SETTINGS_OPTIONS, nil)
return
}
@@ -444,7 +444,7 @@ func SettingsProtectedBranch(ctx *context.Context) {
ctx.HTML(200, SETTINGS_PROTECTED_BRANCH)
}
func SettingsProtectedBranchPost(ctx *context.Context, form auth.ProtectBranchForm) {
func SettingsProtectedBranchPost(ctx *context.Context, f form.ProtectBranch) {
branch := ctx.Params("*")
if !ctx.Repo.GitRepo.IsBranchExist(branch) {
ctx.NotFound()
@@ -465,11 +465,11 @@ func SettingsProtectedBranchPost(ctx *context.Context, form auth.ProtectBranchFo
}
}
protectBranch.Protected = form.Protected
protectBranch.RequirePullRequest = form.RequirePullRequest
protectBranch.EnableWhitelist = form.EnableWhitelist
protectBranch.Protected = f.Protected
protectBranch.RequirePullRequest = f.RequirePullRequest
protectBranch.EnableWhitelist = f.EnableWhitelist
if ctx.Repo.Owner.IsOrganization() {
err = models.UpdateOrgProtectBranch(ctx.Repo.Repository, protectBranch, form.WhitelistUsers, form.WhitelistTeams)
err = models.UpdateOrgProtectBranch(ctx.Repo.Repository, protectBranch, f.WhitelistUsers, f.WhitelistTeams)
} else {
err = models.UpdateProtectBranch(protectBranch)
}
@@ -547,7 +547,7 @@ func SettingsDeployKeys(ctx *context.Context) {
ctx.HTML(200, SETTINGS_DEPLOY_KEYS)
}
func SettingsDeployKeysPost(ctx *context.Context, form auth.AddSSHKeyForm) {
func SettingsDeployKeysPost(ctx *context.Context, f form.AddSSHKey) {
ctx.Data["Title"] = ctx.Tr("repo.settings.deploy_keys")
ctx.Data["PageIsSettingsKeys"] = true
@@ -563,7 +563,7 @@ func SettingsDeployKeysPost(ctx *context.Context, form auth.AddSSHKeyForm) {
return
}
content, err := models.CheckPublicKeyString(form.Content)
content, err := models.CheckPublicKeyString(f.Content)
if err != nil {
if models.IsErrKeyUnableVerify(err) {
ctx.Flash.Info(ctx.Tr("form.unable_verify_ssh_key"))
@@ -576,16 +576,16 @@ func SettingsDeployKeysPost(ctx *context.Context, form auth.AddSSHKeyForm) {
}
}
key, err := models.AddDeployKey(ctx.Repo.Repository.ID, form.Title, content)
key, err := models.AddDeployKey(ctx.Repo.Repository.ID, f.Title, content)
if err != nil {
ctx.Data["HasError"] = true
switch {
case models.IsErrKeyAlreadyExist(err):
ctx.Data["Err_Content"] = true
ctx.RenderWithErr(ctx.Tr("repo.settings.key_been_used"), SETTINGS_DEPLOY_KEYS, &form)
ctx.RenderWithErr(ctx.Tr("repo.settings.key_been_used"), SETTINGS_DEPLOY_KEYS, &f)
case models.IsErrKeyNameAlreadyUsed(err):
ctx.Data["Err_Title"] = true
ctx.RenderWithErr(ctx.Tr("repo.settings.key_name_used"), SETTINGS_DEPLOY_KEYS, &form)
ctx.RenderWithErr(ctx.Tr("repo.settings.key_name_used"), SETTINGS_DEPLOY_KEYS, &f)
default:
ctx.Handle(500, "AddDeployKey", err)
}

View File

@@ -16,9 +16,9 @@ import (
api "github.com/gogits/go-gogs-client"
"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"
)
@@ -103,20 +103,22 @@ func WebhooksNew(ctx *context.Context) {
ctx.HTML(200, orCtx.NewTemplate)
}
func ParseHookEvent(form auth.WebhookForm) *models.HookEvent {
func ParseHookEvent(f form.Webhook) *models.HookEvent {
return &models.HookEvent{
PushOnly: form.PushOnly(),
SendEverything: form.SendEverything(),
ChooseEvents: form.ChooseEvents(),
PushOnly: f.PushOnly(),
SendEverything: f.SendEverything(),
ChooseEvents: f.ChooseEvents(),
HookEvents: models.HookEvents{
Create: form.Create,
Push: form.Push,
PullRequest: form.PullRequest,
Create: f.Create,
Delete: f.Delete,
Fork: f.Fork,
Push: f.Push,
PullRequest: f.PullRequest,
},
}
}
func WebHooksNewPost(ctx *context.Context, form auth.NewWebhookForm) {
func WebHooksNewPost(ctx *context.Context, f form.NewWebhook) {
ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook")
ctx.Data["PageIsSettingsHooks"] = true
ctx.Data["PageIsSettingsHooksNew"] = true
@@ -136,17 +138,17 @@ func WebHooksNewPost(ctx *context.Context, form auth.NewWebhookForm) {
}
contentType := models.JSON
if models.HookContentType(form.ContentType) == models.FORM {
if models.HookContentType(f.ContentType) == models.FORM {
contentType = models.FORM
}
w := &models.Webhook{
RepoID: orCtx.RepoID,
URL: form.PayloadURL,
URL: f.PayloadURL,
ContentType: contentType,
Secret: form.Secret,
HookEvent: ParseHookEvent(form.WebhookForm),
IsActive: form.Active,
Secret: f.Secret,
HookEvent: ParseHookEvent(f.Webhook),
IsActive: f.Active,
HookTaskType: models.GOGS,
OrgID: orCtx.OrgID,
}
@@ -162,7 +164,7 @@ func WebHooksNewPost(ctx *context.Context, form auth.NewWebhookForm) {
ctx.Redirect(orCtx.Link + "/settings/hooks")
}
func SlackHooksNewPost(ctx *context.Context, form auth.NewSlackHookForm) {
func SlackHooksNewPost(ctx *context.Context, f form.NewSlackHook) {
ctx.Data["Title"] = ctx.Tr("repo.settings")
ctx.Data["PageIsSettingsHooks"] = true
ctx.Data["PageIsSettingsHooksNew"] = true
@@ -180,10 +182,10 @@ func SlackHooksNewPost(ctx *context.Context, form auth.NewSlackHookForm) {
}
meta, err := json.Marshal(&models.SlackMeta{
Channel: form.Channel,
Username: form.Username,
IconURL: form.IconURL,
Color: form.Color,
Channel: f.Channel,
Username: f.Username,
IconURL: f.IconURL,
Color: f.Color,
})
if err != nil {
ctx.Handle(500, "Marshal", err)
@@ -192,10 +194,10 @@ func SlackHooksNewPost(ctx *context.Context, form auth.NewSlackHookForm) {
w := &models.Webhook{
RepoID: orCtx.RepoID,
URL: form.PayloadURL,
URL: f.PayloadURL,
ContentType: models.JSON,
HookEvent: ParseHookEvent(form.WebhookForm),
IsActive: form.Active,
HookEvent: ParseHookEvent(f.Webhook),
IsActive: f.Active,
HookTaskType: models.SLACK,
Meta: string(meta),
OrgID: orCtx.OrgID,
@@ -213,7 +215,7 @@ func SlackHooksNewPost(ctx *context.Context, form auth.NewSlackHookForm) {
}
// FIXME: merge logic to Slack
func DiscordHooksNewPost(ctx *context.Context, form auth.NewDiscordHookForm) {
func DiscordHooksNewPost(ctx *context.Context, f form.NewDiscordHook) {
ctx.Data["Title"] = ctx.Tr("repo.settings")
ctx.Data["PageIsSettingsHooks"] = true
ctx.Data["PageIsSettingsHooksNew"] = true
@@ -231,9 +233,9 @@ func DiscordHooksNewPost(ctx *context.Context, form auth.NewDiscordHookForm) {
}
meta, err := json.Marshal(&models.SlackMeta{
Username: form.Username,
IconURL: form.IconURL,
Color: form.Color,
Username: f.Username,
IconURL: f.IconURL,
Color: f.Color,
})
if err != nil {
ctx.Handle(500, "Marshal", err)
@@ -242,10 +244,10 @@ func DiscordHooksNewPost(ctx *context.Context, form auth.NewDiscordHookForm) {
w := &models.Webhook{
RepoID: orCtx.RepoID,
URL: form.PayloadURL,
URL: f.PayloadURL,
ContentType: models.JSON,
HookEvent: ParseHookEvent(form.WebhookForm),
IsActive: form.Active,
HookEvent: ParseHookEvent(f.Webhook),
IsActive: f.Active,
HookTaskType: models.DISCORD,
Meta: string(meta),
OrgID: orCtx.OrgID,
@@ -319,7 +321,7 @@ func WebHooksEdit(ctx *context.Context) {
ctx.HTML(200, orCtx.NewTemplate)
}
func WebHooksEditPost(ctx *context.Context, form auth.NewWebhookForm) {
func WebHooksEditPost(ctx *context.Context, f form.NewWebhook) {
ctx.Data["Title"] = ctx.Tr("repo.settings.update_webhook")
ctx.Data["PageIsSettingsHooks"] = true
ctx.Data["PageIsSettingsHooksEdit"] = true
@@ -336,15 +338,15 @@ func WebHooksEditPost(ctx *context.Context, form auth.NewWebhookForm) {
}
contentType := models.JSON
if models.HookContentType(form.ContentType) == models.FORM {
if models.HookContentType(f.ContentType) == models.FORM {
contentType = models.FORM
}
w.URL = form.PayloadURL
w.URL = f.PayloadURL
w.ContentType = contentType
w.Secret = form.Secret
w.HookEvent = ParseHookEvent(form.WebhookForm)
w.IsActive = form.Active
w.Secret = f.Secret
w.HookEvent = ParseHookEvent(f.Webhook)
w.IsActive = f.Active
if err := w.UpdateEvent(); err != nil {
ctx.Handle(500, "UpdateEvent", err)
return
@@ -357,7 +359,7 @@ func WebHooksEditPost(ctx *context.Context, form auth.NewWebhookForm) {
ctx.Redirect(fmt.Sprintf("%s/settings/hooks/%d", orCtx.Link, w.ID))
}
func SlackHooksEditPost(ctx *context.Context, form auth.NewSlackHookForm) {
func SlackHooksEditPost(ctx *context.Context, f form.NewSlackHook) {
ctx.Data["Title"] = ctx.Tr("repo.settings")
ctx.Data["PageIsSettingsHooks"] = true
ctx.Data["PageIsSettingsHooksEdit"] = true
@@ -374,20 +376,20 @@ func SlackHooksEditPost(ctx *context.Context, form auth.NewSlackHookForm) {
}
meta, err := json.Marshal(&models.SlackMeta{
Channel: form.Channel,
Username: form.Username,
IconURL: form.IconURL,
Color: form.Color,
Channel: f.Channel,
Username: f.Username,
IconURL: f.IconURL,
Color: f.Color,
})
if err != nil {
ctx.Handle(500, "Marshal", err)
return
}
w.URL = form.PayloadURL
w.URL = f.PayloadURL
w.Meta = string(meta)
w.HookEvent = ParseHookEvent(form.WebhookForm)
w.IsActive = form.Active
w.HookEvent = ParseHookEvent(f.Webhook)
w.IsActive = f.Active
if err := w.UpdateEvent(); err != nil {
ctx.Handle(500, "UpdateEvent", err)
return
@@ -401,7 +403,7 @@ func SlackHooksEditPost(ctx *context.Context, form auth.NewSlackHookForm) {
}
// FIXME: merge logic to Slack
func DiscordHooksEditPost(ctx *context.Context, form auth.NewDiscordHookForm) {
func DiscordHooksEditPost(ctx *context.Context, f form.NewDiscordHook) {
ctx.Data["Title"] = ctx.Tr("repo.settings")
ctx.Data["PageIsSettingsHooks"] = true
ctx.Data["PageIsSettingsHooksEdit"] = true
@@ -418,19 +420,19 @@ func DiscordHooksEditPost(ctx *context.Context, form auth.NewDiscordHookForm) {
}
meta, err := json.Marshal(&models.SlackMeta{
Username: form.Username,
IconURL: form.IconURL,
Color: form.Color,
Username: f.Username,
IconURL: f.IconURL,
Color: f.Color,
})
if err != nil {
ctx.Handle(500, "Marshal", err)
return
}
w.URL = form.PayloadURL
w.URL = f.PayloadURL
w.Meta = string(meta)
w.HookEvent = ParseHookEvent(form.WebhookForm)
w.IsActive = form.Active
w.HookEvent = ParseHookEvent(f.Webhook)
w.IsActive = f.Active
if err := w.UpdateEvent(); err != nil {
ctx.Handle(500, "UpdateEvent", err)
return

View File

@@ -12,9 +12,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/markdown"
)
@@ -198,7 +198,7 @@ func NewWiki(ctx *context.Context) {
ctx.HTML(200, WIKI_NEW)
}
func NewWikiPost(ctx *context.Context, form auth.NewWikiForm) {
func NewWikiPost(ctx *context.Context, f form.NewWiki) {
ctx.Data["Title"] = ctx.Tr("repo.wiki.new_page")
ctx.Data["PageIsWiki"] = true
ctx.Data["RequireSimpleMDE"] = true
@@ -208,17 +208,17 @@ func NewWikiPost(ctx *context.Context, form auth.NewWikiForm) {
return
}
if err := ctx.Repo.Repository.AddWikiPage(ctx.User, form.Title, form.Content, form.Message); err != nil {
if err := ctx.Repo.Repository.AddWikiPage(ctx.User, f.Title, f.Content, f.Message); err != nil {
if models.IsErrWikiAlreadyExist(err) {
ctx.Data["Err_Title"] = true
ctx.RenderWithErr(ctx.Tr("repo.wiki.page_already_exists"), WIKI_NEW, &form)
ctx.RenderWithErr(ctx.Tr("repo.wiki.page_already_exists"), WIKI_NEW, &f)
} else {
ctx.Handle(500, "AddWikiPage", err)
}
return
}
ctx.Redirect(ctx.Repo.RepoLink + "/wiki/" + models.ToWikiPageURL(models.ToWikiPageName(form.Title)))
ctx.Redirect(ctx.Repo.RepoLink + "/wiki/" + models.ToWikiPageURL(models.ToWikiPageName(f.Title)))
}
func EditWiki(ctx *context.Context) {
@@ -239,7 +239,7 @@ func EditWiki(ctx *context.Context) {
ctx.HTML(200, WIKI_NEW)
}
func EditWikiPost(ctx *context.Context, form auth.NewWikiForm) {
func EditWikiPost(ctx *context.Context, f form.NewWiki) {
ctx.Data["Title"] = ctx.Tr("repo.wiki.new_page")
ctx.Data["PageIsWiki"] = true
ctx.Data["RequireSimpleMDE"] = true
@@ -249,12 +249,12 @@ func EditWikiPost(ctx *context.Context, form auth.NewWikiForm) {
return
}
if err := ctx.Repo.Repository.EditWikiPage(ctx.User, form.OldTitle, form.Title, form.Content, form.Message); err != nil {
if err := ctx.Repo.Repository.EditWikiPage(ctx.User, f.OldTitle, f.Title, f.Content, f.Message); err != nil {
ctx.Handle(500, "EditWikiPage", err)
return
}
ctx.Redirect(ctx.Repo.RepoLink + "/wiki/" + models.ToWikiPageURL(models.ToWikiPageName(form.Title)))
ctx.Redirect(ctx.Repo.RepoLink + "/wiki/" + models.ToWikiPageURL(models.ToWikiPageName(f.Title)))
}
func DeleteWikiPagePost(ctx *context.Context) {

View File

@@ -12,9 +12,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"
)
@@ -103,7 +103,7 @@ func SignIn(ctx *context.Context) {
ctx.HTML(200, SIGNIN)
}
func SignInPost(ctx *context.Context, form auth.SignInForm) {
func SignInPost(ctx *context.Context, f form.SignIn) {
ctx.Data["Title"] = ctx.Tr("sign_in")
if ctx.HasError() {
@@ -111,17 +111,17 @@ func SignInPost(ctx *context.Context, form auth.SignInForm) {
return
}
u, err := models.UserSignIn(form.UserName, form.Password)
u, err := models.UserSignIn(f.UserName, f.Password)
if err != nil {
if models.IsErrUserNotExist(err) {
ctx.RenderWithErr(ctx.Tr("form.username_password_incorrect"), SIGNIN, &form)
ctx.RenderWithErr(ctx.Tr("form.username_password_incorrect"), SIGNIN, &f)
} else {
ctx.Handle(500, "UserSignIn", err)
}
return
}
if form.Remember {
if f.Remember {
days := 86400 * setting.LogInRememberDays
ctx.SetCookie(setting.CookieUserName, u.Name, days, setting.AppSubUrl, "", setting.CookieSecure, true)
ctx.SetSuperSecureCookie(u.Rands+u.Passwd, setting.CookieRememberName, u.Name, days, setting.AppSubUrl, "", setting.CookieSecure, true)
@@ -169,7 +169,7 @@ func SignUp(ctx *context.Context) {
ctx.HTML(200, SIGNUP)
}
func SignUpPost(ctx *context.Context, cpt *captcha.Captcha, form auth.RegisterForm) {
func SignUpPost(ctx *context.Context, cpt *captcha.Captcha, f form.Register) {
ctx.Data["Title"] = ctx.Tr("sign_up")
ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha
@@ -186,36 +186,36 @@ func SignUpPost(ctx *context.Context, cpt *captcha.Captcha, form auth.RegisterFo
if setting.Service.EnableCaptcha && !cpt.VerifyReq(ctx.Req) {
ctx.Data["Err_Captcha"] = true
ctx.RenderWithErr(ctx.Tr("form.captcha_incorrect"), SIGNUP, &form)
ctx.RenderWithErr(ctx.Tr("form.captcha_incorrect"), SIGNUP, &f)
return
}
if form.Password != form.Retype {
if f.Password != f.Retype {
ctx.Data["Err_Password"] = true
ctx.RenderWithErr(ctx.Tr("form.password_not_match"), SIGNUP, &form)
ctx.RenderWithErr(ctx.Tr("form.password_not_match"), SIGNUP, &f)
return
}
u := &models.User{
Name: form.UserName,
Email: form.Email,
Passwd: form.Password,
Name: f.UserName,
Email: f.Email,
Passwd: f.Password,
IsActive: !setting.Service.RegisterEmailConfirm,
}
if err := models.CreateUser(u); err != nil {
switch {
case models.IsErrUserAlreadyExist(err):
ctx.Data["Err_UserName"] = true
ctx.RenderWithErr(ctx.Tr("form.username_been_taken"), SIGNUP, &form)
ctx.RenderWithErr(ctx.Tr("form.username_been_taken"), SIGNUP, &f)
case models.IsErrEmailAlreadyUsed(err):
ctx.Data["Err_Email"] = true
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), SIGNUP, &form)
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), SIGNUP, &f)
case models.IsErrNameReserved(err):
ctx.Data["Err_UserName"] = true
ctx.RenderWithErr(ctx.Tr("user.form.name_reserved", err.(models.ErrNameReserved).Name), SIGNUP, &form)
ctx.RenderWithErr(ctx.Tr("user.form.name_reserved", err.(models.ErrNameReserved).Name), SIGNUP, &f)
case models.IsErrNamePatternNotAllowed(err):
ctx.Data["Err_UserName"] = true
ctx.RenderWithErr(ctx.Tr("user.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), SIGNUP, &form)
ctx.RenderWithErr(ctx.Tr("user.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), SIGNUP, &f)
default:
ctx.Handle(500, "CreateUser", err)
}

View File

@@ -14,9 +14,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"
)
@@ -76,7 +76,7 @@ func handleUsernameChange(ctx *context.Context, newName string) {
ctx.User.LowerName = strings.ToLower(newName)
}
func SettingsPost(ctx *context.Context, form auth.UpdateProfileForm) {
func SettingsPost(ctx *context.Context, f form.UpdateProfile) {
ctx.Data["Title"] = ctx.Tr("settings")
ctx.Data["PageIsSettingsProfile"] = true
@@ -85,15 +85,15 @@ func SettingsPost(ctx *context.Context, form auth.UpdateProfileForm) {
return
}
handleUsernameChange(ctx, form.Name)
handleUsernameChange(ctx, f.Name)
if ctx.Written() {
return
}
ctx.User.FullName = form.FullName
ctx.User.Email = form.Email
ctx.User.Website = form.Website
ctx.User.Location = form.Location
ctx.User.FullName = f.FullName
ctx.User.Email = f.Email
ctx.User.Website = f.Website
ctx.User.Location = f.Location
if err := models.UpdateUser(ctx.User); err != nil {
ctx.Handle(500, "UpdateUser", err)
return
@@ -105,15 +105,15 @@ func SettingsPost(ctx *context.Context, form auth.UpdateProfileForm) {
}
// FIXME: limit size.
func UpdateAvatarSetting(ctx *context.Context, form auth.AvatarForm, ctxUser *models.User) error {
ctxUser.UseCustomAvatar = form.Source == auth.AVATAR_LOCAL
if len(form.Gravatar) > 0 {
ctxUser.Avatar = base.EncodeMD5(form.Gravatar)
ctxUser.AvatarEmail = form.Gravatar
func UpdateAvatarSetting(ctx *context.Context, f form.Avatar, ctxUser *models.User) error {
ctxUser.UseCustomAvatar = f.Source == form.AVATAR_LOCAL
if len(f.Gravatar) > 0 {
ctxUser.Avatar = base.EncodeMD5(f.Gravatar)
ctxUser.AvatarEmail = f.Gravatar
}
if form.Avatar != nil {
fr, err := form.Avatar.Open()
if f.Avatar != nil {
fr, err := f.Avatar.Open()
if err != nil {
return fmt.Errorf("Avatar.Open: %v", err)
}
@@ -152,8 +152,8 @@ func SettingsAvatar(ctx *context.Context) {
ctx.HTML(200, SETTINGS_AVATAR)
}
func SettingsAvatarPost(ctx *context.Context, form auth.AvatarForm) {
if err := UpdateAvatarSetting(ctx, form, ctx.User); err != nil {
func SettingsAvatarPost(ctx *context.Context, f form.Avatar) {
if err := UpdateAvatarSetting(ctx, f, ctx.User); err != nil {
ctx.Flash.Error(err.Error())
} else {
ctx.Flash.Success(ctx.Tr("settings.update_avatar_success"))
@@ -176,7 +176,7 @@ func SettingsPassword(ctx *context.Context) {
ctx.HTML(200, SETTINGS_PASSWORD)
}
func SettingsPasswordPost(ctx *context.Context, form auth.ChangePasswordForm) {
func SettingsPasswordPost(ctx *context.Context, f form.ChangePassword) {
ctx.Data["Title"] = ctx.Tr("settings")
ctx.Data["PageIsSettingsPassword"] = true
@@ -185,12 +185,12 @@ func SettingsPasswordPost(ctx *context.Context, form auth.ChangePasswordForm) {
return
}
if !ctx.User.ValidatePassword(form.OldPassword) {
if !ctx.User.ValidatePassword(f.OldPassword) {
ctx.Flash.Error(ctx.Tr("settings.password_incorrect"))
} else if form.Password != form.Retype {
} else if f.Password != f.Retype {
ctx.Flash.Error(ctx.Tr("form.password_not_match"))
} else {
ctx.User.Passwd = form.Password
ctx.User.Passwd = f.Password
var err error
if ctx.User.Salt, err = models.GetUserSalt(); err != nil {
ctx.Handle(500, "UpdateUser", err)
@@ -222,7 +222,7 @@ func SettingsEmails(ctx *context.Context) {
ctx.HTML(200, SETTINGS_EMAILS)
}
func SettingsEmailPost(ctx *context.Context, form auth.AddEmailForm) {
func SettingsEmailPost(ctx *context.Context, f form.AddEmail) {
ctx.Data["Title"] = ctx.Tr("settings")
ctx.Data["PageIsSettingsEmails"] = true
@@ -253,12 +253,12 @@ func SettingsEmailPost(ctx *context.Context, form auth.AddEmailForm) {
email := &models.EmailAddress{
UID: ctx.User.ID,
Email: form.Email,
Email: f.Email,
IsActivated: !setting.Service.RegisterEmailConfirm,
}
if err := models.AddEmailAddress(email); err != nil {
if models.IsErrEmailAlreadyUsed(err) {
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), SETTINGS_EMAILS, &form)
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), SETTINGS_EMAILS, &f)
return
}
ctx.Handle(500, "AddEmailAddress", err)
@@ -311,7 +311,7 @@ func SettingsSSHKeys(ctx *context.Context) {
ctx.HTML(200, SETTINGS_SSH_KEYS)
}
func SettingsSSHKeysPost(ctx *context.Context, form auth.AddSSHKeyForm) {
func SettingsSSHKeysPost(ctx *context.Context, f form.AddSSHKey) {
ctx.Data["Title"] = ctx.Tr("settings")
ctx.Data["PageIsSettingsSSHKeys"] = true
@@ -327,7 +327,7 @@ func SettingsSSHKeysPost(ctx *context.Context, form auth.AddSSHKeyForm) {
return
}
content, err := models.CheckPublicKeyString(form.Content)
content, err := models.CheckPublicKeyString(f.Content)
if err != nil {
if models.IsErrKeyUnableVerify(err) {
ctx.Flash.Info(ctx.Tr("form.unable_verify_ssh_key"))
@@ -338,22 +338,22 @@ func SettingsSSHKeysPost(ctx *context.Context, form auth.AddSSHKeyForm) {
}
}
if _, err = models.AddPublicKey(ctx.User.ID, form.Title, content); err != nil {
if _, err = models.AddPublicKey(ctx.User.ID, f.Title, content); err != nil {
ctx.Data["HasError"] = true
switch {
case models.IsErrKeyAlreadyExist(err):
ctx.Data["Err_Content"] = true
ctx.RenderWithErr(ctx.Tr("settings.ssh_key_been_used"), SETTINGS_SSH_KEYS, &form)
ctx.RenderWithErr(ctx.Tr("settings.ssh_key_been_used"), SETTINGS_SSH_KEYS, &f)
case models.IsErrKeyNameAlreadyUsed(err):
ctx.Data["Err_Title"] = true
ctx.RenderWithErr(ctx.Tr("settings.ssh_key_name_used"), SETTINGS_SSH_KEYS, &form)
ctx.RenderWithErr(ctx.Tr("settings.ssh_key_name_used"), SETTINGS_SSH_KEYS, &f)
default:
ctx.Handle(500, "AddPublicKey", err)
}
return
}
ctx.Flash.Success(ctx.Tr("settings.add_key_success", form.Title))
ctx.Flash.Success(ctx.Tr("settings.add_key_success", f.Title))
ctx.Redirect(setting.AppSubUrl + "/user/settings/ssh")
}
@@ -383,7 +383,7 @@ func SettingsApplications(ctx *context.Context) {
ctx.HTML(200, SETTINGS_APPLICATIONS)
}
func SettingsApplicationsPost(ctx *context.Context, form auth.NewAccessTokenForm) {
func SettingsApplicationsPost(ctx *context.Context, f form.NewAccessToken) {
ctx.Data["Title"] = ctx.Tr("settings")
ctx.Data["PageIsSettingsApplications"] = true
@@ -400,7 +400,7 @@ func SettingsApplicationsPost(ctx *context.Context, form auth.NewAccessTokenForm
t := &models.AccessToken{
UID: ctx.User.ID,
Name: form.Name,
Name: f.Name,
}
if err := models.NewAccessToken(t); err != nil {
ctx.Handle(500, "NewAccessToken", err)

View File

@@ -2,10 +2,7 @@
Description=Gogs
After=syslog.target
After=network.target
#After=mysqld.service
#After=postgresql.service
#After=memcached.service
#After=redis.service
After=mariadb.service mysqld.service postgresql.service memcached.service redis.service
[Service]
# Modify these two values and uncomment them if you have

View File

@@ -1 +1 @@
0.10.0.0227
0.10.8.0307

View File

@@ -170,7 +170,7 @@
<dd><i class="fa fa{{if .MailerEnabled}}-check{{end}}-square-o"></i></dd>
{{if .MailerEnabled}}
<dt>{{.i18n.Tr "admin.config.mailer_name"}}</dt>
<dd>{{.Mailer.Name}}</dd>
<dd>{{.Mailer.Subject}}</dd>
<dt>{{.i18n.Tr "admin.config.mailer_disable_helo"}}</dt>
<dd><i class="fa fa{{if .Mailer.DisableHelo}}-check{{end}}-square-o"></i></dd>
<dt>{{.i18n.Tr "admin.config.mailer_host"}}</dt>
@@ -258,8 +258,6 @@
<dd>{{.Git.MaxGitDiffFiles}}</dd>
<dt>{{.i18n.Tr "admin.config.git_gc_args"}}</dt>
<dd><code>{{.Git.GCArgs}}</code></dd>
<dt>{{.i18n.Tr "admin.config.git_max_diff_lines"}}</dt>
<dd>{{.Git.MaxGitDiffLines}}</dd>
<div class="ui divider"></div>
<dt>{{.i18n.Tr "admin.config.git_migrate_timeout"}}</dt>
<dd>{{.Git.Timeout.Migrate}} {{.i18n.Tr "tool.raw_seconds"}}</dd>
@@ -277,15 +275,19 @@
<h4 class="ui top attached header">
{{.i18n.Tr "admin.config.log_config"}}
</h4>
<div class="ui attached table segment">
<dl class="dl-horizontal admin-dl-horizontal">
<div class="ui attached log-config segment">
<table class="ui very basic table">
{{range .Loggers}}
<dt>{{$.i18n.Tr "admin.config.log_mode"}}</dt>
<dd>{{.Mode}}</dd>
<dt>{{$.i18n.Tr "admin.config.log_config"}}</dt>
<dd><pre><code>{{.Config}}</code></pre></dd>
<tr>
<td>{{$.i18n.Tr "admin.config.log_mode"}}</td>
<td>{{.Mode}}</td>
<tr>
</tr>
<td>{{$.i18n.Tr "admin.config.log_options"}}</td>
<td><pre><code>{{.Config}}</code></pre></td>
</tr>
{{end}}
</dl>
</table>
</div>
</div>
</div>

View File

@@ -12,7 +12,7 @@
<div class="inline required field {{if .Err_Owner}}error{{end}}">
<label>{{.i18n.Tr "repo.owner"}}</label>
<div class="ui selection owner dropdown">
<input type="hidden" id="uid" name="uid" value="{{.ContextUser.ID}}" required>
<input type="hidden" id="user_id" name="user_id" value="{{.ContextUser.ID}}" required>
<span class="text">
<img class="ui mini image" src="{{.ContextUser.RelAvatarLink}}">
{{.ContextUser.ShortName 20}}

View File

@@ -12,7 +12,7 @@
<div class="inline required field {{if .Err_Owner}}error{{end}}">
<label>{{.i18n.Tr "repo.owner"}}</label>
<div class="ui selection owner dropdown">
<input type="hidden" id="uid" name="uid" value="{{.ContextUser.ID}}" required>
<input type="hidden" id="user_id" name="user_id" value="{{.ContextUser.ID}}" required>
<span class="text">
<img class="ui mini image" src="{{.ContextUser.RelAvatarLink}}">
{{.ContextUser.ShortName 20}}

View File

@@ -306,11 +306,11 @@
</div>
<div class="required field">
<label for="repo_name">{{.i18n.Tr "repo.repo_name"}}</label>
<input id="repo_name" name="repo_name" required>
<input id="repo_name" name="repo_name" autocomplete="off" required>
</div>
<div class="required field">
<label for="new_owner_name">{{.i18n.Tr "repo.settings.transfer_owner"}}</label>
<input id="new_owner_name" name="new_owner_name" required>
<input id="new_owner_name" name="new_owner_name" autocomplete="off" required>
</div>
<div class="text right actions">
@@ -344,7 +344,7 @@
</div>
<div class="required field">
<label for="repo_name">{{.i18n.Tr "repo.repo_name"}}</label>
<input id="repo_name" name="repo_name" required>
<input id="repo_name" name="repo_name" autocomplete="off" required>
</div>
<div class="text right actions">
@@ -376,7 +376,7 @@
</div>
<div class="required field">
<label for="repo_name">{{.i18n.Tr "repo.repo_name"}}</label>
<input id="repo_name" name="repo_name" required>
<input id="repo_name" name="repo_name" autocomplete="off" required>
</div>
<div class="text right actions">

View File

@@ -32,6 +32,26 @@
</div>
</div>
</div>
<!-- Delete -->
<div class="seven wide column">
<div class="field">
<div class="ui checkbox">
<input class="hidden" name="delete" type="checkbox" tabindex="0" {{if .Webhook.Delete}}checked{{end}}>
<label>{{.i18n.Tr "repo.settings.event_delete"}}</label>
<span class="help">{{.i18n.Tr "repo.settings.event_delete_desc"}}</span>
</div>
</div>
</div>
<!-- Fork -->
<div class="seven wide column">
<div class="field">
<div class="ui checkbox">
<input class="hidden" name="fork" type="checkbox" tabindex="0" {{if .Webhook.Fork}}checked{{end}}>
<label>{{.i18n.Tr "repo.settings.event_fork"}}</label>
<span class="help">{{.i18n.Tr "repo.settings.event_fork_desc"}}</span>
</div>
</div>
</div>
<!-- Push -->
<div class="seven wide column">
<div class="field">

View File

@@ -18,7 +18,7 @@
<h4 class="ui top attached header">
{{.i18n.Tr "home.my_repos"}} <span class="ui grey label">{{.ContextUser.NumRepos}}</span>
<div class="ui right">
<a class="poping up" href="{{AppSubUrl}}/repo/create" data-content="{{.i18n.Tr "new_repo"}}" data-variation="tiny inverted" data-position="left center">
<a class="poping up" href="{{AppSubUrl}}/repo/create{{if .ContextUser.IsOrganization}}?org={{.ContextUser.ID}}{{end}}" data-content="{{.i18n.Tr "new_repo"}}" data-variation="tiny inverted" data-position="left center">
<i class="plus icon"></i>
<span class="sr-only">{{.i18n.Tr "new_repo"}}</span>
</a>

View File

@@ -8,7 +8,8 @@
<div class="{{if eq .GetOpType 5}}push news{{end}}">
<p>
<a href="{{AppSubUrl}}/{{.GetActUserName}}">{{.ShortActUserName}}</a>
{{if eq .GetOpType 1}}
<!-- Reference types to models/action.go -->
{{if eq .GetOpType 1}}
{{$.i18n.Tr "action.create_repo" .GetRepoLink .ShortRepoPath | Str2html}}
{{else if eq .GetOpType 2}}
{{$.i18n.Tr "action.rename_repo" .GetContent .GetRepoLink .ShortRepoPath | Str2html}}
@@ -43,6 +44,15 @@
{{else if eq .GetOpType 15}}
{{ $index := index .GetIssueInfos 0}}
{{$.i18n.Tr "action.reopen_pull_request" .GetRepoLink $index .ShortRepoPath | Str2html}}
{{else if eq .GetOpType 16}}
{{ $branchLink := .GetBranch | EscapePound}}
{{$.i18n.Tr "action.create_branch" .GetRepoLink $branchLink .GetBranch .ShortRepoPath | Str2html}}
{{else if eq .GetOpType 17}}
{{$.i18n.Tr "action.delete_branch" .GetRepoLink .GetBranch .ShortRepoPath | Str2html}}
{{else if eq .GetOpType 18}}
{{$.i18n.Tr "action.delete_tag" .GetRepoLink .GetBranch .ShortRepoPath | Str2html}}
{{else if eq .GetOpType 19}}
{{$.i18n.Tr "action.fork_repo" .GetRepoLink .ShortRepoPath | Str2html}}
{{end}}
</p>
{{if eq .GetOpType 5}}

View File

@@ -5,7 +5,7 @@
<div class="ui five wide column">
<div class="ui card">
{{if eq .SignedUserName .Owner.Name}}
<a class="image poping up" href="{{AppSubUrl}}/user/settings" id="profile-avatar" data-content="{{.i18n.Tr "user.change_avatar"}}" data-variation="inverted tiny" data-position="bottom center">
<a class="image poping up" href="{{AppSubUrl}}/user/settings/avatar" id="profile-avatar" data-content="{{.i18n.Tr "user.change_avatar"}}" data-variation="inverted tiny" data-position="bottom center">
<img src="{{.Owner.RelAvatarLink}}?s=290" title="{{.Owner.Name}}"/>
</a>
{{else}}

View File

@@ -25,7 +25,7 @@
</div>
<div class="required field {{if .Err_Email}}error{{end}}">
<label for="email">{{.i18n.Tr "email"}}</label>
<input id="email" name="email" value="{{.SignedUser.Email}}">
<input id="email" name="email" value="{{.SignedUser.Email}}" required>
</div>
<div class="field {{if .Err_Website}}error{{end}}">
<label for="website">{{.i18n.Tr "settings.website"}}</label>

View File

@@ -14,7 +14,7 @@ import (
)
func Version() string {
return "0.12.6"
return "0.12.7"
}
// Client represents a Gogs API client.

View File

@@ -91,6 +91,7 @@ type PayloadCommit struct {
var (
_ Payloader = &CreatePayload{}
_ Payloader = &DeletePayload{}
_ Payloader = &PushPayload{}
_ Payloader = &PullRequestPayload{}
)
@@ -103,10 +104,11 @@ var (
// \/ \/ \/ \/
type CreatePayload struct {
Ref string `json:"ref"`
RefType string `json:"ref_type"`
Repo *Repository `json:"repository"`
Sender *User `json:"sender"`
Ref string `json:"ref"`
RefType string `json:"ref_type"`
DefaultBranch string `json:"default_branch"`
Repo *Repository `json:"repository"`
Sender *User `json:"sender"`
}
func (p *CreatePayload) JSONPayload() ([]byte, error) {
@@ -133,6 +135,48 @@ func ParseCreateHook(raw []byte) (*CreatePayload, error) {
return hook, nil
}
// ________ .__ __
// \______ \ ____ | | _____/ |_ ____
// | | \_/ __ \| | _/ __ \ __\/ __ \
// | ` \ ___/| |_\ ___/| | \ ___/
// /_______ /\___ >____/\___ >__| \___ >
// \/ \/ \/ \/
type PusherType string
const (
PUSHER_TYPE_USER PusherType = "user"
)
type DeletePayload struct {
Ref string `json:"ref"`
RefType string `json:"ref_type"`
PusherType PusherType `json:"pusher_type"`
Repo *Repository `json:"repository"`
Sender *User `json:"sender"`
}
func (p *DeletePayload) JSONPayload() ([]byte, error) {
return json.MarshalIndent(p, "", " ")
}
// ___________ __
// \_ _____/__________| | __
// | __)/ _ \_ __ \ |/ /
// | \( <_> ) | \/ <
// \___ / \____/|__| |__|_ \
// \/ \/
type ForkPayload struct {
Forkee *Repository `json:"forkee"`
Repo *Repository `json:"repository"`
Sender *User `json:"sender"`
}
func (p *ForkPayload) JSONPayload() ([]byte, error) {
return json.MarshalIndent(p, "", " ")
}
// __________ .__
// \______ \__ __ _____| |__
// | ___/ | \/ ___/ | \

View File

@@ -23,7 +23,9 @@ func init() {
if err != nil {
panic(err)
}
if interactive {
// While run as Windows service, it is not an interactive session,
// but we don't want hook execute to be treated as service, e.g. gogs.exe hook pre-receive.
if interactive || len(os.Getenv("SSH_ORIGINAL_COMMAND")) > 0 {
return
}
go func() {

View File

@@ -461,8 +461,8 @@ func (m *mux) newChannel(chanType string, direction channelDirection, extraData
pending: newBuffer(),
extPending: newBuffer(),
direction: direction,
incomingRequests: make(chan *Request, 16),
msg: make(chan interface{}, 16),
incomingRequests: make(chan *Request, chanSize),
msg: make(chan interface{}, chanSize),
chanType: chanType,
extraData: extraData,
mux: m,

View File

@@ -135,6 +135,7 @@ const prefixLen = 5
type streamPacketCipher struct {
mac hash.Hash
cipher cipher.Stream
etm bool
// The following members are to avoid per-packet allocations.
prefix [prefixLen]byte
@@ -150,7 +151,14 @@ func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, err
return nil, err
}
s.cipher.XORKeyStream(s.prefix[:], s.prefix[:])
var encryptedPaddingLength [1]byte
if s.mac != nil && s.etm {
copy(encryptedPaddingLength[:], s.prefix[4:5])
s.cipher.XORKeyStream(s.prefix[4:5], s.prefix[4:5])
} else {
s.cipher.XORKeyStream(s.prefix[:], s.prefix[:])
}
length := binary.BigEndian.Uint32(s.prefix[0:4])
paddingLength := uint32(s.prefix[4])
@@ -159,7 +167,12 @@ func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, err
s.mac.Reset()
binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum)
s.mac.Write(s.seqNumBytes[:])
s.mac.Write(s.prefix[:])
if s.etm {
s.mac.Write(s.prefix[:4])
s.mac.Write(encryptedPaddingLength[:])
} else {
s.mac.Write(s.prefix[:])
}
macSize = uint32(s.mac.Size())
}
@@ -184,10 +197,17 @@ func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, err
}
mac := s.packetData[length-1:]
data := s.packetData[:length-1]
if s.mac != nil && s.etm {
s.mac.Write(data)
}
s.cipher.XORKeyStream(data, data)
if s.mac != nil {
s.mac.Write(data)
if !s.etm {
s.mac.Write(data)
}
s.macResult = s.mac.Sum(s.macResult[:0])
if subtle.ConstantTimeCompare(s.macResult, mac) != 1 {
return nil, errors.New("ssh: MAC failure")
@@ -203,7 +223,13 @@ func (s *streamPacketCipher) writePacket(seqNum uint32, w io.Writer, rand io.Rea
return errors.New("ssh: packet too large")
}
paddingLength := packetSizeMultiple - (prefixLen+len(packet))%packetSizeMultiple
aadlen := 0
if s.mac != nil && s.etm {
// packet length is not encrypted for EtM modes
aadlen = 4
}
paddingLength := packetSizeMultiple - (prefixLen+len(packet)-aadlen)%packetSizeMultiple
if paddingLength < 4 {
paddingLength += packetSizeMultiple
}
@@ -220,15 +246,37 @@ func (s *streamPacketCipher) writePacket(seqNum uint32, w io.Writer, rand io.Rea
s.mac.Reset()
binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum)
s.mac.Write(s.seqNumBytes[:])
if s.etm {
// For EtM algorithms, the packet length must stay unencrypted,
// but the following data (padding length) must be encrypted
s.cipher.XORKeyStream(s.prefix[4:5], s.prefix[4:5])
}
s.mac.Write(s.prefix[:])
if !s.etm {
// For non-EtM algorithms, the algorithm is applied on unencrypted data
s.mac.Write(packet)
s.mac.Write(padding)
}
}
if !(s.mac != nil && s.etm) {
// For EtM algorithms, the padding length has already been encrypted
// and the packet length must remain unencrypted
s.cipher.XORKeyStream(s.prefix[:], s.prefix[:])
}
s.cipher.XORKeyStream(packet, packet)
s.cipher.XORKeyStream(padding, padding)
if s.mac != nil && s.etm {
// For EtM algorithms, packet and padding must be encrypted
s.mac.Write(packet)
s.mac.Write(padding)
}
s.cipher.XORKeyStream(s.prefix[:], s.prefix[:])
s.cipher.XORKeyStream(packet, packet)
s.cipher.XORKeyStream(padding, padding)
if _, err := w.Write(s.prefix[:]); err != nil {
return err
}

View File

@@ -40,7 +40,7 @@ func (c *Client) HandleChannelOpen(channelType string) <-chan NewChannel {
return nil
}
ch = make(chan NewChannel, 16)
ch = make(chan NewChannel, chanSize)
c.channelHandlers[channelType] = ch
return ch
}
@@ -97,13 +97,11 @@ func (c *connection) clientHandshake(dialAddress string, config *ClientConfig) e
c.transport = newClientTransport(
newTransport(c.sshConn.conn, config.Rand, true /* is client */),
c.clientVersion, c.serverVersion, config, dialAddress, c.sshConn.RemoteAddr())
if err := c.transport.requestInitialKeyChange(); err != nil {
if err := c.transport.waitSession(); err != nil {
return err
}
// We just did the key change, so the session ID is established.
c.sessionID = c.transport.getSessionID()
return c.clientAuthenticate(config)
}

View File

@@ -30,8 +30,10 @@ func (c *connection) clientAuthenticate(config *ClientConfig) error {
// then any untried methods suggested by the server.
tried := make(map[string]bool)
var lastMethods []string
sessionID := c.transport.getSessionID()
for auth := AuthMethod(new(noneAuth)); auth != nil; {
ok, methods, err := auth.auth(c.transport.getSessionID(), config.User, c.transport, config.Rand)
ok, methods, err := auth.auth(sessionID, config.User, c.transport, config.Rand)
if err != nil {
return err
}

View File

@@ -56,7 +56,7 @@ var supportedHostKeyAlgos = []string{
// This is based on RFC 4253, section 6.4, but with hmac-md5 variants removed
// because they have reached the end of their useful life.
var supportedMACs = []string{
"hmac-sha2-256", "hmac-sha1", "hmac-sha1-96",
"hmac-sha2-256-etm@openssh.com", "hmac-sha2-256", "hmac-sha1", "hmac-sha1-96",
}
var supportedCompressions = []string{compressionNone}
@@ -104,6 +104,21 @@ type directionAlgorithms struct {
Compression string
}
// rekeyBytes returns a rekeying intervals in bytes.
func (a *directionAlgorithms) rekeyBytes() int64 {
// According to RFC4344 block ciphers should rekey after
// 2^(BLOCKSIZE/4) blocks. For all AES flavors BLOCKSIZE is
// 128.
switch a.Cipher {
case "aes128-ctr", "aes192-ctr", "aes256-ctr", gcmCipherID, aes128cbcID:
return 16 * (1 << 32)
}
// For others, stick with RFC4253 recommendation to rekey after 1 Gb of data.
return 1 << 30
}
type algorithms struct {
kex string
hostKey string

View File

@@ -19,6 +19,11 @@ import (
// messages are wrong when using ECDH.
const debugHandshake = false
// chanSize sets the amount of buffering SSH connections. This is
// primarily for testing: setting chanSize=0 uncovers deadlocks more
// quickly.
const chanSize = 16
// keyingTransport is a packet based transport that supports key
// changes. It need not be thread-safe. It should pass through
// msgNewKeys in both directions.
@@ -53,34 +58,58 @@ type handshakeTransport struct {
incoming chan []byte
readError error
mu sync.Mutex
writeError error
sentInitPacket []byte
sentInitMsg *kexInitMsg
pendingPackets [][]byte // Used when a key exchange is in progress.
// If the read loop wants to schedule a kex, it pings this
// channel, and the write loop will send out a kex
// message.
requestKex chan struct{}
// If the other side requests or confirms a kex, its kexInit
// packet is sent here for the write loop to find it.
startKex chan *pendingKex
// data for host key checking
hostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error
dialAddress string
remoteAddr net.Addr
readSinceKex uint64
// Algorithms agreed in the last key exchange.
algorithms *algorithms
// Protects the writing side of the connection
mu sync.Mutex
cond *sync.Cond
sentInitPacket []byte
sentInitMsg *kexInitMsg
writtenSinceKex uint64
writeError error
readPacketsLeft uint32
readBytesLeft int64
writePacketsLeft uint32
writeBytesLeft int64
// The session ID or nil if first kex did not complete yet.
sessionID []byte
}
type pendingKex struct {
otherInit []byte
done chan error
}
func newHandshakeTransport(conn keyingTransport, config *Config, clientVersion, serverVersion []byte) *handshakeTransport {
t := &handshakeTransport{
conn: conn,
serverVersion: serverVersion,
clientVersion: clientVersion,
incoming: make(chan []byte, 16),
config: config,
incoming: make(chan []byte, chanSize),
requestKex: make(chan struct{}, 1),
startKex: make(chan *pendingKex, 1),
config: config,
}
t.cond = sync.NewCond(&t.mu)
// We always start with a mandatory key exchange.
t.requestKex <- struct{}{}
return t
}
@@ -95,6 +124,7 @@ func newClientTransport(conn keyingTransport, clientVersion, serverVersion []byt
t.hostKeyAlgorithms = supportedHostKeyAlgos
}
go t.readLoop()
go t.kexLoop()
return t
}
@@ -102,6 +132,7 @@ func newServerTransport(conn keyingTransport, clientVersion, serverVersion []byt
t := newHandshakeTransport(conn, &config.Config, clientVersion, serverVersion)
t.hostKeys = config.hostKeys
go t.readLoop()
go t.kexLoop()
return t
}
@@ -109,6 +140,20 @@ func (t *handshakeTransport) getSessionID() []byte {
return t.sessionID
}
// waitSession waits for the session to be established. This should be
// the first thing to call after instantiating handshakeTransport.
func (t *handshakeTransport) waitSession() error {
p, err := t.readPacket()
if err != nil {
return err
}
if p[0] != msgNewKeys {
return fmt.Errorf("ssh: first packet should be msgNewKeys")
}
return nil
}
func (t *handshakeTransport) id() string {
if len(t.hostKeys) > 0 {
return "server"
@@ -116,6 +161,20 @@ func (t *handshakeTransport) id() string {
return "client"
}
func (t *handshakeTransport) printPacket(p []byte, write bool) {
action := "got"
if write {
action = "sent"
}
if p[0] == msgChannelData || p[0] == msgChannelExtendedData {
log.Printf("%s %s data (packet %d bytes)", t.id(), action, len(p))
} else {
msg, err := decode(p)
log.Printf("%s %s %T %v (%v)", t.id(), action, msg, msg, err)
}
}
func (t *handshakeTransport) readPacket() ([]byte, error) {
p, ok := <-t.incoming
if !ok {
@@ -125,8 +184,10 @@ func (t *handshakeTransport) readPacket() ([]byte, error) {
}
func (t *handshakeTransport) readLoop() {
first := true
for {
p, err := t.readOnePacket()
p, err := t.readOnePacket(first)
first = false
if err != nil {
t.readError = err
close(t.incoming)
@@ -138,67 +199,204 @@ func (t *handshakeTransport) readLoop() {
t.incoming <- p
}
// If we can't read, declare the writing part dead too.
t.mu.Lock()
defer t.mu.Unlock()
if t.writeError == nil {
t.writeError = t.readError
}
t.cond.Broadcast()
// Stop writers too.
t.recordWriteError(t.readError)
// Unblock the writer should it wait for this.
close(t.startKex)
// Don't close t.requestKex; it's also written to from writePacket.
}
func (t *handshakeTransport) readOnePacket() ([]byte, error) {
if t.readSinceKex > t.config.RekeyThreshold {
if err := t.requestKeyChange(); err != nil {
return nil, err
func (t *handshakeTransport) pushPacket(p []byte) error {
if debugHandshake {
t.printPacket(p, true)
}
return t.conn.writePacket(p)
}
func (t *handshakeTransport) getWriteError() error {
t.mu.Lock()
defer t.mu.Unlock()
return t.writeError
}
func (t *handshakeTransport) recordWriteError(err error) {
t.mu.Lock()
defer t.mu.Unlock()
if t.writeError == nil && err != nil {
t.writeError = err
}
}
func (t *handshakeTransport) requestKeyExchange() {
select {
case t.requestKex <- struct{}{}:
default:
// something already requested a kex, so do nothing.
}
}
func (t *handshakeTransport) kexLoop() {
write:
for t.getWriteError() == nil {
var request *pendingKex
var sent bool
for request == nil || !sent {
var ok bool
select {
case request, ok = <-t.startKex:
if !ok {
break write
}
case <-t.requestKex:
break
}
if !sent {
if err := t.sendKexInit(); err != nil {
t.recordWriteError(err)
break
}
sent = true
}
}
if err := t.getWriteError(); err != nil {
if request != nil {
request.done <- err
}
break
}
// We're not servicing t.requestKex, but that is OK:
// we never block on sending to t.requestKex.
// We're not servicing t.startKex, but the remote end
// has just sent us a kexInitMsg, so it can't send
// another key change request, until we close the done
// channel on the pendingKex request.
err := t.enterKeyExchange(request.otherInit)
t.mu.Lock()
t.writeError = err
t.sentInitPacket = nil
t.sentInitMsg = nil
t.writePacketsLeft = packetRekeyThreshold
if t.config.RekeyThreshold > 0 {
t.writeBytesLeft = int64(t.config.RekeyThreshold)
} else if t.algorithms != nil {
t.writeBytesLeft = t.algorithms.w.rekeyBytes()
}
// we have completed the key exchange. Since the
// reader is still blocked, it is safe to clear out
// the requestKex channel. This avoids the situation
// where: 1) we consumed our own request for the
// initial kex, and 2) the kex from the remote side
// caused another send on the requestKex channel,
clear:
for {
select {
case <-t.requestKex:
//
default:
break clear
}
}
request.done <- t.writeError
// kex finished. Push packets that we received while
// the kex was in progress. Don't look at t.startKex
// and don't increment writtenSinceKex: if we trigger
// another kex while we are still busy with the last
// one, things will become very confusing.
for _, p := range t.pendingPackets {
t.writeError = t.pushPacket(p)
if t.writeError != nil {
break
}
}
t.pendingPackets = t.pendingPackets[:0]
t.mu.Unlock()
}
// drain startKex channel. We don't service t.requestKex
// because nobody does blocking sends there.
go func() {
for init := range t.startKex {
init.done <- t.writeError
}
}()
// Unblock reader.
t.conn.Close()
}
// The protocol uses uint32 for packet counters, so we can't let them
// reach 1<<32. We will actually read and write more packets than
// this, though: the other side may send more packets, and after we
// hit this limit on writing we will send a few more packets for the
// key exchange itself.
const packetRekeyThreshold = (1 << 31)
func (t *handshakeTransport) readOnePacket(first bool) ([]byte, error) {
p, err := t.conn.readPacket()
if err != nil {
return nil, err
}
t.readSinceKex += uint64(len(p))
if debugHandshake {
if p[0] == msgChannelData || p[0] == msgChannelExtendedData {
log.Printf("%s got data (packet %d bytes)", t.id(), len(p))
} else {
msg, err := decode(p)
log.Printf("%s got %T %v (%v)", t.id(), msg, msg, err)
}
if t.readPacketsLeft > 0 {
t.readPacketsLeft--
} else {
t.requestKeyExchange()
}
if t.readBytesLeft > 0 {
t.readBytesLeft -= int64(len(p))
} else {
t.requestKeyExchange()
}
if debugHandshake {
t.printPacket(p, false)
}
if first && p[0] != msgKexInit {
return nil, fmt.Errorf("ssh: first packet should be msgKexInit")
}
if p[0] != msgKexInit {
return p, nil
}
t.mu.Lock()
firstKex := t.sessionID == nil
err = t.enterKeyExchangeLocked(p)
if err != nil {
// drop connection
t.conn.Close()
t.writeError = err
kex := pendingKex{
done: make(chan error, 1),
otherInit: p,
}
t.startKex <- &kex
err = <-kex.done
if debugHandshake {
log.Printf("%s exited key exchange (first %v), err %v", t.id(), firstKex, err)
}
// Unblock writers.
t.sentInitMsg = nil
t.sentInitPacket = nil
t.cond.Broadcast()
t.writtenSinceKex = 0
t.mu.Unlock()
if err != nil {
return nil, err
}
t.readSinceKex = 0
t.readPacketsLeft = packetRekeyThreshold
if t.config.RekeyThreshold > 0 {
t.readBytesLeft = int64(t.config.RekeyThreshold)
} else {
t.readBytesLeft = t.algorithms.r.rekeyBytes()
}
// By default, a key exchange is hidden from higher layers by
// translating it into msgIgnore.
@@ -213,61 +411,16 @@ func (t *handshakeTransport) readOnePacket() ([]byte, error) {
return successPacket, nil
}
// keyChangeCategory describes whether a key exchange is the first on a
// connection, or a subsequent one.
type keyChangeCategory bool
const (
firstKeyExchange keyChangeCategory = true
subsequentKeyExchange keyChangeCategory = false
)
// sendKexInit sends a key change message, and returns the message
// that was sent. After initiating the key change, all writes will be
// blocked until the change is done, and a failed key change will
// close the underlying transport. This function is safe for
// concurrent use by multiple goroutines.
func (t *handshakeTransport) sendKexInit(isFirst keyChangeCategory) error {
var err error
// sendKexInit sends a key change message.
func (t *handshakeTransport) sendKexInit() error {
t.mu.Lock()
// If this is the initial key change, but we already have a sessionID,
// then do nothing because the key exchange has already completed
// asynchronously.
if !isFirst || t.sessionID == nil {
_, _, err = t.sendKexInitLocked(isFirst)
}
t.mu.Unlock()
if err != nil {
return err
}
if isFirst {
if packet, err := t.readPacket(); err != nil {
return err
} else if packet[0] != msgNewKeys {
return unexpectedMessageError(msgNewKeys, packet[0])
}
}
return nil
}
func (t *handshakeTransport) requestInitialKeyChange() error {
return t.sendKexInit(firstKeyExchange)
}
func (t *handshakeTransport) requestKeyChange() error {
return t.sendKexInit(subsequentKeyExchange)
}
// sendKexInitLocked sends a key change message. t.mu must be locked
// while this happens.
func (t *handshakeTransport) sendKexInitLocked(isFirst keyChangeCategory) (*kexInitMsg, []byte, error) {
// kexInits may be sent either in response to the other side,
// or because our side wants to initiate a key change, so we
// may have already sent a kexInit. In that case, don't send a
// second kexInit.
defer t.mu.Unlock()
if t.sentInitMsg != nil {
return t.sentInitMsg, t.sentInitPacket, nil
// kexInits may be sent either in response to the other side,
// or because our side wants to initiate a key change, so we
// may have already sent a kexInit. In that case, don't send a
// second kexInit.
return nil
}
msg := &kexInitMsg{
@@ -295,53 +448,65 @@ func (t *handshakeTransport) sendKexInitLocked(isFirst keyChangeCategory) (*kexI
packetCopy := make([]byte, len(packet))
copy(packetCopy, packet)
if err := t.conn.writePacket(packetCopy); err != nil {
return nil, nil, err
if err := t.pushPacket(packetCopy); err != nil {
return err
}
t.sentInitMsg = msg
t.sentInitPacket = packet
return msg, packet, nil
return nil
}
func (t *handshakeTransport) writePacket(p []byte) error {
t.mu.Lock()
defer t.mu.Unlock()
if t.writtenSinceKex > t.config.RekeyThreshold {
t.sendKexInitLocked(subsequentKeyExchange)
}
for t.sentInitMsg != nil && t.writeError == nil {
t.cond.Wait()
}
if t.writeError != nil {
return t.writeError
}
t.writtenSinceKex += uint64(len(p))
switch p[0] {
case msgKexInit:
return errors.New("ssh: only handshakeTransport can send kexInit")
case msgNewKeys:
return errors.New("ssh: only handshakeTransport can send newKeys")
default:
return t.conn.writePacket(p)
}
t.mu.Lock()
defer t.mu.Unlock()
if t.writeError != nil {
return t.writeError
}
if t.sentInitMsg != nil {
// Copy the packet so the writer can reuse the buffer.
cp := make([]byte, len(p))
copy(cp, p)
t.pendingPackets = append(t.pendingPackets, cp)
return nil
}
if t.writeBytesLeft > 0 {
t.writeBytesLeft -= int64(len(p))
} else {
t.requestKeyExchange()
}
if t.writePacketsLeft > 0 {
t.writePacketsLeft--
} else {
t.requestKeyExchange()
}
if err := t.pushPacket(p); err != nil {
t.writeError = err
}
return nil
}
func (t *handshakeTransport) Close() error {
return t.conn.Close()
}
// enterKeyExchange runs the key exchange. t.mu must be held while running this.
func (t *handshakeTransport) enterKeyExchangeLocked(otherInitPacket []byte) error {
func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error {
if debugHandshake {
log.Printf("%s entered key exchange", t.id())
}
myInit, myInitPacket, err := t.sendKexInitLocked(subsequentKeyExchange)
if err != nil {
return err
}
otherInit := &kexInitMsg{}
if err := Unmarshal(otherInitPacket, otherInit); err != nil {
@@ -352,20 +517,20 @@ func (t *handshakeTransport) enterKeyExchangeLocked(otherInitPacket []byte) erro
clientVersion: t.clientVersion,
serverVersion: t.serverVersion,
clientKexInit: otherInitPacket,
serverKexInit: myInitPacket,
serverKexInit: t.sentInitPacket,
}
clientInit := otherInit
serverInit := myInit
serverInit := t.sentInitMsg
if len(t.hostKeys) == 0 {
clientInit = myInit
serverInit = otherInit
clientInit, serverInit = serverInit, clientInit
magics.clientKexInit = myInitPacket
magics.clientKexInit = t.sentInitPacket
magics.serverKexInit = otherInitPacket
}
algs, err := findAgreedAlgorithms(clientInit, serverInit)
var err error
t.algorithms, err = findAgreedAlgorithms(clientInit, serverInit)
if err != nil {
return err
}
@@ -388,16 +553,16 @@ func (t *handshakeTransport) enterKeyExchangeLocked(otherInitPacket []byte) erro
}
}
kex, ok := kexAlgoMap[algs.kex]
kex, ok := kexAlgoMap[t.algorithms.kex]
if !ok {
return fmt.Errorf("ssh: unexpected key exchange algorithm %v", algs.kex)
return fmt.Errorf("ssh: unexpected key exchange algorithm %v", t.algorithms.kex)
}
var result *kexResult
if len(t.hostKeys) > 0 {
result, err = t.server(kex, algs, &magics)
result, err = t.server(kex, t.algorithms, &magics)
} else {
result, err = t.client(kex, algs, &magics)
result, err = t.client(kex, t.algorithms, &magics)
}
if err != nil {
@@ -409,7 +574,7 @@ func (t *handshakeTransport) enterKeyExchangeLocked(otherInitPacket []byte) erro
}
result.SessionID = t.sessionID
t.conn.prepareKeyChange(algs, result)
t.conn.prepareKeyChange(t.algorithms, result)
if err = t.conn.writePacket([]byte{msgNewKeys}); err != nil {
return err
}

View File

@@ -798,8 +798,8 @@ func ParseDSAPrivateKey(der []byte) (*dsa.PrivateKey, error) {
P *big.Int
Q *big.Int
G *big.Int
Priv *big.Int
Pub *big.Int
Priv *big.Int
}
rest, err := asn1.Unmarshal(der, &k)
if err != nil {
@@ -816,9 +816,9 @@ func ParseDSAPrivateKey(der []byte) (*dsa.PrivateKey, error) {
Q: k.Q,
G: k.G,
},
Y: k.Priv,
Y: k.Pub,
},
X: k.Pub,
X: k.Priv,
}, nil
}

View File

@@ -15,6 +15,7 @@ import (
type macMode struct {
keySize int
etm bool
new func(key []byte) hash.Hash
}
@@ -45,13 +46,16 @@ func (t truncatingMAC) Size() int {
func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() }
var macModes = map[string]*macMode{
"hmac-sha2-256": {32, func(key []byte) hash.Hash {
"hmac-sha2-256-etm@openssh.com": {32, true, func(key []byte) hash.Hash {
return hmac.New(sha256.New, key)
}},
"hmac-sha1": {20, func(key []byte) hash.Hash {
"hmac-sha2-256": {32, false, func(key []byte) hash.Hash {
return hmac.New(sha256.New, key)
}},
"hmac-sha1": {20, false, func(key []byte) hash.Hash {
return hmac.New(sha1.New, key)
}},
"hmac-sha1-96": {20, func(key []byte) hash.Hash {
"hmac-sha1-96": {20, false, func(key []byte) hash.Hash {
return truncatingMAC{12, hmac.New(sha1.New, key)}
}},
}

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